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

Cache object: 41265a3963fa5d05c0742aa213c00298


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