exynos5410_clock.c revision 1.2 1 /* $NetBSD: exynos5410_clock.c,v 1.2 2017/06/20 17:43:51 skrll 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.2 2017/06/20 17:43:51 skrll 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, 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, const void *data, size_t len)
553 {
554 struct exynos_clk *eclk;
555
556 /* #clock-cells should be 1 */
557 if (len != 4) {
558 return NULL;
559 }
560
561 const u_int clock_id = be32dec(data);
562
563 eclk = exynos5410_clock_find_by_id(clock_id);
564 if (eclk)
565 return &eclk->base;
566
567 return NULL;
568 }
569
570 static u_int
571 exynos5410_clock_get_rate_pll(struct exynos5410_clock_softc *sc,
572 struct exynos_clk *eclk)
573 {
574 struct exynos_pll_clk *epll = &eclk->u.pll;
575 struct exynos_clk *clk_parent;
576
577 KASSERT(eclk->type == EXYNOS_CLK_PLL);
578
579 clk_parent = exynos5410_clock_find(eclk->parent);
580 KASSERT(clk_parent != NULL);
581 const u_int rate_parent = exynos5410_clock_get_rate(sc,
582 &clk_parent->base);
583
584 const uint32_t v = CLOCK_READ(sc, epll->con0_reg);
585
586 return PLL_FREQ(rate_parent, v);
587 }
588
589 static int
590 exynos5410_clock_set_rate_pll(struct exynos5410_clock_softc *sc,
591 struct exynos_clk *eclk, u_int rate)
592 {
593 /* TODO */
594 return EOPNOTSUPP;
595 }
596
597 static int
598 exynos5410_clock_set_parent_mux(struct exynos5410_clock_softc *sc,
599 struct exynos_clk *eclk, struct exynos_clk *eclk_parent)
600 {
601 struct exynos_mux_clk *emux = &eclk->u.mux;
602 const char *pname = eclk_parent->base.name;
603 u_int sel;
604
605 KASSERT(eclk->type == EXYNOS_CLK_MUX);
606
607 for (sel = 0; sel < emux->nparents; sel++) {
608 if (strcmp(pname, emux->parents[sel]) == 0) {
609 break;
610 }
611 }
612 if (sel == emux->nparents) {
613 return EINVAL;
614 }
615
616 uint32_t v = CLOCK_READ(sc, emux->reg);
617 v &= ~emux->bits;
618 v |= __SHIFTIN(sel, emux->bits);
619 CLOCK_WRITE(sc, emux->reg, v);
620
621 return 0;
622 }
623
624 static struct exynos_clk *
625 exynos5410_clock_get_parent_mux(struct exynos5410_clock_softc *sc,
626 struct exynos_clk *eclk)
627 {
628 struct exynos_mux_clk *emux = &eclk->u.mux;
629
630 KASSERT(eclk->type == EXYNOS_CLK_MUX);
631
632 const uint32_t v = CLOCK_READ(sc, emux->reg);
633 const u_int sel = __SHIFTOUT(v, emux->bits);
634
635 KASSERT(sel < emux->nparents);
636
637 return exynos5410_clock_find(emux->parents[sel]);
638 }
639
640 static u_int
641 exynos5410_clock_get_rate_div(struct exynos5410_clock_softc *sc,
642 struct exynos_clk *eclk)
643 {
644 struct exynos_div_clk *ediv = &eclk->u.div;
645 struct clk *clk_parent;
646
647 KASSERT(eclk->type == EXYNOS_CLK_DIV);
648
649 clk_parent = exynos5410_clock_get_parent(sc, &eclk->base);
650 const u_int parent_rate = exynos5410_clock_get_rate(sc, clk_parent);
651
652 const uint32_t v = CLOCK_READ(sc, ediv->reg);
653 const u_int div = __SHIFTOUT(v, ediv->bits);
654
655 return parent_rate / (div + 1);
656 }
657
658 static int
659 exynos5410_clock_set_rate_div(struct exynos5410_clock_softc *sc,
660 struct exynos_clk *eclk, u_int rate)
661 {
662 struct exynos_div_clk *ediv = &eclk->u.div;
663 struct clk *clk_parent;
664 int tmp_div, new_div = -1;
665 u_int tmp_rate;
666
667 KASSERT(eclk->type == EXYNOS_CLK_DIV);
668
669 clk_parent = exynos5410_clock_get_parent(sc, &eclk->base);
670 const u_int parent_rate = exynos5410_clock_get_rate(sc, clk_parent);
671
672 for (tmp_div = 0; tmp_div < popcount32(ediv->bits); tmp_div++) {
673 tmp_rate = parent_rate / (tmp_div + 1);
674 if (tmp_rate <= rate) {
675 new_div = tmp_div;
676 break;
677 }
678 }
679 if (new_div == -1)
680 return EINVAL;
681
682 uint32_t v = CLOCK_READ(sc, ediv->reg);
683 v &= ~ediv->bits;
684 v |= __SHIFTIN(new_div, ediv->bits);
685 CLOCK_WRITE(sc, ediv->reg, v);
686
687 return 0;
688 }
689
690 static int
691 exynos5410_clock_enable_gate(struct exynos5410_clock_softc *sc,
692 struct exynos_clk *eclk, bool enable)
693 {
694 struct exynos_gate_clk *egate = &eclk->u.gate;
695
696 KASSERT(eclk->type == EXYNOS_CLK_GATE);
697
698 uint32_t v = CLOCK_READ(sc, egate->reg);
699 if (enable) {
700 v |= egate->bits;
701 } else {
702 v &= ~egate->bits;
703 }
704 CLOCK_WRITE(sc, egate->reg, v);
705
706 return 0;
707 }
708
709 /*
710 * clk api
711 */
712
713 static struct clk *
714 exynos5410_clock_get(void *priv, const char *name)
715 {
716 struct exynos_clk *eclk;
717
718 eclk = exynos5410_clock_find(name);
719 if (eclk == NULL)
720 return NULL;
721
722 atomic_inc_uint(&eclk->refcnt);
723
724 return &eclk->base;
725 }
726
727 static void
728 exynos5410_clock_put(void *priv, struct clk *clk)
729 {
730 struct exynos_clk *eclk = (struct exynos_clk *)clk;
731
732 KASSERT(eclk->refcnt > 0);
733
734 atomic_dec_uint(&eclk->refcnt);
735 }
736
737 static u_int
738 exynos5410_clock_get_rate(void *priv, struct clk *clk)
739 {
740 struct exynos_clk *eclk = (struct exynos_clk *)clk;
741 struct clk *clk_parent;
742
743 switch (eclk->type) {
744 case EXYNOS_CLK_FIXED:
745 return eclk->u.fixed.rate;
746 case EXYNOS_CLK_PLL:
747 return exynos5410_clock_get_rate_pll(priv, eclk);
748 case EXYNOS_CLK_MUX:
749 case EXYNOS_CLK_GATE:
750 clk_parent = exynos5410_clock_get_parent(priv, clk);
751 return exynos5410_clock_get_rate(priv, clk_parent);
752 case EXYNOS_CLK_DIV:
753 return exynos5410_clock_get_rate_div(priv, eclk);
754 default:
755 panic("exynos5410: unknown eclk type %d", eclk->type);
756 }
757 }
758
759 static int
760 exynos5410_clock_set_rate(void *priv, struct clk *clk, u_int rate)
761 {
762 struct exynos_clk *eclk = (struct exynos_clk *)clk;
763
764 KASSERT((clk->flags & CLK_SET_RATE_PARENT) == 0);
765
766 switch (eclk->type) {
767 case EXYNOS_CLK_FIXED:
768 return EIO;
769 case EXYNOS_CLK_PLL:
770 return exynos5410_clock_set_rate_pll(priv, eclk, rate);
771 case EXYNOS_CLK_MUX:
772 return EIO;
773 case EXYNOS_CLK_DIV:
774 return exynos5410_clock_set_rate_div(priv, eclk, rate);
775 case EXYNOS_CLK_GATE:
776 return EINVAL;
777 default:
778 panic("exynos5410: unknown eclk type %d", eclk->type);
779 }
780 }
781
782 static int
783 exynos5410_clock_enable(void *priv, struct clk *clk)
784 {
785 struct exynos_clk *eclk = (struct exynos_clk *)clk;
786
787 switch (eclk->type) {
788 case EXYNOS_CLK_FIXED:
789 return 0; /* always on */
790 case EXYNOS_CLK_PLL:
791 return 0; /* XXX */
792 case EXYNOS_CLK_MUX:
793 case EXYNOS_CLK_DIV:
794 return 0;
795 case EXYNOS_CLK_GATE:
796 return exynos5410_clock_enable_gate(priv, eclk, true);
797 default:
798 panic("exynos5410: unknown eclk type %d", eclk->type);
799 }
800 }
801
802 static int
803 exynos5410_clock_disable(void *priv, struct clk *clk)
804 {
805 struct exynos_clk *eclk = (struct exynos_clk *)clk;
806
807 switch (eclk->type) {
808 case EXYNOS_CLK_FIXED:
809 return EINVAL; /* always on */
810 case EXYNOS_CLK_PLL:
811 return EINVAL; /* XXX */
812 case EXYNOS_CLK_MUX:
813 case EXYNOS_CLK_DIV:
814 return EINVAL;
815 case EXYNOS_CLK_GATE:
816 return exynos5410_clock_enable_gate(priv, eclk, false);
817 default:
818 panic("exynos5410: unknown eclk type %d", eclk->type);
819 }
820 }
821
822 static int
823 exynos5410_clock_set_parent(void *priv, struct clk *clk, struct clk *clk_parent)
824 {
825 struct exynos_clk *eclk = (struct exynos_clk *)clk;
826 struct exynos_clk *eclk_parent = (struct exynos_clk *)clk_parent;
827
828 switch (eclk->type) {
829 case EXYNOS_CLK_FIXED:
830 case EXYNOS_CLK_PLL:
831 case EXYNOS_CLK_DIV:
832 case EXYNOS_CLK_GATE:
833 return EINVAL;
834 case EXYNOS_CLK_MUX:
835 return exynos5410_clock_set_parent_mux(priv, eclk, eclk_parent);
836 default:
837 panic("exynos5410: unknown eclk type %d", eclk->type);
838 }
839 }
840
841 static struct clk *
842 exynos5410_clock_get_parent(void *priv, struct clk *clk)
843 {
844 struct exynos_clk *eclk = (struct exynos_clk *)clk;
845 struct exynos_clk *eclk_parent = NULL;
846
847 switch (eclk->type) {
848 case EXYNOS_CLK_FIXED:
849 case EXYNOS_CLK_PLL:
850 case EXYNOS_CLK_DIV:
851 case EXYNOS_CLK_GATE:
852 if (eclk->parent != NULL) {
853 eclk_parent = exynos5410_clock_find(eclk->parent);
854 }
855 break;
856 case EXYNOS_CLK_MUX:
857 eclk_parent = exynos5410_clock_get_parent_mux(priv, eclk);
858 break;
859 default:
860 panic("exynos5410: unknown eclk type %d", eclk->type);
861 }
862
863 return (struct clk *)eclk_parent;
864 }
865