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

clk-renesas-pcie.c (8535B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Driver for Renesas 9-series PCIe clock generator driver
      4 *
      5 * The following series can be supported:
      6 *   - 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ
      7 * Currently supported:
      8 *   - 9FGV0241
      9 *
     10 * Copyright (C) 2022 Marek Vasut <marex@denx.de>
     11 */
     12
     13#include <linux/clk-provider.h>
     14#include <linux/i2c.h>
     15#include <linux/mod_devicetable.h>
     16#include <linux/module.h>
     17#include <linux/of.h>
     18#include <linux/regmap.h>
     19
     20#define RS9_REG_OE				0x0
     21#define RS9_REG_OE_DIF_OE(n)			BIT((n) + 1)
     22#define RS9_REG_SS				0x1
     23#define RS9_REG_SS_AMP_0V6			0x0
     24#define RS9_REG_SS_AMP_0V7			0x1
     25#define RS9_REG_SS_AMP_0V8			0x2
     26#define RS9_REG_SS_AMP_0V9			0x3
     27#define RS9_REG_SS_AMP_MASK			0x3
     28#define RS9_REG_SS_SSC_100			0
     29#define RS9_REG_SS_SSC_M025			(1 << 3)
     30#define RS9_REG_SS_SSC_M050			(3 << 3)
     31#define RS9_REG_SS_SSC_MASK			(3 << 3)
     32#define RS9_REG_SS_SSC_LOCK			BIT(5)
     33#define RS9_REG_SR				0x2
     34#define RS9_REG_SR_2V0_DIF(n)			0
     35#define RS9_REG_SR_3V0_DIF(n)			BIT((n) + 1)
     36#define RS9_REG_SR_DIF_MASK(n)		BIT((n) + 1)
     37#define RS9_REG_REF				0x3
     38#define RS9_REG_REF_OE				BIT(4)
     39#define RS9_REG_REF_OD				BIT(5)
     40#define RS9_REG_REF_SR_SLOWEST			0
     41#define RS9_REG_REF_SR_SLOW			(1 << 6)
     42#define RS9_REG_REF_SR_FAST			(2 << 6)
     43#define RS9_REG_REF_SR_FASTER			(3 << 6)
     44#define RS9_REG_VID				0x5
     45#define RS9_REG_DID				0x6
     46#define RS9_REG_BCP				0x7
     47
     48/* Supported Renesas 9-series models. */
     49enum rs9_model {
     50	RENESAS_9FGV0241,
     51};
     52
     53/* Structure to describe features of a particular 9-series model */
     54struct rs9_chip_info {
     55	const enum rs9_model	model;
     56	unsigned int		num_clks;
     57};
     58
     59struct rs9_driver_data {
     60	struct i2c_client	*client;
     61	struct regmap		*regmap;
     62	const struct rs9_chip_info *chip_info;
     63	struct clk		*pin_xin;
     64	struct clk_hw		*clk_dif[2];
     65	u8			pll_amplitude;
     66	u8			pll_ssc;
     67	u8			clk_dif_sr;
     68};
     69
     70/*
     71 * Renesas 9-series i2c regmap
     72 */
     73static const struct regmap_range rs9_readable_ranges[] = {
     74	regmap_reg_range(RS9_REG_OE, RS9_REG_REF),
     75	regmap_reg_range(RS9_REG_VID, RS9_REG_BCP),
     76};
     77
     78static const struct regmap_access_table rs9_readable_table = {
     79	.yes_ranges = rs9_readable_ranges,
     80	.n_yes_ranges = ARRAY_SIZE(rs9_readable_ranges),
     81};
     82
     83static const struct regmap_range rs9_writeable_ranges[] = {
     84	regmap_reg_range(RS9_REG_OE, RS9_REG_REF),
     85	regmap_reg_range(RS9_REG_BCP, RS9_REG_BCP),
     86};
     87
     88static const struct regmap_access_table rs9_writeable_table = {
     89	.yes_ranges = rs9_writeable_ranges,
     90	.n_yes_ranges = ARRAY_SIZE(rs9_writeable_ranges),
     91};
     92
     93static const struct regmap_config rs9_regmap_config = {
     94	.reg_bits = 8,
     95	.val_bits = 8,
     96	.cache_type = REGCACHE_FLAT,
     97	.max_register = 0x8,
     98	.rd_table = &rs9_readable_table,
     99	.wr_table = &rs9_writeable_table,
    100};
    101
    102static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx)
    103{
    104	struct i2c_client *client = rs9->client;
    105	unsigned char name[5] = "DIF0";
    106	struct device_node *np;
    107	int ret;
    108	u32 sr;
    109
    110	/* Set defaults */
    111	rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
    112	rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx);
    113
    114	snprintf(name, 5, "DIF%d", idx);
    115	np = of_get_child_by_name(client->dev.of_node, name);
    116	if (!np)
    117		return 0;
    118
    119	/* Output clock slew rate */
    120	ret = of_property_read_u32(np, "renesas,slew-rate", &sr);
    121	of_node_put(np);
    122	if (!ret) {
    123		if (sr == 2000000) {		/* 2V/ns */
    124			rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
    125			rs9->clk_dif_sr |= RS9_REG_SR_2V0_DIF(idx);
    126		} else if (sr == 3000000) {	/* 3V/ns (default) */
    127			rs9->clk_dif_sr &= ~RS9_REG_SR_DIF_MASK(idx);
    128			rs9->clk_dif_sr |= RS9_REG_SR_3V0_DIF(idx);
    129		} else
    130			ret = dev_err_probe(&client->dev, -EINVAL,
    131					    "Invalid renesas,slew-rate value\n");
    132	}
    133
    134	return ret;
    135}
    136
    137static int rs9_get_common_config(struct rs9_driver_data *rs9)
    138{
    139	struct i2c_client *client = rs9->client;
    140	struct device_node *np = client->dev.of_node;
    141	unsigned int amp, ssc;
    142	int ret;
    143
    144	/* Set defaults */
    145	rs9->pll_amplitude = RS9_REG_SS_AMP_0V7;
    146	rs9->pll_ssc = RS9_REG_SS_SSC_100;
    147
    148	/* Output clock amplitude */
    149	ret = of_property_read_u32(np, "renesas,out-amplitude-microvolt",
    150				   &amp);
    151	if (!ret) {
    152		if (amp == 600000)	/* 0.6V */
    153			rs9->pll_amplitude = RS9_REG_SS_AMP_0V6;
    154		else if (amp == 700000)	/* 0.7V (default) */
    155			rs9->pll_amplitude = RS9_REG_SS_AMP_0V7;
    156		else if (amp == 800000)	/* 0.8V */
    157			rs9->pll_amplitude = RS9_REG_SS_AMP_0V8;
    158		else if (amp == 900000)	/* 0.9V */
    159			rs9->pll_amplitude = RS9_REG_SS_AMP_0V9;
    160		else
    161			return dev_err_probe(&client->dev, -EINVAL,
    162					     "Invalid renesas,out-amplitude-microvolt value\n");
    163	}
    164
    165	/* Output clock spread spectrum */
    166	ret = of_property_read_u32(np, "renesas,out-spread-spectrum", &ssc);
    167	if (!ret) {
    168		if (ssc == 100000)	/* 100% ... no spread (default) */
    169			rs9->pll_ssc = RS9_REG_SS_SSC_100;
    170		else if (ssc == 99750)	/* -0.25% ... down spread */
    171			rs9->pll_ssc = RS9_REG_SS_SSC_M025;
    172		else if (ssc == 99500)	/* -0.50% ... down spread */
    173			rs9->pll_ssc = RS9_REG_SS_SSC_M050;
    174		else
    175			return dev_err_probe(&client->dev, -EINVAL,
    176					     "Invalid renesas,out-spread-spectrum value\n");
    177	}
    178
    179	return 0;
    180}
    181
    182static void rs9_update_config(struct rs9_driver_data *rs9)
    183{
    184	int i;
    185
    186	/* If amplitude is non-default, update it. */
    187	if (rs9->pll_amplitude != RS9_REG_SS_AMP_0V7) {
    188		regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_AMP_MASK,
    189				   rs9->pll_amplitude);
    190	}
    191
    192	/* If SSC is non-default, update it. */
    193	if (rs9->pll_ssc != RS9_REG_SS_SSC_100) {
    194		regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_SSC_MASK,
    195				   rs9->pll_ssc);
    196	}
    197
    198	for (i = 0; i < rs9->chip_info->num_clks; i++) {
    199		if (rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i))
    200			continue;
    201
    202		regmap_update_bits(rs9->regmap, RS9_REG_SR, RS9_REG_SR_3V0_DIF(i),
    203				   rs9->clk_dif_sr & RS9_REG_SR_3V0_DIF(i));
    204	}
    205}
    206
    207static struct clk_hw *
    208rs9_of_clk_get(struct of_phandle_args *clkspec, void *data)
    209{
    210	struct rs9_driver_data *rs9 = data;
    211	unsigned int idx = clkspec->args[0];
    212
    213	return rs9->clk_dif[idx];
    214}
    215
    216static int rs9_probe(struct i2c_client *client)
    217{
    218	unsigned char name[5] = "DIF0";
    219	struct rs9_driver_data *rs9;
    220	struct clk_hw *hw;
    221	int i, ret;
    222
    223	rs9 = devm_kzalloc(&client->dev, sizeof(*rs9), GFP_KERNEL);
    224	if (!rs9)
    225		return -ENOMEM;
    226
    227	i2c_set_clientdata(client, rs9);
    228	rs9->client = client;
    229	rs9->chip_info = device_get_match_data(&client->dev);
    230	if (!rs9->chip_info)
    231		return -EINVAL;
    232
    233	/* Fetch common configuration from DT (if specified) */
    234	ret = rs9_get_common_config(rs9);
    235	if (ret)
    236		return ret;
    237
    238	/* Fetch DIFx output configuration from DT (if specified) */
    239	for (i = 0; i < rs9->chip_info->num_clks; i++) {
    240		ret = rs9_get_output_config(rs9, i);
    241		if (ret)
    242			return ret;
    243	}
    244
    245	rs9->regmap = devm_regmap_init_i2c(client, &rs9_regmap_config);
    246	if (IS_ERR(rs9->regmap))
    247		return dev_err_probe(&client->dev, PTR_ERR(rs9->regmap),
    248				     "Failed to allocate register map\n");
    249
    250	/* Register clock */
    251	for (i = 0; i < rs9->chip_info->num_clks; i++) {
    252		snprintf(name, 5, "DIF%d", i);
    253		hw = devm_clk_hw_register_fixed_factor_index(&client->dev, name,
    254						    0, 0, 4, 1);
    255		if (IS_ERR(hw))
    256			return PTR_ERR(hw);
    257
    258		rs9->clk_dif[i] = hw;
    259	}
    260
    261	ret = devm_of_clk_add_hw_provider(&client->dev, rs9_of_clk_get, rs9);
    262	if (!ret)
    263		rs9_update_config(rs9);
    264
    265	return ret;
    266}
    267
    268static int __maybe_unused rs9_suspend(struct device *dev)
    269{
    270	struct rs9_driver_data *rs9 = dev_get_drvdata(dev);
    271
    272	regcache_cache_only(rs9->regmap, true);
    273	regcache_mark_dirty(rs9->regmap);
    274
    275	return 0;
    276}
    277
    278static int __maybe_unused rs9_resume(struct device *dev)
    279{
    280	struct rs9_driver_data *rs9 = dev_get_drvdata(dev);
    281	int ret;
    282
    283	regcache_cache_only(rs9->regmap, false);
    284	ret = regcache_sync(rs9->regmap);
    285	if (ret)
    286		dev_err(dev, "Failed to restore register map: %d\n", ret);
    287	return ret;
    288}
    289
    290static const struct rs9_chip_info renesas_9fgv0241_info = {
    291	.model		= RENESAS_9FGV0241,
    292	.num_clks	= 2,
    293};
    294
    295static const struct i2c_device_id rs9_id[] = {
    296	{ "9fgv0241", .driver_data = RENESAS_9FGV0241 },
    297	{ }
    298};
    299MODULE_DEVICE_TABLE(i2c, rs9_id);
    300
    301static const struct of_device_id clk_rs9_of_match[] = {
    302	{ .compatible = "renesas,9fgv0241", .data = &renesas_9fgv0241_info },
    303	{ }
    304};
    305MODULE_DEVICE_TABLE(of, clk_rs9_of_match);
    306
    307static SIMPLE_DEV_PM_OPS(rs9_pm_ops, rs9_suspend, rs9_resume);
    308
    309static struct i2c_driver rs9_driver = {
    310	.driver = {
    311		.name = "clk-renesas-pcie-9series",
    312		.pm	= &rs9_pm_ops,
    313		.of_match_table = clk_rs9_of_match,
    314	},
    315	.probe_new	= rs9_probe,
    316	.id_table	= rs9_id,
    317};
    318module_i2c_driver(rs9_driver);
    319
    320MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
    321MODULE_DESCRIPTION("Renesas 9-series PCIe clock generator driver");
    322MODULE_LICENSE("GPL");