blob: c15b033064e7317388bdbde932098b49b1d4d588 [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;
148 case s32cc_pll_t:
149 ret = -ENOTSUP;
150 break;
151 case s32cc_pll_out_div_t:
152 ret = -ENOTSUP;
153 break;
Ghennadi Procopciuc9dee8e42024-06-12 09:25:17 +0300154 default:
155 ret = -EINVAL;
156 break;
157 }
158
159 return ret;
160}
161
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300162static int s32cc_clk_enable(unsigned long id)
163{
Ghennadi Procopciuc9dee8e42024-06-12 09:25:17 +0300164 unsigned int depth = MAX_STACK_DEPTH;
165 const struct s32cc_clk *clk;
166
167 clk = s32cc_get_arch_clk(id);
168 if (clk == NULL) {
169 return -EINVAL;
170 }
171
172 return enable_module(&clk->desc, &depth);
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300173}
174
175static void s32cc_clk_disable(unsigned long id)
176{
177}
178
179static bool s32cc_clk_is_enabled(unsigned long id)
180{
181 return false;
182}
183
184static unsigned long s32cc_clk_get_rate(unsigned long id)
185{
186 return 0;
187}
188
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +0300189static int set_module_rate(const struct s32cc_clk_obj *module,
190 unsigned long rate, unsigned long *orate,
191 unsigned int *depth);
192
193static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate,
194 unsigned long *orate, unsigned int *depth)
195{
196 struct s32cc_osc *osc = s32cc_obj2osc(module);
197 int ret;
198
199 ret = update_stack_depth(depth);
200 if (ret != 0) {
201 return ret;
202 }
203
204 if ((osc->freq != 0UL) && (rate != osc->freq)) {
205 ERROR("Already initialized oscillator. freq = %lu\n",
206 osc->freq);
207 return -EINVAL;
208 }
209
210 osc->freq = rate;
211 *orate = osc->freq;
212
213 return 0;
214}
215
216static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate,
217 unsigned long *orate, unsigned int *depth)
218{
219 const struct s32cc_clk *clk = s32cc_obj2clk(module);
220 int ret;
221
222 ret = update_stack_depth(depth);
223 if (ret != 0) {
224 return ret;
225 }
226
227 if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) &&
228 ((rate < clk->min_freq) || (rate > clk->max_freq))) {
229 ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n",
230 rate, clk->min_freq, clk->max_freq);
231 return -EINVAL;
232 }
233
234 if (clk->module != NULL) {
235 return set_module_rate(clk->module, rate, orate, depth);
236 }
237
238 if (clk->pclock != NULL) {
239 return set_clk_freq(&clk->pclock->desc, rate, orate, depth);
240 }
241
242 return -EINVAL;
243}
244
245static int set_module_rate(const struct s32cc_clk_obj *module,
246 unsigned long rate, unsigned long *orate,
247 unsigned int *depth)
248{
249 int ret = 0;
250
251 ret = update_stack_depth(depth);
252 if (ret != 0) {
253 return ret;
254 }
255
256 switch (module->type) {
257 case s32cc_clk_t:
258 ret = set_clk_freq(module, rate, orate, depth);
259 break;
260 case s32cc_osc_t:
261 ret = set_osc_freq(module, rate, orate, depth);
262 break;
Ghennadi Procopciuc7277b972024-06-12 09:53:18 +0300263 case s32cc_clkmux_t:
264 case s32cc_pll_t:
265 case s32cc_pll_out_div_t:
266 ret = -ENOTSUP;
267 break;
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +0300268 default:
269 ret = -EINVAL;
270 break;
271 }
272
273 return ret;
274}
275
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300276static int s32cc_clk_set_rate(unsigned long id, unsigned long rate,
277 unsigned long *orate)
278{
Ghennadi Procopciuc0d525772024-06-12 08:09:19 +0300279 unsigned int depth = MAX_STACK_DEPTH;
280 const struct s32cc_clk *clk;
281 int ret;
282
283 clk = s32cc_get_arch_clk(id);
284 if (clk == NULL) {
285 return -EINVAL;
286 }
287
288 ret = set_module_rate(&clk->desc, rate, orate, &depth);
289 if (ret != 0) {
290 ERROR("Failed to set frequency (%lu MHz) for clock %lu\n",
291 rate, id);
292 }
293
294 return ret;
Ghennadi Procopciucfc26eb02024-06-11 18:39:58 +0300295}
296
297static int s32cc_clk_get_parent(unsigned long id)
298{
299 return -ENOTSUP;
300}
301
302static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id)
303{
304 return -ENOTSUP;
305}
306
307void s32cc_clk_register_drv(void)
308{
309 static const struct clk_ops s32cc_clk_ops = {
310 .enable = s32cc_clk_enable,
311 .disable = s32cc_clk_disable,
312 .is_enabled = s32cc_clk_is_enabled,
313 .get_rate = s32cc_clk_get_rate,
314 .set_rate = s32cc_clk_set_rate,
315 .get_parent = s32cc_clk_get_parent,
316 .set_parent = s32cc_clk_set_parent,
317 };
318
319 clk_register(&s32cc_clk_ops);
320}
321