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 EARLY_DRIVER_MODULE(imxccm, simplebus, imxccm_driver, 0, 0, BUS_PASS_CPU);
  152 
  153 static inline uint32_t
  154 pll_read_4(struct imxccm_softc *sc, int pll, int reg)
  155 {
  156 
  157         return (bus_space_read_4(sc->pllbst, sc->pllbsh[pll - 1], reg));
  158 }
  159 
  160 static inline uint32_t
  161 ccm_read_4(struct imxccm_softc *sc, int reg)
  162 {
  163 
  164         return (bus_read_4(sc->ccmregs, reg));
  165 }
  166 
  167 static inline void
  168 ccm_write_4(struct imxccm_softc *sc, int reg, uint32_t val)
  169 {
  170 
  171         bus_write_4(sc->ccmregs, reg, val);
  172 }
  173 
  174 static int
  175 imxccm_match(device_t dev)
  176 {
  177 
  178         if (!ofw_bus_status_okay(dev))
  179                 return (ENXIO);
  180 
  181         if (!ofw_bus_is_compatible(dev, "fsl,imx51-ccm") &&
  182             !ofw_bus_is_compatible(dev, "fsl,imx53-ccm"))
  183                 return (ENXIO);
  184 
  185         device_set_desc(dev, "Freescale Clock Control Module");
  186         return (BUS_PROBE_DEFAULT);
  187 }
  188 
  189 static int
  190 imxccm_attach(device_t dev)
  191 {
  192         struct imxccm_softc *sc;
  193         int idx;
  194         u_int soc;
  195         uint32_t *pll_addrs;
  196 
  197         sc = device_get_softc(dev);
  198         sc->sc_dev = dev;
  199 
  200         switch ((soc = imx_soc_type())) {
  201         case IMXSOC_51:
  202                 pll_addrs = imx51_dpll_addrs;
  203                 break;
  204         case IMXSOC_53:
  205                 pll_addrs = imx53_dpll_addrs;
  206                 break;
  207         default:
  208                 device_printf(dev, "No support for SoC type 0x%08x\n", soc);
  209                 goto noclocks;
  210         }
  211 
  212         idx = 0;
  213         sc->ccmregs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &idx,
  214             RF_ACTIVE);
  215         if (sc->ccmregs == NULL) {
  216                 device_printf(dev, "could not allocate resources\n");
  217                 goto noclocks;
  218         }
  219 
  220         sc->pllbst = fdtbus_bs_tag;
  221         for (idx = 0; idx < IMX51_N_DPLLS; ++idx) {
  222                 if (bus_space_map(sc->pllbst, pll_addrs[idx], DPLL_REGS_SZ, 0,
  223                     &sc->pllbsh[idx]) != 0) {
  224                         device_printf(dev, "Cannot map DPLL registers\n");
  225                         goto noclocks;
  226                 }
  227         }
  228 
  229         ccm_softc = sc;
  230 
  231         imx51_get_pll_freq(1);
  232         imx51_get_pll_freq(2);
  233         imx51_get_pll_freq(3);
  234 
  235         device_printf(dev, "PLL1=%lluMHz, PLL2=%lluMHz, PLL3=%lluMHz\n",
  236             sc->pll_freq[0] / 1000000,
  237             sc->pll_freq[1] / 1000000,
  238             sc->pll_freq[2] / 1000000);
  239         device_printf(dev, "CPU clock=%d, UART clock=%d\n",
  240             imx51_get_clock(IMX51CLK_ARM_ROOT),
  241             imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
  242         device_printf(dev,
  243             "mainbus clock=%d, ahb clock=%d ipg clock=%d perclk=%d\n",
  244             imx51_get_clock(IMX51CLK_MAIN_BUS_CLK),
  245             imx51_get_clock(IMX51CLK_AHB_CLK_ROOT),
  246             imx51_get_clock(IMX51CLK_IPG_CLK_ROOT),
  247             imx51_get_clock(IMX51CLK_PERCLK_ROOT));
  248 
  249         return (0);
  250 
  251 noclocks:
  252 
  253         panic("Cannot continue without clock support");
  254 }
  255 
  256 u_int
  257 imx51_get_clock(enum imx51_clock clk)
  258 {
  259         u_int freq;
  260         u_int sel;
  261         uint32_t cacrr; /* ARM clock root register */
  262         uint32_t ccsr;
  263         uint32_t cscdr1;
  264         uint32_t cscmr1;
  265         uint32_t cbcdr;
  266         uint32_t cbcmr;
  267         uint32_t cdcr;
  268 
  269         if (ccm_softc == NULL)
  270                 return (0);
  271 
  272         switch (clk) {
  273         case IMX51CLK_PLL1:
  274         case IMX51CLK_PLL2:
  275         case IMX51CLK_PLL3:
  276                 return ccm_softc->pll_freq[clk-IMX51CLK_PLL1];
  277         case IMX51CLK_PLL1SW:
  278                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
  279                 if ((ccsr & CCSR_PLL1_SW_CLK_SEL) == 0)
  280                         return ccm_softc->pll_freq[1-1];
  281                 /* step clock */
  282                 /* FALLTHROUGH */
  283         case IMX51CLK_PLL1STEP:
  284                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
  285                 switch ((ccsr & CCSR_STEP_SEL_MASK) >> CCSR_STEP_SEL_SHIFT) {
  286                 case 0:
  287                         return imx51_get_clock(IMX51CLK_LP_APM);
  288                 case 1:
  289                         return 0; /* XXX PLL bypass clock */
  290                 case 2:
  291                         return ccm_softc->pll_freq[2-1] /
  292                             (1 + ((ccsr & CCSR_PLL2_DIV_PODF_MASK) >>
  293                                 CCSR_PLL2_DIV_PODF_SHIFT));
  294                 case 3:
  295                         return ccm_softc->pll_freq[3-1] /
  296                             (1 + ((ccsr & CCSR_PLL3_DIV_PODF_MASK) >>
  297                                 CCSR_PLL3_DIV_PODF_SHIFT));
  298                 }
  299                 /*NOTREACHED*/
  300         case IMX51CLK_PLL2SW:
  301                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
  302                 if ((ccsr & CCSR_PLL2_SW_CLK_SEL) == 0)
  303                         return imx51_get_clock(IMX51CLK_PLL2);
  304                 return 0; /* XXX PLL2 bypass clk */
  305         case IMX51CLK_PLL3SW:
  306                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
  307                 if ((ccsr & CCSR_PLL3_SW_CLK_SEL) == 0)
  308                         return imx51_get_clock(IMX51CLK_PLL3);
  309                 return 0; /* XXX PLL3 bypass clk */
  310 
  311         case IMX51CLK_LP_APM:
  312                 ccsr = ccm_read_4(ccm_softc, CCMC_CCSR);
  313                 return (ccsr & CCSR_LP_APM) ?
  314                             imx51_get_clock(IMX51CLK_FPM) : IMX51_OSC_FREQ;
  315 
  316         case IMX51CLK_ARM_ROOT:
  317                 freq = imx51_get_clock(IMX51CLK_PLL1SW);
  318                 cacrr = ccm_read_4(ccm_softc, CCMC_CACRR);
  319                 return freq / (cacrr + 1);
  320 
  321                 /* ... */
  322         case IMX51CLK_MAIN_BUS_CLK_SRC:
  323                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
  324                 if ((cbcdr & CBCDR_PERIPH_CLK_SEL) == 0)
  325                         freq = imx51_get_clock(IMX51CLK_PLL2SW);
  326                 else {
  327                         freq = 0;
  328                         cbcmr = ccm_read_4(ccm_softc,  CCMC_CBCMR);
  329                         switch ((cbcmr & CBCMR_PERIPH_APM_SEL_MASK) >>
  330                                 CBCMR_PERIPH_APM_SEL_SHIFT) {
  331                         case 0:
  332                                 freq = imx51_get_clock(IMX51CLK_PLL1SW);
  333                                 break;
  334                         case 1:
  335                                 freq = imx51_get_clock(IMX51CLK_PLL3SW);
  336                                 break;
  337                         case 2:
  338                                 freq = imx51_get_clock(IMX51CLK_LP_APM);
  339                                 break;
  340                         case 3:
  341                                 /* XXX: error */
  342                                 break;
  343                         }
  344                 }
  345                 return freq;
  346         case IMX51CLK_MAIN_BUS_CLK:
  347                 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
  348                 cdcr = ccm_read_4(ccm_softc, CCMC_CDCR);
  349                 return freq / (1 + ((cdcr & CDCR_PERIPH_CLK_DVFS_PODF_MASK) >>
  350                         CDCR_PERIPH_CLK_DVFS_PODF_SHIFT));
  351         case IMX51CLK_AHB_CLK_ROOT:
  352                 freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK);
  353                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
  354                 return freq / (1 + ((cbcdr & CBCDR_AHB_PODF_MASK) >>
  355                                     CBCDR_AHB_PODF_SHIFT));
  356         case IMX51CLK_IPG_CLK_ROOT:
  357                 freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
  358                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
  359                 return freq / (1 + ((cbcdr & CBCDR_IPG_PODF_MASK) >>
  360                                     CBCDR_IPG_PODF_SHIFT));
  361 
  362         case IMX51CLK_PERCLK_ROOT:
  363                 cbcmr = ccm_read_4(ccm_softc, CCMC_CBCMR);
  364                 if (cbcmr & CBCMR_PERCLK_IPG_SEL)
  365                         return imx51_get_clock(IMX51CLK_IPG_CLK_ROOT);
  366                 if (cbcmr & CBCMR_PERCLK_LP_APM_SEL)
  367                         freq = imx51_get_clock(IMX51CLK_LP_APM);
  368                 else
  369                         freq = imx51_get_clock(IMX51CLK_MAIN_BUS_CLK_SRC);
  370                 cbcdr = ccm_read_4(ccm_softc, CCMC_CBCDR);
  371 
  372 #ifdef IMXCCMDEBUG
  373                 printf("cbcmr=%x cbcdr=%x\n", cbcmr, cbcdr);
  374 #endif
  375 
  376                 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED1_MASK) >>
  377                         CBCDR_PERCLK_PRED1_SHIFT);
  378                 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PRED2_MASK) >>
  379                         CBCDR_PERCLK_PRED2_SHIFT);
  380                 freq /= 1 + ((cbcdr & CBCDR_PERCLK_PODF_MASK) >>
  381                         CBCDR_PERCLK_PODF_SHIFT);
  382                 return freq;
  383         case IMX51CLK_UART_CLK_ROOT:
  384                 cscdr1 = ccm_read_4(ccm_softc, CCMC_CSCDR1);
  385                 cscmr1 = ccm_read_4(ccm_softc, CCMC_CSCMR1);
  386 
  387 #ifdef IMXCCMDEBUG
  388                 printf("cscdr1=%x cscmr1=%x\n", cscdr1, cscmr1);
  389 #endif
  390 
  391                 sel = (cscmr1 & CSCMR1_UART_CLK_SEL_MASK) >>
  392                     CSCMR1_UART_CLK_SEL_SHIFT;
  393 
  394                 freq = 0; /* shut up GCC */
  395                 switch (sel) {
  396                 case 0:
  397                 case 1:
  398                 case 2:
  399                         freq = imx51_get_clock(IMX51CLK_PLL1SW + sel);
  400                         break;
  401                 case 3:
  402                         freq = imx51_get_clock(IMX51CLK_LP_APM);
  403                         break;
  404                 }
  405 
  406                 return freq / (1 + ((cscdr1 & CSCDR1_UART_CLK_PRED_MASK) >>
  407                         CSCDR1_UART_CLK_PRED_SHIFT)) /
  408                     (1 + ((cscdr1 & CSCDR1_UART_CLK_PODF_MASK) >>
  409                         CSCDR1_UART_CLK_PODF_SHIFT));
  410         case IMX51CLK_IPU_HSP_CLK_ROOT:
  411                 freq = 0;
  412                 cbcmr = ccm_read_4(ccm_softc,  CCMC_CBCMR);
  413                 switch ((cbcmr & CBCMR_IPU_HSP_CLK_SEL_MASK) >>
  414                                 CBCMR_IPU_HSP_CLK_SEL_SHIFT) {
  415                         case 0:
  416                                 freq = imx51_get_clock(IMX51CLK_ARM_AXI_A_CLK);
  417                                 break;
  418                         case 1:
  419                                 freq = imx51_get_clock(IMX51CLK_ARM_AXI_B_CLK);
  420                                 break;
  421                         case 2:
  422                                 freq = imx51_get_clock(
  423                                         IMX51CLK_EMI_SLOW_CLK_ROOT);
  424                                 break;
  425                         case 3:
  426                                 freq = imx51_get_clock(IMX51CLK_AHB_CLK_ROOT);
  427                                 break;
  428                         }
  429                 return freq;
  430         default:
  431                 device_printf(ccm_softc->sc_dev,
  432                     "clock %d: not supported yet\n", clk);
  433                 return 0;
  434         }
  435 }
  436 
  437 static uint64_t
  438 imx51_get_pll_freq(u_int pll_no)
  439 {
  440         uint32_t dp_ctrl;
  441         uint32_t dp_op;
  442         uint32_t dp_mfd;
  443         uint32_t dp_mfn;
  444         uint32_t mfi;
  445         int32_t mfn;
  446         uint32_t mfd;
  447         uint32_t pdf;
  448         uint32_t ccr;
  449         uint64_t freq = 0;
  450         u_int ref = 0;
  451 
  452         KASSERT(1 <= pll_no && pll_no <= IMX51_N_DPLLS, ("Wrong PLL id"));
  453 
  454         dp_ctrl = pll_read_4(ccm_softc, pll_no, DPLL_DP_CTL);
  455 
  456         if (dp_ctrl & DP_CTL_HFSM) {
  457                 dp_op  = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_OP);
  458                 dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFD);
  459                 dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_HFS_MFN);
  460         } else {
  461                 dp_op  = pll_read_4(ccm_softc, pll_no, DPLL_DP_OP);
  462                 dp_mfd = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFD);
  463                 dp_mfn = pll_read_4(ccm_softc, pll_no, DPLL_DP_MFN);
  464         }
  465 
  466         pdf = dp_op & DP_OP_PDF_MASK;
  467         mfi = max(5, (dp_op & DP_OP_MFI_MASK) >> DP_OP_MFI_SHIFT);
  468         mfd = dp_mfd;
  469         if (dp_mfn & 0x04000000)
  470                 /* 27bit signed value */
  471                 mfn = (uint32_t)(0xf8000000 | dp_mfn);
  472         else
  473                 mfn = dp_mfn;
  474 
  475         switch (dp_ctrl &  DP_CTL_REF_CLK_SEL_MASK) {
  476         case DP_CTL_REF_CLK_SEL_COSC:
  477                 /* Internal Oscillator */
  478                 /* TODO: get from FDT "fsl,imx-osc" */
  479                 ref = 24000000; /* IMX51_OSC_FREQ */
  480                 break;
  481         case DP_CTL_REF_CLK_SEL_FPM:
  482                 ccr = ccm_read_4(ccm_softc, CCMC_CCR);
  483                 if (ccr & CCR_FPM_MULT)
  484                 /* TODO: get from FDT "fsl,imx-ckil" */
  485                         ref = 32768 * 1024;
  486                 else
  487                 /* TODO: get from FDT "fsl,imx-ckil" */
  488                         ref = 32768 * 512;
  489                 break;
  490         default:
  491                 ref = 0;
  492         }
  493 
  494         if (dp_ctrl & DP_CTL_REF_CLK_DIV)
  495                 ref /= 2;
  496 
  497         ref *= 4;
  498         freq = (int64_t)ref * mfi + (int64_t)ref * mfn / (mfd + 1);
  499         freq /= pdf + 1;
  500 
  501         if (!(dp_ctrl & DP_CTL_DPDCK0_2_EN))
  502                 freq /= 2;
  503 
  504 #ifdef IMXCCMDEBUG
  505         printf("ref: %dKHz ", ref);
  506         printf("dp_ctl: %08x ", dp_ctrl);
  507         printf("pdf: %3d ", pdf);
  508         printf("mfi: %3d ", mfi);
  509         printf("mfd: %3d ", mfd);
  510         printf("mfn: %3d ", mfn);
  511         printf("pll: %d\n", (uint32_t)freq);
  512 #endif
  513 
  514         ccm_softc->pll_freq[pll_no-1] = freq;
  515 
  516         return (freq);
  517 }
  518 
  519 void
  520 imx51_clk_gating(int clk_src, int mode)
  521 {
  522         int field, group;
  523         uint32_t reg;
  524 
  525         group = CCMR_CCGR_MODULE(clk_src);
  526         field = clk_src % CCMR_CCGR_NSOURCE;
  527         reg = ccm_read_4(ccm_softc, CCMC_CCGR(group));
  528         reg &= ~(0x03 << field * 2);
  529         reg |= (mode << field * 2);
  530         ccm_write_4(ccm_softc, CCMC_CCGR(group), reg);
  531 }
  532 
  533 int
  534 imx51_get_clk_gating(int clk_src)
  535 {
  536         uint32_t reg;
  537 
  538         reg = ccm_read_4(ccm_softc,
  539             CCMC_CCGR(CCMR_CCGR_MODULE(clk_src)));
  540         return ((reg >> (clk_src % CCMR_CCGR_NSOURCE) * 2) & 0x03);
  541 }
  542 
  543 /*
  544  * Code from here down is temporary, in lieu of a SoC-independent clock API.
  545  */
  546 
  547 void
  548 imx_ccm_usb_enable(device_t dev)
  549 {
  550         uint32_t regval;
  551 
  552         /*
  553          * Select PLL2 as the source for the USB clock.
  554          * The default is PLL3, but U-boot changes it to PLL2.
  555          */
  556         regval = ccm_read_4(ccm_softc, CCMC_CSCMR1);
  557         regval &= ~CSCMR1_USBOH3_CLK_SEL_MASK;
  558         regval |= 1 << CSCMR1_USBOH3_CLK_SEL_SHIFT;
  559         ccm_write_4(ccm_softc, CCMC_CSCMR1, regval);
  560 
  561         /*
  562          * Set the USB clock pre-divider to div-by-5, post-divider to div-by-2.
  563          */
  564         regval = ccm_read_4(ccm_softc, CCMC_CSCDR1);
  565         regval &= ~CSCDR1_USBOH3_CLK_PODF_MASK;
  566         regval &= ~CSCDR1_USBOH3_CLK_PRED_MASK;
  567         regval |= 4 << CSCDR1_USBOH3_CLK_PRED_SHIFT;
  568         regval |= 1 << CSCDR1_USBOH3_CLK_PODF_SHIFT;
  569         ccm_write_4(ccm_softc, CCMC_CSCDR1, regval);
  570 
  571         /*
  572          * The same two clocks gates are used on imx51 and imx53.
  573          */
  574         imx51_clk_gating(CCGR_USBOH3_IPG_AHB_CLK, CCGR_CLK_MODE_ALWAYS);
  575         imx51_clk_gating(CCGR_USBOH3_60M_CLK, CCGR_CLK_MODE_ALWAYS);
  576 }
  577 
  578 void
  579 imx_ccm_usbphy_enable(device_t dev)
  580 {
  581         uint32_t regval;
  582 
  583         /*
  584          * Select PLL3 as the source for the USBPHY clock.  U-boot does this 
  585          * only for imx53, but the bit exists on imx51.  That seems a bit
  586          * strange, but we'll go with it until more is known.
  587          */
  588         if (imx_soc_type() == IMXSOC_53) {
  589                 regval = ccm_read_4(ccm_softc, CCMC_CSCMR1);
  590                 regval |= 1 << CSCMR1_USBPHY_CLK_SEL_SHIFT;
  591                 ccm_write_4(ccm_softc, CCMC_CSCMR1, regval);
  592         }
  593 
  594         /*
  595          * For the imx51 there's just one phy gate control, enable it.
  596          */
  597         if (imx_soc_type() == IMXSOC_51) {
  598                 imx51_clk_gating(CCGR_USB_PHY_CLK, CCGR_CLK_MODE_ALWAYS);
  599                 return;
  600         }
  601 
  602         /*
  603          * For imx53 we don't have a full set of clock defines yet, but the
  604          * datasheet says:
  605          *   gate reg 4, bits 13-12 usb ph2 clock (usb_phy2_clk_enable)
  606          *   gate reg 4, bits 11-10 usb ph1 clock (usb_phy1_clk_enable)
  607          *
  608          * We should use the fdt data for the device to figure out which of
  609          * the two we're working on, but for now just turn them both on.
  610          */
  611         if (imx_soc_type() == IMXSOC_53) {
  612                 imx51_clk_gating(__CCGR_NUM(4, 5), CCGR_CLK_MODE_ALWAYS);
  613                 imx51_clk_gating(__CCGR_NUM(4, 6), CCGR_CLK_MODE_ALWAYS);
  614                 return;
  615         }
  616 }
  617 
  618 uint32_t
  619 imx_ccm_ecspi_hz(void)
  620 {
  621 
  622         return (imx51_get_clock(IMX51CLK_CSPI_CLK_ROOT));
  623 }
  624 
  625 uint32_t
  626 imx_ccm_ipg_hz(void)
  627 {
  628 
  629         return (imx51_get_clock(IMX51CLK_IPG_CLK_ROOT));
  630 }
  631 
  632 uint32_t
  633 imx_ccm_sdhci_hz(void)
  634 {
  635 
  636         return (imx51_get_clock(IMX51CLK_ESDHC1_CLK_ROOT));
  637 }
  638 
  639 uint32_t
  640 imx_ccm_perclk_hz(void)
  641 {
  642 
  643         return (imx51_get_clock(IMX51CLK_PERCLK_ROOT));
  644 }
  645 
  646 uint32_t
  647 imx_ccm_uart_hz(void)
  648 {
  649 
  650         return (imx51_get_clock(IMX51CLK_UART_CLK_ROOT));
  651 }
  652 
  653 uint32_t
  654 imx_ccm_ahb_hz(void)
  655 {
  656 
  657         return (imx51_get_clock(IMX51CLK_AHB_CLK_ROOT));
  658 }

Cache object: 3a19ee3a6c199b718ffb34d5f6611be6


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