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/arm64/rockchip/clk/rk_clk_pll.c

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

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * $FreeBSD$
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 
   37 #include <dev/extres/clk/clk.h>
   38 
   39 #include <arm64/rockchip/clk/rk_clk_pll.h>
   40 
   41 #include "clkdev_if.h"
   42 
   43 struct rk_clk_pll_sc {
   44         uint32_t        base_offset;
   45 
   46         uint32_t        gate_offset;
   47         uint32_t        gate_shift;
   48 
   49         uint32_t        mode_reg;
   50         uint32_t        mode_shift;
   51 
   52         uint32_t        flags;
   53 
   54         struct rk_clk_pll_rate  *rates;
   55         struct rk_clk_pll_rate  *frac_rates;
   56 };
   57 
   58 #define WRITE4(_clk, off, val)                                          \
   59         CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
   60 #define READ4(_clk, off, val)                                           \
   61         CLKDEV_READ_4(clknode_get_device(_clk), off, val)
   62 #define DEVICE_LOCK(_clk)                                               \
   63         CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
   64 #define DEVICE_UNLOCK(_clk)                                             \
   65         CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
   66 
   67 #define RK_CLK_PLL_MASK_SHIFT   16
   68 
   69 #if 0
   70 #define dprintf(format, arg...)                                         \
   71         printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg)
   72 #else
   73 #define dprintf(format, arg...)
   74 #endif
   75 
   76 static int
   77 rk_clk_pll_set_gate(struct clknode *clk, bool enable)
   78 {
   79         struct rk_clk_pll_sc *sc;
   80         uint32_t val = 0;
   81 
   82         sc = clknode_get_softc(clk);
   83 
   84         if ((sc->flags & RK_CLK_PLL_HAVE_GATE) == 0)
   85                 return (0);
   86 
   87         dprintf("%sabling gate\n", enable ? "En" : "Dis");
   88         if (!enable)
   89                 val |= 1 << sc->gate_shift;
   90         dprintf("sc->gate_shift: %x\n", sc->gate_shift);
   91         val |= (1 << sc->gate_shift) << RK_CLK_PLL_MASK_SHIFT;
   92         dprintf("Write: gate_offset=%x, val=%x\n", sc->gate_offset, val);
   93         DEVICE_LOCK(clk);
   94         WRITE4(clk, sc->gate_offset, val);
   95         DEVICE_UNLOCK(clk);
   96 
   97         return (0);
   98 }
   99 
  100 /* CON0 */
  101 #define RK3066_CLK_PLL_REFDIV_SHIFT     8
  102 #define RK3066_CLK_PLL_REFDIV_MASK      0x3F00
  103 #define RK3066_CLK_PLL_POSTDIV_SHIFT    0
  104 #define RK3066_CLK_PLL_POSTDIV_MASK     0x000F
  105 /* CON1 */
  106 #define RK3066_CLK_PLL_LOCK_MASK        (1U << 31)
  107 #define RK3066_CLK_PLL_FBDIV_SHIFT      0
  108 #define RK3066_CLK_PLL_FBDIV_MASK       0x0FFF
  109 /* CON2 */
  110 
  111 /* CON3 */
  112 #define RK3066_CLK_PLL_RESET            (1 << 5)
  113 #define RK3066_CLK_PLL_TEST             (1 << 4)
  114 #define RK3066_CLK_PLL_ENSAT            (1 << 3)
  115 #define RK3066_CLK_PLL_FASTEN           (1 << 2)
  116 #define RK3066_CLK_PLL_POWER_DOWN       (1 << 1)
  117 #define RK3066_CLK_PLL_BYPASS           (1 << 0)
  118 
  119 #define RK3066_CLK_PLL_MODE_SLOW        0
  120 #define RK3066_CLK_PLL_MODE_NORMAL      1
  121 #define RK3066_CLK_PLL_MODE_DEEP_SLOW   2
  122 #define RK3066_CLK_PLL_MODE_MASK        0x3
  123 
  124 static int
  125 rk3066_clk_pll_init(struct clknode *clk, device_t dev)
  126 {
  127         struct rk_clk_pll_sc *sc;
  128         uint32_t reg;
  129 
  130         sc = clknode_get_softc(clk);
  131 
  132         DEVICE_LOCK(clk);
  133         READ4(clk, sc->mode_reg, &reg);
  134         DEVICE_UNLOCK(clk);
  135 
  136         reg = (reg >> sc->mode_shift) & RK3066_CLK_PLL_MODE_MASK;
  137         clknode_init_parent_idx(clk, reg);
  138 
  139         return (0);
  140 }
  141 
  142 static int
  143 rk3066_clk_pll_set_mux(struct clknode *clk, int idx)
  144 {
  145         uint32_t reg;
  146         struct rk_clk_pll_sc *sc;
  147 
  148         sc = clknode_get_softc(clk);
  149 
  150         reg = (idx & RK3066_CLK_PLL_MODE_MASK) << sc->mode_shift;
  151         reg |= (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
  152                 RK_CLK_PLL_MASK_SHIFT;
  153 
  154         DEVICE_LOCK(clk);
  155         WRITE4(clk, sc->mode_reg, reg);
  156         DEVICE_UNLOCK(clk);
  157         return(0);
  158 }
  159 
  160 static int
  161 rk3066_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
  162 {
  163         struct rk_clk_pll_sc *sc;
  164         uint64_t rate;
  165         uint32_t refdiv, fbdiv, postdiv;
  166         uint32_t raw0, raw1, raw2, reg;
  167 
  168         sc = clknode_get_softc(clk);
  169 
  170         DEVICE_LOCK(clk);
  171 
  172         READ4(clk, sc->base_offset, &raw0);
  173         READ4(clk, sc->base_offset + 4, &raw1);
  174         READ4(clk, sc->base_offset + 8, &raw2);
  175         READ4(clk, sc->mode_reg, &reg);
  176 
  177         DEVICE_UNLOCK(clk);
  178 
  179         reg = (reg >> sc->mode_shift) & RK3066_CLK_PLL_MODE_MASK;
  180 
  181         if (reg != RK3066_CLK_PLL_MODE_NORMAL)
  182                 return (0);
  183 
  184         if (!(raw1 & RK3066_CLK_PLL_LOCK_MASK)) {
  185                 *freq = 0;
  186                 return (0);
  187         }
  188 
  189         /* TODO MUX */
  190         refdiv = (raw0 & RK3066_CLK_PLL_REFDIV_MASK) >>
  191             RK3066_CLK_PLL_REFDIV_SHIFT;
  192         refdiv += 1;
  193         postdiv = (raw0 & RK3066_CLK_PLL_POSTDIV_MASK) >>
  194             RK3066_CLK_PLL_POSTDIV_SHIFT;
  195         postdiv += 1;
  196         fbdiv = (raw1 & RK3066_CLK_PLL_FBDIV_MASK) >>
  197             RK3066_CLK_PLL_FBDIV_SHIFT;
  198         fbdiv += 1;
  199 
  200         rate = *freq * fbdiv;
  201         rate /= refdiv;
  202         *freq = rate / postdiv;
  203 
  204         return (0);
  205 }
  206 
  207 static int
  208 rk3066_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
  209     int flags, int *stop)
  210 {
  211         struct rk_clk_pll_rate *rates;
  212         struct rk_clk_pll_sc *sc;
  213         uint32_t reg;
  214         int rv, timeout;
  215 
  216         sc = clknode_get_softc(clk);
  217 
  218         if (sc->rates == NULL)
  219                 return (EINVAL);
  220 
  221         for (rates = sc->rates; rates->freq; rates++) {
  222                 if (rates->freq == *fout)
  223                         break;
  224         }
  225         if (rates->freq == 0) {
  226                 *stop = 1;
  227                 return (EINVAL);
  228         }
  229 
  230         DEVICE_LOCK(clk);
  231 
  232         /* Setting to slow mode during frequency change */
  233         reg = (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
  234                 RK_CLK_PLL_MASK_SHIFT;
  235         dprintf("Set PLL_MODEREG to %x\n", reg);
  236         WRITE4(clk, sc->mode_reg, reg);
  237 
  238         /* Reset PLL */
  239         WRITE4(clk, sc->base_offset + 12, RK3066_CLK_PLL_RESET |
  240             RK3066_CLK_PLL_RESET << RK_CLK_PLL_MASK_SHIFT);
  241 
  242         /* Setting postdiv and refdiv */
  243         reg = 0;
  244         reg |= RK3066_CLK_PLL_POSTDIV_MASK << 16;
  245         reg |= (rates->postdiv1 - 1) << RK3066_CLK_PLL_POSTDIV_SHIFT;
  246 
  247         reg |= RK3066_CLK_PLL_REFDIV_MASK << 16;
  248         reg |= (rates->refdiv - 1)<< RK3066_CLK_PLL_REFDIV_SHIFT;
  249 
  250         dprintf("Set PLL_CON0 to %x\n", reg);
  251         WRITE4(clk, sc->base_offset, reg);
  252 
  253 
  254         /* Setting  fbdiv (no write mask)*/
  255         READ4(clk, sc->base_offset + 4, &reg);
  256         reg &= ~RK3066_CLK_PLL_FBDIV_MASK;
  257         reg |= RK3066_CLK_PLL_FBDIV_MASK << 16;
  258         reg = (rates->fbdiv - 1) << RK3066_CLK_PLL_FBDIV_SHIFT;
  259 
  260         dprintf("Set PLL_CON1 to %x\n", reg);
  261         WRITE4(clk, sc->base_offset + 0x4, reg);
  262 
  263         /* PLL loop bandwidth adjust */
  264         reg =  rates->bwadj - 1;
  265         dprintf("Set PLL_CON2 to %x (%x)\n", reg, rates->bwadj);
  266         WRITE4(clk, sc->base_offset + 0x8, reg);
  267 
  268         /* Clear reset */
  269         WRITE4(clk, sc->base_offset + 12,
  270             RK3066_CLK_PLL_RESET << RK_CLK_PLL_MASK_SHIFT);
  271         DELAY(100000);
  272 
  273         /* Reading lock */
  274         for (timeout = 1000; timeout >= 0; timeout--) {
  275                 READ4(clk, sc->base_offset + 0x4, &reg);
  276                 if ((reg & RK3066_CLK_PLL_LOCK_MASK) != 0)
  277                         break;
  278                 DELAY(1);
  279         }
  280 
  281         rv = 0;
  282         if (timeout < 0) {
  283                 device_printf(clknode_get_device(clk),
  284                     "%s - Timedout while waiting for lock.\n",
  285                     clknode_get_name(clk));
  286                 dprintf("PLL_CON1: %x\n", reg);
  287                 rv = ETIMEDOUT;
  288         }
  289 
  290         /* Set back to normal mode */
  291         reg = (RK3066_CLK_PLL_MODE_NORMAL << sc->mode_shift);
  292         reg |= (RK3066_CLK_PLL_MODE_MASK << sc->mode_shift) <<
  293                 RK_CLK_PLL_MASK_SHIFT;
  294         dprintf("Set PLL_MODEREG to %x\n", reg);
  295         WRITE4(clk, sc->mode_reg, reg);
  296 
  297         DEVICE_UNLOCK(clk);
  298         *stop = 1;
  299         rv = clknode_set_parent_by_idx(clk, 1);
  300         return (rv);
  301 }
  302 
  303 static clknode_method_t rk3066_clk_pll_clknode_methods[] = {
  304         /* Device interface */
  305         CLKNODEMETHOD(clknode_init,             rk3066_clk_pll_init),
  306         CLKNODEMETHOD(clknode_set_gate,         rk_clk_pll_set_gate),
  307         CLKNODEMETHOD(clknode_recalc_freq,      rk3066_clk_pll_recalc),
  308         CLKNODEMETHOD(clknode_set_freq,         rk3066_clk_pll_set_freq),
  309         CLKNODEMETHOD(clknode_set_mux,          rk3066_clk_pll_set_mux),
  310         CLKNODEMETHOD_END
  311 };
  312 
  313 DEFINE_CLASS_1(rk3066_clk_pll_clknode, rk3066_clk_pll_clknode_class,
  314     rk3066_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
  315 
  316 int
  317 rk3066_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
  318 {
  319         struct clknode *clk;
  320         struct rk_clk_pll_sc *sc;
  321 
  322         clk = clknode_create(clkdom, &rk3066_clk_pll_clknode_class,
  323             &clkdef->clkdef);
  324         if (clk == NULL)
  325                 return (1);
  326 
  327         sc = clknode_get_softc(clk);
  328 
  329         sc->base_offset = clkdef->base_offset;
  330         sc->gate_offset = clkdef->gate_offset;
  331         sc->gate_shift = clkdef->gate_shift;
  332         sc->mode_reg = clkdef->mode_reg;
  333         sc->mode_shift = clkdef->mode_shift;
  334         sc->flags = clkdef->flags;
  335         sc->rates = clkdef->rates;
  336         sc->frac_rates = clkdef->frac_rates;
  337 
  338         clknode_register(clkdom, clk);
  339 
  340         return (0);
  341 }
  342 
  343 #define RK3328_CLK_PLL_FBDIV_OFFSET     0
  344 #define RK3328_CLK_PLL_FBDIV_SHIFT      0
  345 #define RK3328_CLK_PLL_FBDIV_MASK       0xFFF
  346 
  347 #define RK3328_CLK_PLL_POSTDIV1_OFFSET  0
  348 #define RK3328_CLK_PLL_POSTDIV1_SHIFT   12
  349 #define RK3328_CLK_PLL_POSTDIV1_MASK    0x7000
  350 
  351 #define RK3328_CLK_PLL_DSMPD_OFFSET     4
  352 #define RK3328_CLK_PLL_DSMPD_SHIFT      12
  353 #define RK3328_CLK_PLL_DSMPD_MASK       0x1000
  354 
  355 #define RK3328_CLK_PLL_REFDIV_OFFSET    4
  356 #define RK3328_CLK_PLL_REFDIV_SHIFT     0
  357 #define RK3328_CLK_PLL_REFDIV_MASK      0x3F
  358 
  359 #define RK3328_CLK_PLL_POSTDIV2_OFFSET  4
  360 #define RK3328_CLK_PLL_POSTDIV2_SHIFT   6
  361 #define RK3328_CLK_PLL_POSTDIV2_MASK    0x1C0
  362 
  363 #define RK3328_CLK_PLL_FRAC_OFFSET      8
  364 #define RK3328_CLK_PLL_FRAC_SHIFT       0
  365 #define RK3328_CLK_PLL_FRAC_MASK        0xFFFFFF
  366 
  367 #define RK3328_CLK_PLL_LOCK_MASK        0x400
  368 
  369 #define RK3328_CLK_PLL_MODE_SLOW        0
  370 #define RK3328_CLK_PLL_MODE_NORMAL      1
  371 #define RK3328_CLK_PLL_MODE_MASK        0x1
  372 
  373 static int
  374 rk3328_clk_pll_init(struct clknode *clk, device_t dev)
  375 {
  376         clknode_init_parent_idx(clk, 0);
  377 
  378         return (0);
  379 }
  380 
  381 static int
  382 rk3328_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
  383 {
  384         struct rk_clk_pll_sc *sc;
  385         uint64_t rate;
  386         uint32_t dsmpd, refdiv, fbdiv;
  387         uint32_t postdiv1, postdiv2, frac;
  388         uint32_t raw1, raw2, raw3;
  389 
  390         sc = clknode_get_softc(clk);
  391 
  392         DEVICE_LOCK(clk);
  393 
  394         READ4(clk, sc->base_offset, &raw1);
  395         READ4(clk, sc->base_offset + 4, &raw2);
  396         READ4(clk, sc->base_offset + 8, &raw3);
  397 
  398         fbdiv = (raw1 & RK3328_CLK_PLL_FBDIV_MASK) >> RK3328_CLK_PLL_FBDIV_SHIFT;
  399         postdiv1 = (raw1 & RK3328_CLK_PLL_POSTDIV1_MASK) >> RK3328_CLK_PLL_POSTDIV1_SHIFT;
  400 
  401         dsmpd = (raw2 & RK3328_CLK_PLL_DSMPD_MASK) >> RK3328_CLK_PLL_DSMPD_SHIFT;
  402         refdiv = (raw2 & RK3328_CLK_PLL_REFDIV_MASK) >> RK3328_CLK_PLL_REFDIV_SHIFT;
  403         postdiv2 = (raw2 & RK3328_CLK_PLL_POSTDIV2_MASK) >> RK3328_CLK_PLL_POSTDIV2_SHIFT;
  404 
  405         frac = (raw3 & RK3328_CLK_PLL_FRAC_MASK) >> RK3328_CLK_PLL_FRAC_SHIFT;
  406 
  407         DEVICE_UNLOCK(clk);
  408 
  409         rate = *freq * fbdiv / refdiv;
  410         if (dsmpd == 0) {
  411                 /* Fractional mode */
  412                 uint64_t frac_rate;
  413 
  414                 frac_rate = *freq * frac / refdiv;
  415                 rate += frac_rate >> 24;
  416         }
  417 
  418         *freq = rate / postdiv1 / postdiv2;
  419 
  420         if (*freq % 2)
  421                 *freq = *freq + 1;
  422 
  423         return (0);
  424 }
  425 
  426 static int
  427 rk3328_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
  428     int flags, int *stop)
  429 {
  430         struct rk_clk_pll_rate *rates;
  431         struct rk_clk_pll_sc *sc;
  432         uint32_t reg;
  433         int timeout;
  434 
  435         sc = clknode_get_softc(clk);
  436 
  437         if (sc->rates)
  438                 rates = sc->rates;
  439         else if (sc->frac_rates)
  440                 rates = sc->frac_rates;
  441         else
  442                 return (EINVAL);
  443 
  444         for (; rates->freq; rates++) {
  445                 if (rates->freq == *fout)
  446                         break;
  447         }
  448         if (rates->freq == 0) {
  449                 *stop = 1;
  450                 return (EINVAL);
  451         }
  452 
  453         DEVICE_LOCK(clk);
  454 
  455         /* Setting to slow mode during frequency change */
  456         reg = (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
  457                 RK_CLK_PLL_MASK_SHIFT;
  458         dprintf("Set PLL_MODEREG to %x\n", reg);
  459         WRITE4(clk, sc->mode_reg, reg);
  460 
  461         /* Setting postdiv1 and fbdiv */
  462         reg = (rates->postdiv1 << RK3328_CLK_PLL_POSTDIV1_SHIFT) |
  463                 (rates->fbdiv << RK3328_CLK_PLL_FBDIV_SHIFT);
  464         reg |= (RK3328_CLK_PLL_POSTDIV1_MASK | RK3328_CLK_PLL_FBDIV_MASK) << 16;
  465         dprintf("Set PLL_CON0 to %x\n", reg);
  466         WRITE4(clk, sc->base_offset, reg);
  467 
  468         /* Setting dsmpd, postdiv2 and refdiv */
  469         reg = (rates->dsmpd << RK3328_CLK_PLL_DSMPD_SHIFT) |
  470                 (rates->postdiv2 << RK3328_CLK_PLL_POSTDIV2_SHIFT) |
  471                 (rates->refdiv << RK3328_CLK_PLL_REFDIV_SHIFT);
  472         reg |= (RK3328_CLK_PLL_DSMPD_MASK |
  473             RK3328_CLK_PLL_POSTDIV2_MASK |
  474             RK3328_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
  475         dprintf("Set PLL_CON1 to %x\n", reg);
  476         WRITE4(clk, sc->base_offset + 0x4, reg);
  477 
  478         /* Setting frac */
  479         READ4(clk, sc->base_offset + 0x8, &reg);
  480         reg &= ~RK3328_CLK_PLL_FRAC_MASK;
  481         reg |= rates->frac << RK3328_CLK_PLL_FRAC_SHIFT;
  482         dprintf("Set PLL_CON2 to %x\n", reg);
  483         WRITE4(clk, sc->base_offset + 0x8, reg);
  484 
  485         /* Reading lock */
  486         for (timeout = 1000; timeout; timeout--) {
  487                 READ4(clk, sc->base_offset + 0x4, &reg);
  488                 if ((reg & RK3328_CLK_PLL_LOCK_MASK) == 0)
  489                         break;
  490                 DELAY(1);
  491         }
  492 
  493         /* Set back to normal mode */
  494         reg = (RK3328_CLK_PLL_MODE_NORMAL << sc->mode_shift);
  495         reg |= (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) <<
  496                 RK_CLK_PLL_MASK_SHIFT;
  497         dprintf("Set PLL_MODEREG to %x\n", reg);
  498         WRITE4(clk, sc->mode_reg, reg);
  499 
  500         DEVICE_UNLOCK(clk);
  501 
  502         *stop = 1;
  503         return (0);
  504 }
  505 
  506 static clknode_method_t rk3328_clk_pll_clknode_methods[] = {
  507         /* Device interface */
  508         CLKNODEMETHOD(clknode_init,             rk3328_clk_pll_init),
  509         CLKNODEMETHOD(clknode_set_gate,         rk_clk_pll_set_gate),
  510         CLKNODEMETHOD(clknode_recalc_freq,      rk3328_clk_pll_recalc),
  511         CLKNODEMETHOD(clknode_set_freq,         rk3328_clk_pll_set_freq),
  512         CLKNODEMETHOD_END
  513 };
  514 
  515 DEFINE_CLASS_1(rk3328_clk_pll_clknode, rk3328_clk_pll_clknode_class,
  516     rk3328_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
  517 
  518 int
  519 rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
  520 {
  521         struct clknode *clk;
  522         struct rk_clk_pll_sc *sc;
  523 
  524         clk = clknode_create(clkdom, &rk3328_clk_pll_clknode_class,
  525             &clkdef->clkdef);
  526         if (clk == NULL)
  527                 return (1);
  528 
  529         sc = clknode_get_softc(clk);
  530 
  531         sc->base_offset = clkdef->base_offset;
  532         sc->gate_offset = clkdef->gate_offset;
  533         sc->gate_shift = clkdef->gate_shift;
  534         sc->mode_reg = clkdef->mode_reg;
  535         sc->mode_shift = clkdef->mode_shift;
  536         sc->flags = clkdef->flags;
  537         sc->rates = clkdef->rates;
  538         sc->frac_rates = clkdef->frac_rates;
  539 
  540         clknode_register(clkdom, clk);
  541 
  542         return (0);
  543 }
  544 
  545 #define RK3399_CLK_PLL_FBDIV_OFFSET             0
  546 #define RK3399_CLK_PLL_FBDIV_SHIFT              0
  547 #define RK3399_CLK_PLL_FBDIV_MASK               0xFFF
  548 
  549 #define RK3399_CLK_PLL_POSTDIV2_OFFSET  4
  550 #define RK3399_CLK_PLL_POSTDIV2_SHIFT   12
  551 #define RK3399_CLK_PLL_POSTDIV2_MASK    0x7000
  552 
  553 #define RK3399_CLK_PLL_POSTDIV1_OFFSET  4
  554 #define RK3399_CLK_PLL_POSTDIV1_SHIFT   8
  555 #define RK3399_CLK_PLL_POSTDIV1_MASK    0x700
  556 
  557 #define RK3399_CLK_PLL_REFDIV_OFFSET    4
  558 #define RK3399_CLK_PLL_REFDIV_SHIFT     0
  559 #define RK3399_CLK_PLL_REFDIV_MASK      0x3F
  560 
  561 #define RK3399_CLK_PLL_FRAC_OFFSET      8
  562 #define RK3399_CLK_PLL_FRAC_SHIFT       0
  563 #define RK3399_CLK_PLL_FRAC_MASK        0xFFFFFF
  564 
  565 #define RK3399_CLK_PLL_DSMPD_OFFSET     0xC
  566 #define RK3399_CLK_PLL_DSMPD_SHIFT      3
  567 #define RK3399_CLK_PLL_DSMPD_MASK       0x8
  568 
  569 #define RK3399_CLK_PLL_LOCK_OFFSET      8
  570 #define RK3399_CLK_PLL_LOCK_MASK        0x400
  571 
  572 #define RK3399_CLK_PLL_MODE_OFFSET      0xC
  573 #define RK3399_CLK_PLL_MODE_MASK        0x300
  574 #define RK3399_CLK_PLL_MODE_SLOW        0
  575 #define RK3399_CLK_PLL_MODE_NORMAL      1
  576 #define RK3399_CLK_PLL_MODE_DEEPSLOW    2
  577 #define RK3399_CLK_PLL_MODE_SHIFT       8
  578 
  579 #define RK3399_CLK_PLL_WRITE_MASK       0xFFFF0000
  580 
  581 static int
  582 rk3399_clk_pll_init(struct clknode *clk, device_t dev)
  583 {
  584         clknode_init_parent_idx(clk, 0);
  585 
  586         return (0);
  587 }
  588 
  589 static int
  590 rk3399_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
  591 {
  592         struct rk_clk_pll_sc *sc;
  593         uint32_t dsmpd, refdiv, fbdiv;
  594         uint32_t postdiv1, postdiv2, fracdiv;
  595         uint32_t con1, con2, con3, con4;
  596         uint64_t foutvco;
  597         uint32_t mode;
  598         sc = clknode_get_softc(clk);
  599 
  600         DEVICE_LOCK(clk);
  601         READ4(clk, sc->base_offset, &con1);
  602         READ4(clk, sc->base_offset + 4, &con2);
  603         READ4(clk, sc->base_offset + 8, &con3);
  604         READ4(clk, sc->base_offset + 0xC, &con4);
  605         DEVICE_UNLOCK(clk);
  606 
  607         /*
  608          * if we are in slow mode the output freq
  609          * is the parent one, the 24Mhz external oscillator
  610          * if we are in deep mode the output freq is 32.768khz
  611          */
  612         mode = (con4 & RK3399_CLK_PLL_MODE_MASK) >> RK3399_CLK_PLL_MODE_SHIFT;
  613         if (mode == RK3399_CLK_PLL_MODE_SLOW) {
  614                 dprintf("pll in slow mode, con4=%x\n", con4);
  615                 return (0);
  616         } else if (mode == RK3399_CLK_PLL_MODE_DEEPSLOW) {
  617                 dprintf("pll in deep slow, con4=%x\n", con4);
  618                 *freq = 32768;
  619                 return (0);
  620         }
  621 
  622         dprintf("con0: %x\n", con1);
  623         dprintf("con1: %x\n", con2);
  624         dprintf("con2: %x\n", con3);
  625         dprintf("con3: %x\n", con4);
  626 
  627         fbdiv = (con1 & RK3399_CLK_PLL_FBDIV_MASK)
  628             >> RK3399_CLK_PLL_FBDIV_SHIFT;
  629 
  630         postdiv1 = (con2 & RK3399_CLK_PLL_POSTDIV1_MASK)
  631             >> RK3399_CLK_PLL_POSTDIV1_SHIFT;
  632         postdiv2 = (con2 & RK3399_CLK_PLL_POSTDIV2_MASK)
  633             >> RK3399_CLK_PLL_POSTDIV2_SHIFT;
  634         refdiv = (con2 & RK3399_CLK_PLL_REFDIV_MASK)
  635             >> RK3399_CLK_PLL_REFDIV_SHIFT;
  636 
  637         fracdiv = (con3 & RK3399_CLK_PLL_FRAC_MASK)
  638             >> RK3399_CLK_PLL_FRAC_SHIFT;
  639         fracdiv >>= 24;
  640 
  641         dsmpd = (con4 & RK3399_CLK_PLL_DSMPD_MASK) >> RK3399_CLK_PLL_DSMPD_SHIFT;
  642 
  643         dprintf("fbdiv: %d\n", fbdiv);
  644         dprintf("postdiv1: %d\n", postdiv1);
  645         dprintf("postdiv2: %d\n", postdiv2);
  646         dprintf("refdiv: %d\n", refdiv);
  647         dprintf("fracdiv: %d\n", fracdiv);
  648         dprintf("dsmpd: %d\n", dsmpd);
  649 
  650         dprintf("parent freq=%ju\n", *freq);
  651 
  652         if (dsmpd == 0) {
  653                 /* Fractional mode */
  654                 foutvco = *freq / refdiv * (fbdiv + fracdiv);
  655         } else {
  656                 /* Integer mode */
  657                 foutvco = *freq / refdiv * fbdiv;
  658         }
  659         dprintf("foutvco: %ju\n", foutvco);
  660 
  661         *freq = foutvco / postdiv1 / postdiv2;
  662         dprintf("freq: %ju\n", *freq);
  663 
  664         return (0);
  665 }
  666 
  667 static int
  668 rk3399_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
  669     int flags, int *stop)
  670 {
  671         struct rk_clk_pll_rate *rates;
  672         struct rk_clk_pll_sc *sc;
  673         uint32_t reg;
  674         int timeout;
  675 
  676         sc = clknode_get_softc(clk);
  677 
  678         if (sc->rates)
  679                 rates = sc->rates;
  680         else if (sc->frac_rates)
  681                 rates = sc->frac_rates;
  682         else
  683                 return (EINVAL);
  684 
  685         for (; rates->freq; rates++) {
  686                 if (rates->freq == *fout)
  687                         break;
  688         }
  689         if (rates->freq == 0) {
  690                 *stop = 1;
  691                 return (EINVAL);
  692         }
  693 
  694         DEVICE_LOCK(clk);
  695 
  696         /* Set to slow mode during frequency change */
  697         reg = RK3399_CLK_PLL_MODE_SLOW << RK3399_CLK_PLL_MODE_SHIFT;
  698         reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
  699         WRITE4(clk, sc->base_offset + 0xC, reg);
  700 
  701         /* Setting fbdiv */
  702         reg = rates->fbdiv << RK3399_CLK_PLL_FBDIV_SHIFT;
  703         reg |= RK3399_CLK_PLL_FBDIV_MASK << RK_CLK_PLL_MASK_SHIFT;
  704         WRITE4(clk, sc->base_offset, reg);
  705 
  706         /* Setting postdiv1, postdiv2 and refdiv */
  707         reg = rates->postdiv1 << RK3399_CLK_PLL_POSTDIV1_SHIFT;
  708         reg |= rates->postdiv2 << RK3399_CLK_PLL_POSTDIV2_SHIFT;
  709         reg |= rates->refdiv << RK3399_CLK_PLL_REFDIV_SHIFT;
  710         reg |= (RK3399_CLK_PLL_POSTDIV1_MASK | RK3399_CLK_PLL_POSTDIV2_MASK |
  711             RK3399_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT;
  712         WRITE4(clk, sc->base_offset + 0x4, reg);
  713 
  714         /* Setting frac */
  715         READ4(clk, sc->base_offset + 0x8, &reg);
  716         reg &= ~RK3399_CLK_PLL_FRAC_MASK;
  717         reg |= rates->frac << RK3399_CLK_PLL_FRAC_SHIFT;
  718         WRITE4(clk, sc->base_offset + 0x8, reg | RK3399_CLK_PLL_WRITE_MASK);
  719 
  720         /* Set dsmpd */
  721         reg = rates->dsmpd << RK3399_CLK_PLL_DSMPD_SHIFT;
  722         reg |= RK3399_CLK_PLL_DSMPD_MASK << RK_CLK_PLL_MASK_SHIFT;
  723         WRITE4(clk, sc->base_offset + 0xC, reg);
  724 
  725         /* Reading lock */
  726         for (timeout = 1000; timeout; timeout--) {
  727                 READ4(clk, sc->base_offset + RK3399_CLK_PLL_LOCK_OFFSET, &reg);
  728                 if ((reg & RK3399_CLK_PLL_LOCK_MASK) == 0)
  729                         break;
  730                 DELAY(1);
  731         }
  732 
  733         /* Set back to normal mode */
  734         reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT;
  735         reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT;
  736         WRITE4(clk, sc->base_offset + 0xC, reg);
  737 
  738         DEVICE_UNLOCK(clk);
  739 
  740         *stop = 1;
  741         return (0);
  742 }
  743 
  744 static clknode_method_t rk3399_clk_pll_clknode_methods[] = {
  745         /* Device interface */
  746         CLKNODEMETHOD(clknode_init,             rk3399_clk_pll_init),
  747         CLKNODEMETHOD(clknode_set_gate,         rk_clk_pll_set_gate),
  748         CLKNODEMETHOD(clknode_recalc_freq,      rk3399_clk_pll_recalc),
  749         CLKNODEMETHOD(clknode_set_freq,         rk3399_clk_pll_set_freq),
  750         CLKNODEMETHOD_END
  751 };
  752 
  753 DEFINE_CLASS_1(rk3399_clk_pll_clknode, rk3399_clk_pll_clknode_class,
  754     rk3399_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class);
  755 
  756 int
  757 rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef)
  758 {
  759         struct clknode *clk;
  760         struct rk_clk_pll_sc *sc;
  761 
  762         clk = clknode_create(clkdom, &rk3399_clk_pll_clknode_class,
  763             &clkdef->clkdef);
  764         if (clk == NULL)
  765                 return (1);
  766 
  767         sc = clknode_get_softc(clk);
  768 
  769         sc->base_offset = clkdef->base_offset;
  770         sc->gate_offset = clkdef->gate_offset;
  771         sc->gate_shift = clkdef->gate_shift;
  772         sc->flags = clkdef->flags;
  773         sc->rates = clkdef->rates;
  774         sc->frac_rates = clkdef->frac_rates;
  775 
  776         clknode_register(clkdom, clk);
  777 
  778         return (0);
  779 }

Cache object: 83c17beedde78ba1fab97d75998c464e


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