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

rsmu_spi.c (6562B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * SPI driver for Renesas Synchronization Management Unit (SMU) devices.
      4 *
      5 * Copyright (C) 2021 Integrated Device Technology, Inc., a Renesas Company.
      6 */
      7
      8#include <linux/init.h>
      9#include <linux/kernel.h>
     10#include <linux/mfd/core.h>
     11#include <linux/mfd/rsmu.h>
     12#include <linux/module.h>
     13#include <linux/of.h>
     14#include <linux/regmap.h>
     15#include <linux/slab.h>
     16#include <linux/spi/spi.h>
     17
     18#include "rsmu.h"
     19
     20#define	RSMU_CM_PAGE_ADDR		0x7C
     21#define	RSMU_SABRE_PAGE_ADDR		0x7F
     22#define	RSMU_HIGHER_ADDR_MASK		0xFF80
     23#define	RSMU_HIGHER_ADDR_SHIFT		7
     24#define	RSMU_LOWER_ADDR_MASK		0x7F
     25
     26static int rsmu_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes)
     27{
     28	struct spi_device *client = to_spi_device(rsmu->dev);
     29	struct spi_transfer xfer = {0};
     30	struct spi_message msg;
     31	u8 cmd[256] = {0};
     32	u8 rsp[256] = {0};
     33	int ret;
     34
     35	cmd[0] = reg | 0x80;
     36	xfer.rx_buf = rsp;
     37	xfer.len = bytes + 1;
     38	xfer.tx_buf = cmd;
     39	xfer.bits_per_word = client->bits_per_word;
     40	xfer.speed_hz = client->max_speed_hz;
     41
     42	spi_message_init(&msg);
     43	spi_message_add_tail(&xfer, &msg);
     44
     45	/*
     46	 * 4-wire SPI is a shift register, so for every byte you send,
     47	 * you get one back at the same time. Example read from 0xC024,
     48	 * which has value of 0x2D
     49	 *
     50	 * MOSI:
     51	 *       7C 00 C0 #Set page register
     52	 *       A4 00    #MSB is set, so this is read command
     53	 * MISO:
     54	 *       XX 2D    #XX is a dummy byte from sending A4 and we
     55	 *                 need to throw it away
     56	 */
     57	ret = spi_sync(client, &msg);
     58	if (ret >= 0)
     59		memcpy(buf, &rsp[1], xfer.len-1);
     60
     61	return ret;
     62}
     63
     64static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes)
     65{
     66	struct spi_device *client = to_spi_device(rsmu->dev);
     67	struct spi_transfer xfer = {0};
     68	struct spi_message msg;
     69	u8 cmd[256] = {0};
     70
     71	cmd[0] = reg;
     72	memcpy(&cmd[1], buf, bytes);
     73
     74	xfer.len = bytes + 1;
     75	xfer.tx_buf = cmd;
     76	xfer.bits_per_word = client->bits_per_word;
     77	xfer.speed_hz = client->max_speed_hz;
     78	spi_message_init(&msg);
     79	spi_message_add_tail(&xfer, &msg);
     80
     81	return  spi_sync(client, &msg);
     82}
     83
     84/*
     85 * 1-byte (1B) offset addressing:
     86 * 16-bit register address: the lower 7 bits of the register address come
     87 * from the offset addr byte and the upper 9 bits come from the page register.
     88 */
     89static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u16 reg)
     90{
     91	u8 page_reg;
     92	u8 buf[2];
     93	u16 bytes;
     94	u16 page;
     95	int err;
     96
     97	switch (rsmu->type) {
     98	case RSMU_CM:
     99		page_reg = RSMU_CM_PAGE_ADDR;
    100		page = reg & RSMU_HIGHER_ADDR_MASK;
    101		buf[0] = (u8)(page & 0xff);
    102		buf[1] = (u8)((page >> 8) & 0xff);
    103		bytes = 2;
    104		break;
    105	case RSMU_SABRE:
    106		page_reg = RSMU_SABRE_PAGE_ADDR;
    107		page = reg >> RSMU_HIGHER_ADDR_SHIFT;
    108		buf[0] = (u8)(page & 0xff);
    109		bytes = 1;
    110		break;
    111	default:
    112		dev_err(rsmu->dev, "Unsupported RSMU device type: %d\n", rsmu->type);
    113		return -ENODEV;
    114	}
    115
    116	/* Simply return if we are on the same page */
    117	if (rsmu->page == page)
    118		return 0;
    119
    120	err = rsmu_write_device(rsmu, page_reg, buf, bytes);
    121	if (err)
    122		dev_err(rsmu->dev, "Failed to set page offset 0x%x\n", page);
    123	else
    124		/* Remember the last page */
    125		rsmu->page = page;
    126
    127	return err;
    128}
    129
    130static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val)
    131{
    132	struct rsmu_ddata *rsmu = spi_get_drvdata((struct spi_device *)context);
    133	u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK);
    134	int err;
    135
    136	err = rsmu_write_page_register(rsmu, reg);
    137	if (err)
    138		return err;
    139
    140	err = rsmu_read_device(rsmu, addr, (u8 *)val, 1);
    141	if (err)
    142		dev_err(rsmu->dev, "Failed to read offset address 0x%x\n", addr);
    143
    144	return err;
    145}
    146
    147static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val)
    148{
    149	struct rsmu_ddata *rsmu = spi_get_drvdata((struct spi_device *)context);
    150	u8 addr = (u8)(reg & RSMU_LOWER_ADDR_MASK);
    151	u8 data = (u8)val;
    152	int err;
    153
    154	err = rsmu_write_page_register(rsmu, reg);
    155	if (err)
    156		return err;
    157
    158	err = rsmu_write_device(rsmu, addr, &data, 1);
    159	if (err)
    160		dev_err(rsmu->dev,
    161			"Failed to write offset address 0x%x\n", addr);
    162
    163	return err;
    164}
    165
    166static const struct regmap_config rsmu_cm_regmap_config = {
    167	.reg_bits = 16,
    168	.val_bits = 8,
    169	.max_register = 0xD000,
    170	.reg_read = rsmu_reg_read,
    171	.reg_write = rsmu_reg_write,
    172	.cache_type = REGCACHE_NONE,
    173};
    174
    175static const struct regmap_config rsmu_sabre_regmap_config = {
    176	.reg_bits = 16,
    177	.val_bits = 8,
    178	.max_register = 0x400,
    179	.reg_read = rsmu_reg_read,
    180	.reg_write = rsmu_reg_write,
    181	.cache_type = REGCACHE_NONE,
    182};
    183
    184static int rsmu_spi_probe(struct spi_device *client)
    185{
    186	const struct spi_device_id *id = spi_get_device_id(client);
    187	const struct regmap_config *cfg;
    188	struct rsmu_ddata *rsmu;
    189	int ret;
    190
    191	rsmu = devm_kzalloc(&client->dev, sizeof(*rsmu), GFP_KERNEL);
    192	if (!rsmu)
    193		return -ENOMEM;
    194
    195	spi_set_drvdata(client, rsmu);
    196
    197	rsmu->dev = &client->dev;
    198	rsmu->type = (enum rsmu_type)id->driver_data;
    199
    200	/* Initialize regmap */
    201	switch (rsmu->type) {
    202	case RSMU_CM:
    203		cfg = &rsmu_cm_regmap_config;
    204		break;
    205	case RSMU_SABRE:
    206		cfg = &rsmu_sabre_regmap_config;
    207		break;
    208	default:
    209		dev_err(rsmu->dev, "Unsupported RSMU device type: %d\n", rsmu->type);
    210		return -ENODEV;
    211	}
    212
    213	rsmu->regmap = devm_regmap_init(&client->dev, NULL, client, cfg);
    214	if (IS_ERR(rsmu->regmap)) {
    215		ret = PTR_ERR(rsmu->regmap);
    216		dev_err(rsmu->dev, "Failed to allocate register map: %d\n", ret);
    217		return ret;
    218	}
    219
    220	return rsmu_core_init(rsmu);
    221}
    222
    223static void rsmu_spi_remove(struct spi_device *client)
    224{
    225	struct rsmu_ddata *rsmu = spi_get_drvdata(client);
    226
    227	rsmu_core_exit(rsmu);
    228}
    229
    230static const struct spi_device_id rsmu_spi_id[] = {
    231	{ "8a34000",  RSMU_CM },
    232	{ "8a34001",  RSMU_CM },
    233	{ "82p33810", RSMU_SABRE },
    234	{ "82p33811", RSMU_SABRE },
    235	{}
    236};
    237MODULE_DEVICE_TABLE(spi, rsmu_spi_id);
    238
    239static const struct of_device_id rsmu_spi_of_match[] = {
    240	{ .compatible = "idt,8a34000",  .data = (void *)RSMU_CM },
    241	{ .compatible = "idt,8a34001",  .data = (void *)RSMU_CM },
    242	{ .compatible = "idt,82p33810", .data = (void *)RSMU_SABRE },
    243	{ .compatible = "idt,82p33811", .data = (void *)RSMU_SABRE },
    244	{}
    245};
    246MODULE_DEVICE_TABLE(of, rsmu_spi_of_match);
    247
    248static struct spi_driver rsmu_spi_driver = {
    249	.driver = {
    250		.name = "rsmu-spi",
    251		.of_match_table = of_match_ptr(rsmu_spi_of_match),
    252	},
    253	.probe = rsmu_spi_probe,
    254	.remove	= rsmu_spi_remove,
    255	.id_table = rsmu_spi_id,
    256};
    257
    258static int __init rsmu_spi_init(void)
    259{
    260	return spi_register_driver(&rsmu_spi_driver);
    261}
    262subsys_initcall(rsmu_spi_init);
    263
    264static void __exit rsmu_spi_exit(void)
    265{
    266	spi_unregister_driver(&rsmu_spi_driver);
    267}
    268module_exit(rsmu_spi_exit);
    269
    270MODULE_DESCRIPTION("Renesas SMU SPI driver");
    271MODULE_LICENSE("GPL");