cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

atxp1.c (6643B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * atxp1.c - kernel module for setting CPU VID and general purpose
      4 *	     I/Os using the Attansic ATXP1 chip.
      5 *
      6 * The ATXP1 can reside on I2C addresses 0x37 or 0x4e. The chip is
      7 * not auto-detected by the driver and must be instantiated explicitly.
      8 * See Documentation/i2c/instantiating-devices.rst for more information.
      9 */
     10
     11#include <linux/kernel.h>
     12#include <linux/init.h>
     13#include <linux/module.h>
     14#include <linux/jiffies.h>
     15#include <linux/i2c.h>
     16#include <linux/hwmon.h>
     17#include <linux/hwmon-vid.h>
     18#include <linux/err.h>
     19#include <linux/mutex.h>
     20#include <linux/sysfs.h>
     21#include <linux/slab.h>
     22
     23MODULE_LICENSE("GPL");
     24MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
     25MODULE_VERSION("0.6.3");
     26MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
     27
     28#define ATXP1_VID	0x00
     29#define ATXP1_CVID	0x01
     30#define ATXP1_GPIO1	0x06
     31#define ATXP1_GPIO2	0x0a
     32#define ATXP1_VIDENA	0x20
     33#define ATXP1_VIDMASK	0x1f
     34#define ATXP1_GPIO1MASK	0x0f
     35
     36struct atxp1_data {
     37	struct i2c_client *client;
     38	struct mutex update_lock;
     39	unsigned long last_updated;
     40	bool valid;
     41	struct {
     42		u8 vid;		/* VID output register */
     43		u8 cpu_vid; /* VID input from CPU */
     44		u8 gpio1;   /* General purpose I/O register 1 */
     45		u8 gpio2;   /* General purpose I/O register 2 */
     46	} reg;
     47	u8 vrm;			/* Detected CPU VRM */
     48};
     49
     50static struct atxp1_data *atxp1_update_device(struct device *dev)
     51{
     52	struct atxp1_data *data = dev_get_drvdata(dev);
     53	struct i2c_client *client = data->client;
     54
     55	mutex_lock(&data->update_lock);
     56
     57	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
     58
     59		/* Update local register data */
     60		data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID);
     61		data->reg.cpu_vid = i2c_smbus_read_byte_data(client,
     62							     ATXP1_CVID);
     63		data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1);
     64		data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2);
     65
     66		data->valid = true;
     67	}
     68
     69	mutex_unlock(&data->update_lock);
     70
     71	return data;
     72}
     73
     74/* sys file functions for cpu0_vid */
     75static ssize_t cpu0_vid_show(struct device *dev,
     76			     struct device_attribute *attr, char *buf)
     77{
     78	int size;
     79	struct atxp1_data *data;
     80
     81	data = atxp1_update_device(dev);
     82
     83	size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK,
     84						 data->vrm));
     85
     86	return size;
     87}
     88
     89static ssize_t cpu0_vid_store(struct device *dev,
     90			      struct device_attribute *attr, const char *buf,
     91			      size_t count)
     92{
     93	struct atxp1_data *data = atxp1_update_device(dev);
     94	struct i2c_client *client = data->client;
     95	int vid, cvid;
     96	unsigned long vcore;
     97	int err;
     98
     99	err = kstrtoul(buf, 10, &vcore);
    100	if (err)
    101		return err;
    102
    103	vcore /= 25;
    104	vcore *= 25;
    105
    106	/* Calculate VID */
    107	vid = vid_to_reg(vcore, data->vrm);
    108	if (vid < 0) {
    109		dev_err(dev, "VID calculation failed.\n");
    110		return vid;
    111	}
    112
    113	/*
    114	 * If output enabled, use control register value.
    115	 * Otherwise original CPU VID
    116	 */
    117	if (data->reg.vid & ATXP1_VIDENA)
    118		cvid = data->reg.vid & ATXP1_VIDMASK;
    119	else
    120		cvid = data->reg.cpu_vid;
    121
    122	/* Nothing changed, aborting */
    123	if (vid == cvid)
    124		return count;
    125
    126	dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", (int)vcore, vid);
    127
    128	/* Write every 25 mV step to increase stability */
    129	if (cvid > vid) {
    130		for (; cvid >= vid; cvid--)
    131			i2c_smbus_write_byte_data(client,
    132						ATXP1_VID, cvid | ATXP1_VIDENA);
    133	} else {
    134		for (; cvid <= vid; cvid++)
    135			i2c_smbus_write_byte_data(client,
    136						ATXP1_VID, cvid | ATXP1_VIDENA);
    137	}
    138
    139	data->valid = false;
    140
    141	return count;
    142}
    143
    144/*
    145 * CPU core reference voltage
    146 * unit: millivolt
    147 */
    148static DEVICE_ATTR_RW(cpu0_vid);
    149
    150/* sys file functions for GPIO1 */
    151static ssize_t gpio1_show(struct device *dev, struct device_attribute *attr,
    152			  char *buf)
    153{
    154	int size;
    155	struct atxp1_data *data;
    156
    157	data = atxp1_update_device(dev);
    158
    159	size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK);
    160
    161	return size;
    162}
    163
    164static ssize_t gpio1_store(struct device *dev, struct device_attribute *attr,
    165			   const char *buf, size_t count)
    166{
    167	struct atxp1_data *data = atxp1_update_device(dev);
    168	struct i2c_client *client = data->client;
    169	unsigned long value;
    170	int err;
    171
    172	err = kstrtoul(buf, 16, &value);
    173	if (err)
    174		return err;
    175
    176	value &= ATXP1_GPIO1MASK;
    177
    178	if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) {
    179		dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value);
    180
    181		i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value);
    182
    183		data->valid = false;
    184	}
    185
    186	return count;
    187}
    188
    189/*
    190 * GPIO1 data register
    191 * unit: Four bit as hex (e.g. 0x0f)
    192 */
    193static DEVICE_ATTR_RW(gpio1);
    194
    195/* sys file functions for GPIO2 */
    196static ssize_t gpio2_show(struct device *dev, struct device_attribute *attr,
    197			  char *buf)
    198{
    199	int size;
    200	struct atxp1_data *data;
    201
    202	data = atxp1_update_device(dev);
    203
    204	size = sprintf(buf, "0x%02x\n", data->reg.gpio2);
    205
    206	return size;
    207}
    208
    209static ssize_t gpio2_store(struct device *dev, struct device_attribute *attr,
    210			   const char *buf, size_t count)
    211{
    212	struct atxp1_data *data = atxp1_update_device(dev);
    213	struct i2c_client *client = data->client;
    214	unsigned long value;
    215	int err;
    216
    217	err = kstrtoul(buf, 16, &value);
    218	if (err)
    219		return err;
    220	value &= 0xff;
    221
    222	if (value != data->reg.gpio2) {
    223		dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value);
    224
    225		i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value);
    226
    227		data->valid = false;
    228	}
    229
    230	return count;
    231}
    232
    233/*
    234 * GPIO2 data register
    235 * unit: Eight bit as hex (e.g. 0xff)
    236 */
    237static DEVICE_ATTR_RW(gpio2);
    238
    239static struct attribute *atxp1_attrs[] = {
    240	&dev_attr_gpio1.attr,
    241	&dev_attr_gpio2.attr,
    242	&dev_attr_cpu0_vid.attr,
    243	NULL
    244};
    245ATTRIBUTE_GROUPS(atxp1);
    246
    247static int atxp1_probe(struct i2c_client *client)
    248{
    249	struct device *dev = &client->dev;
    250	struct atxp1_data *data;
    251	struct device *hwmon_dev;
    252
    253	data = devm_kzalloc(dev, sizeof(struct atxp1_data), GFP_KERNEL);
    254	if (!data)
    255		return -ENOMEM;
    256
    257	/* Get VRM */
    258	data->vrm = vid_which_vrm();
    259	if (data->vrm != 90 && data->vrm != 91) {
    260		dev_err(dev, "atxp1: Not supporting VRM %d.%d\n",
    261			data->vrm / 10, data->vrm % 10);
    262		return -ENODEV;
    263	}
    264
    265	data->client = client;
    266	mutex_init(&data->update_lock);
    267
    268	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
    269							   data,
    270							   atxp1_groups);
    271	if (IS_ERR(hwmon_dev))
    272		return PTR_ERR(hwmon_dev);
    273
    274	dev_info(dev, "Using VRM: %d.%d\n", data->vrm / 10, data->vrm % 10);
    275
    276	return 0;
    277};
    278
    279static const struct i2c_device_id atxp1_id[] = {
    280	{ "atxp1", 0 },
    281	{ }
    282};
    283MODULE_DEVICE_TABLE(i2c, atxp1_id);
    284
    285static struct i2c_driver atxp1_driver = {
    286	.class		= I2C_CLASS_HWMON,
    287	.driver = {
    288		.name	= "atxp1",
    289	},
    290	.probe_new	= atxp1_probe,
    291	.id_table	= atxp1_id,
    292};
    293
    294module_i2c_driver(atxp1_driver);