xref: /openbsd/sys/arch/armv7/omap/prcm.c (revision 9fdf0c62)
1 /* $OpenBSD: prcm.c,v 1.18 2021/10/24 17:52:28 mpi 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 int	prcm_match(struct device *, void *, void *);
92 void	prcm_attach(struct device *, struct device *, void *);
93 int	prcm_setup_dpll5(struct prcm_softc *);
94 uint32_t prcm_v3_bit(int mod);
95 uint32_t prcm_am335x_clkctrl(int mod);
96 
97 void prcm_am335x_enablemodule(struct prcm_softc *, int);
98 void prcm_am335x_setclock(struct prcm_softc *, int, int);
99 
100 void prcm_v3_setup(struct prcm_softc *);
101 void prcm_v3_enablemodule(struct prcm_softc *, int);
102 void prcm_v3_setclock(struct prcm_softc *, int, int);
103 
104 void prcm_v4_enablemodule(struct prcm_softc *, int);
105 int prcm_v4_hsusbhost_activate(int);
106 int prcm_v4_hsusbhost_set_source(int, int);
107 
108 const struct cfattach	prcm_ca = {
109 	sizeof (struct prcm_softc), NULL, prcm_attach
110 };
111 
112 struct cfdriver prcm_cd = {
113 	NULL, "prcm", DV_DULL
114 };
115 
116 void
prcm_attach(struct device * parent,struct device * self,void * args)117 prcm_attach(struct device *parent, struct device *self, void *args)
118 {
119 	struct armv7_attach_args *aa = args;
120 	struct prcm_softc *sc = (struct prcm_softc *) self;
121 	u_int32_t reg;
122 	void *node;
123 
124 	sc->sc_iot = aa->aa_iot;
125 
126 	node = fdt_find_node("/");
127 	if (node == NULL)
128 		panic("%s: could not get fdt root node",
129 		    sc->sc_dev.dv_xname);
130 
131 	if (fdt_is_compatible(node, "ti,am33xx")) {
132 		sc->sc_setup = NULL;
133 		sc->sc_enablemodule = prcm_am335x_enablemodule;
134 		sc->sc_setclock = prcm_am335x_setclock;
135 	} else if (fdt_is_compatible(node, "ti,omap3")) {
136 		sc->sc_setup = prcm_v3_setup;
137 		sc->sc_enablemodule = prcm_v3_enablemodule;
138 		sc->sc_setclock = prcm_v3_setclock;
139 	} else if (fdt_is_compatible(node, "ti,omap4")) {
140 		sc->sc_setup = NULL;
141 		sc->sc_enablemodule = prcm_v4_enablemodule;
142 		sc->sc_setclock = NULL;
143 		sc->cm1_avail = 1;
144 		sc->cm2_avail = 1;
145 	} else
146 		panic("%s: could not find a compatible soc",
147 		    sc->sc_dev.dv_xname);
148 
149 	if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
150 	    aa->aa_dev->mem[0].size, 0, &sc->sc_prcm))
151 		panic("prcm_attach: bus_space_map failed!");
152 
153 	if (sc->cm1_avail &&
154 	    bus_space_map(sc->sc_iot, aa->aa_dev->mem[1].addr,
155 	    aa->aa_dev->mem[1].size, 0, &sc->sc_cm1))
156 		panic("prcm_attach: bus_space_map failed!");
157 
158 	if (sc->cm2_avail &&
159 	    bus_space_map(sc->sc_iot, aa->aa_dev->mem[2].addr,
160 	    aa->aa_dev->mem[2].size, 0, &sc->sc_cm2))
161 		panic("prcm_attach: bus_space_map failed!");
162 
163 	reg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_REVISION);
164 	printf(" rev %d.%d\n", reg >> 4 & 0xf, reg & 0xf);
165 
166 	if (sc->sc_setup != NULL)
167 		sc->sc_setup(sc);
168 }
169 
170 void
prcm_v3_setup(struct prcm_softc * sc)171 prcm_v3_setup(struct prcm_softc *sc)
172 {
173 	/* Setup the 120MHZ DPLL5 clock, to be used by USB. */
174 	prcm_setup_dpll5(sc);
175 
176 	prcm_fmask_mask[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_FMASK;
177 	prcm_imask_mask[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_IMASK;
178 	prcm_fmask_addr[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_FADDR;
179 	prcm_imask_addr[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_IADDR;
180 
181 	prcm_fmask_mask[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_FMASK;
182 	prcm_imask_mask[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_IMASK;
183 	prcm_fmask_addr[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_FADDR;
184 	prcm_imask_addr[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_IADDR;
185 
186 	prcm_fmask_mask[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_FMASK;
187 	prcm_imask_mask[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_IMASK;
188 	prcm_fmask_addr[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_FADDR;
189 	prcm_imask_addr[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_IADDR;
190 
191 	prcm_fmask_mask[PRCM_REG_WKUP] = PRCM_REG_WKUP_FMASK;
192 	prcm_imask_mask[PRCM_REG_WKUP] = PRCM_REG_WKUP_IMASK;
193 	prcm_fmask_addr[PRCM_REG_WKUP] = PRCM_REG_WKUP_FADDR;
194 	prcm_imask_addr[PRCM_REG_WKUP] = PRCM_REG_WKUP_IADDR;
195 
196 	prcm_fmask_mask[PRCM_REG_PER] = PRCM_REG_PER_FMASK;
197 	prcm_imask_mask[PRCM_REG_PER] = PRCM_REG_PER_IMASK;
198 	prcm_fmask_addr[PRCM_REG_PER] = PRCM_REG_PER_FADDR;
199 	prcm_imask_addr[PRCM_REG_PER] = PRCM_REG_PER_IADDR;
200 
201 	prcm_fmask_mask[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_FMASK;
202 	prcm_imask_mask[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_IMASK;
203 	prcm_fmask_addr[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_FADDR;
204 	prcm_imask_addr[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_IADDR;
205 }
206 
207 void
prcm_setclock(int clock,int speed)208 prcm_setclock(int clock, int speed)
209 {
210 	struct prcm_softc *sc = prcm_cd.cd_devs[0];
211 
212 	if (!sc->sc_setclock)
213 		panic("%s: not initialised!", __func__);
214 
215 	sc->sc_setclock(sc, clock, speed);
216 }
217 
218 void
prcm_am335x_setclock(struct prcm_softc * sc,int clock,int speed)219 prcm_am335x_setclock(struct prcm_softc *sc, int clock, int speed)
220 {
221 	u_int32_t oreg, reg, mask;
222 
223 	/* set CLKSEL register */
224 	if (clock == 1) {
225 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
226 		    PRCM_AM335X_CLKSEL_TIMER2_CLK);
227 		mask = 3;
228 		reg = oreg & ~mask;
229 		reg |=0x02;
230 		bus_space_write_4(sc->sc_iot, sc->sc_prcm,
231 		    PRCM_AM335X_CLKSEL_TIMER2_CLK, reg);
232 	} else if (clock == 2) {
233 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
234 		    PRCM_AM335X_CLKSEL_TIMER3_CLK);
235 		mask = 3;
236 		reg = oreg & ~mask;
237 		reg |=0x02;
238 		bus_space_write_4(sc->sc_iot, sc->sc_prcm,
239 		    PRCM_AM335X_CLKSEL_TIMER3_CLK, reg);
240 	} else if (clock == 3) { /* DISP M1 */
241 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
242 		oreg &= ~0x7;
243 		oreg |= 0x4;
244 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
245 		while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
246 		    & 0x10)));
247 
248 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL);
249 		oreg &= 0xFFF800FF;
250 		oreg |= (speed & 0x7FF) << 8;
251 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL, oreg);
252 
253 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
254 		oreg |= 0x7;
255 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
256 		while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
257 		    & 0x10)));
258 	} else if (clock == 4) { /* DISP N */
259 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
260 		oreg &= ~0x7;
261 		oreg |= 0x4;
262 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
263 		while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
264 		    & 0x10)));
265 
266 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL);
267 		oreg &= 0xFFFFFF80;
268 		oreg |= speed & 0x7F;
269 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL, oreg);
270 
271 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
272 		oreg |= 0x7;
273 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
274 		while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
275 		    & 0x10)));
276 	} else if (clock == 5) { /* DISP M2 */
277 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_M2);
278 		oreg &= ~(0x1F);
279 		oreg |= speed & 0x1F;
280 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_M2, oreg);
281 	}
282 }
283 
284 void
prcm_v3_setclock(struct prcm_softc * sc,int clock,int speed)285 prcm_v3_setclock(struct prcm_softc *sc, int clock, int speed)
286 {
287 	u_int32_t oreg, reg, mask;
288 
289 	if (clock == 1) {
290 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP);
291 		mask = 1;
292 		reg = (oreg &~mask) | (speed & mask);
293 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP, reg);
294 	} else if (clock >= 2 && clock <= 9) {
295 		int shift =  (clock-2);
296 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER);
297 		mask = 1 << (shift);
298 		reg =  (oreg & ~mask) | ( (speed << shift) & mask);
299 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER, reg);
300 	} else
301 		panic("%s: invalid clock %d", __func__, clock);
302 }
303 
304 uint32_t
prcm_v3_bit(int mod)305 prcm_v3_bit(int mod)
306 {
307 	switch(mod) {
308 	case PRCM_MMC0:
309 		return PRCM_CLK_EN_MMC1;
310 	case PRCM_MMC1:
311 		return PRCM_CLK_EN_MMC2;
312 	case PRCM_MMC2:
313 		return PRCM_CLK_EN_MMC3;
314 	case PRCM_USB:
315 		return PRCM_CLK_EN_USB;
316 	case PRCM_GPIO0:
317 		return PRCM_CLK_EN_GPIO1;
318 	case PRCM_GPIO1:
319 		return PRCM_CLK_EN_GPIO2;
320 	case PRCM_GPIO2:
321 		return PRCM_CLK_EN_GPIO3;
322 	case PRCM_GPIO3:
323 		return PRCM_CLK_EN_GPIO4;
324 	case PRCM_GPIO4:
325 		return PRCM_CLK_EN_GPIO5;
326 	case PRCM_GPIO5:
327 		return PRCM_CLK_EN_GPIO6;
328 	case PRCM_I2C0:
329 		return PRCM_CLK_EN_I2C1;
330 	case PRCM_I2C1:
331 		return PRCM_CLK_EN_I2C2;
332 	case PRCM_I2C2:
333 		return PRCM_CLK_EN_I2C3;
334 	default:
335 		panic("%s: module not found", __func__);
336 	}
337 }
338 
339 uint32_t
prcm_am335x_clkctrl(int mod)340 prcm_am335x_clkctrl(int mod)
341 {
342 	switch(mod) {
343 	case PRCM_TIMER2:
344 		return PRCM_AM335X_TIMER2_CLKCTRL;
345 	case PRCM_TIMER3:
346 		return PRCM_AM335X_TIMER3_CLKCTRL;
347 	case PRCM_MMC0:
348 		return PRCM_AM335X_MMC0_CLKCTRL;
349 	case PRCM_MMC1:
350 		return PRCM_AM335X_MMC1_CLKCTRL;
351 	case PRCM_MMC2:
352 		return PRCM_AM335X_MMC2_CLKCTRL;
353 	case PRCM_USB:
354 		return PRCM_AM335X_USB0_CLKCTRL;
355 	case PRCM_GPIO0:
356 		return PRCM_AM335X_GPIO0_CLKCTRL;
357 	case PRCM_GPIO1:
358 		return PRCM_AM335X_GPIO1_CLKCTRL;
359 	case PRCM_GPIO2:
360 		return PRCM_AM335X_GPIO2_CLKCTRL;
361 	case PRCM_GPIO3:
362 		return PRCM_AM335X_GPIO3_CLKCTRL;
363 	case PRCM_TPCC:
364 		return PRCM_AM335X_TPCC_CLKCTRL;
365 	case PRCM_TPTC0:
366 		return PRCM_AM335X_TPTC0_CLKCTRL;
367 	case PRCM_TPTC1:
368 		return PRCM_AM335X_TPTC1_CLKCTRL;
369 	case PRCM_TPTC2:
370 		return PRCM_AM335X_TPTC2_CLKCTRL;
371 	case PRCM_I2C0:
372 		return PRCM_AM335X_I2C0_CLKCTRL;
373 	case PRCM_I2C1:
374 		return PRCM_AM335X_I2C1_CLKCTRL;
375 	case PRCM_I2C2:
376 		return PRCM_AM335X_I2C2_CLKCTRL;
377 	case PRCM_LCDC:
378 		return PRCM_AM335X_LCDC_CLKCTRL;
379 	case PRCM_RNG:
380 		return PRCM_AM335X_RNG_CLKCTRL;
381 	default:
382 		panic("%s: module not found", __func__);
383 	}
384 }
385 
386 void
prcm_enablemodule(int mod)387 prcm_enablemodule(int mod)
388 {
389 	struct prcm_softc *sc = prcm_cd.cd_devs[0];
390 
391 	if (!sc->sc_enablemodule)
392 		panic("%s: not initialised!", __func__);
393 
394 	sc->sc_enablemodule(sc, mod);
395 }
396 
397 void
prcm_am335x_enablemodule(struct prcm_softc * sc,int mod)398 prcm_am335x_enablemodule(struct prcm_softc *sc, int mod)
399 {
400 	uint32_t clkctrl;
401 	int reg;
402 
403 	/*set enable bits in CLKCTRL register */
404 	reg = prcm_am335x_clkctrl(mod);
405 	clkctrl = bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg);
406 	clkctrl &=~AM335X_CLKCTRL_MODULEMODE_MASK;
407 	clkctrl |= AM335X_CLKCTRL_MODULEMODE_ENABLE;
408 	bus_space_write_4(sc->sc_iot, sc->sc_prcm, reg, clkctrl);
409 
410 	/* wait until module is enabled */
411 	while (bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg) & 0x30000)
412 		;
413 }
414 
415 void
prcm_v3_enablemodule(struct prcm_softc * sc,int mod)416 prcm_v3_enablemodule(struct prcm_softc *sc, int mod)
417 {
418 	uint32_t bit;
419 	uint32_t fclk, iclk, fmask, imask, mbit;
420 	int freg, ireg, reg;
421 
422 	bit = prcm_v3_bit(mod);
423 	reg = bit >> 5;
424 
425 	freg = prcm_fmask_addr[reg];
426 	ireg = prcm_imask_addr[reg];
427 	fmask = prcm_fmask_mask[reg];
428 	imask = prcm_imask_mask[reg];
429 
430 	mbit = 1 << (bit & 0x1f);
431 	if (fmask & mbit) { /* dont access the register if bit isn't present */
432 		fclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, freg);
433 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, freg, fclk | mbit);
434 	}
435 	if (imask & mbit) { /* dont access the register if bit isn't present */
436 		iclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, ireg);
437 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, ireg, iclk | mbit);
438 	}
439 	printf("\n");
440 }
441 
442 void
prcm_v4_enablemodule(struct prcm_softc * sc,int mod)443 prcm_v4_enablemodule(struct prcm_softc *sc, int mod)
444 {
445 	switch (mod) {
446 		case PRCM_MMC0:
447 		case PRCM_MMC1:
448 		case PRCM_MMC2:
449 		case PRCM_MMC3:
450 		case PRCM_MMC4:
451 			break;
452 		case PRCM_USBP1_PHY:
453 		case PRCM_USBP2_PHY:
454 			prcm_v4_hsusbhost_set_source(mod, 0);
455 		case PRCM_USB:
456 		case PRCM_USBTLL:
457 		case PRCM_USBP1_UTMI:
458 		case PRCM_USBP1_HSIC:
459 		case PRCM_USBP2_UTMI:
460 		case PRCM_USBP2_HSIC:
461 			prcm_v4_hsusbhost_activate(mod);
462 			return;
463 		case  PRCM_GPIO0:
464 		case  PRCM_GPIO1:
465 		case  PRCM_GPIO2:
466 		case  PRCM_GPIO3:
467 		case  PRCM_GPIO4:
468 		case  PRCM_GPIO5:
469 			/* XXX */
470 			break;
471 		case PRCM_I2C0:
472 		case PRCM_I2C1:
473 		case PRCM_I2C2:
474 		case PRCM_I2C3:
475 			/* XXX */
476 			break;
477 	default:
478 		panic("%s: module not found", __func__);
479 	}
480 }
481 
482 int
prcm_v4_hsusbhost_activate(int type)483 prcm_v4_hsusbhost_activate(int type)
484 {
485 	struct prcm_softc *sc = prcm_cd.cd_devs[0];
486 	uint32_t i;
487 	uint32_t clksel_reg_off;
488 	uint32_t clksel, oclksel;
489 
490 	switch (type) {
491 		case PRCM_USB:
492 		case PRCM_USBP1_PHY:
493 		case PRCM_USBP2_PHY:
494 			/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
495 			clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58;
496 			clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
497 			oclksel = clksel;
498 			/* Enable the module and also enable the optional func clocks */
499 			if (type == PRCM_USB) {
500 				clksel &= ~O4_CLKCTRL_MODULEMODE_MASK;
501 				clksel |=  /*O4_CLKCTRL_MODULEMODE_ENABLE*/2;
502 
503 				clksel |= (0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */
504 			}
505 
506 			break;
507 
508 		default:
509 			panic("%s: invalid type %d", __func__, type);
510 			return (EINVAL);
511 	}
512 	bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel);
513 
514 	/* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */
515 	for (i = 0; i < O4_MAX_MODULE_ENABLE_WAIT; i++) {
516 		clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
517 		if ((clksel & O4_CLKCTRL_IDLEST_MASK) == O4_CLKCTRL_IDLEST_ENABLED)
518 			break;
519 	}
520 
521 	/* Check the enabled state */
522 	if ((clksel & O4_CLKCTRL_IDLEST_MASK) != O4_CLKCTRL_IDLEST_ENABLED) {
523 		printf("Error: HERE failed to enable module with clock %d\n", type);
524 		printf("Error: 0x%08x => 0x%08x\n", clksel_reg_off, clksel);
525 		return (ETIMEDOUT);
526 	}
527 
528 	return (0);
529 }
530 
531 int
prcm_v4_hsusbhost_set_source(int clk,int clksrc)532 prcm_v4_hsusbhost_set_source(int clk, int clksrc)
533 {
534 	struct prcm_softc *sc = prcm_cd.cd_devs[0];
535 	uint32_t clksel_reg_off;
536 	uint32_t clksel;
537 	unsigned int bit;
538 
539 	if (clk == PRCM_USBP1_PHY)
540 		bit = 24;
541 	else if (clk != PRCM_USBP2_PHY)
542 		bit = 25;
543 	else
544 		return (-EINVAL);
545 
546 	/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
547 	clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58;
548 	clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
549 
550 	/* XXX: Set the clock source to either external or internal */
551 	if (clksrc == 0)
552 		clksel |= (0x1 << bit);
553 	else
554 		clksel &= ~(0x1 << bit);
555 
556 	bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel);
557 
558 	return (0);
559 }
560 
561 /*
562  * OMAP35xx Power, Reset, and Clock Management Reference Guide
563  * (sprufa5.pdf) and AM/DM37x Multimedia Device Technical Reference
564  * Manual (sprugn4h.pdf) note that DPLL5 provides a 120MHz clock for
565  * peripheral domain modules (page 107 and page 302).
566  * The reference clock for DPLL5 is DPLL5_ALWON_FCLK which is
567  * SYS_CLK, running at 13MHz.
568  */
569 int
prcm_setup_dpll5(struct prcm_softc * sc)570 prcm_setup_dpll5(struct prcm_softc *sc)
571 {
572 	uint32_t val;
573 
574 	/*
575 	 * We need to set the multiplier and divider values for PLL.
576 	 * To end up with 120MHz we take SYS_CLK, divide by it and multiply
577 	 * with 120 (sprugn4h.pdf, 13.4.11.4.1 SSC Configuration)
578 	 */
579 	val = ((120 & 0x7ff) << 8) | ((SYS_CLK - 1) & 0x7f);
580 	bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL4_PLL, val);
581 
582 	/* Clock divider from the PLL to the 120MHz clock. */
583 	bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL5_PLL, val);
584 
585 	/*
586 	 * spruf98o.pdf, page 2319:
587 	 * PERIPH2_DPLL_FREQSEL is 0x7 1.75MHz to 2.1MHz
588 	 * EN_PERIPH2_DPLL is 0x7
589 	 */
590 	val = (7 << 4) | (7 << 0);
591 	bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKEN2_PLL, val);
592 
593 	/* Disable the interconnect clock auto-idle. */
594 	bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_AUTOIDLE2_PLL, 0x0);
595 
596 	/* Wait until DPLL5 is locked and there's clock activity. */
597 	while ((val = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
598 	    CM_IDLEST_CKGEN) & 0x01) == 0x00) {
599 #ifdef DIAGNOSTIC
600 		printf("CM_IDLEST_PLL = 0x%08x\n", val);
601 #endif
602 	}
603 
604 	return 0;
605 }
606