1 // SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause
2 /*
3 * Copyright (C) 2021 Microchip
4 */
5
6 #include <dt-bindings/clock/at91.h>
7 #include <io.h>
8 #include <kernel/panic.h>
9 #include <kernel/pm.h>
10 #include <malloc.h>
11 #include <string.h>
12 #include <trace.h>
13 #include <types_ext.h>
14
15 #include "at91_clk.h"
16
17 #define PMC_MAX_IDS 128
18 #define PMC_MAX_PCKS 8
19
pmc_clk_get_by_id(struct pmc_clk * clks,unsigned int nclk,unsigned int id)20 static struct clk *pmc_clk_get_by_id(struct pmc_clk *clks, unsigned int nclk,
21 unsigned int id)
22 {
23 unsigned int i = 0;
24
25 for (i = 0; i < nclk; i++) {
26 if (clks[i].clk && clks[i].id == id)
27 return clks[i].clk;
28 }
29
30 return NULL;
31 }
32
pmc_clk_get_by_name(struct pmc_clk * clks,unsigned int nclk,const char * name)33 struct clk *pmc_clk_get_by_name(struct pmc_clk *clks, unsigned int nclk,
34 const char *name)
35 {
36 unsigned int i = 0;
37
38 for (i = 0; i < nclk; i++)
39 if (clks[i].clk && strcmp(clks[i].clk->name, name) == 0)
40 return clks[i].clk;
41
42 return NULL;
43 }
44
pmc_clk_get(struct pmc_data * pmc,unsigned int type,unsigned int idx,struct clk ** clk)45 TEE_Result pmc_clk_get(struct pmc_data *pmc, unsigned int type,
46 unsigned int idx, struct clk **clk)
47 {
48 unsigned int nclk = 0;
49 struct pmc_clk *clks = NULL;
50
51 switch (type) {
52 case PMC_TYPE_CORE:
53 nclk = pmc->ncore;
54 clks = pmc->chws;
55 break;
56 case PMC_TYPE_SYSTEM:
57 nclk = pmc->nsystem;
58 clks = pmc->shws;
59 break;
60 case PMC_TYPE_PERIPHERAL:
61 nclk = pmc->nperiph;
62 clks = pmc->phws;
63 break;
64 case PMC_TYPE_GCK:
65 nclk = pmc->ngck;
66 clks = pmc->ghws;
67 break;
68 case PMC_TYPE_PROGRAMMABLE:
69 nclk = pmc->npck;
70 clks = pmc->pchws;
71 break;
72 default:
73 return TEE_ERROR_BAD_PARAMETERS;
74 }
75
76 *clk = pmc_clk_get_by_id(clks, nclk, idx);
77 if (!*clk)
78 return TEE_ERROR_BAD_PARAMETERS;
79
80 return TEE_SUCCESS;
81 }
82
clk_dt_pmc_get(struct dt_pargs * clkspec,void * data,struct clk ** out_clk)83 TEE_Result clk_dt_pmc_get(struct dt_pargs *clkspec, void *data,
84 struct clk **out_clk)
85 {
86 unsigned int type = clkspec->args[0];
87 unsigned int idx = clkspec->args[1];
88 struct pmc_data *pmc_data = data;
89
90 if (clkspec->args_count != 2)
91 return TEE_ERROR_BAD_PARAMETERS;
92
93 return pmc_clk_get(pmc_data, type, idx, out_clk);
94 }
95
pmc_data_allocate(unsigned int ncore,unsigned int nsystem,unsigned int nperiph,unsigned int ngck,unsigned int npck)96 struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
97 unsigned int nperiph, unsigned int ngck,
98 unsigned int npck)
99 {
100 unsigned int num_clks = ncore + nsystem + nperiph + ngck + npck;
101 unsigned int alloc_size = sizeof(struct pmc_data) +
102 num_clks * sizeof(struct pmc_clk);
103 struct pmc_data *pmc_data = NULL;
104
105 pmc_data = calloc(1, alloc_size);
106 if (!pmc_data)
107 return NULL;
108
109 pmc_data->ncore = ncore;
110 pmc_data->chws = pmc_data->hwtable;
111
112 pmc_data->nsystem = nsystem;
113 pmc_data->shws = pmc_data->chws + ncore;
114
115 pmc_data->nperiph = nperiph;
116 pmc_data->phws = pmc_data->shws + nsystem;
117
118 pmc_data->ngck = ngck;
119 pmc_data->ghws = pmc_data->phws + nperiph;
120
121 pmc_data->npck = npck;
122 pmc_data->pchws = pmc_data->ghws + ngck;
123
124 return pmc_data;
125 }
126
127 #ifdef CFG_PM_ARM32
128 static uint8_t registered_ids[PMC_MAX_IDS];
129 static uint8_t registered_pcks[PMC_MAX_PCKS];
130
131 static struct
132 {
133 uint32_t scsr;
134 uint32_t pcsr0;
135 uint32_t uckr;
136 uint32_t mor;
137 uint32_t mcfr;
138 uint32_t pllar;
139 uint32_t mckr;
140 uint32_t usb;
141 uint32_t imr;
142 uint32_t pcsr1;
143 uint32_t pcr[PMC_MAX_IDS];
144 uint32_t audio_pll0;
145 uint32_t audio_pll1;
146 uint32_t pckr[PMC_MAX_PCKS];
147 } pmc_cache;
148
149 /*
150 * As Peripheral ID 0 is invalid on AT91 chips, the identifier is stored
151 * without alteration in the table, and 0 is for unused clocks.
152 */
pmc_register_id(uint8_t id)153 void pmc_register_id(uint8_t id)
154 {
155 int i = 0;
156
157 for (i = 0; i < PMC_MAX_IDS; i++) {
158 if (registered_ids[i] == 0) {
159 registered_ids[i] = id;
160 return;
161 }
162 if (registered_ids[i] == id)
163 return;
164 }
165
166 panic("Invalid clock ID");
167 }
168
169 /*
170 * As Programmable Clock 0 is valid on AT91 chips, there is an offset
171 * of 1 between the stored value and the real clock ID.
172 */
pmc_register_pck(uint8_t pck)173 void pmc_register_pck(uint8_t pck)
174 {
175 int i = 0;
176
177 for (i = 0; i < PMC_MAX_PCKS; i++) {
178 if (registered_pcks[i] == 0) {
179 registered_pcks[i] = pck + 1;
180 return;
181 }
182 if (registered_pcks[i] == pck + 1)
183 return;
184 }
185
186 panic("Invalid clock ID");
187 }
188
pmc_suspend(void)189 static void pmc_suspend(void)
190 {
191 int i = 0;
192 uint8_t num = 0;
193 vaddr_t pmc_base = at91_pmc_get_base();
194
195 pmc_cache.scsr = io_read32(pmc_base + AT91_PMC_SCSR);
196 pmc_cache.pcsr0 = io_read32(pmc_base + AT91_PMC_PCSR);
197 pmc_cache.uckr = io_read32(pmc_base + AT91_CKGR_UCKR);
198 pmc_cache.mor = io_read32(pmc_base + AT91_CKGR_MOR);
199 pmc_cache.mcfr = io_read32(pmc_base + AT91_CKGR_MCFR);
200 pmc_cache.pllar = io_read32(pmc_base + AT91_CKGR_PLLAR);
201 pmc_cache.mckr = io_read32(pmc_base + AT91_PMC_MCKR);
202 pmc_cache.usb = io_read32(pmc_base + AT91_PMC_USB);
203 pmc_cache.imr = io_read32(pmc_base + AT91_PMC_IMR);
204 pmc_cache.pcsr1 = io_read32(pmc_base + AT91_PMC_PCSR1);
205
206 for (i = 0; registered_ids[i]; i++) {
207 io_write32(pmc_base + AT91_PMC_PCR,
208 registered_ids[i] & AT91_PMC_PCR_PID_MASK);
209 pmc_cache.pcr[registered_ids[i]] = io_read32(pmc_base +
210 AT91_PMC_PCR);
211 }
212 for (i = 0; registered_pcks[i]; i++) {
213 num = registered_pcks[i] - 1;
214 pmc_cache.pckr[num] = io_read32(pmc_base + AT91_PMC_PCKR(num));
215 }
216 }
217
pmc_ready(vaddr_t pmc_base,unsigned int mask)218 static bool pmc_ready(vaddr_t pmc_base, unsigned int mask)
219 {
220 uint32_t status = 0;
221
222 status = io_read32(pmc_base + AT91_PMC_SR);
223
224 return (status & mask) == mask;
225 }
226
pmc_resume(void)227 static void pmc_resume(void)
228 {
229 int i = 0;
230 uint8_t num = 0;
231 uint32_t tmp = 0;
232 vaddr_t pmc_base = at91_pmc_get_base();
233 uint32_t mask = AT91_PMC_MCKRDY | AT91_PMC_LOCKA;
234
235 tmp = io_read32(pmc_base + AT91_PMC_MCKR);
236 if (pmc_cache.mckr != tmp)
237 panic("MCKR was not configured properly by the previous bootstage");
238 tmp = io_read32(pmc_base + AT91_CKGR_PLLAR);
239 if (pmc_cache.pllar != tmp)
240 panic("PLLAR was not configured properly by the previous bootstage");
241
242 io_write32(pmc_base + AT91_PMC_SCER, pmc_cache.scsr);
243 io_write32(pmc_base + AT91_PMC_PCER, pmc_cache.pcsr0);
244 io_write32(pmc_base + AT91_CKGR_UCKR, pmc_cache.uckr);
245 io_write32(pmc_base + AT91_CKGR_MOR, pmc_cache.mor);
246 io_write32(pmc_base + AT91_CKGR_MCFR, pmc_cache.mcfr);
247 io_write32(pmc_base + AT91_PMC_USB, pmc_cache.usb);
248 io_write32(pmc_base + AT91_PMC_IMR, pmc_cache.imr);
249 io_write32(pmc_base + AT91_PMC_PCER1, pmc_cache.pcsr1);
250
251 for (i = 0; registered_ids[i]; i++) {
252 io_write32(pmc_base + AT91_PMC_PCR,
253 pmc_cache.pcr[registered_ids[i]] | AT91_PMC_PCR_CMD);
254 }
255 for (i = 0; registered_pcks[i]; i++) {
256 num = registered_pcks[i] - 1;
257 io_write32(pmc_base + AT91_PMC_PCKR(num), pmc_cache.pckr[num]);
258 }
259
260 if (pmc_cache.uckr & AT91_PMC_UPLLEN)
261 mask |= AT91_PMC_LOCKU;
262
263 while (!pmc_ready(pmc_base, mask))
264 ;
265 }
266
pmc_pm(enum pm_op op,uint32_t pm_hint __unused,const struct pm_callback_handle * hdl __unused)267 static TEE_Result pmc_pm(enum pm_op op, uint32_t pm_hint __unused,
268 const struct pm_callback_handle *hdl __unused)
269 {
270 switch (op) {
271 case PM_OP_RESUME:
272 pmc_resume();
273 break;
274 case PM_OP_SUSPEND:
275 pmc_suspend();
276 break;
277 default:
278 panic("Invalid PM operation");
279 }
280
281 return TEE_SUCCESS;
282 }
283
pmc_register_pm(void)284 void pmc_register_pm(void)
285 {
286 /*
287 * We register the clock as a core service since clocks must be
288 * re-enable prior to accessing devices
289 */
290 register_pm_core_service_cb(pmc_pm, NULL, "pmc");
291 }
292
293 #endif
294