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

q54sj108a2.c (11620B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Driver for Delta modules, Q54SJ108A2 series 1/4 Brick DC/DC
      4 * Regulated Power Module
      5 *
      6 * Copyright 2020 Delta LLC.
      7 */
      8
      9#include <linux/debugfs.h>
     10#include <linux/i2c.h>
     11#include <linux/module.h>
     12#include <linux/of_device.h>
     13#include "pmbus.h"
     14
     15#define STORE_DEFAULT_ALL		0x11
     16#define ERASE_BLACKBOX_DATA		0xD1
     17#define READ_HISTORY_EVENT_NUMBER	0xD2
     18#define READ_HISTORY_EVENTS		0xE0
     19#define SET_HISTORY_EVENT_OFFSET	0xE1
     20#define PMBUS_FLASH_KEY_WRITE		0xEC
     21
     22enum chips {
     23	q54sj108a2
     24};
     25
     26enum {
     27	Q54SJ108A2_DEBUGFS_OPERATION = 0,
     28	Q54SJ108A2_DEBUGFS_CLEARFAULT,
     29	Q54SJ108A2_DEBUGFS_WRITEPROTECT,
     30	Q54SJ108A2_DEBUGFS_STOREDEFAULT,
     31	Q54SJ108A2_DEBUGFS_VOOV_RESPONSE,
     32	Q54SJ108A2_DEBUGFS_IOOC_RESPONSE,
     33	Q54SJ108A2_DEBUGFS_PMBUS_VERSION,
     34	Q54SJ108A2_DEBUGFS_MFR_ID,
     35	Q54SJ108A2_DEBUGFS_MFR_MODEL,
     36	Q54SJ108A2_DEBUGFS_MFR_REVISION,
     37	Q54SJ108A2_DEBUGFS_MFR_LOCATION,
     38	Q54SJ108A2_DEBUGFS_BLACKBOX_ERASE,
     39	Q54SJ108A2_DEBUGFS_BLACKBOX_READ_OFFSET,
     40	Q54SJ108A2_DEBUGFS_BLACKBOX_SET_OFFSET,
     41	Q54SJ108A2_DEBUGFS_BLACKBOX_READ,
     42	Q54SJ108A2_DEBUGFS_FLASH_KEY,
     43	Q54SJ108A2_DEBUGFS_NUM_ENTRIES
     44};
     45
     46struct q54sj108a2_data {
     47	enum chips chip;
     48	struct i2c_client *client;
     49
     50	int debugfs_entries[Q54SJ108A2_DEBUGFS_NUM_ENTRIES];
     51};
     52
     53#define to_psu(x, y) container_of((x), struct q54sj108a2_data, debugfs_entries[(y)])
     54
     55static struct pmbus_driver_info q54sj108a2_info[] = {
     56	[q54sj108a2] = {
     57		.pages = 1,
     58
     59		/* Source : Delta Q54SJ108A2 */
     60		.format[PSC_TEMPERATURE] = linear,
     61		.format[PSC_VOLTAGE_IN] = linear,
     62		.format[PSC_CURRENT_OUT] = linear,
     63
     64		.func[0] = PMBUS_HAVE_VIN |
     65		PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
     66		PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
     67		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
     68		PMBUS_HAVE_STATUS_INPUT,
     69	},
     70};
     71
     72static ssize_t q54sj108a2_debugfs_read(struct file *file, char __user *buf,
     73				       size_t count, loff_t *ppos)
     74{
     75	int rc;
     76	int *idxp = file->private_data;
     77	int idx = *idxp;
     78	struct q54sj108a2_data *psu = to_psu(idxp, idx);
     79	char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
     80	char data_char[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
     81	char *res;
     82
     83	switch (idx) {
     84	case Q54SJ108A2_DEBUGFS_OPERATION:
     85		rc = i2c_smbus_read_byte_data(psu->client, PMBUS_OPERATION);
     86		if (rc < 0)
     87			return rc;
     88
     89		rc = snprintf(data, 3, "%02x", rc);
     90		break;
     91	case Q54SJ108A2_DEBUGFS_WRITEPROTECT:
     92		rc = i2c_smbus_read_byte_data(psu->client, PMBUS_WRITE_PROTECT);
     93		if (rc < 0)
     94			return rc;
     95
     96		rc = snprintf(data, 3, "%02x", rc);
     97		break;
     98	case Q54SJ108A2_DEBUGFS_VOOV_RESPONSE:
     99		rc = i2c_smbus_read_byte_data(psu->client, PMBUS_VOUT_OV_FAULT_RESPONSE);
    100		if (rc < 0)
    101			return rc;
    102
    103		rc = snprintf(data, 3, "%02x", rc);
    104		break;
    105	case Q54SJ108A2_DEBUGFS_IOOC_RESPONSE:
    106		rc = i2c_smbus_read_byte_data(psu->client, PMBUS_IOUT_OC_FAULT_RESPONSE);
    107		if (rc < 0)
    108			return rc;
    109
    110		rc = snprintf(data, 3, "%02x", rc);
    111		break;
    112	case Q54SJ108A2_DEBUGFS_PMBUS_VERSION:
    113		rc = i2c_smbus_read_byte_data(psu->client, PMBUS_REVISION);
    114		if (rc < 0)
    115			return rc;
    116
    117		rc = snprintf(data, 3, "%02x", rc);
    118		break;
    119	case Q54SJ108A2_DEBUGFS_MFR_ID:
    120		rc = i2c_smbus_read_block_data(psu->client, PMBUS_MFR_ID, data);
    121		if (rc < 0)
    122			return rc;
    123		break;
    124	case Q54SJ108A2_DEBUGFS_MFR_MODEL:
    125		rc = i2c_smbus_read_block_data(psu->client, PMBUS_MFR_MODEL, data);
    126		if (rc < 0)
    127			return rc;
    128		break;
    129	case Q54SJ108A2_DEBUGFS_MFR_REVISION:
    130		rc = i2c_smbus_read_block_data(psu->client, PMBUS_MFR_REVISION, data);
    131		if (rc < 0)
    132			return rc;
    133		break;
    134	case Q54SJ108A2_DEBUGFS_MFR_LOCATION:
    135		rc = i2c_smbus_read_block_data(psu->client, PMBUS_MFR_LOCATION, data);
    136		if (rc < 0)
    137			return rc;
    138		break;
    139	case Q54SJ108A2_DEBUGFS_BLACKBOX_READ_OFFSET:
    140		rc = i2c_smbus_read_byte_data(psu->client, READ_HISTORY_EVENT_NUMBER);
    141		if (rc < 0)
    142			return rc;
    143
    144		rc = snprintf(data, 3, "%02x", rc);
    145		break;
    146	case Q54SJ108A2_DEBUGFS_BLACKBOX_READ:
    147		rc = i2c_smbus_read_block_data(psu->client, READ_HISTORY_EVENTS, data);
    148		if (rc < 0)
    149			return rc;
    150
    151		res = bin2hex(data, data_char, 32);
    152		rc = res - data;
    153
    154		break;
    155	case Q54SJ108A2_DEBUGFS_FLASH_KEY:
    156		rc = i2c_smbus_read_block_data(psu->client, PMBUS_FLASH_KEY_WRITE, data);
    157		if (rc < 0)
    158			return rc;
    159
    160		res = bin2hex(data, data_char, 4);
    161		rc = res - data;
    162
    163		break;
    164	default:
    165		return -EINVAL;
    166	}
    167
    168	data[rc] = '\n';
    169	rc += 2;
    170
    171	return simple_read_from_buffer(buf, count, ppos, data, rc);
    172}
    173
    174static ssize_t q54sj108a2_debugfs_write(struct file *file, const char __user *buf,
    175					size_t count, loff_t *ppos)
    176{
    177	u8 flash_key[4];
    178	u8 dst_data;
    179	ssize_t rc;
    180	int *idxp = file->private_data;
    181	int idx = *idxp;
    182	struct q54sj108a2_data *psu = to_psu(idxp, idx);
    183
    184	rc = i2c_smbus_write_byte_data(psu->client, PMBUS_WRITE_PROTECT, 0);
    185	if (rc)
    186		return rc;
    187
    188	switch (idx) {
    189	case Q54SJ108A2_DEBUGFS_OPERATION:
    190		rc = kstrtou8_from_user(buf, count, 0, &dst_data);
    191		if (rc < 0)
    192			return rc;
    193
    194		rc = i2c_smbus_write_byte_data(psu->client, PMBUS_OPERATION, dst_data);
    195		if (rc < 0)
    196			return rc;
    197
    198		break;
    199	case Q54SJ108A2_DEBUGFS_CLEARFAULT:
    200		rc = i2c_smbus_write_byte(psu->client, PMBUS_CLEAR_FAULTS);
    201		if (rc < 0)
    202			return rc;
    203
    204		break;
    205	case Q54SJ108A2_DEBUGFS_STOREDEFAULT:
    206		flash_key[0] = 0x7E;
    207		flash_key[1] = 0x15;
    208		flash_key[2] = 0xDC;
    209		flash_key[3] = 0x42;
    210		rc = i2c_smbus_write_block_data(psu->client, PMBUS_FLASH_KEY_WRITE, 4, flash_key);
    211		if (rc < 0)
    212			return rc;
    213
    214		rc = i2c_smbus_write_byte(psu->client, STORE_DEFAULT_ALL);
    215		if (rc < 0)
    216			return rc;
    217
    218		break;
    219	case Q54SJ108A2_DEBUGFS_VOOV_RESPONSE:
    220		rc = kstrtou8_from_user(buf, count, 0, &dst_data);
    221		if (rc < 0)
    222			return rc;
    223
    224		rc = i2c_smbus_write_byte_data(psu->client, PMBUS_VOUT_OV_FAULT_RESPONSE, dst_data);
    225		if (rc < 0)
    226			return rc;
    227
    228		break;
    229	case Q54SJ108A2_DEBUGFS_IOOC_RESPONSE:
    230		rc = kstrtou8_from_user(buf, count, 0, &dst_data);
    231		if (rc < 0)
    232			return rc;
    233
    234		rc = i2c_smbus_write_byte_data(psu->client, PMBUS_IOUT_OC_FAULT_RESPONSE, dst_data);
    235		if (rc < 0)
    236			return rc;
    237
    238		break;
    239	case Q54SJ108A2_DEBUGFS_BLACKBOX_ERASE:
    240		rc = i2c_smbus_write_byte(psu->client, ERASE_BLACKBOX_DATA);
    241		if (rc < 0)
    242			return rc;
    243
    244		break;
    245	case Q54SJ108A2_DEBUGFS_BLACKBOX_SET_OFFSET:
    246		rc = kstrtou8_from_user(buf, count, 0, &dst_data);
    247		if (rc < 0)
    248			return rc;
    249
    250		rc = i2c_smbus_write_byte_data(psu->client, SET_HISTORY_EVENT_OFFSET, dst_data);
    251		if (rc < 0)
    252			return rc;
    253
    254		break;
    255	default:
    256		return -EINVAL;
    257	}
    258
    259	return count;
    260}
    261
    262static const struct file_operations q54sj108a2_fops = {
    263	.llseek = noop_llseek,
    264	.read = q54sj108a2_debugfs_read,
    265	.write = q54sj108a2_debugfs_write,
    266	.open = simple_open,
    267};
    268
    269static const struct i2c_device_id q54sj108a2_id[] = {
    270	{ "q54sj108a2", q54sj108a2 },
    271	{ },
    272};
    273
    274MODULE_DEVICE_TABLE(i2c, q54sj108a2_id);
    275
    276static int q54sj108a2_probe(struct i2c_client *client)
    277{
    278	struct device *dev = &client->dev;
    279	u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
    280	enum chips chip_id;
    281	int ret, i;
    282	struct dentry *debugfs;
    283	struct dentry *q54sj108a2_dir;
    284	struct q54sj108a2_data *psu;
    285
    286	if (!i2c_check_functionality(client->adapter,
    287				     I2C_FUNC_SMBUS_BYTE_DATA |
    288				     I2C_FUNC_SMBUS_WORD_DATA |
    289				     I2C_FUNC_SMBUS_BLOCK_DATA))
    290		return -ENODEV;
    291
    292	if (client->dev.of_node)
    293		chip_id = (enum chips)(unsigned long)of_device_get_match_data(dev);
    294	else
    295		chip_id = i2c_match_id(q54sj108a2_id, client)->driver_data;
    296
    297	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
    298	if (ret < 0) {
    299		dev_err(&client->dev, "Failed to read Manufacturer ID\n");
    300		return ret;
    301	}
    302	if (ret != 6 || strncmp(buf, "DELTA", 5)) {
    303		buf[ret] = '\0';
    304		dev_err(dev, "Unsupported Manufacturer ID '%s'\n", buf);
    305		return -ENODEV;
    306	}
    307
    308	/*
    309	 * The chips support reading PMBUS_MFR_MODEL.
    310	 */
    311	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
    312	if (ret < 0) {
    313		dev_err(dev, "Failed to read Manufacturer Model\n");
    314		return ret;
    315	}
    316	if (ret != 14 || strncmp(buf, "Q54SJ108A2", 10)) {
    317		buf[ret] = '\0';
    318		dev_err(dev, "Unsupported Manufacturer Model '%s'\n", buf);
    319		return -ENODEV;
    320	}
    321
    322	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_REVISION, buf);
    323	if (ret < 0) {
    324		dev_err(dev, "Failed to read Manufacturer Revision\n");
    325		return ret;
    326	}
    327	if (ret != 4 || buf[0] != 'S') {
    328		buf[ret] = '\0';
    329		dev_err(dev, "Unsupported Manufacturer Revision '%s'\n", buf);
    330		return -ENODEV;
    331	}
    332
    333	ret = pmbus_do_probe(client, &q54sj108a2_info[chip_id]);
    334	if (ret)
    335		return ret;
    336
    337	psu = devm_kzalloc(&client->dev, sizeof(*psu), GFP_KERNEL);
    338	if (!psu)
    339		return 0;
    340
    341	psu->client = client;
    342
    343	debugfs = pmbus_get_debugfs_dir(client);
    344
    345	q54sj108a2_dir = debugfs_create_dir(client->name, debugfs);
    346
    347	for (i = 0; i < Q54SJ108A2_DEBUGFS_NUM_ENTRIES; ++i)
    348		psu->debugfs_entries[i] = i;
    349
    350	debugfs_create_file("operation", 0644, q54sj108a2_dir,
    351			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_OPERATION],
    352			    &q54sj108a2_fops);
    353	debugfs_create_file("clear_fault", 0200, q54sj108a2_dir,
    354			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_CLEARFAULT],
    355			    &q54sj108a2_fops);
    356	debugfs_create_file("write_protect", 0444, q54sj108a2_dir,
    357			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_WRITEPROTECT],
    358			    &q54sj108a2_fops);
    359	debugfs_create_file("store_default", 0200, q54sj108a2_dir,
    360			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_STOREDEFAULT],
    361			    &q54sj108a2_fops);
    362	debugfs_create_file("vo_ov_response", 0644, q54sj108a2_dir,
    363			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_VOOV_RESPONSE],
    364			    &q54sj108a2_fops);
    365	debugfs_create_file("io_oc_response", 0644, q54sj108a2_dir,
    366			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_IOOC_RESPONSE],
    367			    &q54sj108a2_fops);
    368	debugfs_create_file("pmbus_revision", 0444, q54sj108a2_dir,
    369			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_PMBUS_VERSION],
    370			    &q54sj108a2_fops);
    371	debugfs_create_file("mfr_id", 0444, q54sj108a2_dir,
    372			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_MFR_ID],
    373			    &q54sj108a2_fops);
    374	debugfs_create_file("mfr_model", 0444, q54sj108a2_dir,
    375			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_MFR_MODEL],
    376			    &q54sj108a2_fops);
    377	debugfs_create_file("mfr_revision", 0444, q54sj108a2_dir,
    378			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_MFR_REVISION],
    379			    &q54sj108a2_fops);
    380	debugfs_create_file("mfr_location", 0444, q54sj108a2_dir,
    381			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_MFR_LOCATION],
    382			    &q54sj108a2_fops);
    383	debugfs_create_file("blackbox_erase", 0200, q54sj108a2_dir,
    384			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_BLACKBOX_ERASE],
    385			    &q54sj108a2_fops);
    386	debugfs_create_file("blackbox_read_offset", 0444, q54sj108a2_dir,
    387			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_BLACKBOX_READ_OFFSET],
    388			    &q54sj108a2_fops);
    389	debugfs_create_file("blackbox_set_offset", 0200, q54sj108a2_dir,
    390			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_BLACKBOX_SET_OFFSET],
    391			    &q54sj108a2_fops);
    392	debugfs_create_file("blackbox_read", 0444, q54sj108a2_dir,
    393			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_BLACKBOX_READ],
    394			    &q54sj108a2_fops);
    395	debugfs_create_file("flash_key", 0444, q54sj108a2_dir,
    396			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_FLASH_KEY],
    397			    &q54sj108a2_fops);
    398
    399	return 0;
    400}
    401
    402static const struct of_device_id q54sj108a2_of_match[] = {
    403	{ .compatible = "delta,q54sj108a2", .data = (void *)q54sj108a2 },
    404	{ },
    405};
    406
    407MODULE_DEVICE_TABLE(of, q54sj108a2_of_match);
    408
    409static struct i2c_driver q54sj108a2_driver = {
    410	.driver = {
    411		.name = "q54sj108a2",
    412		.of_match_table = q54sj108a2_of_match,
    413	},
    414	.probe_new = q54sj108a2_probe,
    415	.id_table = q54sj108a2_id,
    416};
    417
    418module_i2c_driver(q54sj108a2_driver);
    419
    420MODULE_AUTHOR("Xiao.Ma <xiao.mx.ma@deltaww.com>");
    421MODULE_DESCRIPTION("PMBus driver for Delta Q54SJ108A2 series modules");
    422MODULE_LICENSE("GPL");
    423MODULE_IMPORT_NS(PMBUS);