xref: /optee_os/core/drivers/clk/sam/at91_main.c (revision 2798ddd35d692c18571559ef288c15a99a5a5ecb)
1*2798ddd3SClément Léger // SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause
2*2798ddd3SClément Léger /*
3*2798ddd3SClément Léger  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
4*2798ddd3SClément Léger  *  Copyright (C) 2021 Microchip
5*2798ddd3SClément Léger  */
6*2798ddd3SClément Léger 
7*2798ddd3SClément Léger #include <io.h>
8*2798ddd3SClément Léger #include <kernel/delay.h>
9*2798ddd3SClément Léger #include <kernel/panic.h>
10*2798ddd3SClément Léger #include <mm/core_memprot.h>
11*2798ddd3SClément Léger #include <types_ext.h>
12*2798ddd3SClément Léger 
13*2798ddd3SClément Léger #include "at91_clk.h"
14*2798ddd3SClément Léger 
15*2798ddd3SClément Léger #define SLOW_CLOCK_FREQ		32768
16*2798ddd3SClément Léger #define MAINF_DIV		16
17*2798ddd3SClément Léger #define USEC_PER_SEC		1000000L
18*2798ddd3SClément Léger #define MAINF_LOOP_MIN_WAIT	(USEC_PER_SEC / SLOW_CLOCK_FREQ)
19*2798ddd3SClément Léger 
20*2798ddd3SClément Léger #define OSC_READY_TIMEOUT_US	1000
21*2798ddd3SClément Léger 
22*2798ddd3SClément Léger #define MOR_KEY_MASK		(0xFF << 16)
23*2798ddd3SClément Léger 
24*2798ddd3SClément Léger #define CLK_MAIN_PARENT_SELECT(s)	(((s) & \
25*2798ddd3SClément Léger 					(AT91_PMC_MOSCEN | \
26*2798ddd3SClément Léger 					AT91_PMC_OSCBYPASS)) ? 1 : 0)
27*2798ddd3SClément Léger 
28*2798ddd3SClément Léger /*
29*2798ddd3SClément Léger  * Main RC Oscillator
30*2798ddd3SClément Léger  */
31*2798ddd3SClément Léger 
32*2798ddd3SClément Léger struct main_rc_osc {
33*2798ddd3SClément Léger 	unsigned long freq;
34*2798ddd3SClément Léger 	vaddr_t base;
35*2798ddd3SClément Léger };
36*2798ddd3SClément Léger 
pmc_main_rc_osc_ready(struct main_rc_osc * osc)37*2798ddd3SClément Léger static bool pmc_main_rc_osc_ready(struct main_rc_osc *osc)
38*2798ddd3SClément Léger {
39*2798ddd3SClément Léger 	uint32_t status = io_read32(osc->base + AT91_PMC_SR);
40*2798ddd3SClément Léger 
41*2798ddd3SClément Léger 	return status & AT91_PMC_MOSCRCS;
42*2798ddd3SClément Léger }
43*2798ddd3SClément Léger 
pmc_main_rc_osc_enable(struct clk * clk)44*2798ddd3SClément Léger static TEE_Result pmc_main_rc_osc_enable(struct clk *clk)
45*2798ddd3SClément Léger {
46*2798ddd3SClément Léger 	struct main_rc_osc *osc = clk->priv;
47*2798ddd3SClément Léger 	uint32_t mor = io_read32(osc->base + AT91_CKGR_MOR);
48*2798ddd3SClément Léger 
49*2798ddd3SClément Léger 	/* Enable the oscillator if not */
50*2798ddd3SClément Léger 	if (!(mor & AT91_PMC_MOSCRCEN)) {
51*2798ddd3SClément Léger 		io_clrsetbits32(osc->base + AT91_CKGR_MOR,
52*2798ddd3SClément Léger 				MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
53*2798ddd3SClément Léger 				AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
54*2798ddd3SClément Léger 	}
55*2798ddd3SClément Léger 
56*2798ddd3SClément Léger 	while (!pmc_main_rc_osc_ready(osc))
57*2798ddd3SClément Léger 		;
58*2798ddd3SClément Léger 
59*2798ddd3SClément Léger 	return TEE_SUCCESS;
60*2798ddd3SClément Léger }
61*2798ddd3SClément Léger 
pmc_main_rc_osc_disable(struct clk * clk)62*2798ddd3SClément Léger static void pmc_main_rc_osc_disable(struct clk *clk)
63*2798ddd3SClément Léger {
64*2798ddd3SClément Léger 	struct main_rc_osc *osc = clk->priv;
65*2798ddd3SClément Léger 	uint32_t mor = io_read32(osc->base + AT91_CKGR_MOR);
66*2798ddd3SClément Léger 
67*2798ddd3SClément Léger 	if (!(mor & AT91_PMC_MOSCRCEN))
68*2798ddd3SClément Léger 		return;
69*2798ddd3SClément Léger 
70*2798ddd3SClément Léger 	io_clrsetbits32(osc->base + AT91_CKGR_MOR,
71*2798ddd3SClément Léger 			MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
72*2798ddd3SClément Léger }
73*2798ddd3SClément Léger 
74*2798ddd3SClément Léger static unsigned long
pmc_main_rc_osc_get_rate(struct clk * clk,unsigned long parent_rate __unused)75*2798ddd3SClément Léger pmc_main_rc_osc_get_rate(struct clk *clk, unsigned long parent_rate __unused)
76*2798ddd3SClément Léger {
77*2798ddd3SClément Léger 	struct main_rc_osc *osc = clk->priv;
78*2798ddd3SClément Léger 
79*2798ddd3SClément Léger 	return osc->freq;
80*2798ddd3SClément Léger }
81*2798ddd3SClément Léger 
82*2798ddd3SClément Léger static const struct clk_ops pmc_main_rc_osc_clk_ops = {
83*2798ddd3SClément Léger 	.enable = pmc_main_rc_osc_enable,
84*2798ddd3SClément Léger 	.disable = pmc_main_rc_osc_disable,
85*2798ddd3SClément Léger 	.get_rate = pmc_main_rc_osc_get_rate,
86*2798ddd3SClément Léger };
87*2798ddd3SClément Léger 
pmc_register_main_rc_osc(struct pmc_data * pmc,const char * name,unsigned long freq)88*2798ddd3SClément Léger struct clk *pmc_register_main_rc_osc(struct pmc_data *pmc, const char *name,
89*2798ddd3SClément Léger 				     unsigned long freq)
90*2798ddd3SClément Léger {
91*2798ddd3SClément Léger 	struct clk *clk = NULL;
92*2798ddd3SClément Léger 	struct main_rc_osc *osc = NULL;
93*2798ddd3SClément Léger 
94*2798ddd3SClément Léger 	clk = clk_alloc(name, &pmc_main_rc_osc_clk_ops, NULL, 0);
95*2798ddd3SClément Léger 	if (!clk)
96*2798ddd3SClément Léger 		return NULL;
97*2798ddd3SClément Léger 
98*2798ddd3SClément Léger 	osc = calloc(1, sizeof(*osc));
99*2798ddd3SClément Léger 	if (!osc) {
100*2798ddd3SClément Léger 		clk_free(clk);
101*2798ddd3SClément Léger 		return NULL;
102*2798ddd3SClément Léger 	}
103*2798ddd3SClément Léger 
104*2798ddd3SClément Léger 	osc->freq = freq;
105*2798ddd3SClément Léger 	osc->base = pmc->base;
106*2798ddd3SClément Léger 
107*2798ddd3SClément Léger 	clk->priv = osc;
108*2798ddd3SClément Léger 
109*2798ddd3SClément Léger 	if (clk_register(clk)) {
110*2798ddd3SClément Léger 		free(osc);
111*2798ddd3SClément Léger 		clk_free(clk);
112*2798ddd3SClément Léger 		return NULL;
113*2798ddd3SClément Léger 	}
114*2798ddd3SClément Léger 
115*2798ddd3SClément Léger 	return clk;
116*2798ddd3SClément Léger }
117*2798ddd3SClément Léger 
118*2798ddd3SClément Léger /*
119*2798ddd3SClément Léger  * Main Oscillator
120*2798ddd3SClément Léger  */
pmc_main_osc_ready(struct pmc_data * pmc)121*2798ddd3SClément Léger static bool pmc_main_osc_ready(struct pmc_data *pmc)
122*2798ddd3SClément Léger {
123*2798ddd3SClément Léger 	uint32_t status = io_read32(pmc->base + AT91_PMC_SR);
124*2798ddd3SClément Léger 
125*2798ddd3SClément Léger 	return status & AT91_PMC_MOSCS;
126*2798ddd3SClément Léger }
127*2798ddd3SClément Léger 
pmc_main_osc_enable(struct clk * clk)128*2798ddd3SClément Léger static TEE_Result pmc_main_osc_enable(struct clk *clk)
129*2798ddd3SClément Léger {
130*2798ddd3SClément Léger 	struct pmc_data *pmc = clk->priv;
131*2798ddd3SClément Léger 	uint32_t mor = io_read32(pmc->base + AT91_CKGR_MOR);
132*2798ddd3SClément Léger 
133*2798ddd3SClément Léger 	mor &= ~MOR_KEY_MASK;
134*2798ddd3SClément Léger 
135*2798ddd3SClément Léger 	if (mor & AT91_PMC_OSCBYPASS)
136*2798ddd3SClément Léger 		return TEE_SUCCESS;
137*2798ddd3SClément Léger 
138*2798ddd3SClément Léger 	if (!(mor & AT91_PMC_MOSCEN)) {
139*2798ddd3SClément Léger 		mor |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
140*2798ddd3SClément Léger 		io_write32(pmc->base + AT91_CKGR_MOR, mor);
141*2798ddd3SClément Léger 	}
142*2798ddd3SClément Léger 
143*2798ddd3SClément Léger 	while (!pmc_main_osc_ready(pmc))
144*2798ddd3SClément Léger 		;
145*2798ddd3SClément Léger 
146*2798ddd3SClément Léger 	return TEE_SUCCESS;
147*2798ddd3SClément Léger }
148*2798ddd3SClément Léger 
pmc_main_osc_disable(struct clk * clk)149*2798ddd3SClément Léger static void pmc_main_osc_disable(struct clk *clk)
150*2798ddd3SClément Léger {
151*2798ddd3SClément Léger 	struct pmc_data *pmc = clk->priv;
152*2798ddd3SClément Léger 	uint32_t mor = io_read32(pmc->base + AT91_CKGR_MOR);
153*2798ddd3SClément Léger 
154*2798ddd3SClément Léger 	if (mor & AT91_PMC_OSCBYPASS)
155*2798ddd3SClément Léger 		return;
156*2798ddd3SClément Léger 
157*2798ddd3SClément Léger 	if (!(mor & AT91_PMC_MOSCEN))
158*2798ddd3SClément Léger 		return;
159*2798ddd3SClément Léger 
160*2798ddd3SClément Léger 	mor &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
161*2798ddd3SClément Léger 	io_write32(pmc->base + AT91_CKGR_MOR, mor | AT91_PMC_KEY);
162*2798ddd3SClément Léger }
163*2798ddd3SClément Léger 
164*2798ddd3SClément Léger static const struct clk_ops pmc_main_osc_clk_ops = {
165*2798ddd3SClément Léger 	.enable = pmc_main_osc_enable,
166*2798ddd3SClément Léger 	.disable = pmc_main_osc_disable,
167*2798ddd3SClément Léger };
168*2798ddd3SClément Léger 
pmc_register_main_osc(struct pmc_data * pmc,const char * name,struct clk * parent,bool bypass)169*2798ddd3SClément Léger struct clk *pmc_register_main_osc(struct pmc_data *pmc, const char *name,
170*2798ddd3SClément Léger 				  struct clk *parent, bool bypass)
171*2798ddd3SClément Léger {
172*2798ddd3SClément Léger 	struct clk *clk = NULL;
173*2798ddd3SClément Léger 
174*2798ddd3SClément Léger 	clk = clk_alloc(name, &pmc_main_osc_clk_ops, &parent, 1);
175*2798ddd3SClément Léger 	if (!clk)
176*2798ddd3SClément Léger 		panic();
177*2798ddd3SClément Léger 
178*2798ddd3SClément Léger 	clk->priv = pmc;
179*2798ddd3SClément Léger 
180*2798ddd3SClément Léger 	if (bypass)
181*2798ddd3SClément Léger 		io_clrsetbits32(pmc->base + AT91_CKGR_MOR,
182*2798ddd3SClément Léger 				MOR_KEY_MASK | AT91_PMC_OSCBYPASS,
183*2798ddd3SClément Léger 				AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
184*2798ddd3SClément Léger 
185*2798ddd3SClément Léger 	if (clk_register(clk)) {
186*2798ddd3SClément Léger 		clk_free(clk);
187*2798ddd3SClément Léger 		return NULL;
188*2798ddd3SClément Léger 	}
189*2798ddd3SClément Léger 
190*2798ddd3SClément Léger 	return clk;
191*2798ddd3SClément Léger }
192*2798ddd3SClément Léger 
193*2798ddd3SClément Léger /*
194*2798ddd3SClément Léger  * Main Clock
195*2798ddd3SClément Léger  */
clk_main_probe_frequency(vaddr_t base)196*2798ddd3SClément Léger static TEE_Result clk_main_probe_frequency(vaddr_t base)
197*2798ddd3SClément Léger {
198*2798ddd3SClément Léger 	while (!(io_read32(base + AT91_CKGR_MCFR) & AT91_PMC_MAINRDY))
199*2798ddd3SClément Léger 		;
200*2798ddd3SClément Léger 
201*2798ddd3SClément Léger 	return TEE_SUCCESS;
202*2798ddd3SClément Léger }
203*2798ddd3SClément Léger 
clk_main_get_rate(vaddr_t base,unsigned long parent_rate)204*2798ddd3SClément Léger static unsigned long clk_main_get_rate(vaddr_t base,
205*2798ddd3SClément Léger 				       unsigned long parent_rate)
206*2798ddd3SClément Léger {
207*2798ddd3SClément Léger 	uint32_t mcfr = 0;
208*2798ddd3SClément Léger 
209*2798ddd3SClément Léger 	if (parent_rate)
210*2798ddd3SClément Léger 		return parent_rate;
211*2798ddd3SClément Léger 
212*2798ddd3SClément Léger 	IMSG("Main crystal frequency not set, using approximate value");
213*2798ddd3SClément Léger 	mcfr = io_read32(base + AT91_CKGR_MCFR);
214*2798ddd3SClément Léger 	if (!(mcfr & AT91_PMC_MAINRDY))
215*2798ddd3SClément Léger 		return 0;
216*2798ddd3SClément Léger 
217*2798ddd3SClément Léger 	return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
218*2798ddd3SClément Léger }
219*2798ddd3SClément Léger 
clk_sam9x5_main_ready(vaddr_t base)220*2798ddd3SClément Léger static bool clk_sam9x5_main_ready(vaddr_t base)
221*2798ddd3SClément Léger {
222*2798ddd3SClément Léger 	uint32_t status = io_read32(base + AT91_PMC_SR);
223*2798ddd3SClément Léger 
224*2798ddd3SClément Léger 	return status & AT91_PMC_MOSCSELS;
225*2798ddd3SClément Léger }
226*2798ddd3SClément Léger 
clk_sam9x5_main_enable(struct clk * clk)227*2798ddd3SClément Léger static TEE_Result clk_sam9x5_main_enable(struct clk *clk)
228*2798ddd3SClément Léger {
229*2798ddd3SClément Léger 	struct pmc_data *pmc = clk->priv;
230*2798ddd3SClément Léger 
231*2798ddd3SClément Léger 	while (!clk_sam9x5_main_ready(pmc->base))
232*2798ddd3SClément Léger 		;
233*2798ddd3SClément Léger 
234*2798ddd3SClément Léger 	return clk_main_probe_frequency(pmc->base);
235*2798ddd3SClément Léger }
236*2798ddd3SClément Léger 
clk_sam9x5_main_get_rate(struct clk * clk,unsigned long parent_rate)237*2798ddd3SClément Léger static unsigned long clk_sam9x5_main_get_rate(struct clk *clk,
238*2798ddd3SClément Léger 					      unsigned long parent_rate)
239*2798ddd3SClément Léger {
240*2798ddd3SClément Léger 	struct pmc_data *pmc = clk->priv;
241*2798ddd3SClément Léger 
242*2798ddd3SClément Léger 	return clk_main_get_rate(pmc->base, parent_rate);
243*2798ddd3SClément Léger }
244*2798ddd3SClément Léger 
clk_sam9x5_main_set_parent(struct clk * clk,size_t index)245*2798ddd3SClément Léger static TEE_Result clk_sam9x5_main_set_parent(struct clk *clk, size_t index)
246*2798ddd3SClément Léger {
247*2798ddd3SClément Léger 	struct pmc_data *pmc = clk->priv;
248*2798ddd3SClément Léger 	uint32_t tmp = 0;
249*2798ddd3SClément Léger 
250*2798ddd3SClément Léger 	if (index > 1)
251*2798ddd3SClément Léger 		return TEE_ERROR_BAD_PARAMETERS;
252*2798ddd3SClément Léger 
253*2798ddd3SClément Léger 	tmp = io_read32(pmc->base + AT91_CKGR_MOR);
254*2798ddd3SClément Léger 
255*2798ddd3SClément Léger 	if (index && !(tmp & AT91_PMC_MOSCSEL))
256*2798ddd3SClément Léger 		tmp = AT91_PMC_MOSCSEL;
257*2798ddd3SClément Léger 	else if (!index && (tmp & AT91_PMC_MOSCSEL))
258*2798ddd3SClément Léger 		tmp = 0;
259*2798ddd3SClément Léger 	else
260*2798ddd3SClément Léger 		return TEE_SUCCESS;
261*2798ddd3SClément Léger 
262*2798ddd3SClément Léger 	io_clrsetbits32(pmc->base + AT91_CKGR_MOR,
263*2798ddd3SClément Léger 			AT91_PMC_MOSCSEL | MOR_KEY_MASK,
264*2798ddd3SClément Léger 			tmp | AT91_PMC_KEY);
265*2798ddd3SClément Léger 
266*2798ddd3SClément Léger 	while (!clk_sam9x5_main_ready(pmc->base))
267*2798ddd3SClément Léger 		;
268*2798ddd3SClément Léger 
269*2798ddd3SClément Léger 	return TEE_SUCCESS;
270*2798ddd3SClément Léger }
271*2798ddd3SClément Léger 
clk_sam9x5_main_get_parent(struct clk * clk)272*2798ddd3SClément Léger static size_t clk_sam9x5_main_get_parent(struct clk *clk)
273*2798ddd3SClément Léger {
274*2798ddd3SClément Léger 	struct pmc_data *pmc = clk->priv;
275*2798ddd3SClément Léger 	uint32_t status = io_read32(pmc->base + AT91_CKGR_MOR);
276*2798ddd3SClément Léger 
277*2798ddd3SClément Léger 	return CLK_MAIN_PARENT_SELECT(status);
278*2798ddd3SClément Léger }
279*2798ddd3SClément Léger 
280*2798ddd3SClément Léger static const struct clk_ops sam9x5_main_ops = {
281*2798ddd3SClément Léger 	.enable = clk_sam9x5_main_enable,
282*2798ddd3SClément Léger 	.get_rate = clk_sam9x5_main_get_rate,
283*2798ddd3SClément Léger 	.set_parent = clk_sam9x5_main_set_parent,
284*2798ddd3SClément Léger 	.get_parent = clk_sam9x5_main_get_parent,
285*2798ddd3SClément Léger };
286*2798ddd3SClément Léger 
287*2798ddd3SClément Léger struct clk *
at91_clk_register_sam9x5_main(struct pmc_data * pmc,const char * name,struct clk ** parent_clocks,unsigned int num_parents)288*2798ddd3SClément Léger at91_clk_register_sam9x5_main(struct pmc_data *pmc,
289*2798ddd3SClément Léger 			      const char *name,
290*2798ddd3SClément Léger 			      struct clk **parent_clocks,
291*2798ddd3SClément Léger 			      unsigned int num_parents)
292*2798ddd3SClément Léger {
293*2798ddd3SClément Léger 	struct clk *clk = NULL;
294*2798ddd3SClément Léger 
295*2798ddd3SClément Léger 	if (!name)
296*2798ddd3SClément Léger 		return NULL;
297*2798ddd3SClément Léger 
298*2798ddd3SClément Léger 	if (!parent_clocks || !num_parents)
299*2798ddd3SClément Léger 		return NULL;
300*2798ddd3SClément Léger 
301*2798ddd3SClément Léger 	clk = clk_alloc(name, &sam9x5_main_ops, parent_clocks, num_parents);
302*2798ddd3SClément Léger 	if (!clk)
303*2798ddd3SClément Léger 		return NULL;
304*2798ddd3SClément Léger 
305*2798ddd3SClément Léger 	clk->flags = CLK_SET_PARENT_GATE;
306*2798ddd3SClément Léger 	clk->priv = pmc;
307*2798ddd3SClément Léger 
308*2798ddd3SClément Léger 	if (clk_register(clk)) {
309*2798ddd3SClément Léger 		clk_free(clk);
310*2798ddd3SClément Léger 		return NULL;
311*2798ddd3SClément Léger 	}
312*2798ddd3SClément Léger 
313*2798ddd3SClément Léger 	return clk;
314*2798ddd3SClément Léger }
315