1 /* $NetBSD: zynq7000_clkc.c,v 1.5 2022/11/11 20:29:47 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 2022 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30
31 __KERNEL_RCSID(0, "$NetBSD: zynq7000_clkc.c,v 1.5 2022/11/11 20:29:47 jmcneill Exp $");
32
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/device.h>
36 #include <sys/intr.h>
37 #include <sys/systm.h>
38 #include <sys/time.h>
39 #include <sys/kmem.h>
40
41 #include <dev/clk/clk_backend.h>
42
43 #include <dev/fdt/fdtvar.h>
44 #include <dev/fdt/syscon.h>
45
46 #define ARM_PLL_CTRL 0x100
47 #define DDR_PLL_CTRL 0x104
48 #define IO_PLL_CTRL 0x108
49 #define PLL_FDIV __BITS(18,12)
50 #define ARM_CLK_CTRL 0x120
51 #define ARM_CLK_CTRL_CPU_1XCLKACT __BIT(27)
52 #define ARM_CLK_CTRL_CPU_2XCLKACT __BIT(26)
53 #define ARM_CLK_CTRL_CPU_3OR2XCLKACT __BIT(25)
54 #define ARM_CLK_CTRL_CPU_6OR4XCLKACT __BIT(24)
55 #define ARM_CLK_CTRL_DIVISOR __BITS(13,8)
56 #define APER_CLK_CTRL 0x12c
57 #define UART1_CPU_1XCLKACT __BIT(21)
58 #define UART0_CPU_1XCLKACT __BIT(20)
59 #define I2C1_CPU_1XCLKACT __BIT(19)
60 #define I2C0_CPU_1XCLKACT __BIT(18)
61 #define SDI1_CPU_1XCLKACT __BIT(11)
62 #define SDI0_CPU_1XCLKACT __BIT(10)
63 #define SDIO_CLK_CTRL 0x150
64 #define UART_CLK_CTRL 0x154
65 #define PCAP_CLK_CTRL 0x168
66 #define CLK_CTRL_DIVISOR __BITS(13,8)
67 #define CLK_CTRL_SRCSEL __BITS(5,4)
68 #define CLK_CTRL_CLKACT1 __BIT(1)
69 #define CLK_CTRL_CLKACT0 __BIT(0)
70 #define CLK_621_TRUE 0x1C4
71 #define CLK_621_TRUE_EN __BIT(0)
72
73 enum xynq7000_clkid {
74 clkid_armpll,
75 clkid_ddrpll,
76 clkid_iopll,
77 clkid_cpu_6or4x,
78 clkid_cpu_3or2x,
79 clkid_cpu_2x,
80 clkid_cpu_1x,
81 clkid_ddr2x,
82 clkid_ddr3x,
83 clkid_dci,
84 clkid_lqspi,
85 clkid_smc,
86 clkid_pcap,
87 clkid_gem0,
88 clkid_gem1,
89 clkid_fclk0,
90 clkid_fclk1,
91 clkid_fclk2,
92 clkid_fclk3,
93 clkid_can0,
94 clkid_can1,
95 clkid_sdio0,
96 clkid_sdio1,
97 clkid_uart0,
98 clkid_uart1,
99 clkid_spi0,
100 clkid_spi1,
101 clkid_dma,
102 clkid_usb0_aper,
103 clkid_usb1_aper,
104 clkid_gem0_aper,
105 clkid_gem1_aper,
106 clkid_sdio0_aper,
107 clkid_sdio1_aper,
108 clkid_spi0_aper,
109 clkid_spi1_aper,
110 clkid_can0_aper,
111 clkid_can1_aper,
112 clkid_i2c0_aper,
113 clkid_i2c1_aper,
114 clkid_uart0_aper,
115 clkid_uart1_aper,
116 clkid_gpio_aper,
117 clkid_lqspi_aper,
118 clkid_smc_aper,
119 clkid_swdt,
120 clkid_dbg_trc,
121 clkid_dbg_apb,
122 num_clkid
123 };
124 CTASSERT(clkid_dbg_apb == 47);
125
126 static int zynq7000_clkc_match(device_t, cfdata_t, void *);
127 static void zynq7000_clkc_attach(device_t, device_t, void *);
128
129 static u_int zynq7000_clkc_clk_get_rate(void *, struct clk *);
130
131 static const struct device_compatible_entry compat_data[] = {
132 { .compat = "xlnx,ps7-clkc" },
133 DEVICE_COMPAT_EOL
134 };
135
136 struct zynq7000_clkc_softc {
137 device_t sc_dev;
138 struct clk_domain sc_clkdom;
139 struct clk sc_clk[num_clkid];
140
141 u_int sc_ps_clk_frequency;
142 struct syscon *sc_syscon;
143 };
144
145 CFATTACH_DECL_NEW(zynq7000_clkc, sizeof(struct zynq7000_clkc_softc),
146 zynq7000_clkc_match, zynq7000_clkc_attach, NULL, NULL);
147
148 static struct clk *
zynq7000_clkc_clk_get(void * priv,const char * name)149 zynq7000_clkc_clk_get(void *priv, const char *name)
150 {
151 struct zynq7000_clkc_softc * const sc = priv;
152 u_int clkid;
153
154 for (clkid = 0; clkid < num_clkid; clkid++) {
155 if (strcmp(name, sc->sc_clk[clkid].name) == 0) {
156 return &sc->sc_clk[clkid];
157 }
158 }
159
160 return NULL;
161 }
162
163 static void
zynq7000_clkc_clk_put(void * priv,struct clk * clk)164 zynq7000_clkc_clk_put(void *priv, struct clk *clk)
165 {
166 }
167
168 static u_int
zynq7000_clkc_get_rate_pll(struct zynq7000_clkc_softc * sc,bus_addr_t reg)169 zynq7000_clkc_get_rate_pll(struct zynq7000_clkc_softc *sc,
170 bus_addr_t reg)
171 {
172 uint32_t val;
173
174 syscon_lock(sc->sc_syscon);
175 val = syscon_read_4(sc->sc_syscon, reg);
176 syscon_unlock(sc->sc_syscon);
177
178 return sc->sc_ps_clk_frequency * __SHIFTOUT(val, PLL_FDIV);
179 }
180
181 static u_int
zynq7000_clkc_get_rate_iop(struct zynq7000_clkc_softc * sc,bus_addr_t reg)182 zynq7000_clkc_get_rate_iop(struct zynq7000_clkc_softc *sc,
183 bus_addr_t reg)
184 {
185 uint32_t val;
186 u_int prate, sel;
187
188 syscon_lock(sc->sc_syscon);
189 val = syscon_read_4(sc->sc_syscon, reg);
190 syscon_unlock(sc->sc_syscon);
191
192 sel = __SHIFTOUT(val, CLK_CTRL_SRCSEL);
193 if (sel == 2) {
194 prate = zynq7000_clkc_clk_get_rate(sc,
195 &sc->sc_clk[clkid_armpll]);
196 } else if (sel == 3) {
197 prate = zynq7000_clkc_clk_get_rate(sc,
198 &sc->sc_clk[clkid_ddrpll]);
199 } else {
200 prate = zynq7000_clkc_clk_get_rate(sc,
201 &sc->sc_clk[clkid_iopll]);
202 }
203
204 return prate / __SHIFTOUT(val, CLK_CTRL_DIVISOR);
205 }
206
207 static u_int
zynq7000_clkc_clk_get_rate(void * priv,struct clk * clk)208 zynq7000_clkc_clk_get_rate(void *priv, struct clk *clk)
209 {
210 struct zynq7000_clkc_softc * const sc = priv;
211 uint32_t val;
212 u_int prate;
213
214 if (clk == &sc->sc_clk[clkid_armpll]) {
215 return zynq7000_clkc_get_rate_pll(sc, ARM_PLL_CTRL);
216 } else if (clk == &sc->sc_clk[clkid_iopll]) {
217 return zynq7000_clkc_get_rate_pll(sc, IO_PLL_CTRL);
218 } else if (clk == &sc->sc_clk[clkid_cpu_6or4x]) {
219 prate = zynq7000_clkc_clk_get_rate(sc,
220 &sc->sc_clk[clkid_cpu_1x]);
221 syscon_lock(sc->sc_syscon);
222 val = syscon_read_4(sc->sc_syscon, CLK_621_TRUE);
223 syscon_unlock(sc->sc_syscon);
224 return (val & CLK_621_TRUE_EN) != 0 ?
225 prate * 6 : prate * 4;
226 } else if (clk == &sc->sc_clk[clkid_cpu_3or2x]) {
227 prate = zynq7000_clkc_clk_get_rate(sc,
228 &sc->sc_clk[clkid_cpu_1x]);
229 syscon_lock(sc->sc_syscon);
230 val = syscon_read_4(sc->sc_syscon, CLK_621_TRUE);
231 syscon_unlock(sc->sc_syscon);
232 return (val & CLK_621_TRUE_EN) != 0 ?
233 prate * 3 : prate * 2;
234 } else if (clk == &sc->sc_clk[clkid_cpu_2x]) {
235 prate = zynq7000_clkc_clk_get_rate(sc,
236 &sc->sc_clk[clkid_cpu_1x]);
237 return prate * 2;
238 } else if (clk == &sc->sc_clk[clkid_cpu_1x]) {
239 prate = zynq7000_clkc_clk_get_rate(sc,
240 &sc->sc_clk[clkid_armpll]);
241 syscon_lock(sc->sc_syscon);
242 val = syscon_read_4(sc->sc_syscon, ARM_CLK_CTRL);
243 syscon_unlock(sc->sc_syscon);
244 return prate / __SHIFTOUT(val, ARM_CLK_CTRL_DIVISOR) / 6;
245 } else if (clk == &sc->sc_clk[clkid_sdio0] ||
246 clk == &sc->sc_clk[clkid_sdio1]) {
247 return zynq7000_clkc_get_rate_iop(sc, SDIO_CLK_CTRL);
248 } else if (clk == &sc->sc_clk[clkid_uart0] ||
249 clk == &sc->sc_clk[clkid_uart1]) {
250 return zynq7000_clkc_get_rate_iop(sc, UART_CLK_CTRL);
251 } else if (clk == &sc->sc_clk[clkid_pcap]) {
252 return zynq7000_clkc_get_rate_iop(sc, PCAP_CLK_CTRL);
253 } else if (clk == &sc->sc_clk[clkid_uart0_aper] ||
254 clk == &sc->sc_clk[clkid_uart1_aper] ||
255 clk == &sc->sc_clk[clkid_i2c0_aper] ||
256 clk == &sc->sc_clk[clkid_i2c1_aper]) {
257 return zynq7000_clkc_clk_get_rate(sc,
258 &sc->sc_clk[clkid_cpu_1x]);
259 } else {
260 /* Not implemented. */
261 return 0;
262 }
263 }
264
265 static int
zynq7000_clkc_clk_enable(void * priv,struct clk * clk)266 zynq7000_clkc_clk_enable(void *priv, struct clk *clk)
267 {
268 struct zynq7000_clkc_softc * const sc = priv;
269 uint32_t val, mask;
270 bus_addr_t reg;
271
272 if (clk == &sc->sc_clk[clkid_cpu_1x]) {
273 reg = ARM_CLK_CTRL;
274 mask = ARM_CLK_CTRL_CPU_1XCLKACT;
275 } else if (clk == &sc->sc_clk[clkid_cpu_2x]) {
276 reg = ARM_CLK_CTRL;
277 mask = ARM_CLK_CTRL_CPU_2XCLKACT;
278 } else if (clk == &sc->sc_clk[clkid_cpu_3or2x]) {
279 reg = ARM_CLK_CTRL;
280 mask = ARM_CLK_CTRL_CPU_3OR2XCLKACT;
281 } else if (clk == &sc->sc_clk[clkid_cpu_6or4x]) {
282 reg = ARM_CLK_CTRL;
283 mask = ARM_CLK_CTRL_CPU_6OR4XCLKACT;
284 } else if (clk == &sc->sc_clk[clkid_sdio0]) {
285 reg = SDIO_CLK_CTRL;
286 mask = CLK_CTRL_CLKACT0;
287 } else if (clk == &sc->sc_clk[clkid_sdio1]) {
288 reg = SDIO_CLK_CTRL;
289 mask = CLK_CTRL_CLKACT1;
290 } else if (clk == &sc->sc_clk[clkid_uart0]) {
291 reg = UART_CLK_CTRL;
292 mask = CLK_CTRL_CLKACT0;
293 } else if (clk == &sc->sc_clk[clkid_uart1]) {
294 reg = UART_CLK_CTRL;
295 mask = CLK_CTRL_CLKACT1;
296 } else if (clk == &sc->sc_clk[clkid_pcap]) {
297 reg = PCAP_CLK_CTRL;
298 mask = CLK_CTRL_CLKACT0;
299 } else if (clk == &sc->sc_clk[clkid_sdio0_aper]) {
300 reg = APER_CLK_CTRL;
301 mask = SDI0_CPU_1XCLKACT;
302 } else if (clk == &sc->sc_clk[clkid_sdio1_aper]) {
303 reg = APER_CLK_CTRL;
304 mask = SDI1_CPU_1XCLKACT;
305 } else if (clk == &sc->sc_clk[clkid_uart0_aper]) {
306 reg = APER_CLK_CTRL;
307 mask = UART0_CPU_1XCLKACT;
308 } else if (clk == &sc->sc_clk[clkid_uart1_aper]) {
309 reg = APER_CLK_CTRL;
310 mask = UART1_CPU_1XCLKACT;
311 } else if (clk == &sc->sc_clk[clkid_i2c0_aper]) {
312 reg = APER_CLK_CTRL;
313 mask = I2C0_CPU_1XCLKACT;
314 } else if (clk == &sc->sc_clk[clkid_i2c1_aper]) {
315 reg = APER_CLK_CTRL;
316 mask = I2C1_CPU_1XCLKACT;
317 } else {
318 return ENXIO;
319 }
320
321 syscon_lock(sc->sc_syscon);
322 val = syscon_read_4(sc->sc_syscon, reg);
323 syscon_write_4(sc->sc_syscon, reg, val | mask);
324 syscon_unlock(sc->sc_syscon);
325
326 return 0;
327 }
328
329 static int
zynq7000_clkc_clk_disable(void * priv,struct clk * clk)330 zynq7000_clkc_clk_disable(void *priv, struct clk *clk)
331 {
332 return ENXIO;
333 }
334
335 static const struct clk_funcs zynq7000_clkc_clk_funcs = {
336 .get = zynq7000_clkc_clk_get,
337 .put = zynq7000_clkc_clk_put,
338 .get_rate = zynq7000_clkc_clk_get_rate,
339 .enable = zynq7000_clkc_clk_enable,
340 .disable = zynq7000_clkc_clk_disable,
341 };
342
343 static struct clk *
zynq7000_clkc_fdt_decode(device_t dev,int cc_phandle,const void * data,size_t len)344 zynq7000_clkc_fdt_decode(device_t dev, int cc_phandle, const void *data, size_t len)
345 {
346 struct zynq7000_clkc_softc * const sc = device_private(dev);
347 u_int clkid;
348
349 if (len != 4) {
350 return NULL;
351 }
352
353 clkid = be32dec(data);
354 if (clkid >= num_clkid) {
355 return NULL;
356 }
357
358 return &sc->sc_clk[clkid];
359 }
360
361 static const struct fdtbus_clock_controller_func zynq7000_clkc_fdt_funcs = {
362 .decode = zynq7000_clkc_fdt_decode
363 };
364
365 static int
zynq7000_clkc_match(device_t parent,cfdata_t cf,void * aux)366 zynq7000_clkc_match(device_t parent, cfdata_t cf, void *aux)
367 {
368 struct fdt_attach_args * const faa = aux;
369
370 return of_compatible_match(faa->faa_phandle, compat_data);
371 }
372
373 static void
zynq7000_clkc_attach(device_t parent,device_t self,void * aux)374 zynq7000_clkc_attach(device_t parent, device_t self, void *aux)
375 {
376 struct zynq7000_clkc_softc * const sc = device_private(self);
377 struct fdt_attach_args * const faa = aux;
378 const int phandle = faa->faa_phandle;
379 const char *clkname;
380 bus_addr_t addr;
381 bus_size_t size;
382 u_int clkid;
383 int error;
384
385 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
386 aprint_error(": couldn't get registers\n");
387 return;
388 }
389
390 sc->sc_dev = self;
391 sc->sc_syscon = fdtbus_syscon_lookup(OF_parent(phandle));
392 if (sc->sc_syscon == NULL) {
393 aprint_error(": couldn't get syscon registers\n");
394 return;
395 }
396
397 error = of_getprop_uint32(phandle, "ps-clk-frequency",
398 &sc->sc_ps_clk_frequency);
399 if (error != 0) {
400 aprint_error(": couldn't get ps-clk-frequency\n");
401 return;
402 }
403
404 sc->sc_clkdom.name = device_xname(self);
405 sc->sc_clkdom.funcs = &zynq7000_clkc_clk_funcs;
406 sc->sc_clkdom.priv = sc;
407 for (clkid = 0; clkid < num_clkid; clkid++) {
408 clkname = fdtbus_get_string_index(phandle,
409 "clock-output-names", clkid);
410 sc->sc_clk[clkid].domain = &sc->sc_clkdom;
411 if (clkname != NULL) {
412 sc->sc_clk[clkid].name = kmem_asprintf("%s", clkname);
413 }
414 clk_attach(&sc->sc_clk[clkid]);
415 }
416
417 aprint_naive("\n");
418 aprint_normal(": Zynq-7000 PS clock subsystem (PS_CLK %u Hz)\n",
419 sc->sc_ps_clk_frequency);
420
421 for (clkid = 0; clkid < num_clkid; clkid++) {
422 aprint_debug_dev(self, "clkid %u [%s]: %u Hz\n", clkid,
423 sc->sc_clk[clkid].name ? sc->sc_clk[clkid].name : "<none>",
424 clk_get_rate(&sc->sc_clk[clkid]));
425 }
426
427 fdtbus_register_clock_controller(self, phandle, &zynq7000_clkc_fdt_funcs);
428 }
429