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/imx51_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 /*      $NetBSD: imx51_ccm.c,v 1.1 2012/04/17 09:33:31 bsh Exp $        */
    2 /*-
    3  * SPDX-License-Identifier: BSD-2-Clause AND BSD-2-Clause-FreeBSD
    4  *
    5  * Copyright (c) 2010, 2011, 2012  Genetec Corporation.  All rights reserved.
    6  * Written by Hashimoto Kenichi for Genetec Corporation.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
   21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   27  * POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 
   30 /*-
   31  * Copyright (c) 2012, 2013 The FreeBSD Foundation
   32  * All rights reserved.
   33  *
   34  * Portions of this software were developed by Oleksandr Rybalko
   35  * under sponsorship from the FreeBSD Foundation.
   36  *
   37  * Redistribution and use in source and binary forms, with or without
   38  * modification, are permitted provided that the following conditions
   39  * are met:
   40  * 1.   Redistributions of source code must retain the above copyright
   41  *      notice, this list of conditions and the following disclaimer.
   42  * 2.   Redistributions in binary form must reproduce the above copyright
   43  *      notice, this list of conditions and the following disclaimer in the
   44  *      documentation and/or other materials provided with the distribution.
   45  *
   46  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   49  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   50  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   56  * SUCH DAMAGE.
   57  */
   58 
   59 /*
   60  * Clock Controller Module (CCM)
   61  */
   62 
   63 #include <sys/cdefs.h>
   64 __FBSDID("$FreeBSD$");
   65 
   66 #include <sys/param.h>
   67 #include <sys/systm.h>
   68 #include <sys/bus.h>
   69 #include <sys/kernel.h>
   70 #include <sys/module.h>
   71 #include <sys/malloc.h>
   72 #include <sys/rman.h>
   73 #include <machine/bus.h>
   74 #include <machine/cpu.h>
   75 #include <machine/intr.h>
   76 
   77 #include <dev/ofw/openfirm.h>
   78 #include <dev/ofw/ofw_bus.h>
   79 #include <dev/ofw/ofw_bus_subr.h>
   80 
   81 #include <machine/bus.h>
   82 #include <machine/fdt.h>
   83 
   84 #include <arm/freescale/imx/imx51_ccmvar.h>
   85 #include <arm/freescale/imx/imx51_ccmreg.h>
   86 #include <arm/freescale/imx/imx51_dpllreg.h>
   87 #include <arm/freescale/imx/imx_ccmvar.h>
   88 #include <arm/freescale/imx/imx_machdep.h>
   89 
   90 #define IMXCCMDEBUG
   91 #undef  IMXCCMDEBUG
   92 
   93 #ifndef IMX51_OSC_FREQ
   94 #define IMX51_OSC_FREQ  (24 * 1000 * 1000)      /* 24MHz */
   95 #endif
   96 
   97 #ifndef IMX51_CKIL_FREQ
   98 #define IMX51_CKIL_FREQ 32768
   99 #endif
  100 
  101 /*
  102  * The fdt data does not provide reg properties describing the DPLL register
  103  * blocks we need to access, presumably because the needed addresses are
  104  * hard-coded within the linux driver.  That leaves us with no choice but to do
  105  * the same thing, if we want to run with vendor-supplied fdt data.  So here we
  106  * have tables of the physical addresses we need for each soc, and we'll use
  107  * bus_space_map() at attach() time to get access to them.
  108  */
  109 static uint32_t imx51_dpll_addrs[IMX51_N_DPLLS] = {
  110         0x83f80000,     /* DPLL1 */
  111         0x83f84000,     /* DPLL2 */
  112         0x83f88000,     /* DPLL3 */
  113 };
  114 
  115 static uint32_t imx53_dpll_addrs[IMX51_N_DPLLS] = {
  116         0x63f80000,     /* DPLL1 */
  117         0x63f84000,     /* DPLL2 */
  118         0x63f88000,     /* DPLL3 */
  119 };
  120 
  121 #define DPLL_REGS_SZ    (16 * 1024)
  122 
  123 struct imxccm_softc {
  124         device_t        sc_dev;
  125         struct resource *ccmregs;
  126         u_int64_t       pll_freq[IMX51_N_DPLLS];
  127         bus_space_tag_t    pllbst;
  128         bus_space_handle_t pllbsh[IMX51_N_DPLLS];
  129 };
  130 
  131 struct imxccm_softc *ccm_softc = NULL;
  132 
  133 static uint64_t imx51_get_pll_freq(u_int);
  134 
  135 static int imxccm_match(device_t);
  136 static int imxccm_attach(device_t);
  137 
  138 static device_method_t imxccm_methods[] = {
  139         DEVMETHOD(device_probe, imxccm_match),
  140         DEVMETHOD(device_attach, imxccm_attach),
  141 
  142         DEVMETHOD_END
  143 };
  144 
  145 static driver_t imxccm_driver = {
  146         "imxccm",
  147         imxccm_methods,
  148         sizeof(struct imxccm_softc),
  149 };
  150 
  151 static devclass_t imxccm_devclass;
  152 
  153 EARLY_DRIVER_MODULE(imxccm, simplebus, imxccm_driver, imxccm_devclass, 0, 0,
  154     BUS_PASS_CPU);
  155 
  156 static inline uint32_t
  157 pll_read_4(struct imxccm_softc *sc, int pll, int reg)
  158 {
  159 
  160         return (bus_space_read_4(sc->pllbst, sc->pllbsh[pll - 1], reg));
  161 }
  162 
  163 static inline uint32_t
  164 ccm_read_4(struct imxccm_softc *sc, int reg)
  165 {
  166 
  167         return (bus_read_4(sc->ccmregs, reg));
  168 }
  169 
  170 static inline void
  171 ccm_write_4(struct imxccm_softc *sc, int reg, uint32_t val)
  172 {
  173 
  174         bus_write_4(sc->ccmregs, reg, val);
  175 }
  176 
  177 static int
  178 imxccm_match(device_t dev)
  179 {
  180 
  181         if (!ofw_bus_status_okay(dev))
  182                 return (ENXIO);
  183 
  184         if (!ofw_bus_is_compatible(dev, "fsl,imx51-ccm") &&
  185             !ofw_bus_is_compatible(dev, "fsl,imx53-ccm"))
  186                 return (ENXIO);
  187 
  188         device_set_desc(dev, "Freescale Clock Control Module");
  189         return (BUS_PROBE_DEFAULT);
  190 }
  191 
  192 static int
  193 imxccm_attach(device_t dev)
  194 {
  195         struct imxccm_softc *sc;
  196         int idx;
  197         u_int soc;
  198         uint32_t *pll_addrs;
  199 
  200         sc = device_get_softc(dev);
  201         sc->sc_dev = dev;
  202 
  203         switch ((soc = imx_soc_type())) {
  204         case IMXSOC_51:
  205                 pll_addrs = imx51_dpll_addrs;
  206                 break;
  207         case IMXSOC_53:
  208                 pll_addrs = imx53_dpll_addrs;
  209                 break;
  210         default:
  211                 device_printf(dev, "No support for SoC type 0x%08x\n", soc);
  212                 goto noclocks;
  213         }
  214 
  215         idx = 0;
  216         sc->ccmregs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &idx,
  217             RF_ACTIVE);
  218         if (sc->ccmregs == NULL) {
  219                 device_printf(dev, "could not allocate resources\n");
  220                 goto noclocks;
  221         }
  222 
  223         sc->pllbst = fdtbus_bs_tag;
  224         for (idx = 0; idx < IMX51_N_DPLLS; ++idx) {
  225                 if (bus_space_map(sc->pllbst, pll_addrs[idx], DPLL_REGS_SZ, 0,
  226                     &sc->pllbsh[idx]) != 0) {
  227                         device_printf(dev, "Cannot map DPLL registers\n");
  228                         goto noclocks;
  229                 }
  230         }
  231 
  232         ccm_softc = sc;
  233 
  234         imx51_get_pll_freq(1);
  235         imx51_get_pll_freq(2);
  236         imx51_get_pll_freq(3);
  237 
  238         device_printf(dev, "PLL1=%lluMHz, PLL2=%lluMHz, PLL3=%lluMHz\n",
  239             sc->pll_freq[0] / 1000000,
  240             sc->pll_freq[1] / 1000000,
  241             sc->pll_freq[2] / 1000000);
  242         device_printf(dev, "CPU clock=%d, UART clock=%d\n",
  243             imx51_get_clock(IMX51CLK_ARM_ROOT),
  244             imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
  245         device_printf(dev,
  246             "mainbus clock=%d, ahb clock=%d ipg clock=%d perclk=%d\n",
  247             imx51_get_clock(IMX51CLK_MAIN_BUS_CLK),
  248             imx51_get_clock(IMX51CLK_AHB_CLK_ROOT),
  249             imx51_get_clock(IMX51CLK_IPG_CLK_ROOT),
  250             imx51_get_clock(IMX51CLK_PERCLK_ROOT));
  251 
  252         return (0);
  253 
  254 noclocks:
  255 
  256         panic("Cannot continue without clock support");
  257 }
  258 
  259 u_int
  260 imx51_get_clock(enum imx51_clock clk)
  261 {
  262         u_int freq;
  263         u_int sel;
  264         uint32_t cacrr; /* ARM clock root register */
  265         uint32_t ccsr;
  266         uint32_t cscdr1;
  267         uint32_t cscmr1;
  268         uint32_t cbcdr;
  269         uint32_t cbcmr;
  270         uint32_t cdcr;
  271 
  272         if (ccm_softc == NULL)
  273                 return (0);
  274 
  275         switch (clk) {
  276         case IMX51CLK_PLL1:
  277         case IMX51CLK_PLL2:
  278         case IMX51CLK_PLL3:
  279                 return ccm_softc->pll_freq[clk-IMX51CLK_PLL1];
  280         case IMX51CLK_PLL1SW:
  281                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
  282                 if ((ccsr & CCSR_PLL1_SW_CLK_SEL) == 0)
  283                         return ccm_softc->pll_freq[1-1];
  284                 /* step clock */
  285                 /* FALLTHROUGH */
  286         case IMX51CLK_PLL1STEP:
  287                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
  288                 switch ((ccsr & CCSR_STEP_SEL_MASK) >> CCSR_STEP_SEL_SHIFT) {
  289                 case 0:
  290                         return imx51_get_clock(IMX51CLK_LP_APM);
  291                 case 1:
  292                         return 0; /* XXX PLL bypass clock */
  293                 case 2:
  294                         return ccm_softc->pll_freq[2-1] /
  295                             (1 + ((ccsr & CCSR_PLL2_DIV_PODF_MASK) >>
  296                                 CCSR_PLL2_DIV_PODF_SHIFT));
  297                 case 3:
  298                         return ccm_softc->pll_freq[3-1] /
  299                             (1 + ((ccsr & CCSR_PLL3_DIV_PODF_MASK) >>
  300                                 CCSR_PLL3_DIV_PODF_SHIFT));
  301                 }
  302                 /*NOTREACHED*/
  303         case IMX51CLK_PLL2SW:
  304                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
  305                 if ((ccsr & CCSR_PLL2_SW_CLK_SEL) == 0)
  306                         return imx51_get_clock(IMX51CLK_PLL2);
  307                 return 0; /* XXX PLL2 bypass clk */
  308         case IMX51CLK_PLL3SW:
  309                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
  310                 if ((ccsr & CCSR_PLL3_SW_CLK_SEL) == 0)
  311                         return imx51_get_clock(IMX51CLK_PLL3);
  312                 return 0; /* XXX PLL3 bypass clk */
  313 
  314         case IMX51CLK_LP_APM:
  315                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
  316                 return (ccsr & CCSR_LP_APM) ?
  317                             imx51_get_clock(IMX51CLK_FPM) : IMX51_OSC_FREQ;
  318 
  319         case IMX51CLK_ARM_ROOT:
  320                 freq = imx51_get_clock(IMX51CLK_PLL1SW);
  321                 cacrr = ccm_read_4(ccm_softc, CCMC_CACRR);
  322                 return freq / (cacrr + 1);
  323 
  324                 /* ... */
  325         case IMX51CLK_MAIN_BUS_CLK_SRC:
  326                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
  327                 if ((cbcdr & CBCDR_PERIPH_CLK_SEL) == 0)
  328                         freq = imx51_get_clock(IMX51CLK_PLL2SW);
  329                 else {
  330                         freq = 0;
  331                         cbcmr = ccm_read_4(ccm_softc,  CCMC_CBCMR);
  332                         switch ((cbcmr & CBCMR_PERIPH_APM_SEL_MASK) >>
  333                                 CBCMR_PERIPH_APM_SEL_SHIFT) {
  334                         case 0:
  335                                 freq = imx51_get_clock(IMX51CLK_PLL1SW);
  336                                 break;
  337                         case 1:
  338                                 freq = imx51_get_clock(IMX51CLK_PLL3SW);
  339                                 break;
  340                         case 2:
  341                                 freq = imx51_get_clock(IMX51CLK_LP_APM);
  342                                 break;
  343                         case 3:
  344                                 /* XXX: error */
  345                                 break;
  346                         }
  347                 }
  348                 return freq;
  349         case IMX51CLK_MAIN_BUS_CLK:
  350                 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
  351                 cdcr = ccm_read_4(ccm_softc, CCMC_CDCR);
  352                 return freq / (1 + ((cdcr & CDCR_PERIPH_CLK_DVFS_PODF_MASK) >>
  353                         CDCR_PERIPH_CLK_DVFS_PODF_SHIFT));
  354         case IMX51CLK_AHB_CLK_ROOT:
  355                 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK);
  356                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
  357                 return freq / (1 + ((cbcdr & CBCDR_AHB_PODF_MASK) >>
  358                                     CBCDR_AHB_PODF_SHIFT));
  359         case IMX51CLK_IPG_CLK_ROOT:
  360                 freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
  361                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
  362                 return freq / (1 + ((cbcdr & CBCDR_IPG_PODF_MASK) >>
  363                                     CBCDR_IPG_PODF_SHIFT));
  364 
  365         case IMX51CLK_PERCLK_ROOT:
  366                 cbcmr = ccm_read_4(ccm_softc, CCMC_CBCMR);
  367                 if (cbcmr & CBCMR_PERCLK_IPG_SEL)
  368                         return imx51_get_clock(IMX51CLK_IPG_CLK_ROOT);
  369                 if (cbcmr & CBCMR_PERCLK_LP_APM_SEL)
  370                         freq = imx51_get_clock(IMX51CLK_LP_APM);
  371                 else
  372                         freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
  373                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
  374 
  375 #ifdef IMXCCMDEBUG
  376                 printf("cbcmr=%x cbcdr=%x\n", cbcmr, cbcdr);
  377 #endif
  378 
  379                 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED1_MASK) >>
  380                         CBCDR_PERCLK_PRED1_SHIFT);
  381                 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED2_MASK) >>
  382                         CBCDR_PERCLK_PRED2_SHIFT);
  383                 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PODF_MASK) >>
  384                         CBCDR_PERCLK_PODF_SHIFT);
  385                 return freq;
  386         case IMX51CLK_UART_CLK_ROOT:
  387                 cscdr1 = ccm_read_4(ccm_softc, CCMC_CSCDR1);
  388                 cscmr1 = ccm_read_4(ccm_softc, CCMC_CSCMR1);
  389 
  390 #ifdef IMXCCMDEBUG
  391                 printf("cscdr1=%x cscmr1=%x\n", cscdr1, cscmr1);
  392 #endif
  393 
  394                 sel = (cscmr1 & CSCMR1_UART_CLK_SEL_MASK) >>
  395                     CSCMR1_UART_CLK_SEL_SHIFT;
  396 
  397                 freq = 0; /* shut up GCC */
  398                 switch (sel) {
  399                 case 0:
  400                 case 1:
  401                 case 2:
  402                         freq = imx51_get_clock(IMX51CLK_PLL1SW + sel);
  403                         break;
  404                 case 3:
  405                         freq = imx51_get_clock(IMX51CLK_LP_APM);
  406                         break;
  407                 }
  408 
  409                 return freq / (1 + ((cscdr1 & CSCDR1_UART_CLK_PRED_MASK) >>
  410                         CSCDR1_UART_CLK_PRED_SHIFT)) /
  411                     (1 + ((cscdr1 & CSCDR1_UART_CLK_PODF_MASK) >>
  412                         CSCDR1_UART_CLK_PODF_SHIFT));
  413         case IMX51CLK_IPU_HSP_CLK_ROOT:
  414                 freq = 0;
  415                 cbcmr = ccm_read_4(ccm_softc,  CCMC_CBCMR);
  416                 switch ((cbcmr & CBCMR_IPU_HSP_CLK_SEL_MASK) >>
  417                                 CBCMR_IPU_HSP_CLK_SEL_SHIFT) {
  418                         case 0:
  419                                 freq = imx51_get_clock(IMX51CLK_ARM_AXI_A_CLK);
  420                                 break;
  421                         case 1:
  422                                 freq = imx51_get_clock(IMX51CLK_ARM_AXI_B_CLK);
  423                                 break;
  424                         case 2:
  425                                 freq = imx51_get_clock(
  426                                         IMX51CLK_EMI_SLOW_CLK_ROOT);
  427                                 break;
  428                         case 3:
  429                                 freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
  430                                 break;
  431                         }
  432                 return freq;
  433         default:
  434                 device_printf(ccm_softc->sc_dev,
  435                     "clock %d: not supported yet\n", clk);
  436                 return 0;
  437         }
  438 }
  439 
  440 static uint64_t
  441 imx51_get_pll_freq(u_int pll_no)
  442 {
  443         uint32_t dp_ctrl;
  444         uint32_t dp_op;
  445         uint32_t dp_mfd;
  446         uint32_t dp_mfn;
  447         uint32_t mfi;
  448         int32_t mfn;
  449         uint32_t mfd;
  450         uint32_t pdf;
  451         uint32_t ccr;
  452         uint64_t freq = 0;
  453         u_int ref = 0;
  454 
  455         KASSERT(1 <= pll_no && pll_no <= IMX51_N_DPLLS, ("Wrong PLL id"));
  456 
  457         dp_ctrl = pll_read_4(ccm_softc, pll_no, DPLL_DP_CTL);
  458 
  459         if (dp_ctrl & DP_CTL_HFSM) {
  460                 dp_op  = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_OP);
  461                 dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFD);
  462                 dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFN);
  463         } else {
  464                 dp_op  = pll_read_4(ccm_softc, pll_no, DPLL_DP_OP);
  465                 dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFD);
  466                 dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFN);
  467         }
  468 
  469         pdf = dp_op & DP_OP_PDF_MASK;
  470         mfi = max(5, (dp_op & DP_OP_MFI_MASK) >> DP_OP_MFI_SHIFT);
  471         mfd = dp_mfd;
  472         if (dp_mfn & 0x04000000)
  473                 /* 27bit signed value */
  474                 mfn = (uint32_t)(0xf8000000 | dp_mfn);
  475         else
  476                 mfn = dp_mfn;
  477 
  478         switch (dp_ctrl &  DP_CTL_REF_CLK_SEL_MASK) {
  479         case DP_CTL_REF_CLK_SEL_COSC:
  480                 /* Internal Oscillator */
  481                 /* TODO: get from FDT "fsl,imx-osc" */
  482                 ref = 24000000; /* IMX51_OSC_FREQ */
  483                 break;
  484         case DP_CTL_REF_CLK_SEL_FPM:
  485                 ccr = ccm_read_4(ccm_softc, CCMC_CCR);
  486                 if (ccr & CCR_FPM_MULT)
  487                 /* TODO: get from FDT "fsl,imx-ckil" */
  488                         ref = 32768 * 1024;
  489                 else
  490                 /* TODO: get from FDT "fsl,imx-ckil" */
  491                         ref = 32768 * 512;
  492                 break;
  493         default:
  494                 ref = 0;
  495         }
  496 
  497         if (dp_ctrl & DP_CTL_REF_CLK_DIV)
  498                 ref /= 2;
  499 
  500         ref *= 4;
  501         freq = (int64_t)ref * mfi + (int64_t)ref * mfn / (mfd + 1);
  502         freq /= pdf + 1;
  503 
  504         if (!(dp_ctrl & DP_CTL_DPDCK0_2_EN))
  505                 freq /= 2;
  506 
  507 #ifdef IMXCCMDEBUG
  508         printf("ref: %dKHz ", ref);
  509         printf("dp_ctl: %08x ", dp_ctrl);
  510         printf("pdf: %3d ", pdf);
  511         printf("mfi: %3d ", mfi);
  512         printf("mfd: %3d ", mfd);
  513         printf("mfn: %3d ", mfn);
  514         printf("pll: %d\n", (uint32_t)freq);
  515 #endif
  516 
  517         ccm_softc->pll_freq[pll_no-1] = freq;
  518 
  519         return (freq);
  520 }
  521 
  522 void
  523 imx51_clk_gating(int clk_src, int mode)
  524 {
  525         int field, group;
  526         uint32_t reg;
  527 
  528         group = CCMR_CCGR_MODULE(clk_src);
  529         field = clk_src % CCMR_CCGR_NSOURCE;
  530         reg = ccm_read_4(ccm_softc, CCMC_CCGR(group));
  531         reg &= ~(0x03 << field * 2);
  532         reg |= (mode << field * 2);
  533         ccm_write_4(ccm_softc, CCMC_CCGR(group), reg);
  534 }
  535 
  536 int
  537 imx51_get_clk_gating(int clk_src)
  538 {
  539         uint32_t reg;
  540 
  541         reg = ccm_read_4(ccm_softc,
  542             CCMC_CCGR(CCMR_CCGR_MODULE(clk_src)));
  543         return ((reg >> (clk_src % CCMR_CCGR_NSOURCE) * 2) & 0x03);
  544 }
  545 
  546 /*
  547  * Code from here down is temporary, in lieu of a SoC-independent clock API.
  548  */
  549 
  550 void
  551 imx_ccm_usb_enable(device_t dev)
  552 {
  553         uint32_t regval;
  554 
  555         /*
  556          * Select PLL2 as the source for the USB clock.
  557          * The default is PLL3, but U-boot changes it to PLL2.
  558          */
  559         regval = ccm_read_4(ccm_softc, CCMC_CSCMR1);
  560         regval &= ~CSCMR1_USBOH3_CLK_SEL_MASK;
  561         regval |= 1 << CSCMR1_USBOH3_CLK_SEL_SHIFT;
  562         ccm_write_4(ccm_softc, CCMC_CSCMR1, regval);
  563 
  564         /*
  565          * Set the USB clock pre-divider to div-by-5, post-divider to div-by-2.
  566          */
  567         regval = ccm_read_4(ccm_softc, CCMC_CSCDR1);
  568         regval &= ~CSCDR1_USBOH3_CLK_PODF_MASK;
  569         regval &= ~CSCDR1_USBOH3_CLK_PRED_MASK;
  570         regval |= 4 << CSCDR1_USBOH3_CLK_PRED_SHIFT;
  571         regval |= 1 << CSCDR1_USBOH3_CLK_PODF_SHIFT;
  572         ccm_write_4(ccm_softc, CCMC_CSCDR1, regval);
  573 
  574         /*
  575          * The same two clocks gates are used on imx51 and imx53.
  576          */
  577         imx51_clk_gating(CCGR_USBOH3_IPG_AHB_CLK, CCGR_CLK_MODE_ALWAYS);
  578         imx51_clk_gating(CCGR_USBOH3_60M_CLK, CCGR_CLK_MODE_ALWAYS);
  579 }
  580 
  581 void
  582 imx_ccm_usbphy_enable(device_t dev)
  583 {
  584         uint32_t regval;
  585 
  586         /*
  587          * Select PLL3 as the source for the USBPHY clock.  U-boot does this 
  588          * only for imx53, but the bit exists on imx51.  That seems a bit
  589          * strange, but we'll go with it until more is known.
  590          */
  591         if (imx_soc_type() == IMXSOC_53) {
  592                 regval = ccm_read_4(ccm_softc, CCMC_CSCMR1);
  593                 regval |= 1 << CSCMR1_USBPHY_CLK_SEL_SHIFT;
  594                 ccm_write_4(ccm_softc, CCMC_CSCMR1, regval);
  595         }
  596 
  597         /*
  598          * For the imx51 there's just one phy gate control, enable it.
  599          */
  600         if (imx_soc_type() == IMXSOC_51) {
  601                 imx51_clk_gating(CCGR_USB_PHY_CLK, CCGR_CLK_MODE_ALWAYS);
  602                 return;
  603         }
  604 
  605         /*
  606          * For imx53 we don't have a full set of clock defines yet, but the
  607          * datasheet says:
  608          *   gate reg 4, bits 13-12 usb ph2 clock (usb_phy2_clk_enable)
  609          *   gate reg 4, bits 11-10 usb ph1 clock (usb_phy1_clk_enable)
  610          *
  611          * We should use the fdt data for the device to figure out which of
  612          * the two we're working on, but for now just turn them both on.
  613          */
  614         if (imx_soc_type() == IMXSOC_53) {
  615                 imx51_clk_gating(__CCGR_NUM(4, 5), CCGR_CLK_MODE_ALWAYS);
  616                 imx51_clk_gating(__CCGR_NUM(4, 6), CCGR_CLK_MODE_ALWAYS);
  617                 return;
  618         }
  619 }
  620 
  621 uint32_t
  622 imx_ccm_ecspi_hz(void)
  623 {
  624 
  625         return (imx51_get_clock(IMX51CLK_CSPI_CLK_ROOT));
  626 }
  627 
  628 uint32_t
  629 imx_ccm_ipg_hz(void)
  630 {
  631 
  632         return (imx51_get_clock(IMX51CLK_IPG_CLK_ROOT));
  633 }
  634 
  635 uint32_t
  636 imx_ccm_sdhci_hz(void)
  637 {
  638 
  639         return (imx51_get_clock(IMX51CLK_ESDHC1_CLK_ROOT));
  640 }
  641 
  642 uint32_t
  643 imx_ccm_perclk_hz(void)
  644 {
  645 
  646         return (imx51_get_clock(IMX51CLK_PERCLK_ROOT));
  647 }
  648 
  649 uint32_t
  650 imx_ccm_uart_hz(void)
  651 {
  652 
  653         return (imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
  654 }
  655 
  656 uint32_t
  657 imx_ccm_ahb_hz(void)
  658 {
  659 
  660         return (imx51_get_clock(IMX51CLK_AHB_CLK_ROOT));
  661 }

Cache object: a4e2e1fc156fb7c719229297870a50fe


[ 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.