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/imx_machdep.h> 499808ebfaSIan Lepore #include <arm/freescale/imx/imx6_ccmreg.h> 509808ebfaSIan Lepore 519808ebfaSIan Lepore 529808ebfaSIan Lepore /* XXX temp kludge for imx51_get_clock. */ 539808ebfaSIan Lepore #include <arm/freescale/imx/imx51_ccmvar.h> 549808ebfaSIan Lepore #include <arm/freescale/imx/imx51_ccmreg.h> 559808ebfaSIan Lepore 569808ebfaSIan Lepore struct ccm_softc { 579808ebfaSIan Lepore device_t dev; 589808ebfaSIan Lepore struct resource *mem_res; 599808ebfaSIan Lepore }; 609808ebfaSIan Lepore 619808ebfaSIan Lepore static struct ccm_softc *ccm_sc; 629808ebfaSIan Lepore 639808ebfaSIan Lepore static inline uint32_t 649808ebfaSIan Lepore RD4(struct ccm_softc *sc, bus_size_t off) 659808ebfaSIan Lepore { 669808ebfaSIan Lepore 679808ebfaSIan Lepore return (bus_read_4(sc->mem_res, off)); 689808ebfaSIan Lepore } 699808ebfaSIan Lepore 709808ebfaSIan Lepore static inline void 719808ebfaSIan Lepore WR4(struct ccm_softc *sc, bus_size_t off, uint32_t val) 729808ebfaSIan Lepore { 739808ebfaSIan Lepore 749808ebfaSIan Lepore bus_write_4(sc->mem_res, off, val); 759808ebfaSIan Lepore } 769808ebfaSIan Lepore 779808ebfaSIan Lepore static int 789808ebfaSIan Lepore ccm_detach(device_t dev) 799808ebfaSIan Lepore { 809808ebfaSIan Lepore struct ccm_softc *sc; 819808ebfaSIan Lepore 829808ebfaSIan Lepore sc = device_get_softc(dev); 839808ebfaSIan Lepore 849808ebfaSIan Lepore if (sc->mem_res != NULL) 859808ebfaSIan Lepore bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 869808ebfaSIan Lepore 879808ebfaSIan Lepore return (0); 889808ebfaSIan Lepore } 899808ebfaSIan Lepore 909808ebfaSIan Lepore static int 919808ebfaSIan Lepore ccm_attach(device_t dev) 929808ebfaSIan Lepore { 939808ebfaSIan Lepore struct ccm_softc *sc; 949808ebfaSIan Lepore int err, rid; 959808ebfaSIan Lepore 969808ebfaSIan Lepore sc = device_get_softc(dev); 979808ebfaSIan Lepore err = 0; 989808ebfaSIan Lepore 999808ebfaSIan Lepore /* Allocate bus_space resources. */ 1009808ebfaSIan Lepore rid = 0; 1019808ebfaSIan Lepore sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1029808ebfaSIan Lepore RF_ACTIVE); 1039808ebfaSIan Lepore if (sc->mem_res == NULL) { 1049808ebfaSIan Lepore device_printf(dev, "Cannot allocate memory resources\n"); 1059808ebfaSIan Lepore err = ENXIO; 1069808ebfaSIan Lepore goto out; 1079808ebfaSIan Lepore } 1089808ebfaSIan Lepore 1099808ebfaSIan Lepore ccm_sc = sc; 1109808ebfaSIan Lepore err = 0; 1119808ebfaSIan Lepore 1129808ebfaSIan Lepore out: 1139808ebfaSIan Lepore 1149808ebfaSIan Lepore if (err != 0) 1159808ebfaSIan Lepore ccm_detach(dev); 1169808ebfaSIan Lepore 1179808ebfaSIan Lepore return (err); 1189808ebfaSIan Lepore } 1199808ebfaSIan Lepore 1209808ebfaSIan Lepore static int 1219808ebfaSIan Lepore ccm_probe(device_t dev) 1229808ebfaSIan Lepore { 1239808ebfaSIan Lepore 1249808ebfaSIan Lepore if (ofw_bus_is_compatible(dev, "fsl,imx6q-ccm") == 0) 1259808ebfaSIan Lepore return (ENXIO); 1269808ebfaSIan Lepore 1279808ebfaSIan Lepore device_set_desc(dev, "Freescale i.MX6 Clock Control Module"); 1289808ebfaSIan Lepore 1299808ebfaSIan Lepore return (BUS_PROBE_DEFAULT); 1309808ebfaSIan Lepore } 1319808ebfaSIan Lepore 1329808ebfaSIan Lepore void 1339808ebfaSIan Lepore imx_ccm_usb_enable(device_t _usbdev) 1349808ebfaSIan Lepore { 1359808ebfaSIan Lepore 1369808ebfaSIan Lepore /* 1379808ebfaSIan Lepore * For imx6, the USBOH3 clock gate is bits 0-1 of CCGR6, so no need for 1389808ebfaSIan Lepore * shifting and masking here, just set the low-order two bits to ALWAYS. 1399808ebfaSIan Lepore */ 1409808ebfaSIan Lepore WR4(ccm_sc, CCM_CCGR6, RD4(ccm_sc, CCM_CCGR6) | CCGR_CLK_MODE_ALWAYS); 1419808ebfaSIan Lepore } 1429808ebfaSIan Lepore 1439808ebfaSIan Lepore void 1449808ebfaSIan Lepore imx_ccm_usbphy_enable(device_t _phydev) 1459808ebfaSIan Lepore { 1469808ebfaSIan Lepore /* 1479808ebfaSIan Lepore * XXX Which unit? 1489808ebfaSIan Lepore * Right now it's not clear how to figure from fdt data which phy unit 1499808ebfaSIan Lepore * we're supposed to operate on. Until this is worked out, just enable 1509808ebfaSIan Lepore * both PHYs. 1519808ebfaSIan Lepore */ 1529808ebfaSIan Lepore #if 0 1539808ebfaSIan Lepore int phy_num, regoff; 1549808ebfaSIan Lepore 1559808ebfaSIan Lepore phy_num = 0; /* XXX */ 1569808ebfaSIan Lepore 1579808ebfaSIan Lepore switch (phy_num) { 1589808ebfaSIan Lepore case 0: 1599808ebfaSIan Lepore regoff = 0; 1609808ebfaSIan Lepore break; 1619808ebfaSIan Lepore case 1: 1629808ebfaSIan Lepore regoff = 0x10; 1639808ebfaSIan Lepore break; 1649808ebfaSIan Lepore default: 1659808ebfaSIan Lepore device_printf(ccm_sc->dev, "Bad PHY number %u,\n", 1669808ebfaSIan Lepore phy_num); 1679808ebfaSIan Lepore return; 1689808ebfaSIan Lepore } 1699808ebfaSIan Lepore 1709808ebfaSIan Lepore imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + regoff, 1719808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_ENABLE | 1729808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_POWER | 1739808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS); 1749808ebfaSIan Lepore #else 1759808ebfaSIan Lepore imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + 0, 1769808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_ENABLE | 1779808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_POWER | 1789808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS); 1799808ebfaSIan Lepore 1809808ebfaSIan Lepore imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + 0x10, 1819808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_ENABLE | 1829808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_POWER | 1839808ebfaSIan Lepore IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS); 1849808ebfaSIan Lepore #endif 1859808ebfaSIan Lepore } 1869808ebfaSIan Lepore 1879808ebfaSIan Lepore 1889808ebfaSIan Lepore 1899808ebfaSIan Lepore 1909808ebfaSIan Lepore 1919808ebfaSIan Lepore // XXX Fix this. This has to be here for other code to link, 1929808ebfaSIan Lepore // but it doesn't have to return anything useful for imx6 right now. 1939808ebfaSIan Lepore u_int 1949808ebfaSIan Lepore imx51_get_clock(enum imx51_clock clk) 1959808ebfaSIan Lepore { 1969808ebfaSIan Lepore switch (clk) 1979808ebfaSIan Lepore { 1989808ebfaSIan Lepore case IMX51CLK_IPG_CLK_ROOT: 1999808ebfaSIan Lepore return 66000000; 2009808ebfaSIan Lepore default: 2019808ebfaSIan Lepore printf("imx51_get_clock() on imx6 doesn't know about clock %d\n", clk); 2029808ebfaSIan Lepore break; 2039808ebfaSIan Lepore } 2049808ebfaSIan Lepore return 0; 2059808ebfaSIan Lepore } 2069808ebfaSIan Lepore 2079808ebfaSIan Lepore static device_method_t ccm_methods[] = { 2089808ebfaSIan Lepore /* Device interface */ 2099808ebfaSIan Lepore DEVMETHOD(device_probe, ccm_probe), 2109808ebfaSIan Lepore DEVMETHOD(device_attach, ccm_attach), 2119808ebfaSIan Lepore DEVMETHOD(device_detach, ccm_detach), 2129808ebfaSIan Lepore 2139808ebfaSIan Lepore DEVMETHOD_END 2149808ebfaSIan Lepore }; 2159808ebfaSIan Lepore 2169808ebfaSIan Lepore static driver_t ccm_driver = { 2179808ebfaSIan Lepore "ccm", 2189808ebfaSIan Lepore ccm_methods, 2199808ebfaSIan Lepore sizeof(struct ccm_softc) 2209808ebfaSIan Lepore }; 2219808ebfaSIan Lepore 2229808ebfaSIan Lepore static devclass_t ccm_devclass; 2239808ebfaSIan Lepore 2249808ebfaSIan Lepore DRIVER_MODULE(ccm, simplebus, ccm_driver, ccm_devclass, 0, 0); 2259808ebfaSIan Lepore 226