1 /*-
2 * Copyright 2015 Alexander Kabaev <kan@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 /*
28 * Ingenic JZ4780 CGU driver.
29 *
30 */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/lock.h>
42 #include <sys/mutex.h>
43 #include <sys/resource.h>
44 #include <sys/rman.h>
45
46 #include <machine/bus.h>
47
48 #include <dev/fdt/fdt_common.h>
49 #include <dev/ofw/ofw_bus.h>
50 #include <dev/ofw/ofw_bus_subr.h>
51
52 #include <mips/ingenic/jz4780_clk.h>
53 #include <mips/ingenic/jz4780_regs.h>
54 #include <mips/ingenic/jz4780_clock.h>
55
56 #include "clkdev_if.h"
57
58 #include <gnu/dts/include/dt-bindings/clock/jz4780-cgu.h>
59
60 /**********************************************************************
61 * JZ4780 CGU clock domain
62 **********************************************************************/
63 struct jz4780_clock_softc {
64 device_t dev;
65 struct resource *res[1];
66 struct mtx mtx;
67 struct clkdom *clkdom;
68 };
69
70 static struct resource_spec jz4780_clock_spec[] = {
71 { SYS_RES_MEMORY, 0, RF_ACTIVE },
72 { -1, 0 }
73 };
74
75 struct jz4780_clk_pll_def {
76 uint16_t clk_id;
77 uint16_t clk_reg;
78 const char *clk_name;
79 const char *clk_pname[1];
80 };
81
82 #define PLL(_id, cname, pname, reg) { \
83 .clk_id = _id, \
84 .clk_reg = reg, \
85 .clk_name = cname, \
86 .clk_pname[0] = pname, \
87 }
88
89 struct jz4780_clk_gate_def {
90 uint16_t clk_id;
91 uint16_t clk_bit;
92 const char *clk_name;
93 const char *clk_pname[1];
94 };
95
96 #define GATE(_id, cname, pname, bit) { \
97 .clk_id = _id, \
98 .clk_bit = bit, \
99 .clk_name = cname, \
100 .clk_pname[0] = pname, \
101 }
102
103 #define MUX(reg, shift, bits, map) \
104 .clk_mux.mux_reg = (reg), \
105 .clk_mux.mux_shift = (shift), \
106 .clk_mux.mux_bits = (bits), \
107 .clk_mux.mux_map = (map),
108 #define NO_MUX
109
110 #define DIV(reg, shift, lg, bits, ce, st, bb) \
111 .clk_div.div_reg = (reg), \
112 .clk_div.div_shift = (shift), \
113 .clk_div.div_bits = (bits), \
114 .clk_div.div_lg = (lg), \
115 .clk_div.div_ce_bit = (ce), \
116 .clk_div.div_st_bit = (st), \
117 .clk_div.div_busy_bit = (bb),
118 #define NO_DIV \
119
120 #define GATEBIT(bit) \
121 .clk_gate_bit = (bit),
122 #define NO_GATE \
123 .clk_gate_bit = (-1),
124
125 #define PLIST(pnames...) \
126 .clk_pnames = { pnames },
127
128 #define GENCLK(id, name, type, parents, mux, div, gt) { \
129 .clk_id = id, \
130 .clk_type = type, \
131 .clk_name = name, \
132 parents \
133 mux \
134 div \
135 gt \
136 }
137
138 /* PLL definitions */
139 static struct jz4780_clk_pll_def pll_clks[] = {
140 PLL(JZ4780_CLK_APLL, "apll", "ext", JZ_CPAPCR),
141 PLL(JZ4780_CLK_MPLL, "mpll", "ext", JZ_CPMPCR),
142 PLL(JZ4780_CLK_EPLL, "epll", "ext", JZ_CPEPCR),
143 PLL(JZ4780_CLK_VPLL, "vpll", "ext", JZ_CPVPCR),
144 };
145
146 /* OTG PHY clock (reuse gate def structure */
147 static struct jz4780_clk_gate_def otg_clks[] = {
148 GATE(JZ4780_CLK_OTGPHY, "otg_phy", "ext", 0),
149 };
150
151 static const struct jz4780_clk_descr gen_clks[] = {
152 GENCLK(JZ4780_CLK_SCLKA, "sclk_a", CLK_MASK_MUX,
153 PLIST("apll", "ext", "rtc"),
154 MUX(JZ_CPCCR, 30, 2, 0x7),
155 NO_DIV,
156 NO_GATE
157 ),
158
159 GENCLK(JZ4780_CLK_CPUMUX, "cpumux", CLK_MASK_MUX,
160 PLIST("sclk_a", "mpll", "epll"),
161 MUX(JZ_CPCCR, 28, 2, 0x7),
162 NO_DIV,
163 NO_GATE
164 ),
165
166 GENCLK(JZ4780_CLK_CPU, "cpu", CLK_MASK_DIV,
167 PLIST("cpumux"),
168 NO_MUX,
169 DIV(JZ_CPCCR, 0, 0, 4, 22, -1, -1),
170 NO_GATE
171 ),
172
173 GENCLK(JZ4780_CLK_L2CACHE, "l2cache", CLK_MASK_DIV,
174 PLIST("cpumux"),
175 NO_MUX,
176 DIV(JZ_CPCCR, 4, 0, 4, -1, -1, -1),
177 NO_GATE
178 ),
179
180 GENCLK(JZ4780_CLK_AHB0, "ahb0", CLK_MASK_MUX | CLK_MASK_DIV,
181 PLIST("sclk_a", "mpll", "epll"),
182 MUX(JZ_CPCCR, 26, 2, 0x7),
183 DIV(JZ_CPCCR, 8, 0, 4, 21, -1, -1),
184 NO_GATE
185 ),
186
187 GENCLK(JZ4780_CLK_AHB2PMUX, "ahb2_apb_mux", CLK_MASK_MUX,
188 PLIST("sclk_a", "mpll", "rtc"),
189 MUX(JZ_CPCCR, 24, 2, 0x7),
190 NO_DIV,
191 NO_GATE
192 ),
193
194 GENCLK(JZ4780_CLK_AHB2, "ahb2", CLK_MASK_DIV,
195 PLIST("ahb2_apb_mux"),
196 NO_MUX,
197 DIV(JZ_CPCCR, 12, 0, 4, 20, -1, -1),
198 NO_GATE
199 ),
200
201 GENCLK(JZ4780_CLK_PCLK, "pclk", CLK_MASK_DIV,
202 PLIST("ahb2_apb_mux"),
203 NO_MUX,
204 DIV(JZ_CPCCR, 16, 0, 4, 20, -1, -1),
205 NO_GATE
206 ),
207
208 GENCLK(JZ4780_CLK_DDR, "ddr", CLK_MASK_MUX | CLK_MASK_DIV,
209 PLIST("sclk_a", "mpll"),
210 MUX(JZ_DDCDR, 30, 2, 0x6),
211 DIV(JZ_DDCDR, 0, 0, 4, 29, 28, 27),
212 NO_GATE
213 ),
214
215 GENCLK(JZ4780_CLK_VPU, "vpu", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE,
216 PLIST("sclk_a", "mpll", "epll"),
217 MUX(JZ_VPUCDR, 30, 2, 0xe),
218 DIV(JZ_VPUCDR, 0, 0, 4, 29, 28, 27),
219 GATEBIT(32 + 2)
220 ),
221
222 GENCLK(JZ4780_CLK_I2SPLL, "i2s_pll", CLK_MASK_MUX | CLK_MASK_DIV,
223 PLIST("sclk_a", "epll"),
224 MUX(JZ_I2SCDR, 30, 1, 0xc),
225 DIV(JZ_I2SCDR, 0, 0, 8, 29, 28, 27),
226 NO_GATE
227 ),
228
229 GENCLK(JZ4780_CLK_I2S, "i2s", CLK_MASK_MUX,
230 PLIST("ext", "i2s_pll"),
231 MUX(JZ_I2SCDR, 31, 1, 0xc),
232 NO_DIV,
233 NO_GATE
234 ),
235
236 GENCLK(JZ4780_CLK_LCD0PIXCLK, "lcd0pixclk", CLK_MASK_MUX | CLK_MASK_DIV,
237 PLIST("sclk_a", "mpll", "vpll"),
238 MUX(JZ_LP0CDR, 30, 2, 0xe),
239 DIV(JZ_LP0CDR, 0, 0, 8, 28, 27, 26),
240 NO_GATE
241 ),
242
243 GENCLK(JZ4780_CLK_LCD1PIXCLK, "lcd1pixclk", CLK_MASK_MUX | CLK_MASK_DIV,
244 PLIST("sclk_a", "mpll", "vpll"),
245 MUX(JZ_LP1CDR, 30, 2, 0xe),
246 DIV(JZ_LP1CDR, 0, 0, 8, 28, 27, 26),
247 NO_GATE
248 ),
249
250 GENCLK(JZ4780_CLK_MSCMUX, "msc_mux", CLK_MASK_MUX,
251 PLIST("sclk_a", "mpll"),
252 MUX(JZ_MSC0CDR, 30, 2, 0x6),
253 NO_DIV,
254 NO_GATE
255 ),
256
257 GENCLK(JZ4780_CLK_MSC0, "msc0", CLK_MASK_DIV | CLK_MASK_GATE,
258 PLIST("msc_mux"),
259 NO_MUX,
260 DIV(JZ_MSC0CDR, 0, 1, 8, 29, 28, 27),
261 GATEBIT(3)
262 ),
263
264 GENCLK(JZ4780_CLK_MSC1, "msc1", CLK_MASK_DIV | CLK_MASK_GATE,
265 PLIST("msc_mux"),
266 NO_MUX,
267 DIV(JZ_MSC1CDR, 0, 1, 8, 29, 28, 27),
268 GATEBIT(11)
269 ),
270
271 GENCLK(JZ4780_CLK_MSC2, "msc2", CLK_MASK_DIV | CLK_MASK_GATE,
272 PLIST("msc_mux"),
273 NO_MUX,
274 DIV(JZ_MSC2CDR, 0, 1, 8, 29, 28, 27),
275 GATEBIT(12)
276 ),
277
278 GENCLK(JZ4780_CLK_UHC, "uhc", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE,
279 PLIST("sclk_a", "mpll", "epll", "otg_phy"),
280 MUX(JZ_UHCCDR, 30, 2, 0xf),
281 DIV(JZ_UHCCDR, 0, 0, 8, 29, 28, 27),
282 GATEBIT(24)
283 ),
284
285 GENCLK(JZ4780_CLK_SSIPLL, "ssi_pll", CLK_MASK_MUX | CLK_MASK_DIV,
286 PLIST("sclk_a", "mpll"),
287 MUX(JZ_SSICDR, 30, 1, 0xc),
288 DIV(JZ_SSICDR, 0, 0, 8, 29, 28, 27),
289 NO_GATE
290 ),
291
292 GENCLK(JZ4780_CLK_SSI, "ssi", CLK_MASK_MUX,
293 PLIST("ext", "ssi_pll"),
294 MUX(JZ_SSICDR, 31, 1, 0xc),
295 NO_DIV,
296 NO_GATE
297 ),
298
299 GENCLK(JZ4780_CLK_CIMMCLK, "cim_mclk", CLK_MASK_MUX | CLK_MASK_DIV,
300 PLIST("sclk_a", "mpll"),
301 MUX(JZ_CIMCDR, 31, 1, 0xc),
302 DIV(JZ_CIMCDR, 0, 0, 8, 30, 29, 28),
303 NO_GATE
304 ),
305
306 GENCLK(JZ4780_CLK_PCMPLL, "pcm_pll", CLK_MASK_MUX | CLK_MASK_DIV,
307 PLIST("sclk_a", "mpll", "epll", "vpll"),
308 MUX(JZ_PCMCDR, 29, 2, 0xf),
309 DIV(JZ_PCMCDR, 0, 0, 8, 28, 27, 26),
310 NO_GATE
311 ),
312
313 GENCLK(JZ4780_CLK_PCM, "pcm", CLK_MASK_MUX | CLK_MASK_GATE,
314 PLIST("ext", "pcm_pll"),
315 MUX(JZ_PCMCDR, 31, 1, 0xc),
316 NO_DIV,
317 GATEBIT(32 + 3)
318 ),
319
320 GENCLK(JZ4780_CLK_GPU, "gpu", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE,
321 PLIST("sclk_a", "mpll", "epll"),
322 MUX(JZ_GPUCDR, 30, 2, 0x7),
323 DIV(JZ_GPUCDR, 0, 0, 4, 29, 28, 27),
324 GATEBIT(32 + 4)
325 ),
326
327 GENCLK(JZ4780_CLK_HDMI, "hdmi", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE,
328 PLIST("sclk_a", "mpll", "vpll"),
329 MUX(JZ_HDMICDR, 30, 2, 0xe),
330 DIV(JZ_HDMICDR, 0, 0, 8, 29, 28, 26),
331 GATEBIT(32 + 9)
332 ),
333
334 GENCLK(JZ4780_CLK_BCH, "bch", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE,
335 PLIST("sclk_a", "mpll", "epll"),
336 MUX(JZ_BCHCDR, 30, 2, 0x7),
337 DIV(JZ_BCHCDR, 0, 0, 4, 29, 28, 27),
338 GATEBIT(1)
339 ),
340 };
341
342 static struct jz4780_clk_gate_def gate_clks[] = {
343 GATE(JZ4780_CLK_NEMC, "nemc", "ahb2", 0),
344 GATE(JZ4780_CLK_OTG0, "otg0", "ext", 2),
345 GATE(JZ4780_CLK_SSI0, "ssi0", "ssi", 4),
346 GATE(JZ4780_CLK_SMB0, "smb0", "pclk", 5),
347 GATE(JZ4780_CLK_SMB1, "smb1", "pclk", 6),
348 GATE(JZ4780_CLK_SCC, "scc", "ext", 7),
349 GATE(JZ4780_CLK_AIC, "aic", "ext", 8),
350 GATE(JZ4780_CLK_TSSI0, "tssi0", "ext", 9),
351 GATE(JZ4780_CLK_OWI, "owi", "ext", 10),
352 GATE(JZ4780_CLK_KBC, "kbc", "ext", 13),
353 GATE(JZ4780_CLK_SADC, "sadc", "ext", 14),
354 GATE(JZ4780_CLK_UART0, "uart0", "ext", 15),
355 GATE(JZ4780_CLK_UART1, "uart1", "ext", 16),
356 GATE(JZ4780_CLK_UART2, "uart2", "ext", 17),
357 GATE(JZ4780_CLK_UART3, "uart3", "ext", 18),
358 GATE(JZ4780_CLK_SSI1, "ssi1", "ssi", 19),
359 GATE(JZ4780_CLK_SSI2, "ssi2", "ssi", 20),
360 GATE(JZ4780_CLK_PDMA, "pdma", "ext", 21),
361 GATE(JZ4780_CLK_GPS, "gps", "ext", 22),
362 GATE(JZ4780_CLK_MAC, "mac", "ext", 23),
363 GATE(JZ4780_CLK_SMB2, "smb2", "pclk", 25),
364 GATE(JZ4780_CLK_CIM, "cim", "ext", 26),
365 GATE(JZ4780_CLK_LCD, "lcd", "ext", 28),
366 GATE(JZ4780_CLK_TVE, "tve", "lcd", 27),
367 GATE(JZ4780_CLK_IPU, "ipu", "ext", 29),
368 GATE(JZ4780_CLK_DDR0, "ddr0", "ddr", 30),
369 GATE(JZ4780_CLK_DDR1, "ddr1", "ddr", 31),
370 GATE(JZ4780_CLK_SMB3, "smb3", "pclk", 32 + 0),
371 GATE(JZ4780_CLK_TSSI1, "tssi1", "ext", 32 + 1),
372 GATE(JZ4780_CLK_COMPRESS, "compress", "ext", 32 + 5),
373 GATE(JZ4780_CLK_AIC1, "aic1", "ext", 32 + 6),
374 GATE(JZ4780_CLK_GPVLC, "gpvlc", "ext", 32 + 7),
375 GATE(JZ4780_CLK_OTG1, "otg1", "ext", 32 + 8),
376 GATE(JZ4780_CLK_UART4, "uart4", "ext", 32 + 10),
377 GATE(JZ4780_CLK_AHBMON, "ahb_mon", "ext", 32 + 11),
378 GATE(JZ4780_CLK_SMB4, "smb4", "pclk", 32 + 12),
379 GATE(JZ4780_CLK_DES, "des", "ext", 32 + 13),
380 GATE(JZ4780_CLK_X2D, "x2d", "ext", 32 + 14),
381 GATE(JZ4780_CLK_CORE1, "core1", "cpu", 32 + 15),
382 };
383
384 static int
385 jz4780_clock_register(struct jz4780_clock_softc *sc)
386 {
387 int i, ret;
388
389 /* Register PLLs */
390 for (i = 0; i < nitems(pll_clks); i++) {
391 struct clknode_init_def clkdef;
392
393 clkdef.id = pll_clks[i].clk_id;
394 clkdef.name = __DECONST(char *, pll_clks[i].clk_name);
395 clkdef.parent_names = pll_clks[i].clk_pname;
396 clkdef.parent_cnt = 1;
397 clkdef.flags = CLK_NODE_STATIC_STRINGS;
398
399 ret = jz4780_clk_pll_register(sc->clkdom, &clkdef, &sc->mtx,
400 sc->res[0], pll_clks[i].clk_reg);
401 if (ret != 0)
402 return (ret);
403 }
404
405 /* Register OTG clock */
406 for (i = 0; i < nitems(otg_clks); i++) {
407 struct clknode_init_def clkdef;
408
409 clkdef.id = otg_clks[i].clk_id;
410 clkdef.name = __DECONST(char *, otg_clks[i].clk_name);
411 clkdef.parent_names = otg_clks[i].clk_pname;
412 clkdef.parent_cnt = 1;
413 clkdef.flags = CLK_NODE_STATIC_STRINGS;
414
415 ret = jz4780_clk_otg_register(sc->clkdom, &clkdef, &sc->mtx,
416 sc->res[0]);
417 if (ret != 0)
418 return (ret);
419 }
420
421 /* Register muxes and divisors */
422 for (i = 0; i < nitems(gen_clks); i++) {
423 ret = jz4780_clk_gen_register(sc->clkdom, &gen_clks[i],
424 &sc->mtx, sc->res[0]);
425 if (ret != 0)
426 return (ret);
427 }
428
429 /* Register simple gates */
430 for (i = 0; i < nitems(gate_clks); i++) {
431 struct clk_gate_def gatedef;
432
433 gatedef.clkdef.id = gate_clks[i].clk_id;
434 gatedef.clkdef.name = __DECONST(char *, gate_clks[i].clk_name);
435 gatedef.clkdef.parent_names = gate_clks[i].clk_pname;
436 gatedef.clkdef.parent_cnt = 1;
437 gatedef.clkdef.flags = CLK_NODE_STATIC_STRINGS;
438
439 if (gate_clks[i].clk_bit < 32) {
440 gatedef.offset = JZ_CLKGR0;
441 gatedef.shift = gate_clks[i].clk_bit;
442 } else {
443 gatedef.offset = JZ_CLKGR1;
444 gatedef.shift = gate_clks[i].clk_bit - 32;
445 }
446 gatedef.mask = 1;
447 gatedef.on_value = 0;
448 gatedef.off_value = 1;
449 gatedef.gate_flags = 0;
450
451 ret = clknode_gate_register(sc->clkdom, &gatedef);
452 if (ret != 0)
453 return (ret);
454
455 }
456
457 return (0);
458 }
459
460 static int
461 jz4780_clock_fixup(struct jz4780_clock_softc *sc)
462 {
463 struct clknode *clk_uhc;
464 int ret;
465
466 /*
467 * Make UHC mux use MPLL as the source. It defaults to OTG_PHY
468 * and that somehow just does not work.
469 */
470 clkdom_xlock(sc->clkdom);
471
472 /* Assume the worst */
473 ret = ENXIO;
474
475 clk_uhc = clknode_find_by_id(sc->clkdom, JZ4780_CLK_UHC);
476 if (clk_uhc != NULL) {
477 ret = clknode_set_parent_by_name(clk_uhc, "mpll");
478 if (ret != 0)
479 device_printf(sc->dev,
480 "unable to reparent uhc clock\n");
481 else
482 ret = clknode_set_freq(clk_uhc, 48000000, 0, 0);
483 if (ret != 0)
484 device_printf(sc->dev, "unable to init uhc clock\n");
485 } else
486 device_printf(sc->dev, "unable to lookup uhc clock\n");
487
488 clkdom_unlock(sc->clkdom);
489 return (ret);
490 }
491
492 #define CGU_LOCK(sc) mtx_lock(&(sc)->mtx)
493 #define CGU_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
494 #define CGU_LOCK_INIT(sc) \
495 mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
496 "jz4780-cgu", MTX_DEF)
497 #define CGU_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx);
498
499 #define CSR_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], (reg), (val))
500 #define CSR_READ_4(sc, reg) bus_read_4((sc)->res[0], (reg))
501
502 static int
503 jz4780_clock_probe(device_t dev)
504 {
505
506 if (!ofw_bus_status_okay(dev))
507 return (ENXIO);
508
509 if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-cgu"))
510 return (ENXIO);
511
512 device_set_desc(dev, "Ingenic jz4780 CGU");
513
514 return (BUS_PROBE_DEFAULT);
515 }
516
517 static int
518 jz4780_clock_attach(device_t dev)
519 {
520 struct jz4780_clock_softc *sc;
521
522 sc = device_get_softc(dev);
523 if (bus_alloc_resources(dev, jz4780_clock_spec, sc->res)) {
524 device_printf(dev, "could not allocate resources for device\n");
525 return (ENXIO);
526 }
527
528 sc->dev = dev;
529 CGU_LOCK_INIT(sc);
530
531 sc->clkdom = clkdom_create(dev);
532 if (sc->clkdom == NULL)
533 goto fail;
534 if (jz4780_clock_register(sc) != 0)
535 goto fail;
536 if (clkdom_finit(sc->clkdom) != 0)
537 goto fail;
538 if (jz4780_clock_fixup(sc) != 0)
539 goto fail;
540 if (bootverbose)
541 clkdom_dump(sc->clkdom);
542
543 return (0);
544 fail:
545 bus_release_resources(dev, jz4780_clock_spec, sc->res);
546 CGU_LOCK_DESTROY(sc);
547
548 return (ENXIO);
549 }
550
551 static int
552 jz4780_clock_detach(device_t dev)
553 {
554 struct jz4780_clock_softc *sc;
555
556 sc = device_get_softc(dev);
557 bus_release_resources(dev, jz4780_clock_spec, sc->res);
558 CGU_LOCK_DESTROY(sc);
559
560 return (0);
561 }
562
563 static int
564 jz4780_clock_write_4(device_t dev, bus_addr_t addr, uint32_t val)
565 {
566 struct jz4780_clock_softc *sc;
567
568 sc = device_get_softc(dev);
569 CSR_WRITE_4(sc, addr, val);
570 return (0);
571 }
572
573 static int
574 jz4780_clock_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
575 {
576 struct jz4780_clock_softc *sc;
577
578 sc = device_get_softc(dev);
579 *val = CSR_READ_4(sc, addr);
580 return (0);
581 }
582
583 static int
584 jz4780_clock_modify_4(device_t dev, bus_addr_t addr, uint32_t clear_mask,
585 uint32_t set_mask)
586 {
587 struct jz4780_clock_softc *sc;
588 uint32_t val;
589
590 sc = device_get_softc(dev);
591 val = CSR_READ_4(sc, addr);
592 val &= ~clear_mask;
593 val |= set_mask;
594 CSR_WRITE_4(sc, addr, val);
595 return (0);
596 }
597
598 static void
599 jz4780_clock_device_lock(device_t dev)
600 {
601 struct jz4780_clock_softc *sc;
602
603 sc = device_get_softc(dev);
604 CGU_LOCK(sc);
605 }
606
607 static void
608 jz4780_clock_device_unlock(device_t dev)
609 {
610 struct jz4780_clock_softc *sc;
611
612 sc = device_get_softc(dev);
613 CGU_UNLOCK(sc);
614 }
615
616 static device_method_t jz4780_clock_methods[] = {
617 /* Device interface */
618 DEVMETHOD(device_probe, jz4780_clock_probe),
619 DEVMETHOD(device_attach, jz4780_clock_attach),
620 DEVMETHOD(device_detach, jz4780_clock_detach),
621
622 /* Clock device interface */
623 DEVMETHOD(clkdev_write_4, jz4780_clock_write_4),
624 DEVMETHOD(clkdev_read_4, jz4780_clock_read_4),
625 DEVMETHOD(clkdev_modify_4, jz4780_clock_modify_4),
626 DEVMETHOD(clkdev_device_lock, jz4780_clock_device_lock),
627 DEVMETHOD(clkdev_device_unlock, jz4780_clock_device_unlock),
628
629 DEVMETHOD_END
630 };
631
632 static driver_t jz4780_clock_driver = {
633 "cgu",
634 jz4780_clock_methods,
635 sizeof(struct jz4780_clock_softc),
636 };
637
638 static devclass_t jz4780_clock_devclass;
639
640 EARLY_DRIVER_MODULE(jz4780_clock, simplebus, jz4780_clock_driver,
641 jz4780_clock_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_LATE);
642
643 static int
644 jz4780_ehci_clk_config(struct jz4780_clock_softc *sc)
645 {
646 clk_t phy_clk, ext_clk;
647 uint64_t phy_freq;
648 int err;
649
650 phy_clk = NULL;
651 ext_clk = NULL;
652 err = -1;
653
654 /* Set phy timing by copying it from ext */
655 if (clk_get_by_id(sc->dev, sc->clkdom, JZ4780_CLK_OTGPHY,
656 &phy_clk) != 0)
657 goto done;
658 if (clk_get_parent(phy_clk, &ext_clk) != 0)
659 goto done;
660 if (clk_get_freq(ext_clk, &phy_freq) != 0)
661 goto done;
662 if (clk_set_freq(phy_clk, phy_freq, 0) != 0)
663 goto done;
664 err = 0;
665 done:
666 clk_release(ext_clk);
667 clk_release(phy_clk);
668
669 return (err);
670 }
671
672 int
673 jz4780_ohci_enable(void)
674 {
675 device_t dev;
676 struct jz4780_clock_softc *sc;
677 uint32_t reg;
678
679 dev = devclass_get_device(jz4780_clock_devclass, 0);
680 if (dev == NULL)
681 return (-1);
682
683 sc = device_get_softc(dev);
684 CGU_LOCK(sc);
685
686 /* Do not force port1 to suspend mode */
687 reg = CSR_READ_4(sc, JZ_OPCR);
688 reg |= OPCR_SPENDN1;
689 CSR_WRITE_4(sc, JZ_OPCR, reg);
690
691 CGU_UNLOCK(sc);
692 return (0);
693 }
694
695 int
696 jz4780_ehci_enable(void)
697 {
698 device_t dev;
699 struct jz4780_clock_softc *sc;
700 uint32_t reg;
701
702 dev = devclass_get_device(jz4780_clock_devclass, 0);
703 if (dev == NULL)
704 return (-1);
705
706 sc = device_get_softc(dev);
707
708 /*
709 * EHCI should use MPPL as a parent, but Linux configures OTG
710 * clock anyway. Follow their lead blindly.
711 */
712 if (jz4780_ehci_clk_config(sc) != 0)
713 return (-1);
714
715 CGU_LOCK(sc);
716
717 /* Enable OTG, should not be necessary since we use PLL clock */
718 reg = CSR_READ_4(sc, JZ_USBPCR);
719 reg &= ~(PCR_OTG_DISABLE);
720 CSR_WRITE_4(sc, JZ_USBPCR, reg);
721
722 /* Do not force port1 to suspend mode */
723 reg = CSR_READ_4(sc, JZ_OPCR);
724 reg |= OPCR_SPENDN1;
725 CSR_WRITE_4(sc, JZ_OPCR, reg);
726
727 /* D- pulldown */
728 reg = CSR_READ_4(sc, JZ_USBPCR1);
729 reg |= PCR_DMPD1;
730 CSR_WRITE_4(sc, JZ_USBPCR1, reg);
731
732 /* D+ pulldown */
733 reg = CSR_READ_4(sc, JZ_USBPCR1);
734 reg |= PCR_DPPD1;
735 CSR_WRITE_4(sc, JZ_USBPCR1, reg);
736
737 /* 16 bit bus witdth for port 1*/
738 reg = CSR_READ_4(sc, JZ_USBPCR1);
739 reg |= PCR_WORD_I_F1 | PCR_WORD_I_F0;
740 CSR_WRITE_4(sc, JZ_USBPCR1, reg);
741
742 /* Reset USB */
743 reg = CSR_READ_4(sc, JZ_USBPCR);
744 reg |= PCR_POR;
745 CSR_WRITE_4(sc, JZ_USBPCR, reg);
746 DELAY(1);
747 reg = CSR_READ_4(sc, JZ_USBPCR);
748 reg &= ~(PCR_POR);
749 CSR_WRITE_4(sc, JZ_USBPCR, reg);
750
751 /* Soft-reset USB */
752 reg = CSR_READ_4(sc, JZ_SRBC);
753 reg |= SRBC_UHC_SR;
754 CSR_WRITE_4(sc, JZ_SRBC, reg);
755 /* 300ms */
756 DELAY(300*hz/1000);
757
758 reg = CSR_READ_4(sc, JZ_SRBC);
759 reg &= ~(SRBC_UHC_SR);
760 CSR_WRITE_4(sc, JZ_SRBC, reg);
761
762 /* 300ms */
763 DELAY(300*hz/1000);
764
765 CGU_UNLOCK(sc);
766 return (0);
767 }
768
769 #define USBRESET_DETECT_TIME 0x96
770
771 int
772 jz4780_otg_enable(void)
773 {
774 device_t dev;
775 struct jz4780_clock_softc *sc;
776 uint32_t reg;
777
778 dev = devclass_get_device(jz4780_clock_devclass, 0);
779 if (dev == NULL)
780 return (-1);
781
782 sc = device_get_softc(dev);
783
784 CGU_LOCK(sc);
785
786 /* Select Synopsys OTG mode */
787 reg = CSR_READ_4(sc, JZ_USBPCR1);
788 reg |= PCR_SYNOPSYS;
789
790 /* Set UTMI bus width to 16 bit */
791 reg |= PCR_WORD_I_F0 | PCR_WORD_I_F1;
792 CSR_WRITE_4(sc, JZ_USBPCR1, reg);
793
794 /* Blah */
795 reg = CSR_READ_4(sc, JZ_USBVBFIL);
796 reg = REG_SET(reg, USBVBFIL_IDDIGFIL, 0);
797 reg = REG_SET(reg, USBVBFIL_USBVBFIL, 0);
798 CSR_WRITE_4(sc, JZ_USBVBFIL, reg);
799
800 /* Setup reset detect time */
801 reg = CSR_READ_4(sc, JZ_USBRDT);
802 reg = REG_SET(reg, USBRDT_USBRDT, USBRESET_DETECT_TIME);
803 reg |= USBRDT_VBFIL_LD_EN;
804 CSR_WRITE_4(sc, JZ_USBRDT, reg);
805
806 /* Setup USBPCR bits */
807 reg = CSR_READ_4(sc, JZ_USBPCR);
808 reg |= PCR_USB_MODE;
809 reg |= PCR_COMMONONN;
810 reg |= PCR_VBUSVLDEXT;
811 reg |= PCR_VBUSVLDEXTSEL;
812 reg &= ~(PCR_OTG_DISABLE);
813 CSR_WRITE_4(sc, JZ_USBPCR, reg);
814
815 /* Reset USB */
816 reg = CSR_READ_4(sc, JZ_USBPCR);
817 reg |= PCR_POR;
818 CSR_WRITE_4(sc, JZ_USBPCR, reg);
819 DELAY(1000);
820 reg = CSR_READ_4(sc, JZ_USBPCR);
821 reg &= ~(PCR_POR);
822 CSR_WRITE_4(sc, JZ_USBPCR, reg);
823
824 /* Unsuspend OTG port */
825 reg = CSR_READ_4(sc, JZ_OPCR);
826 reg |= OPCR_SPENDN0;
827 CSR_WRITE_4(sc, JZ_OPCR, reg);
828
829 CGU_UNLOCK(sc);
830 return (0);
831 }
Cache object: 433480d68eef27e22a2403997d35691b
|