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/allwinner/clkng/aw_ccung.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) 2017,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 /*
   31  * Allwinner Clock Control Unit
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/bus.h>
   40 #include <sys/rman.h>
   41 #include <sys/kernel.h>
   42 #include <sys/lock.h>
   43 #include <sys/module.h>
   44 #include <sys/mutex.h>
   45 #include <machine/bus.h>
   46 
   47 #include <dev/fdt/simplebus.h>
   48 
   49 #include <dev/ofw/ofw_bus.h>
   50 #include <dev/ofw/ofw_bus_subr.h>
   51 
   52 #include <dev/extres/clk/clk.h>
   53 #include <dev/extres/clk/clk_gate.h>
   54 
   55 #include <dev/extres/hwreset/hwreset.h>
   56 
   57 #include <arm/allwinner/clkng/aw_ccung.h>
   58 #include <arm/allwinner/clkng/aw_clk.h>
   59 
   60 #ifdef __aarch64__
   61 #include "opt_soc.h"
   62 #endif
   63 
   64 #include "clkdev_if.h"
   65 #include "hwreset_if.h"
   66 
   67 #if 0
   68 #define dprintf(format, arg...) device_printf(dev, "%s: " format, __func__, arg)
   69 #else
   70 #define dprintf(format, arg...)
   71 #endif
   72 
   73 static struct resource_spec aw_ccung_spec[] = {
   74         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
   75         { -1, 0 }
   76 };
   77 
   78 #define CCU_READ4(sc, reg)              bus_read_4((sc)->res, (reg))
   79 #define CCU_WRITE4(sc, reg, val)        bus_write_4((sc)->res, (reg), (val))
   80 
   81 static int
   82 aw_ccung_write_4(device_t dev, bus_addr_t addr, uint32_t val)
   83 {
   84         struct aw_ccung_softc *sc;
   85 
   86         sc = device_get_softc(dev);
   87         dprintf("offset=%lx write %x\n", addr, val);
   88         CCU_WRITE4(sc, addr, val);
   89         return (0);
   90 }
   91 
   92 static int
   93 aw_ccung_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
   94 {
   95         struct aw_ccung_softc *sc;
   96 
   97         sc = device_get_softc(dev);
   98 
   99         *val = CCU_READ4(sc, addr);
  100         dprintf("offset=%lx Read %x\n", addr, *val);
  101         return (0);
  102 }
  103 
  104 static int
  105 aw_ccung_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
  106 {
  107         struct aw_ccung_softc *sc;
  108         uint32_t reg;
  109 
  110         sc = device_get_softc(dev);
  111 
  112         dprintf("offset=%lx clr: %x set: %x\n", addr, clr, set);
  113         reg = CCU_READ4(sc, addr);
  114         reg &= ~clr;
  115         reg |= set;
  116         CCU_WRITE4(sc, addr, reg);
  117 
  118         return (0);
  119 }
  120 
  121 static int
  122 aw_ccung_reset_assert(device_t dev, intptr_t id, bool reset)
  123 {
  124         struct aw_ccung_softc *sc;
  125         uint32_t val;
  126 
  127         sc = device_get_softc(dev);
  128 
  129         dprintf("%sassert reset id %ld\n", reset ? "" : "De", id);
  130         if (id >= sc->nresets || sc->resets[id].offset == 0)
  131                 return (0);
  132 
  133         mtx_lock(&sc->mtx);
  134         val = CCU_READ4(sc, sc->resets[id].offset);
  135         dprintf("offset=%x Read %x\n", sc->resets[id].offset, val);
  136         if (reset)
  137                 val &= ~(1 << sc->resets[id].shift);
  138         else
  139                 val |= 1 << sc->resets[id].shift;
  140         dprintf("offset=%x Write %x\n", sc->resets[id].offset, val);
  141         CCU_WRITE4(sc, sc->resets[id].offset, val);
  142         mtx_unlock(&sc->mtx);
  143 
  144         return (0);
  145 }
  146 
  147 static int
  148 aw_ccung_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
  149 {
  150         struct aw_ccung_softc *sc;
  151         uint32_t val;
  152 
  153         sc = device_get_softc(dev);
  154 
  155         if (id >= sc->nresets || sc->resets[id].offset == 0)
  156                 return (0);
  157 
  158         mtx_lock(&sc->mtx);
  159         val = CCU_READ4(sc, sc->resets[id].offset);
  160         dprintf("offset=%x Read %x\n", sc->resets[id].offset, val);
  161         *reset = (val & (1 << sc->resets[id].shift)) != 0 ? false : true;
  162         mtx_unlock(&sc->mtx);
  163 
  164         return (0);
  165 }
  166 
  167 static void
  168 aw_ccung_device_lock(device_t dev)
  169 {
  170         struct aw_ccung_softc *sc;
  171 
  172         sc = device_get_softc(dev);
  173         mtx_lock(&sc->mtx);
  174 }
  175 
  176 static void
  177 aw_ccung_device_unlock(device_t dev)
  178 {
  179         struct aw_ccung_softc *sc;
  180 
  181         sc = device_get_softc(dev);
  182         mtx_unlock(&sc->mtx);
  183 }
  184 
  185 static int
  186 aw_ccung_register_gates(struct aw_ccung_softc *sc)
  187 {
  188         struct clk_gate_def def;
  189         int i;
  190 
  191         for (i = 0; i < sc->ngates; i++) {
  192                 if (sc->gates[i].name == NULL)
  193                         continue;
  194                 memset(&def, 0, sizeof(def));
  195                 def.clkdef.id = i;
  196                 def.clkdef.name = sc->gates[i].name;
  197                 def.clkdef.parent_names = &sc->gates[i].parent_name;
  198                 def.clkdef.parent_cnt = 1;
  199                 def.offset = sc->gates[i].offset;
  200                 def.shift = sc->gates[i].shift;
  201                 def.mask = 1;
  202                 def.on_value = 1;
  203                 def.off_value = 0;
  204                 clknode_gate_register(sc->clkdom, &def);
  205         }
  206 
  207         return (0);
  208 }
  209 
  210 static void
  211 aw_ccung_init_clocks(struct aw_ccung_softc *sc)
  212 {
  213         struct clknode *clknode;
  214         int i, error;
  215 
  216         for (i = 0; i < sc->n_clk_init; i++) {
  217                 clknode = clknode_find_by_name(sc->clk_init[i].name);
  218                 if (clknode == NULL) {
  219                         device_printf(sc->dev, "Cannot find clock %s\n",
  220                             sc->clk_init[i].name);
  221                         continue;
  222                 }
  223 
  224                 if (sc->clk_init[i].parent_name != NULL) {
  225                         if (bootverbose)
  226                                 device_printf(sc->dev, "Setting %s as parent for %s\n",
  227                                     sc->clk_init[i].parent_name,
  228                                     sc->clk_init[i].name);
  229                         error = clknode_set_parent_by_name(clknode,
  230                             sc->clk_init[i].parent_name);
  231                         if (error != 0) {
  232                                 device_printf(sc->dev,
  233                                     "Cannot set parent to %s for %s\n",
  234                                     sc->clk_init[i].parent_name,
  235                                     sc->clk_init[i].name);
  236                                 continue;
  237                         }
  238                 }
  239                 if (sc->clk_init[i].default_freq != 0) {
  240                         if (bootverbose)
  241                                 device_printf(sc->dev,
  242                                     "Setting freq %ju for %s\n",
  243                                     sc->clk_init[i].default_freq,
  244                                     sc->clk_init[i].name);
  245                         error = clknode_set_freq(clknode,
  246                             sc->clk_init[i].default_freq, 0 , 0);
  247                         if (error != 0) {
  248                                 device_printf(sc->dev,
  249                                     "Cannot set frequency for %s to %ju\n",
  250                                     sc->clk_init[i].name,
  251                                     sc->clk_init[i].default_freq);
  252                                 continue;
  253                         }
  254                 }
  255                 if (sc->clk_init[i].enable) {
  256                         error = clknode_enable(clknode);
  257                         if (error != 0) {
  258                                 device_printf(sc->dev,
  259                                     "Cannot enable %s\n",
  260                                     sc->clk_init[i].name);
  261                                 continue;
  262                         }
  263                 }
  264         }
  265 }
  266 
  267 int
  268 aw_ccung_attach(device_t dev)
  269 {
  270         struct aw_ccung_softc *sc;
  271         int i;
  272 
  273         sc = device_get_softc(dev);
  274         sc->dev = dev;
  275 
  276         if (bus_alloc_resources(dev, aw_ccung_spec, &sc->res) != 0) {
  277                 device_printf(dev, "cannot allocate resources for device\n");
  278                 return (ENXIO);
  279         }
  280 
  281         mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
  282 
  283         sc->clkdom = clkdom_create(dev);
  284         if (sc->clkdom == NULL)
  285                 panic("Cannot create clkdom\n");
  286 
  287         for (i = 0; i < sc->nclks; i++) {
  288                 switch (sc->clks[i].type) {
  289                 case AW_CLK_UNDEFINED:
  290                         break;
  291                 case AW_CLK_MUX:
  292                         clknode_mux_register(sc->clkdom, sc->clks[i].clk.mux);
  293                         break;
  294                 case AW_CLK_DIV:
  295                         clknode_div_register(sc->clkdom, sc->clks[i].clk.div);
  296                         break;
  297                 case AW_CLK_FIXED:
  298                         clknode_fixed_register(sc->clkdom,
  299                             sc->clks[i].clk.fixed);
  300                         break;
  301                 case AW_CLK_NKMP:
  302                         aw_clk_nkmp_register(sc->clkdom, sc->clks[i].clk.nkmp);
  303                         break;
  304                 case AW_CLK_NM:
  305                         aw_clk_nm_register(sc->clkdom, sc->clks[i].clk.nm);
  306                         break;
  307                 case AW_CLK_M:
  308                         aw_clk_m_register(sc->clkdom, sc->clks[i].clk.m);
  309                         break;
  310                 case AW_CLK_PREDIV_MUX:
  311                         aw_clk_prediv_mux_register(sc->clkdom,
  312                             sc->clks[i].clk.prediv_mux);
  313                         break;
  314                 case AW_CLK_FRAC:
  315                         aw_clk_frac_register(sc->clkdom, sc->clks[i].clk.frac);
  316                         break;
  317                 case AW_CLK_MIPI:
  318                         aw_clk_mipi_register(sc->clkdom, sc->clks[i].clk.mipi);
  319                         break;
  320                 case AW_CLK_NP:
  321                         aw_clk_np_register(sc->clkdom, sc->clks[i].clk.np);
  322                         break;
  323                 case AW_CLK_NMM:
  324                         aw_clk_nmm_register(sc->clkdom, sc->clks[i].clk.nmm);
  325                         break;
  326                 }
  327         }
  328 
  329         if (sc->gates)
  330                 aw_ccung_register_gates(sc);
  331         if (clkdom_finit(sc->clkdom) != 0)
  332                 panic("cannot finalize clkdom initialization\n");
  333 
  334         clkdom_xlock(sc->clkdom);
  335         aw_ccung_init_clocks(sc);
  336         clkdom_unlock(sc->clkdom);
  337 
  338         if (bootverbose)
  339                 clkdom_dump(sc->clkdom);
  340 
  341         /* If we have resets, register our self as a reset provider */
  342         if (sc->resets)
  343                 hwreset_register_ofw_provider(dev);
  344 
  345         return (0);
  346 }
  347 
  348 static device_method_t aw_ccung_methods[] = {
  349         /* clkdev interface */
  350         DEVMETHOD(clkdev_write_4,       aw_ccung_write_4),
  351         DEVMETHOD(clkdev_read_4,        aw_ccung_read_4),
  352         DEVMETHOD(clkdev_modify_4,      aw_ccung_modify_4),
  353         DEVMETHOD(clkdev_device_lock,   aw_ccung_device_lock),
  354         DEVMETHOD(clkdev_device_unlock, aw_ccung_device_unlock),
  355 
  356         /* Reset interface */
  357         DEVMETHOD(hwreset_assert,       aw_ccung_reset_assert),
  358         DEVMETHOD(hwreset_is_asserted,  aw_ccung_reset_is_asserted),
  359 
  360         DEVMETHOD_END
  361 };
  362 
  363 DEFINE_CLASS_0(aw_ccung, aw_ccung_driver, aw_ccung_methods,
  364     sizeof(struct aw_ccung_softc));

Cache object: 3eefda4512bb657fa4bef1afcd8e1294


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