blob: c331a82823300843a4b38e48cabcfbcb79a85848 [file] [log] [blame]
Ghennadi Procopciuc3a580e92024-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 Procopciuc8ab34352024-06-12 09:25:17 +03008#include <s32cc-clk-regs.h>
9
Ghennadi Procopciucd9373512024-06-12 08:09:19 +030010#include <common/debug.h>
Ghennadi Procopciuc3a580e92024-06-11 18:39:58 +030011#include <drivers/clk.h>
Ghennadi Procopciuc8ab34352024-06-12 09:25:17 +030012#include <lib/mmio.h>
Ghennadi Procopciucd9373512024-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 Procopciuc8ab34352024-06-12 09:25:17 +030018struct s32cc_clk_drv {
19 uintptr_t fxosc_base;
20};
21
Ghennadi Procopciucd9373512024-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 Procopciuc3a580e92024-06-11 18:39:58 +030031
Ghennadi Procopciuc8ab34352024-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;
145 default:
146 ret = -EINVAL;
147 break;
148 }
149
150 return ret;
151}
152
Ghennadi Procopciuc3a580e92024-06-11 18:39:58 +0300153static int s32cc_clk_enable(unsigned long id)
154{
Ghennadi Procopciuc8ab34352024-06-12 09:25:17 +0300155 unsigned int depth = MAX_STACK_DEPTH;
156 const struct s32cc_clk *clk;
157
158 clk = s32cc_get_arch_clk(id);
159 if (clk == NULL) {
160 return -EINVAL;
161 }
162
163 return enable_module(&clk->desc, &depth);
Ghennadi Procopciuc3a580e92024-06-11 18:39:58 +0300164}
165
166static void s32cc_clk_disable(unsigned long id)
167{
168}
169
170static bool s32cc_clk_is_enabled(unsigned long id)
171{
172 return false;
173}
174
175static unsigned long s32cc_clk_get_rate(unsigned long id)
176{
177 return 0;
178}
179
Ghennadi Procopciucd9373512024-06-12 08:09:19 +0300180static int set_module_rate(const struct s32cc_clk_obj *module,
181 unsigned long rate, unsigned long *orate,
182 unsigned int *depth);
183
184static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate,
185 unsigned long *orate, unsigned int *depth)
186{
187 struct s32cc_osc *osc = s32cc_obj2osc(module);
188 int ret;
189
190 ret = update_stack_depth(depth);
191 if (ret != 0) {
192 return ret;
193 }
194
195 if ((osc->freq != 0UL) && (rate != osc->freq)) {
196 ERROR("Already initialized oscillator. freq = %lu\n",
197 osc->freq);
198 return -EINVAL;
199 }
200
201 osc->freq = rate;
202 *orate = osc->freq;
203
204 return 0;
205}
206
207static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate,
208 unsigned long *orate, unsigned int *depth)
209{
210 const struct s32cc_clk *clk = s32cc_obj2clk(module);
211 int ret;
212
213 ret = update_stack_depth(depth);
214 if (ret != 0) {
215 return ret;
216 }
217
218 if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) &&
219 ((rate < clk->min_freq) || (rate > clk->max_freq))) {
220 ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n",
221 rate, clk->min_freq, clk->max_freq);
222 return -EINVAL;
223 }
224
225 if (clk->module != NULL) {
226 return set_module_rate(clk->module, rate, orate, depth);
227 }
228
229 if (clk->pclock != NULL) {
230 return set_clk_freq(&clk->pclock->desc, rate, orate, depth);
231 }
232
233 return -EINVAL;
234}
235
236static int set_module_rate(const struct s32cc_clk_obj *module,
237 unsigned long rate, unsigned long *orate,
238 unsigned int *depth)
239{
240 int ret = 0;
241
242 ret = update_stack_depth(depth);
243 if (ret != 0) {
244 return ret;
245 }
246
247 switch (module->type) {
248 case s32cc_clk_t:
249 ret = set_clk_freq(module, rate, orate, depth);
250 break;
251 case s32cc_osc_t:
252 ret = set_osc_freq(module, rate, orate, depth);
253 break;
254 default:
255 ret = -EINVAL;
256 break;
257 }
258
259 return ret;
260}
261
Ghennadi Procopciuc3a580e92024-06-11 18:39:58 +0300262static int s32cc_clk_set_rate(unsigned long id, unsigned long rate,
263 unsigned long *orate)
264{
Ghennadi Procopciucd9373512024-06-12 08:09:19 +0300265 unsigned int depth = MAX_STACK_DEPTH;
266 const struct s32cc_clk *clk;
267 int ret;
268
269 clk = s32cc_get_arch_clk(id);
270 if (clk == NULL) {
271 return -EINVAL;
272 }
273
274 ret = set_module_rate(&clk->desc, rate, orate, &depth);
275 if (ret != 0) {
276 ERROR("Failed to set frequency (%lu MHz) for clock %lu\n",
277 rate, id);
278 }
279
280 return ret;
Ghennadi Procopciuc3a580e92024-06-11 18:39:58 +0300281}
282
283static int s32cc_clk_get_parent(unsigned long id)
284{
285 return -ENOTSUP;
286}
287
288static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id)
289{
290 return -ENOTSUP;
291}
292
293void s32cc_clk_register_drv(void)
294{
295 static const struct clk_ops s32cc_clk_ops = {
296 .enable = s32cc_clk_enable,
297 .disable = s32cc_clk_disable,
298 .is_enabled = s32cc_clk_is_enabled,
299 .get_rate = s32cc_clk_get_rate,
300 .set_rate = s32cc_clk_set_rate,
301 .get_parent = s32cc_clk_get_parent,
302 .set_parent = s32cc_clk_set_parent,
303 };
304
305 clk_register(&s32cc_clk_ops);
306}
307