1 /* $OpenBSD: prcm.c,v 1.19 2024/05/13 01:15:50 jsg Exp $ */
2 /*
3 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /*-
19 * Copyright (c) 2011
20 * Ben Gray <ben.r.gray@gmail.com>.
21 * All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 3. The name of the company nor the name of the author may be used to
32 * endorse or promote products derived from this software without specific
33 * prior written permission.
34 *
35 * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR
36 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
38 * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
39 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
41 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
43 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
44 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 */
46
47 /*
48 * Driver for the Power, Reset and Clock Management Module (PRCM).
49 */
50
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/device.h>
54
55 #include <machine/bus.h>
56 #include <armv7/armv7/armv7var.h>
57 #include <armv7/omap/prcmvar.h>
58
59 #include <armv7/omap/am335x_prcmreg.h>
60 #include <armv7/omap/omap3_prcmreg.h>
61 #include <armv7/omap/omap4_prcmreg.h>
62
63 #include <dev/ofw/fdt.h>
64
65 #define PRCM_REVISION 0x0800
66 #define PRCM_SYSCONFIG 0x0810
67
68 uint32_t prcm_imask_mask[PRCM_REG_MAX];
69 uint32_t prcm_fmask_mask[PRCM_REG_MAX];
70 uint32_t prcm_imask_addr[PRCM_REG_MAX];
71 uint32_t prcm_fmask_addr[PRCM_REG_MAX];
72
73 #define SYS_CLK 13 /* SYS_CLK speed in MHz */
74 #define PRCM_AM335X_MASTER_OSC 24000 /* kHz */
75
76
77 struct prcm_softc {
78 struct device sc_dev;
79 bus_space_tag_t sc_iot;
80 bus_space_handle_t sc_prcm;
81 bus_space_handle_t sc_cm1;
82 bus_space_handle_t sc_cm2;
83 void (*sc_setup)(struct prcm_softc *sc);
84 void (*sc_enablemodule)(struct prcm_softc *sc, int mod);
85 void (*sc_setclock)(struct prcm_softc *sc,
86 int clock, int speed);
87 uint32_t cm1_avail;
88 uint32_t cm2_avail;
89 };
90
91 void prcm_attach(struct device *, struct device *, void *);
92 int prcm_setup_dpll5(struct prcm_softc *);
93 uint32_t prcm_v3_bit(int mod);
94 uint32_t prcm_am335x_clkctrl(int mod);
95
96 void prcm_am335x_enablemodule(struct prcm_softc *, int);
97 void prcm_am335x_setclock(struct prcm_softc *, int, int);
98
99 void prcm_v3_setup(struct prcm_softc *);
100 void prcm_v3_enablemodule(struct prcm_softc *, int);
101 void prcm_v3_setclock(struct prcm_softc *, int, int);
102
103 void prcm_v4_enablemodule(struct prcm_softc *, int);
104 int prcm_v4_hsusbhost_activate(int);
105 int prcm_v4_hsusbhost_set_source(int, int);
106
107 const struct cfattach prcm_ca = {
108 sizeof (struct prcm_softc), NULL, prcm_attach
109 };
110
111 struct cfdriver prcm_cd = {
112 NULL, "prcm", DV_DULL
113 };
114
115 void
prcm_attach(struct device * parent,struct device * self,void * args)116 prcm_attach(struct device *parent, struct device *self, void *args)
117 {
118 struct armv7_attach_args *aa = args;
119 struct prcm_softc *sc = (struct prcm_softc *) self;
120 u_int32_t reg;
121 void *node;
122
123 sc->sc_iot = aa->aa_iot;
124
125 node = fdt_find_node("/");
126 if (node == NULL)
127 panic("%s: could not get fdt root node",
128 sc->sc_dev.dv_xname);
129
130 if (fdt_is_compatible(node, "ti,am33xx")) {
131 sc->sc_setup = NULL;
132 sc->sc_enablemodule = prcm_am335x_enablemodule;
133 sc->sc_setclock = prcm_am335x_setclock;
134 } else if (fdt_is_compatible(node, "ti,omap3")) {
135 sc->sc_setup = prcm_v3_setup;
136 sc->sc_enablemodule = prcm_v3_enablemodule;
137 sc->sc_setclock = prcm_v3_setclock;
138 } else if (fdt_is_compatible(node, "ti,omap4")) {
139 sc->sc_setup = NULL;
140 sc->sc_enablemodule = prcm_v4_enablemodule;
141 sc->sc_setclock = NULL;
142 sc->cm1_avail = 1;
143 sc->cm2_avail = 1;
144 } else
145 panic("%s: could not find a compatible soc",
146 sc->sc_dev.dv_xname);
147
148 if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
149 aa->aa_dev->mem[0].size, 0, &sc->sc_prcm))
150 panic("prcm_attach: bus_space_map failed!");
151
152 if (sc->cm1_avail &&
153 bus_space_map(sc->sc_iot, aa->aa_dev->mem[1].addr,
154 aa->aa_dev->mem[1].size, 0, &sc->sc_cm1))
155 panic("prcm_attach: bus_space_map failed!");
156
157 if (sc->cm2_avail &&
158 bus_space_map(sc->sc_iot, aa->aa_dev->mem[2].addr,
159 aa->aa_dev->mem[2].size, 0, &sc->sc_cm2))
160 panic("prcm_attach: bus_space_map failed!");
161
162 reg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_REVISION);
163 printf(" rev %d.%d\n", reg >> 4 & 0xf, reg & 0xf);
164
165 if (sc->sc_setup != NULL)
166 sc->sc_setup(sc);
167 }
168
169 void
prcm_v3_setup(struct prcm_softc * sc)170 prcm_v3_setup(struct prcm_softc *sc)
171 {
172 /* Setup the 120MHZ DPLL5 clock, to be used by USB. */
173 prcm_setup_dpll5(sc);
174
175 prcm_fmask_mask[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_FMASK;
176 prcm_imask_mask[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_IMASK;
177 prcm_fmask_addr[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_FADDR;
178 prcm_imask_addr[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_IADDR;
179
180 prcm_fmask_mask[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_FMASK;
181 prcm_imask_mask[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_IMASK;
182 prcm_fmask_addr[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_FADDR;
183 prcm_imask_addr[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_IADDR;
184
185 prcm_fmask_mask[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_FMASK;
186 prcm_imask_mask[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_IMASK;
187 prcm_fmask_addr[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_FADDR;
188 prcm_imask_addr[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_IADDR;
189
190 prcm_fmask_mask[PRCM_REG_WKUP] = PRCM_REG_WKUP_FMASK;
191 prcm_imask_mask[PRCM_REG_WKUP] = PRCM_REG_WKUP_IMASK;
192 prcm_fmask_addr[PRCM_REG_WKUP] = PRCM_REG_WKUP_FADDR;
193 prcm_imask_addr[PRCM_REG_WKUP] = PRCM_REG_WKUP_IADDR;
194
195 prcm_fmask_mask[PRCM_REG_PER] = PRCM_REG_PER_FMASK;
196 prcm_imask_mask[PRCM_REG_PER] = PRCM_REG_PER_IMASK;
197 prcm_fmask_addr[PRCM_REG_PER] = PRCM_REG_PER_FADDR;
198 prcm_imask_addr[PRCM_REG_PER] = PRCM_REG_PER_IADDR;
199
200 prcm_fmask_mask[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_FMASK;
201 prcm_imask_mask[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_IMASK;
202 prcm_fmask_addr[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_FADDR;
203 prcm_imask_addr[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_IADDR;
204 }
205
206 void
prcm_setclock(int clock,int speed)207 prcm_setclock(int clock, int speed)
208 {
209 struct prcm_softc *sc = prcm_cd.cd_devs[0];
210
211 if (!sc->sc_setclock)
212 panic("%s: not initialised!", __func__);
213
214 sc->sc_setclock(sc, clock, speed);
215 }
216
217 void
prcm_am335x_setclock(struct prcm_softc * sc,int clock,int speed)218 prcm_am335x_setclock(struct prcm_softc *sc, int clock, int speed)
219 {
220 u_int32_t oreg, reg, mask;
221
222 /* set CLKSEL register */
223 if (clock == 1) {
224 oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
225 PRCM_AM335X_CLKSEL_TIMER2_CLK);
226 mask = 3;
227 reg = oreg & ~mask;
228 reg |=0x02;
229 bus_space_write_4(sc->sc_iot, sc->sc_prcm,
230 PRCM_AM335X_CLKSEL_TIMER2_CLK, reg);
231 } else if (clock == 2) {
232 oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
233 PRCM_AM335X_CLKSEL_TIMER3_CLK);
234 mask = 3;
235 reg = oreg & ~mask;
236 reg |=0x02;
237 bus_space_write_4(sc->sc_iot, sc->sc_prcm,
238 PRCM_AM335X_CLKSEL_TIMER3_CLK, reg);
239 } else if (clock == 3) { /* DISP M1 */
240 oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
241 oreg &= ~0x7;
242 oreg |= 0x4;
243 bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
244 while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
245 & 0x10)));
246
247 oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL);
248 oreg &= 0xFFF800FF;
249 oreg |= (speed & 0x7FF) << 8;
250 bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL, oreg);
251
252 oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
253 oreg |= 0x7;
254 bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
255 while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
256 & 0x10)));
257 } else if (clock == 4) { /* DISP N */
258 oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
259 oreg &= ~0x7;
260 oreg |= 0x4;
261 bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
262 while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
263 & 0x10)));
264
265 oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL);
266 oreg &= 0xFFFFFF80;
267 oreg |= speed & 0x7F;
268 bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL, oreg);
269
270 oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
271 oreg |= 0x7;
272 bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
273 while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
274 & 0x10)));
275 } else if (clock == 5) { /* DISP M2 */
276 oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_M2);
277 oreg &= ~(0x1F);
278 oreg |= speed & 0x1F;
279 bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_M2, oreg);
280 }
281 }
282
283 void
prcm_v3_setclock(struct prcm_softc * sc,int clock,int speed)284 prcm_v3_setclock(struct prcm_softc *sc, int clock, int speed)
285 {
286 u_int32_t oreg, reg, mask;
287
288 if (clock == 1) {
289 oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP);
290 mask = 1;
291 reg = (oreg &~mask) | (speed & mask);
292 bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP, reg);
293 } else if (clock >= 2 && clock <= 9) {
294 int shift = (clock-2);
295 oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER);
296 mask = 1 << (shift);
297 reg = (oreg & ~mask) | ( (speed << shift) & mask);
298 bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER, reg);
299 } else
300 panic("%s: invalid clock %d", __func__, clock);
301 }
302
303 uint32_t
prcm_v3_bit(int mod)304 prcm_v3_bit(int mod)
305 {
306 switch(mod) {
307 case PRCM_MMC0:
308 return PRCM_CLK_EN_MMC1;
309 case PRCM_MMC1:
310 return PRCM_CLK_EN_MMC2;
311 case PRCM_MMC2:
312 return PRCM_CLK_EN_MMC3;
313 case PRCM_USB:
314 return PRCM_CLK_EN_USB;
315 case PRCM_GPIO0:
316 return PRCM_CLK_EN_GPIO1;
317 case PRCM_GPIO1:
318 return PRCM_CLK_EN_GPIO2;
319 case PRCM_GPIO2:
320 return PRCM_CLK_EN_GPIO3;
321 case PRCM_GPIO3:
322 return PRCM_CLK_EN_GPIO4;
323 case PRCM_GPIO4:
324 return PRCM_CLK_EN_GPIO5;
325 case PRCM_GPIO5:
326 return PRCM_CLK_EN_GPIO6;
327 case PRCM_I2C0:
328 return PRCM_CLK_EN_I2C1;
329 case PRCM_I2C1:
330 return PRCM_CLK_EN_I2C2;
331 case PRCM_I2C2:
332 return PRCM_CLK_EN_I2C3;
333 default:
334 panic("%s: module not found", __func__);
335 }
336 }
337
338 uint32_t
prcm_am335x_clkctrl(int mod)339 prcm_am335x_clkctrl(int mod)
340 {
341 switch(mod) {
342 case PRCM_TIMER2:
343 return PRCM_AM335X_TIMER2_CLKCTRL;
344 case PRCM_TIMER3:
345 return PRCM_AM335X_TIMER3_CLKCTRL;
346 case PRCM_MMC0:
347 return PRCM_AM335X_MMC0_CLKCTRL;
348 case PRCM_MMC1:
349 return PRCM_AM335X_MMC1_CLKCTRL;
350 case PRCM_MMC2:
351 return PRCM_AM335X_MMC2_CLKCTRL;
352 case PRCM_USB:
353 return PRCM_AM335X_USB0_CLKCTRL;
354 case PRCM_GPIO0:
355 return PRCM_AM335X_GPIO0_CLKCTRL;
356 case PRCM_GPIO1:
357 return PRCM_AM335X_GPIO1_CLKCTRL;
358 case PRCM_GPIO2:
359 return PRCM_AM335X_GPIO2_CLKCTRL;
360 case PRCM_GPIO3:
361 return PRCM_AM335X_GPIO3_CLKCTRL;
362 case PRCM_TPCC:
363 return PRCM_AM335X_TPCC_CLKCTRL;
364 case PRCM_TPTC0:
365 return PRCM_AM335X_TPTC0_CLKCTRL;
366 case PRCM_TPTC1:
367 return PRCM_AM335X_TPTC1_CLKCTRL;
368 case PRCM_TPTC2:
369 return PRCM_AM335X_TPTC2_CLKCTRL;
370 case PRCM_I2C0:
371 return PRCM_AM335X_I2C0_CLKCTRL;
372 case PRCM_I2C1:
373 return PRCM_AM335X_I2C1_CLKCTRL;
374 case PRCM_I2C2:
375 return PRCM_AM335X_I2C2_CLKCTRL;
376 case PRCM_LCDC:
377 return PRCM_AM335X_LCDC_CLKCTRL;
378 case PRCM_RNG:
379 return PRCM_AM335X_RNG_CLKCTRL;
380 default:
381 panic("%s: module not found", __func__);
382 }
383 }
384
385 void
prcm_enablemodule(int mod)386 prcm_enablemodule(int mod)
387 {
388 struct prcm_softc *sc = prcm_cd.cd_devs[0];
389
390 if (!sc->sc_enablemodule)
391 panic("%s: not initialised!", __func__);
392
393 sc->sc_enablemodule(sc, mod);
394 }
395
396 void
prcm_am335x_enablemodule(struct prcm_softc * sc,int mod)397 prcm_am335x_enablemodule(struct prcm_softc *sc, int mod)
398 {
399 uint32_t clkctrl;
400 int reg;
401
402 /*set enable bits in CLKCTRL register */
403 reg = prcm_am335x_clkctrl(mod);
404 clkctrl = bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg);
405 clkctrl &=~AM335X_CLKCTRL_MODULEMODE_MASK;
406 clkctrl |= AM335X_CLKCTRL_MODULEMODE_ENABLE;
407 bus_space_write_4(sc->sc_iot, sc->sc_prcm, reg, clkctrl);
408
409 /* wait until module is enabled */
410 while (bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg) & 0x30000)
411 ;
412 }
413
414 void
prcm_v3_enablemodule(struct prcm_softc * sc,int mod)415 prcm_v3_enablemodule(struct prcm_softc *sc, int mod)
416 {
417 uint32_t bit;
418 uint32_t fclk, iclk, fmask, imask, mbit;
419 int freg, ireg, reg;
420
421 bit = prcm_v3_bit(mod);
422 reg = bit >> 5;
423
424 freg = prcm_fmask_addr[reg];
425 ireg = prcm_imask_addr[reg];
426 fmask = prcm_fmask_mask[reg];
427 imask = prcm_imask_mask[reg];
428
429 mbit = 1 << (bit & 0x1f);
430 if (fmask & mbit) { /* dont access the register if bit isn't present */
431 fclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, freg);
432 bus_space_write_4(sc->sc_iot, sc->sc_prcm, freg, fclk | mbit);
433 }
434 if (imask & mbit) { /* dont access the register if bit isn't present */
435 iclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, ireg);
436 bus_space_write_4(sc->sc_iot, sc->sc_prcm, ireg, iclk | mbit);
437 }
438 printf("\n");
439 }
440
441 void
prcm_v4_enablemodule(struct prcm_softc * sc,int mod)442 prcm_v4_enablemodule(struct prcm_softc *sc, int mod)
443 {
444 switch (mod) {
445 case PRCM_MMC0:
446 case PRCM_MMC1:
447 case PRCM_MMC2:
448 case PRCM_MMC3:
449 case PRCM_MMC4:
450 break;
451 case PRCM_USBP1_PHY:
452 case PRCM_USBP2_PHY:
453 prcm_v4_hsusbhost_set_source(mod, 0);
454 case PRCM_USB:
455 case PRCM_USBTLL:
456 case PRCM_USBP1_UTMI:
457 case PRCM_USBP1_HSIC:
458 case PRCM_USBP2_UTMI:
459 case PRCM_USBP2_HSIC:
460 prcm_v4_hsusbhost_activate(mod);
461 return;
462 case PRCM_GPIO0:
463 case PRCM_GPIO1:
464 case PRCM_GPIO2:
465 case PRCM_GPIO3:
466 case PRCM_GPIO4:
467 case PRCM_GPIO5:
468 /* XXX */
469 break;
470 case PRCM_I2C0:
471 case PRCM_I2C1:
472 case PRCM_I2C2:
473 case PRCM_I2C3:
474 /* XXX */
475 break;
476 default:
477 panic("%s: module not found", __func__);
478 }
479 }
480
481 int
prcm_v4_hsusbhost_activate(int type)482 prcm_v4_hsusbhost_activate(int type)
483 {
484 struct prcm_softc *sc = prcm_cd.cd_devs[0];
485 uint32_t i;
486 uint32_t clksel_reg_off;
487 uint32_t clksel, oclksel;
488
489 switch (type) {
490 case PRCM_USB:
491 case PRCM_USBP1_PHY:
492 case PRCM_USBP2_PHY:
493 /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
494 clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58;
495 clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
496 oclksel = clksel;
497 /* Enable the module and also enable the optional func clocks */
498 if (type == PRCM_USB) {
499 clksel &= ~O4_CLKCTRL_MODULEMODE_MASK;
500 clksel |= /*O4_CLKCTRL_MODULEMODE_ENABLE*/2;
501
502 clksel |= (0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */
503 }
504
505 break;
506
507 default:
508 panic("%s: invalid type %d", __func__, type);
509 return (EINVAL);
510 }
511 bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel);
512
513 /* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */
514 for (i = 0; i < O4_MAX_MODULE_ENABLE_WAIT; i++) {
515 clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
516 if ((clksel & O4_CLKCTRL_IDLEST_MASK) == O4_CLKCTRL_IDLEST_ENABLED)
517 break;
518 }
519
520 /* Check the enabled state */
521 if ((clksel & O4_CLKCTRL_IDLEST_MASK) != O4_CLKCTRL_IDLEST_ENABLED) {
522 printf("Error: HERE failed to enable module with clock %d\n", type);
523 printf("Error: 0x%08x => 0x%08x\n", clksel_reg_off, clksel);
524 return (ETIMEDOUT);
525 }
526
527 return (0);
528 }
529
530 int
prcm_v4_hsusbhost_set_source(int clk,int clksrc)531 prcm_v4_hsusbhost_set_source(int clk, int clksrc)
532 {
533 struct prcm_softc *sc = prcm_cd.cd_devs[0];
534 uint32_t clksel_reg_off;
535 uint32_t clksel;
536 unsigned int bit;
537
538 if (clk == PRCM_USBP1_PHY)
539 bit = 24;
540 else if (clk != PRCM_USBP2_PHY)
541 bit = 25;
542 else
543 return (-EINVAL);
544
545 /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
546 clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58;
547 clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
548
549 /* XXX: Set the clock source to either external or internal */
550 if (clksrc == 0)
551 clksel |= (0x1 << bit);
552 else
553 clksel &= ~(0x1 << bit);
554
555 bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel);
556
557 return (0);
558 }
559
560 /*
561 * OMAP35xx Power, Reset, and Clock Management Reference Guide
562 * (sprufa5.pdf) and AM/DM37x Multimedia Device Technical Reference
563 * Manual (sprugn4h.pdf) note that DPLL5 provides a 120MHz clock for
564 * peripheral domain modules (page 107 and page 302).
565 * The reference clock for DPLL5 is DPLL5_ALWON_FCLK which is
566 * SYS_CLK, running at 13MHz.
567 */
568 int
prcm_setup_dpll5(struct prcm_softc * sc)569 prcm_setup_dpll5(struct prcm_softc *sc)
570 {
571 uint32_t val;
572
573 /*
574 * We need to set the multiplier and divider values for PLL.
575 * To end up with 120MHz we take SYS_CLK, divide by it and multiply
576 * with 120 (sprugn4h.pdf, 13.4.11.4.1 SSC Configuration)
577 */
578 val = ((120 & 0x7ff) << 8) | ((SYS_CLK - 1) & 0x7f);
579 bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL4_PLL, val);
580
581 /* Clock divider from the PLL to the 120MHz clock. */
582 bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL5_PLL, val);
583
584 /*
585 * spruf98o.pdf, page 2319:
586 * PERIPH2_DPLL_FREQSEL is 0x7 1.75MHz to 2.1MHz
587 * EN_PERIPH2_DPLL is 0x7
588 */
589 val = (7 << 4) | (7 << 0);
590 bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKEN2_PLL, val);
591
592 /* Disable the interconnect clock auto-idle. */
593 bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_AUTOIDLE2_PLL, 0x0);
594
595 /* Wait until DPLL5 is locked and there's clock activity. */
596 while ((val = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
597 CM_IDLEST_CKGEN) & 0x01) == 0x00) {
598 #ifdef DIAGNOSTIC
599 printf("CM_IDLEST_PLL = 0x%08x\n", val);
600 #endif
601 }
602
603 return 0;
604 }
605