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

sckc.c (14845B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * drivers/clk/at91/sckc.c
      4 *
      5 *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
      6 */
      7
      8#include <linux/clk-provider.h>
      9#include <linux/clkdev.h>
     10#include <linux/delay.h>
     11#include <linux/of.h>
     12#include <linux/of_address.h>
     13#include <linux/io.h>
     14
     15#define SLOW_CLOCK_FREQ		32768
     16#define SLOWCK_SW_CYCLES	5
     17#define SLOWCK_SW_TIME_USEC	((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \
     18				 SLOW_CLOCK_FREQ)
     19
     20#define	AT91_SCKC_CR			0x00
     21
     22struct clk_slow_bits {
     23	u32 cr_rcen;
     24	u32 cr_osc32en;
     25	u32 cr_osc32byp;
     26	u32 cr_oscsel;
     27};
     28
     29struct clk_slow_osc {
     30	struct clk_hw hw;
     31	void __iomem *sckcr;
     32	const struct clk_slow_bits *bits;
     33	unsigned long startup_usec;
     34};
     35
     36#define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw)
     37
     38struct clk_sama5d4_slow_osc {
     39	struct clk_hw hw;
     40	void __iomem *sckcr;
     41	const struct clk_slow_bits *bits;
     42	unsigned long startup_usec;
     43	bool prepared;
     44};
     45
     46#define to_clk_sama5d4_slow_osc(hw) container_of(hw, struct clk_sama5d4_slow_osc, hw)
     47
     48struct clk_slow_rc_osc {
     49	struct clk_hw hw;
     50	void __iomem *sckcr;
     51	const struct clk_slow_bits *bits;
     52	unsigned long frequency;
     53	unsigned long accuracy;
     54	unsigned long startup_usec;
     55};
     56
     57#define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw)
     58
     59struct clk_sam9x5_slow {
     60	struct clk_hw hw;
     61	void __iomem *sckcr;
     62	const struct clk_slow_bits *bits;
     63	u8 parent;
     64};
     65
     66#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
     67
     68static int clk_slow_osc_prepare(struct clk_hw *hw)
     69{
     70	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
     71	void __iomem *sckcr = osc->sckcr;
     72	u32 tmp = readl(sckcr);
     73
     74	if (tmp & (osc->bits->cr_osc32byp | osc->bits->cr_osc32en))
     75		return 0;
     76
     77	writel(tmp | osc->bits->cr_osc32en, sckcr);
     78
     79	if (system_state < SYSTEM_RUNNING)
     80		udelay(osc->startup_usec);
     81	else
     82		usleep_range(osc->startup_usec, osc->startup_usec + 1);
     83
     84	return 0;
     85}
     86
     87static void clk_slow_osc_unprepare(struct clk_hw *hw)
     88{
     89	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
     90	void __iomem *sckcr = osc->sckcr;
     91	u32 tmp = readl(sckcr);
     92
     93	if (tmp & osc->bits->cr_osc32byp)
     94		return;
     95
     96	writel(tmp & ~osc->bits->cr_osc32en, sckcr);
     97}
     98
     99static int clk_slow_osc_is_prepared(struct clk_hw *hw)
    100{
    101	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
    102	void __iomem *sckcr = osc->sckcr;
    103	u32 tmp = readl(sckcr);
    104
    105	if (tmp & osc->bits->cr_osc32byp)
    106		return 1;
    107
    108	return !!(tmp & osc->bits->cr_osc32en);
    109}
    110
    111static const struct clk_ops slow_osc_ops = {
    112	.prepare = clk_slow_osc_prepare,
    113	.unprepare = clk_slow_osc_unprepare,
    114	.is_prepared = clk_slow_osc_is_prepared,
    115};
    116
    117static struct clk_hw * __init
    118at91_clk_register_slow_osc(void __iomem *sckcr,
    119			   const char *name,
    120			   const char *parent_name,
    121			   unsigned long startup,
    122			   bool bypass,
    123			   const struct clk_slow_bits *bits)
    124{
    125	struct clk_slow_osc *osc;
    126	struct clk_hw *hw;
    127	struct clk_init_data init;
    128	int ret;
    129
    130	if (!sckcr || !name || !parent_name)
    131		return ERR_PTR(-EINVAL);
    132
    133	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
    134	if (!osc)
    135		return ERR_PTR(-ENOMEM);
    136
    137	init.name = name;
    138	init.ops = &slow_osc_ops;
    139	init.parent_names = &parent_name;
    140	init.num_parents = 1;
    141	init.flags = CLK_IGNORE_UNUSED;
    142
    143	osc->hw.init = &init;
    144	osc->sckcr = sckcr;
    145	osc->startup_usec = startup;
    146	osc->bits = bits;
    147
    148	if (bypass)
    149		writel((readl(sckcr) & ~osc->bits->cr_osc32en) |
    150					osc->bits->cr_osc32byp, sckcr);
    151
    152	hw = &osc->hw;
    153	ret = clk_hw_register(NULL, &osc->hw);
    154	if (ret) {
    155		kfree(osc);
    156		hw = ERR_PTR(ret);
    157	}
    158
    159	return hw;
    160}
    161
    162static void at91_clk_unregister_slow_osc(struct clk_hw *hw)
    163{
    164	struct clk_slow_osc *osc = to_clk_slow_osc(hw);
    165
    166	clk_hw_unregister(hw);
    167	kfree(osc);
    168}
    169
    170static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
    171						 unsigned long parent_rate)
    172{
    173	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
    174
    175	return osc->frequency;
    176}
    177
    178static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw,
    179						     unsigned long parent_acc)
    180{
    181	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
    182
    183	return osc->accuracy;
    184}
    185
    186static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
    187{
    188	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
    189	void __iomem *sckcr = osc->sckcr;
    190
    191	writel(readl(sckcr) | osc->bits->cr_rcen, sckcr);
    192
    193	if (system_state < SYSTEM_RUNNING)
    194		udelay(osc->startup_usec);
    195	else
    196		usleep_range(osc->startup_usec, osc->startup_usec + 1);
    197
    198	return 0;
    199}
    200
    201static void clk_slow_rc_osc_unprepare(struct clk_hw *hw)
    202{
    203	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
    204	void __iomem *sckcr = osc->sckcr;
    205
    206	writel(readl(sckcr) & ~osc->bits->cr_rcen, sckcr);
    207}
    208
    209static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw)
    210{
    211	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
    212
    213	return !!(readl(osc->sckcr) & osc->bits->cr_rcen);
    214}
    215
    216static const struct clk_ops slow_rc_osc_ops = {
    217	.prepare = clk_slow_rc_osc_prepare,
    218	.unprepare = clk_slow_rc_osc_unprepare,
    219	.is_prepared = clk_slow_rc_osc_is_prepared,
    220	.recalc_rate = clk_slow_rc_osc_recalc_rate,
    221	.recalc_accuracy = clk_slow_rc_osc_recalc_accuracy,
    222};
    223
    224static struct clk_hw * __init
    225at91_clk_register_slow_rc_osc(void __iomem *sckcr,
    226			      const char *name,
    227			      unsigned long frequency,
    228			      unsigned long accuracy,
    229			      unsigned long startup,
    230			      const struct clk_slow_bits *bits)
    231{
    232	struct clk_slow_rc_osc *osc;
    233	struct clk_hw *hw;
    234	struct clk_init_data init;
    235	int ret;
    236
    237	if (!sckcr || !name)
    238		return ERR_PTR(-EINVAL);
    239
    240	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
    241	if (!osc)
    242		return ERR_PTR(-ENOMEM);
    243
    244	init.name = name;
    245	init.ops = &slow_rc_osc_ops;
    246	init.parent_names = NULL;
    247	init.num_parents = 0;
    248	init.flags = CLK_IGNORE_UNUSED;
    249
    250	osc->hw.init = &init;
    251	osc->sckcr = sckcr;
    252	osc->bits = bits;
    253	osc->frequency = frequency;
    254	osc->accuracy = accuracy;
    255	osc->startup_usec = startup;
    256
    257	hw = &osc->hw;
    258	ret = clk_hw_register(NULL, &osc->hw);
    259	if (ret) {
    260		kfree(osc);
    261		hw = ERR_PTR(ret);
    262	}
    263
    264	return hw;
    265}
    266
    267static void at91_clk_unregister_slow_rc_osc(struct clk_hw *hw)
    268{
    269	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw);
    270
    271	clk_hw_unregister(hw);
    272	kfree(osc);
    273}
    274
    275static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
    276{
    277	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
    278	void __iomem *sckcr = slowck->sckcr;
    279	u32 tmp;
    280
    281	if (index > 1)
    282		return -EINVAL;
    283
    284	tmp = readl(sckcr);
    285
    286	if ((!index && !(tmp & slowck->bits->cr_oscsel)) ||
    287	    (index && (tmp & slowck->bits->cr_oscsel)))
    288		return 0;
    289
    290	if (index)
    291		tmp |= slowck->bits->cr_oscsel;
    292	else
    293		tmp &= ~slowck->bits->cr_oscsel;
    294
    295	writel(tmp, sckcr);
    296
    297	if (system_state < SYSTEM_RUNNING)
    298		udelay(SLOWCK_SW_TIME_USEC);
    299	else
    300		usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
    301
    302	return 0;
    303}
    304
    305static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw)
    306{
    307	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
    308
    309	return !!(readl(slowck->sckcr) & slowck->bits->cr_oscsel);
    310}
    311
    312static const struct clk_ops sam9x5_slow_ops = {
    313	.set_parent = clk_sam9x5_slow_set_parent,
    314	.get_parent = clk_sam9x5_slow_get_parent,
    315};
    316
    317static struct clk_hw * __init
    318at91_clk_register_sam9x5_slow(void __iomem *sckcr,
    319			      const char *name,
    320			      const char **parent_names,
    321			      int num_parents,
    322			      const struct clk_slow_bits *bits)
    323{
    324	struct clk_sam9x5_slow *slowck;
    325	struct clk_hw *hw;
    326	struct clk_init_data init;
    327	int ret;
    328
    329	if (!sckcr || !name || !parent_names || !num_parents)
    330		return ERR_PTR(-EINVAL);
    331
    332	slowck = kzalloc(sizeof(*slowck), GFP_KERNEL);
    333	if (!slowck)
    334		return ERR_PTR(-ENOMEM);
    335
    336	init.name = name;
    337	init.ops = &sam9x5_slow_ops;
    338	init.parent_names = parent_names;
    339	init.num_parents = num_parents;
    340	init.flags = 0;
    341
    342	slowck->hw.init = &init;
    343	slowck->sckcr = sckcr;
    344	slowck->bits = bits;
    345	slowck->parent = !!(readl(sckcr) & slowck->bits->cr_oscsel);
    346
    347	hw = &slowck->hw;
    348	ret = clk_hw_register(NULL, &slowck->hw);
    349	if (ret) {
    350		kfree(slowck);
    351		hw = ERR_PTR(ret);
    352	}
    353
    354	return hw;
    355}
    356
    357static void at91_clk_unregister_sam9x5_slow(struct clk_hw *hw)
    358{
    359	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
    360
    361	clk_hw_unregister(hw);
    362	kfree(slowck);
    363}
    364
    365static void __init at91sam9x5_sckc_register(struct device_node *np,
    366					    unsigned int rc_osc_startup_us,
    367					    const struct clk_slow_bits *bits)
    368{
    369	const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
    370	void __iomem *regbase = of_iomap(np, 0);
    371	struct device_node *child = NULL;
    372	const char *xtal_name;
    373	struct clk_hw *slow_rc, *slow_osc, *slowck;
    374	bool bypass;
    375	int ret;
    376
    377	if (!regbase)
    378		return;
    379
    380	slow_rc = at91_clk_register_slow_rc_osc(regbase, parent_names[0],
    381						32768, 50000000,
    382						rc_osc_startup_us, bits);
    383	if (IS_ERR(slow_rc))
    384		return;
    385
    386	xtal_name = of_clk_get_parent_name(np, 0);
    387	if (!xtal_name) {
    388		/* DT backward compatibility */
    389		child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
    390		if (!child)
    391			goto unregister_slow_rc;
    392
    393		xtal_name = of_clk_get_parent_name(child, 0);
    394		bypass = of_property_read_bool(child, "atmel,osc-bypass");
    395
    396		child =  of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow");
    397	} else {
    398		bypass = of_property_read_bool(np, "atmel,osc-bypass");
    399	}
    400
    401	if (!xtal_name)
    402		goto unregister_slow_rc;
    403
    404	slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
    405					      xtal_name, 1200000, bypass, bits);
    406	if (IS_ERR(slow_osc))
    407		goto unregister_slow_rc;
    408
    409	slowck = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names,
    410					       2, bits);
    411	if (IS_ERR(slowck))
    412		goto unregister_slow_osc;
    413
    414	/* DT backward compatibility */
    415	if (child)
    416		ret = of_clk_add_hw_provider(child, of_clk_hw_simple_get,
    417					     slowck);
    418	else
    419		ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
    420
    421	if (WARN_ON(ret))
    422		goto unregister_slowck;
    423
    424	return;
    425
    426unregister_slowck:
    427	at91_clk_unregister_sam9x5_slow(slowck);
    428unregister_slow_osc:
    429	at91_clk_unregister_slow_osc(slow_osc);
    430unregister_slow_rc:
    431	at91_clk_unregister_slow_rc_osc(slow_rc);
    432}
    433
    434static const struct clk_slow_bits at91sam9x5_bits = {
    435	.cr_rcen = BIT(0),
    436	.cr_osc32en = BIT(1),
    437	.cr_osc32byp = BIT(2),
    438	.cr_oscsel = BIT(3),
    439};
    440
    441static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
    442{
    443	at91sam9x5_sckc_register(np, 75, &at91sam9x5_bits);
    444}
    445CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
    446	       of_at91sam9x5_sckc_setup);
    447
    448static void __init of_sama5d3_sckc_setup(struct device_node *np)
    449{
    450	at91sam9x5_sckc_register(np, 500, &at91sam9x5_bits);
    451}
    452CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
    453	       of_sama5d3_sckc_setup);
    454
    455static const struct clk_slow_bits at91sam9x60_bits = {
    456	.cr_osc32en = BIT(1),
    457	.cr_osc32byp = BIT(2),
    458	.cr_oscsel = BIT(24),
    459};
    460
    461static void __init of_sam9x60_sckc_setup(struct device_node *np)
    462{
    463	void __iomem *regbase = of_iomap(np, 0);
    464	struct clk_hw_onecell_data *clk_data;
    465	struct clk_hw *slow_rc, *slow_osc;
    466	const char *xtal_name;
    467	const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
    468	bool bypass;
    469	int ret;
    470
    471	if (!regbase)
    472		return;
    473
    474	slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
    475							   NULL, 0, 32768,
    476							   93750000);
    477	if (IS_ERR(slow_rc))
    478		return;
    479
    480	xtal_name = of_clk_get_parent_name(np, 0);
    481	if (!xtal_name)
    482		goto unregister_slow_rc;
    483
    484	bypass = of_property_read_bool(np, "atmel,osc-bypass");
    485	slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1],
    486					      xtal_name, 5000000, bypass,
    487					      &at91sam9x60_bits);
    488	if (IS_ERR(slow_osc))
    489		goto unregister_slow_rc;
    490
    491	clk_data = kzalloc(struct_size(clk_data, hws, 2), GFP_KERNEL);
    492	if (!clk_data)
    493		goto unregister_slow_osc;
    494
    495	/* MD_SLCK and TD_SLCK. */
    496	clk_data->num = 2;
    497	clk_data->hws[0] = clk_hw_register_fixed_rate(NULL, "md_slck",
    498						      parent_names[0],
    499						      0, 32768);
    500	if (IS_ERR(clk_data->hws[0]))
    501		goto clk_data_free;
    502
    503	clk_data->hws[1] = at91_clk_register_sam9x5_slow(regbase, "td_slck",
    504							 parent_names, 2,
    505							 &at91sam9x60_bits);
    506	if (IS_ERR(clk_data->hws[1]))
    507		goto unregister_md_slck;
    508
    509	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
    510	if (WARN_ON(ret))
    511		goto unregister_td_slck;
    512
    513	return;
    514
    515unregister_td_slck:
    516	at91_clk_unregister_sam9x5_slow(clk_data->hws[1]);
    517unregister_md_slck:
    518	clk_hw_unregister(clk_data->hws[0]);
    519clk_data_free:
    520	kfree(clk_data);
    521unregister_slow_osc:
    522	at91_clk_unregister_slow_osc(slow_osc);
    523unregister_slow_rc:
    524	clk_hw_unregister(slow_rc);
    525}
    526CLK_OF_DECLARE(sam9x60_clk_sckc, "microchip,sam9x60-sckc",
    527	       of_sam9x60_sckc_setup);
    528
    529static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
    530{
    531	struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
    532
    533	if (osc->prepared)
    534		return 0;
    535
    536	/*
    537	 * Assume that if it has already been selected (for example by the
    538	 * bootloader), enough time has already passed.
    539	 */
    540	if ((readl(osc->sckcr) & osc->bits->cr_oscsel)) {
    541		osc->prepared = true;
    542		return 0;
    543	}
    544
    545	if (system_state < SYSTEM_RUNNING)
    546		udelay(osc->startup_usec);
    547	else
    548		usleep_range(osc->startup_usec, osc->startup_usec + 1);
    549	osc->prepared = true;
    550
    551	return 0;
    552}
    553
    554static int clk_sama5d4_slow_osc_is_prepared(struct clk_hw *hw)
    555{
    556	struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
    557
    558	return osc->prepared;
    559}
    560
    561static const struct clk_ops sama5d4_slow_osc_ops = {
    562	.prepare = clk_sama5d4_slow_osc_prepare,
    563	.is_prepared = clk_sama5d4_slow_osc_is_prepared,
    564};
    565
    566static const struct clk_slow_bits at91sama5d4_bits = {
    567	.cr_oscsel = BIT(3),
    568};
    569
    570static void __init of_sama5d4_sckc_setup(struct device_node *np)
    571{
    572	void __iomem *regbase = of_iomap(np, 0);
    573	struct clk_hw *slow_rc, *slowck;
    574	struct clk_sama5d4_slow_osc *osc;
    575	struct clk_init_data init;
    576	const char *xtal_name;
    577	const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
    578	int ret;
    579
    580	if (!regbase)
    581		return;
    582
    583	slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL,
    584							   parent_names[0],
    585							   NULL, 0, 32768,
    586							   250000000);
    587	if (IS_ERR(slow_rc))
    588		return;
    589
    590	xtal_name = of_clk_get_parent_name(np, 0);
    591
    592	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
    593	if (!osc)
    594		goto unregister_slow_rc;
    595
    596	init.name = parent_names[1];
    597	init.ops = &sama5d4_slow_osc_ops;
    598	init.parent_names = &xtal_name;
    599	init.num_parents = 1;
    600	init.flags = CLK_IGNORE_UNUSED;
    601
    602	osc->hw.init = &init;
    603	osc->sckcr = regbase;
    604	osc->startup_usec = 1200000;
    605	osc->bits = &at91sama5d4_bits;
    606
    607	ret = clk_hw_register(NULL, &osc->hw);
    608	if (ret)
    609		goto free_slow_osc_data;
    610
    611	slowck = at91_clk_register_sam9x5_slow(regbase, "slowck",
    612					       parent_names, 2,
    613					       &at91sama5d4_bits);
    614	if (IS_ERR(slowck))
    615		goto unregister_slow_osc;
    616
    617	ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck);
    618	if (WARN_ON(ret))
    619		goto unregister_slowck;
    620
    621	return;
    622
    623unregister_slowck:
    624	at91_clk_unregister_sam9x5_slow(slowck);
    625unregister_slow_osc:
    626	clk_hw_unregister(&osc->hw);
    627free_slow_osc_data:
    628	kfree(osc);
    629unregister_slow_rc:
    630	clk_hw_unregister(slow_rc);
    631}
    632CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
    633	       of_sama5d4_sckc_setup);