xref: /openbsd/sys/arch/armv7/omap/prcm.c (revision 0f9e9ec2)
1*0f9e9ec2Sjsg /* $OpenBSD: prcm.c,v 1.19 2024/05/13 01:15:50 jsg Exp $ */
28eda2d14Spatrick /*
38eda2d14Spatrick  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
48eda2d14Spatrick  *
58eda2d14Spatrick  * Permission to use, copy, modify, and distribute this software for any
68eda2d14Spatrick  * purpose with or without fee is hereby granted, provided that the above
78eda2d14Spatrick  * copyright notice and this permission notice appear in all copies.
88eda2d14Spatrick  *
98eda2d14Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
108eda2d14Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
118eda2d14Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
128eda2d14Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
138eda2d14Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
148eda2d14Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
158eda2d14Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
168eda2d14Spatrick  */
178eda2d14Spatrick 
188eda2d14Spatrick /*-
198eda2d14Spatrick  * Copyright (c) 2011
208eda2d14Spatrick  *	Ben Gray <ben.r.gray@gmail.com>.
218eda2d14Spatrick  * All rights reserved.
228eda2d14Spatrick  *
238eda2d14Spatrick  * Redistribution and use in source and binary forms, with or without
248eda2d14Spatrick  * modification, are permitted provided that the following conditions
258eda2d14Spatrick  * are met:
268eda2d14Spatrick  * 1. Redistributions of source code must retain the above copyright
278eda2d14Spatrick  *    notice, this list of conditions and the following disclaimer.
288eda2d14Spatrick  * 2. Redistributions in binary form must reproduce the above copyright
298eda2d14Spatrick  *    notice, this list of conditions and the following disclaimer in the
308eda2d14Spatrick  *    documentation and/or other materials provided with the distribution.
318eda2d14Spatrick  * 3. The name of the company nor the name of the author may be used to
328eda2d14Spatrick  *    endorse or promote products derived from this software without specific
338eda2d14Spatrick  *    prior written permission.
348eda2d14Spatrick  *
358eda2d14Spatrick  * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR
368eda2d14Spatrick  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
378eda2d14Spatrick  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
388eda2d14Spatrick  * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
398eda2d14Spatrick  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
408eda2d14Spatrick  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
418eda2d14Spatrick  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
428eda2d14Spatrick  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
438eda2d14Spatrick  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
448eda2d14Spatrick  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
458eda2d14Spatrick  */
468eda2d14Spatrick 
478eda2d14Spatrick /*
488eda2d14Spatrick  * Driver for the Power, Reset and Clock Management Module (PRCM).
498eda2d14Spatrick  */
508eda2d14Spatrick 
518eda2d14Spatrick #include <sys/param.h>
528eda2d14Spatrick #include <sys/systm.h>
538eda2d14Spatrick #include <sys/device.h>
548eda2d14Spatrick 
558eda2d14Spatrick #include <machine/bus.h>
568d957e1aSsyl #include <armv7/armv7/armv7var.h>
578eda2d14Spatrick #include <armv7/omap/prcmvar.h>
588eda2d14Spatrick 
598eda2d14Spatrick #include <armv7/omap/am335x_prcmreg.h>
608eda2d14Spatrick #include <armv7/omap/omap3_prcmreg.h>
618eda2d14Spatrick #include <armv7/omap/omap4_prcmreg.h>
628eda2d14Spatrick 
63d5df157eSjsg #include <dev/ofw/fdt.h>
64d5df157eSjsg 
658eda2d14Spatrick #define PRCM_REVISION		0x0800
668eda2d14Spatrick #define PRCM_SYSCONFIG		0x0810
678eda2d14Spatrick 
688eda2d14Spatrick uint32_t prcm_imask_mask[PRCM_REG_MAX];
698eda2d14Spatrick uint32_t prcm_fmask_mask[PRCM_REG_MAX];
708eda2d14Spatrick uint32_t prcm_imask_addr[PRCM_REG_MAX];
718eda2d14Spatrick uint32_t prcm_fmask_addr[PRCM_REG_MAX];
728eda2d14Spatrick 
738eda2d14Spatrick #define SYS_CLK			13    /* SYS_CLK speed in MHz */
742252d02cSkettenis #define PRCM_AM335X_MASTER_OSC	24000 /* kHz */
752b401c1dSians 
768eda2d14Spatrick 
778eda2d14Spatrick struct prcm_softc {
788eda2d14Spatrick 	struct device		sc_dev;
798eda2d14Spatrick 	bus_space_tag_t		sc_iot;
808eda2d14Spatrick 	bus_space_handle_t	sc_prcm;
818eda2d14Spatrick 	bus_space_handle_t	sc_cm1;
828eda2d14Spatrick 	bus_space_handle_t	sc_cm2;
838eda2d14Spatrick 	void (*sc_setup)(struct prcm_softc *sc);
848eda2d14Spatrick 	void (*sc_enablemodule)(struct prcm_softc *sc, int mod);
858eda2d14Spatrick 	void (*sc_setclock)(struct prcm_softc *sc,
868eda2d14Spatrick 	    int clock, int speed);
878eda2d14Spatrick 	uint32_t		cm1_avail;
888eda2d14Spatrick 	uint32_t		cm2_avail;
898eda2d14Spatrick };
908eda2d14Spatrick 
918eda2d14Spatrick void	prcm_attach(struct device *, struct device *, void *);
928eda2d14Spatrick int	prcm_setup_dpll5(struct prcm_softc *);
938eda2d14Spatrick uint32_t prcm_v3_bit(int mod);
948eda2d14Spatrick uint32_t prcm_am335x_clkctrl(int mod);
958eda2d14Spatrick 
968eda2d14Spatrick void prcm_am335x_enablemodule(struct prcm_softc *, int);
978eda2d14Spatrick void prcm_am335x_setclock(struct prcm_softc *, int, int);
988eda2d14Spatrick 
998eda2d14Spatrick void prcm_v3_setup(struct prcm_softc *);
1008eda2d14Spatrick void prcm_v3_enablemodule(struct prcm_softc *, int);
1018eda2d14Spatrick void prcm_v3_setclock(struct prcm_softc *, int, int);
1028eda2d14Spatrick 
1038eda2d14Spatrick void prcm_v4_enablemodule(struct prcm_softc *, int);
1048eda2d14Spatrick int prcm_v4_hsusbhost_activate(int);
1058eda2d14Spatrick int prcm_v4_hsusbhost_set_source(int, int);
1068eda2d14Spatrick 
1079fdf0c62Smpi const struct cfattach	prcm_ca = {
1088eda2d14Spatrick 	sizeof (struct prcm_softc), NULL, prcm_attach
1098eda2d14Spatrick };
1108eda2d14Spatrick 
1118eda2d14Spatrick struct cfdriver prcm_cd = {
1128eda2d14Spatrick 	NULL, "prcm", DV_DULL
1138eda2d14Spatrick };
1148eda2d14Spatrick 
1158eda2d14Spatrick void
prcm_attach(struct device * parent,struct device * self,void * args)1168eda2d14Spatrick prcm_attach(struct device *parent, struct device *self, void *args)
1178eda2d14Spatrick {
1188d957e1aSsyl 	struct armv7_attach_args *aa = args;
1198eda2d14Spatrick 	struct prcm_softc *sc = (struct prcm_softc *) self;
1208eda2d14Spatrick 	u_int32_t reg;
121d5df157eSjsg 	void *node;
1228eda2d14Spatrick 
1238d957e1aSsyl 	sc->sc_iot = aa->aa_iot;
1248eda2d14Spatrick 
125d5df157eSjsg 	node = fdt_find_node("/");
126d5df157eSjsg 	if (node == NULL)
127d5df157eSjsg 		panic("%s: could not get fdt root node",
128d5df157eSjsg 		    sc->sc_dev.dv_xname);
129d5df157eSjsg 
130d5df157eSjsg 	if (fdt_is_compatible(node, "ti,am33xx")) {
1318eda2d14Spatrick 		sc->sc_setup = NULL;
1328eda2d14Spatrick 		sc->sc_enablemodule = prcm_am335x_enablemodule;
1338eda2d14Spatrick 		sc->sc_setclock = prcm_am335x_setclock;
134d5df157eSjsg 	} else if (fdt_is_compatible(node, "ti,omap3")) {
1358eda2d14Spatrick 		sc->sc_setup = prcm_v3_setup;
1368eda2d14Spatrick 		sc->sc_enablemodule = prcm_v3_enablemodule;
1378eda2d14Spatrick 		sc->sc_setclock = prcm_v3_setclock;
138d5df157eSjsg 	} else if (fdt_is_compatible(node, "ti,omap4")) {
1398eda2d14Spatrick 		sc->sc_setup = NULL;
1408eda2d14Spatrick 		sc->sc_enablemodule = prcm_v4_enablemodule;
1418eda2d14Spatrick 		sc->sc_setclock = NULL;
1428eda2d14Spatrick 		sc->cm1_avail = 1;
1438eda2d14Spatrick 		sc->cm2_avail = 1;
144d5df157eSjsg 	} else
145d5df157eSjsg 		panic("%s: could not find a compatible soc",
146d5df157eSjsg 		    sc->sc_dev.dv_xname);
1478eda2d14Spatrick 
1488d957e1aSsyl 	if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
1498d957e1aSsyl 	    aa->aa_dev->mem[0].size, 0, &sc->sc_prcm))
1508eda2d14Spatrick 		panic("prcm_attach: bus_space_map failed!");
1518eda2d14Spatrick 
1528eda2d14Spatrick 	if (sc->cm1_avail &&
1538d957e1aSsyl 	    bus_space_map(sc->sc_iot, aa->aa_dev->mem[1].addr,
1548d957e1aSsyl 	    aa->aa_dev->mem[1].size, 0, &sc->sc_cm1))
1558eda2d14Spatrick 		panic("prcm_attach: bus_space_map failed!");
1568eda2d14Spatrick 
1578eda2d14Spatrick 	if (sc->cm2_avail &&
1588d957e1aSsyl 	    bus_space_map(sc->sc_iot, aa->aa_dev->mem[2].addr,
1598d957e1aSsyl 	    aa->aa_dev->mem[2].size, 0, &sc->sc_cm2))
1608eda2d14Spatrick 		panic("prcm_attach: bus_space_map failed!");
1618eda2d14Spatrick 
1628eda2d14Spatrick 	reg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_REVISION);
1638eda2d14Spatrick 	printf(" rev %d.%d\n", reg >> 4 & 0xf, reg & 0xf);
1648eda2d14Spatrick 
165511fd411Sdlg 	if (sc->sc_setup != NULL)
1668eda2d14Spatrick 		sc->sc_setup(sc);
1678eda2d14Spatrick }
1688eda2d14Spatrick 
1698eda2d14Spatrick void
prcm_v3_setup(struct prcm_softc * sc)1708eda2d14Spatrick prcm_v3_setup(struct prcm_softc *sc)
1718eda2d14Spatrick {
1728eda2d14Spatrick 	/* Setup the 120MHZ DPLL5 clock, to be used by USB. */
1738eda2d14Spatrick 	prcm_setup_dpll5(sc);
1748eda2d14Spatrick 
1758eda2d14Spatrick 	prcm_fmask_mask[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_FMASK;
1768eda2d14Spatrick 	prcm_imask_mask[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_IMASK;
1778eda2d14Spatrick 	prcm_fmask_addr[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_FADDR;
1788eda2d14Spatrick 	prcm_imask_addr[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_IADDR;
1798eda2d14Spatrick 
1808eda2d14Spatrick 	prcm_fmask_mask[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_FMASK;
1818eda2d14Spatrick 	prcm_imask_mask[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_IMASK;
1828eda2d14Spatrick 	prcm_fmask_addr[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_FADDR;
1838eda2d14Spatrick 	prcm_imask_addr[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_IADDR;
1848eda2d14Spatrick 
1858eda2d14Spatrick 	prcm_fmask_mask[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_FMASK;
1868eda2d14Spatrick 	prcm_imask_mask[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_IMASK;
1878eda2d14Spatrick 	prcm_fmask_addr[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_FADDR;
1888eda2d14Spatrick 	prcm_imask_addr[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_IADDR;
1898eda2d14Spatrick 
1905193e4e0Srapha 	prcm_fmask_mask[PRCM_REG_WKUP] = PRCM_REG_WKUP_FMASK;
1915193e4e0Srapha 	prcm_imask_mask[PRCM_REG_WKUP] = PRCM_REG_WKUP_IMASK;
1925193e4e0Srapha 	prcm_fmask_addr[PRCM_REG_WKUP] = PRCM_REG_WKUP_FADDR;
1935193e4e0Srapha 	prcm_imask_addr[PRCM_REG_WKUP] = PRCM_REG_WKUP_IADDR;
1945193e4e0Srapha 
1955193e4e0Srapha 	prcm_fmask_mask[PRCM_REG_PER] = PRCM_REG_PER_FMASK;
1965193e4e0Srapha 	prcm_imask_mask[PRCM_REG_PER] = PRCM_REG_PER_IMASK;
1975193e4e0Srapha 	prcm_fmask_addr[PRCM_REG_PER] = PRCM_REG_PER_FADDR;
1985193e4e0Srapha 	prcm_imask_addr[PRCM_REG_PER] = PRCM_REG_PER_IADDR;
1995193e4e0Srapha 
2008eda2d14Spatrick 	prcm_fmask_mask[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_FMASK;
2018eda2d14Spatrick 	prcm_imask_mask[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_IMASK;
2028eda2d14Spatrick 	prcm_fmask_addr[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_FADDR;
2038eda2d14Spatrick 	prcm_imask_addr[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_IADDR;
2048eda2d14Spatrick }
2058eda2d14Spatrick 
2068eda2d14Spatrick void
prcm_setclock(int clock,int speed)2078eda2d14Spatrick prcm_setclock(int clock, int speed)
2088eda2d14Spatrick {
2098eda2d14Spatrick 	struct prcm_softc *sc = prcm_cd.cd_devs[0];
2108eda2d14Spatrick 
2118eda2d14Spatrick 	if (!sc->sc_setclock)
2128eda2d14Spatrick 		panic("%s: not initialised!", __func__);
2138eda2d14Spatrick 
2148eda2d14Spatrick 	sc->sc_setclock(sc, clock, speed);
2158eda2d14Spatrick }
2168eda2d14Spatrick 
2178eda2d14Spatrick void
prcm_am335x_setclock(struct prcm_softc * sc,int clock,int speed)2188eda2d14Spatrick prcm_am335x_setclock(struct prcm_softc *sc, int clock, int speed)
2198eda2d14Spatrick {
2208eda2d14Spatrick 	u_int32_t oreg, reg, mask;
2218eda2d14Spatrick 
2228eda2d14Spatrick 	/* set CLKSEL register */
2238eda2d14Spatrick 	if (clock == 1) {
2248eda2d14Spatrick 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
2258eda2d14Spatrick 		    PRCM_AM335X_CLKSEL_TIMER2_CLK);
2268eda2d14Spatrick 		mask = 3;
2278eda2d14Spatrick 		reg = oreg & ~mask;
2288eda2d14Spatrick 		reg |=0x02;
2298eda2d14Spatrick 		bus_space_write_4(sc->sc_iot, sc->sc_prcm,
2308eda2d14Spatrick 		    PRCM_AM335X_CLKSEL_TIMER2_CLK, reg);
2318eda2d14Spatrick 	} else if (clock == 2) {
2328eda2d14Spatrick 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
2338eda2d14Spatrick 		    PRCM_AM335X_CLKSEL_TIMER3_CLK);
2348eda2d14Spatrick 		mask = 3;
2358eda2d14Spatrick 		reg = oreg & ~mask;
2368eda2d14Spatrick 		reg |=0x02;
2378eda2d14Spatrick 		bus_space_write_4(sc->sc_iot, sc->sc_prcm,
2388eda2d14Spatrick 		    PRCM_AM335X_CLKSEL_TIMER3_CLK, reg);
2392b401c1dSians 	} else if (clock == 3) { /* DISP M1 */
2402b401c1dSians 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
2412b401c1dSians 		oreg &= ~0x7;
2422b401c1dSians 		oreg |= 0x4;
2432b401c1dSians 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
2442b401c1dSians 		while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
2452b401c1dSians 		    & 0x10)));
2462b401c1dSians 
2472b401c1dSians 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL);
2482b401c1dSians 		oreg &= 0xFFF800FF;
2492b401c1dSians 		oreg |= (speed & 0x7FF) << 8;
2502b401c1dSians 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL, oreg);
2512b401c1dSians 
2522b401c1dSians 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
2532b401c1dSians 		oreg |= 0x7;
2542b401c1dSians 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
2552b401c1dSians 		while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
2562b401c1dSians 		    & 0x10)));
2572b401c1dSians 	} else if (clock == 4) { /* DISP N */
2582b401c1dSians 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
2592b401c1dSians 		oreg &= ~0x7;
2602b401c1dSians 		oreg |= 0x4;
2612b401c1dSians 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
2622b401c1dSians 		while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
2632b401c1dSians 		    & 0x10)));
2642b401c1dSians 
2652b401c1dSians 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL);
2662b401c1dSians 		oreg &= 0xFFFFFF80;
2672b401c1dSians 		oreg |= speed & 0x7F;
2682b401c1dSians 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKSEL, oreg);
2692b401c1dSians 
2702b401c1dSians 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE);
2712b401c1dSians 		oreg |= 0x7;
2722b401c1dSians 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_CLKMODE, oreg);
2732b401c1dSians 		while(!(bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_IDLEST
2742b401c1dSians 		    & 0x10)));
2752b401c1dSians 	} else if (clock == 5) { /* DISP M2 */
2762b401c1dSians 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_M2);
2772b401c1dSians 		oreg &= ~(0x1F);
2782b401c1dSians 		oreg |= speed & 0x1F;
2792b401c1dSians 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_DISP_M2, oreg);
2808eda2d14Spatrick 	}
2818eda2d14Spatrick }
2828eda2d14Spatrick 
2838eda2d14Spatrick void
prcm_v3_setclock(struct prcm_softc * sc,int clock,int speed)2848eda2d14Spatrick prcm_v3_setclock(struct prcm_softc *sc, int clock, int speed)
2858eda2d14Spatrick {
2868eda2d14Spatrick 	u_int32_t oreg, reg, mask;
2878eda2d14Spatrick 
2888eda2d14Spatrick 	if (clock == 1) {
2898eda2d14Spatrick 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP);
2908eda2d14Spatrick 		mask = 1;
2918eda2d14Spatrick 		reg = (oreg &~mask) | (speed & mask);
2928eda2d14Spatrick 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP, reg);
2938eda2d14Spatrick 	} else if (clock >= 2 && clock <= 9) {
2948eda2d14Spatrick 		int shift =  (clock-2);
2958eda2d14Spatrick 		oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER);
2968eda2d14Spatrick 		mask = 1 << (shift);
2978eda2d14Spatrick 		reg =  (oreg & ~mask) | ( (speed << shift) & mask);
2988eda2d14Spatrick 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER, reg);
2998eda2d14Spatrick 	} else
3008eda2d14Spatrick 		panic("%s: invalid clock %d", __func__, clock);
3018eda2d14Spatrick }
3028eda2d14Spatrick 
3038eda2d14Spatrick uint32_t
prcm_v3_bit(int mod)3048eda2d14Spatrick prcm_v3_bit(int mod)
3058eda2d14Spatrick {
3068eda2d14Spatrick 	switch(mod) {
3074d9eaee2Ssyl 	case PRCM_MMC0:
3088eda2d14Spatrick 		return PRCM_CLK_EN_MMC1;
3094d9eaee2Ssyl 	case PRCM_MMC1:
3104d9eaee2Ssyl 		return PRCM_CLK_EN_MMC2;
3114d9eaee2Ssyl 	case PRCM_MMC2:
3124d9eaee2Ssyl 		return PRCM_CLK_EN_MMC3;
3138eda2d14Spatrick 	case PRCM_USB:
3148eda2d14Spatrick 		return PRCM_CLK_EN_USB;
3155193e4e0Srapha 	case PRCM_GPIO0:
3165193e4e0Srapha 		return PRCM_CLK_EN_GPIO1;
3175193e4e0Srapha 	case PRCM_GPIO1:
3185193e4e0Srapha 		return PRCM_CLK_EN_GPIO2;
3195193e4e0Srapha 	case PRCM_GPIO2:
3205193e4e0Srapha 		return PRCM_CLK_EN_GPIO3;
3215193e4e0Srapha 	case PRCM_GPIO3:
3225193e4e0Srapha 		return PRCM_CLK_EN_GPIO4;
3235193e4e0Srapha 	case PRCM_GPIO4:
3245193e4e0Srapha 		return PRCM_CLK_EN_GPIO5;
3255193e4e0Srapha 	case PRCM_GPIO5:
3265193e4e0Srapha 		return PRCM_CLK_EN_GPIO6;
327a7c7ce51Sjsg 	case PRCM_I2C0:
328a7c7ce51Sjsg 		return PRCM_CLK_EN_I2C1;
329a7c7ce51Sjsg 	case PRCM_I2C1:
330a7c7ce51Sjsg 		return PRCM_CLK_EN_I2C2;
331a7c7ce51Sjsg 	case PRCM_I2C2:
332a7c7ce51Sjsg 		return PRCM_CLK_EN_I2C3;
3338eda2d14Spatrick 	default:
3344123b6a7Sderaadt 		panic("%s: module not found", __func__);
3358eda2d14Spatrick 	}
3368eda2d14Spatrick }
3378eda2d14Spatrick 
3388eda2d14Spatrick uint32_t
prcm_am335x_clkctrl(int mod)3398eda2d14Spatrick prcm_am335x_clkctrl(int mod)
3408eda2d14Spatrick {
3418eda2d14Spatrick 	switch(mod) {
3428eda2d14Spatrick 	case PRCM_TIMER2:
3438eda2d14Spatrick 		return PRCM_AM335X_TIMER2_CLKCTRL;
3448eda2d14Spatrick 	case PRCM_TIMER3:
3458eda2d14Spatrick 		return PRCM_AM335X_TIMER3_CLKCTRL;
3464d9eaee2Ssyl 	case PRCM_MMC0:
3478eda2d14Spatrick 		return PRCM_AM335X_MMC0_CLKCTRL;
3484d9eaee2Ssyl 	case PRCM_MMC1:
3494d9eaee2Ssyl 		return PRCM_AM335X_MMC1_CLKCTRL;
3504d9eaee2Ssyl 	case PRCM_MMC2:
3514d9eaee2Ssyl 		return PRCM_AM335X_MMC2_CLKCTRL;
3528eda2d14Spatrick 	case PRCM_USB:
3538eda2d14Spatrick 		return PRCM_AM335X_USB0_CLKCTRL;
3545193e4e0Srapha 	case PRCM_GPIO0:
3555193e4e0Srapha 		return PRCM_AM335X_GPIO0_CLKCTRL;
3565193e4e0Srapha 	case PRCM_GPIO1:
3575193e4e0Srapha 		return PRCM_AM335X_GPIO1_CLKCTRL;
3585193e4e0Srapha 	case PRCM_GPIO2:
3595193e4e0Srapha 		return PRCM_AM335X_GPIO2_CLKCTRL;
3605193e4e0Srapha 	case PRCM_GPIO3:
3615193e4e0Srapha 		return PRCM_AM335X_GPIO3_CLKCTRL;
362e02a18b3Ssyl 	case PRCM_TPCC:
363e02a18b3Ssyl 		return PRCM_AM335X_TPCC_CLKCTRL;
364e02a18b3Ssyl 	case PRCM_TPTC0:
365e02a18b3Ssyl 		return PRCM_AM335X_TPTC0_CLKCTRL;
366e02a18b3Ssyl 	case PRCM_TPTC1:
367e02a18b3Ssyl 		return PRCM_AM335X_TPTC1_CLKCTRL;
368e02a18b3Ssyl 	case PRCM_TPTC2:
369e02a18b3Ssyl 		return PRCM_AM335X_TPTC2_CLKCTRL;
3706b4d768cSsyl 	case PRCM_I2C0:
3716b4d768cSsyl 		return PRCM_AM335X_I2C0_CLKCTRL;
3726b4d768cSsyl 	case PRCM_I2C1:
3736b4d768cSsyl 		return PRCM_AM335X_I2C1_CLKCTRL;
3746b4d768cSsyl 	case PRCM_I2C2:
3756b4d768cSsyl 		return PRCM_AM335X_I2C2_CLKCTRL;
3762b401c1dSians 	case PRCM_LCDC:
3772b401c1dSians 		return PRCM_AM335X_LCDC_CLKCTRL;
37859b39244Skettenis 	case PRCM_RNG:
37959b39244Skettenis 		return PRCM_AM335X_RNG_CLKCTRL;
3808eda2d14Spatrick 	default:
3814123b6a7Sderaadt 		panic("%s: module not found", __func__);
3828eda2d14Spatrick 	}
3838eda2d14Spatrick }
3848eda2d14Spatrick 
3858eda2d14Spatrick void
prcm_enablemodule(int mod)3868eda2d14Spatrick prcm_enablemodule(int mod)
3878eda2d14Spatrick {
3888eda2d14Spatrick 	struct prcm_softc *sc = prcm_cd.cd_devs[0];
3898eda2d14Spatrick 
3908eda2d14Spatrick 	if (!sc->sc_enablemodule)
3918eda2d14Spatrick 		panic("%s: not initialised!", __func__);
3928eda2d14Spatrick 
3938eda2d14Spatrick 	sc->sc_enablemodule(sc, mod);
3948eda2d14Spatrick }
3958eda2d14Spatrick 
3968eda2d14Spatrick void
prcm_am335x_enablemodule(struct prcm_softc * sc,int mod)3978eda2d14Spatrick prcm_am335x_enablemodule(struct prcm_softc *sc, int mod)
3988eda2d14Spatrick {
3998eda2d14Spatrick 	uint32_t clkctrl;
4008eda2d14Spatrick 	int reg;
4018eda2d14Spatrick 
4028eda2d14Spatrick 	/*set enable bits in CLKCTRL register */
4038eda2d14Spatrick 	reg = prcm_am335x_clkctrl(mod);
4048eda2d14Spatrick 	clkctrl = bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg);
4058eda2d14Spatrick 	clkctrl &=~AM335X_CLKCTRL_MODULEMODE_MASK;
4068eda2d14Spatrick 	clkctrl |= AM335X_CLKCTRL_MODULEMODE_ENABLE;
4078eda2d14Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_prcm, reg, clkctrl);
4088eda2d14Spatrick 
4098eda2d14Spatrick 	/* wait until module is enabled */
4108eda2d14Spatrick 	while (bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg) & 0x30000)
4118eda2d14Spatrick 		;
4128eda2d14Spatrick }
4138eda2d14Spatrick 
4148eda2d14Spatrick void
prcm_v3_enablemodule(struct prcm_softc * sc,int mod)4158eda2d14Spatrick prcm_v3_enablemodule(struct prcm_softc *sc, int mod)
4168eda2d14Spatrick {
4178eda2d14Spatrick 	uint32_t bit;
4188eda2d14Spatrick 	uint32_t fclk, iclk, fmask, imask, mbit;
4198eda2d14Spatrick 	int freg, ireg, reg;
4208eda2d14Spatrick 
4218eda2d14Spatrick 	bit = prcm_v3_bit(mod);
4228eda2d14Spatrick 	reg = bit >> 5;
4238eda2d14Spatrick 
4248eda2d14Spatrick 	freg = prcm_fmask_addr[reg];
4258eda2d14Spatrick 	ireg = prcm_imask_addr[reg];
4268eda2d14Spatrick 	fmask = prcm_fmask_mask[reg];
4278eda2d14Spatrick 	imask = prcm_imask_mask[reg];
4288eda2d14Spatrick 
4298eda2d14Spatrick 	mbit = 1 << (bit & 0x1f);
4308eda2d14Spatrick 	if (fmask & mbit) { /* dont access the register if bit isn't present */
4318eda2d14Spatrick 		fclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, freg);
4328eda2d14Spatrick 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, freg, fclk | mbit);
4338eda2d14Spatrick 	}
4348eda2d14Spatrick 	if (imask & mbit) { /* dont access the register if bit isn't present */
4358eda2d14Spatrick 		iclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, ireg);
4368eda2d14Spatrick 		bus_space_write_4(sc->sc_iot, sc->sc_prcm, ireg, iclk | mbit);
4378eda2d14Spatrick 	}
4388eda2d14Spatrick 	printf("\n");
4398eda2d14Spatrick }
4408eda2d14Spatrick 
4418eda2d14Spatrick void
prcm_v4_enablemodule(struct prcm_softc * sc,int mod)4428eda2d14Spatrick prcm_v4_enablemodule(struct prcm_softc *sc, int mod)
4438eda2d14Spatrick {
4448eda2d14Spatrick 	switch (mod) {
445ef92a366Ssyl 		case PRCM_MMC0:
446a7c7ce51Sjsg 		case PRCM_MMC1:
447a7c7ce51Sjsg 		case PRCM_MMC2:
448a7c7ce51Sjsg 		case PRCM_MMC3:
449a7c7ce51Sjsg 		case PRCM_MMC4:
450ef92a366Ssyl 			break;
4518eda2d14Spatrick 		case PRCM_USBP1_PHY:
4528eda2d14Spatrick 		case PRCM_USBP2_PHY:
4538eda2d14Spatrick 			prcm_v4_hsusbhost_set_source(mod, 0);
4548eda2d14Spatrick 		case PRCM_USB:
4558eda2d14Spatrick 		case PRCM_USBTLL:
4568eda2d14Spatrick 		case PRCM_USBP1_UTMI:
4578eda2d14Spatrick 		case PRCM_USBP1_HSIC:
4588eda2d14Spatrick 		case PRCM_USBP2_UTMI:
4598eda2d14Spatrick 		case PRCM_USBP2_HSIC:
4608eda2d14Spatrick 			prcm_v4_hsusbhost_activate(mod);
4618eda2d14Spatrick 			return;
4625193e4e0Srapha 		case  PRCM_GPIO0:
4635193e4e0Srapha 		case  PRCM_GPIO1:
4645193e4e0Srapha 		case  PRCM_GPIO2:
4655193e4e0Srapha 		case  PRCM_GPIO3:
4665193e4e0Srapha 		case  PRCM_GPIO4:
4675193e4e0Srapha 		case  PRCM_GPIO5:
4685193e4e0Srapha 			/* XXX */
4695193e4e0Srapha 			break;
470a7c7ce51Sjsg 		case PRCM_I2C0:
471a7c7ce51Sjsg 		case PRCM_I2C1:
472a7c7ce51Sjsg 		case PRCM_I2C2:
473a7c7ce51Sjsg 		case PRCM_I2C3:
474a7c7ce51Sjsg 			/* XXX */
475a7c7ce51Sjsg 			break;
4768eda2d14Spatrick 	default:
4774123b6a7Sderaadt 		panic("%s: module not found", __func__);
4788eda2d14Spatrick 	}
4798eda2d14Spatrick }
4808eda2d14Spatrick 
4818eda2d14Spatrick int
prcm_v4_hsusbhost_activate(int type)4828eda2d14Spatrick prcm_v4_hsusbhost_activate(int type)
4838eda2d14Spatrick {
4848eda2d14Spatrick 	struct prcm_softc *sc = prcm_cd.cd_devs[0];
4858eda2d14Spatrick 	uint32_t i;
4868eda2d14Spatrick 	uint32_t clksel_reg_off;
4878eda2d14Spatrick 	uint32_t clksel, oclksel;
4888eda2d14Spatrick 
4898eda2d14Spatrick 	switch (type) {
4908eda2d14Spatrick 		case PRCM_USB:
4918eda2d14Spatrick 		case PRCM_USBP1_PHY:
4928eda2d14Spatrick 		case PRCM_USBP2_PHY:
4938eda2d14Spatrick 			/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
4948eda2d14Spatrick 			clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58;
4958eda2d14Spatrick 			clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
4968eda2d14Spatrick 			oclksel = clksel;
4978eda2d14Spatrick 			/* Enable the module and also enable the optional func clocks */
4988eda2d14Spatrick 			if (type == PRCM_USB) {
4998eda2d14Spatrick 				clksel &= ~O4_CLKCTRL_MODULEMODE_MASK;
5008eda2d14Spatrick 				clksel |=  /*O4_CLKCTRL_MODULEMODE_ENABLE*/2;
5018eda2d14Spatrick 
5028eda2d14Spatrick 				clksel |= (0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */
5038eda2d14Spatrick 			}
5048eda2d14Spatrick 
5058eda2d14Spatrick 			break;
5068eda2d14Spatrick 
5078eda2d14Spatrick 		default:
508ddb53a58Smiod 			panic("%s: invalid type %d", __func__, type);
5098eda2d14Spatrick 			return (EINVAL);
5108eda2d14Spatrick 	}
5118eda2d14Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel);
5128eda2d14Spatrick 
5138eda2d14Spatrick 	/* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */
5148eda2d14Spatrick 	for (i = 0; i < O4_MAX_MODULE_ENABLE_WAIT; i++) {
5158eda2d14Spatrick 		clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
5168eda2d14Spatrick 		if ((clksel & O4_CLKCTRL_IDLEST_MASK) == O4_CLKCTRL_IDLEST_ENABLED)
5178eda2d14Spatrick 			break;
5188eda2d14Spatrick 	}
5198eda2d14Spatrick 
5208eda2d14Spatrick 	/* Check the enabled state */
5218eda2d14Spatrick 	if ((clksel & O4_CLKCTRL_IDLEST_MASK) != O4_CLKCTRL_IDLEST_ENABLED) {
5228eda2d14Spatrick 		printf("Error: HERE failed to enable module with clock %d\n", type);
5238eda2d14Spatrick 		printf("Error: 0x%08x => 0x%08x\n", clksel_reg_off, clksel);
5248eda2d14Spatrick 		return (ETIMEDOUT);
5258eda2d14Spatrick 	}
5268eda2d14Spatrick 
5278eda2d14Spatrick 	return (0);
5288eda2d14Spatrick }
5298eda2d14Spatrick 
5308eda2d14Spatrick int
prcm_v4_hsusbhost_set_source(int clk,int clksrc)5318eda2d14Spatrick prcm_v4_hsusbhost_set_source(int clk, int clksrc)
5328eda2d14Spatrick {
5338eda2d14Spatrick 	struct prcm_softc *sc = prcm_cd.cd_devs[0];
5348eda2d14Spatrick 	uint32_t clksel_reg_off;
5358eda2d14Spatrick 	uint32_t clksel;
5368eda2d14Spatrick 	unsigned int bit;
5378eda2d14Spatrick 
5388eda2d14Spatrick 	if (clk == PRCM_USBP1_PHY)
5398eda2d14Spatrick 		bit = 24;
5408eda2d14Spatrick 	else if (clk != PRCM_USBP2_PHY)
5418eda2d14Spatrick 		bit = 25;
5428eda2d14Spatrick 	else
5438eda2d14Spatrick 		return (-EINVAL);
5448eda2d14Spatrick 
5458eda2d14Spatrick 	/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
5468eda2d14Spatrick 	clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58;
5478eda2d14Spatrick 	clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off);
5488eda2d14Spatrick 
5498eda2d14Spatrick 	/* XXX: Set the clock source to either external or internal */
5508eda2d14Spatrick 	if (clksrc == 0)
5518eda2d14Spatrick 		clksel |= (0x1 << bit);
5528eda2d14Spatrick 	else
5538eda2d14Spatrick 		clksel &= ~(0x1 << bit);
5548eda2d14Spatrick 
5558eda2d14Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel);
5568eda2d14Spatrick 
5578eda2d14Spatrick 	return (0);
5588eda2d14Spatrick }
5598eda2d14Spatrick 
5608eda2d14Spatrick /*
5618eda2d14Spatrick  * OMAP35xx Power, Reset, and Clock Management Reference Guide
5628eda2d14Spatrick  * (sprufa5.pdf) and AM/DM37x Multimedia Device Technical Reference
5638eda2d14Spatrick  * Manual (sprugn4h.pdf) note that DPLL5 provides a 120MHz clock for
5648eda2d14Spatrick  * peripheral domain modules (page 107 and page 302).
5658eda2d14Spatrick  * The reference clock for DPLL5 is DPLL5_ALWON_FCLK which is
5668eda2d14Spatrick  * SYS_CLK, running at 13MHz.
5678eda2d14Spatrick  */
5688eda2d14Spatrick int
prcm_setup_dpll5(struct prcm_softc * sc)5698eda2d14Spatrick prcm_setup_dpll5(struct prcm_softc *sc)
5708eda2d14Spatrick {
5718eda2d14Spatrick 	uint32_t val;
5728eda2d14Spatrick 
5738eda2d14Spatrick 	/*
5748eda2d14Spatrick 	 * We need to set the multiplier and divider values for PLL.
5758eda2d14Spatrick 	 * To end up with 120MHz we take SYS_CLK, divide by it and multiply
5768eda2d14Spatrick 	 * with 120 (sprugn4h.pdf, 13.4.11.4.1 SSC Configuration)
5778eda2d14Spatrick 	 */
5788eda2d14Spatrick 	val = ((120 & 0x7ff) << 8) | ((SYS_CLK - 1) & 0x7f);
5798eda2d14Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL4_PLL, val);
5808eda2d14Spatrick 
5818eda2d14Spatrick 	/* Clock divider from the PLL to the 120MHz clock. */
5828eda2d14Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL5_PLL, val);
5838eda2d14Spatrick 
5848eda2d14Spatrick 	/*
5858eda2d14Spatrick 	 * spruf98o.pdf, page 2319:
5868eda2d14Spatrick 	 * PERIPH2_DPLL_FREQSEL is 0x7 1.75MHz to 2.1MHz
5878eda2d14Spatrick 	 * EN_PERIPH2_DPLL is 0x7
5888eda2d14Spatrick 	 */
5898eda2d14Spatrick 	val = (7 << 4) | (7 << 0);
5908eda2d14Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKEN2_PLL, val);
5918eda2d14Spatrick 
5928eda2d14Spatrick 	/* Disable the interconnect clock auto-idle. */
5938eda2d14Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_AUTOIDLE2_PLL, 0x0);
5948eda2d14Spatrick 
5958eda2d14Spatrick 	/* Wait until DPLL5 is locked and there's clock activity. */
5968eda2d14Spatrick 	while ((val = bus_space_read_4(sc->sc_iot, sc->sc_prcm,
5978eda2d14Spatrick 	    CM_IDLEST_CKGEN) & 0x01) == 0x00) {
5988eda2d14Spatrick #ifdef DIAGNOSTIC
5998eda2d14Spatrick 		printf("CM_IDLEST_PLL = 0x%08x\n", val);
6008eda2d14Spatrick #endif
6018eda2d14Spatrick 	}
6028eda2d14Spatrick 
6038eda2d14Spatrick 	return 0;
6048eda2d14Spatrick }
605