1 /* $NetBSD: exynos5410_clock.c,v 1.7 2021/01/27 03:10:19 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2015-2017 Jared McNeill <jmcneill@invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: exynos5410_clock.c,v 1.7 2021/01/27 03:10:19 thorpej Exp $");
31
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/device.h>
35 #include <sys/intr.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/atomic.h>
39
40 #include <dev/clk/clk_backend.h>
41
42 #include <arm/samsung/exynos_reg.h>
43 #include <arm/samsung/exynos_var.h>
44 #include <arm/samsung/exynos_clock.h>
45
46 #include <dev/fdt/fdtvar.h>
47
48 static struct clk *exynos5410_clock_decode(device_t, int, const void *, size_t);
49
50 static const struct fdtbus_clock_controller_func exynos5410_car_fdtclock_funcs = {
51 .decode = exynos5410_clock_decode
52 };
53
54 /* DT clock ID to clock name mappings */
55 static struct exynos5410_clock_id {
56 u_int id;
57 const char *name;
58 } exynos5410_clock_ids[] = {
59 /* core clocks */
60 { 1, "fin_pll" },
61 { 2, "fout_apll" },
62 { 3, "fout_cpll" },
63 { 4, "fout_dpll" },
64 { 5, "fout_mpll" },
65 { 6, "fout_kpll" },
66 { 7, "fout_epll" },
67
68 /* gate for special clocks (sclk) */
69 { 128, "sclk_uart0" },
70 { 129, "sclk_uart1" },
71 { 130, "sclk_uart2" },
72 { 131, "sclk_uart3" },
73 { 132, "sclk_mmc0" },
74 { 133, "sclk_mmc1" },
75 { 134, "sclk_mmc2" },
76 { 150, "sclk_usbd300" },
77 { 151, "sclk_usbd301" },
78 { 152, "sclk_usbphy300" },
79 { 153, "sclk_usbphy301" },
80 { 155, "sclk_pwm" },
81
82 /* gate clocks */
83 { 257, "uart0" },
84 { 258, "uart1" },
85 { 259, "uart2" },
86 { 260, "uart3" },
87 { 261, "i2c0" },
88 { 262, "i2c1" },
89 { 263, "i2c2" },
90 { 264, "i2c3" },
91 { 265, "usi0" },
92 { 266, "usi1" },
93 { 267, "usi2" },
94 { 268, "usi3" },
95 { 279, "pwm" },
96 { 315, "mct" },
97 { 316, "wdt" },
98 { 317, "rtc" },
99 { 318, "tmu" },
100 { 351, "mmc0" },
101 { 352, "mmc1" },
102 { 353, "mmc2" },
103 { 362, "pdma0" },
104 { 363, "pdma1" },
105 { 365, "usbh20" },
106 { 366, "usbd300" },
107 { 367, "usbd301" },
108 { 471, "sss" },
109 };
110
111 static struct clk *exynos5410_clock_get(void *, const char *);
112 static void exynos5410_clock_put(void *, struct clk *);
113 static u_int exynos5410_clock_get_rate(void *, struct clk *);
114 static int exynos5410_clock_set_rate(void *, struct clk *, u_int);
115 static int exynos5410_clock_enable(void *, struct clk *);
116 static int exynos5410_clock_disable(void *, struct clk *);
117 static int exynos5410_clock_set_parent(void *, struct clk *, struct clk *);
118 static struct clk *exynos5410_clock_get_parent(void *, struct clk *);
119
120 static const struct clk_funcs exynos5410_clock_funcs = {
121 .get = exynos5410_clock_get,
122 .put = exynos5410_clock_put,
123 .get_rate = exynos5410_clock_get_rate,
124 .set_rate = exynos5410_clock_set_rate,
125 .enable = exynos5410_clock_enable,
126 .disable = exynos5410_clock_disable,
127 .set_parent = exynos5410_clock_set_parent,
128 .get_parent = exynos5410_clock_get_parent,
129 };
130
131 #define CLK_FIXED(_name, _rate) { \
132 .base = { .name = (_name) }, .type = EXYNOS_CLK_FIXED, \
133 .u = { .fixed = { .rate = (_rate) } } \
134 }
135
136 #define CLK_PLL(_name, _parent, _lock, _con0) { \
137 .base = { .name = (_name) }, .type = EXYNOS_CLK_PLL, \
138 .parent = (_parent), \
139 .u = { \
140 .pll = { \
141 .lock_reg = (_lock), \
142 .con0_reg = (_con0), \
143 } \
144 } \
145 }
146
147 #define CLK_MUXF(_name, _alias, _reg, _bits, _f, _p) { \
148 .base = { .name = (_name), .flags = (_f) }, \
149 .type = EXYNOS_CLK_MUX, \
150 .alias = (_alias), \
151 .u = { \
152 .mux = { \
153 .nparents = __arraycount(_p), \
154 .parents = (_p), \
155 .reg = (_reg), \
156 .bits = (_bits) \
157 } \
158 } \
159 }
160
161 #define CLK_MUXA(_name, _alias, _reg, _bits, _p) \
162 CLK_MUXF(_name, _alias, _reg, _bits, 0, _p)
163
164 #define CLK_MUX(_name, _reg, _bits, _p) \
165 CLK_MUXF(_name, NULL, _reg, _bits, 0, _p)
166
167 #define CLK_DIVF(_name, _parent, _reg, _bits, _f) { \
168 .base = { .name = (_name), .flags = (_f) }, \
169 .type = EXYNOS_CLK_DIV, \
170 .parent = (_parent), \
171 .u = { \
172 .div = { \
173 .reg = (_reg), \
174 .bits = (_bits) \
175 } \
176 } \
177 }
178
179 #define CLK_DIV(_name, _parent, _reg, _bits) \
180 CLK_DIVF(_name, _parent, _reg, _bits, 0)
181
182 #define CLK_GATE(_name, _parent, _reg, _bits, _f) { \
183 .base = { .name = (_name), .flags = (_f) }, \
184 .type = EXYNOS_CLK_GATE, \
185 .parent = (_parent), \
186 .u = { \
187 .gate = { \
188 .reg = (_reg), \
189 .bits = (_bits) \
190 } \
191 } \
192 }
193
194 #define EXYNOS5410_APLL_LOCK 0x00000
195 #define EXYNOS5410_APLL_CON0 0x00100
196 #define EXYNOS5410_MPLL_LOCK 0x04000
197 #define EXYNOS5410_MPLL_CON0 0x04100
198 #define EXYNOS5410_CPLL_LOCK 0x10020
199 #define EXYNOS5410_EPLL_LOCK 0x10040
200 #define EXYNOS5410_CPLL_CON0 0x10120
201 #define EXYNOS5410_EPLL_CON0 0x10130
202 #define EXYNOS5410_EPLL_CON1 0x10134
203 #define EXYNOS5410_EPLL_CON2 0x10138
204 #define EXYNOS5410_BPLL_LOCK 0x20010
205 #define EXYNOS5410_BPLL_CON0 0x20110
206 #define EXYNOS5410_KPLL_LOCK 0x28000
207 #define EXYNOS5410_KPLL_CON0 0x28100
208
209 #define EXYNOS5410_SRC_CPU 0x00200
210 #define EXYNOS5410_SRC_CPERI1 0x04204
211 #define EXYNOS5410_SRC_TOP0 0x10210
212 #define EXYNOS5410_SRC_TOP1 0x10214
213 #define EXYNOS5410_SRC_TOP2 0x10218
214 #define EXYNOS5410_SRC_FSYS 0x10244
215 #define EXYNOS5410_SRC_PERIC0 0x10250
216 #define EXYNOS5410_SRC_MASK_FSYS 0x10340
217 #define EXYNOS5410_SRC_MASK_PERIC0 0x10350
218 #define EXYNOS5410_SRC_CDREX 0x20200
219 #define EXYNOS5410_SRC_KFC 0x28200
220
221 #define EXYNOS5410_DIV_CPU0 0x00500
222 #define EXYNOS5410_DIV_TOP0 0x10510
223 #define EXYNOS5410_DIV_TOP1 0x10514
224 #define EXYNOS5410_DIV_FSYS0 0x10548
225 #define EXYNOS5410_DIV_FSYS1 0x1054c
226 #define EXYNOS5410_DIV_FSYS2 0x10550
227 #define EXYNOS5410_DIV_PERIC0 0x10558
228 #define EXYNOS5410_DIV_PERIC3 0x10564
229 #define EXYNOS5410_DIV_KFC0 0x28500
230
231 #define EXYNOS5410_GATE_IP_G2D 0x08800
232 #define EXYNOS5410_GATE_BUS_FSYS0 0x10740
233 #define EXYNOS5410_GATE_TOP_SCLK_FSYS 0x10840
234 #define EXYNOS5410_GATE_TOP_SCLK_PERIC 0x10850
235 #define EXYNOS5410_GATE_IP_FSYS 0x10944
236 #define EXYNOS5410_GATE_IP_PERIC 0x10950
237 #define EXYNOS5410_GATE_IP_PERIS 0x10960
238
239 static const char *mout_apll_p[] = { "fin_pll", "fout_apll" };
240 static const char *mout_bpll_p[] = { "fin_pll", "fout_bpll" };
241 static const char *mout_cpll_p[] = { "fin_pll", "fout_cpll" };
242 static const char *mout_epll_p[] = { "fin_pll", "fout_epll" };
243 static const char *mout_mpll_p[] = { "fin_pll", "fout_mpll" };
244 static const char *mout_kpll_p[] = { "fin_pll", "fout_kpll" };
245
246 static const char *mout_cpu_p[] = { "mout_apll", "sclk_mpll" };
247 static const char *mout_kfc_p[] = { "mout_kpll", "sclk_mpll" };
248
249 static const char *mout_mpll_user_p[] = { "fin_pll", "sclk_mpll" };
250 static const char *mout_bpll_user_p[] = { "fin_pll", "sclk_bpll" };
251 static const char *mout_mpll_bpll_p[] =
252 { "sclk_mpll_muxed", "sclk_bpll_muxed" };
253 static const char *mout_sclk_mpll_bpll_p[] = { "sclk_mpll_bpll", "fin_pll" };
254
255 static const char *mout_group2_p[] =
256 { "fin_pll", "fin_pll", "none", "none", "none", "none",
257 "sclk_mpll_bpll", "none", "none", "sclk_cpll" };
258
259 static struct exynos_clk exynos5410_clocks[] = {
260 CLK_FIXED("fin_pll", EXYNOS_F_IN_FREQ),
261
262 CLK_PLL("fout_apll", "fin_pll", EXYNOS5410_APLL_LOCK,
263 EXYNOS5410_APLL_CON0),
264 CLK_PLL("fout_bpll", "fin_pll", EXYNOS5410_BPLL_LOCK,
265 EXYNOS5410_BPLL_CON0),
266 CLK_PLL("fout_cpll", "fin_pll", EXYNOS5410_CPLL_LOCK,
267 EXYNOS5410_CPLL_CON0),
268 CLK_PLL("fout_epll", "fin_pll", EXYNOS5410_EPLL_LOCK,
269 EXYNOS5410_EPLL_CON0),
270 CLK_PLL("fout_mpll", "fin_pll", EXYNOS5410_MPLL_LOCK,
271 EXYNOS5410_MPLL_CON0),
272 CLK_PLL("fout_kpll", "fin_pll", EXYNOS5410_KPLL_LOCK,
273 EXYNOS5410_KPLL_CON0),
274
275 CLK_MUX("mout_apll", EXYNOS5410_SRC_CPU, __BIT(0), mout_apll_p),
276 CLK_MUX("mout_cpu", EXYNOS5410_SRC_CPU, __BIT(16), mout_cpu_p),
277 CLK_MUX("mout_kpll", EXYNOS5410_SRC_KFC, __BIT(0), mout_kpll_p),
278 CLK_MUX("mout_kfc", EXYNOS5410_SRC_KFC, __BIT(16), mout_kfc_p),
279
280 CLK_MUX("sclk_mpll", EXYNOS5410_SRC_CPERI1, __BIT(8), mout_mpll_p),
281 CLK_MUX("sclk_mpll_muxed", EXYNOS5410_SRC_TOP2, __BIT(20), mout_mpll_user_p),
282 CLK_MUX("sclk_bpll", EXYNOS5410_SRC_CDREX, __BIT(0), mout_bpll_p),
283 CLK_MUX("sclk_bpll_muxed", EXYNOS5410_SRC_TOP2, __BIT(24), mout_bpll_user_p),
284 CLK_MUX("sclk_epll", EXYNOS5410_SRC_TOP2, __BIT(12), mout_epll_p),
285 CLK_MUX("sclk_cpll", EXYNOS5410_SRC_TOP2, __BIT(8), mout_cpll_p),
286 CLK_MUX("sclk_mpll_bpll", EXYNOS5410_SRC_TOP1, __BIT(20), mout_mpll_bpll_p),
287
288 CLK_MUX("mout_mmc0", EXYNOS5410_SRC_FSYS, __BITS(3,0), mout_group2_p),
289 CLK_MUX("mout_mmc1", EXYNOS5410_SRC_FSYS, __BITS(7,4), mout_group2_p),
290 CLK_MUX("mout_mmc2", EXYNOS5410_SRC_FSYS, __BITS(11,8), mout_group2_p),
291 CLK_MUX("mout_usbd300", EXYNOS5410_SRC_FSYS, __BIT(28), mout_sclk_mpll_bpll_p),
292 CLK_MUX("mout_usbd301", EXYNOS5410_SRC_FSYS, __BIT(29), mout_sclk_mpll_bpll_p),
293 CLK_MUX("mout_uart0", EXYNOS5410_SRC_PERIC0, __BITS(3,0), mout_group2_p),
294 CLK_MUX("mout_uart1", EXYNOS5410_SRC_PERIC0, __BITS(7,4), mout_group2_p),
295 CLK_MUX("mout_uart2", EXYNOS5410_SRC_PERIC0, __BITS(11,8), mout_group2_p),
296 CLK_MUX("mout_uart3", EXYNOS5410_SRC_PERIC0, __BITS(15,12), mout_group2_p),
297 CLK_MUX("mout_pwm", EXYNOS5410_SRC_PERIC0, __BITS(27,24), mout_group2_p),
298 CLK_MUX("mout_aclk200", EXYNOS5410_SRC_TOP0, __BIT(12), mout_mpll_bpll_p),
299 CLK_MUX("mout_aclk400", EXYNOS5410_SRC_TOP0, __BIT(20), mout_mpll_bpll_p),
300
301 CLK_DIV("div_arm", "mout_cpu", EXYNOS5410_DIV_CPU0, __BITS(2,0)),
302 CLK_DIV("div_arm2", "div_arm", EXYNOS5410_DIV_CPU0, __BITS(30,28)),
303
304 CLK_DIV("div_acp", "div_arm2", EXYNOS5410_DIV_CPU0, __BITS(10,8)),
305 CLK_DIV("div_cpud", "div_arm2", EXYNOS5410_DIV_CPU0, __BITS(6,4)),
306 CLK_DIV("div_atb", "div_arm2", EXYNOS5410_DIV_CPU0, __BITS(18,16)),
307 CLK_DIV("pclk_dbg", "div_arm2", EXYNOS5410_DIV_CPU0, __BITS(22,20)),
308
309 CLK_DIV("div_kfc", "mout_kfc", EXYNOS5410_DIV_KFC0, __BITS(2,0)),
310 CLK_DIV("div_aclk", "div_kfc", EXYNOS5410_DIV_KFC0, __BITS(6,4)),
311 CLK_DIV("div_pclk", "div_kfc", EXYNOS5410_DIV_KFC0, __BITS(22,20)),
312
313 CLK_DIV("aclk66_pre", "sclk_mpll_muxed", EXYNOS5410_DIV_TOP1, __BITS(26,24)),
314 CLK_DIV("aclk66", "aclk66_pre", EXYNOS5410_DIV_TOP0, __BITS(2,0)),
315
316 CLK_DIV("dout_usbphy300", "mout_usbd300", EXYNOS5410_DIV_FSYS0, __BITS(19,16)),
317 CLK_DIV("dout_usbphy301", "mout_usbd301", EXYNOS5410_DIV_FSYS0, __BITS(23,20)),
318 CLK_DIV("dout_usbd300", "mout_usbd300", EXYNOS5410_DIV_FSYS0, __BITS(27,24)),
319 CLK_DIV("dout_usbd301", "mout_usbd301", EXYNOS5410_DIV_FSYS0, __BITS(31,28)),
320
321 CLK_DIV("dout_mmc0", "mout_mmc0", EXYNOS5410_DIV_FSYS1, __BITS(3,0)),
322 CLK_DIV("dout_mmc1", "mout_mmc1", EXYNOS5410_DIV_FSYS1, __BITS(19,16)),
323 CLK_DIV("dout_mmc2", "mout_mmc2", EXYNOS5410_DIV_FSYS2, __BITS(3,0)),
324
325 CLK_DIVF("dout_mmc_pre0", "dout_mmc0", EXYNOS5410_DIV_FSYS1, __BITS(15,8),
326 CLK_SET_RATE_PARENT),
327 CLK_DIVF("dout_mmc_pre1", "dout_mmc1", EXYNOS5410_DIV_FSYS1, __BITS(31,24),
328 CLK_SET_RATE_PARENT),
329 CLK_DIVF("dout_mmc_pre2", "dout_mmc2", EXYNOS5410_DIV_FSYS2, __BITS(15,8),
330 CLK_SET_RATE_PARENT),
331
332 CLK_DIV("div_uart0", "mout_uart0", EXYNOS5410_DIV_PERIC0, __BITS(3,0)),
333 CLK_DIV("div_uart1", "mout_uart1", EXYNOS5410_DIV_PERIC0, __BITS(7,4)),
334 CLK_DIV("div_uart2", "mout_uart2", EXYNOS5410_DIV_PERIC0, __BITS(11,8)),
335 CLK_DIV("div_uart3", "mout_uart3", EXYNOS5410_DIV_PERIC0, __BITS(15,12)),
336
337 CLK_DIV("dout_pwm", "mout_pwm", EXYNOS5410_DIV_PERIC3, __BITS(3,0)),
338
339 CLK_DIV("aclk200", "mout_aclk200", EXYNOS5410_DIV_TOP0, __BITS(14,12)),
340 CLK_DIV("aclk266", "sclk_mpll_muxed", EXYNOS5410_DIV_TOP0, __BITS(18,16)),
341 CLK_DIV("aclk400", "mout_aclk400", EXYNOS5410_DIV_TOP0, __BITS(26,24)),
342
343 CLK_GATE("sss", "aclk266", EXYNOS5410_GATE_IP_G2D, __BIT(2), 0),
344
345 CLK_GATE("mct", "aclk66", EXYNOS5410_GATE_IP_PERIS, __BIT(18), 0),
346 CLK_GATE("wdt", "aclk66", EXYNOS5410_GATE_IP_PERIS, __BIT(19), 0),
347 CLK_GATE("rtc", "aclk66", EXYNOS5410_GATE_IP_PERIS, __BIT(20), 0),
348 CLK_GATE("tmu", "aclk66", EXYNOS5410_GATE_IP_PERIS, __BIT(21), 0),
349
350 CLK_GATE("sclk_mmc0", "dout_mmc_pre0", EXYNOS5410_SRC_MASK_FSYS,
351 __BIT(0), CLK_SET_RATE_PARENT),
352 CLK_GATE("sclk_mmc1", "dout_mmc_pre1", EXYNOS5410_SRC_MASK_FSYS,
353 __BIT(4), CLK_SET_RATE_PARENT),
354 CLK_GATE("sclk_mmc2", "dout_mmc_pre2", EXYNOS5410_SRC_MASK_FSYS,
355 __BIT(8), CLK_SET_RATE_PARENT),
356
357 CLK_GATE("mmc0", "aclk200", EXYNOS5410_GATE_BUS_FSYS0, __BIT(12), 0),
358 CLK_GATE("mmc1", "aclk200", EXYNOS5410_GATE_BUS_FSYS0, __BIT(13), 0),
359 CLK_GATE("mmc2", "aclk200", EXYNOS5410_GATE_BUS_FSYS0, __BIT(14), 0),
360 CLK_GATE("pdma1", "aclk200", EXYNOS5410_GATE_BUS_FSYS0, __BIT(2), 0),
361 CLK_GATE("pdma0", "aclk200", EXYNOS5410_GATE_BUS_FSYS0, __BIT(1), 0),
362
363 CLK_GATE("sclk_usbphy301", "dout_usbphy301", EXYNOS5410_GATE_TOP_SCLK_FSYS,
364 __BIT(7), CLK_SET_RATE_PARENT),
365 CLK_GATE("sclk_usbphy300", "dout_usbphy300", EXYNOS5410_GATE_TOP_SCLK_FSYS,
366 __BIT(8), CLK_SET_RATE_PARENT),
367 CLK_GATE("sclk_usbd301", "dout_usbd301", EXYNOS5410_GATE_TOP_SCLK_FSYS,
368 __BIT(9), CLK_SET_RATE_PARENT),
369 CLK_GATE("sclk_usbd301", "dout_usbd301", EXYNOS5410_GATE_TOP_SCLK_FSYS,
370 __BIT(10), CLK_SET_RATE_PARENT),
371
372 CLK_GATE("sclk_pwm", "dout_pwm", EXYNOS5410_GATE_TOP_SCLK_PERIC,
373 __BIT(11), CLK_SET_RATE_PARENT),
374
375 CLK_GATE("uart0", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(0), 0),
376 CLK_GATE("uart1", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(1), 0),
377 CLK_GATE("uart2", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(2), 0),
378 CLK_GATE("uart3", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(3), 0),
379 CLK_GATE("i2c0", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(6), 0),
380 CLK_GATE("i2c1", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(7), 0),
381 CLK_GATE("i2c2", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(8), 0),
382 CLK_GATE("i2c3", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(9), 0),
383 CLK_GATE("usi0", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(10), 0),
384 CLK_GATE("usi1", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(11), 0),
385 CLK_GATE("usi2", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(12), 0),
386 CLK_GATE("usi3", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(13), 0),
387 CLK_GATE("pwm", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(24), 0),
388
389 CLK_GATE("sclk_uart0", "div_uart0", EXYNOS5410_SRC_MASK_PERIC0,
390 __BIT(0), CLK_SET_RATE_PARENT),
391 CLK_GATE("sclk_uart1", "div_uart1", EXYNOS5410_SRC_MASK_PERIC0,
392 __BIT(4), CLK_SET_RATE_PARENT),
393 CLK_GATE("sclk_uart2", "div_uart2", EXYNOS5410_SRC_MASK_PERIC0,
394 __BIT(8), CLK_SET_RATE_PARENT),
395 CLK_GATE("sclk_uart3", "div_uart3", EXYNOS5410_SRC_MASK_PERIC0,
396 __BIT(12), CLK_SET_RATE_PARENT),
397
398 CLK_GATE("usbh20", "aclk200", EXYNOS5410_GATE_IP_FSYS, __BIT(18), 0),
399 CLK_GATE("usbd301", "aclk200", EXYNOS5410_GATE_IP_FSYS, __BIT(19), 0),
400 CLK_GATE("usbd300", "aclk200", EXYNOS5410_GATE_IP_FSYS, __BIT(20), 0),
401 };
402
403 static int exynos5410_clock_match(device_t, cfdata_t, void *);
404 static void exynos5410_clock_attach(device_t, device_t, void *);
405
406 struct exynos5410_clock_softc {
407 device_t sc_dev;
408 bus_space_tag_t sc_bst;
409 bus_space_handle_t sc_bsh;
410
411 struct clk_domain sc_clkdom;
412 };
413
414 static void exynos5410_clock_print_header(void);
415 static void exynos5410_clock_print(struct exynos5410_clock_softc *,
416 struct exynos_clk *);
417
418 CFATTACH_DECL_NEW(exynos5410_clock, sizeof(struct exynos5410_clock_softc),
419 exynos5410_clock_match, exynos5410_clock_attach, NULL, NULL);
420
421 #define CLOCK_READ(sc, reg) \
422 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
423 #define CLOCK_WRITE(sc, reg, val) \
424 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
425
426 static const struct device_compatible_entry compat_data[] = {
427 { .compat = "samsung,exynos5410-clock" },
428 DEVICE_COMPAT_EOL
429 };
430
431 static int
exynos5410_clock_match(device_t parent,cfdata_t cf,void * aux)432 exynos5410_clock_match(device_t parent, cfdata_t cf, void *aux)
433 {
434 struct fdt_attach_args * const faa = aux;
435
436 return of_compatible_match(faa->faa_phandle, compat_data);
437 }
438
439 static void
exynos5410_clock_attach(device_t parent,device_t self,void * aux)440 exynos5410_clock_attach(device_t parent, device_t self, void *aux)
441 {
442 struct exynos5410_clock_softc * const sc = device_private(self);
443 struct fdt_attach_args * const faa = aux;
444 bus_addr_t addr;
445 bus_size_t size;
446 int error;
447
448 if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) {
449 aprint_error(": couldn't get registers\n");
450 return;
451 }
452
453 sc->sc_dev = self;
454 sc->sc_bst = faa->faa_bst;
455
456 error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
457 if (error) {
458 aprint_error(": couldn't map %#" PRIxBUSADDR ": %d",
459 addr, error);
460 return;
461 }
462
463 aprint_naive("\n");
464 aprint_normal(": Exynos5410 Clock Controller\n");
465
466 sc->sc_clkdom.funcs = &exynos5410_clock_funcs;
467 sc->sc_clkdom.priv = sc;
468 for (u_int n = 0; n < __arraycount(exynos5410_clocks); n++) {
469 exynos5410_clocks[n].base.domain = &sc->sc_clkdom;
470 }
471
472 fdtbus_register_clock_controller(self, faa->faa_phandle,
473 &exynos5410_car_fdtclock_funcs);
474
475 exynos5410_clock_print_header();
476 for (u_int n = 0; n < __arraycount(exynos5410_clocks); n++) {
477 exynos5410_clock_print(sc, &exynos5410_clocks[n]);
478 }
479 }
480
481 static struct exynos_clk *
exynos5410_clock_find(const char * name)482 exynos5410_clock_find(const char *name)
483 {
484 u_int n;
485
486 for (n = 0; n < __arraycount(exynos5410_clocks); n++) {
487 if (strcmp(exynos5410_clocks[n].base.name, name) == 0) {
488 return &exynos5410_clocks[n];
489 }
490 }
491
492 return NULL;
493 }
494
495 static struct exynos_clk *
exynos5410_clock_find_by_id(u_int clock_id)496 exynos5410_clock_find_by_id(u_int clock_id)
497 {
498 u_int n;
499
500 for (n = 0; n < __arraycount(exynos5410_clock_ids); n++) {
501 if (exynos5410_clock_ids[n].id == clock_id) {
502 const char *name = exynos5410_clock_ids[n].name;
503 return exynos5410_clock_find(name);
504 }
505 }
506
507 return NULL;
508 }
509
510 static void
exynos5410_clock_print_header(void)511 exynos5410_clock_print_header(void)
512 {
513 printf(" %-10s %2s %-10s %-5s %10s\n",
514 "clock", "", "parent", "type", "rate");
515 printf(" %-10s %2s %-10s %-5s %10s\n",
516 "=====", "", "======", "====", "====");
517 }
518
519 static void
exynos5410_clock_print(struct exynos5410_clock_softc * sc,struct exynos_clk * eclk)520 exynos5410_clock_print(struct exynos5410_clock_softc *sc,
521 struct exynos_clk *eclk)
522 {
523 struct exynos_clk *eclk_parent;
524 struct clk *clk_parent;
525 const char *type = "?";
526
527 switch (eclk->type) {
528 case EXYNOS_CLK_FIXED:
529 type = "fixed";
530 break;
531 case EXYNOS_CLK_PLL:
532 type = "pll";
533 break;
534 case EXYNOS_CLK_MUX:
535 type = "mux";
536 break;
537 case EXYNOS_CLK_DIV:
538 type = "div";
539 break;
540 case EXYNOS_CLK_GATE:
541 type = "gate";
542 break;
543 }
544
545 clk_parent = exynos5410_clock_get_parent(sc, &eclk->base);
546 eclk_parent = (struct exynos_clk *)clk_parent;
547
548 printf(" %-10s %2s %-10s %-5s %10d Hz\n",
549 eclk->base.name,
550 eclk_parent ? "<-" : "",
551 eclk_parent ? eclk_parent->base.name : "",
552 type, clk_get_rate(&eclk->base));
553 }
554
555 static struct clk *
exynos5410_clock_decode(device_t dev,int cc_phandle,const void * data,size_t len)556 exynos5410_clock_decode(device_t dev, int cc_phandle, const void *data,
557 size_t len)
558 {
559 struct exynos_clk *eclk;
560
561 /* #clock-cells should be 1 */
562 if (len != 4) {
563 return NULL;
564 }
565
566 const u_int clock_id = be32dec(data);
567
568 eclk = exynos5410_clock_find_by_id(clock_id);
569 if (eclk)
570 return &eclk->base;
571
572 return NULL;
573 }
574
575 static u_int
exynos5410_clock_get_rate_pll(struct exynos5410_clock_softc * sc,struct exynos_clk * eclk)576 exynos5410_clock_get_rate_pll(struct exynos5410_clock_softc *sc,
577 struct exynos_clk *eclk)
578 {
579 struct exynos_pll_clk *epll = &eclk->u.pll;
580 struct exynos_clk *clk_parent;
581
582 KASSERT(eclk->type == EXYNOS_CLK_PLL);
583
584 clk_parent = exynos5410_clock_find(eclk->parent);
585 KASSERT(clk_parent != NULL);
586 const u_int rate_parent = exynos5410_clock_get_rate(sc,
587 &clk_parent->base);
588
589 const uint32_t v = CLOCK_READ(sc, epll->con0_reg);
590
591 return PLL_FREQ(rate_parent, v);
592 }
593
594 static int
exynos5410_clock_set_rate_pll(struct exynos5410_clock_softc * sc,struct exynos_clk * eclk,u_int rate)595 exynos5410_clock_set_rate_pll(struct exynos5410_clock_softc *sc,
596 struct exynos_clk *eclk, u_int rate)
597 {
598 /* TODO */
599 return EOPNOTSUPP;
600 }
601
602 static int
exynos5410_clock_set_parent_mux(struct exynos5410_clock_softc * sc,struct exynos_clk * eclk,struct exynos_clk * eclk_parent)603 exynos5410_clock_set_parent_mux(struct exynos5410_clock_softc *sc,
604 struct exynos_clk *eclk, struct exynos_clk *eclk_parent)
605 {
606 struct exynos_mux_clk *emux = &eclk->u.mux;
607 const char *pname = eclk_parent->base.name;
608 u_int sel;
609
610 KASSERT(eclk->type == EXYNOS_CLK_MUX);
611
612 for (sel = 0; sel < emux->nparents; sel++) {
613 if (strcmp(pname, emux->parents[sel]) == 0) {
614 break;
615 }
616 }
617 if (sel == emux->nparents) {
618 return EINVAL;
619 }
620
621 uint32_t v = CLOCK_READ(sc, emux->reg);
622 v &= ~emux->bits;
623 v |= __SHIFTIN(sel, emux->bits);
624 CLOCK_WRITE(sc, emux->reg, v);
625
626 return 0;
627 }
628
629 static struct exynos_clk *
exynos5410_clock_get_parent_mux(struct exynos5410_clock_softc * sc,struct exynos_clk * eclk)630 exynos5410_clock_get_parent_mux(struct exynos5410_clock_softc *sc,
631 struct exynos_clk *eclk)
632 {
633 struct exynos_mux_clk *emux = &eclk->u.mux;
634
635 KASSERT(eclk->type == EXYNOS_CLK_MUX);
636
637 const uint32_t v = CLOCK_READ(sc, emux->reg);
638 const u_int sel = __SHIFTOUT(v, emux->bits);
639
640 KASSERT(sel < emux->nparents);
641
642 return exynos5410_clock_find(emux->parents[sel]);
643 }
644
645 static u_int
exynos5410_clock_get_rate_div(struct exynos5410_clock_softc * sc,struct exynos_clk * eclk)646 exynos5410_clock_get_rate_div(struct exynos5410_clock_softc *sc,
647 struct exynos_clk *eclk)
648 {
649 struct exynos_div_clk *ediv = &eclk->u.div;
650 struct clk *clk_parent;
651
652 KASSERT(eclk->type == EXYNOS_CLK_DIV);
653
654 clk_parent = exynos5410_clock_get_parent(sc, &eclk->base);
655 const u_int parent_rate = exynos5410_clock_get_rate(sc, clk_parent);
656
657 const uint32_t v = CLOCK_READ(sc, ediv->reg);
658 const u_int div = __SHIFTOUT(v, ediv->bits);
659
660 return parent_rate / (div + 1);
661 }
662
663 static int
exynos5410_clock_set_rate_div(struct exynos5410_clock_softc * sc,struct exynos_clk * eclk,u_int rate)664 exynos5410_clock_set_rate_div(struct exynos5410_clock_softc *sc,
665 struct exynos_clk *eclk, u_int rate)
666 {
667 struct exynos_div_clk *ediv = &eclk->u.div;
668 struct clk *clk_parent;
669 int tmp_div, new_div = -1;
670 u_int tmp_rate;
671
672 KASSERT(eclk->type == EXYNOS_CLK_DIV);
673
674 clk_parent = exynos5410_clock_get_parent(sc, &eclk->base);
675 const u_int parent_rate = exynos5410_clock_get_rate(sc, clk_parent);
676
677 for (tmp_div = 0; tmp_div < __SHIFTOUT_MASK(ediv->bits); tmp_div++) {
678 tmp_rate = parent_rate / (tmp_div + 1);
679 if (tmp_rate <= rate) {
680 new_div = tmp_div;
681 break;
682 }
683 }
684 if (new_div == -1)
685 return EINVAL;
686
687 uint32_t v = CLOCK_READ(sc, ediv->reg);
688 v &= ~ediv->bits;
689 v |= __SHIFTIN(new_div, ediv->bits);
690 CLOCK_WRITE(sc, ediv->reg, v);
691
692 return 0;
693 }
694
695 static int
exynos5410_clock_enable_gate(struct exynos5410_clock_softc * sc,struct exynos_clk * eclk,bool enable)696 exynos5410_clock_enable_gate(struct exynos5410_clock_softc *sc,
697 struct exynos_clk *eclk, bool enable)
698 {
699 struct exynos_gate_clk *egate = &eclk->u.gate;
700
701 KASSERT(eclk->type == EXYNOS_CLK_GATE);
702
703 uint32_t v = CLOCK_READ(sc, egate->reg);
704 if (enable) {
705 v |= egate->bits;
706 } else {
707 v &= ~egate->bits;
708 }
709 CLOCK_WRITE(sc, egate->reg, v);
710
711 return 0;
712 }
713
714 /*
715 * clk api
716 */
717
718 static struct clk *
exynos5410_clock_get(void * priv,const char * name)719 exynos5410_clock_get(void *priv, const char *name)
720 {
721 struct exynos_clk *eclk;
722
723 eclk = exynos5410_clock_find(name);
724 if (eclk == NULL)
725 return NULL;
726
727 atomic_inc_uint(&eclk->refcnt);
728
729 return &eclk->base;
730 }
731
732 static void
exynos5410_clock_put(void * priv,struct clk * clk)733 exynos5410_clock_put(void *priv, struct clk *clk)
734 {
735 struct exynos_clk *eclk = (struct exynos_clk *)clk;
736
737 KASSERT(eclk->refcnt > 0);
738
739 atomic_dec_uint(&eclk->refcnt);
740 }
741
742 static u_int
exynos5410_clock_get_rate(void * priv,struct clk * clk)743 exynos5410_clock_get_rate(void *priv, struct clk *clk)
744 {
745 struct exynos_clk *eclk = (struct exynos_clk *)clk;
746 struct clk *clk_parent;
747
748 switch (eclk->type) {
749 case EXYNOS_CLK_FIXED:
750 return eclk->u.fixed.rate;
751 case EXYNOS_CLK_PLL:
752 return exynos5410_clock_get_rate_pll(priv, eclk);
753 case EXYNOS_CLK_MUX:
754 case EXYNOS_CLK_GATE:
755 clk_parent = exynos5410_clock_get_parent(priv, clk);
756 return exynos5410_clock_get_rate(priv, clk_parent);
757 case EXYNOS_CLK_DIV:
758 return exynos5410_clock_get_rate_div(priv, eclk);
759 default:
760 panic("exynos5410: unknown eclk type %d", eclk->type);
761 }
762 }
763
764 static int
exynos5410_clock_set_rate(void * priv,struct clk * clk,u_int rate)765 exynos5410_clock_set_rate(void *priv, struct clk *clk, u_int rate)
766 {
767 struct exynos_clk *eclk = (struct exynos_clk *)clk;
768
769 KASSERT((clk->flags & CLK_SET_RATE_PARENT) == 0);
770
771 switch (eclk->type) {
772 case EXYNOS_CLK_FIXED:
773 return EIO;
774 case EXYNOS_CLK_PLL:
775 return exynos5410_clock_set_rate_pll(priv, eclk, rate);
776 case EXYNOS_CLK_MUX:
777 return EIO;
778 case EXYNOS_CLK_DIV:
779 return exynos5410_clock_set_rate_div(priv, eclk, rate);
780 case EXYNOS_CLK_GATE:
781 return EINVAL;
782 default:
783 panic("exynos5410: unknown eclk type %d", eclk->type);
784 }
785 }
786
787 static int
exynos5410_clock_enable(void * priv,struct clk * clk)788 exynos5410_clock_enable(void *priv, struct clk *clk)
789 {
790 struct exynos_clk *eclk = (struct exynos_clk *)clk;
791
792 switch (eclk->type) {
793 case EXYNOS_CLK_FIXED:
794 return 0; /* always on */
795 case EXYNOS_CLK_PLL:
796 return 0; /* XXX */
797 case EXYNOS_CLK_MUX:
798 case EXYNOS_CLK_DIV:
799 return 0;
800 case EXYNOS_CLK_GATE:
801 return exynos5410_clock_enable_gate(priv, eclk, true);
802 default:
803 panic("exynos5410: unknown eclk type %d", eclk->type);
804 }
805 }
806
807 static int
exynos5410_clock_disable(void * priv,struct clk * clk)808 exynos5410_clock_disable(void *priv, struct clk *clk)
809 {
810 struct exynos_clk *eclk = (struct exynos_clk *)clk;
811
812 switch (eclk->type) {
813 case EXYNOS_CLK_FIXED:
814 return EINVAL; /* always on */
815 case EXYNOS_CLK_PLL:
816 return EINVAL; /* XXX */
817 case EXYNOS_CLK_MUX:
818 case EXYNOS_CLK_DIV:
819 return EINVAL;
820 case EXYNOS_CLK_GATE:
821 return exynos5410_clock_enable_gate(priv, eclk, false);
822 default:
823 panic("exynos5410: unknown eclk type %d", eclk->type);
824 }
825 }
826
827 static int
exynos5410_clock_set_parent(void * priv,struct clk * clk,struct clk * clk_parent)828 exynos5410_clock_set_parent(void *priv, struct clk *clk, struct clk *clk_parent)
829 {
830 struct exynos_clk *eclk = (struct exynos_clk *)clk;
831 struct exynos_clk *eclk_parent = (struct exynos_clk *)clk_parent;
832
833 switch (eclk->type) {
834 case EXYNOS_CLK_FIXED:
835 case EXYNOS_CLK_PLL:
836 case EXYNOS_CLK_DIV:
837 case EXYNOS_CLK_GATE:
838 return EINVAL;
839 case EXYNOS_CLK_MUX:
840 return exynos5410_clock_set_parent_mux(priv, eclk, eclk_parent);
841 default:
842 panic("exynos5410: unknown eclk type %d", eclk->type);
843 }
844 }
845
846 static struct clk *
exynos5410_clock_get_parent(void * priv,struct clk * clk)847 exynos5410_clock_get_parent(void *priv, struct clk *clk)
848 {
849 struct exynos_clk *eclk = (struct exynos_clk *)clk;
850 struct exynos_clk *eclk_parent = NULL;
851
852 switch (eclk->type) {
853 case EXYNOS_CLK_FIXED:
854 case EXYNOS_CLK_PLL:
855 case EXYNOS_CLK_DIV:
856 case EXYNOS_CLK_GATE:
857 if (eclk->parent != NULL) {
858 eclk_parent = exynos5410_clock_find(eclk->parent);
859 }
860 break;
861 case EXYNOS_CLK_MUX:
862 eclk_parent = exynos5410_clock_get_parent_mux(priv, eclk);
863 break;
864 default:
865 panic("exynos5410: unknown eclk type %d", eclk->type);
866 }
867
868 return (struct clk *)eclk_parent;
869 }
870