xref: /freebsd/sys/arm/freescale/imx/imx6_ccm.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
19808ebfaSIan Lepore /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3af3dc4a7SPedro F. Giffuni  *
49808ebfaSIan Lepore  * Copyright (c) 2013 Ian Lepore <ian@freebsd.org>
59808ebfaSIan Lepore  * All rights reserved.
69808ebfaSIan Lepore  *
79808ebfaSIan Lepore  * Redistribution and use in source and binary forms, with or without
89808ebfaSIan Lepore  * modification, are permitted provided that the following conditions
99808ebfaSIan Lepore  * are met:
109808ebfaSIan Lepore  * 1. Redistributions of source code must retain the above copyright
119808ebfaSIan Lepore  *    notice, this list of conditions and the following disclaimer.
129808ebfaSIan Lepore  * 2. Redistributions in binary form must reproduce the above copyright
139808ebfaSIan Lepore  *    notice, this list of conditions and the following disclaimer in the
149808ebfaSIan Lepore  *    documentation and/or other materials provided with the distribution.
159808ebfaSIan Lepore  *
169808ebfaSIan Lepore  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
179808ebfaSIan Lepore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
189808ebfaSIan Lepore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199808ebfaSIan Lepore  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
209808ebfaSIan Lepore  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
219808ebfaSIan Lepore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
229808ebfaSIan Lepore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
239808ebfaSIan Lepore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
249808ebfaSIan Lepore  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
259808ebfaSIan Lepore  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
269808ebfaSIan Lepore  * SUCH DAMAGE.
279808ebfaSIan Lepore  */
289808ebfaSIan Lepore 
299808ebfaSIan Lepore #include <sys/cdefs.h>
309808ebfaSIan Lepore /*
319808ebfaSIan Lepore  * Clocks and power control driver for Freescale i.MX6 family of SoCs.
329808ebfaSIan Lepore  */
339808ebfaSIan Lepore 
349808ebfaSIan Lepore #include <sys/param.h>
359808ebfaSIan Lepore #include <sys/systm.h>
369808ebfaSIan Lepore #include <sys/kernel.h>
379808ebfaSIan Lepore #include <sys/module.h>
389808ebfaSIan Lepore #include <sys/bus.h>
399808ebfaSIan Lepore #include <sys/rman.h>
409808ebfaSIan Lepore 
419808ebfaSIan Lepore #include <dev/ofw/ofw_bus.h>
429808ebfaSIan Lepore #include <dev/ofw/ofw_bus_subr.h>
439808ebfaSIan Lepore 
449808ebfaSIan Lepore #include <machine/bus.h>
459808ebfaSIan Lepore 
469808ebfaSIan Lepore #include <arm/freescale/imx/imx6_anatopreg.h>
479808ebfaSIan Lepore #include <arm/freescale/imx/imx6_anatopvar.h>
489808ebfaSIan Lepore #include <arm/freescale/imx/imx6_ccmreg.h>
49a7fa939bSIan Lepore #include <arm/freescale/imx/imx_machdep.h>
50a7fa939bSIan Lepore #include <arm/freescale/imx/imx_ccmvar.h>
519808ebfaSIan Lepore 
52a7fa939bSIan Lepore #ifndef CCGR_CLK_MODE_ALWAYS
53a7fa939bSIan Lepore #define	CCGR_CLK_MODE_OFF		0
54a7fa939bSIan Lepore #define	CCGR_CLK_MODE_RUNMODE		1
55a7fa939bSIan Lepore #define	CCGR_CLK_MODE_ALWAYS		3
56a7fa939bSIan Lepore #endif
579808ebfaSIan Lepore 
589808ebfaSIan Lepore struct ccm_softc {
599808ebfaSIan Lepore 	device_t	dev;
609808ebfaSIan Lepore 	struct resource	*mem_res;
619808ebfaSIan Lepore };
629808ebfaSIan Lepore 
639808ebfaSIan Lepore static struct ccm_softc *ccm_sc;
649808ebfaSIan Lepore 
659808ebfaSIan Lepore static inline uint32_t
RD4(struct ccm_softc * sc,bus_size_t off)669808ebfaSIan Lepore RD4(struct ccm_softc *sc, bus_size_t off)
679808ebfaSIan Lepore {
689808ebfaSIan Lepore 
699808ebfaSIan Lepore 	return (bus_read_4(sc->mem_res, off));
709808ebfaSIan Lepore }
719808ebfaSIan Lepore 
729808ebfaSIan Lepore static inline void
WR4(struct ccm_softc * sc,bus_size_t off,uint32_t val)739808ebfaSIan Lepore WR4(struct ccm_softc *sc, bus_size_t off, uint32_t val)
749808ebfaSIan Lepore {
759808ebfaSIan Lepore 
769808ebfaSIan Lepore 	bus_write_4(sc->mem_res, off, val);
779808ebfaSIan Lepore }
789808ebfaSIan Lepore 
792586993bSIan Lepore /*
802586993bSIan Lepore  * Until we have a fully functional ccm driver which implements the fdt_clock
812586993bSIan Lepore  * interface, use the age-old workaround of unconditionally enabling the clocks
822586993bSIan Lepore  * for devices we might need to use.  The SoC defaults to most clocks enabled,
832586993bSIan Lepore  * but the rom boot code and u-boot disable a few of them.  We turn on only
842586993bSIan Lepore  * what's needed to run the chip plus devices we have drivers for, and turn off
852586993bSIan Lepore  * devices we don't yet have drivers for.  (Note that USB is not turned on here
862586993bSIan Lepore  * because that is one we do when the driver asks for it.)
872586993bSIan Lepore  */
882586993bSIan Lepore static void
ccm_init_gates(struct ccm_softc * sc)892586993bSIan Lepore ccm_init_gates(struct ccm_softc *sc)
902586993bSIan Lepore {
91183413c8SOleksandr Tymoshenko 	uint32_t reg;
92183413c8SOleksandr Tymoshenko 
93db4fcadfSConrad Meyer  	/* ahpbdma, aipstz 1 & 2 buses */
94183413c8SOleksandr Tymoshenko 	reg = CCGR0_AIPS_TZ1 | CCGR0_AIPS_TZ2 | CCGR0_ABPHDMA;
95183413c8SOleksandr Tymoshenko 	WR4(sc, CCM_CCGR0, reg);
96183413c8SOleksandr Tymoshenko 
97a0fd2339SIan Lepore 	/* enet, epit, gpt, spi */
98a0fd2339SIan Lepore 	reg = CCGR1_ENET | CCGR1_EPIT1 | CCGR1_GPT | CCGR1_ECSPI1 |
99a0fd2339SIan Lepore 	    CCGR1_ECSPI2 | CCGR1_ECSPI3 | CCGR1_ECSPI4 | CCGR1_ECSPI5;
100183413c8SOleksandr Tymoshenko 	WR4(sc, CCM_CCGR1, reg);
101183413c8SOleksandr Tymoshenko 
102183413c8SOleksandr Tymoshenko 	/* ipmux & ipsync (bridges), iomux, i2c */
103183413c8SOleksandr Tymoshenko 	reg = CCGR2_I2C1 | CCGR2_I2C2 | CCGR2_I2C3 | CCGR2_IIM |
104183413c8SOleksandr Tymoshenko 	    CCGR2_IOMUX_IPT | CCGR2_IPMUX1 | CCGR2_IPMUX2 | CCGR2_IPMUX3 |
105183413c8SOleksandr Tymoshenko 	    CCGR2_IPSYNC_IP2APB_TZASC1 | CCGR2_IPSYNC_IP2APB_TZASC2 |
106183413c8SOleksandr Tymoshenko 	    CCGR2_IPSYNC_VDOA;
107183413c8SOleksandr Tymoshenko 	WR4(sc, CCM_CCGR2, reg);
108183413c8SOleksandr Tymoshenko 
109183413c8SOleksandr Tymoshenko 	/* DDR memory controller */
110183413c8SOleksandr Tymoshenko 	reg = CCGR3_OCRAM | CCGR3_MMDC_CORE_IPG |
111183413c8SOleksandr Tymoshenko 	    CCGR3_MMDC_CORE_ACLK_FAST | CCGR3_CG11 | CCGR3_CG13;
112183413c8SOleksandr Tymoshenko 	WR4(sc, CCM_CCGR3, reg);
113183413c8SOleksandr Tymoshenko 
114183413c8SOleksandr Tymoshenko 	/* pl301 bus crossbar */
115183413c8SOleksandr Tymoshenko 	reg = CCGR4_PL301_MX6QFAST1_S133 |
116183413c8SOleksandr Tymoshenko 	    CCGR4_PL301_MX6QPER1_BCH | CCGR4_PL301_MX6QPER2_MAIN;
117183413c8SOleksandr Tymoshenko 	WR4(sc, CCM_CCGR4, reg);
118183413c8SOleksandr Tymoshenko 
119183413c8SOleksandr Tymoshenko 	/* uarts, ssi, sdma */
120183413c8SOleksandr Tymoshenko 	reg = CCGR5_SDMA | CCGR5_SSI1 | CCGR5_SSI2 | CCGR5_SSI3 |
121183413c8SOleksandr Tymoshenko 	    CCGR5_UART | CCGR5_UART_SERIAL;
122183413c8SOleksandr Tymoshenko 	WR4(sc, CCM_CCGR5, reg);
123183413c8SOleksandr Tymoshenko 
124183413c8SOleksandr Tymoshenko 	/* usdhc 1-4, usboh3 */
125183413c8SOleksandr Tymoshenko 	reg = CCGR6_USBOH3 | CCGR6_USDHC1 | CCGR6_USDHC2 |
126183413c8SOleksandr Tymoshenko 	    CCGR6_USDHC3 | CCGR6_USDHC4;
127183413c8SOleksandr Tymoshenko 	WR4(sc, CCM_CCGR6, reg);
1282586993bSIan Lepore }
1292586993bSIan Lepore 
1309808ebfaSIan Lepore static int
ccm_detach(device_t dev)1319808ebfaSIan Lepore ccm_detach(device_t dev)
1329808ebfaSIan Lepore {
1339808ebfaSIan Lepore 	struct ccm_softc *sc;
1349808ebfaSIan Lepore 
1359808ebfaSIan Lepore 	sc = device_get_softc(dev);
1369808ebfaSIan Lepore 
1379808ebfaSIan Lepore 	if (sc->mem_res != NULL)
1389808ebfaSIan Lepore 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
1399808ebfaSIan Lepore 
1409808ebfaSIan Lepore 	return (0);
1419808ebfaSIan Lepore }
1429808ebfaSIan Lepore 
1439808ebfaSIan Lepore static int
ccm_attach(device_t dev)1449808ebfaSIan Lepore ccm_attach(device_t dev)
1459808ebfaSIan Lepore {
1469808ebfaSIan Lepore 	struct ccm_softc *sc;
1479808ebfaSIan Lepore 	int err, rid;
148a78ec805SIan Lepore 	uint32_t reg;
1499808ebfaSIan Lepore 
1509808ebfaSIan Lepore 	sc = device_get_softc(dev);
1519808ebfaSIan Lepore 	err = 0;
1529808ebfaSIan Lepore 
1539808ebfaSIan Lepore 	/* Allocate bus_space resources. */
1549808ebfaSIan Lepore 	rid = 0;
1559808ebfaSIan Lepore 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1569808ebfaSIan Lepore 	    RF_ACTIVE);
1579808ebfaSIan Lepore 	if (sc->mem_res == NULL) {
1589808ebfaSIan Lepore 		device_printf(dev, "Cannot allocate memory resources\n");
1599808ebfaSIan Lepore 		err = ENXIO;
1609808ebfaSIan Lepore 		goto out;
1619808ebfaSIan Lepore 	}
1629808ebfaSIan Lepore 
1639808ebfaSIan Lepore 	ccm_sc = sc;
164a78ec805SIan Lepore 
165a78ec805SIan Lepore 	/*
166a78ec805SIan Lepore 	 * Configure the Low Power Mode setting to leave the ARM core power on
167a78ec805SIan Lepore 	 * when a WFI instruction is executed.  This lets the MPCore timers and
168a78ec805SIan Lepore 	 * GIC continue to run, which is helpful when the only thing that can
169a78ec805SIan Lepore 	 * wake you up is an MPCore Private Timer interrupt delivered via GIC.
170a78ec805SIan Lepore 	 *
171a78ec805SIan Lepore 	 * XXX Based on the docs, setting CCM_CGPR_INT_MEM_CLK_LPM shouldn't be
172a78ec805SIan Lepore 	 * required when the LPM bits are set to LPM_RUN.  But experimentally
173a78ec805SIan Lepore 	 * I've experienced a fairly rare lockup when not setting it.  I was
174a78ec805SIan Lepore 	 * unable to prove conclusively that the lockup was related to power
175a78ec805SIan Lepore 	 * management or that this definitively fixes it.  Revisit this.
176a78ec805SIan Lepore 	 */
177a78ec805SIan Lepore 	reg = RD4(sc, CCM_CGPR);
178a78ec805SIan Lepore 	reg |= CCM_CGPR_INT_MEM_CLK_LPM;
179a78ec805SIan Lepore 	WR4(sc, CCM_CGPR, reg);
180a78ec805SIan Lepore 	reg = RD4(sc, CCM_CLPCR);
181a78ec805SIan Lepore 	reg = (reg & ~CCM_CLPCR_LPM_MASK) | CCM_CLPCR_LPM_RUN;
182a78ec805SIan Lepore 	WR4(sc, CCM_CLPCR, reg);
183a78ec805SIan Lepore 
1842586993bSIan Lepore 	ccm_init_gates(sc);
1852586993bSIan Lepore 
1869808ebfaSIan Lepore 	err = 0;
1879808ebfaSIan Lepore 
1889808ebfaSIan Lepore out:
1899808ebfaSIan Lepore 
1909808ebfaSIan Lepore 	if (err != 0)
1919808ebfaSIan Lepore 		ccm_detach(dev);
1929808ebfaSIan Lepore 
1939808ebfaSIan Lepore 	return (err);
1949808ebfaSIan Lepore }
1959808ebfaSIan Lepore 
1969808ebfaSIan Lepore static int
ccm_probe(device_t dev)1979808ebfaSIan Lepore ccm_probe(device_t dev)
1989808ebfaSIan Lepore {
1999808ebfaSIan Lepore 
200add35ed5SIan Lepore 	if (!ofw_bus_status_okay(dev))
201add35ed5SIan Lepore 		return (ENXIO);
202add35ed5SIan Lepore 
2039808ebfaSIan Lepore         if (ofw_bus_is_compatible(dev, "fsl,imx6q-ccm") == 0)
2049808ebfaSIan Lepore 		return (ENXIO);
2059808ebfaSIan Lepore 
2069808ebfaSIan Lepore 	device_set_desc(dev, "Freescale i.MX6 Clock Control Module");
2079808ebfaSIan Lepore 
2089808ebfaSIan Lepore 	return (BUS_PROBE_DEFAULT);
2099808ebfaSIan Lepore }
2109808ebfaSIan Lepore 
2119808ebfaSIan Lepore void
imx_ccm_ssi_configure(device_t _ssidev)212f0583578SRuslan Bukin imx_ccm_ssi_configure(device_t _ssidev)
213f0583578SRuslan Bukin {
214f0583578SRuslan Bukin 	struct ccm_softc *sc;
215f0583578SRuslan Bukin 	uint32_t reg;
216f0583578SRuslan Bukin 
217f0583578SRuslan Bukin 	sc = ccm_sc;
218f0583578SRuslan Bukin 
219f0583578SRuslan Bukin 	/*
220f0583578SRuslan Bukin 	 * Select PLL4 (Audio PLL) clock multiplexer as source.
221f0583578SRuslan Bukin 	 * PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM).
222f0583578SRuslan Bukin 	 */
223f0583578SRuslan Bukin 
224f0583578SRuslan Bukin 	reg = RD4(sc, CCM_CSCMR1);
225f0583578SRuslan Bukin 	reg &= ~(SSI_CLK_SEL_M << SSI1_CLK_SEL_S);
226f0583578SRuslan Bukin 	reg |= (SSI_CLK_SEL_PLL4 << SSI1_CLK_SEL_S);
227f0583578SRuslan Bukin 	reg &= ~(SSI_CLK_SEL_M << SSI2_CLK_SEL_S);
228f0583578SRuslan Bukin 	reg |= (SSI_CLK_SEL_PLL4 << SSI2_CLK_SEL_S);
229f0583578SRuslan Bukin 	reg &= ~(SSI_CLK_SEL_M << SSI3_CLK_SEL_S);
230f0583578SRuslan Bukin 	reg |= (SSI_CLK_SEL_PLL4 << SSI3_CLK_SEL_S);
231f0583578SRuslan Bukin 	WR4(sc, CCM_CSCMR1, reg);
232f0583578SRuslan Bukin 
233f0583578SRuslan Bukin 	/*
234f0583578SRuslan Bukin 	 * Ensure we have set hardware-default values
235f0583578SRuslan Bukin 	 * for pre and post dividers.
236f0583578SRuslan Bukin 	 */
237f0583578SRuslan Bukin 
238f0583578SRuslan Bukin 	/* SSI1 and SSI3 */
239f0583578SRuslan Bukin 	reg = RD4(sc, CCM_CS1CDR);
240f0583578SRuslan Bukin 	/* Divide by 2 */
241f0583578SRuslan Bukin 	reg &= ~(SSI_CLK_PODF_MASK << SSI1_CLK_PODF_SHIFT);
242f0583578SRuslan Bukin 	reg &= ~(SSI_CLK_PODF_MASK << SSI3_CLK_PODF_SHIFT);
243f0583578SRuslan Bukin 	reg |= (0x1 << SSI1_CLK_PODF_SHIFT);
244f0583578SRuslan Bukin 	reg |= (0x1 << SSI3_CLK_PODF_SHIFT);
245f0583578SRuslan Bukin 	/* Divide by 4 */
246f0583578SRuslan Bukin 	reg &= ~(SSI_CLK_PRED_MASK << SSI1_CLK_PRED_SHIFT);
247f0583578SRuslan Bukin 	reg &= ~(SSI_CLK_PRED_MASK << SSI3_CLK_PRED_SHIFT);
248f0583578SRuslan Bukin 	reg |= (0x3 << SSI1_CLK_PRED_SHIFT);
249f0583578SRuslan Bukin 	reg |= (0x3 << SSI3_CLK_PRED_SHIFT);
250f0583578SRuslan Bukin 	WR4(sc, CCM_CS1CDR, reg);
251f0583578SRuslan Bukin 
252f0583578SRuslan Bukin 	/* SSI2 */
253f0583578SRuslan Bukin 	reg = RD4(sc, CCM_CS2CDR);
254f0583578SRuslan Bukin 	/* Divide by 2 */
255f0583578SRuslan Bukin 	reg &= ~(SSI_CLK_PODF_MASK << SSI2_CLK_PODF_SHIFT);
256f0583578SRuslan Bukin 	reg |= (0x1 << SSI2_CLK_PODF_SHIFT);
257f0583578SRuslan Bukin 	/* Divide by 4 */
258f0583578SRuslan Bukin 	reg &= ~(SSI_CLK_PRED_MASK << SSI2_CLK_PRED_SHIFT);
259f0583578SRuslan Bukin 	reg |= (0x3 << SSI2_CLK_PRED_SHIFT);
260f0583578SRuslan Bukin 	WR4(sc, CCM_CS2CDR, reg);
261f0583578SRuslan Bukin }
262f0583578SRuslan Bukin 
263f0583578SRuslan Bukin void
imx_ccm_usb_enable(device_t _usbdev)2649808ebfaSIan Lepore imx_ccm_usb_enable(device_t _usbdev)
2659808ebfaSIan Lepore {
2669808ebfaSIan Lepore 
2679808ebfaSIan Lepore 	/*
2689808ebfaSIan Lepore 	 * For imx6, the USBOH3 clock gate is bits 0-1 of CCGR6, so no need for
2699808ebfaSIan Lepore 	 * shifting and masking here, just set the low-order two bits to ALWAYS.
2709808ebfaSIan Lepore 	 */
2719808ebfaSIan Lepore 	WR4(ccm_sc, CCM_CCGR6, RD4(ccm_sc, CCM_CCGR6) | CCGR_CLK_MODE_ALWAYS);
2729808ebfaSIan Lepore }
2739808ebfaSIan Lepore 
2749808ebfaSIan Lepore void
imx_ccm_usbphy_enable(device_t _phydev)2759808ebfaSIan Lepore imx_ccm_usbphy_enable(device_t _phydev)
2769808ebfaSIan Lepore {
2779808ebfaSIan Lepore         /*
2789808ebfaSIan Lepore          * XXX Which unit?
2799808ebfaSIan Lepore          * Right now it's not clear how to figure from fdt data which phy unit
2809808ebfaSIan Lepore          * we're supposed to operate on.  Until this is worked out, just enable
2819808ebfaSIan Lepore          * both PHYs.
2829808ebfaSIan Lepore          */
2839808ebfaSIan Lepore #if 0
2849808ebfaSIan Lepore 	int phy_num, regoff;
2859808ebfaSIan Lepore 
2869808ebfaSIan Lepore 	phy_num = 0; /* XXX */
2879808ebfaSIan Lepore 
2889808ebfaSIan Lepore 	switch (phy_num) {
2899808ebfaSIan Lepore 	case 0:
2909808ebfaSIan Lepore 		regoff = 0;
2919808ebfaSIan Lepore 		break;
2929808ebfaSIan Lepore 	case 1:
2939808ebfaSIan Lepore 		regoff = 0x10;
2949808ebfaSIan Lepore 		break;
2959808ebfaSIan Lepore 	default:
2969808ebfaSIan Lepore 		device_printf(ccm_sc->dev, "Bad PHY number %u,\n",
2979808ebfaSIan Lepore 		    phy_num);
2989808ebfaSIan Lepore 		return;
2999808ebfaSIan Lepore 	}
3009808ebfaSIan Lepore 
3019808ebfaSIan Lepore 	imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + regoff,
3029808ebfaSIan Lepore 	    IMX6_ANALOG_CCM_PLL_USB_ENABLE |
3039808ebfaSIan Lepore 	    IMX6_ANALOG_CCM_PLL_USB_POWER |
3049808ebfaSIan Lepore 	    IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS);
3059808ebfaSIan Lepore #else
3069808ebfaSIan Lepore 	imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + 0,
3079808ebfaSIan Lepore 	    IMX6_ANALOG_CCM_PLL_USB_ENABLE |
3089808ebfaSIan Lepore 	    IMX6_ANALOG_CCM_PLL_USB_POWER |
3099808ebfaSIan Lepore 	    IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS);
3109808ebfaSIan Lepore 
3119808ebfaSIan Lepore 	imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + 0x10,
3129808ebfaSIan Lepore 	    IMX6_ANALOG_CCM_PLL_USB_ENABLE |
3139808ebfaSIan Lepore 	    IMX6_ANALOG_CCM_PLL_USB_POWER |
3149808ebfaSIan Lepore 	    IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS);
3159808ebfaSIan Lepore #endif
3169808ebfaSIan Lepore }
3179808ebfaSIan Lepore 
318854519fdSIan Lepore int
imx6_ccm_sata_enable(void)319854519fdSIan Lepore imx6_ccm_sata_enable(void)
320854519fdSIan Lepore {
321854519fdSIan Lepore 	uint32_t v;
322854519fdSIan Lepore 	int timeout;
323854519fdSIan Lepore 
324854519fdSIan Lepore 	/* Un-gate the sata controller. */
325854519fdSIan Lepore 	WR4(ccm_sc, CCM_CCGR5, RD4(ccm_sc, CCM_CCGR5) | CCGR5_SATA);
326854519fdSIan Lepore 
327854519fdSIan Lepore 	/* Power up the PLL that feeds ENET/SATA/PCI phys, wait for lock. */
328854519fdSIan Lepore 	v = RD4(ccm_sc, CCM_ANALOG_PLL_ENET);
329854519fdSIan Lepore 	v &= ~CCM_ANALOG_PLL_ENET_POWERDOWN;
330854519fdSIan Lepore 	WR4(ccm_sc, CCM_ANALOG_PLL_ENET, v);
331854519fdSIan Lepore 
332854519fdSIan Lepore 	for (timeout = 100000; timeout > 0; timeout--) {
333854519fdSIan Lepore 		if (RD4(ccm_sc, CCM_ANALOG_PLL_ENET) &
334854519fdSIan Lepore 		   CCM_ANALOG_PLL_ENET_LOCK) {
335854519fdSIan Lepore 			break;
336854519fdSIan Lepore 		}
337854519fdSIan Lepore 	}
338854519fdSIan Lepore 	if (timeout <= 0) {
339854519fdSIan Lepore 		return ETIMEDOUT;
340854519fdSIan Lepore 	}
341854519fdSIan Lepore 
342854519fdSIan Lepore 	/* Enable the PLL, and enable its 100mhz output. */
343854519fdSIan Lepore 	v |= CCM_ANALOG_PLL_ENET_ENABLE;
344854519fdSIan Lepore 	v &= ~CCM_ANALOG_PLL_ENET_BYPASS;
345854519fdSIan Lepore 	WR4(ccm_sc, CCM_ANALOG_PLL_ENET, v);
346854519fdSIan Lepore 
347854519fdSIan Lepore 	v |= CCM_ANALOG_PLL_ENET_ENABLE_100M;
348854519fdSIan Lepore 	WR4(ccm_sc, CCM_ANALOG_PLL_ENET, v);
349854519fdSIan Lepore 
350854519fdSIan Lepore 	return 0;
351854519fdSIan Lepore }
352854519fdSIan Lepore 
353a7fa939bSIan Lepore uint32_t
imx_ccm_ecspi_hz(void)354a0fd2339SIan Lepore imx_ccm_ecspi_hz(void)
355a0fd2339SIan Lepore {
356a0fd2339SIan Lepore 
357a0fd2339SIan Lepore 	return (60000000);
358a0fd2339SIan Lepore }
359a0fd2339SIan Lepore 
360a0fd2339SIan Lepore uint32_t
imx_ccm_ipg_hz(void)361a7fa939bSIan Lepore imx_ccm_ipg_hz(void)
3629808ebfaSIan Lepore {
363a7fa939bSIan Lepore 
364a7fa939bSIan Lepore 	return (66000000);
3659808ebfaSIan Lepore }
366a7fa939bSIan Lepore 
367a7fa939bSIan Lepore uint32_t
imx_ccm_perclk_hz(void)368a7fa939bSIan Lepore imx_ccm_perclk_hz(void)
369a7fa939bSIan Lepore {
370a7fa939bSIan Lepore 
371a7fa939bSIan Lepore 	return (66000000);
372a7fa939bSIan Lepore }
373a7fa939bSIan Lepore 
374a7fa939bSIan Lepore uint32_t
imx_ccm_sdhci_hz(void)375a7fa939bSIan Lepore imx_ccm_sdhci_hz(void)
376a7fa939bSIan Lepore {
377a7fa939bSIan Lepore 
378a7fa939bSIan Lepore 	return (200000000);
379a7fa939bSIan Lepore }
380a7fa939bSIan Lepore 
381a7fa939bSIan Lepore uint32_t
imx_ccm_uart_hz(void)382a7fa939bSIan Lepore imx_ccm_uart_hz(void)
383a7fa939bSIan Lepore {
384a7fa939bSIan Lepore 
385a7fa939bSIan Lepore 	return (80000000);
3869808ebfaSIan Lepore }
3879808ebfaSIan Lepore 
388f14514a3SIan Lepore uint32_t
imx_ccm_ahb_hz(void)389f14514a3SIan Lepore imx_ccm_ahb_hz(void)
390f14514a3SIan Lepore {
391f14514a3SIan Lepore 	return (132000000);
392f14514a3SIan Lepore }
393f14514a3SIan Lepore 
394da21a623SOleksandr Tymoshenko int
imx_ccm_pll_video_enable(void)395da21a623SOleksandr Tymoshenko imx_ccm_pll_video_enable(void)
396da21a623SOleksandr Tymoshenko {
397da21a623SOleksandr Tymoshenko 	uint32_t reg;
398da21a623SOleksandr Tymoshenko 	int timeout;
399da21a623SOleksandr Tymoshenko 
400da21a623SOleksandr Tymoshenko 	/* Power down PLL */
401da21a623SOleksandr Tymoshenko 	reg = RD4(ccm_sc, CCM_ANALOG_PLL_VIDEO);
402da21a623SOleksandr Tymoshenko 	reg &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;
403da21a623SOleksandr Tymoshenko 	WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO, reg);
404da21a623SOleksandr Tymoshenko 
405da21a623SOleksandr Tymoshenko 	/*
406da21a623SOleksandr Tymoshenko 	 * Fvideo = Fref * (37 + 11/12) / 2
407da21a623SOleksandr Tymoshenko 	 * Fref = 24MHz, Fvideo = 455MHz
408da21a623SOleksandr Tymoshenko 	 */
409da21a623SOleksandr Tymoshenko 	reg &= ~CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_MASK;
410da21a623SOleksandr Tymoshenko 	reg |= CCM_ANALOG_PLL_VIDEO_POST_DIV_2;
411da21a623SOleksandr Tymoshenko 	reg &= ~CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK;
412da21a623SOleksandr Tymoshenko 	reg |= 37 << CCM_ANALOG_PLL_VIDEO_DIV_SELECT_SHIFT;
413da21a623SOleksandr Tymoshenko 	WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO, reg);
414da21a623SOleksandr Tymoshenko 
415da21a623SOleksandr Tymoshenko 	WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO_NUM, 11);
416da21a623SOleksandr Tymoshenko 	WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO_DENOM, 12);
417da21a623SOleksandr Tymoshenko 
418da21a623SOleksandr Tymoshenko 	/* Power up and wait for PLL lock down */
419da21a623SOleksandr Tymoshenko 	reg = RD4(ccm_sc, CCM_ANALOG_PLL_VIDEO);
420da21a623SOleksandr Tymoshenko 	reg &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;
421da21a623SOleksandr Tymoshenko 	WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO, reg);
422da21a623SOleksandr Tymoshenko 
423da21a623SOleksandr Tymoshenko 	for (timeout = 100000; timeout > 0; timeout--) {
424da21a623SOleksandr Tymoshenko 		if (RD4(ccm_sc, CCM_ANALOG_PLL_VIDEO) &
425da21a623SOleksandr Tymoshenko 		   CCM_ANALOG_PLL_VIDEO_LOCK) {
426da21a623SOleksandr Tymoshenko 			break;
427da21a623SOleksandr Tymoshenko 		}
428da21a623SOleksandr Tymoshenko 	}
429da21a623SOleksandr Tymoshenko 	if (timeout <= 0) {
430da21a623SOleksandr Tymoshenko 		return ETIMEDOUT;
431da21a623SOleksandr Tymoshenko 	}
432da21a623SOleksandr Tymoshenko 
433da21a623SOleksandr Tymoshenko 	/* Enable the PLL */
434da21a623SOleksandr Tymoshenko 	reg |= CCM_ANALOG_PLL_VIDEO_ENABLE;
435da21a623SOleksandr Tymoshenko 	reg &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;
436da21a623SOleksandr Tymoshenko 	WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO, reg);
437da21a623SOleksandr Tymoshenko 
438da21a623SOleksandr Tymoshenko 	return (0);
439da21a623SOleksandr Tymoshenko }
440da21a623SOleksandr Tymoshenko 
441c0f3a6c2SOleksandr Tymoshenko void
imx_ccm_ipu_enable(int ipu)442c0f3a6c2SOleksandr Tymoshenko imx_ccm_ipu_enable(int ipu)
443c0f3a6c2SOleksandr Tymoshenko {
444c0f3a6c2SOleksandr Tymoshenko 	struct ccm_softc *sc;
445c0f3a6c2SOleksandr Tymoshenko 	uint32_t reg;
446c0f3a6c2SOleksandr Tymoshenko 
447c0f3a6c2SOleksandr Tymoshenko 	sc = ccm_sc;
448c0f3a6c2SOleksandr Tymoshenko 	reg = RD4(sc, CCM_CCGR3);
449c0f3a6c2SOleksandr Tymoshenko 	if (ipu == 1)
450c0f3a6c2SOleksandr Tymoshenko 		reg |= CCGR3_IPU1_IPU | CCGR3_IPU1_DI0;
451c0f3a6c2SOleksandr Tymoshenko 	else
452c0f3a6c2SOleksandr Tymoshenko 		reg |= CCGR3_IPU2_IPU | CCGR3_IPU2_DI0;
453c0f3a6c2SOleksandr Tymoshenko 	WR4(sc, CCM_CCGR3, reg);
454da21a623SOleksandr Tymoshenko 
455da21a623SOleksandr Tymoshenko 	/* Set IPU1_DI0 clock to source from PLL5 and divide it by 3 */
456da21a623SOleksandr Tymoshenko 	reg = RD4(sc, CCM_CHSCCDR);
457da21a623SOleksandr Tymoshenko 	reg &= ~(CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK |
458da21a623SOleksandr Tymoshenko 	    CHSCCDR_IPU1_DI0_PODF_MASK | CHSCCDR_IPU1_DI0_CLK_SEL_MASK);
459da21a623SOleksandr Tymoshenko 	reg |= (CHSCCDR_PODF_DIVIDE_BY_3 << CHSCCDR_IPU1_DI0_PODF_SHIFT);
460da21a623SOleksandr Tymoshenko 	reg |= (CHSCCDR_IPU_PRE_CLK_PLL5 << CHSCCDR_IPU1_DI0_PRE_CLK_SEL_SHIFT);
461da21a623SOleksandr Tymoshenko 	WR4(sc, CCM_CHSCCDR, reg);
462da21a623SOleksandr Tymoshenko 
463da21a623SOleksandr Tymoshenko 	reg |= (CHSCCDR_CLK_SEL_PREMUXED << CHSCCDR_IPU1_DI0_CLK_SEL_SHIFT);
464da21a623SOleksandr Tymoshenko 	WR4(sc, CCM_CHSCCDR, reg);
465da21a623SOleksandr Tymoshenko }
466da21a623SOleksandr Tymoshenko 
467da21a623SOleksandr Tymoshenko uint32_t
imx_ccm_ipu_hz(void)468da21a623SOleksandr Tymoshenko imx_ccm_ipu_hz(void)
469da21a623SOleksandr Tymoshenko {
470da21a623SOleksandr Tymoshenko 
471da21a623SOleksandr Tymoshenko 	return (455000000 / 3);
472c0f3a6c2SOleksandr Tymoshenko }
473c0f3a6c2SOleksandr Tymoshenko 
474c0f3a6c2SOleksandr Tymoshenko void
imx_ccm_hdmi_enable(void)475c0f3a6c2SOleksandr Tymoshenko imx_ccm_hdmi_enable(void)
476c0f3a6c2SOleksandr Tymoshenko {
477c0f3a6c2SOleksandr Tymoshenko 	struct ccm_softc *sc;
478c0f3a6c2SOleksandr Tymoshenko 	uint32_t reg;
479c0f3a6c2SOleksandr Tymoshenko 
480c0f3a6c2SOleksandr Tymoshenko 	sc = ccm_sc;
481c0f3a6c2SOleksandr Tymoshenko 	reg = RD4(sc, CCM_CCGR2);
482c0f3a6c2SOleksandr Tymoshenko 	reg |= CCGR2_HDMI_TX | CCGR2_HDMI_TX_ISFR;
483c0f3a6c2SOleksandr Tymoshenko 	WR4(sc, CCM_CCGR2, reg);
484c0f3a6c2SOleksandr Tymoshenko }
485c0f3a6c2SOleksandr Tymoshenko 
486955691feSIan Lepore uint32_t
imx_ccm_get_cacrr(void)487955691feSIan Lepore imx_ccm_get_cacrr(void)
488955691feSIan Lepore {
489955691feSIan Lepore 
490955691feSIan Lepore 	return (RD4(ccm_sc, CCM_CACCR));
491955691feSIan Lepore }
492955691feSIan Lepore 
493955691feSIan Lepore void
imx_ccm_set_cacrr(uint32_t divisor)494955691feSIan Lepore imx_ccm_set_cacrr(uint32_t divisor)
495955691feSIan Lepore {
496955691feSIan Lepore 
497955691feSIan Lepore 	WR4(ccm_sc, CCM_CACCR, divisor);
498955691feSIan Lepore }
499955691feSIan Lepore 
5009808ebfaSIan Lepore static device_method_t ccm_methods[] = {
5019808ebfaSIan Lepore 	/* Device interface */
5029808ebfaSIan Lepore 	DEVMETHOD(device_probe,  ccm_probe),
5039808ebfaSIan Lepore 	DEVMETHOD(device_attach, ccm_attach),
5049808ebfaSIan Lepore 	DEVMETHOD(device_detach, ccm_detach),
5059808ebfaSIan Lepore 
5069808ebfaSIan Lepore 	DEVMETHOD_END
5079808ebfaSIan Lepore };
5089808ebfaSIan Lepore 
5099808ebfaSIan Lepore static driver_t ccm_driver = {
5109808ebfaSIan Lepore 	"ccm",
5119808ebfaSIan Lepore 	ccm_methods,
5129808ebfaSIan Lepore 	sizeof(struct ccm_softc)
5139808ebfaSIan Lepore };
5149808ebfaSIan Lepore 
515ea538dabSJohn Baldwin EARLY_DRIVER_MODULE(ccm, simplebus, ccm_driver, 0, 0,
51652d99877SIan Lepore     BUS_PASS_CPU + BUS_PASS_ORDER_EARLY);
517