exynos5410_clock.c revision 1.4 1 /* $NetBSD: exynos5410_clock.c,v 1.4 2018/09/09 07:21:18 aymeric Exp $ */
2
3 /*-
4 * Copyright (c) 2015-2017 Jared McNeill <jmcneill (at) 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.4 2018/09/09 07:21:18 aymeric 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 int
427 exynos5410_clock_match(device_t parent, cfdata_t cf, void *aux)
428 {
429 const char * const compatible[] = { "samsung,exynos5410-clock", NULL };
430 struct fdt_attach_args * const faa = aux;
431
432 return of_match_compatible(faa->faa_phandle, compatible);
433 }
434
435 static void
436 exynos5410_clock_attach(device_t parent, device_t self, void *aux)
437 {
438 struct exynos5410_clock_softc * const sc = device_private(self);
439 struct fdt_attach_args * const faa = aux;
440 bus_addr_t addr;
441 bus_size_t size;
442 int error;
443
444 if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) {
445 aprint_error(": couldn't get registers\n");
446 return;
447 }
448
449 sc->sc_dev = self;
450 sc->sc_bst = faa->faa_bst;
451
452 error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
453 if (error) {
454 aprint_error(": couldn't map %#llx: %d",
455 (uint64_t)addr, error);
456 return;
457 }
458
459 aprint_naive("\n");
460 aprint_normal(": Exynos5410 Clock Controller\n");
461
462 sc->sc_clkdom.funcs = &exynos5410_clock_funcs;
463 sc->sc_clkdom.priv = sc;
464 for (u_int n = 0; n < __arraycount(exynos5410_clocks); n++) {
465 exynos5410_clocks[n].base.domain = &sc->sc_clkdom;
466 }
467
468 fdtbus_register_clock_controller(self, faa->faa_phandle,
469 &exynos5410_car_fdtclock_funcs);
470
471 exynos5410_clock_print_header();
472 for (u_int n = 0; n < __arraycount(exynos5410_clocks); n++) {
473 exynos5410_clock_print(sc, &exynos5410_clocks[n]);
474 }
475 }
476
477 static struct exynos_clk *
478 exynos5410_clock_find(const char *name)
479 {
480 u_int n;
481
482 for (n = 0; n < __arraycount(exynos5410_clocks); n++) {
483 if (strcmp(exynos5410_clocks[n].base.name, name) == 0) {
484 return &exynos5410_clocks[n];
485 }
486 }
487
488 return NULL;
489 }
490
491 static struct exynos_clk *
492 exynos5410_clock_find_by_id(u_int clock_id)
493 {
494 u_int n;
495
496 for (n = 0; n < __arraycount(exynos5410_clock_ids); n++) {
497 if (exynos5410_clock_ids[n].id == clock_id) {
498 const char *name = exynos5410_clock_ids[n].name;
499 return exynos5410_clock_find(name);
500 }
501 }
502
503 return NULL;
504 }
505
506 static void
507 exynos5410_clock_print_header(void)
508 {
509 printf(" %-10s %2s %-10s %-5s %10s\n",
510 "clock", "", "parent", "type", "rate");
511 printf(" %-10s %2s %-10s %-5s %10s\n",
512 "=====", "", "======", "====", "====");
513 }
514
515 static void
516 exynos5410_clock_print(struct exynos5410_clock_softc *sc,
517 struct exynos_clk *eclk)
518 {
519 struct exynos_clk *eclk_parent;
520 struct clk *clk_parent;
521 const char *type = "?";
522
523 switch (eclk->type) {
524 case EXYNOS_CLK_FIXED:
525 type = "fixed";
526 break;
527 case EXYNOS_CLK_PLL:
528 type = "pll";
529 break;
530 case EXYNOS_CLK_MUX:
531 type = "mux";
532 break;
533 case EXYNOS_CLK_DIV:
534 type = "div";
535 break;
536 case EXYNOS_CLK_GATE:
537 type = "gate";
538 break;
539 }
540
541 clk_parent = exynos5410_clock_get_parent(sc, &eclk->base);
542 eclk_parent = (struct exynos_clk *)clk_parent;
543
544 printf(" %-10s %2s %-10s %-5s %10d Hz\n",
545 eclk->base.name,
546 eclk_parent ? "<-" : "",
547 eclk_parent ? eclk_parent->base.name : "",
548 type, clk_get_rate(&eclk->base));
549 }
550
551 static struct clk *
552 exynos5410_clock_decode(device_t dev, int cc_phandle, const void *data,
553 size_t len)
554 {
555 struct exynos_clk *eclk;
556
557 /* #clock-cells should be 1 */
558 if (len != 4) {
559 return NULL;
560 }
561
562 const u_int clock_id = be32dec(data);
563
564 eclk = exynos5410_clock_find_by_id(clock_id);
565 if (eclk)
566 return &eclk->base;
567
568 return NULL;
569 }
570
571 static u_int
572 exynos5410_clock_get_rate_pll(struct exynos5410_clock_softc *sc,
573 struct exynos_clk *eclk)
574 {
575 struct exynos_pll_clk *epll = &eclk->u.pll;
576 struct exynos_clk *clk_parent;
577
578 KASSERT(eclk->type == EXYNOS_CLK_PLL);
579
580 clk_parent = exynos5410_clock_find(eclk->parent);
581 KASSERT(clk_parent != NULL);
582 const u_int rate_parent = exynos5410_clock_get_rate(sc,
583 &clk_parent->base);
584
585 const uint32_t v = CLOCK_READ(sc, epll->con0_reg);
586
587 return PLL_FREQ(rate_parent, v);
588 }
589
590 static int
591 exynos5410_clock_set_rate_pll(struct exynos5410_clock_softc *sc,
592 struct exynos_clk *eclk, u_int rate)
593 {
594 /* TODO */
595 return EOPNOTSUPP;
596 }
597
598 static int
599 exynos5410_clock_set_parent_mux(struct exynos5410_clock_softc *sc,
600 struct exynos_clk *eclk, struct exynos_clk *eclk_parent)
601 {
602 struct exynos_mux_clk *emux = &eclk->u.mux;
603 const char *pname = eclk_parent->base.name;
604 u_int sel;
605
606 KASSERT(eclk->type == EXYNOS_CLK_MUX);
607
608 for (sel = 0; sel < emux->nparents; sel++) {
609 if (strcmp(pname, emux->parents[sel]) == 0) {
610 break;
611 }
612 }
613 if (sel == emux->nparents) {
614 return EINVAL;
615 }
616
617 uint32_t v = CLOCK_READ(sc, emux->reg);
618 v &= ~emux->bits;
619 v |= __SHIFTIN(sel, emux->bits);
620 CLOCK_WRITE(sc, emux->reg, v);
621
622 return 0;
623 }
624
625 static struct exynos_clk *
626 exynos5410_clock_get_parent_mux(struct exynos5410_clock_softc *sc,
627 struct exynos_clk *eclk)
628 {
629 struct exynos_mux_clk *emux = &eclk->u.mux;
630
631 KASSERT(eclk->type == EXYNOS_CLK_MUX);
632
633 const uint32_t v = CLOCK_READ(sc, emux->reg);
634 const u_int sel = __SHIFTOUT(v, emux->bits);
635
636 KASSERT(sel < emux->nparents);
637
638 return exynos5410_clock_find(emux->parents[sel]);
639 }
640
641 static u_int
642 exynos5410_clock_get_rate_div(struct exynos5410_clock_softc *sc,
643 struct exynos_clk *eclk)
644 {
645 struct exynos_div_clk *ediv = &eclk->u.div;
646 struct clk *clk_parent;
647
648 KASSERT(eclk->type == EXYNOS_CLK_DIV);
649
650 clk_parent = exynos5410_clock_get_parent(sc, &eclk->base);
651 const u_int parent_rate = exynos5410_clock_get_rate(sc, clk_parent);
652
653 const uint32_t v = CLOCK_READ(sc, ediv->reg);
654 const u_int div = __SHIFTOUT(v, ediv->bits);
655
656 return parent_rate / (div + 1);
657 }
658
659 static int
660 exynos5410_clock_set_rate_div(struct exynos5410_clock_softc *sc,
661 struct exynos_clk *eclk, u_int rate)
662 {
663 struct exynos_div_clk *ediv = &eclk->u.div;
664 struct clk *clk_parent;
665 int tmp_div, new_div = -1;
666 u_int tmp_rate;
667
668 KASSERT(eclk->type == EXYNOS_CLK_DIV);
669
670 clk_parent = exynos5410_clock_get_parent(sc, &eclk->base);
671 const u_int parent_rate = exynos5410_clock_get_rate(sc, clk_parent);
672
673 for (tmp_div = 0; tmp_div < __SHIFTOUT_MASK(ediv->bits); tmp_div++) {
674 tmp_rate = parent_rate / (tmp_div + 1);
675 if (tmp_rate <= rate) {
676 new_div = tmp_div;
677 break;
678 }
679 }
680 if (new_div == -1)
681 return EINVAL;
682
683 uint32_t v = CLOCK_READ(sc, ediv->reg);
684 v &= ~ediv->bits;
685 v |= __SHIFTIN(new_div, ediv->bits);
686 CLOCK_WRITE(sc, ediv->reg, v);
687
688 return 0;
689 }
690
691 static int
692 exynos5410_clock_enable_gate(struct exynos5410_clock_softc *sc,
693 struct exynos_clk *eclk, bool enable)
694 {
695 struct exynos_gate_clk *egate = &eclk->u.gate;
696
697 KASSERT(eclk->type == EXYNOS_CLK_GATE);
698
699 uint32_t v = CLOCK_READ(sc, egate->reg);
700 if (enable) {
701 v |= egate->bits;
702 } else {
703 v &= ~egate->bits;
704 }
705 CLOCK_WRITE(sc, egate->reg, v);
706
707 return 0;
708 }
709
710 /*
711 * clk api
712 */
713
714 static struct clk *
715 exynos5410_clock_get(void *priv, const char *name)
716 {
717 struct exynos_clk *eclk;
718
719 eclk = exynos5410_clock_find(name);
720 if (eclk == NULL)
721 return NULL;
722
723 atomic_inc_uint(&eclk->refcnt);
724
725 return &eclk->base;
726 }
727
728 static void
729 exynos5410_clock_put(void *priv, struct clk *clk)
730 {
731 struct exynos_clk *eclk = (struct exynos_clk *)clk;
732
733 KASSERT(eclk->refcnt > 0);
734
735 atomic_dec_uint(&eclk->refcnt);
736 }
737
738 static u_int
739 exynos5410_clock_get_rate(void *priv, struct clk *clk)
740 {
741 struct exynos_clk *eclk = (struct exynos_clk *)clk;
742 struct clk *clk_parent;
743
744 switch (eclk->type) {
745 case EXYNOS_CLK_FIXED:
746 return eclk->u.fixed.rate;
747 case EXYNOS_CLK_PLL:
748 return exynos5410_clock_get_rate_pll(priv, eclk);
749 case EXYNOS_CLK_MUX:
750 case EXYNOS_CLK_GATE:
751 clk_parent = exynos5410_clock_get_parent(priv, clk);
752 return exynos5410_clock_get_rate(priv, clk_parent);
753 case EXYNOS_CLK_DIV:
754 return exynos5410_clock_get_rate_div(priv, eclk);
755 default:
756 panic("exynos5410: unknown eclk type %d", eclk->type);
757 }
758 }
759
760 static int
761 exynos5410_clock_set_rate(void *priv, struct clk *clk, u_int rate)
762 {
763 struct exynos_clk *eclk = (struct exynos_clk *)clk;
764
765 KASSERT((clk->flags & CLK_SET_RATE_PARENT) == 0);
766
767 switch (eclk->type) {
768 case EXYNOS_CLK_FIXED:
769 return EIO;
770 case EXYNOS_CLK_PLL:
771 return exynos5410_clock_set_rate_pll(priv, eclk, rate);
772 case EXYNOS_CLK_MUX:
773 return EIO;
774 case EXYNOS_CLK_DIV:
775 return exynos5410_clock_set_rate_div(priv, eclk, rate);
776 case EXYNOS_CLK_GATE:
777 return EINVAL;
778 default:
779 panic("exynos5410: unknown eclk type %d", eclk->type);
780 }
781 }
782
783 static int
784 exynos5410_clock_enable(void *priv, struct clk *clk)
785 {
786 struct exynos_clk *eclk = (struct exynos_clk *)clk;
787
788 switch (eclk->type) {
789 case EXYNOS_CLK_FIXED:
790 return 0; /* always on */
791 case EXYNOS_CLK_PLL:
792 return 0; /* XXX */
793 case EXYNOS_CLK_MUX:
794 case EXYNOS_CLK_DIV:
795 return 0;
796 case EXYNOS_CLK_GATE:
797 return exynos5410_clock_enable_gate(priv, eclk, true);
798 default:
799 panic("exynos5410: unknown eclk type %d", eclk->type);
800 }
801 }
802
803 static int
804 exynos5410_clock_disable(void *priv, struct clk *clk)
805 {
806 struct exynos_clk *eclk = (struct exynos_clk *)clk;
807
808 switch (eclk->type) {
809 case EXYNOS_CLK_FIXED:
810 return EINVAL; /* always on */
811 case EXYNOS_CLK_PLL:
812 return EINVAL; /* XXX */
813 case EXYNOS_CLK_MUX:
814 case EXYNOS_CLK_DIV:
815 return EINVAL;
816 case EXYNOS_CLK_GATE:
817 return exynos5410_clock_enable_gate(priv, eclk, false);
818 default:
819 panic("exynos5410: unknown eclk type %d", eclk->type);
820 }
821 }
822
823 static int
824 exynos5410_clock_set_parent(void *priv, struct clk *clk, struct clk *clk_parent)
825 {
826 struct exynos_clk *eclk = (struct exynos_clk *)clk;
827 struct exynos_clk *eclk_parent = (struct exynos_clk *)clk_parent;
828
829 switch (eclk->type) {
830 case EXYNOS_CLK_FIXED:
831 case EXYNOS_CLK_PLL:
832 case EXYNOS_CLK_DIV:
833 case EXYNOS_CLK_GATE:
834 return EINVAL;
835 case EXYNOS_CLK_MUX:
836 return exynos5410_clock_set_parent_mux(priv, eclk, eclk_parent);
837 default:
838 panic("exynos5410: unknown eclk type %d", eclk->type);
839 }
840 }
841
842 static struct clk *
843 exynos5410_clock_get_parent(void *priv, struct clk *clk)
844 {
845 struct exynos_clk *eclk = (struct exynos_clk *)clk;
846 struct exynos_clk *eclk_parent = NULL;
847
848 switch (eclk->type) {
849 case EXYNOS_CLK_FIXED:
850 case EXYNOS_CLK_PLL:
851 case EXYNOS_CLK_DIV:
852 case EXYNOS_CLK_GATE:
853 if (eclk->parent != NULL) {
854 eclk_parent = exynos5410_clock_find(eclk->parent);
855 }
856 break;
857 case EXYNOS_CLK_MUX:
858 eclk_parent = exynos5410_clock_get_parent_mux(priv, eclk);
859 break;
860 default:
861 panic("exynos5410: unknown eclk type %d", eclk->type);
862 }
863
864 return (struct clk *)eclk_parent;
865 }
866