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