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_i2c.c (4864B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * I2C 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/i2c.h>
      9#include <linux/init.h>
     10#include <linux/kernel.h>
     11#include <linux/mfd/core.h>
     12#include <linux/mfd/rsmu.h>
     13#include <linux/module.h>
     14#include <linux/of.h>
     15#include <linux/regmap.h>
     16#include <linux/slab.h>
     17
     18#include "rsmu.h"
     19
     20/*
     21 * 16-bit register address: the lower 8 bits of the register address come
     22 * from the offset addr byte and the upper 8 bits come from the page register.
     23 */
     24#define	RSMU_CM_PAGE_ADDR		0xFD
     25#define	RSMU_CM_PAGE_WINDOW		256
     26
     27/*
     28 * 15-bit register address: the lower 7 bits of the register address come
     29 * from the offset addr byte and the upper 8 bits come from the page register.
     30 */
     31#define	RSMU_SABRE_PAGE_ADDR		0x7F
     32#define	RSMU_SABRE_PAGE_WINDOW		128
     33
     34static const struct regmap_range_cfg rsmu_cm_range_cfg[] = {
     35	{
     36		.range_min = 0,
     37		.range_max = 0xD000,
     38		.selector_reg = RSMU_CM_PAGE_ADDR,
     39		.selector_mask = 0xFF,
     40		.selector_shift = 0,
     41		.window_start = 0,
     42		.window_len = RSMU_CM_PAGE_WINDOW,
     43	}
     44};
     45
     46static const struct regmap_range_cfg rsmu_sabre_range_cfg[] = {
     47	{
     48		.range_min = 0,
     49		.range_max = 0x400,
     50		.selector_reg = RSMU_SABRE_PAGE_ADDR,
     51		.selector_mask = 0xFF,
     52		.selector_shift = 0,
     53		.window_start = 0,
     54		.window_len = RSMU_SABRE_PAGE_WINDOW,
     55	}
     56};
     57
     58static bool rsmu_cm_volatile_reg(struct device *dev, unsigned int reg)
     59{
     60	switch (reg) {
     61	case RSMU_CM_PAGE_ADDR:
     62		return false;
     63	default:
     64		return true;
     65	}
     66}
     67
     68static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg)
     69{
     70	switch (reg) {
     71	case RSMU_SABRE_PAGE_ADDR:
     72		return false;
     73	default:
     74		return true;
     75	}
     76}
     77
     78static const struct regmap_config rsmu_cm_regmap_config = {
     79	.reg_bits = 8,
     80	.val_bits = 8,
     81	.max_register = 0xD000,
     82	.ranges = rsmu_cm_range_cfg,
     83	.num_ranges = ARRAY_SIZE(rsmu_cm_range_cfg),
     84	.volatile_reg = rsmu_cm_volatile_reg,
     85	.cache_type = REGCACHE_RBTREE,
     86	.can_multi_write = true,
     87};
     88
     89static const struct regmap_config rsmu_sabre_regmap_config = {
     90	.reg_bits = 8,
     91	.val_bits = 8,
     92	.max_register = 0x400,
     93	.ranges = rsmu_sabre_range_cfg,
     94	.num_ranges = ARRAY_SIZE(rsmu_sabre_range_cfg),
     95	.volatile_reg = rsmu_sabre_volatile_reg,
     96	.cache_type = REGCACHE_RBTREE,
     97	.can_multi_write = true,
     98};
     99
    100static const struct regmap_config rsmu_sl_regmap_config = {
    101	.reg_bits = 16,
    102	.val_bits = 8,
    103	.reg_format_endian = REGMAP_ENDIAN_BIG,
    104	.max_register = 0x339,
    105	.cache_type = REGCACHE_NONE,
    106	.can_multi_write = true,
    107};
    108
    109static int rsmu_i2c_probe(struct i2c_client *client,
    110			  const struct i2c_device_id *id)
    111{
    112	const struct regmap_config *cfg;
    113	struct rsmu_ddata *rsmu;
    114	int ret;
    115
    116	rsmu = devm_kzalloc(&client->dev, sizeof(*rsmu), GFP_KERNEL);
    117	if (!rsmu)
    118		return -ENOMEM;
    119
    120	i2c_set_clientdata(client, rsmu);
    121
    122	rsmu->dev = &client->dev;
    123	rsmu->type = (enum rsmu_type)id->driver_data;
    124
    125	switch (rsmu->type) {
    126	case RSMU_CM:
    127		cfg = &rsmu_cm_regmap_config;
    128		break;
    129	case RSMU_SABRE:
    130		cfg = &rsmu_sabre_regmap_config;
    131		break;
    132	case RSMU_SL:
    133		cfg = &rsmu_sl_regmap_config;
    134		break;
    135	default:
    136		dev_err(rsmu->dev, "Unsupported RSMU device type: %d\n", rsmu->type);
    137		return -ENODEV;
    138	}
    139	rsmu->regmap = devm_regmap_init_i2c(client, cfg);
    140	if (IS_ERR(rsmu->regmap)) {
    141		ret = PTR_ERR(rsmu->regmap);
    142		dev_err(rsmu->dev, "Failed to allocate register map: %d\n", ret);
    143		return ret;
    144	}
    145
    146	return rsmu_core_init(rsmu);
    147}
    148
    149static int rsmu_i2c_remove(struct i2c_client *client)
    150{
    151	struct rsmu_ddata *rsmu = i2c_get_clientdata(client);
    152
    153	rsmu_core_exit(rsmu);
    154
    155	return 0;
    156}
    157
    158static const struct i2c_device_id rsmu_i2c_id[] = {
    159	{ "8a34000",  RSMU_CM },
    160	{ "8a34001",  RSMU_CM },
    161	{ "82p33810", RSMU_SABRE },
    162	{ "82p33811", RSMU_SABRE },
    163	{ "8v19n850", RSMU_SL },
    164	{ "8v19n851", RSMU_SL },
    165	{}
    166};
    167MODULE_DEVICE_TABLE(i2c, rsmu_i2c_id);
    168
    169static const struct of_device_id rsmu_i2c_of_match[] = {
    170	{ .compatible = "idt,8a34000",  .data = (void *)RSMU_CM },
    171	{ .compatible = "idt,8a34001",  .data = (void *)RSMU_CM },
    172	{ .compatible = "idt,82p33810", .data = (void *)RSMU_SABRE },
    173	{ .compatible = "idt,82p33811", .data = (void *)RSMU_SABRE },
    174	{ .compatible = "idt,8v19n850", .data = (void *)RSMU_SL },
    175	{ .compatible = "idt,8v19n851", .data = (void *)RSMU_SL },
    176	{}
    177};
    178MODULE_DEVICE_TABLE(of, rsmu_i2c_of_match);
    179
    180static struct i2c_driver rsmu_i2c_driver = {
    181	.driver = {
    182		.name = "rsmu-i2c",
    183		.of_match_table = of_match_ptr(rsmu_i2c_of_match),
    184	},
    185	.probe = rsmu_i2c_probe,
    186	.remove	= rsmu_i2c_remove,
    187	.id_table = rsmu_i2c_id,
    188};
    189
    190static int __init rsmu_i2c_init(void)
    191{
    192	return i2c_add_driver(&rsmu_i2c_driver);
    193}
    194subsys_initcall(rsmu_i2c_init);
    195
    196static void __exit rsmu_i2c_exit(void)
    197{
    198	i2c_del_driver(&rsmu_i2c_driver);
    199}
    200module_exit(rsmu_i2c_exit);
    201
    202MODULE_DESCRIPTION("Renesas SMU I2C driver");
    203MODULE_LICENSE("GPL");