19808ebfaSIan Lepore /*- 29808ebfaSIan Lepore * Copyright (c) 2013 Ian Lepore <ian@freebsd.org> 39808ebfaSIan Lepore * All rights reserved. 49808ebfaSIan Lepore * 59808ebfaSIan Lepore * Redistribution and use in source and binary forms, with or without 69808ebfaSIan Lepore * modification, are permitted provided that the following conditions 79808ebfaSIan Lepore * are met: 89808ebfaSIan Lepore * 1. Redistributions of source code must retain the above copyright 99808ebfaSIan Lepore * notice, this list of conditions and the following disclaimer. 109808ebfaSIan Lepore * 2. Redistributions in binary form must reproduce the above copyright 119808ebfaSIan Lepore * notice, this list of conditions and the following disclaimer in the 129808ebfaSIan Lepore * documentation and/or other materials provided with the distribution. 139808ebfaSIan Lepore * 149808ebfaSIan Lepore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 159808ebfaSIan Lepore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 169808ebfaSIan Lepore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 179808ebfaSIan Lepore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 189808ebfaSIan Lepore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 199808ebfaSIan Lepore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 209808ebfaSIan Lepore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 219808ebfaSIan Lepore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 229808ebfaSIan Lepore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 239808ebfaSIan Lepore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 249808ebfaSIan Lepore * SUCH DAMAGE. 259808ebfaSIan Lepore */ 269808ebfaSIan Lepore 279808ebfaSIan Lepore #include <sys/cdefs.h> 289808ebfaSIan Lepore __FBSDID("$FreeBSD$"); 299808ebfaSIan Lepore 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 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 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 799808ebfaSIan Lepore static int 809808ebfaSIan Lepore ccm_detach(device_t dev) 819808ebfaSIan Lepore { 829808ebfaSIan Lepore struct ccm_softc *sc; 839808ebfaSIan Lepore 849808ebfaSIan Lepore sc = device_get_softc(dev); 859808ebfaSIan Lepore 869808ebfaSIan Lepore if (sc->mem_res != NULL) 879808ebfaSIan Lepore bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 889808ebfaSIan Lepore 899808ebfaSIan Lepore return (0); 909808ebfaSIan Lepore } 919808ebfaSIan Lepore 929808ebfaSIan Lepore static int 939808ebfaSIan Lepore ccm_attach(device_t dev) 949808ebfaSIan Lepore { 959808ebfaSIan Lepore struct ccm_softc *sc; 969808ebfaSIan Lepore int err, rid; 97a78ec805SIan Lepore uint32_t reg; 989808ebfaSIan Lepore 999808ebfaSIan Lepore sc = device_get_softc(dev); 1009808ebfaSIan Lepore err = 0; 1019808ebfaSIan Lepore 1029808ebfaSIan Lepore /* Allocate bus_space resources. */ 1039808ebfaSIan Lepore rid = 0; 1049808ebfaSIan Lepore sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1059808ebfaSIan Lepore RF_ACTIVE); 1069808ebfaSIan Lepore if (sc->mem_res == NULL) { 1079808ebfaSIan Lepore device_printf(dev, "Cannot allocate memory resources\n"); 1089808ebfaSIan Lepore err = ENXIO; 1099808ebfaSIan Lepore goto out; 1109808ebfaSIan Lepore } 1119808ebfaSIan Lepore 1129808ebfaSIan Lepore ccm_sc = sc; 113a78ec805SIan Lepore 114a78ec805SIan Lepore /* 115a78ec805SIan Lepore * Configure the Low Power Mode setting to leave the ARM core power on 116a78ec805SIan Lepore * when a WFI instruction is executed. This lets the MPCore timers and 117a78ec805SIan Lepore * GIC continue to run, which is helpful when the only thing that can 118a78ec805SIan Lepore * wake you up is an MPCore Private Timer interrupt delivered via GIC. 119a78ec805SIan Lepore * 120a78ec805SIan Lepore * XXX Based on the docs, setting CCM_CGPR_INT_MEM_CLK_LPM shouldn't be 121a78ec805SIan Lepore * required when the LPM bits are set to LPM_RUN. But experimentally 122a78ec805SIan Lepore * I've experienced a fairly rare lockup when not setting it. I was 123a78ec805SIan Lepore * unable to prove conclusively that the lockup was related to power 124a78ec805SIan Lepore * management or that this definitively fixes it. Revisit this. 125a78ec805SIan Lepore */ 126a78ec805SIan Lepore reg = RD4(sc, CCM_CGPR); 127a78ec805SIan Lepore reg |= CCM_CGPR_INT_MEM_CLK_LPM; 128a78ec805SIan Lepore WR4(sc, CCM_CGPR, reg); 129a78ec805SIan Lepore reg = RD4(sc, CCM_CLPCR); 130a78ec805SIan Lepore reg = (reg & ~CCM_CLPCR_LPM_MASK) | CCM_CLPCR_LPM_RUN; 131a78ec805SIan Lepore WR4(sc, CCM_CLPCR, reg); 132a78ec805SIan Lepore 1339808ebfaSIan Lepore err = 0; 1349808ebfaSIan Lepore 1359808ebfaSIan Lepore out: 1369808ebfaSIan Lepore 1379808ebfaSIan Lepore if (err != 0) 1389808ebfaSIan Lepore ccm_detach(dev); 1399808ebfaSIan Lepore 1409808ebfaSIan Lepore return (err); 1419808ebfaSIan Lepore } 1429808ebfaSIan Lepore 1439808ebfaSIan Lepore static int 1449808ebfaSIan Lepore ccm_probe(device_t dev) 1459808ebfaSIan Lepore { 1469808ebfaSIan Lepore 147add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 148add35ed5SIan Lepore return (ENXIO); 149add35ed5SIan Lepore 1509808ebfaSIan Lepore if (ofw_bus_is_compatible(dev, "fsl,imx6q-ccm") == 0) 1519808ebfaSIan Lepore return (ENXIO); 1529808ebfaSIan Lepore 1539808ebfaSIan Lepore device_set_desc(dev, "Freescale i.MX6 Clock Control Module"); 1549808ebfaSIan Lepore 1559808ebfaSIan Lepore return (BUS_PROBE_DEFAULT); 1569808ebfaSIan Lepore } 1579808ebfaSIan Lepore 1589808ebfaSIan Lepore void 1599808ebfaSIan Lepore imx_ccm_usb_enable(device_t _usbdev) 1609808ebfaSIan Lepore { 1619808ebfaSIan Lepore 1629808ebfaSIan Lepore /* 1639808ebfaSIan Lepore * For imx6, the USBOH3 clock gate is bits 0-1 of CCGR6, so no need for 1649808ebfaSIan Lepore * shifting and masking here, just set the low-order two bits to ALWAYS. 1659808ebfaSIan Lepore */ 1669808ebfaSIan Lepore WR4(ccm_sc, CCM_CCGR6, RD4(ccm_sc, CCM_CCGR6) | CCGR_CLK_MODE_ALWAYS); 1679808ebfaSIan Lepore } 1689808ebfaSIan Lepore 1699808ebfaSIan Lepore void 1709808ebfaSIan Lepore imx_ccm_usbphy_enable(device_t _phydev) 1719808ebfaSIan Lepore { 1729808ebfaSIan Lepore /* 1739808ebfaSIan Lepore * XXX Which unit? 1749808ebfaSIan Lepore * Right now it's not clear how to figure from fdt data which phy unit 1759808ebfaSIan Lepore * we're supposed to operate on. Until this is worked out, just enable 1769808ebfaSIan Lepore * both PHYs. 1779808ebfaSIan Lepore */ 1789808ebfaSIan Lepore #if 0 1799808ebfaSIan Lepore int phy_num, regoff; 1809808ebfaSIan Lepore 1819808ebfaSIan Lepore phy_num = 0; /* XXX */ 1829808ebfaSIan Lepore 1839808ebfaSIan Lepore switch (phy_num) { 1849808ebfaSIan Lepore case 0: 1859808ebfaSIan Lepore regoff = 0; 1869808ebfaSIan Lepore break; 1879808ebfaSIan Lepore case 1: 1889808ebfaSIan Lepore regoff = 0x10; 1899808ebfaSIan Lepore break; 1909808ebfaSIan Lepore default: 1919808ebfaSIan Lepore device_printf(ccm_sc->dev, "Bad PHY number %u,\n", 1929808ebfaSIan Lepore phy_num); 1939808ebfaSIan Lepore return; 1949808ebfaSIan Lepore } 1959808ebfaSIan Lepore 1969808ebfaSIan Lepore imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + regoff, 1979808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_ENABLE | 1989808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_POWER | 1999808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS); 2009808ebfaSIan Lepore #else 2019808ebfaSIan Lepore imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + 0, 2029808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_ENABLE | 2039808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_POWER | 2049808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS); 2059808ebfaSIan Lepore 2069808ebfaSIan Lepore imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + 0x10, 2079808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_ENABLE | 2089808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_POWER | 2099808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS); 2109808ebfaSIan Lepore #endif 2119808ebfaSIan Lepore } 2129808ebfaSIan Lepore 213a7fa939bSIan Lepore uint32_t 214a7fa939bSIan Lepore imx_ccm_ipg_hz(void) 2159808ebfaSIan Lepore { 216a7fa939bSIan Lepore 217a7fa939bSIan Lepore return (66000000); 2189808ebfaSIan Lepore } 219a7fa939bSIan Lepore 220a7fa939bSIan Lepore uint32_t 221a7fa939bSIan Lepore imx_ccm_perclk_hz(void) 222a7fa939bSIan Lepore { 223a7fa939bSIan Lepore 224a7fa939bSIan Lepore return (66000000); 225a7fa939bSIan Lepore } 226a7fa939bSIan Lepore 227a7fa939bSIan Lepore uint32_t 228a7fa939bSIan Lepore imx_ccm_sdhci_hz(void) 229a7fa939bSIan Lepore { 230a7fa939bSIan Lepore 231a7fa939bSIan Lepore return (200000000); 232a7fa939bSIan Lepore } 233a7fa939bSIan Lepore 234a7fa939bSIan Lepore uint32_t 235a7fa939bSIan Lepore imx_ccm_uart_hz(void) 236a7fa939bSIan Lepore { 237a7fa939bSIan Lepore 238a7fa939bSIan Lepore return (80000000); 2399808ebfaSIan Lepore } 2409808ebfaSIan Lepore 241f14514a3SIan Lepore uint32_t 242f14514a3SIan Lepore imx_ccm_ahb_hz(void) 243f14514a3SIan Lepore { 244f14514a3SIan Lepore return (132000000); 245f14514a3SIan Lepore } 246f14514a3SIan Lepore 2479808ebfaSIan Lepore static device_method_t ccm_methods[] = { 2489808ebfaSIan Lepore /* Device interface */ 2499808ebfaSIan Lepore DEVMETHOD(device_probe, ccm_probe), 2509808ebfaSIan Lepore DEVMETHOD(device_attach, ccm_attach), 2519808ebfaSIan Lepore DEVMETHOD(device_detach, ccm_detach), 2529808ebfaSIan Lepore 2539808ebfaSIan Lepore DEVMETHOD_END 2549808ebfaSIan Lepore }; 2559808ebfaSIan Lepore 2569808ebfaSIan Lepore static driver_t ccm_driver = { 2579808ebfaSIan Lepore "ccm", 2589808ebfaSIan Lepore ccm_methods, 2599808ebfaSIan Lepore sizeof(struct ccm_softc) 2609808ebfaSIan Lepore }; 2619808ebfaSIan Lepore 2629808ebfaSIan Lepore static devclass_t ccm_devclass; 2639808ebfaSIan Lepore 264*52d99877SIan Lepore EARLY_DRIVER_MODULE(ccm, simplebus, ccm_driver, ccm_devclass, 0, 0, 265*52d99877SIan Lepore BUS_PASS_CPU + BUS_PASS_ORDER_EARLY); 2669808ebfaSIan Lepore 267