blob: 34e8e742a69671cc67433a4a0aa56a759d238762 [file] [log] [blame]
Sean Andersonf9c7d4f2020-06-24 06:41:11 -04001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com>
4 */
5#include <kendryte/clk.h>
6
Sean Anderson609bd602021-06-11 00:16:08 -04007#include <common.h>
Sean Andersonf9c7d4f2020-06-24 06:41:11 -04008#include <dt-bindings/clock/k210-sysctl.h>
9#include <dt-bindings/mfd/k210-sysctl.h>
10#include <dm.h>
11#include <log.h>
12#include <mapmem.h>
13
14#include <kendryte/bypass.h>
15#include <kendryte/pll.h>
16
Sean Andersonf9c7d4f2020-06-24 06:41:11 -040017/*
18 * All parameters for different sub-clocks are collected into parameter arrays.
19 * These parameters are then initialized by the clock which uses them during
20 * probe. To save space, ids are automatically generated for each sub-clock by
21 * using an enum. Instead of storing a parameter struct for each clock, even for
22 * those clocks which don't use a particular type of sub-clock, we can just
23 * store the parameters for the clocks which need them.
24 *
25 * So why do it like this? Arranging all the sub-clocks together makes it very
26 * easy to find bugs in the code.
27 */
28
Sean Anderson609bd602021-06-11 00:16:08 -040029/**
30 * enum k210_clk_div_type - The type of divider
31 * @K210_DIV_ONE: freq = parent / (reg + 1)
32 * @K210_DIV_EVEN: freq = parent / 2 / (reg + 1)
33 * @K210_DIV_POWER: freq = parent / (2 << reg)
34 * @K210_DIV_FIXED: freq = parent / factor
35 */
36enum k210_clk_div_type {
37 K210_DIV_ONE,
38 K210_DIV_EVEN,
39 K210_DIV_POWER,
40 K210_DIV_FIXED,
41};
42
43/**
44 * struct k210_div_params - Parameters for dividing clocks
45 * @type: An &enum k210_clk_div_type specifying the dividing formula
46 * @off: The offset of the divider from the sysctl base address
47 * @shift: The offset of the LSB of the divider
48 * @width: The number of bits in the divider
49 * @div: The fixed divisor for this divider
50 */
51struct k210_div_params {
52 u8 type;
53 union {
54 struct {
55 u8 off;
56 u8 shift;
57 u8 width;
58 };
59 u8 div;
60 };
61};
62
Sean Andersonf9c7d4f2020-06-24 06:41:11 -040063#define DIV_LIST \
Sean Anderson609bd602021-06-11 00:16:08 -040064 DIV(K210_CLK_ACLK, K210_SYSCTL_SEL0, 1, 2, K210_DIV_POWER) \
65 DIV(K210_CLK_APB0, K210_SYSCTL_SEL0, 3, 3, K210_DIV_ONE) \
66 DIV(K210_CLK_APB1, K210_SYSCTL_SEL0, 6, 3, K210_DIV_ONE) \
67 DIV(K210_CLK_APB2, K210_SYSCTL_SEL0, 9, 3, K210_DIV_ONE) \
68 DIV(K210_CLK_SRAM0, K210_SYSCTL_THR0, 0, 4, K210_DIV_ONE) \
69 DIV(K210_CLK_SRAM1, K210_SYSCTL_THR0, 4, 4, K210_DIV_ONE) \
70 DIV(K210_CLK_AI, K210_SYSCTL_THR0, 8, 4, K210_DIV_ONE) \
71 DIV(K210_CLK_DVP, K210_SYSCTL_THR0, 12, 4, K210_DIV_ONE) \
72 DIV(K210_CLK_ROM, K210_SYSCTL_THR0, 16, 4, K210_DIV_ONE) \
73 DIV(K210_CLK_SPI0, K210_SYSCTL_THR1, 0, 8, K210_DIV_EVEN) \
74 DIV(K210_CLK_SPI1, K210_SYSCTL_THR1, 8, 8, K210_DIV_EVEN) \
75 DIV(K210_CLK_SPI2, K210_SYSCTL_THR1, 16, 8, K210_DIV_EVEN) \
76 DIV(K210_CLK_SPI3, K210_SYSCTL_THR1, 24, 8, K210_DIV_EVEN) \
77 DIV(K210_CLK_TIMER0, K210_SYSCTL_THR2, 0, 8, K210_DIV_EVEN) \
78 DIV(K210_CLK_TIMER1, K210_SYSCTL_THR2, 8, 8, K210_DIV_EVEN) \
79 DIV(K210_CLK_TIMER2, K210_SYSCTL_THR2, 16, 8, K210_DIV_EVEN) \
80 DIV(K210_CLK_I2S0, K210_SYSCTL_THR3, 0, 16, K210_DIV_EVEN) \
81 DIV(K210_CLK_I2S1, K210_SYSCTL_THR3, 16, 16, K210_DIV_EVEN) \
82 DIV(K210_CLK_I2S2, K210_SYSCTL_THR4, 0, 16, K210_DIV_EVEN) \
83 DIV(K210_CLK_I2S0_M, K210_SYSCTL_THR4, 16, 8, K210_DIV_EVEN) \
84 DIV(K210_CLK_I2S1_M, K210_SYSCTL_THR4, 24, 8, K210_DIV_EVEN) \
85 DIV(K210_CLK_I2S2_M, K210_SYSCTL_THR4, 0, 8, K210_DIV_EVEN) \
86 DIV(K210_CLK_I2C0, K210_SYSCTL_THR5, 8, 8, K210_DIV_EVEN) \
87 DIV(K210_CLK_I2C1, K210_SYSCTL_THR5, 16, 8, K210_DIV_EVEN) \
88 DIV(K210_CLK_I2C2, K210_SYSCTL_THR5, 24, 8, K210_DIV_EVEN) \
89 DIV(K210_CLK_WDT0, K210_SYSCTL_THR6, 0, 8, K210_DIV_EVEN) \
90 DIV(K210_CLK_WDT1, K210_SYSCTL_THR6, 8, 8, K210_DIV_EVEN) \
91 DIV_FIXED(K210_CLK_CLINT, 50) \
Sean Andersonf9c7d4f2020-06-24 06:41:11 -040092
93#define _DIVIFY(id) K210_CLK_DIV_##id
94#define DIVIFY(id) _DIVIFY(id)
95
Sean Anderson609bd602021-06-11 00:16:08 -040096enum k210_div_id {
97#define DIV(id, ...) DIVIFY(id),
98#define DIV_FIXED DIV
Sean Andersonf9c7d4f2020-06-24 06:41:11 -040099 DIV_LIST
Sean Anderson609bd602021-06-11 00:16:08 -0400100#undef DIV
101#undef DIV_FIXED
102 K210_CLK_DIV_NONE,
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400103};
104
105static const struct k210_div_params k210_divs[] = {
Sean Anderson609bd602021-06-11 00:16:08 -0400106#define DIV(id, _off, _shift, _width, _type) \
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400107 [DIVIFY(id)] = { \
Sean Anderson609bd602021-06-11 00:16:08 -0400108 .type = (_type), \
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400109 .off = (_off), \
110 .shift = (_shift), \
111 .width = (_width), \
Sean Anderson609bd602021-06-11 00:16:08 -0400112 },
113#define DIV_FIXED(id, _div) \
114 [DIVIFY(id)] = { \
115 .type = K210_DIV_FIXED, \
116 .div = (_div) \
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400117 },
118 DIV_LIST
Sean Anderson609bd602021-06-11 00:16:08 -0400119#undef DIV
120#undef DIV_FIXED
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400121};
122
123#undef DIV
124#undef DIV_LIST
125
Sean Anderson609bd602021-06-11 00:16:08 -0400126/**
127 * struct k210_gate_params - Parameters for gated clocks
128 * @off: The offset of the gate from the sysctl base address
129 * @bit_idx: The index of the bit within the register
130 */
131struct k210_gate_params {
132 u8 off;
133 u8 bit_idx;
134};
135
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400136#define GATE_LIST \
137 GATE(K210_CLK_CPU, K210_SYSCTL_EN_CENT, 0) \
138 GATE(K210_CLK_SRAM0, K210_SYSCTL_EN_CENT, 1) \
139 GATE(K210_CLK_SRAM1, K210_SYSCTL_EN_CENT, 2) \
140 GATE(K210_CLK_APB0, K210_SYSCTL_EN_CENT, 3) \
141 GATE(K210_CLK_APB1, K210_SYSCTL_EN_CENT, 4) \
142 GATE(K210_CLK_APB2, K210_SYSCTL_EN_CENT, 5) \
143 GATE(K210_CLK_ROM, K210_SYSCTL_EN_PERI, 0) \
144 GATE(K210_CLK_DMA, K210_SYSCTL_EN_PERI, 1) \
145 GATE(K210_CLK_AI, K210_SYSCTL_EN_PERI, 2) \
146 GATE(K210_CLK_DVP, K210_SYSCTL_EN_PERI, 3) \
147 GATE(K210_CLK_FFT, K210_SYSCTL_EN_PERI, 4) \
148 GATE(K210_CLK_GPIO, K210_SYSCTL_EN_PERI, 5) \
149 GATE(K210_CLK_SPI0, K210_SYSCTL_EN_PERI, 6) \
150 GATE(K210_CLK_SPI1, K210_SYSCTL_EN_PERI, 7) \
151 GATE(K210_CLK_SPI2, K210_SYSCTL_EN_PERI, 8) \
152 GATE(K210_CLK_SPI3, K210_SYSCTL_EN_PERI, 9) \
153 GATE(K210_CLK_I2S0, K210_SYSCTL_EN_PERI, 10) \
154 GATE(K210_CLK_I2S1, K210_SYSCTL_EN_PERI, 11) \
155 GATE(K210_CLK_I2S2, K210_SYSCTL_EN_PERI, 12) \
156 GATE(K210_CLK_I2C0, K210_SYSCTL_EN_PERI, 13) \
157 GATE(K210_CLK_I2C1, K210_SYSCTL_EN_PERI, 14) \
158 GATE(K210_CLK_I2C2, K210_SYSCTL_EN_PERI, 15) \
159 GATE(K210_CLK_UART1, K210_SYSCTL_EN_PERI, 16) \
160 GATE(K210_CLK_UART2, K210_SYSCTL_EN_PERI, 17) \
161 GATE(K210_CLK_UART3, K210_SYSCTL_EN_PERI, 18) \
162 GATE(K210_CLK_AES, K210_SYSCTL_EN_PERI, 19) \
163 GATE(K210_CLK_FPIOA, K210_SYSCTL_EN_PERI, 20) \
164 GATE(K210_CLK_TIMER0, K210_SYSCTL_EN_PERI, 21) \
165 GATE(K210_CLK_TIMER1, K210_SYSCTL_EN_PERI, 22) \
166 GATE(K210_CLK_TIMER2, K210_SYSCTL_EN_PERI, 23) \
167 GATE(K210_CLK_WDT0, K210_SYSCTL_EN_PERI, 24) \
168 GATE(K210_CLK_WDT1, K210_SYSCTL_EN_PERI, 25) \
169 GATE(K210_CLK_SHA, K210_SYSCTL_EN_PERI, 26) \
170 GATE(K210_CLK_OTP, K210_SYSCTL_EN_PERI, 27) \
171 GATE(K210_CLK_RTC, K210_SYSCTL_EN_PERI, 29)
172
173#define _GATEIFY(id) K210_CLK_GATE_##id
174#define GATEIFY(id) _GATEIFY(id)
175
Sean Anderson609bd602021-06-11 00:16:08 -0400176enum k210_gate_id {
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400177#define GATE(id, ...) GATEIFY(id),
178 GATE_LIST
179#undef GATE
Sean Anderson609bd602021-06-11 00:16:08 -0400180 K210_CLK_GATE_NONE,
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400181};
182
183static const struct k210_gate_params k210_gates[] = {
184#define GATE(id, _off, _idx) \
185 [GATEIFY(id)] = { \
186 .off = (_off), \
187 .bit_idx = (_idx), \
188 },
189 GATE_LIST
190#undef GATE
191};
192
193#undef GATE_LIST
194
Sean Anderson609bd602021-06-11 00:16:08 -0400195/* The most parents is PLL2 */
196#define K210_CLK_MAX_PARENTS 3
197
198/**
199 * struct k210_mux_params - Parameters for muxed clocks
200 * @parents: A list of parent clock ids
201 * @num_parents: The number of parent clocks
202 * @off: The offset of the mux from the base sysctl address
203 * @shift: The offset of the LSB of the mux selector
204 * @width: The number of bits in the mux selector
205 */
206struct k210_mux_params {
207 u8 parents[K210_CLK_MAX_PARENTS];
208 u8 num_parents;
209 u8 off;
210 u8 shift;
211 u8 width;
212};
213
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400214#define MUX(id, reg, shift, width) \
Sean Anderson609bd602021-06-11 00:16:08 -0400215 MUX_PARENTS(id, reg, shift, width, K210_CLK_IN0, K210_CLK_PLL0)
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400216#define MUX_LIST \
Sean Anderson609bd602021-06-11 00:16:08 -0400217 MUX_PARENTS(K210_CLK_PLL2, K210_SYSCTL_PLL2, 26, 2, \
218 K210_CLK_IN0, K210_CLK_PLL0, K210_CLK_PLL1) \
219 MUX(K210_CLK_ACLK, K210_SYSCTL_SEL0, 0, 1) \
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400220 MUX(K210_CLK_SPI3, K210_SYSCTL_SEL0, 12, 1) \
221 MUX(K210_CLK_TIMER0, K210_SYSCTL_SEL0, 13, 1) \
222 MUX(K210_CLK_TIMER1, K210_SYSCTL_SEL0, 14, 1) \
223 MUX(K210_CLK_TIMER2, K210_SYSCTL_SEL0, 15, 1)
224
225#define _MUXIFY(id) K210_CLK_MUX_##id
226#define MUXIFY(id) _MUXIFY(id)
227
Sean Anderson609bd602021-06-11 00:16:08 -0400228enum k210_mux_id {
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400229#define MUX_PARENTS(id, ...) MUXIFY(id),
230 MUX_LIST
231#undef MUX_PARENTS
232 K210_CLK_MUX_NONE,
233};
234
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400235static const struct k210_mux_params k210_muxes[] = {
Sean Anderson609bd602021-06-11 00:16:08 -0400236#define MUX_PARENTS(id, _off, _shift, _width, ...) \
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400237 [MUXIFY(id)] = { \
Sean Anderson609bd602021-06-11 00:16:08 -0400238 .parents = { __VA_ARGS__ }, \
239 .num_parents = __count_args(__VA_ARGS__), \
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400240 .off = (_off), \
241 .shift = (_shift), \
242 .width = (_width), \
243 },
244 MUX_LIST
245#undef MUX_PARENTS
246};
247
248#undef MUX
249#undef MUX_LIST
250
Sean Anderson609bd602021-06-11 00:16:08 -0400251/**
252 * enum k210_clk_flags - The type of a K210 clock
253 * @K210_CLKF_MUX: This clock has a mux and not a static parent
254 * @K210_CLKF_PLL: This clock is a PLL
255 */
256enum k210_clk_flags {
257 K210_CLKF_MUX = BIT(0),
258 K210_CLKF_PLL = BIT(1),
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400259};
260
Sean Anderson609bd602021-06-11 00:16:08 -0400261/**
262 * struct k210_clk_params - The parameters defining a K210 clock
263 * @name: The name of the clock
264 * @flags: A set of &enum k210_clk_flags defining which fields are valid
265 * @mux: An &enum k210_mux_id of this clock's mux
266 * @parent: The clock id of this clock's parent
267 * @pll: The id of the PLL (if this clock is a PLL)
268 * @div: An &enum k210_div_id of this clock's divider
269 * @gate: An &enum k210_gate_id of this clock's gate
270 */
271struct k210_clk_params {
272#if CONFIG_IS_ENABLED(CMD_CLK)
273 const char *name;
274#endif
275 u8 flags;
276 union {
277 u8 parent;
278 u8 mux;
279 };
280 union {
281 u8 pll;
282 struct {
283 u8 div;
284 u8 gate;
285 };
286 };
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400287};
288
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400289
Sean Anderson609bd602021-06-11 00:16:08 -0400290static const struct k210_clk_params k210_clks[] = {
291#if CONFIG_IS_ENABLED(CMD_CLK)
292#define NAME(_name) .name = (_name),
293#else
294#define NAME(name)
295#endif
296#define CLK(id, _name, _parent, _div, _gate) \
297 [id] = { \
298 NAME(_name) \
299 .parent = (_parent), \
300 .div = (_div), \
301 .gate = (_gate), \
302 }
303#define CLK_MUX(id, _name, _mux, _div, _gate) \
304 [id] = { \
305 NAME(_name) \
306 .flags = K210_CLKF_MUX, \
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400307 .mux = (_mux), \
308 .div = (_div), \
309 .gate = (_gate), \
Sean Anderson609bd602021-06-11 00:16:08 -0400310 }
311#define CLK_PLL(id, _pll, _parent) \
312 [id] = { \
313 NAME("pll" #_pll) \
314 .flags = K210_CLKF_PLL, \
315 .parent = (_parent), \
316 .pll = (_pll), \
317 }
318#define CLK_FULL(id, name) \
319 CLK_MUX(id, name, MUXIFY(id), DIVIFY(id), GATEIFY(id))
320#define CLK_NOMUX(id, name, parent) \
321 CLK(id, name, parent, DIVIFY(id), GATEIFY(id))
322#define CLK_DIV(id, name, parent) \
323 CLK(id, name, parent, DIVIFY(id), K210_CLK_GATE_NONE)
324#define CLK_GATE(id, name, parent) \
325 CLK(id, name, parent, K210_CLK_DIV_NONE, GATEIFY(id))
326 CLK_PLL(K210_CLK_PLL0, 0, K210_CLK_IN0),
327 CLK_PLL(K210_CLK_PLL1, 1, K210_CLK_IN0),
328 [K210_CLK_PLL2] = {
329 NAME("pll2")
330 .flags = K210_CLKF_MUX | K210_CLKF_PLL,
331 .mux = MUXIFY(K210_CLK_PLL2),
332 .pll = 2,
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400333 },
Sean Anderson609bd602021-06-11 00:16:08 -0400334 CLK_MUX(K210_CLK_ACLK, "aclk", MUXIFY(K210_CLK_ACLK),
335 DIVIFY(K210_CLK_ACLK), K210_CLK_GATE_NONE),
336 CLK_FULL(K210_CLK_SPI3, "spi3"),
337 CLK_FULL(K210_CLK_TIMER0, "timer0"),
338 CLK_FULL(K210_CLK_TIMER1, "timer1"),
339 CLK_FULL(K210_CLK_TIMER2, "timer2"),
340 CLK_NOMUX(K210_CLK_SRAM0, "sram0", K210_CLK_ACLK),
341 CLK_NOMUX(K210_CLK_SRAM1, "sram1", K210_CLK_ACLK),
342 CLK_NOMUX(K210_CLK_ROM, "rom", K210_CLK_ACLK),
343 CLK_NOMUX(K210_CLK_DVP, "dvp", K210_CLK_ACLK),
344 CLK_NOMUX(K210_CLK_APB0, "apb0", K210_CLK_ACLK),
345 CLK_NOMUX(K210_CLK_APB1, "apb1", K210_CLK_ACLK),
346 CLK_NOMUX(K210_CLK_APB2, "apb2", K210_CLK_ACLK),
347 CLK_NOMUX(K210_CLK_AI, "ai", K210_CLK_PLL1),
348 CLK_NOMUX(K210_CLK_I2S0, "i2s0", K210_CLK_PLL2),
349 CLK_NOMUX(K210_CLK_I2S1, "i2s1", K210_CLK_PLL2),
350 CLK_NOMUX(K210_CLK_I2S2, "i2s2", K210_CLK_PLL2),
351 CLK_NOMUX(K210_CLK_WDT0, "wdt0", K210_CLK_IN0),
352 CLK_NOMUX(K210_CLK_WDT1, "wdt1", K210_CLK_IN0),
353 CLK_NOMUX(K210_CLK_SPI0, "spi0", K210_CLK_PLL0),
354 CLK_NOMUX(K210_CLK_SPI1, "spi1", K210_CLK_PLL0),
355 CLK_NOMUX(K210_CLK_SPI2, "spi2", K210_CLK_PLL0),
356 CLK_NOMUX(K210_CLK_I2C0, "i2c0", K210_CLK_PLL0),
357 CLK_NOMUX(K210_CLK_I2C1, "i2c1", K210_CLK_PLL0),
358 CLK_NOMUX(K210_CLK_I2C2, "i2c2", K210_CLK_PLL0),
359 CLK_DIV(K210_CLK_I2S0_M, "i2s0_m", K210_CLK_PLL2),
360 CLK_DIV(K210_CLK_I2S1_M, "i2s1_m", K210_CLK_PLL2),
361 CLK_DIV(K210_CLK_I2S2_M, "i2s2_m", K210_CLK_PLL2),
362 CLK_DIV(K210_CLK_CLINT, "clint", K210_CLK_ACLK),
363 CLK_GATE(K210_CLK_CPU, "cpu", K210_CLK_ACLK),
364 CLK_GATE(K210_CLK_DMA, "dma", K210_CLK_ACLK),
365 CLK_GATE(K210_CLK_FFT, "fft", K210_CLK_ACLK),
366 CLK_GATE(K210_CLK_GPIO, "gpio", K210_CLK_APB0),
367 CLK_GATE(K210_CLK_UART1, "uart1", K210_CLK_APB0),
368 CLK_GATE(K210_CLK_UART2, "uart2", K210_CLK_APB0),
369 CLK_GATE(K210_CLK_UART3, "uart3", K210_CLK_APB0),
370 CLK_GATE(K210_CLK_FPIOA, "fpioa", K210_CLK_APB0),
371 CLK_GATE(K210_CLK_SHA, "sha", K210_CLK_APB0),
372 CLK_GATE(K210_CLK_AES, "aes", K210_CLK_APB1),
373 CLK_GATE(K210_CLK_OTP, "otp", K210_CLK_APB1),
374 CLK_GATE(K210_CLK_RTC, "rtc", K210_CLK_IN0),
375#undef NAME
376#undef CLK_PLL
377#undef CLK
378#undef CLK_FULL
379#undef CLK_NOMUX
380#undef CLK_DIV
381#undef CLK_GATE
382#undef CLK_LIST
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400383};
384
Sean Anderson609bd602021-06-11 00:16:08 -0400385static u32 k210_clk_readl(struct k210_clk_priv *priv, u8 off, u8 shift,
386 u8 width)
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400387{
Sean Anderson609bd602021-06-11 00:16:08 -0400388 u32 reg = readl(priv->base + off);
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400389
Sean Anderson609bd602021-06-11 00:16:08 -0400390 return (reg >> shift) & (BIT(width) - 1);
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400391}
392
Sean Anderson609bd602021-06-11 00:16:08 -0400393static void k210_clk_writel(struct k210_clk_priv *priv, u8 off, u8 shift,
394 u8 width, u32 val)
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400395{
Sean Anderson609bd602021-06-11 00:16:08 -0400396 u32 reg = readl(priv->base + off);
397 u32 mask = (BIT(width) - 1) << shift;
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400398
Sean Anderson609bd602021-06-11 00:16:08 -0400399 reg &= ~mask;
400 reg |= mask & (val << shift);
401 writel(reg, priv->base + off);
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400402}
403
Sean Anderson609bd602021-06-11 00:16:08 -0400404static int k210_clk_get_parent(struct k210_clk_priv *priv, int id)
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400405{
Sean Anderson609bd602021-06-11 00:16:08 -0400406 u32 sel;
407 const struct k210_mux_params *mux;
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400408
Sean Anderson609bd602021-06-11 00:16:08 -0400409 if (!(k210_clks[id].flags & K210_CLKF_MUX))
410 return k210_clks[id].parent;
411 mux = &k210_muxes[k210_clks[id].mux];
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400412
Sean Anderson609bd602021-06-11 00:16:08 -0400413 sel = k210_clk_readl(priv, mux->off, mux->shift, mux->width);
414 assert(sel < mux->num_parents);
415 return mux->parents[sel];
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400416}
417
Sean Anderson609bd602021-06-11 00:16:08 -0400418static ulong do_k210_clk_get_rate(struct k210_clk_priv *priv, int id)
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400419{
Sean Anderson609bd602021-06-11 00:16:08 -0400420 int parent;
421 u32 val;
422 ulong parent_rate;
423 const struct k210_div_params *div;
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400424
Sean Anderson609bd602021-06-11 00:16:08 -0400425 if (id == K210_CLK_IN0)
426 return clk_get_rate(&priv->in0);
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400427
Sean Anderson609bd602021-06-11 00:16:08 -0400428 parent = k210_clk_get_parent(priv, id);
429 parent_rate = do_k210_clk_get_rate(priv, parent);
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400430
Sean Anderson609bd602021-06-11 00:16:08 -0400431 if (k210_clks[id].flags & K210_CLKF_PLL)
432 return k210_pll_get_rate(priv, k210_clks[id].pll, parent_rate);
433
434 if (k210_clks[id].div == K210_CLK_DIV_NONE)
435 return parent_rate;
436 div = &k210_divs[k210_clks[id].div];
437
438 if (div->type == K210_DIV_FIXED)
439 return parent_rate / div->div;
440
441 val = k210_clk_readl(priv, div->off, div->shift, div->width);
442 switch (div->type) {
443 case K210_DIV_ONE:
444 return parent_rate / (val + 1);
445 case K210_DIV_EVEN:
446 return parent_rate / 2 / (val + 1);
447 case K210_DIV_POWER:
448 /* This is ACLK, which has no divider on IN0 */
449 if (parent == K210_CLK_IN0)
450 return parent_rate;
451 return parent_rate / (2 << val);
452 default:
453 assert(false);
454 return -EINVAL;
455 };
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400456}
457
Sean Anderson609bd602021-06-11 00:16:08 -0400458static ulong k210_clk_get_rate(struct clk *clk)
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400459{
Sean Anderson609bd602021-06-11 00:16:08 -0400460 return do_k210_clk_get_rate(dev_get_priv(clk->dev), clk->id);
461}
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400462
Sean Anderson609bd602021-06-11 00:16:08 -0400463static ulong k210_clk_set_rate(struct clk *clk, unsigned long rate)
464{
465 return -ENOSYS;
466}
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400467
Sean Anderson609bd602021-06-11 00:16:08 -0400468static int do_k210_clk_set_parent(struct k210_clk_priv *priv, int id, int new)
469{
470 int i;
471 const struct k210_mux_params *mux;
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400472
Sean Anderson609bd602021-06-11 00:16:08 -0400473 if (!(k210_clks[id].flags & K210_CLKF_MUX))
474 return -ENOSYS;
475 mux = &k210_muxes[k210_clks[id].mux];
476
477 for (i = 0; i < mux->num_parents; i++) {
478 if (mux->parents[i] == new) {
479 k210_clk_writel(priv, mux->off, mux->shift, mux->width,
480 i);
481 return 0;
482 }
483 }
484 return -EINVAL;
485}
486
487static int k210_clk_set_parent(struct clk *clk, struct clk *parent)
488{
489 return do_k210_clk_set_parent(dev_get_priv(clk->dev), clk->id,
490 parent->id);
491}
492
493static int k210_clk_endisable(struct k210_clk_priv *priv, int id, bool enable)
494{
495 int parent = k210_clk_get_parent(priv, id);
496 const struct k210_gate_params *gate;
497
498 if (id == K210_CLK_IN0) {
499 if (enable)
500 return clk_enable(&priv->in0);
501 else
502 return clk_disable(&priv->in0);
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400503 }
504
Sean Anderson609bd602021-06-11 00:16:08 -0400505 /* Only recursively enable clocks since we don't track refcounts */
506 if (enable) {
507 int ret = k210_clk_endisable(priv, parent, true);
508
509 if (ret && ret != -ENOSYS)
510 return ret;
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400511 }
512
Sean Anderson609bd602021-06-11 00:16:08 -0400513 if (k210_clks[id].flags & K210_CLKF_PLL) {
514 if (enable)
515 return k210_pll_enable(priv, k210_clks[id].pll);
516 else
517 return k210_pll_disable(priv, k210_clks[id].pll);
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400518 }
519
Sean Anderson609bd602021-06-11 00:16:08 -0400520 if (k210_clks[id].gate == K210_CLK_GATE_NONE)
521 return -ENOSYS;
522 gate = &k210_gates[k210_clks[id].gate];
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400523
Sean Anderson609bd602021-06-11 00:16:08 -0400524 k210_clk_writel(priv, gate->off, gate->bit_idx, 1, enable);
Sean Anderson09ad08f2021-04-08 22:13:08 -0400525 return 0;
526}
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400527
Sean Anderson609bd602021-06-11 00:16:08 -0400528static int k210_clk_enable(struct clk *clk)
529{
530 return k210_clk_endisable(dev_get_priv(clk->dev), clk->id, true);
531}
532
533static int k210_clk_disable(struct clk *clk)
534{
535 return k210_clk_endisable(dev_get_priv(clk->dev), clk->id, false);
536}
537
538static int k210_clk_request(struct clk *clk)
539{
540 if (clk->id >= ARRAY_SIZE(k210_clks))
541 return -EINVAL;
542 return 0;
543}
544
545static const struct clk_ops k210_clk_ops = {
546 .request = k210_clk_request,
547 .set_rate = k210_clk_set_rate,
548 .get_rate = k210_clk_get_rate,
549 .set_parent = k210_clk_set_parent,
550 .enable = k210_clk_enable,
551 .disable = k210_clk_disable,
552};
553
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400554static int k210_clk_probe(struct udevice *dev)
555{
556 int ret;
Sean Anderson609bd602021-06-11 00:16:08 -0400557 struct k210_clk_priv *priv = dev_get_priv(dev);
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400558
Sean Anderson609bd602021-06-11 00:16:08 -0400559 priv->base = dev_read_addr_ptr(dev_get_parent(dev));
560 if (!priv->base)
Simon Glass9042bf62021-03-25 10:26:08 +1300561 return -EINVAL;
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400562
Sean Anderson609bd602021-06-11 00:16:08 -0400563 ret = clk_get_by_index(dev, 0, &priv->in0);
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400564 if (ret)
565 return ret;
Sean Andersona952c3a2020-09-28 10:52:27 -0400566
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400567 return 0;
568}
569
570static const struct udevice_id k210_clk_ids[] = {
571 { .compatible = "kendryte,k210-clk" },
572 { },
573};
574
575U_BOOT_DRIVER(k210_clk) = {
576 .name = "k210_clk",
577 .id = UCLASS_CLK,
578 .of_match = k210_clk_ids,
579 .ops = &k210_clk_ops,
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400580 .probe = k210_clk_probe,
Sean Anderson609bd602021-06-11 00:16:08 -0400581 .priv_auto = sizeof(struct k210_clk_priv),
Sean Andersonf9c7d4f2020-06-24 06:41:11 -0400582};