blob: 69a9d2173ada22e782e92da0764fcace34c2164f [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
248static int set_module_rate(const struct s32cc_clk_obj *module,
249 unsigned long rate, unsigned long *orate,
250 unsigned int *depth)
251{
252 int ret = 0;
253
254 ret = update_stack_depth(depth);
255 if (ret != 0) {
256 return ret;
257 }
258
259 switch (module->type) {
260 case s32cc_clk_t:
261 ret = set_clk_freq(module, rate, orate, depth);
262 break;
263 case s32cc_osc_t:
264 ret = set_osc_freq(module, rate, orate, depth);
265 break;
Ghennadi Procopciuc7277b972024-06-12 09:53:18 +0300266 case s32cc_clkmux_t:
Ghennadi Procopciuc8384d182024-06-12 10:53:06 +0300267 case s32cc_shared_clkmux_t:
Ghennadi Procopciuc7277b972024-06-12 09:53:18 +0300268 case s32cc_pll_t:
269 case s32cc_pll_out_div_t:
270 ret = -ENOTSUP;
271 break;
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +0300272 default:
273 ret = -EINVAL;
274 break;
275 }
276
277 return ret;
278}
279
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300280static int s32cc_clk_set_rate(unsigned long id, unsigned long rate,
281 unsigned long *orate)
282{
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +0300283 unsigned int depth = MAX_STACK_DEPTH;
284 const struct s32cc_clk *clk;
285 int ret;
286
287 clk = s32cc_get_arch_clk(id);
288 if (clk == NULL) {
289 return -EINVAL;
290 }
291
292 ret = set_module_rate(&clk->desc, rate, orate, &depth);
293 if (ret != 0) {
294 ERROR("Failed to set frequency (%lu MHz) for clock %lu\n",
295 rate, id);
296 }
297
298 return ret;
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300299}
300
301static int s32cc_clk_get_parent(unsigned long id)
302{
303 return -ENOTSUP;
304}
305
306static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id)
307{
Ghennadi Procopciucaa45fa92024-06-12 10:02:07 +0300308 const struct s32cc_clk *parent;
309 const struct s32cc_clk *clk;
310 bool valid_source = false;
311 struct s32cc_clkmux *mux;
312 uint8_t i;
313
314 clk = s32cc_get_arch_clk(id);
315 if (clk == NULL) {
316 return -EINVAL;
317 }
318
319 parent = s32cc_get_arch_clk(parent_id);
320 if (parent == NULL) {
321 return -EINVAL;
322 }
323
324 if (!is_s32cc_clk_mux(clk)) {
325 ERROR("Clock %lu is not a mux\n", id);
326 return -EINVAL;
327 }
328
329 mux = s32cc_clk2mux(clk);
330 if (mux == NULL) {
331 ERROR("Failed to cast clock %lu to clock mux\n", id);
332 return -EINVAL;
333 }
334
335 for (i = 0; i < mux->nclks; i++) {
336 if (mux->clkids[i] == parent_id) {
337 valid_source = true;
338 break;
339 }
340 }
341
342 if (!valid_source) {
343 ERROR("Clock %lu is not a valid clock for mux %lu\n",
344 parent_id, id);
345 return -EINVAL;
346 }
347
348 mux->source_id = parent_id;
349
350 return 0;
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300351}
352
353void s32cc_clk_register_drv(void)
354{
355 static const struct clk_ops s32cc_clk_ops = {
356 .enable = s32cc_clk_enable,
357 .disable = s32cc_clk_disable,
358 .is_enabled = s32cc_clk_is_enabled,
359 .get_rate = s32cc_clk_get_rate,
360 .set_rate = s32cc_clk_set_rate,
361 .get_parent = s32cc_clk_get_parent,
362 .set_parent = s32cc_clk_set_parent,
363 };
364
365 clk_register(&s32cc_clk_ops);
366}
367