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/nvidia/tegra210/tegra210_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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright 2020 Michal Meloun <mmel@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 AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, 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 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/bus.h>
   34 #include <sys/kernel.h>
   35 #include <sys/kobj.h>
   36 #include <sys/module.h>
   37 #include <sys/malloc.h>
   38 #include <sys/rman.h>
   39 #include <sys/lock.h>
   40 #include <sys/mutex.h>
   41 
   42 #include <machine/bus.h>
   43 #include <machine/cpu.h>
   44 
   45 #include <dev/extres/clk/clk_div.h>
   46 #include <dev/extres/clk/clk_fixed.h>
   47 #include <dev/extres/clk/clk_gate.h>
   48 #include <dev/extres/clk/clk_mux.h>
   49 #include <dev/extres/hwreset/hwreset.h>
   50 #include <dev/ofw/openfirm.h>
   51 #include <dev/ofw/ofw_bus.h>
   52 #include <dev/ofw/ofw_bus_subr.h>
   53 
   54 #include <dt-bindings/clock/tegra210-car.h>
   55 
   56 #include "clkdev_if.h"
   57 #include "hwreset_if.h"
   58 #include "tegra210_car.h"
   59 
   60 static struct ofw_compat_data compat_data[] = {
   61         {"nvidia,tegra210-car", 1},
   62         {NULL,                  0},
   63 };
   64 
   65 #define PLIST(x) static const char *x[]
   66 
   67 /* Pure multiplexer. */
   68 #define MUX(_id, cname, plists, o, s, w)                                \
   69 {                                                                       \
   70         .clkdef.id = _id,                                               \
   71         .clkdef.name = cname,                                           \
   72         .clkdef.parent_names = plists,                                  \
   73         .clkdef.parent_cnt = nitems(plists),                            \
   74         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
   75         .offset = o,                                                    \
   76         .shift  = s,                                                    \
   77         .width = w,                                                     \
   78 }
   79 
   80 /* Fractional divider (7.1). */
   81 #define DIV7_1(_id, cname, plist, o, s)                                 \
   82 {                                                                       \
   83         .clkdef.id = _id,                                               \
   84         .clkdef.name = cname,                                           \
   85         .clkdef.parent_names = (const char *[]){plist},                 \
   86         .clkdef.parent_cnt = 1,                                         \
   87         .clkdef.flags =  CLK_NODE_STATIC_STRINGS,                       \
   88         .offset = o,                                                    \
   89         .i_shift = (s) + 1,                                             \
   90         .i_width = 7,                                                   \
   91         .f_shift = s,                                                   \
   92         .f_width = 1,                                                   \
   93 }
   94 
   95 /* Integer divider. */
   96 #define DIV(_id, cname, plist, o, s, w, f)                              \
   97 {                                                                       \
   98         .clkdef.id = _id,                                               \
   99         .clkdef.name = cname,                                           \
  100         .clkdef.parent_names = (const char *[]){plist},                 \
  101         .clkdef.parent_cnt = 1,                                         \
  102         .clkdef.flags =  CLK_NODE_STATIC_STRINGS,                       \
  103         .offset = o,                                                    \
  104         .i_shift = s,                                                   \
  105         .i_width = w,                                                   \
  106         .div_flags = f,                                                 \
  107 }
  108 
  109 /* Gate in PLL block. */
  110 #define GATE_PLL(_id, cname, plist, o, s)                               \
  111 {                                                                       \
  112         .clkdef.id = _id,                                               \
  113         .clkdef.name = cname,                                           \
  114         .clkdef.parent_names = (const char *[]){plist},                 \
  115         .clkdef.parent_cnt = 1,                                         \
  116         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
  117         .offset = o,                                                    \
  118         .shift = s,                                                     \
  119         .mask = 3,                                                      \
  120         .on_value = 3,                                                  \
  121         .off_value = 0,                                                 \
  122 }
  123 
  124 /* Standard gate. */
  125 #define GATE(_id, cname, plist, o, s)                                   \
  126 {                                                                       \
  127         .clkdef.id = _id,                                               \
  128         .clkdef.name = cname,                                           \
  129         .clkdef.parent_names = (const char *[]){plist},                 \
  130         .clkdef.parent_cnt = 1,                                         \
  131         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
  132         .offset = o,                                                    \
  133         .shift = s,                                                     \
  134         .mask = 1,                                                      \
  135         .on_value = 1,                                                  \
  136         .off_value = 0,                                                 \
  137 }
  138 
  139 /* Inverted gate. */
  140 #define GATE_INV(_id, cname, plist, o, s)                               \
  141 {                                                                       \
  142         .clkdef.id = _id,                                               \
  143         .clkdef.name = cname,                                           \
  144         .clkdef.parent_names = (const char *[]){plist},                 \
  145         .clkdef.parent_cnt = 1,                                         \
  146         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
  147         .offset = o,                                                    \
  148         .shift = s,                                                     \
  149         .mask = 1,                                                      \
  150         .on_value = 0,                                                  \
  151         .off_value = 1,                                                 \
  152 }
  153 
  154 /* Fixed rate clock. */
  155 #define FRATE(_id, cname, _freq)                                        \
  156 {                                                                       \
  157         .clkdef.id = _id,                                               \
  158         .clkdef.name = cname,                                           \
  159         .clkdef.parent_names = NULL,                                    \
  160         .clkdef.parent_cnt = 0,                                         \
  161         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
  162         .freq = _freq,                                                  \
  163 }
  164 
  165 /* Fixed rate multipier/divider. */
  166 #define FACT(_id, cname, pname, _mult, _div)                            \
  167 {                                                                       \
  168         .clkdef.id = _id,                                               \
  169         .clkdef.name = cname,                                           \
  170         .clkdef.parent_names = (const char *[]){pname},                 \
  171         .clkdef.parent_cnt = 1,                                         \
  172         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
  173         .mult = _mult,                                                  \
  174         .div = _div,                                                    \
  175 }
  176 
  177 static uint32_t osc_freqs[16] = {
  178          [0] =  13000000,
  179          [1] =  16800000,
  180          [4] =  19200000,
  181          [5] =  38400000,
  182          [8] =  12000000,
  183          [9] =  48000000,
  184 };
  185 
  186 
  187 /* Parent lists. */
  188 PLIST(mux_xusb_hs) = {"xusb_ss_div2", "pllU_60", "pc_xusb_ss" };
  189 PLIST(mux_xusb_ssp) = {"xusb_ss", "osc_div_clk"};
  190 
  191 
  192 /* Clocks adjusted online. */
  193 static struct clk_fixed_def fixed_osc =
  194         FRATE(TEGRA210_CLK_CLK_M, "osc", 38400000);
  195 static struct clk_fixed_def fixed_clk_m =
  196         FACT(0, "clk_m", "osc", 1, 1);
  197 static struct clk_fixed_def fixed_osc_div =
  198         FACT(0, "osc_div_clk", "osc", 1, 1);
  199 
  200 static struct clk_fixed_def tegra210_fixed_clks[] = {
  201         /* Core clocks. */
  202         FRATE(0, "bogus", 1),
  203         FRATE(0, "clk_s", 32768),
  204 
  205         /* Audio clocks. */
  206         FRATE(0, "vimclk_sync", 1),
  207         FRATE(0, "i2s1_sync", 1),
  208         FRATE(0, "i2s2_sync", 1),
  209         FRATE(0, "i2s3_sync", 1),
  210         FRATE(0, "i2s4_sync", 1),
  211         FRATE(0, "i2s5_sync", 1),
  212         FRATE(0, "spdif_in_sync", 1),
  213 
  214         /* XUSB */
  215         FACT(TEGRA210_CLK_XUSB_SS_DIV2, "xusb_ss_div2", "xusb_ss", 1, 2),
  216 
  217         /* SOR */
  218         FACT(0, "sor_safe_div", "pllP_out0", 1, 17),
  219         FACT(0, "dpaux_div", "sor_safe", 1, 17),
  220         FACT(0, "dpaux1_div", "sor_safe", 1, 17),
  221 
  222         /* Not Yet Implemented */
  223         FRATE(0, "audio", 10000000),
  224         FRATE(0, "audio0", 10000000),
  225         FRATE(0, "audio1", 10000000),
  226         FRATE(0, "audio2", 10000000),
  227         FRATE(0, "audio3", 10000000),
  228         FRATE(0, "audio4", 10000000),
  229         FRATE(0, "ext_vimclk", 10000000),
  230         FRATE(0, "audiod1", 10000000),
  231         FRATE(0, "audiod2", 10000000),
  232         FRATE(0, "audiod3", 10000000),
  233         FRATE(0, "dfllCPU_out", 10000000),
  234 
  235 };
  236 
  237 
  238 static struct clk_mux_def tegra210_mux_clks[] = {
  239         /* USB. */
  240         MUX(TEGRA210_CLK_XUSB_HS_SRC, "xusb_hs", mux_xusb_hs, CLK_SOURCE_XUSB_SS, 25, 2),
  241         MUX(0, "xusb_ssp", mux_xusb_ssp, CLK_SOURCE_XUSB_SS, 24, 1),
  242 
  243 };
  244 
  245 
  246 static struct clk_gate_def tegra210_gate_clks[] = {
  247         /* Base peripheral clocks. */
  248         GATE_INV(TEGRA210_CLK_HCLK, "hclk", "hclk_div", CLK_SYSTEM_RATE, 7),
  249         GATE_INV(TEGRA210_CLK_PCLK, "pclk", "pclk_div", CLK_SYSTEM_RATE, 3),
  250         GATE(TEGRA210_CLK_CML0, "cml0", "pllE_out0", PLLE_AUX, 0),
  251         GATE(TEGRA210_CLK_CML1, "cml1", "pllE_out0", PLLE_AUX, 1),
  252         GATE(0, "pllD_dsi_csi", "pllD_out0", PLLD_MISC, 21),
  253         GATE(0, "pllP_hsio", "pllP_out0", PLLP_MISC1, 29),
  254         GATE(0, "pllP_xusb", "pllP_hsio", PLLP_MISC1, 28),
  255 };
  256 
  257 static struct clk_div_def tegra210_div_clks[] = {
  258         /* Base peripheral clocks. */
  259         DIV(0, "hclk_div", "sclk", CLK_SYSTEM_RATE, 4, 2, 0),
  260         DIV(0, "pclk_div", "hclk", CLK_SYSTEM_RATE, 0, 2, 0),
  261 };
  262 
  263 /* Initial setup table. */
  264 static struct  tegra210_init_item clk_init_table[] = {
  265         /* clock, partent, frequency, enable */
  266         {"uarta", "pllP_out0", 408000000, 0},
  267         {"uartb", "pllP_out0", 408000000, 0},
  268         {"uartc", "pllP_out0", 408000000, 0},
  269         {"uartd", "pllP_out0", 408000000, 0},
  270         {"pllA", NULL, 564480000, 1},
  271         {"pllA_out0", NULL, 11289600, 1},
  272         {"extperiph1", "pllA_out0", 0, 1},
  273         {"i2s1", "pllA_out0", 11289600, 0},
  274         {"i2s2", "pllA_out0", 11289600, 0},
  275         {"i2s3", "pllA_out0", 11289600, 0},
  276         {"i2s4", "pllA_out0", 11289600, 0},
  277         {"i2s5", "pllA_out0", 11289600, 0},
  278         {"host1x", "pllP_out0", 136000000, 1},
  279         {"sclk", "pllP_out2", 102000000, 1},
  280         {"dvfs_soc", "pllP_out0", 51000000, 1},
  281         {"dvfs_ref", "pllP_out0", 51000000, 1},
  282         {"spi4", "pllP_out0", 12000000, 1},
  283         {"pllREFE", NULL, 672000000, 0},
  284 
  285         {"xusb", NULL, 0, 1},
  286         {"xusb_ss", "pllU_480", 120000000, 0},
  287         {"pc_xusb_fs", "pllU_48", 48000000, 0},
  288         {"xusb_hs", "pc_xusb_ss", 120000000, 0},
  289         {"xusb_ssp", "xusb_ss", 120000000, 0},
  290         {"pc_xusb_falcon", "pllP_xusb", 204000000, 0},
  291         {"pc_xusb_core_host", "pllP_xusb", 102000000, 0},
  292         {"pc_xusb_core_dev", "pllP_xusb", 102000000, 0},
  293 
  294         {"sata", "pllP_out0", 104000000, 0},
  295         {"sata_oob", "pllP_out0", 204000000, 0},
  296         {"emc", NULL, 0, 1},
  297         {"mselect", NULL, 0, 1},
  298         {"csite", NULL, 0, 1},
  299 
  300         {"dbgapb", NULL, 0, 1 },
  301         {"tsensor", "clk_m", 400000, 0},
  302         {"i2c1", "pllP_out0", 0, 0},
  303         {"i2c2", "pllP_out0", 0, 0},
  304         {"i2c3", "pllP_out0", 0, 0},
  305         {"i2c4", "pllP_out0", 0, 0},
  306         {"i2c5", "pllP_out0", 0, 0},
  307         {"i2c6", "pllP_out0", 0, 0},
  308 
  309         {"pllDP_out0", NULL, 270000000, 0},
  310         {"soc_therm", "pllP_out0", 51000000, 0},
  311         {"cclk_g", NULL, 0, 1},
  312         {"pllU_out1", NULL, 48000000, 1},
  313         {"pllU_out2", NULL, 60000000, 1},
  314         {"pllC4",  NULL, 1000000000, 1},
  315         {"pllC4_out0", NULL, 1000000000, 1},
  316 };
  317 
  318 static void
  319 init_divs(struct tegra210_car_softc *sc, struct clk_div_def *clks, int nclks)
  320 {
  321         int i, rv;
  322 
  323         for (i = 0; i < nclks; i++) {
  324                 rv = clknode_div_register(sc->clkdom, clks + i);
  325                 if (rv != 0)
  326                         panic("clk_div_register failed");
  327         }
  328 }
  329 
  330 static void
  331 init_gates(struct tegra210_car_softc *sc, struct clk_gate_def *clks, int nclks)
  332 {
  333         int i, rv;
  334 
  335 
  336         for (i = 0; i < nclks; i++) {
  337                 rv = clknode_gate_register(sc->clkdom, clks + i);
  338                 if (rv != 0)
  339                         panic("clk_gate_register failed");
  340         }
  341 }
  342 
  343 static void
  344 init_muxes(struct tegra210_car_softc *sc, struct clk_mux_def *clks, int nclks)
  345 {
  346         int i, rv;
  347 
  348 
  349         for (i = 0; i < nclks; i++) {
  350                 rv = clknode_mux_register(sc->clkdom, clks + i);
  351                 if (rv != 0)
  352                         panic("clk_mux_register failed");
  353         }
  354 }
  355 
  356 static void
  357 init_fixeds(struct tegra210_car_softc *sc, struct clk_fixed_def *clks,
  358     int nclks)
  359 {
  360         int i, rv;
  361         uint32_t val;
  362         int osc_idx;
  363 
  364         CLKDEV_READ_4(sc->dev, OSC_CTRL, &val);
  365         osc_idx = OSC_CTRL_OSC_FREQ_GET(val);
  366         fixed_osc.freq = osc_freqs[osc_idx];
  367         if (fixed_osc.freq == 0)
  368                 panic("Undefined input frequency");
  369         rv = clknode_fixed_register(sc->clkdom, &fixed_osc);
  370         if (rv != 0)
  371             panic("clk_fixed_register failed");
  372 
  373         fixed_osc_div.div = 1 << OSC_CTRL_PLL_REF_DIV_GET(val);
  374         rv = clknode_fixed_register(sc->clkdom, &fixed_osc_div);
  375         if (rv != 0)
  376             panic("clk_fixed_register failed");
  377 
  378         CLKDEV_READ_4(sc->dev, SPARE_REG0, &val);
  379         fixed_clk_m.div = SPARE_REG0_MDIV_GET(val) + 1;
  380         rv = clknode_fixed_register(sc->clkdom, &fixed_clk_m);
  381         if (rv != 0)
  382             panic("clk_fixed_register failed");
  383 
  384         for (i = 0; i < nclks; i++) {
  385                 rv = clknode_fixed_register(sc->clkdom, clks + i);
  386                 if (rv != 0)
  387                         panic("clk_fixed_register failed");
  388         }
  389 }
  390 
  391 static void
  392 postinit_clock(struct tegra210_car_softc *sc)
  393 {
  394         int i;
  395         struct tegra210_init_item *tbl;
  396         struct clknode *clknode;
  397         int rv;
  398 
  399         for (i = 0; i < nitems(clk_init_table); i++) {
  400                 tbl = &clk_init_table[i];
  401 
  402                 clknode =  clknode_find_by_name(tbl->name);
  403                 if (clknode == NULL) {
  404                         device_printf(sc->dev, "Cannot find clock %s\n",
  405                             tbl->name);
  406                         continue;
  407                 }
  408                 if (tbl->parent != NULL) {
  409                         rv = clknode_set_parent_by_name(clknode, tbl->parent);
  410                         if (rv != 0) {
  411                                 device_printf(sc->dev,
  412                                     "Cannot set parent for %s (to %s): %d\n",
  413                                     tbl->name, tbl->parent, rv);
  414                                 continue;
  415                         }
  416                 }
  417                 if (tbl->frequency != 0) {
  418                         rv = clknode_set_freq(clknode, tbl->frequency, 0 , 9999);
  419                         if (rv != 0) {
  420                                 device_printf(sc->dev,
  421                                     "Cannot set frequency for %s: %d\n",
  422                                     tbl->name, rv);
  423                                 continue;
  424                         }
  425                 }
  426                 if (tbl->enable!= 0) {
  427                         rv = clknode_enable(clknode);
  428                         if (rv != 0) {
  429                                 device_printf(sc->dev,
  430                                     "Cannot enable %s: %d\n", tbl->name, rv);
  431                                 continue;
  432                         }
  433                 }
  434         }
  435 }
  436 
  437 static void
  438 register_clocks(device_t dev)
  439 {
  440         struct tegra210_car_softc *sc;
  441 
  442         sc = device_get_softc(dev);
  443         sc->clkdom = clkdom_create(dev);
  444         if (sc->clkdom == NULL)
  445                 panic("clkdom == NULL");
  446 
  447         init_fixeds(sc, tegra210_fixed_clks, nitems(tegra210_fixed_clks));
  448         tegra210_init_plls(sc);
  449         init_muxes(sc, tegra210_mux_clks, nitems(tegra210_mux_clks));
  450         init_divs(sc, tegra210_div_clks, nitems(tegra210_div_clks));
  451         init_gates(sc, tegra210_gate_clks, nitems(tegra210_gate_clks));
  452         tegra210_periph_clock(sc);
  453         tegra210_super_mux_clock(sc);
  454         clkdom_finit(sc->clkdom);
  455         clkdom_xlock(sc->clkdom);
  456         postinit_clock(sc);
  457         clkdom_unlock(sc->clkdom);
  458         if (bootverbose)
  459                 clkdom_dump(sc->clkdom);
  460 }
  461 
  462 static int
  463 tegra210_car_clkdev_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
  464 {
  465         struct tegra210_car_softc *sc;
  466 
  467         sc = device_get_softc(dev);
  468         *val = bus_read_4(sc->mem_res, addr);
  469         return (0);
  470 }
  471 
  472 static int
  473 tegra210_car_clkdev_write_4(device_t dev, bus_addr_t addr, uint32_t val)
  474 {
  475         struct tegra210_car_softc *sc;
  476 
  477         sc = device_get_softc(dev);
  478         bus_write_4(sc->mem_res, addr, val);
  479         return (0);
  480 }
  481 
  482 static int
  483 tegra210_car_clkdev_modify_4(device_t dev, bus_addr_t addr, uint32_t clear_mask,
  484     uint32_t set_mask)
  485 {
  486         struct tegra210_car_softc *sc;
  487         uint32_t reg;
  488 
  489         sc = device_get_softc(dev);
  490         reg = bus_read_4(sc->mem_res, addr);
  491         reg &= ~clear_mask;
  492         reg |= set_mask;
  493         bus_write_4(sc->mem_res, addr, reg);
  494         return (0);
  495 }
  496 
  497 static void
  498 tegra210_car_clkdev_device_lock(device_t dev)
  499 {
  500         struct tegra210_car_softc *sc;
  501 
  502         sc = device_get_softc(dev);
  503         mtx_lock(&sc->mtx);
  504 }
  505 
  506 static void
  507 tegra210_car_clkdev_device_unlock(device_t dev)
  508 {
  509         struct tegra210_car_softc *sc;
  510 
  511         sc = device_get_softc(dev);
  512         mtx_unlock(&sc->mtx);
  513 }
  514 
  515 static int
  516 tegra210_car_detach(device_t dev)
  517 {
  518 
  519         device_printf(dev, "Error: Clock driver cannot be detached\n");
  520         return (EBUSY);
  521 }
  522 
  523 static int
  524 tegra210_car_probe(device_t dev)
  525 {
  526 
  527         if (!ofw_bus_status_okay(dev))
  528                 return (ENXIO);
  529 
  530         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
  531                 device_set_desc(dev, "Tegra Clock Driver");
  532                 return (BUS_PROBE_DEFAULT);
  533         }
  534 
  535         return (ENXIO);
  536 }
  537 
  538 static int
  539 tegra210_car_attach(device_t dev)
  540 {
  541         struct tegra210_car_softc *sc = device_get_softc(dev);
  542         int rid, rv;
  543 
  544         sc->dev = dev;
  545 
  546         mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
  547         sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
  548 
  549         /* Resource setup. */
  550         rid = 0;
  551         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  552             RF_ACTIVE);
  553         if (!sc->mem_res) {
  554                 device_printf(dev, "cannot allocate memory resource\n");
  555                 rv = ENXIO;
  556                 goto fail;
  557         }
  558 
  559         register_clocks(dev);
  560         hwreset_register_ofw_provider(dev);
  561         return (0);
  562 
  563 fail:
  564         if (sc->mem_res)
  565                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
  566 
  567         return (rv);
  568 }
  569 
  570 static int
  571 tegra210_car_hwreset_assert(device_t dev, intptr_t id, bool value)
  572 {
  573         struct tegra210_car_softc *sc = device_get_softc(dev);
  574 
  575         return (tegra210_hwreset_by_idx(sc, id, value));
  576 }
  577 
  578 static device_method_t tegra210_car_methods[] = {
  579         /* Device interface */
  580         DEVMETHOD(device_probe,         tegra210_car_probe),
  581         DEVMETHOD(device_attach,        tegra210_car_attach),
  582         DEVMETHOD(device_detach,        tegra210_car_detach),
  583 
  584         /* Clkdev interface*/
  585         DEVMETHOD(clkdev_read_4,        tegra210_car_clkdev_read_4),
  586         DEVMETHOD(clkdev_write_4,       tegra210_car_clkdev_write_4),
  587         DEVMETHOD(clkdev_modify_4,      tegra210_car_clkdev_modify_4),
  588         DEVMETHOD(clkdev_device_lock,   tegra210_car_clkdev_device_lock),
  589         DEVMETHOD(clkdev_device_unlock, tegra210_car_clkdev_device_unlock),
  590 
  591         /* Reset interface */
  592         DEVMETHOD(hwreset_assert,       tegra210_car_hwreset_assert),
  593 
  594         DEVMETHOD_END
  595 };
  596 
  597 static DEFINE_CLASS_0(car, tegra210_car_driver, tegra210_car_methods,
  598     sizeof(struct tegra210_car_softc));
  599 EARLY_DRIVER_MODULE(tegra210_car, simplebus, tegra210_car_driver, NULL, NULL,
  600     BUS_PASS_TIMER);

Cache object: fdc6baad2ee75322ca58dd51ee2283d3


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