The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/freescale/imx/imx6_ccm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2013 Ian Lepore <ian@freebsd.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 /*
   33  * Clocks and power control driver for Freescale i.MX6 family of SoCs.
   34  */
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/kernel.h>
   39 #include <sys/module.h>
   40 #include <sys/bus.h>
   41 #include <sys/rman.h>
   42 
   43 #include <dev/ofw/ofw_bus.h>
   44 #include <dev/ofw/ofw_bus_subr.h>
   45 
   46 #include <machine/bus.h>
   47 
   48 #include <arm/freescale/imx/imx6_anatopreg.h>
   49 #include <arm/freescale/imx/imx6_anatopvar.h>
   50 #include <arm/freescale/imx/imx6_ccmreg.h>
   51 #include <arm/freescale/imx/imx_machdep.h>
   52 #include <arm/freescale/imx/imx_ccmvar.h>
   53 
   54 #ifndef CCGR_CLK_MODE_ALWAYS
   55 #define CCGR_CLK_MODE_OFF               0
   56 #define CCGR_CLK_MODE_RUNMODE           1
   57 #define CCGR_CLK_MODE_ALWAYS            3
   58 #endif
   59 
   60 struct ccm_softc {
   61         device_t        dev;
   62         struct resource *mem_res;
   63 };
   64 
   65 static struct ccm_softc *ccm_sc;
   66 
   67 static inline uint32_t
   68 RD4(struct ccm_softc *sc, bus_size_t off)
   69 {
   70 
   71         return (bus_read_4(sc->mem_res, off));
   72 }
   73 
   74 static inline void
   75 WR4(struct ccm_softc *sc, bus_size_t off, uint32_t val)
   76 {
   77 
   78         bus_write_4(sc->mem_res, off, val);
   79 }
   80 
   81 /*
   82  * Until we have a fully functional ccm driver which implements the fdt_clock
   83  * interface, use the age-old workaround of unconditionally enabling the clocks
   84  * for devices we might need to use.  The SoC defaults to most clocks enabled,
   85  * but the rom boot code and u-boot disable a few of them.  We turn on only
   86  * what's needed to run the chip plus devices we have drivers for, and turn off
   87  * devices we don't yet have drivers for.  (Note that USB is not turned on here
   88  * because that is one we do when the driver asks for it.)
   89  */
   90 static void
   91 ccm_init_gates(struct ccm_softc *sc)
   92 {
   93         uint32_t reg;
   94 
   95         /* ahpbdma, aipstz 1 & 2 buses */
   96         reg = CCGR0_AIPS_TZ1 | CCGR0_AIPS_TZ2 | CCGR0_ABPHDMA;
   97         WR4(sc, CCM_CCGR0, reg);
   98 
   99         /* enet, epit, gpt, spi */
  100         reg = CCGR1_ENET | CCGR1_EPIT1 | CCGR1_GPT | CCGR1_ECSPI1 |
  101             CCGR1_ECSPI2 | CCGR1_ECSPI3 | CCGR1_ECSPI4 | CCGR1_ECSPI5;
  102         WR4(sc, CCM_CCGR1, reg);
  103 
  104         /* ipmux & ipsync (bridges), iomux, i2c */
  105         reg = CCGR2_I2C1 | CCGR2_I2C2 | CCGR2_I2C3 | CCGR2_IIM |
  106             CCGR2_IOMUX_IPT | CCGR2_IPMUX1 | CCGR2_IPMUX2 | CCGR2_IPMUX3 |
  107             CCGR2_IPSYNC_IP2APB_TZASC1 | CCGR2_IPSYNC_IP2APB_TZASC2 |
  108             CCGR2_IPSYNC_VDOA;
  109         WR4(sc, CCM_CCGR2, reg);
  110 
  111         /* DDR memory controller */
  112         reg = CCGR3_OCRAM | CCGR3_MMDC_CORE_IPG |
  113             CCGR3_MMDC_CORE_ACLK_FAST | CCGR3_CG11 | CCGR3_CG13;
  114         WR4(sc, CCM_CCGR3, reg);
  115 
  116         /* pl301 bus crossbar */
  117         reg = CCGR4_PL301_MX6QFAST1_S133 |
  118             CCGR4_PL301_MX6QPER1_BCH | CCGR4_PL301_MX6QPER2_MAIN;
  119         WR4(sc, CCM_CCGR4, reg);
  120 
  121         /* uarts, ssi, sdma */
  122         reg = CCGR5_SDMA | CCGR5_SSI1 | CCGR5_SSI2 | CCGR5_SSI3 |
  123             CCGR5_UART | CCGR5_UART_SERIAL;
  124         WR4(sc, CCM_CCGR5, reg);
  125 
  126         /* usdhc 1-4, usboh3 */
  127         reg = CCGR6_USBOH3 | CCGR6_USDHC1 | CCGR6_USDHC2 |
  128             CCGR6_USDHC3 | CCGR6_USDHC4;
  129         WR4(sc, CCM_CCGR6, reg);
  130 }
  131 
  132 static int
  133 ccm_detach(device_t dev)
  134 {
  135         struct ccm_softc *sc;
  136 
  137         sc = device_get_softc(dev);
  138 
  139         if (sc->mem_res != NULL)
  140                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
  141 
  142         return (0);
  143 }
  144 
  145 static int
  146 ccm_attach(device_t dev)
  147 {
  148         struct ccm_softc *sc;
  149         int err, rid;
  150         uint32_t reg;
  151 
  152         sc = device_get_softc(dev);
  153         err = 0;
  154 
  155         /* Allocate bus_space resources. */
  156         rid = 0;
  157         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  158             RF_ACTIVE);
  159         if (sc->mem_res == NULL) {
  160                 device_printf(dev, "Cannot allocate memory resources\n");
  161                 err = ENXIO;
  162                 goto out;
  163         }
  164 
  165         ccm_sc = sc;
  166 
  167         /*
  168          * Configure the Low Power Mode setting to leave the ARM core power on
  169          * when a WFI instruction is executed.  This lets the MPCore timers and
  170          * GIC continue to run, which is helpful when the only thing that can
  171          * wake you up is an MPCore Private Timer interrupt delivered via GIC.
  172          *
  173          * XXX Based on the docs, setting CCM_CGPR_INT_MEM_CLK_LPM shouldn't be
  174          * required when the LPM bits are set to LPM_RUN.  But experimentally
  175          * I've experienced a fairly rare lockup when not setting it.  I was
  176          * unable to prove conclusively that the lockup was related to power
  177          * management or that this definitively fixes it.  Revisit this.
  178          */
  179         reg = RD4(sc, CCM_CGPR);
  180         reg |= CCM_CGPR_INT_MEM_CLK_LPM;
  181         WR4(sc, CCM_CGPR, reg);
  182         reg = RD4(sc, CCM_CLPCR);
  183         reg = (reg & ~CCM_CLPCR_LPM_MASK) | CCM_CLPCR_LPM_RUN;
  184         WR4(sc, CCM_CLPCR, reg);
  185 
  186         ccm_init_gates(sc);
  187 
  188         err = 0;
  189 
  190 out:
  191 
  192         if (err != 0)
  193                 ccm_detach(dev);
  194 
  195         return (err);
  196 }
  197 
  198 static int
  199 ccm_probe(device_t dev)
  200 {
  201 
  202         if (!ofw_bus_status_okay(dev))
  203                 return (ENXIO);
  204 
  205         if (ofw_bus_is_compatible(dev, "fsl,imx6q-ccm") == 0)
  206                 return (ENXIO);
  207 
  208         device_set_desc(dev, "Freescale i.MX6 Clock Control Module");
  209 
  210         return (BUS_PROBE_DEFAULT);
  211 }
  212 
  213 void
  214 imx_ccm_ssi_configure(device_t _ssidev)
  215 {
  216         struct ccm_softc *sc;
  217         uint32_t reg;
  218 
  219         sc = ccm_sc;
  220 
  221         /*
  222          * Select PLL4 (Audio PLL) clock multiplexer as source.
  223          * PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM).
  224          */
  225 
  226         reg = RD4(sc, CCM_CSCMR1);
  227         reg &= ~(SSI_CLK_SEL_M << SSI1_CLK_SEL_S);
  228         reg |= (SSI_CLK_SEL_PLL4 << SSI1_CLK_SEL_S);
  229         reg &= ~(SSI_CLK_SEL_M << SSI2_CLK_SEL_S);
  230         reg |= (SSI_CLK_SEL_PLL4 << SSI2_CLK_SEL_S);
  231         reg &= ~(SSI_CLK_SEL_M << SSI3_CLK_SEL_S);
  232         reg |= (SSI_CLK_SEL_PLL4 << SSI3_CLK_SEL_S);
  233         WR4(sc, CCM_CSCMR1, reg);
  234 
  235         /*
  236          * Ensure we have set hardware-default values
  237          * for pre and post dividers.
  238          */
  239 
  240         /* SSI1 and SSI3 */
  241         reg = RD4(sc, CCM_CS1CDR);
  242         /* Divide by 2 */
  243         reg &= ~(SSI_CLK_PODF_MASK << SSI1_CLK_PODF_SHIFT);
  244         reg &= ~(SSI_CLK_PODF_MASK << SSI3_CLK_PODF_SHIFT);
  245         reg |= (0x1 << SSI1_CLK_PODF_SHIFT);
  246         reg |= (0x1 << SSI3_CLK_PODF_SHIFT);
  247         /* Divide by 4 */
  248         reg &= ~(SSI_CLK_PRED_MASK << SSI1_CLK_PRED_SHIFT);
  249         reg &= ~(SSI_CLK_PRED_MASK << SSI3_CLK_PRED_SHIFT);
  250         reg |= (0x3 << SSI1_CLK_PRED_SHIFT);
  251         reg |= (0x3 << SSI3_CLK_PRED_SHIFT);
  252         WR4(sc, CCM_CS1CDR, reg);
  253 
  254         /* SSI2 */
  255         reg = RD4(sc, CCM_CS2CDR);
  256         /* Divide by 2 */
  257         reg &= ~(SSI_CLK_PODF_MASK << SSI2_CLK_PODF_SHIFT);
  258         reg |= (0x1 << SSI2_CLK_PODF_SHIFT);
  259         /* Divide by 4 */
  260         reg &= ~(SSI_CLK_PRED_MASK << SSI2_CLK_PRED_SHIFT);
  261         reg |= (0x3 << SSI2_CLK_PRED_SHIFT);
  262         WR4(sc, CCM_CS2CDR, reg);
  263 }
  264 
  265 void
  266 imx_ccm_usb_enable(device_t _usbdev)
  267 {
  268 
  269         /*
  270          * For imx6, the USBOH3 clock gate is bits 0-1 of CCGR6, so no need for
  271          * shifting and masking here, just set the low-order two bits to ALWAYS.
  272          */
  273         WR4(ccm_sc, CCM_CCGR6, RD4(ccm_sc, CCM_CCGR6) | CCGR_CLK_MODE_ALWAYS);
  274 }
  275 
  276 void
  277 imx_ccm_usbphy_enable(device_t _phydev)
  278 {
  279         /*
  280          * XXX Which unit?
  281          * Right now it's not clear how to figure from fdt data which phy unit
  282          * we're supposed to operate on.  Until this is worked out, just enable
  283          * both PHYs.
  284          */
  285 #if 0
  286         int phy_num, regoff;
  287 
  288         phy_num = 0; /* XXX */
  289 
  290         switch (phy_num) {
  291         case 0:
  292                 regoff = 0;
  293                 break;
  294         case 1:
  295                 regoff = 0x10;
  296                 break;
  297         default:
  298                 device_printf(ccm_sc->dev, "Bad PHY number %u,\n", 
  299                     phy_num);
  300                 return;
  301         }
  302 
  303         imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + regoff, 
  304             IMX6_ANALOG_CCM_PLL_USB_ENABLE | 
  305             IMX6_ANALOG_CCM_PLL_USB_POWER |
  306             IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS);
  307 #else
  308         imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + 0,
  309             IMX6_ANALOG_CCM_PLL_USB_ENABLE | 
  310             IMX6_ANALOG_CCM_PLL_USB_POWER |
  311             IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS);
  312 
  313         imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_USB1 + 0x10, 
  314             IMX6_ANALOG_CCM_PLL_USB_ENABLE | 
  315             IMX6_ANALOG_CCM_PLL_USB_POWER |
  316             IMX6_ANALOG_CCM_PLL_USB_EN_USB_CLKS);
  317 #endif
  318 }
  319 
  320 int
  321 imx6_ccm_sata_enable(void)
  322 {
  323         uint32_t v;
  324         int timeout;
  325 
  326         /* Un-gate the sata controller. */
  327         WR4(ccm_sc, CCM_CCGR5, RD4(ccm_sc, CCM_CCGR5) | CCGR5_SATA);
  328 
  329         /* Power up the PLL that feeds ENET/SATA/PCI phys, wait for lock. */
  330         v = RD4(ccm_sc, CCM_ANALOG_PLL_ENET);
  331         v &= ~CCM_ANALOG_PLL_ENET_POWERDOWN;
  332         WR4(ccm_sc, CCM_ANALOG_PLL_ENET, v);
  333 
  334         for (timeout = 100000; timeout > 0; timeout--) {
  335                 if (RD4(ccm_sc, CCM_ANALOG_PLL_ENET) &
  336                    CCM_ANALOG_PLL_ENET_LOCK) {
  337                         break;
  338                 }
  339         }
  340         if (timeout <= 0) {
  341                 return ETIMEDOUT;
  342         }
  343 
  344         /* Enable the PLL, and enable its 100mhz output. */
  345         v |= CCM_ANALOG_PLL_ENET_ENABLE;
  346         v &= ~CCM_ANALOG_PLL_ENET_BYPASS;
  347         WR4(ccm_sc, CCM_ANALOG_PLL_ENET, v);
  348 
  349         v |= CCM_ANALOG_PLL_ENET_ENABLE_100M;
  350         WR4(ccm_sc, CCM_ANALOG_PLL_ENET, v);
  351 
  352         return 0;
  353 }
  354 
  355 uint32_t
  356 imx_ccm_ecspi_hz(void)
  357 {
  358 
  359         return (60000000);
  360 }
  361 
  362 uint32_t
  363 imx_ccm_ipg_hz(void)
  364 {
  365 
  366         return (66000000);
  367 }
  368 
  369 uint32_t
  370 imx_ccm_perclk_hz(void)
  371 {
  372 
  373         return (66000000);
  374 }
  375 
  376 uint32_t
  377 imx_ccm_sdhci_hz(void)
  378 {
  379 
  380         return (200000000);
  381 }
  382 
  383 uint32_t
  384 imx_ccm_uart_hz(void)
  385 {
  386 
  387         return (80000000);
  388 }
  389 
  390 uint32_t
  391 imx_ccm_ahb_hz(void)
  392 {
  393         return (132000000);
  394 }
  395 
  396 int
  397 imx_ccm_pll_video_enable(void)
  398 {
  399         uint32_t reg;
  400         int timeout;
  401 
  402         /* Power down PLL */
  403         reg = RD4(ccm_sc, CCM_ANALOG_PLL_VIDEO);
  404         reg &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;
  405         WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO, reg);
  406 
  407         /*
  408          * Fvideo = Fref * (37 + 11/12) / 2
  409          * Fref = 24MHz, Fvideo = 455MHz
  410          */
  411         reg &= ~CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_MASK;
  412         reg |= CCM_ANALOG_PLL_VIDEO_POST_DIV_2;
  413         reg &= ~CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK;
  414         reg |= 37 << CCM_ANALOG_PLL_VIDEO_DIV_SELECT_SHIFT;
  415         WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO, reg);
  416 
  417         WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO_NUM, 11);
  418         WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO_DENOM, 12);
  419 
  420         /* Power up and wait for PLL lock down */
  421         reg = RD4(ccm_sc, CCM_ANALOG_PLL_VIDEO);
  422         reg &= ~CCM_ANALOG_PLL_VIDEO_POWERDOWN;
  423         WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO, reg);
  424 
  425         for (timeout = 100000; timeout > 0; timeout--) {
  426                 if (RD4(ccm_sc, CCM_ANALOG_PLL_VIDEO) &
  427                    CCM_ANALOG_PLL_VIDEO_LOCK) {
  428                         break;
  429                 }
  430         }
  431         if (timeout <= 0) {
  432                 return ETIMEDOUT;
  433         }
  434 
  435         /* Enable the PLL */
  436         reg |= CCM_ANALOG_PLL_VIDEO_ENABLE;
  437         reg &= ~CCM_ANALOG_PLL_VIDEO_BYPASS;
  438         WR4(ccm_sc, CCM_ANALOG_PLL_VIDEO, reg);
  439 
  440         return (0);
  441 }
  442 
  443 void
  444 imx_ccm_ipu_enable(int ipu)
  445 {
  446         struct ccm_softc *sc;
  447         uint32_t reg;
  448 
  449         sc = ccm_sc;
  450         reg = RD4(sc, CCM_CCGR3);
  451         if (ipu == 1)
  452                 reg |= CCGR3_IPU1_IPU | CCGR3_IPU1_DI0;
  453         else
  454                 reg |= CCGR3_IPU2_IPU | CCGR3_IPU2_DI0;
  455         WR4(sc, CCM_CCGR3, reg);
  456 
  457         /* Set IPU1_DI0 clock to source from PLL5 and divide it by 3 */
  458         reg = RD4(sc, CCM_CHSCCDR);
  459         reg &= ~(CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK |
  460             CHSCCDR_IPU1_DI0_PODF_MASK | CHSCCDR_IPU1_DI0_CLK_SEL_MASK);
  461         reg |= (CHSCCDR_PODF_DIVIDE_BY_3 << CHSCCDR_IPU1_DI0_PODF_SHIFT);
  462         reg |= (CHSCCDR_IPU_PRE_CLK_PLL5 << CHSCCDR_IPU1_DI0_PRE_CLK_SEL_SHIFT);
  463         WR4(sc, CCM_CHSCCDR, reg);
  464 
  465         reg |= (CHSCCDR_CLK_SEL_PREMUXED << CHSCCDR_IPU1_DI0_CLK_SEL_SHIFT);
  466         WR4(sc, CCM_CHSCCDR, reg);
  467 }
  468 
  469 uint32_t
  470 imx_ccm_ipu_hz(void)
  471 {
  472 
  473         return (455000000 / 3);
  474 }
  475 
  476 void
  477 imx_ccm_hdmi_enable(void)
  478 {
  479         struct ccm_softc *sc;
  480         uint32_t reg;
  481 
  482         sc = ccm_sc;
  483         reg = RD4(sc, CCM_CCGR2);
  484         reg |= CCGR2_HDMI_TX | CCGR2_HDMI_TX_ISFR;
  485         WR4(sc, CCM_CCGR2, reg);
  486 }
  487 
  488 uint32_t
  489 imx_ccm_get_cacrr(void)
  490 {
  491 
  492         return (RD4(ccm_sc, CCM_CACCR));
  493 }
  494 
  495 void
  496 imx_ccm_set_cacrr(uint32_t divisor)
  497 {
  498 
  499         WR4(ccm_sc, CCM_CACCR, divisor);
  500 }
  501 
  502 static device_method_t ccm_methods[] = {
  503         /* Device interface */
  504         DEVMETHOD(device_probe,  ccm_probe),
  505         DEVMETHOD(device_attach, ccm_attach),
  506         DEVMETHOD(device_detach, ccm_detach),
  507 
  508         DEVMETHOD_END
  509 };
  510 
  511 static driver_t ccm_driver = {
  512         "ccm",
  513         ccm_methods,
  514         sizeof(struct ccm_softc)
  515 };
  516 
  517 EARLY_DRIVER_MODULE(ccm, simplebus, ccm_driver, 0, 0, 
  518     BUS_PASS_CPU + BUS_PASS_ORDER_EARLY);

Cache object: 9e05b596631aca583ec505f6d7e0157b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.