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-main.c (13289B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
      4 */
      5
      6#include <linux/clk-provider.h>
      7#include <linux/clkdev.h>
      8#include <linux/clk/at91_pmc.h>
      9#include <linux/delay.h>
     10#include <linux/mfd/syscon.h>
     11#include <linux/regmap.h>
     12
     13#include "pmc.h"
     14
     15#define SLOW_CLOCK_FREQ		32768
     16#define MAINF_DIV		16
     17#define MAINFRDY_TIMEOUT	(((MAINF_DIV + 1) * USEC_PER_SEC) / \
     18				 SLOW_CLOCK_FREQ)
     19#define MAINF_LOOP_MIN_WAIT	(USEC_PER_SEC / SLOW_CLOCK_FREQ)
     20#define MAINF_LOOP_MAX_WAIT	MAINFRDY_TIMEOUT
     21
     22#define MOR_KEY_MASK		(0xff << 16)
     23
     24#define clk_main_parent_select(s)	(((s) & \
     25					(AT91_PMC_MOSCEN | \
     26					AT91_PMC_OSCBYPASS)) ? 1 : 0)
     27
     28struct clk_main_osc {
     29	struct clk_hw hw;
     30	struct regmap *regmap;
     31	struct at91_clk_pms pms;
     32};
     33
     34#define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw)
     35
     36struct clk_main_rc_osc {
     37	struct clk_hw hw;
     38	struct regmap *regmap;
     39	unsigned long frequency;
     40	unsigned long accuracy;
     41	struct at91_clk_pms pms;
     42};
     43
     44#define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw)
     45
     46struct clk_rm9200_main {
     47	struct clk_hw hw;
     48	struct regmap *regmap;
     49};
     50
     51#define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw)
     52
     53struct clk_sam9x5_main {
     54	struct clk_hw hw;
     55	struct regmap *regmap;
     56	struct at91_clk_pms pms;
     57	u8 parent;
     58};
     59
     60#define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw)
     61
     62static inline bool clk_main_osc_ready(struct regmap *regmap)
     63{
     64	unsigned int status;
     65
     66	regmap_read(regmap, AT91_PMC_SR, &status);
     67
     68	return status & AT91_PMC_MOSCS;
     69}
     70
     71static int clk_main_osc_prepare(struct clk_hw *hw)
     72{
     73	struct clk_main_osc *osc = to_clk_main_osc(hw);
     74	struct regmap *regmap = osc->regmap;
     75	u32 tmp;
     76
     77	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
     78	tmp &= ~MOR_KEY_MASK;
     79
     80	if (tmp & AT91_PMC_OSCBYPASS)
     81		return 0;
     82
     83	if (!(tmp & AT91_PMC_MOSCEN)) {
     84		tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
     85		regmap_write(regmap, AT91_CKGR_MOR, tmp);
     86	}
     87
     88	while (!clk_main_osc_ready(regmap))
     89		cpu_relax();
     90
     91	return 0;
     92}
     93
     94static void clk_main_osc_unprepare(struct clk_hw *hw)
     95{
     96	struct clk_main_osc *osc = to_clk_main_osc(hw);
     97	struct regmap *regmap = osc->regmap;
     98	u32 tmp;
     99
    100	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
    101	if (tmp & AT91_PMC_OSCBYPASS)
    102		return;
    103
    104	if (!(tmp & AT91_PMC_MOSCEN))
    105		return;
    106
    107	tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
    108	regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
    109}
    110
    111static int clk_main_osc_is_prepared(struct clk_hw *hw)
    112{
    113	struct clk_main_osc *osc = to_clk_main_osc(hw);
    114	struct regmap *regmap = osc->regmap;
    115	u32 tmp, status;
    116
    117	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
    118	if (tmp & AT91_PMC_OSCBYPASS)
    119		return 1;
    120
    121	regmap_read(regmap, AT91_PMC_SR, &status);
    122
    123	return (status & AT91_PMC_MOSCS) && clk_main_parent_select(tmp);
    124}
    125
    126static int clk_main_osc_save_context(struct clk_hw *hw)
    127{
    128	struct clk_main_osc *osc = to_clk_main_osc(hw);
    129
    130	osc->pms.status = clk_main_osc_is_prepared(hw);
    131
    132	return 0;
    133}
    134
    135static void clk_main_osc_restore_context(struct clk_hw *hw)
    136{
    137	struct clk_main_osc *osc = to_clk_main_osc(hw);
    138
    139	if (osc->pms.status)
    140		clk_main_osc_prepare(hw);
    141}
    142
    143static const struct clk_ops main_osc_ops = {
    144	.prepare = clk_main_osc_prepare,
    145	.unprepare = clk_main_osc_unprepare,
    146	.is_prepared = clk_main_osc_is_prepared,
    147	.save_context = clk_main_osc_save_context,
    148	.restore_context = clk_main_osc_restore_context,
    149};
    150
    151struct clk_hw * __init
    152at91_clk_register_main_osc(struct regmap *regmap,
    153			   const char *name,
    154			   const char *parent_name,
    155			   bool bypass)
    156{
    157	struct clk_main_osc *osc;
    158	struct clk_init_data init;
    159	struct clk_hw *hw;
    160	int ret;
    161
    162	if (!name || !parent_name)
    163		return ERR_PTR(-EINVAL);
    164
    165	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
    166	if (!osc)
    167		return ERR_PTR(-ENOMEM);
    168
    169	init.name = name;
    170	init.ops = &main_osc_ops;
    171	init.parent_names = &parent_name;
    172	init.num_parents = 1;
    173	init.flags = CLK_IGNORE_UNUSED;
    174
    175	osc->hw.init = &init;
    176	osc->regmap = regmap;
    177
    178	if (bypass)
    179		regmap_update_bits(regmap,
    180				   AT91_CKGR_MOR, MOR_KEY_MASK |
    181				   AT91_PMC_OSCBYPASS,
    182				   AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
    183
    184	hw = &osc->hw;
    185	ret = clk_hw_register(NULL, &osc->hw);
    186	if (ret) {
    187		kfree(osc);
    188		hw = ERR_PTR(ret);
    189	}
    190
    191	return hw;
    192}
    193
    194static bool clk_main_rc_osc_ready(struct regmap *regmap)
    195{
    196	unsigned int status;
    197
    198	regmap_read(regmap, AT91_PMC_SR, &status);
    199
    200	return !!(status & AT91_PMC_MOSCRCS);
    201}
    202
    203static int clk_main_rc_osc_prepare(struct clk_hw *hw)
    204{
    205	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
    206	struct regmap *regmap = osc->regmap;
    207	unsigned int mor;
    208
    209	regmap_read(regmap, AT91_CKGR_MOR, &mor);
    210
    211	if (!(mor & AT91_PMC_MOSCRCEN))
    212		regmap_update_bits(regmap, AT91_CKGR_MOR,
    213				   MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
    214				   AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
    215
    216	while (!clk_main_rc_osc_ready(regmap))
    217		cpu_relax();
    218
    219	return 0;
    220}
    221
    222static void clk_main_rc_osc_unprepare(struct clk_hw *hw)
    223{
    224	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
    225	struct regmap *regmap = osc->regmap;
    226	unsigned int mor;
    227
    228	regmap_read(regmap, AT91_CKGR_MOR, &mor);
    229
    230	if (!(mor & AT91_PMC_MOSCRCEN))
    231		return;
    232
    233	regmap_update_bits(regmap, AT91_CKGR_MOR,
    234			   MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
    235}
    236
    237static int clk_main_rc_osc_is_prepared(struct clk_hw *hw)
    238{
    239	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
    240	struct regmap *regmap = osc->regmap;
    241	unsigned int mor, status;
    242
    243	regmap_read(regmap, AT91_CKGR_MOR, &mor);
    244	regmap_read(regmap, AT91_PMC_SR, &status);
    245
    246	return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);
    247}
    248
    249static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw,
    250						 unsigned long parent_rate)
    251{
    252	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
    253
    254	return osc->frequency;
    255}
    256
    257static unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw,
    258						     unsigned long parent_acc)
    259{
    260	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
    261
    262	return osc->accuracy;
    263}
    264
    265static int clk_main_rc_osc_save_context(struct clk_hw *hw)
    266{
    267	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
    268
    269	osc->pms.status = clk_main_rc_osc_is_prepared(hw);
    270
    271	return 0;
    272}
    273
    274static void clk_main_rc_osc_restore_context(struct clk_hw *hw)
    275{
    276	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw);
    277
    278	if (osc->pms.status)
    279		clk_main_rc_osc_prepare(hw);
    280}
    281
    282static const struct clk_ops main_rc_osc_ops = {
    283	.prepare = clk_main_rc_osc_prepare,
    284	.unprepare = clk_main_rc_osc_unprepare,
    285	.is_prepared = clk_main_rc_osc_is_prepared,
    286	.recalc_rate = clk_main_rc_osc_recalc_rate,
    287	.recalc_accuracy = clk_main_rc_osc_recalc_accuracy,
    288	.save_context = clk_main_rc_osc_save_context,
    289	.restore_context = clk_main_rc_osc_restore_context,
    290};
    291
    292struct clk_hw * __init
    293at91_clk_register_main_rc_osc(struct regmap *regmap,
    294			      const char *name,
    295			      u32 frequency, u32 accuracy)
    296{
    297	struct clk_main_rc_osc *osc;
    298	struct clk_init_data init;
    299	struct clk_hw *hw;
    300	int ret;
    301
    302	if (!name || !frequency)
    303		return ERR_PTR(-EINVAL);
    304
    305	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
    306	if (!osc)
    307		return ERR_PTR(-ENOMEM);
    308
    309	init.name = name;
    310	init.ops = &main_rc_osc_ops;
    311	init.parent_names = NULL;
    312	init.num_parents = 0;
    313	init.flags = CLK_IGNORE_UNUSED;
    314
    315	osc->hw.init = &init;
    316	osc->regmap = regmap;
    317	osc->frequency = frequency;
    318	osc->accuracy = accuracy;
    319
    320	hw = &osc->hw;
    321	ret = clk_hw_register(NULL, hw);
    322	if (ret) {
    323		kfree(osc);
    324		hw = ERR_PTR(ret);
    325	}
    326
    327	return hw;
    328}
    329
    330static int clk_main_probe_frequency(struct regmap *regmap)
    331{
    332	unsigned long prep_time, timeout;
    333	unsigned int mcfr;
    334
    335	timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT);
    336	do {
    337		prep_time = jiffies;
    338		regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
    339		if (mcfr & AT91_PMC_MAINRDY)
    340			return 0;
    341		if (system_state < SYSTEM_RUNNING)
    342			udelay(MAINF_LOOP_MIN_WAIT);
    343		else
    344			usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
    345	} while (time_before(prep_time, timeout));
    346
    347	return -ETIMEDOUT;
    348}
    349
    350static unsigned long clk_main_recalc_rate(struct regmap *regmap,
    351					  unsigned long parent_rate)
    352{
    353	unsigned int mcfr;
    354
    355	if (parent_rate)
    356		return parent_rate;
    357
    358	pr_warn("Main crystal frequency not set, using approximate value\n");
    359	regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
    360	if (!(mcfr & AT91_PMC_MAINRDY))
    361		return 0;
    362
    363	return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
    364}
    365
    366static int clk_rm9200_main_prepare(struct clk_hw *hw)
    367{
    368	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
    369
    370	return clk_main_probe_frequency(clkmain->regmap);
    371}
    372
    373static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
    374{
    375	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
    376	unsigned int status;
    377
    378	regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
    379
    380	return !!(status & AT91_PMC_MAINRDY);
    381}
    382
    383static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
    384						 unsigned long parent_rate)
    385{
    386	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw);
    387
    388	return clk_main_recalc_rate(clkmain->regmap, parent_rate);
    389}
    390
    391static const struct clk_ops rm9200_main_ops = {
    392	.prepare = clk_rm9200_main_prepare,
    393	.is_prepared = clk_rm9200_main_is_prepared,
    394	.recalc_rate = clk_rm9200_main_recalc_rate,
    395};
    396
    397struct clk_hw * __init
    398at91_clk_register_rm9200_main(struct regmap *regmap,
    399			      const char *name,
    400			      const char *parent_name)
    401{
    402	struct clk_rm9200_main *clkmain;
    403	struct clk_init_data init;
    404	struct clk_hw *hw;
    405	int ret;
    406
    407	if (!name)
    408		return ERR_PTR(-EINVAL);
    409
    410	if (!parent_name)
    411		return ERR_PTR(-EINVAL);
    412
    413	clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
    414	if (!clkmain)
    415		return ERR_PTR(-ENOMEM);
    416
    417	init.name = name;
    418	init.ops = &rm9200_main_ops;
    419	init.parent_names = &parent_name;
    420	init.num_parents = 1;
    421	init.flags = 0;
    422
    423	clkmain->hw.init = &init;
    424	clkmain->regmap = regmap;
    425
    426	hw = &clkmain->hw;
    427	ret = clk_hw_register(NULL, &clkmain->hw);
    428	if (ret) {
    429		kfree(clkmain);
    430		hw = ERR_PTR(ret);
    431	}
    432
    433	return hw;
    434}
    435
    436static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
    437{
    438	unsigned int status;
    439
    440	regmap_read(regmap, AT91_PMC_SR, &status);
    441
    442	return !!(status & AT91_PMC_MOSCSELS);
    443}
    444
    445static int clk_sam9x5_main_prepare(struct clk_hw *hw)
    446{
    447	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
    448	struct regmap *regmap = clkmain->regmap;
    449
    450	while (!clk_sam9x5_main_ready(regmap))
    451		cpu_relax();
    452
    453	return clk_main_probe_frequency(regmap);
    454}
    455
    456static int clk_sam9x5_main_is_prepared(struct clk_hw *hw)
    457{
    458	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
    459
    460	return clk_sam9x5_main_ready(clkmain->regmap);
    461}
    462
    463static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw,
    464						 unsigned long parent_rate)
    465{
    466	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
    467
    468	return clk_main_recalc_rate(clkmain->regmap, parent_rate);
    469}
    470
    471static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index)
    472{
    473	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
    474	struct regmap *regmap = clkmain->regmap;
    475	unsigned int tmp;
    476
    477	if (index > 1)
    478		return -EINVAL;
    479
    480	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
    481
    482	if (index && !(tmp & AT91_PMC_MOSCSEL))
    483		tmp = AT91_PMC_MOSCSEL;
    484	else if (!index && (tmp & AT91_PMC_MOSCSEL))
    485		tmp = 0;
    486	else
    487		return 0;
    488
    489	regmap_update_bits(regmap, AT91_CKGR_MOR,
    490			   AT91_PMC_MOSCSEL | MOR_KEY_MASK,
    491			   tmp | AT91_PMC_KEY);
    492
    493	while (!clk_sam9x5_main_ready(regmap))
    494		cpu_relax();
    495
    496	return 0;
    497}
    498
    499static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw)
    500{
    501	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
    502	unsigned int status;
    503
    504	regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
    505
    506	return clk_main_parent_select(status);
    507}
    508
    509static int clk_sam9x5_main_save_context(struct clk_hw *hw)
    510{
    511	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
    512
    513	clkmain->pms.status = clk_main_rc_osc_is_prepared(&clkmain->hw);
    514	clkmain->pms.parent = clk_sam9x5_main_get_parent(&clkmain->hw);
    515
    516	return 0;
    517}
    518
    519static void clk_sam9x5_main_restore_context(struct clk_hw *hw)
    520{
    521	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw);
    522	int ret;
    523
    524	ret = clk_sam9x5_main_set_parent(hw, clkmain->pms.parent);
    525	if (ret)
    526		return;
    527
    528	if (clkmain->pms.status)
    529		clk_sam9x5_main_prepare(hw);
    530}
    531
    532static const struct clk_ops sam9x5_main_ops = {
    533	.prepare = clk_sam9x5_main_prepare,
    534	.is_prepared = clk_sam9x5_main_is_prepared,
    535	.recalc_rate = clk_sam9x5_main_recalc_rate,
    536	.set_parent = clk_sam9x5_main_set_parent,
    537	.get_parent = clk_sam9x5_main_get_parent,
    538	.save_context = clk_sam9x5_main_save_context,
    539	.restore_context = clk_sam9x5_main_restore_context,
    540};
    541
    542struct clk_hw * __init
    543at91_clk_register_sam9x5_main(struct regmap *regmap,
    544			      const char *name,
    545			      const char **parent_names,
    546			      int num_parents)
    547{
    548	struct clk_sam9x5_main *clkmain;
    549	struct clk_init_data init;
    550	unsigned int status;
    551	struct clk_hw *hw;
    552	int ret;
    553
    554	if (!name)
    555		return ERR_PTR(-EINVAL);
    556
    557	if (!parent_names || !num_parents)
    558		return ERR_PTR(-EINVAL);
    559
    560	clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL);
    561	if (!clkmain)
    562		return ERR_PTR(-ENOMEM);
    563
    564	init.name = name;
    565	init.ops = &sam9x5_main_ops;
    566	init.parent_names = parent_names;
    567	init.num_parents = num_parents;
    568	init.flags = CLK_SET_PARENT_GATE;
    569
    570	clkmain->hw.init = &init;
    571	clkmain->regmap = regmap;
    572	regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
    573	clkmain->parent = clk_main_parent_select(status);
    574
    575	hw = &clkmain->hw;
    576	ret = clk_hw_register(NULL, &clkmain->hw);
    577	if (ret) {
    578		kfree(clkmain);
    579		hw = ERR_PTR(ret);
    580	}
    581
    582	return hw;
    583}