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/at91/at91_pmc.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  * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  */
   25 
   26 #include "opt_at91.h"
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/8.1/sys/arm/at91/at91_pmc.c 185492 2008-11-30 22:40:11Z stas $");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/module.h>
   35 #include <sys/time.h>
   36 #include <sys/bus.h>
   37 #include <sys/resource.h>
   38 #include <sys/rman.h>
   39 #include <sys/timetc.h>
   40 
   41 #include <machine/bus.h>
   42 #include <machine/cpu.h>
   43 #include <machine/cpufunc.h>
   44 #include <machine/resource.h>
   45 #include <machine/frame.h>
   46 #include <machine/intr.h>
   47 #include <arm/at91/at91rm92reg.h>
   48 
   49 #include <arm/at91/at91_pmcreg.h>
   50 #include <arm/at91/at91_pmcvar.h>
   51 
   52 static struct at91_pmc_softc {
   53         bus_space_tag_t         sc_st;
   54         bus_space_handle_t      sc_sh;
   55         struct resource *mem_res;       /* Memory resource */
   56         device_t                dev;
   57         unsigned int            main_clock_hz;
   58         uint32_t                pllb_init;
   59 } *pmc_softc;
   60 
   61 static void at91_pmc_set_pllb_mode(struct at91_pmc_clock *, int);
   62 static void at91_pmc_set_sys_mode(struct at91_pmc_clock *, int);
   63 static void at91_pmc_set_periph_mode(struct at91_pmc_clock *, int);
   64 
   65 static struct at91_pmc_clock slck = {
   66         .name = "slck",         // 32,768 Hz slow clock
   67         .hz = 32768,
   68         .refcnt = 1,
   69         .id = 0,
   70         .primary = 1,
   71 };
   72 
   73 static struct at91_pmc_clock main_ck = {
   74         .name = "main",         // Main clock
   75         .refcnt = 0,
   76         .id = 1,
   77         .primary = 1,
   78         .pmc_mask = PMC_IER_MOSCS,
   79 };
   80 
   81 static struct at91_pmc_clock plla = {
   82         .name = "plla",         // PLLA Clock, used for CPU clocking
   83         .parent = &main_ck,
   84         .refcnt = 1,
   85         .id = 0,
   86         .primary = 1,
   87         .pll = 1,
   88         .pmc_mask = PMC_IER_LOCKA,
   89 };
   90 
   91 static struct at91_pmc_clock pllb = {
   92         .name = "pllb",         // PLLB Clock, used for USB functions
   93         .parent = &main_ck,
   94         .refcnt = 0,
   95         .id = 0,
   96         .primary = 1,
   97         .pll = 1,
   98         .pmc_mask = PMC_IER_LOCKB,
   99         .set_mode = &at91_pmc_set_pllb_mode,
  100 };
  101 
  102 static struct at91_pmc_clock udpck = {
  103         .name = "udpck",
  104         .parent = &pllb,
  105         .pmc_mask = PMC_SCER_UDP,
  106         .set_mode = at91_pmc_set_sys_mode
  107 };
  108 
  109 static struct at91_pmc_clock uhpck = {
  110         .name = "uhpck",
  111         .parent = &pllb,
  112         .pmc_mask = PMC_SCER_UHP,
  113         .set_mode = at91_pmc_set_sys_mode
  114 };
  115 
  116 static struct at91_pmc_clock mck = {
  117         .name = "mck",
  118         .pmc_mask = PMC_IER_MCKRDY,
  119         .refcnt = 0,
  120 };
  121 
  122 static struct at91_pmc_clock udc_clk = {
  123         .name = "udc_clk",
  124         .parent = &mck,
  125         .pmc_mask = 1 << AT91RM92_IRQ_UDP,
  126         .set_mode = &at91_pmc_set_periph_mode
  127 };
  128 
  129 static struct at91_pmc_clock ohci_clk = {
  130         .name = "ohci_clk",
  131         .parent = &mck,
  132         .pmc_mask = 1 << AT91RM92_IRQ_UHP,
  133         .set_mode = &at91_pmc_set_periph_mode
  134 };
  135 
  136 static struct at91_pmc_clock *const clock_list[] = {
  137         &slck,
  138         &main_ck,
  139         &plla,
  140         &pllb,
  141         &udpck,
  142         &uhpck,
  143         &mck,
  144         &udc_clk,
  145         &ohci_clk
  146 };
  147 
  148 #if !defined(AT91C_MAIN_CLOCK)
  149 static const unsigned int at91_mainf_tbl[] = {
  150         3000000, 3276800, 3686400, 3840000, 4000000,
  151         4433619, 4915200, 5000000, 5242880, 6000000,
  152         6144000, 6400000, 6553600, 7159090, 7372800,
  153         7864320, 8000000, 9830400, 10000000, 11059200,
  154         12000000, 12288000, 13560000, 14318180, 14745600,
  155         16000000, 17344700, 18432000, 20000000
  156 };
  157 #define MAINF_TBL_LEN   (sizeof(at91_mainf_tbl) / sizeof(*at91_mainf_tbl))
  158 #endif
  159 
  160 static inline uint32_t
  161 RD4(struct at91_pmc_softc *sc, bus_size_t off)
  162 {
  163         return bus_read_4(sc->mem_res, off);
  164 }
  165 
  166 static inline void
  167 WR4(struct at91_pmc_softc *sc, bus_size_t off, uint32_t val)
  168 {
  169         bus_write_4(sc->mem_res, off, val);
  170 }
  171 
  172 static void
  173 at91_pmc_set_pllb_mode(struct at91_pmc_clock *clk, int on)
  174 {
  175         struct at91_pmc_softc *sc = pmc_softc;
  176         uint32_t value;
  177 
  178         if (on) {
  179                 on = PMC_IER_LOCKB;
  180                 value = sc->pllb_init;
  181         } else {
  182                 value = 0;
  183         }
  184         WR4(sc, CKGR_PLLBR, value);
  185         while ((RD4(sc, PMC_SR) & PMC_IER_LOCKB) != on)
  186                 continue;
  187 }
  188 
  189 static void
  190 at91_pmc_set_sys_mode(struct at91_pmc_clock *clk, int on)
  191 {
  192         struct at91_pmc_softc *sc = pmc_softc;
  193 
  194         WR4(sc, on ? PMC_SCER : PMC_SCDR, clk->pmc_mask);
  195         if (on)
  196                 while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) != clk->pmc_mask)
  197                         continue;
  198         else
  199                 while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) == clk->pmc_mask)
  200                         continue;
  201 }
  202 
  203 static void
  204 at91_pmc_set_periph_mode(struct at91_pmc_clock *clk, int on)
  205 {
  206         struct at91_pmc_softc *sc = pmc_softc;
  207 
  208         WR4(sc, on ? PMC_PCER : PMC_PCDR, clk->pmc_mask);
  209         if (on)
  210                 while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) != clk->pmc_mask)
  211                         continue;
  212         else
  213                 while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) == clk->pmc_mask)
  214                         continue;
  215 }
  216 
  217 struct at91_pmc_clock *
  218 at91_pmc_clock_ref(const char *name)
  219 {
  220         int i;
  221 
  222         for (i = 0; i < sizeof(clock_list) / sizeof(clock_list[0]); i++)
  223                 if (strcmp(name, clock_list[i]->name) == 0)
  224                         return (clock_list[i]);
  225 
  226         return (NULL);
  227 }
  228 
  229 void
  230 at91_pmc_clock_deref(struct at91_pmc_clock *clk)
  231 {
  232 }
  233 
  234 void
  235 at91_pmc_clock_enable(struct at91_pmc_clock *clk)
  236 {
  237         /* XXX LOCKING? XXX */
  238         if (clk->parent)
  239                 at91_pmc_clock_enable(clk->parent);
  240         if (clk->refcnt++ == 0 && clk->set_mode)
  241                 clk->set_mode(clk, 1);
  242 }
  243 
  244 void
  245 at91_pmc_clock_disable(struct at91_pmc_clock *clk)
  246 {
  247         /* XXX LOCKING? XXX */
  248         if (--clk->refcnt == 0 && clk->set_mode)
  249                 clk->set_mode(clk, 0);
  250         if (clk->parent)
  251                 at91_pmc_clock_disable(clk->parent);
  252 }
  253 
  254 static int
  255 at91_pmc_pll_rate(int freq, uint32_t reg, int is_pllb)
  256 {
  257         uint32_t mul, div;
  258 
  259         div = reg & 0xff;
  260         mul = (reg >> 16) & 0x7ff;
  261         if (div != 0 && mul != 0) {
  262                 freq /= div;
  263                 freq *= mul + 1;
  264         } else {
  265                 freq = 0;
  266         }
  267         if (is_pllb && (reg & (1 << 28)))
  268                 freq >>= 1;
  269         return (freq);
  270 }
  271 
  272 static uint32_t
  273 at91_pmc_pll_calc(uint32_t main_freq, uint32_t out_freq)
  274 {
  275         uint32_t i, div = 0, mul = 0, diff = 1 << 30;
  276         unsigned ret = (out_freq > PMC_PLL_FAST_THRESH) ? 0xbe00 : 0x3e00; 
  277 
  278         if (out_freq > PMC_PLL_MAX_OUT_FREQ)
  279                 goto fail;
  280 
  281         for (i = 1; i < 256; i++) {
  282                 int32_t diff1;
  283                 uint32_t input, mul1;
  284 
  285                 input = main_freq / i;
  286                 if (input < PMC_PLL_MIN_IN_FREQ)
  287                         break;
  288                 if (input > PMC_PLL_MAX_IN_FREQ)
  289                         continue;
  290 
  291                 mul1 = out_freq / input;
  292                 if (mul1 > PMC_PLL_MULT_MAX)
  293                         continue;
  294                 if (mul1 < PMC_PLL_MULT_MIN)
  295                         break;
  296 
  297                 diff1 = out_freq - input * mul1;
  298                 if (diff1 < 0)
  299                         diff1 = -diff1;
  300                 if (diff > diff1) {
  301                         diff = diff1;
  302                         div = i;
  303                         mul = mul1;
  304                         if (diff == 0)
  305                                 break;
  306                 }
  307         }
  308         if (diff > (out_freq >> PMC_PLL_SHIFT_TOL))
  309                 goto fail;
  310         return ret | ((mul - 1) << 16) | div;
  311 fail:
  312         return 0;
  313 }
  314 
  315 static void
  316 at91_pmc_init_clock(struct at91_pmc_softc *sc, unsigned int main_clock)
  317 {
  318         uint32_t mckr;
  319         int freq;
  320 
  321         sc->main_clock_hz = main_clock;
  322         main_ck.hz = main_clock;
  323         plla.hz = at91_pmc_pll_rate(main_clock, RD4(sc, CKGR_PLLAR), 0);
  324 
  325         /*
  326          * Initialize the usb clock.  This sets up pllb, but disables the
  327          * actual clock.
  328          */
  329         sc->pllb_init = at91_pmc_pll_calc(main_clock, 48000000 * 2) |0x10000000;
  330         pllb.hz = at91_pmc_pll_rate(main_clock, sc->pllb_init, 1);
  331         WR4(sc, PMC_PCDR, (1 << AT91RM92_IRQ_UHP) | (1 << AT91RM92_IRQ_UDP));
  332         WR4(sc, PMC_SCDR, PMC_SCER_UHP | PMC_SCER_UDP);
  333         WR4(sc, CKGR_PLLBR, 0);
  334         WR4(sc, PMC_SCER, PMC_SCER_MCKUDP);
  335 
  336         /*
  337          * MCK and PCU derive from one of the primary clocks.  Initialize
  338          * this relationship.
  339          */
  340         mckr = RD4(sc, PMC_MCKR);
  341         mck.parent = clock_list[mckr & 0x3];
  342         mck.parent->refcnt++;
  343         freq = mck.parent->hz / (1 << ((mckr >> 2) & 3));
  344         mck.hz = freq / (1 + ((mckr >> 8) & 3));
  345 
  346         device_printf(sc->dev,
  347             "Primary: %d Hz PLLA: %d MHz CPU: %d MHz MCK: %d MHz\n",
  348             sc->main_clock_hz,
  349             at91_pmc_pll_rate(main_clock, RD4(sc, CKGR_PLLAR), 0) / 1000000,
  350             freq / 1000000, mck.hz / 1000000);
  351         WR4(sc, PMC_SCDR, PMC_SCER_PCK0 | PMC_SCER_PCK1 | PMC_SCER_PCK2 |
  352             PMC_SCER_PCK3);
  353         /* XXX kludge, turn on all peripherals */
  354         WR4(sc, PMC_PCER, 0xffffffff);
  355         /* Disable all interrupts for PMC */
  356         WR4(sc, PMC_IDR, 0xffffffff);
  357 }
  358 
  359 static void
  360 at91_pmc_deactivate(device_t dev)
  361 {
  362         struct at91_pmc_softc *sc;
  363 
  364         sc = device_get_softc(dev);
  365         bus_generic_detach(sc->dev);
  366         if (sc->mem_res)
  367                 bus_release_resource(dev, SYS_RES_IOPORT,
  368                     rman_get_rid(sc->mem_res), sc->mem_res);
  369         sc->mem_res = 0;
  370         return;
  371 }
  372 
  373 static int
  374 at91_pmc_activate(device_t dev)
  375 {
  376         struct at91_pmc_softc *sc;
  377         int rid;
  378 
  379         sc = device_get_softc(dev);
  380         rid = 0;
  381         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  382             RF_ACTIVE);
  383         if (sc->mem_res == NULL)
  384                 goto errout;
  385         return (0);
  386 errout:
  387         at91_pmc_deactivate(dev);
  388         return (ENOMEM);
  389 }
  390 
  391 static int
  392 at91_pmc_probe(device_t dev)
  393 {
  394 
  395         device_set_desc(dev, "PMC");
  396         return (0);
  397 }
  398 
  399 #if !defined(AT91C_MAIN_CLOCK)
  400 static unsigned int
  401 at91_pmc_sense_mainf(struct at91_pmc_softc *sc)
  402 {
  403         unsigned int ckgr_val;
  404         unsigned int diff, matchdiff;
  405         int i, match;
  406 
  407         ckgr_val = (RD4(sc, CKGR_MCFR) & CKGR_MCFR_MAINF_MASK) << 11;
  408 
  409         /*
  410          * Try to find the standard frequency that match best.
  411          */
  412         match = 0;
  413         matchdiff = abs(ckgr_val - at91_mainf_tbl[0]);
  414         for (i = 1; i < MAINF_TBL_LEN; i++) {
  415                 diff = abs(ckgr_val - at91_mainf_tbl[i]);
  416                 if (diff < matchdiff) {
  417                         match = i;
  418                         matchdiff = diff;
  419                 }
  420         }
  421         return (at91_mainf_tbl[match]);
  422 }
  423 #endif
  424 
  425 static int
  426 at91_pmc_attach(device_t dev)
  427 {
  428         unsigned int mainf;
  429         int err;
  430 
  431         pmc_softc = device_get_softc(dev);
  432         pmc_softc->dev = dev;
  433         if ((err = at91_pmc_activate(dev)) != 0)
  434                 return err;
  435 
  436         /*
  437          * Configure main clock frequency.
  438          */
  439 #if !defined(AT91C_MAIN_CLOCK)
  440         mainf = at91_pmc_sense_mainf(pmc_softc);
  441 #else
  442         mainf = AT91C_MAIN_CLOCK;
  443 #endif
  444         at91_pmc_init_clock(pmc_softc, mainf);
  445         return (0);
  446 }
  447 
  448 static device_method_t at91_pmc_methods[] = {
  449         DEVMETHOD(device_probe, at91_pmc_probe),
  450         DEVMETHOD(device_attach, at91_pmc_attach),
  451         {0, 0},
  452 };
  453 
  454 static driver_t at91_pmc_driver = {
  455         "at91_pmc",
  456         at91_pmc_methods,
  457         sizeof(struct at91_pmc_softc),
  458 };
  459 static devclass_t at91_pmc_devclass;
  460 
  461 DRIVER_MODULE(at91_pmc, atmelarm, at91_pmc_driver, at91_pmc_devclass, 0, 0);

Cache object: 559eb6868af4b66a2ada8421e4f161af


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