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_car.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/kernel.h>
   34 #include <sys/kobj.h>
   35 #include <sys/module.h>
   36 #include <sys/malloc.h>
   37 #include <sys/rman.h>
   38 #include <sys/lock.h>
   39 #include <sys/mutex.h>
   40 
   41 #include <machine/bus.h>
   42 #include <machine/cpu.h>
   43 
   44 #include <dev/extres/clk/clk_div.h>
   45 #include <dev/extres/clk/clk_fixed.h>
   46 #include <dev/extres/clk/clk_gate.h>
   47 #include <dev/extres/clk/clk_mux.h>
   48 #include <dev/extres/hwreset/hwreset.h>
   49 #include <dev/ofw/openfirm.h>
   50 #include <dev/ofw/ofw_bus.h>
   51 #include <dev/ofw/ofw_bus_subr.h>
   52 
   53 #include <dt-bindings/clock/tegra124-car.h>
   54 
   55 #include "clkdev_if.h"
   56 #include "hwreset_if.h"
   57 #include "tegra124_car.h"
   58 
   59 static struct ofw_compat_data compat_data[] = {
   60         {"nvidia,tegra124-car", 1},
   61         {NULL,                  0},
   62 };
   63 
   64 #define PLIST(x) static const char *x[]
   65 
   66 /* Pure multiplexer. */
   67 #define MUX(_id, cname, plists, o, s, w)                                \
   68 {                                                                       \
   69         .clkdef.id = _id,                                               \
   70         .clkdef.name = cname,                                           \
   71         .clkdef.parent_names = plists,                                  \
   72         .clkdef.parent_cnt = nitems(plists),                            \
   73         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
   74         .offset = o,                                                    \
   75         .shift  = s,                                                    \
   76         .width = w,                                                     \
   77 }
   78 
   79 /* Fractional divider (7.1). */
   80 #define DIV7_1(_id, cname, plist, o, s)                                 \
   81 {                                                                       \
   82         .clkdef.id = _id,                                               \
   83         .clkdef.name = cname,                                           \
   84         .clkdef.parent_names = (const char *[]){plist},                 \
   85         .clkdef.parent_cnt = 1,                                         \
   86         .clkdef.flags =  CLK_NODE_STATIC_STRINGS,                       \
   87         .offset = o,                                                    \
   88         .i_shift = (s) + 1,                                             \
   89         .i_width = 7,                                                   \
   90         .f_shift = s,                                                   \
   91         .f_width = 1,                                                   \
   92 }
   93 
   94 /* Integer divider. */
   95 #define DIV(_id, cname, plist, o, s, w, f)                              \
   96 {                                                                       \
   97         .clkdef.id = _id,                                               \
   98         .clkdef.name = cname,                                           \
   99         .clkdef.parent_names = (const char *[]){plist},                 \
  100         .clkdef.parent_cnt = 1,                                         \
  101         .clkdef.flags =  CLK_NODE_STATIC_STRINGS,                       \
  102         .offset = o,                                                    \
  103         .i_shift = s,                                                   \
  104         .i_width = w,                                                   \
  105         .div_flags = f,                                                 \
  106 }
  107 
  108 /* Gate in PLL block. */
  109 #define GATE_PLL(_id, cname, plist, o, s)                               \
  110 {                                                                       \
  111         .clkdef.id = _id,                                               \
  112         .clkdef.name = cname,                                           \
  113         .clkdef.parent_names = (const char *[]){plist},                 \
  114         .clkdef.parent_cnt = 1,                                         \
  115         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
  116         .offset = o,                                                    \
  117         .shift = s,                                                     \
  118         .mask = 3,                                                      \
  119         .on_value = 3,                                                  \
  120         .off_value = 0,                                                 \
  121 }
  122 
  123 /* Standard gate. */
  124 #define GATE(_id, cname, plist, o, s)                                   \
  125 {                                                                       \
  126         .clkdef.id = _id,                                               \
  127         .clkdef.name = cname,                                           \
  128         .clkdef.parent_names = (const char *[]){plist},                 \
  129         .clkdef.parent_cnt = 1,                                         \
  130         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
  131         .offset = o,                                                    \
  132         .shift = s,                                                     \
  133         .mask = 1,                                                      \
  134         .on_value = 1,                                                  \
  135         .off_value = 0,                                                 \
  136 }
  137 
  138 /* Inverted gate. */
  139 #define GATE_INV(_id, cname, plist, o, s)                               \
  140 {                                                                       \
  141         .clkdef.id = _id,                                               \
  142         .clkdef.name = cname,                                           \
  143         .clkdef.parent_names = (const char *[]){plist},                 \
  144         .clkdef.parent_cnt = 1,                                         \
  145         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
  146         .offset = o,                                                    \
  147         .shift = s,                                                     \
  148         .mask = 1,                                                      \
  149         .on_value = 0,                                                  \
  150         .off_value = 1,                                                 \
  151 }
  152 
  153 /* Fixed rate clock. */
  154 #define FRATE(_id, cname, _freq)                                        \
  155 {                                                                       \
  156         .clkdef.id = _id,                                               \
  157         .clkdef.name = cname,                                           \
  158         .clkdef.parent_names = NULL,                                    \
  159         .clkdef.parent_cnt = 0,                                         \
  160         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
  161         .freq = _freq,                                                  \
  162 }
  163 
  164 /* Fixed rate multipier/divider. */
  165 #define FACT(_id, cname, pname, _mult, _div)                            \
  166 {                                                                       \
  167         .clkdef.id = _id,                                               \
  168         .clkdef.name = cname,                                           \
  169         .clkdef.parent_names = (const char *[]){pname},                 \
  170         .clkdef.parent_cnt = 1,                                         \
  171         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
  172         .mult = _mult,                                                  \
  173         .div = _div,                                                    \
  174 }
  175 
  176 static uint32_t osc_freqs[16] = {
  177          [0] =  13000000,
  178          [1] =  16800000,
  179          [4] =  19200000,
  180          [5] =  38400000,
  181          [8] =  12000000,
  182          [9] =  48000000,
  183         [12] = 260000000,
  184 };
  185 
  186 /* Parent lists. */
  187 PLIST(mux_pll_srcs) = {"osc_div_clk", NULL, "pllP_out0", NULL}; /* FIXME */
  188 PLIST(mux_plle_src1) = {"osc_div_clk", "pllP_out0"};
  189 PLIST(mux_plle_src) = {"pllE_src1", "pllREFE_out"};
  190 PLIST(mux_plld_out0_plld2_out0) = {"pllD_out0", "pllD2_out0"};
  191 PLIST(mux_xusb_hs) = {"xusb_ss_div2", "pllU_60"};
  192 PLIST(mux_xusb_ss) = {"pc_xusb_ss", "osc_div_clk"};
  193 
  194 /* Clocks adjusted online. */
  195 static struct clk_fixed_def fixed_clk_m =
  196         FRATE(TEGRA124_CLK_CLK_M, "clk_m", 12000000);
  197 static struct clk_fixed_def fixed_osc_div_clk =
  198         FACT(0, "osc_div_clk", "clk_m", 1, 1);
  199 
  200 static struct clk_fixed_def tegra124_fixed_clks[] = {
  201         /* Core clocks. */
  202         FRATE(0, "clk_s", 32768),
  203         FACT(0, "clk_m_div2", "clk_m", 1, 2),
  204         FACT(0, "clk_m_div4", "clk_m", 1, 3),
  205         FACT(0, "pllU_60", "pllU_out", 1, 8),
  206         FACT(0, "pllU_48", "pllU_out", 1, 10),
  207         FACT(0, "pllU_12", "pllU_out", 1, 40),
  208         FACT(TEGRA124_CLK_PLL_D_OUT0, "pllD_out0", "pllD_out", 1, 2),
  209         FACT(TEGRA124_CLK_PLL_D2_OUT0, "pllD2_out0", "pllD2_out", 1, 1),
  210         FACT(0, "pllX_out0", "pllX_out", 1, 2),
  211         FACT(0, "pllC_UD", "pllC_out0", 1, 1),
  212         FACT(0, "pllM_UD", "pllM_out0", 1, 1),
  213 
  214         /* Audio clocks. */
  215         FRATE(0, "audio0", 10000000),
  216         FRATE(0, "audio1", 10000000),
  217         FRATE(0, "audio2", 10000000),
  218         FRATE(0, "audio3", 10000000),
  219         FRATE(0, "audio4", 10000000),
  220         FRATE(0, "ext_vimclk", 10000000),
  221 
  222         /* XUSB */
  223         FACT(TEGRA124_CLK_XUSB_SS_DIV2, "xusb_ss_div2", "xusb_ss", 1, 2),
  224 
  225 };
  226 
  227 static struct clk_mux_def tegra124_mux_clks[] = {
  228         /* Core clocks. */
  229         MUX(0, "pllD2_src", mux_pll_srcs, PLLD2_BASE, 25, 2),
  230         MUX(0, "pllDP_src", mux_pll_srcs, PLLDP_BASE, 25, 2),
  231         MUX(0, "pllC4_src", mux_pll_srcs, PLLC4_BASE, 25, 2),
  232         MUX(0, "pllE_src1", mux_plle_src1, PLLE_AUX, 2, 1),
  233         MUX(0, "pllE_src",  mux_plle_src, PLLE_AUX, 28, 1),
  234 
  235         /* Base peripheral clocks. */
  236         MUX(0, "dsia_mux", mux_plld_out0_plld2_out0, PLLD_BASE, 25, 1),
  237         MUX(0, "dsib_mux", mux_plld_out0_plld2_out0, PLLD2_BASE, 25, 1),
  238 
  239         /* USB. */
  240         MUX(TEGRA124_CLK_XUSB_HS_SRC, "xusb_hs", mux_xusb_hs, CLK_SOURCE_XUSB_SS, 25, 1),
  241         MUX(0, "xusb_ss_mux", mux_xusb_ss, CLK_SOURCE_XUSB_SS, 24, 1),
  242 
  243 };
  244 
  245 static struct clk_gate_def tegra124_gate_clks[] = {
  246         /* Core clocks. */
  247         GATE_PLL(0, "pllC_out1", "pllC_out1_div", PLLC_OUT, 0),
  248         GATE_PLL(0, "pllM_out1", "pllM_out1_div", PLLM_OUT, 0),
  249         GATE_PLL(TEGRA124_CLK_PLL_U_480M, "pllU_480", "pllU_out", PLLU_BASE, 22),
  250         GATE_PLL(0, "pllP_outX0", "pllP_outX0_div", PLLP_RESHIFT, 0),
  251         GATE_PLL(0, "pllP_out1", "pllP_out1_div", PLLP_OUTA, 0),
  252         GATE_PLL(0, "pllP_out2", "pllP_out2_div", PLLP_OUTA, 16),
  253         GATE_PLL(0, "pllP_out3", "pllP_out3_div", PLLP_OUTB, 0),
  254         GATE_PLL(0, "pllP_out4", "pllP_out4_div", PLLP_OUTB, 16),
  255         GATE_PLL(0, "pllP_out5", "pllP_out5_div", PLLP_OUTC, 16),
  256         GATE_PLL(0, "pllA_out0", "pllA_out1_div", PLLA_OUT, 0),
  257 
  258         /* Base peripheral clocks. */
  259         GATE(TEGRA124_CLK_CML0, "cml0", "pllE_out0", PLLE_AUX, 0),
  260         GATE(TEGRA124_CLK_CML1, "cml1", "pllE_out0", PLLE_AUX, 1),
  261         GATE_INV(TEGRA124_CLK_HCLK, "hclk", "hclk_div", CLK_SYSTEM_RATE, 7),
  262         GATE_INV(TEGRA124_CLK_PCLK, "pclk", "pclk_div", CLK_SYSTEM_RATE, 3),
  263 };
  264 
  265 static struct clk_div_def tegra124_div_clks[] = {
  266         /* Core clocks. */
  267         DIV7_1(0, "pllC_out1_div", "pllC_out0", PLLC_OUT, 2),
  268         DIV7_1(0, "pllM_out1_div", "pllM_out0", PLLM_OUT, 8),
  269         DIV7_1(0, "pllP_outX0_div", "pllP_out0", PLLP_RESHIFT, 2),
  270         DIV7_1(0, "pllP_out1_div", "pllP_out0", PLLP_OUTA, 8),
  271         DIV7_1(0, "pllP_out2_div", "pllP_out0", PLLP_OUTA, 24),
  272         DIV7_1(0, "pllP_out3_div", "pllP_out0", PLLP_OUTB, 8),
  273         DIV7_1(0, "pllP_out4_div", "pllP_out0", PLLP_OUTB, 24),
  274         DIV7_1(0, "pllP_out5_div", "pllP_out0", PLLP_OUTC, 24),
  275         DIV7_1(0, "pllA_out1_div", "pllA_out", PLLA_OUT, 8),
  276 
  277         /* Base peripheral clocks. */
  278         DIV(0, "hclk_div", "sclk", CLK_SYSTEM_RATE, 4, 2, 0),
  279         DIV(0, "pclk_div", "hclk", CLK_SYSTEM_RATE, 0, 2, 0),
  280 };
  281 
  282 /* Initial setup table. */
  283 static struct  tegra124_init_item clk_init_table[] = {
  284         /* clock, partent, frequency, enable */
  285         {"uarta", "pllP_out0", 408000000, 0},
  286         {"uartb", "pllP_out0", 408000000, 0},
  287         {"uartc", "pllP_out0", 408000000, 0},
  288         {"uartd", "pllP_out0", 408000000, 0},
  289         {"pllA_out", NULL, 282240000, 1},
  290         {"pllA_out0", NULL, 11289600, 1},
  291         {"extperiph1", "pllA_out0", 0, 1},
  292         {"i2s0", "pllA_out0", 11289600, 0},
  293         {"i2s1", "pllA_out0", 11289600, 0},
  294         {"i2s2", "pllA_out0", 11289600, 0},
  295         {"i2s3", "pllA_out0", 11289600, 0},
  296         {"i2s4", "pllA_out0", 11289600, 0},
  297         {"vde", "pllP_out0", 0, 0},
  298         {"host1x", "pllP_out0", 136000000, 1},
  299         {"sclk", "pllP_out2", 102000000, 1},
  300         {"dvfs_soc", "pllP_out0", 51000000, 1},
  301         {"dvfs_ref", "pllP_out0", 51000000, 1},
  302         {"pllC_out0", NULL, 600000000, 0},
  303         {"pllC_out1", NULL, 100000000, 0},
  304         {"spi4", "pllP_out0", 12000000, 1},
  305         {"tsec", "pllC3_out0", 0, 0},
  306         {"msenc", "pllC3_out0", 0, 0},
  307         {"pllREFE_out", NULL, 672000000, 0},
  308         {"pc_xusb_ss", "pllU_480", 120000000, 0},
  309         {"xusb_ss", "pc_xusb_ss", 120000000, 0},
  310         {"pc_xusb_fs", "pllU_48", 48000000, 0},
  311         {"xusb_hs", "pllU_60", 60000000, 0},
  312         {"pc_xusb_falcon", "pllREFE_out", 224000000, 0},
  313         {"xusb_core_host", "pllREFE_out", 112000000, 0},
  314         {"sata", "pllP_out0", 102000000, 0},
  315         {"sata_oob", "pllP_out0", 204000000, 0},
  316         {"sata_cold", NULL, 0, 1},
  317         {"emc", NULL, 0, 1},
  318         {"mselect", NULL, 0, 1},
  319         {"csite", NULL, 0, 1},
  320         {"tsensor", "clk_m", 400000, 0},
  321 
  322         /* tegra124 only*/
  323         {"soc_therm", "pllP_out0", 51000000, 0},
  324         {"cclk_g", NULL, 0, 1},
  325         {"hda", "pllP_out0", 102000000, 0},
  326         {"hda2codec_2x", "pllP_out0", 48000000, 0},
  327 };
  328 
  329 static void
  330 init_divs(struct tegra124_car_softc *sc, struct clk_div_def *clks, int nclks)
  331 {
  332         int i, rv;
  333 
  334         for (i = 0; i < nclks; i++) {
  335                 rv = clknode_div_register(sc->clkdom, clks + i);
  336                 if (rv != 0)
  337                         panic("clk_div_register failed");
  338         }
  339 }
  340 
  341 static void
  342 init_gates(struct tegra124_car_softc *sc, struct clk_gate_def *clks, int nclks)
  343 {
  344         int i, rv;
  345 
  346         for (i = 0; i < nclks; i++) {
  347                 rv = clknode_gate_register(sc->clkdom, clks + i);
  348                 if (rv != 0)
  349                         panic("clk_gate_register failed");
  350         }
  351 }
  352 
  353 static void
  354 init_muxes(struct tegra124_car_softc *sc, struct clk_mux_def *clks, int nclks)
  355 {
  356         int i, rv;
  357 
  358         for (i = 0; i < nclks; i++) {
  359                 rv = clknode_mux_register(sc->clkdom, clks + i);
  360                 if (rv != 0)
  361                         panic("clk_mux_register failed");
  362         }
  363 }
  364 
  365 static void
  366 init_fixeds(struct tegra124_car_softc *sc, struct clk_fixed_def *clks,
  367     int nclks)
  368 {
  369         int i, rv;
  370         uint32_t val;
  371         int osc_idx;
  372 
  373         CLKDEV_READ_4(sc->dev, OSC_CTRL, &val);
  374         osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT;
  375         fixed_clk_m.freq = osc_freqs[osc_idx];
  376         if (fixed_clk_m.freq == 0)
  377                 panic("Undefined input frequency");
  378         rv = clknode_fixed_register(sc->clkdom, &fixed_clk_m);
  379         if (rv != 0) panic("clk_fixed_register failed");
  380 
  381         val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3;
  382         fixed_osc_div_clk.div = 1 << val;
  383         rv = clknode_fixed_register(sc->clkdom, &fixed_osc_div_clk);
  384         if (rv != 0) panic("clk_fixed_register failed");
  385 
  386         for (i = 0; i < nclks; i++) {
  387                 rv = clknode_fixed_register(sc->clkdom, clks + i);
  388                 if (rv != 0)
  389                         panic("clk_fixed_register failed");
  390         }
  391 }
  392 
  393 static void
  394 postinit_clock(struct tegra124_car_softc *sc)
  395 {
  396         int i;
  397         struct tegra124_init_item *tbl;
  398         struct clknode *clknode;
  399         int rv;
  400 
  401         for (i = 0; i < nitems(clk_init_table); i++) {
  402                 tbl = &clk_init_table[i];
  403 
  404                 clknode =  clknode_find_by_name(tbl->name);
  405                 if (clknode == NULL) {
  406                         device_printf(sc->dev, "Cannot find clock %s\n",
  407                             tbl->name);
  408                         continue;
  409                 }
  410                 if (tbl->parent != NULL) {
  411                         rv = clknode_set_parent_by_name(clknode, tbl->parent);
  412                         if (rv != 0) {
  413                                 device_printf(sc->dev,
  414                                     "Cannot set parent for %s (to %s): %d\n",
  415                                     tbl->name, tbl->parent, rv);
  416                                 continue;
  417                         }
  418                 }
  419                 if (tbl->frequency != 0) {
  420                         rv = clknode_set_freq(clknode, tbl->frequency, 0 , 9999);
  421                         if (rv != 0) {
  422                                 device_printf(sc->dev,
  423                                     "Cannot set frequency for %s: %d\n",
  424                                     tbl->name, rv);
  425                                 continue;
  426                         }
  427                 }
  428                 if (tbl->enable!= 0) {
  429                         rv = clknode_enable(clknode);
  430                         if (rv != 0) {
  431                                 device_printf(sc->dev,
  432                                     "Cannot enable %s: %d\n", tbl->name, rv);
  433                                 continue;
  434                         }
  435                 }
  436         }
  437 }
  438 
  439 static void
  440 register_clocks(device_t dev)
  441 {
  442         struct tegra124_car_softc *sc;
  443 
  444         sc = device_get_softc(dev);
  445         sc->clkdom = clkdom_create(dev);
  446         if (sc->clkdom == NULL)
  447                 panic("clkdom == NULL");
  448 
  449         tegra124_init_plls(sc);
  450         init_fixeds(sc, tegra124_fixed_clks, nitems(tegra124_fixed_clks));
  451         init_muxes(sc, tegra124_mux_clks, nitems(tegra124_mux_clks));
  452         init_divs(sc, tegra124_div_clks, nitems(tegra124_div_clks));
  453         init_gates(sc, tegra124_gate_clks, nitems(tegra124_gate_clks));
  454         tegra124_periph_clock(sc);
  455         tegra124_super_mux_clock(sc);
  456         clkdom_finit(sc->clkdom);
  457         clkdom_xlock(sc->clkdom);
  458         postinit_clock(sc);
  459         clkdom_unlock(sc->clkdom);
  460         if (bootverbose)
  461                 clkdom_dump(sc->clkdom);
  462 }
  463 
  464 static int
  465 tegra124_car_clkdev_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
  466 {
  467         struct tegra124_car_softc *sc;
  468 
  469         sc = device_get_softc(dev);
  470         *val = bus_read_4(sc->mem_res, addr);
  471         return (0);
  472 }
  473 
  474 static int
  475 tegra124_car_clkdev_write_4(device_t dev, bus_addr_t addr, uint32_t val)
  476 {
  477         struct tegra124_car_softc *sc;
  478 
  479         sc = device_get_softc(dev);
  480         bus_write_4(sc->mem_res, addr, val);
  481         return (0);
  482 }
  483 
  484 static int
  485 tegra124_car_clkdev_modify_4(device_t dev, bus_addr_t addr, uint32_t clear_mask,
  486     uint32_t set_mask)
  487 {
  488         struct tegra124_car_softc *sc;
  489         uint32_t reg;
  490 
  491         sc = device_get_softc(dev);
  492         reg = bus_read_4(sc->mem_res, addr);
  493         reg &= ~clear_mask;
  494         reg |= set_mask;
  495         bus_write_4(sc->mem_res, addr, reg);
  496         return (0);
  497 }
  498 
  499 static void
  500 tegra124_car_clkdev_device_lock(device_t dev)
  501 {
  502         struct tegra124_car_softc *sc;
  503 
  504         sc = device_get_softc(dev);
  505         mtx_lock(&sc->mtx);
  506 }
  507 
  508 static void
  509 tegra124_car_clkdev_device_unlock(device_t dev)
  510 {
  511         struct tegra124_car_softc *sc;
  512 
  513         sc = device_get_softc(dev);
  514         mtx_unlock(&sc->mtx);
  515 }
  516 
  517 static int
  518 tegra124_car_detach(device_t dev)
  519 {
  520 
  521         device_printf(dev, "Error: Clock driver cannot be detached\n");
  522         return (EBUSY);
  523 }
  524 
  525 static int
  526 tegra124_car_probe(device_t dev)
  527 {
  528 
  529         if (!ofw_bus_status_okay(dev))
  530                 return (ENXIO);
  531 
  532         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
  533                 device_set_desc(dev, "Tegra Clock Driver");
  534                 return (BUS_PROBE_DEFAULT);
  535         }
  536 
  537         return (ENXIO);
  538 }
  539 
  540 static int
  541 tegra124_car_attach(device_t dev)
  542 {
  543         struct tegra124_car_softc *sc = device_get_softc(dev);
  544         int rid, rv;
  545 
  546         sc->dev = dev;
  547 
  548         mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
  549         sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
  550 
  551         /* Resource setup. */
  552         rid = 0;
  553         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  554             RF_ACTIVE);
  555         if (!sc->mem_res) {
  556                 device_printf(dev, "cannot allocate memory resource\n");
  557                 rv = ENXIO;
  558                 goto fail;
  559         }
  560 
  561         register_clocks(dev);
  562         hwreset_register_ofw_provider(dev);
  563         return (0);
  564 
  565 fail:
  566         if (sc->mem_res)
  567                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
  568 
  569         return (rv);
  570 }
  571 
  572 static int
  573 tegra124_car_hwreset_assert(device_t dev, intptr_t id, bool value)
  574 {
  575         struct tegra124_car_softc *sc = device_get_softc(dev);
  576 
  577         return (tegra124_hwreset_by_idx(sc, id, value));
  578 }
  579 
  580 static device_method_t tegra124_car_methods[] = {
  581         /* Device interface */
  582         DEVMETHOD(device_probe,         tegra124_car_probe),
  583         DEVMETHOD(device_attach,        tegra124_car_attach),
  584         DEVMETHOD(device_detach,        tegra124_car_detach),
  585 
  586         /* Clkdev  interface*/
  587         DEVMETHOD(clkdev_read_4,        tegra124_car_clkdev_read_4),
  588         DEVMETHOD(clkdev_write_4,       tegra124_car_clkdev_write_4),
  589         DEVMETHOD(clkdev_modify_4,      tegra124_car_clkdev_modify_4),
  590         DEVMETHOD(clkdev_device_lock,   tegra124_car_clkdev_device_lock),
  591         DEVMETHOD(clkdev_device_unlock, tegra124_car_clkdev_device_unlock),
  592 
  593         /* Reset interface */
  594         DEVMETHOD(hwreset_assert,       tegra124_car_hwreset_assert),
  595 
  596         DEVMETHOD_END
  597 };
  598 
  599 static DEFINE_CLASS_0(car, tegra124_car_driver, tegra124_car_methods,
  600     sizeof(struct tegra124_car_softc));
  601 EARLY_DRIVER_MODULE(tegra124_car, simplebus, tegra124_car_driver, NULL, NULL,
  602     BUS_PASS_TIMER);

Cache object: 3b0c1067f19165633f02fdc9962bedf2


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