1257453Sian/*- 2257453Sian * Copyright (c) 2013 Ian Lepore <ian@freebsd.org> 3257453Sian * All rights reserved. 4257453Sian * 5257453Sian * Redistribution and use in source and binary forms, with or without 6257453Sian * modification, are permitted provided that the following conditions 7257453Sian * are met: 8257453Sian * 1. Redistributions of source code must retain the above copyright 9257453Sian * notice, this list of conditions and the following disclaimer. 10257453Sian * 2. Redistributions in binary form must reproduce the above copyright 11257453Sian * notice, this list of conditions and the following disclaimer in the 12257453Sian * documentation and/or other materials provided with the distribution. 13257453Sian * 14257453Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15257453Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16257453Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17257453Sian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18257453Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19257453Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20257453Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21257453Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22257453Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23257453Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24257453Sian * SUCH DAMAGE. 25257453Sian */ 26257453Sian 27257453Sian#include <sys/cdefs.h> 28257453Sian__FBSDID("$FreeBSD: stable/11/sys/arm/freescale/imx/imx6_ccm.c 331722 2018-03-29 02:50:57Z eadler $"); 29257453Sian 30257453Sian/* 31257453Sian * Clocks and power control driver for Freescale i.MX6 family of SoCs. 32257453Sian */ 33257453Sian 34257453Sian#include <sys/param.h> 35257453Sian#include <sys/systm.h> 36257453Sian#include <sys/kernel.h> 37257453Sian#include <sys/module.h> 38257453Sian#include <sys/bus.h> 39257453Sian#include <sys/rman.h> 40257453Sian 41257453Sian#include <dev/ofw/ofw_bus.h> 42257453Sian#include <dev/ofw/ofw_bus_subr.h> 43257453Sian 44257453Sian#include <machine/bus.h> 45257453Sian 46257453Sian#include <arm/freescale/imx/imx6_anatopreg.h> 47257453Sian#include <arm/freescale/imx/imx6_anatopvar.h> 48264977Sian#include <arm/freescale/imx/imx6_ccmreg.h> 49257453Sian#include <arm/freescale/imx/imx_machdep.h> 50264977Sian#include <arm/freescale/imx/imx_ccmvar.h> 51257453Sian 52264977Sian#ifndef CCGR_CLK_MODE_ALWAYS 53264977Sian#define CCGR_CLK_MODE_OFF 0 54264977Sian#define CCGR_CLK_MODE_RUNMODE 1 55264977Sian#define CCGR_CLK_MODE_ALWAYS 3 56264977Sian#endif 57257453Sian 58257453Sianstruct ccm_softc { 59257453Sian device_t dev; 60257453Sian struct resource *mem_res; 61257453Sian}; 62257453Sian 63257453Sianstatic struct ccm_softc *ccm_sc; 64257453Sian 65257453Sianstatic inline uint32_t 66257453SianRD4(struct ccm_softc *sc, bus_size_t off) 67257453Sian{ 68257453Sian 69257453Sian return (bus_read_4(sc->mem_res, off)); 70257453Sian} 71257453Sian 72257453Sianstatic inline void 73257453SianWR4(struct ccm_softc *sc, bus_size_t off, uint32_t val) 74257453Sian{ 75257453Sian 76257453Sian bus_write_4(sc->mem_res, off, val); 77257453Sian} 78257453Sian 79273514Sian/* 80273514Sian * Until we have a fully functional ccm driver which implements the fdt_clock 81273514Sian * interface, use the age-old workaround of unconditionally enabling the clocks 82273514Sian * for devices we might need to use. The SoC defaults to most clocks enabled, 83273514Sian * but the rom boot code and u-boot disable a few of them. We turn on only 84273514Sian * what's needed to run the chip plus devices we have drivers for, and turn off 85273514Sian * devices we don't yet have drivers for. (Note that USB is not turned on here 86273514Sian * because that is one we do when the driver asks for it.) 87273514Sian */ 88273514Sianstatic void 89273514Sianccm_init_gates(struct ccm_softc *sc) 90273514Sian{ 91290834Sgonzo uint32_t reg; 92290834Sgonzo 93290834Sgonzo /* ahpbdma, aipstz 1 & 2 busses */ 94290834Sgonzo reg = CCGR0_AIPS_TZ1 | CCGR0_AIPS_TZ2 | CCGR0_ABPHDMA; 95290834Sgonzo WR4(sc, CCM_CCGR0, reg); 96290834Sgonzo 97331506Sian /* enet, epit, gpt, spi */ 98331506Sian reg = CCGR1_ENET | CCGR1_EPIT1 | CCGR1_GPT | CCGR1_ECSPI1 | 99331506Sian CCGR1_ECSPI2 | CCGR1_ECSPI3 | CCGR1_ECSPI4 | CCGR1_ECSPI5; 100290834Sgonzo WR4(sc, CCM_CCGR1, reg); 101290834Sgonzo 102290834Sgonzo /* ipmux & ipsync (bridges), iomux, i2c */ 103290834Sgonzo reg = CCGR2_I2C1 | CCGR2_I2C2 | CCGR2_I2C3 | CCGR2_IIM | 104290834Sgonzo CCGR2_IOMUX_IPT | CCGR2_IPMUX1 | CCGR2_IPMUX2 | CCGR2_IPMUX3 | 105290834Sgonzo CCGR2_IPSYNC_IP2APB_TZASC1 | CCGR2_IPSYNC_IP2APB_TZASC2 | 106290834Sgonzo CCGR2_IPSYNC_VDOA; 107290834Sgonzo WR4(sc, CCM_CCGR2, reg); 108290834Sgonzo 109290834Sgonzo /* DDR memory controller */ 110290834Sgonzo reg = CCGR3_OCRAM | CCGR3_MMDC_CORE_IPG | 111290834Sgonzo CCGR3_MMDC_CORE_ACLK_FAST | CCGR3_CG11 | CCGR3_CG13; 112290834Sgonzo WR4(sc, CCM_CCGR3, reg); 113290834Sgonzo 114290834Sgonzo /* pl301 bus crossbar */ 115290834Sgonzo reg = CCGR4_PL301_MX6QFAST1_S133 | 116290834Sgonzo CCGR4_PL301_MX6QPER1_BCH | CCGR4_PL301_MX6QPER2_MAIN; 117290834Sgonzo WR4(sc, CCM_CCGR4, reg); 118290834Sgonzo 119290834Sgonzo /* uarts, ssi, sdma */ 120290834Sgonzo reg = CCGR5_SDMA | CCGR5_SSI1 | CCGR5_SSI2 | CCGR5_SSI3 | 121290834Sgonzo CCGR5_UART | CCGR5_UART_SERIAL; 122290834Sgonzo WR4(sc, CCM_CCGR5, reg); 123290834Sgonzo 124290834Sgonzo /* usdhc 1-4, usboh3 */ 125290834Sgonzo reg = CCGR6_USBOH3 | CCGR6_USDHC1 | CCGR6_USDHC2 | 126290834Sgonzo CCGR6_USDHC3 | CCGR6_USDHC4; 127290834Sgonzo WR4(sc, CCM_CCGR6, reg); 128273514Sian} 129273514Sian 130257453Sianstatic int 131257453Sianccm_detach(device_t dev) 132257453Sian{ 133257453Sian struct ccm_softc *sc; 134257453Sian 135257453Sian sc = device_get_softc(dev); 136257453Sian 137257453Sian if (sc->mem_res != NULL) 138257453Sian bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 139257453Sian 140257453Sian return (0); 141257453Sian} 142257453Sian 143257453Sianstatic int 144257453Sianccm_attach(device_t dev) 145257453Sian{ 146257453Sian struct ccm_softc *sc; 147257453Sian int err, rid; 148262581Sian uint32_t reg; 149257453Sian 150257453Sian sc = device_get_softc(dev); 151257453Sian err = 0; 152257453Sian 153257453Sian /* Allocate bus_space resources. */ 154257453Sian rid = 0; 155257453Sian sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 156257453Sian RF_ACTIVE); 157257453Sian if (sc->mem_res == NULL) { 158257453Sian device_printf(dev, "Cannot allocate memory resources\n"); 159257453Sian err = ENXIO; 160257453Sian goto out; 161257453Sian } 162257453Sian 163257453Sian ccm_sc = sc; 164262581Sian 165262581Sian /* 166262581Sian * Configure the Low Power Mode setting to leave the ARM core power on 167262581Sian * when a WFI instruction is executed. This lets the MPCore timers and 168262581Sian * GIC continue to run, which is helpful when the only thing that can 169262581Sian * wake you up is an MPCore Private Timer interrupt delivered via GIC. 170262581Sian * 171262581Sian * XXX Based on the docs, setting CCM_CGPR_INT_MEM_CLK_LPM shouldn't be 172262581Sian * required when the LPM bits are set to LPM_RUN. But experimentally 173262581Sian * I've experienced a fairly rare lockup when not setting it. I was 174262581Sian * unable to prove conclusively that the lockup was related to power 175262581Sian * management or that this definitively fixes it. Revisit this. 176262581Sian */ 177262581Sian reg = RD4(sc, CCM_CGPR); 178262581Sian reg |= CCM_CGPR_INT_MEM_CLK_LPM; 179262581Sian WR4(sc, CCM_CGPR, reg); 180262581Sian reg = RD4(sc, CCM_CLPCR); 181262581Sian reg = (reg & ~CCM_CLPCR_LPM_MASK) | CCM_CLPCR_LPM_RUN; 182262581Sian WR4(sc, CCM_CLPCR, reg); 183262581Sian 184273514Sian ccm_init_gates(sc); 185273514Sian 186257453Sian err = 0; 187257453Sian 188257453Sianout: 189257453Sian 190257453Sian if (err != 0) 191257453Sian ccm_detach(dev); 192257453Sian 193257453Sian return (err); 194257453Sian} 195257453Sian 196257453Sianstatic int 197257453Sianccm_probe(device_t dev) 198257453Sian{ 199257453Sian 200261410Sian if (!ofw_bus_status_okay(dev)) 201261410Sian return (ENXIO); 202261410Sian 203257453Sian if (ofw_bus_is_compatible(dev, "fsl,imx6q-ccm") == 0) 204257453Sian return (ENXIO); 205257453Sian 206257453Sian device_set_desc(dev, "Freescale i.MX6 Clock Control Module"); 207257453Sian 208257453Sian return (BUS_PROBE_DEFAULT); 209257453Sian} 210257453Sian 211257453Sianvoid 212277644Sbrimx_ccm_ssi_configure(device_t _ssidev) 213277644Sbr{ 214277644Sbr struct ccm_softc *sc; 215277644Sbr uint32_t reg; 216277644Sbr 217277644Sbr sc = ccm_sc; 218277644Sbr 219277644Sbr /* 220277644Sbr * Select PLL4 (Audio PLL) clock multiplexer as source. 221277644Sbr * PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). 222277644Sbr */ 223277644Sbr 224277644Sbr reg = RD4(sc, CCM_CSCMR1); 225277644Sbr reg &= ~(SSI_CLK_SEL_M << SSI1_CLK_SEL_S); 226277644Sbr reg |= (SSI_CLK_SEL_PLL4 << SSI1_CLK_SEL_S); 227277644Sbr reg &= ~(SSI_CLK_SEL_M << SSI2_CLK_SEL_S); 228277644Sbr reg |= (SSI_CLK_SEL_PLL4 << SSI2_CLK_SEL_S); 229277644Sbr reg &= ~(SSI_CLK_SEL_M << SSI3_CLK_SEL_S); 230277644Sbr reg |= (SSI_CLK_SEL_PLL4 << SSI3_CLK_SEL_S); 231277644Sbr WR4(sc, CCM_CSCMR1, reg); 232277644Sbr 233277644Sbr /* 234277644Sbr * Ensure we have set hardware-default values 235277644Sbr * for pre and post dividers. 236277644Sbr */ 237277644Sbr 238277644Sbr /* SSI1 and SSI3 */ 239277644Sbr reg = RD4(sc, CCM_CS1CDR); 240277644Sbr /* Divide by 2 */ 241277644Sbr reg &= ~(SSI_CLK_PODF_MASK << SSI1_CLK_PODF_SHIFT); 242277644Sbr reg &= ~(SSI_CLK_PODF_MASK << SSI3_CLK_PODF_SHIFT); 243277644Sbr reg |= (0x1 << SSI1_CLK_PODF_SHIFT); 244277644Sbr reg |= (0x1 << SSI3_CLK_PODF_SHIFT); 245277644Sbr /* Divide by 4 */ 246277644Sbr reg &= ~(SSI_CLK_PRED_MASK << SSI1_CLK_PRED_SHIFT); 247277644Sbr reg &= ~(SSI_CLK_PRED_MASK << SSI3_CLK_PRED_SHIFT); 248277644Sbr reg |= (0x3 << SSI1_CLK_PRED_SHIFT); 249277644Sbr reg |= (0x3 << SSI3_CLK_PRED_SHIFT); 250277644Sbr WR4(sc, CCM_CS1CDR, reg); 251277644Sbr 252277644Sbr /* SSI2 */ 253277644Sbr reg = RD4(sc, CCM_CS2CDR); 254277644Sbr /* Divide by 2 */ 255277644Sbr reg &= ~(SSI_CLK_PODF_MASK << SSI2_CLK_PODF_SHIFT); 256277644Sbr reg |= (0x1 << SSI2_CLK_PODF_SHIFT); 257277644Sbr /* Divide by 4 */ 258277644Sbr reg &= ~(SSI_CLK_PRED_MASK << SSI2_CLK_PRED_SHIFT); 259277644Sbr reg |= (0x3 << SSI2_CLK_PRED_SHIFT); 260277644Sbr WR4(sc, CCM_CS2CDR, reg); 261277644Sbr} 262277644Sbr 263277644Sbrvoid 264257453Sianimx_ccm_usb_enable(device_t _usbdev) 265257453Sian{ 266257453Sian 267257453Sian /* 268257453Sian * For imx6, the USBOH3 clock gate is bits 0-1 of CCGR6, so no need for 269257453Sian * shifting and masking here, just set the low-order two bits to ALWAYS. 270257453Sian */ 271257453Sian WR4(ccm_sc, CCM_CCGR6, RD4(ccm_sc, CCM_CCGR6) | CCGR_CLK_MODE_ALWAYS); 272257453Sian} 273257453Sian 274257453Sianvoid 275257453Sianimx_ccm_usbphy_enable(device_t _phydev) 276257453Sian{ 277257453Sian /* 278257453Sian * XXX Which unit? 279257453Sian * Right now it's not clear how to figure from fdt data which phy unit 280257453Sian * we're supposed to operate on. Until this is worked out, just enable 281257453Sian * both PHYs. 282257453Sian */ 283257453Sian#if 0 284257453Sian int phy_num, regoff; 285257453Sian 286257453Sian phy_num = 0; /* XXX */ 287257453Sian 288257453Sian switch (phy_num) { 289257453Sian case 0: 290257453Sian regoff = 0; 291257453Sian break; 292257453Sian case 1: 293257453Sian regoff = 0x10; 294257453Sian break; 295257453Sian default: 296257453Sian device_printf(ccm_sc->dev, "Bad PHY number %u,\n", 297257453Sian phy_num); 298257453Sian return; 299257453Sian } 300257453Sian 301257453Sian imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + regoff, 302257453Sian IMX6_ANALOG_CCM_PLL_USB_ENABLE | 303257453Sian IMX6_ANALOG_CCM_PLL_USB_POWER | 304257453Sian IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS); 305257453Sian#else 306257453Sian imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + 0, 307257453Sian IMX6_ANALOG_CCM_PLL_USB_ENABLE | 308257453Sian IMX6_ANALOG_CCM_PLL_USB_POWER | 309257453Sian IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS); 310257453Sian 311257453Sian imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + 0x10, 312257453Sian IMX6_ANALOG_CCM_PLL_USB_ENABLE | 313257453Sian IMX6_ANALOG_CCM_PLL_USB_POWER | 314257453Sian IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS); 315257453Sian#endif 316257453Sian} 317257453Sian 318323468Sianint 319323468Sianimx6_ccm_sata_enable(void) 320323468Sian{ 321323468Sian uint32_t v; 322323468Sian int timeout; 323323468Sian 324323468Sian /* Un-gate the sata controller. */ 325323468Sian WR4(ccm_sc, CCM_CCGR5, RD4(ccm_sc, CCM_CCGR5) | CCGR5_SATA); 326323468Sian 327323468Sian /* Power up the PLL that feeds ENET/SATA/PCI phys, wait for lock. */ 328323468Sian v = RD4(ccm_sc, CCM_ANALOG_PLL_ENET); 329323468Sian v &= ~CCM_ANALOG_PLL_ENET_POWERDOWN; 330323468Sian WR4(ccm_sc, CCM_ANALOG_PLL_ENET, v); 331323468Sian 332323468Sian for (timeout = 100000; timeout > 0; timeout--) { 333323468Sian if (RD4(ccm_sc, CCM_ANALOG_PLL_ENET) & 334323468Sian CCM_ANALOG_PLL_ENET_LOCK) { 335323468Sian break; 336323468Sian } 337323468Sian } 338323468Sian if (timeout <= 0) { 339323468Sian return ETIMEDOUT; 340323468Sian } 341323468Sian 342323468Sian /* Enable the PLL, and enable its 100mhz output. */ 343323468Sian v |= CCM_ANALOG_PLL_ENET_ENABLE; 344323468Sian v &= ~CCM_ANALOG_PLL_ENET_BYPASS; 345323468Sian WR4(ccm_sc, CCM_ANALOG_PLL_ENET, v); 346323468Sian 347323468Sian v |= CCM_ANALOG_PLL_ENET_ENABLE_100M; 348323468Sian WR4(ccm_sc, CCM_ANALOG_PLL_ENET, v); 349323468Sian 350323468Sian return 0; 351323468Sian} 352323468Sian 353264977Sianuint32_t 354331506Sianimx_ccm_ecspi_hz(void) 355331506Sian{ 356331506Sian 357331506Sian return (60000000); 358331506Sian} 359331506Sian 360331506Sianuint32_t 361264977Sianimx_ccm_ipg_hz(void) 362264977Sian{ 363257453Sian 364264977Sian return (66000000); 365264977Sian} 366257453Sian 367264977Sianuint32_t 368264977Sianimx_ccm_perclk_hz(void) 369264977Sian{ 370257453Sian 371264977Sian return (66000000); 372264977Sian} 373257453Sian 374264977Sianuint32_t 375264977Sianimx_ccm_sdhci_hz(void) 376257453Sian{ 377264977Sian 378264977Sian return (200000000); 379257453Sian} 380257453Sian 381264977Sianuint32_t 382264977Sianimx_ccm_uart_hz(void) 383264977Sian{ 384264977Sian 385264977Sian return (80000000); 386264977Sian} 387264977Sian 388271055Sianuint32_t 389271055Sianimx_ccm_ahb_hz(void) 390271055Sian{ 391271055Sian return (132000000); 392271055Sian} 393271055Sian 394292565Sgonzovoid 395292565Sgonzoimx_ccm_ipu_enable(int ipu) 396292565Sgonzo{ 397292565Sgonzo struct ccm_softc *sc; 398292565Sgonzo uint32_t reg; 399292565Sgonzo 400292565Sgonzo sc = ccm_sc; 401292565Sgonzo reg = RD4(sc, CCM_CCGR3); 402292565Sgonzo if (ipu == 1) 403292565Sgonzo reg |= CCGR3_IPU1_IPU | CCGR3_IPU1_DI0; 404292565Sgonzo else 405292565Sgonzo reg |= CCGR3_IPU2_IPU | CCGR3_IPU2_DI0; 406292565Sgonzo WR4(sc, CCM_CCGR3, reg); 407292565Sgonzo} 408292565Sgonzo 409292565Sgonzovoid 410292565Sgonzoimx_ccm_hdmi_enable(void) 411292565Sgonzo{ 412292565Sgonzo struct ccm_softc *sc; 413292565Sgonzo uint32_t reg; 414292565Sgonzo 415292565Sgonzo sc = ccm_sc; 416292565Sgonzo reg = RD4(sc, CCM_CCGR2); 417292565Sgonzo reg |= CCGR2_HDMI_TX | CCGR2_HDMI_TX_ISFR; 418292565Sgonzo WR4(sc, CCM_CCGR2, reg); 419292565Sgonzo 420292565Sgonzo /* Set HDMI clock to 280MHz */ 421292565Sgonzo reg = RD4(sc, CCM_CHSCCDR); 422292565Sgonzo reg &= ~(CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK | 423292565Sgonzo CHSCCDR_IPU1_DI0_PODF_MASK | CHSCCDR_IPU1_DI0_CLK_SEL_MASK); 424292565Sgonzo reg |= (CHSCCDR_PODF_DIVIDE_BY_3 << CHSCCDR_IPU1_DI0_PODF_SHIFT); 425292565Sgonzo reg |= (CHSCCDR_IPU_PRE_CLK_540M_PFD << CHSCCDR_IPU1_DI0_PRE_CLK_SEL_SHIFT); 426292565Sgonzo WR4(sc, CCM_CHSCCDR, reg); 427292565Sgonzo reg |= (CHSCCDR_CLK_SEL_LDB_DI0 << CHSCCDR_IPU1_DI0_CLK_SEL_SHIFT); 428292565Sgonzo WR4(sc, CCM_CHSCCDR, reg); 429292565Sgonzo} 430292565Sgonzo 431282516Sianuint32_t 432282516Sianimx_ccm_get_cacrr(void) 433282516Sian{ 434282516Sian 435282516Sian return (RD4(ccm_sc, CCM_CACCR)); 436282516Sian} 437282516Sian 438282516Sianvoid 439282516Sianimx_ccm_set_cacrr(uint32_t divisor) 440282516Sian{ 441282516Sian 442282516Sian WR4(ccm_sc, CCM_CACCR, divisor); 443282516Sian} 444282516Sian 445257453Sianstatic device_method_t ccm_methods[] = { 446257453Sian /* Device interface */ 447257453Sian DEVMETHOD(device_probe, ccm_probe), 448257453Sian DEVMETHOD(device_attach, ccm_attach), 449257453Sian DEVMETHOD(device_detach, ccm_detach), 450257453Sian 451257453Sian DEVMETHOD_END 452257453Sian}; 453257453Sian 454257453Sianstatic driver_t ccm_driver = { 455257453Sian "ccm", 456257453Sian ccm_methods, 457257453Sian sizeof(struct ccm_softc) 458257453Sian}; 459257453Sian 460257453Sianstatic devclass_t ccm_devclass; 461257453Sian 462273353SianEARLY_DRIVER_MODULE(ccm, simplebus, ccm_driver, ccm_devclass, 0, 0, 463273353Sian BUS_PASS_CPU + BUS_PASS_ORDER_EARLY); 464257453Sian 465