blob: d4c6155d089d50014a92e1588480364dac5f2ef7 [file] [log] [blame]
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +03001/*
2 * Copyright 2024 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6#include <errno.h>
7
Ghennadi Procopciuc9dee8e42024-06-12 09:25:17 +03008#include <s32cc-clk-regs.h>
9
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +030010#include <common/debug.h>
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +030011#include <drivers/clk.h>
Ghennadi Procopciuc9dee8e42024-06-12 09:25:17 +030012#include <lib/mmio.h>
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +030013#include <s32cc-clk-modules.h>
14#include <s32cc-clk-utils.h>
15
16#define MAX_STACK_DEPTH (15U)
17
Ghennadi Procopciuc9dee8e42024-06-12 09:25:17 +030018struct s32cc_clk_drv {
19 uintptr_t fxosc_base;
20};
21
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +030022static int update_stack_depth(unsigned int *depth)
23{
24 if (*depth == 0U) {
25 return -ENOMEM;
26 }
27
28 (*depth)--;
29 return 0;
30}
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +030031
Ghennadi Procopciuc9dee8e42024-06-12 09:25:17 +030032static struct s32cc_clk_drv *get_drv(void)
33{
34 static struct s32cc_clk_drv driver = {
35 .fxosc_base = FXOSC_BASE_ADDR,
36 };
37
38 return &driver;
39}
40
41static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth);
42
43static int enable_clk_module(const struct s32cc_clk_obj *module,
44 const struct s32cc_clk_drv *drv,
45 unsigned int *depth)
46{
47 const struct s32cc_clk *clk = s32cc_obj2clk(module);
48 int ret;
49
50 ret = update_stack_depth(depth);
51 if (ret != 0) {
52 return ret;
53 }
54
55 if (clk == NULL) {
56 return -EINVAL;
57 }
58
59 if (clk->module != NULL) {
60 return enable_module(clk->module, depth);
61 }
62
63 if (clk->pclock != NULL) {
64 return enable_clk_module(&clk->pclock->desc, drv, depth);
65 }
66
67 return -EINVAL;
68}
69
70static void enable_fxosc(const struct s32cc_clk_drv *drv)
71{
72 uintptr_t fxosc_base = drv->fxosc_base;
73 uint32_t ctrl;
74
75 ctrl = mmio_read_32(FXOSC_CTRL(fxosc_base));
76 if ((ctrl & FXOSC_CTRL_OSCON) != U(0)) {
77 return;
78 }
79
80 ctrl = FXOSC_CTRL_COMP_EN;
81 ctrl &= ~FXOSC_CTRL_OSC_BYP;
82 ctrl |= FXOSC_CTRL_EOCV(0x1);
83 ctrl |= FXOSC_CTRL_GM_SEL(0x7);
84 mmio_write_32(FXOSC_CTRL(fxosc_base), ctrl);
85
86 /* Switch ON the crystal oscillator. */
87 mmio_setbits_32(FXOSC_CTRL(fxosc_base), FXOSC_CTRL_OSCON);
88
89 /* Wait until the clock is stable. */
90 while ((mmio_read_32(FXOSC_STAT(fxosc_base)) & FXOSC_STAT_OSC_STAT) == U(0)) {
91 }
92}
93
94static int enable_osc(const struct s32cc_clk_obj *module,
95 const struct s32cc_clk_drv *drv,
96 unsigned int *depth)
97{
98 const struct s32cc_osc *osc = s32cc_obj2osc(module);
99 int ret = 0;
100
101 ret = update_stack_depth(depth);
102 if (ret != 0) {
103 return ret;
104 }
105
106 switch (osc->source) {
107 case S32CC_FXOSC:
108 enable_fxosc(drv);
109 break;
110 /* FIRC and SIRC oscillators are enabled by default */
111 case S32CC_FIRC:
112 break;
113 case S32CC_SIRC:
114 break;
115 default:
116 ERROR("Invalid oscillator %d\n", osc->source);
117 ret = -EINVAL;
118 break;
119 };
120
121 return ret;
122}
123
124static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth)
125{
126 const struct s32cc_clk_drv *drv = get_drv();
127 int ret = 0;
128
129 ret = update_stack_depth(depth);
130 if (ret != 0) {
131 return ret;
132 }
133
134 if (drv == NULL) {
135 return -EINVAL;
136 }
137
138 switch (module->type) {
139 case s32cc_osc_t:
140 ret = enable_osc(module, drv, depth);
141 break;
142 case s32cc_clk_t:
143 ret = enable_clk_module(module, drv, depth);
144 break;
Ghennadi Procopciuc7277b972024-06-12 09:53:18 +0300145 case s32cc_clkmux_t:
146 ret = -ENOTSUP;
147 break;
Ghennadi Procopciuc8384d182024-06-12 10:53:06 +0300148 case s32cc_shared_clkmux_t:
149 ret = -ENOTSUP;
150 break;
Ghennadi Procopciuc7277b972024-06-12 09:53:18 +0300151 case s32cc_pll_t:
152 ret = -ENOTSUP;
153 break;
154 case s32cc_pll_out_div_t:
155 ret = -ENOTSUP;
156 break;
Ghennadi Procopciuc9dee8e42024-06-12 09:25:17 +0300157 default:
158 ret = -EINVAL;
159 break;
160 }
161
162 return ret;
163}
164
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300165static int s32cc_clk_enable(unsigned long id)
166{
Ghennadi Procopciuc9dee8e42024-06-12 09:25:17 +0300167 unsigned int depth = MAX_STACK_DEPTH;
168 const struct s32cc_clk *clk;
169
170 clk = s32cc_get_arch_clk(id);
171 if (clk == NULL) {
172 return -EINVAL;
173 }
174
175 return enable_module(&clk->desc, &depth);
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300176}
177
178static void s32cc_clk_disable(unsigned long id)
179{
180}
181
182static bool s32cc_clk_is_enabled(unsigned long id)
183{
184 return false;
185}
186
187static unsigned long s32cc_clk_get_rate(unsigned long id)
188{
189 return 0;
190}
191
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +0300192static int set_module_rate(const struct s32cc_clk_obj *module,
193 unsigned long rate, unsigned long *orate,
194 unsigned int *depth);
195
196static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate,
197 unsigned long *orate, unsigned int *depth)
198{
199 struct s32cc_osc *osc = s32cc_obj2osc(module);
200 int ret;
201
202 ret = update_stack_depth(depth);
203 if (ret != 0) {
204 return ret;
205 }
206
207 if ((osc->freq != 0UL) && (rate != osc->freq)) {
208 ERROR("Already initialized oscillator. freq = %lu\n",
209 osc->freq);
210 return -EINVAL;
211 }
212
213 osc->freq = rate;
214 *orate = osc->freq;
215
216 return 0;
217}
218
219static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate,
220 unsigned long *orate, unsigned int *depth)
221{
222 const struct s32cc_clk *clk = s32cc_obj2clk(module);
223 int ret;
224
225 ret = update_stack_depth(depth);
226 if (ret != 0) {
227 return ret;
228 }
229
230 if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) &&
231 ((rate < clk->min_freq) || (rate > clk->max_freq))) {
232 ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n",
233 rate, clk->min_freq, clk->max_freq);
234 return -EINVAL;
235 }
236
237 if (clk->module != NULL) {
238 return set_module_rate(clk->module, rate, orate, depth);
239 }
240
241 if (clk->pclock != NULL) {
242 return set_clk_freq(&clk->pclock->desc, rate, orate, depth);
243 }
244
245 return -EINVAL;
246}
247
Ghennadi Procopciuce18cf332024-06-12 11:55:32 +0300248static int set_pll_freq(const struct s32cc_clk_obj *module, unsigned long rate,
249 unsigned long *orate, unsigned int *depth)
250{
251 struct s32cc_pll *pll = s32cc_obj2pll(module);
252 int ret;
253
254 ret = update_stack_depth(depth);
255 if (ret != 0) {
256 return ret;
257 }
258
259 if ((pll->vco_freq != 0UL) && (pll->vco_freq != rate)) {
260 ERROR("PLL frequency was already set\n");
261 return -EINVAL;
262 }
263
264 pll->vco_freq = rate;
265 *orate = pll->vco_freq;
266
267 return 0;
268}
269
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +0300270static int set_module_rate(const struct s32cc_clk_obj *module,
271 unsigned long rate, unsigned long *orate,
272 unsigned int *depth)
273{
274 int ret = 0;
275
276 ret = update_stack_depth(depth);
277 if (ret != 0) {
278 return ret;
279 }
280
281 switch (module->type) {
282 case s32cc_clk_t:
283 ret = set_clk_freq(module, rate, orate, depth);
284 break;
285 case s32cc_osc_t:
286 ret = set_osc_freq(module, rate, orate, depth);
287 break;
Ghennadi Procopciuce18cf332024-06-12 11:55:32 +0300288 case s32cc_pll_t:
289 ret = set_pll_freq(module, rate, orate, depth);
290 break;
Ghennadi Procopciuc7277b972024-06-12 09:53:18 +0300291 case s32cc_clkmux_t:
Ghennadi Procopciuc8384d182024-06-12 10:53:06 +0300292 case s32cc_shared_clkmux_t:
Ghennadi Procopciuc7277b972024-06-12 09:53:18 +0300293 case s32cc_pll_out_div_t:
294 ret = -ENOTSUP;
295 break;
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +0300296 default:
297 ret = -EINVAL;
298 break;
299 }
300
301 return ret;
302}
303
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300304static int s32cc_clk_set_rate(unsigned long id, unsigned long rate,
305 unsigned long *orate)
306{
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +0300307 unsigned int depth = MAX_STACK_DEPTH;
308 const struct s32cc_clk *clk;
309 int ret;
310
311 clk = s32cc_get_arch_clk(id);
312 if (clk == NULL) {
313 return -EINVAL;
314 }
315
316 ret = set_module_rate(&clk->desc, rate, orate, &depth);
317 if (ret != 0) {
318 ERROR("Failed to set frequency (%lu MHz) for clock %lu\n",
319 rate, id);
320 }
321
322 return ret;
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300323}
324
325static int s32cc_clk_get_parent(unsigned long id)
326{
327 return -ENOTSUP;
328}
329
330static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id)
331{
Ghennadi Procopciucaa45fa92024-06-12 10:02:07 +0300332 const struct s32cc_clk *parent;
333 const struct s32cc_clk *clk;
334 bool valid_source = false;
335 struct s32cc_clkmux *mux;
336 uint8_t i;
337
338 clk = s32cc_get_arch_clk(id);
339 if (clk == NULL) {
340 return -EINVAL;
341 }
342
343 parent = s32cc_get_arch_clk(parent_id);
344 if (parent == NULL) {
345 return -EINVAL;
346 }
347
348 if (!is_s32cc_clk_mux(clk)) {
349 ERROR("Clock %lu is not a mux\n", id);
350 return -EINVAL;
351 }
352
353 mux = s32cc_clk2mux(clk);
354 if (mux == NULL) {
355 ERROR("Failed to cast clock %lu to clock mux\n", id);
356 return -EINVAL;
357 }
358
359 for (i = 0; i < mux->nclks; i++) {
360 if (mux->clkids[i] == parent_id) {
361 valid_source = true;
362 break;
363 }
364 }
365
366 if (!valid_source) {
367 ERROR("Clock %lu is not a valid clock for mux %lu\n",
368 parent_id, id);
369 return -EINVAL;
370 }
371
372 mux->source_id = parent_id;
373
374 return 0;
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300375}
376
377void s32cc_clk_register_drv(void)
378{
379 static const struct clk_ops s32cc_clk_ops = {
380 .enable = s32cc_clk_enable,
381 .disable = s32cc_clk_disable,
382 .is_enabled = s32cc_clk_is_enabled,
383 .get_rate = s32cc_clk_get_rate,
384 .set_rate = s32cc_clk_set_rate,
385 .get_parent = s32cc_clk_get_parent,
386 .set_parent = s32cc_clk_set_parent,
387 };
388
389 clk_register(&s32cc_clk_ops);
390}
391