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