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

rcar-gen2-cpg.c (9409B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * R-Car Gen2 Clock Pulse Generator
      4 *
      5 * Copyright (C) 2016 Cogent Embedded Inc.
      6 */
      7
      8#include <linux/bug.h>
      9#include <linux/clk.h>
     10#include <linux/clk-provider.h>
     11#include <linux/device.h>
     12#include <linux/err.h>
     13#include <linux/init.h>
     14#include <linux/io.h>
     15#include <linux/slab.h>
     16#include <linux/sys_soc.h>
     17
     18#include "renesas-cpg-mssr.h"
     19#include "rcar-gen2-cpg.h"
     20
     21#define CPG_FRQCRB		0x0004
     22#define CPG_FRQCRB_KICK		BIT(31)
     23#define CPG_SDCKCR		0x0074
     24#define CPG_PLL0CR		0x00d8
     25#define CPG_PLL0CR_STC_SHIFT	24
     26#define CPG_PLL0CR_STC_MASK	(0x7f << CPG_PLL0CR_STC_SHIFT)
     27#define CPG_FRQCRC		0x00e0
     28#define CPG_FRQCRC_ZFC_SHIFT	8
     29#define CPG_FRQCRC_ZFC_MASK	(0x1f << CPG_FRQCRC_ZFC_SHIFT)
     30#define CPG_ADSPCKCR		0x025c
     31#define CPG_RCANCKCR		0x0270
     32
     33static spinlock_t cpg_lock;
     34
     35/*
     36 * Z Clock
     37 *
     38 * Traits of this clock:
     39 * prepare - clk_prepare only ensures that parents are prepared
     40 * enable - clk_enable only ensures that parents are enabled
     41 * rate - rate is adjustable.  clk->rate = parent->rate * mult / 32
     42 * parent - fixed parent.  No clk_set_parent support
     43 */
     44
     45struct cpg_z_clk {
     46	struct clk_hw hw;
     47	void __iomem *reg;
     48	void __iomem *kick_reg;
     49};
     50
     51#define to_z_clk(_hw)	container_of(_hw, struct cpg_z_clk, hw)
     52
     53static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw,
     54					   unsigned long parent_rate)
     55{
     56	struct cpg_z_clk *zclk = to_z_clk(hw);
     57	unsigned int mult;
     58	unsigned int val;
     59
     60	val = (readl(zclk->reg) & CPG_FRQCRC_ZFC_MASK) >> CPG_FRQCRC_ZFC_SHIFT;
     61	mult = 32 - val;
     62
     63	return div_u64((u64)parent_rate * mult, 32);
     64}
     65
     66static int cpg_z_clk_determine_rate(struct clk_hw *hw,
     67				    struct clk_rate_request *req)
     68{
     69	unsigned long prate = req->best_parent_rate;
     70	unsigned int min_mult, max_mult, mult;
     71
     72	min_mult = max(div64_ul(req->min_rate * 32ULL, prate), 1ULL);
     73	max_mult = min(div64_ul(req->max_rate * 32ULL, prate), 32ULL);
     74	if (max_mult < min_mult)
     75		return -EINVAL;
     76
     77	mult = div64_ul(req->rate * 32ULL, prate);
     78	mult = clamp(mult, min_mult, max_mult);
     79
     80	req->rate = div_u64((u64)prate * mult, 32);
     81	return 0;
     82}
     83
     84static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
     85			      unsigned long parent_rate)
     86{
     87	struct cpg_z_clk *zclk = to_z_clk(hw);
     88	unsigned int mult;
     89	u32 val, kick;
     90	unsigned int i;
     91
     92	mult = div64_ul(rate * 32ULL, parent_rate);
     93	mult = clamp(mult, 1U, 32U);
     94
     95	if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
     96		return -EBUSY;
     97
     98	val = readl(zclk->reg);
     99	val &= ~CPG_FRQCRC_ZFC_MASK;
    100	val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;
    101	writel(val, zclk->reg);
    102
    103	/*
    104	 * Set KICK bit in FRQCRB to update hardware setting and wait for
    105	 * clock change completion.
    106	 */
    107	kick = readl(zclk->kick_reg);
    108	kick |= CPG_FRQCRB_KICK;
    109	writel(kick, zclk->kick_reg);
    110
    111	/*
    112	 * Note: There is no HW information about the worst case latency.
    113	 *
    114	 * Using experimental measurements, it seems that no more than
    115	 * ~10 iterations are needed, independently of the CPU rate.
    116	 * Since this value might be dependent on external xtal rate, pll1
    117	 * rate or even the other emulation clocks rate, use 1000 as a
    118	 * "super" safe value.
    119	 */
    120	for (i = 1000; i; i--) {
    121		if (!(readl(zclk->kick_reg) & CPG_FRQCRB_KICK))
    122			return 0;
    123
    124		cpu_relax();
    125	}
    126
    127	return -ETIMEDOUT;
    128}
    129
    130static const struct clk_ops cpg_z_clk_ops = {
    131	.recalc_rate = cpg_z_clk_recalc_rate,
    132	.determine_rate = cpg_z_clk_determine_rate,
    133	.set_rate = cpg_z_clk_set_rate,
    134};
    135
    136static struct clk * __init cpg_z_clk_register(const char *name,
    137					      const char *parent_name,
    138					      void __iomem *base)
    139{
    140	struct clk_init_data init = {};
    141	struct cpg_z_clk *zclk;
    142	struct clk *clk;
    143
    144	zclk = kzalloc(sizeof(*zclk), GFP_KERNEL);
    145	if (!zclk)
    146		return ERR_PTR(-ENOMEM);
    147
    148	init.name = name;
    149	init.ops = &cpg_z_clk_ops;
    150	init.parent_names = &parent_name;
    151	init.num_parents = 1;
    152
    153	zclk->reg = base + CPG_FRQCRC;
    154	zclk->kick_reg = base + CPG_FRQCRB;
    155	zclk->hw.init = &init;
    156
    157	clk = clk_register(NULL, &zclk->hw);
    158	if (IS_ERR(clk))
    159		kfree(zclk);
    160
    161	return clk;
    162}
    163
    164static struct clk * __init cpg_rcan_clk_register(const char *name,
    165						 const char *parent_name,
    166						 void __iomem *base)
    167{
    168	struct clk_fixed_factor *fixed;
    169	struct clk_gate *gate;
    170	struct clk *clk;
    171
    172	fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
    173	if (!fixed)
    174		return ERR_PTR(-ENOMEM);
    175
    176	fixed->mult = 1;
    177	fixed->div = 6;
    178
    179	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
    180	if (!gate) {
    181		kfree(fixed);
    182		return ERR_PTR(-ENOMEM);
    183	}
    184
    185	gate->reg = base + CPG_RCANCKCR;
    186	gate->bit_idx = 8;
    187	gate->flags = CLK_GATE_SET_TO_DISABLE;
    188	gate->lock = &cpg_lock;
    189
    190	clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
    191				     &fixed->hw, &clk_fixed_factor_ops,
    192				     &gate->hw, &clk_gate_ops, 0);
    193	if (IS_ERR(clk)) {
    194		kfree(gate);
    195		kfree(fixed);
    196	}
    197
    198	return clk;
    199}
    200
    201/* ADSP divisors */
    202static const struct clk_div_table cpg_adsp_div_table[] = {
    203	{  1,  3 }, {  2,  4 }, {  3,  6 }, {  4,  8 },
    204	{  5, 12 }, {  6, 16 }, {  7, 18 }, {  8, 24 },
    205	{ 10, 36 }, { 11, 48 }, {  0,  0 },
    206};
    207
    208static struct clk * __init cpg_adsp_clk_register(const char *name,
    209						 const char *parent_name,
    210						 void __iomem *base)
    211{
    212	struct clk_divider *div;
    213	struct clk_gate *gate;
    214	struct clk *clk;
    215
    216	div = kzalloc(sizeof(*div), GFP_KERNEL);
    217	if (!div)
    218		return ERR_PTR(-ENOMEM);
    219
    220	div->reg = base + CPG_ADSPCKCR;
    221	div->width = 4;
    222	div->table = cpg_adsp_div_table;
    223	div->lock = &cpg_lock;
    224
    225	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
    226	if (!gate) {
    227		kfree(div);
    228		return ERR_PTR(-ENOMEM);
    229	}
    230
    231	gate->reg = base + CPG_ADSPCKCR;
    232	gate->bit_idx = 8;
    233	gate->flags = CLK_GATE_SET_TO_DISABLE;
    234	gate->lock = &cpg_lock;
    235
    236	clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
    237				     &div->hw, &clk_divider_ops,
    238				     &gate->hw, &clk_gate_ops, 0);
    239	if (IS_ERR(clk)) {
    240		kfree(gate);
    241		kfree(div);
    242	}
    243
    244	return clk;
    245}
    246
    247/* SDHI divisors */
    248static const struct clk_div_table cpg_sdh_div_table[] = {
    249	{  0,  2 }, {  1,  3 }, {  2,  4 }, {  3,  6 },
    250	{  4,  8 }, {  5, 12 }, {  6, 16 }, {  7, 18 },
    251	{  8, 24 }, { 10, 36 }, { 11, 48 }, {  0,  0 },
    252};
    253
    254static const struct clk_div_table cpg_sd01_div_table[] = {
    255	{  4,  8 }, {  5, 12 }, {  6, 16 }, {  7, 18 },
    256	{  8, 24 }, { 10, 36 }, { 11, 48 }, { 12, 10 },
    257	{  0,  0 },
    258};
    259
    260static const struct rcar_gen2_cpg_pll_config *cpg_pll_config __initdata;
    261static unsigned int cpg_pll0_div __initdata;
    262static u32 cpg_mode __initdata;
    263static u32 cpg_quirks __initdata;
    264
    265#define SD_SKIP_FIRST	BIT(0)		/* Skip first clock in SD table */
    266
    267static const struct soc_device_attribute cpg_quirks_match[] __initconst = {
    268	{
    269		.soc_id = "r8a77470",
    270		.data = (void *)SD_SKIP_FIRST,
    271	},
    272	{ /* sentinel */ }
    273};
    274
    275struct clk * __init rcar_gen2_cpg_clk_register(struct device *dev,
    276	const struct cpg_core_clk *core, const struct cpg_mssr_info *info,
    277	struct clk **clks, void __iomem *base,
    278	struct raw_notifier_head *notifiers)
    279{
    280	const struct clk_div_table *table = NULL;
    281	const struct clk *parent;
    282	const char *parent_name;
    283	unsigned int mult = 1;
    284	unsigned int div = 1;
    285	unsigned int shift;
    286
    287	parent = clks[core->parent];
    288	if (IS_ERR(parent))
    289		return ERR_CAST(parent);
    290
    291	parent_name = __clk_get_name(parent);
    292
    293	switch (core->type) {
    294	/* R-Car Gen2 */
    295	case CLK_TYPE_GEN2_MAIN:
    296		div = cpg_pll_config->extal_div;
    297		break;
    298
    299	case CLK_TYPE_GEN2_PLL0:
    300		/*
    301		 * PLL0 is a  configurable multiplier clock except on R-Car
    302		 * V2H/E2. Register the PLL0 clock as a fixed factor clock for
    303		 * now as there's no generic multiplier clock implementation and
    304		 * we  currently  have no need to change  the multiplier value.
    305		 */
    306		mult = cpg_pll_config->pll0_mult;
    307		div  = cpg_pll0_div;
    308		if (!mult) {
    309			u32 pll0cr = readl(base + CPG_PLL0CR);
    310
    311			mult = (((pll0cr & CPG_PLL0CR_STC_MASK) >>
    312				 CPG_PLL0CR_STC_SHIFT) + 1) * 2;
    313		}
    314		break;
    315
    316	case CLK_TYPE_GEN2_PLL1:
    317		mult = cpg_pll_config->pll1_mult / 2;
    318		break;
    319
    320	case CLK_TYPE_GEN2_PLL3:
    321		mult = cpg_pll_config->pll3_mult;
    322		break;
    323
    324	case CLK_TYPE_GEN2_Z:
    325		return cpg_z_clk_register(core->name, parent_name, base);
    326
    327	case CLK_TYPE_GEN2_LB:
    328		div = cpg_mode & BIT(18) ? 36 : 24;
    329		break;
    330
    331	case CLK_TYPE_GEN2_ADSP:
    332		return cpg_adsp_clk_register(core->name, parent_name, base);
    333
    334	case CLK_TYPE_GEN2_SDH:
    335		table = cpg_sdh_div_table;
    336		shift = 8;
    337		break;
    338
    339	case CLK_TYPE_GEN2_SD0:
    340		table = cpg_sd01_div_table;
    341		if (cpg_quirks & SD_SKIP_FIRST)
    342			table++;
    343
    344		shift = 4;
    345		break;
    346
    347	case CLK_TYPE_GEN2_SD1:
    348		table = cpg_sd01_div_table;
    349		if (cpg_quirks & SD_SKIP_FIRST)
    350			table++;
    351
    352		shift = 0;
    353		break;
    354
    355	case CLK_TYPE_GEN2_QSPI:
    356		div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2) ?
    357		      8 : 10;
    358		break;
    359
    360	case CLK_TYPE_GEN2_RCAN:
    361		return cpg_rcan_clk_register(core->name, parent_name, base);
    362
    363	default:
    364		return ERR_PTR(-EINVAL);
    365	}
    366
    367	if (!table)
    368		return clk_register_fixed_factor(NULL, core->name, parent_name,
    369						 0, mult, div);
    370	else
    371		return clk_register_divider_table(NULL, core->name,
    372						  parent_name, 0,
    373						  base + CPG_SDCKCR, shift, 4,
    374						  0, table, &cpg_lock);
    375}
    376
    377int __init rcar_gen2_cpg_init(const struct rcar_gen2_cpg_pll_config *config,
    378			      unsigned int pll0_div, u32 mode)
    379{
    380	const struct soc_device_attribute *attr;
    381
    382	cpg_pll_config = config;
    383	cpg_pll0_div = pll0_div;
    384	cpg_mode = mode;
    385	attr = soc_device_match(cpg_quirks_match);
    386	if (attr)
    387		cpg_quirks = (uintptr_t)attr->data;
    388	pr_debug("%s: mode = 0x%x quirks = 0x%x\n", __func__, mode, cpg_quirks);
    389
    390	spin_lock_init(&cpg_lock);
    391
    392	return 0;
    393}