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/nvidia/tegra124/tegra124_clk_super.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) 2016 Michal Meloun <mmel@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/lock.h>
   34 #include <sys/mutex.h>
   35 #include <sys/rman.h>
   36 
   37 #include <machine/bus.h>
   38 
   39 #include <dev/extres/clk/clk.h>
   40 
   41 #include <dt-bindings/clock/tegra124-car.h>
   42 #include "tegra124_car.h"
   43 
   44 /* Flags */
   45 #define SMF_HAVE_DIVIDER_2      1
   46 
   47 struct super_mux_def {
   48         struct clknode_init_def clkdef;
   49         uint32_t                base_reg;
   50         uint32_t                flags;
   51         int                     src_pllx;
   52         int                     src_div2;
   53 };
   54 
   55 #define PLIST(x) static const char *x[]
   56 #define SM(_id, cn, pl, r, x, d, f)                             \
   57 {                                                                       \
   58         .clkdef.id = _id,                                               \
   59         .clkdef.name = cn,                                              \
   60         .clkdef.parent_names = pl,                                      \
   61         .clkdef.parent_cnt = nitems(pl),                                \
   62         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                                \
   63         .base_reg = r,                                                  \
   64         .src_pllx = x,                                                  \
   65         .src_div2 = d,                                                  \
   66         .flags = f,                                                     \
   67 }
   68 
   69 PLIST(cclk_g_parents) = {
   70         "clk_m", "pllC_out0", "clk_s", "pllM_out0",
   71         "pllP_out0", "pllP_out4", "pllC2_out0", "pllC3_out0",
   72         "pllX_out", NULL, NULL, NULL,
   73         NULL, NULL, NULL,NULL, // "dfllCPU_out0"
   74 };
   75 
   76 PLIST(cclk_lp_parents) = {
   77         "clk_m", "pllC_out0", "clk_s", "pllM_out0",
   78         "pllP_out0", "pllP_out4", "pllC2_out0", "pllC3_out0",
   79         "pllX_out", NULL, NULL, NULL,
   80         NULL, NULL, NULL, NULL,
   81         "pllX_out0"
   82 };
   83 
   84 PLIST(sclk_parents) = {
   85         "clk_m", "pllC_out1", "pllP_out4", "pllP_out0",
   86         "pllP_out2", "pllC_out0", "clk_s", "pllM_out1",
   87 };
   88 
   89 static struct super_mux_def super_mux_def[] = {
   90  SM(TEGRA124_CLK_CCLK_G, "cclk_g", cclk_g_parents, CCLKG_BURST_POLICY, 0, 0, 0),
   91  SM(TEGRA124_CLK_CCLK_LP, "cclk_lp", cclk_lp_parents, CCLKLP_BURST_POLICY, 8, 16, SMF_HAVE_DIVIDER_2),
   92  SM(TEGRA124_CLK_SCLK, "sclk", sclk_parents, SCLK_BURST_POLICY, 0, 0, 0),
   93 };
   94 
   95 static int super_mux_init(struct clknode *clk, device_t dev);
   96 static int super_mux_set_mux(struct clknode *clk, int idx);
   97 
   98 struct super_mux_sc {
   99         device_t                clkdev;
  100         uint32_t                base_reg;
  101         int                     src_pllx;
  102         int                     src_div2;
  103         uint32_t                flags;
  104 
  105         int                     mux;
  106 };
  107 
  108 static clknode_method_t super_mux_methods[] = {
  109         /* Device interface */
  110         CLKNODEMETHOD(clknode_init,             super_mux_init),
  111         CLKNODEMETHOD(clknode_set_mux,          super_mux_set_mux),
  112         CLKNODEMETHOD_END
  113 };
  114 DEFINE_CLASS_1(tegra124_super_mux, tegra124_super_mux_class, super_mux_methods,
  115    sizeof(struct super_mux_sc), clknode_class);
  116 
  117 /* Mux status. */
  118 #define SUPER_MUX_STATE_STDBY           0
  119 #define SUPER_MUX_STATE_IDLE            1
  120 #define SUPER_MUX_STATE_RUN             2
  121 #define SUPER_MUX_STATE_IRQ             3
  122 #define SUPER_MUX_STATE_FIQ             4
  123 
  124 /* Mux register bits. */
  125 #define SUPER_MUX_STATE_BIT_SHIFT       28
  126 #define SUPER_MUX_STATE_BIT_MASK        0xF
  127 /* State is Priority encoded */
  128 #define SUPER_MUX_STATE_BIT_STDBY       0x00
  129 #define SUPER_MUX_STATE_BIT_IDLE        0x01
  130 #define SUPER_MUX_STATE_BIT_RUN         0x02
  131 #define SUPER_MUX_STATE_BIT_IRQ         0x04
  132 #define SUPER_MUX_STATE_BIT_FIQ         0x08
  133 
  134 #define SUPER_MUX_MUX_WIDTH             4
  135 #define SUPER_MUX_LP_DIV2_BYPASS        (1 << 16)
  136 
  137 static uint32_t
  138 super_mux_get_state(uint32_t reg)
  139 {
  140         reg = (reg >> SUPER_MUX_STATE_BIT_SHIFT) & SUPER_MUX_STATE_BIT_MASK;
  141         if (reg & SUPER_MUX_STATE_BIT_FIQ)
  142                  return (SUPER_MUX_STATE_FIQ);
  143         if (reg & SUPER_MUX_STATE_BIT_IRQ)
  144                  return (SUPER_MUX_STATE_IRQ);
  145         if (reg & SUPER_MUX_STATE_BIT_RUN)
  146                  return (SUPER_MUX_STATE_RUN);
  147         if (reg & SUPER_MUX_STATE_BIT_IDLE)
  148                  return (SUPER_MUX_STATE_IDLE);
  149         return (SUPER_MUX_STATE_STDBY);
  150 }
  151 
  152 static int
  153 super_mux_init(struct clknode *clk, device_t dev)
  154 {
  155         struct super_mux_sc *sc;
  156         uint32_t reg;
  157         int shift, state;
  158 
  159         sc = clknode_get_softc(clk);
  160 
  161         DEVICE_LOCK(sc);
  162         RD4(sc, sc->base_reg, &reg);
  163         DEVICE_UNLOCK(sc);
  164         state = super_mux_get_state(reg);
  165 
  166         if ((state != SUPER_MUX_STATE_RUN) &&
  167             (state != SUPER_MUX_STATE_IDLE)) {
  168                 panic("Unexpected super mux state: %u", state);
  169         }
  170 
  171         shift = state * SUPER_MUX_MUX_WIDTH;
  172 
  173         sc->mux = (reg >> shift) & ((1 << SUPER_MUX_MUX_WIDTH) - 1);
  174 
  175         /*
  176          * CCLKLP uses PLLX/2 as source if LP_DIV2_BYPASS isn't set
  177          * and source mux is set to PLLX.
  178          */
  179         if (sc->flags & SMF_HAVE_DIVIDER_2) {
  180                 if (((reg & SUPER_MUX_LP_DIV2_BYPASS) == 0) &&
  181                     (sc->mux == sc->src_pllx))
  182                 sc->mux = sc->src_div2;
  183         }
  184         clknode_init_parent_idx(clk, sc->mux);
  185 
  186         return(0);
  187 }
  188 
  189 static int
  190 super_mux_set_mux(struct clknode *clk, int idx)
  191 {
  192 
  193         struct super_mux_sc *sc;
  194         int shift, state;
  195         uint32_t reg, dummy;
  196 
  197         sc = clknode_get_softc(clk);
  198 
  199         DEVICE_LOCK(sc);
  200         RD4(sc, sc->base_reg, &reg);
  201         state = super_mux_get_state(reg);
  202 
  203         if ((state != SUPER_MUX_STATE_RUN) &&
  204             (state != SUPER_MUX_STATE_IDLE)) {
  205                 panic("Unexpected super mux state: %u", state);
  206         }
  207         shift = (state - 1) * SUPER_MUX_MUX_WIDTH;
  208         sc->mux = idx;
  209         if (sc->flags & SMF_HAVE_DIVIDER_2) {
  210                 if (idx == sc->src_div2) {
  211                         idx = sc->src_pllx;
  212                         reg &= ~SUPER_MUX_LP_DIV2_BYPASS;
  213                         WR4(sc, sc->base_reg, reg);
  214                         RD4(sc, sc->base_reg, &dummy);
  215                 } else if (idx == sc->src_pllx) {
  216                         reg = SUPER_MUX_LP_DIV2_BYPASS;
  217                         WR4(sc, sc->base_reg, reg);
  218                         RD4(sc, sc->base_reg, &dummy);
  219                 }
  220         }
  221         reg &= ~(((1 << SUPER_MUX_MUX_WIDTH) - 1) << shift);
  222         reg |= idx << shift;
  223 
  224         WR4(sc, sc->base_reg, reg);
  225         RD4(sc, sc->base_reg, &dummy);
  226         DEVICE_UNLOCK(sc);
  227 
  228         return(0);
  229 }
  230 
  231 static int
  232 super_mux_register(struct clkdom *clkdom, struct super_mux_def *clkdef)
  233 {
  234         struct clknode *clk;
  235         struct super_mux_sc *sc;
  236 
  237         clk = clknode_create(clkdom, &tegra124_super_mux_class,
  238             &clkdef->clkdef);
  239         if (clk == NULL)
  240                 return (1);
  241 
  242         sc = clknode_get_softc(clk);
  243         sc->clkdev = clknode_get_device(clk);
  244         sc->base_reg = clkdef->base_reg;
  245         sc->src_pllx = clkdef->src_pllx;
  246         sc->src_div2 = clkdef->src_div2;
  247         sc->flags = clkdef->flags;
  248 
  249         clknode_register(clkdom, clk);
  250         return (0);
  251 }
  252 
  253 void
  254 tegra124_super_mux_clock(struct tegra124_car_softc *sc)
  255 {
  256         int i, rv;
  257 
  258         for (i = 0; i <  nitems(super_mux_def); i++) {
  259                 rv = super_mux_register(sc->clkdom, &super_mux_def[i]);
  260                 if (rv != 0)
  261                         panic("super_mux_register failed");
  262         }
  263 
  264 }

Cache object: 922dca417e67c4764a9613a75f92577e


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