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_mux.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 2016 Michal Meloun <mmel@FreeBSD.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/conf.h>
   34 #include <sys/bus.h>
   35 #include <sys/kernel.h>
   36 #include <sys/systm.h>
   37 
   38 #include <machine/bus.h>
   39 
   40 #include <dev/extres/clk/clk.h>
   41 #include <dev/extres/syscon/syscon.h>
   42 
   43 #include <arm64/rockchip/clk/rk_cru.h>
   44 #include <arm64/rockchip/clk/rk_clk_mux.h>
   45 
   46 #include "clkdev_if.h"
   47 #include "syscon_if.h"
   48 
   49 #define WR4(_clk, off, val)                                             \
   50         CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
   51 #define RD4(_clk, off, val)                                             \
   52         CLKDEV_READ_4(clknode_get_device(_clk), off, val)
   53 #define MD4(_clk, off, clr, set )                                       \
   54         CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
   55 #define DEVICE_LOCK(_clk)                                               \
   56         CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
   57 #define DEVICE_UNLOCK(_clk)                                             \
   58         CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
   59 
   60 #if 0
   61 #define dprintf(format, arg...)                                         \
   62         printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg)
   63 #else
   64 #define dprintf(format, arg...)
   65 #endif
   66 
   67 static int rk_clk_mux_init(struct clknode *clk, device_t dev);
   68 static int rk_clk_mux_set_mux(struct clknode *clk, int idx);
   69 static int rk_clk_mux_set_freq(struct clknode *clk, uint64_t fparent,
   70     uint64_t *fout, int flags, int *stop);
   71 
   72 struct rk_clk_mux_sc {
   73         uint32_t        offset;
   74         uint32_t        shift;
   75         uint32_t        mask;
   76         int             mux_flags;
   77         struct syscon   *grf;
   78 };
   79 
   80 static clknode_method_t rk_clk_mux_methods[] = {
   81         /* Device interface */
   82         CLKNODEMETHOD(clknode_init,     rk_clk_mux_init),
   83         CLKNODEMETHOD(clknode_set_mux,  rk_clk_mux_set_mux),
   84         CLKNODEMETHOD(clknode_set_freq, rk_clk_mux_set_freq),
   85         CLKNODEMETHOD_END
   86 };
   87 DEFINE_CLASS_1(rk_clk_mux, rk_clk_mux_class, rk_clk_mux_methods,
   88    sizeof(struct rk_clk_mux_sc), clknode_class);
   89 
   90 static struct syscon *
   91 rk_clk_mux_get_grf(struct clknode *clk)
   92 {
   93         device_t dev;
   94         phandle_t node;
   95         struct syscon *grf;
   96 
   97         grf = NULL;
   98         dev = clknode_get_device(clk);
   99         node = ofw_bus_get_node(dev);
  100         if (OF_hasprop(node, "rockchip,grf") &&
  101             syscon_get_by_ofw_property(dev, node,
  102             "rockchip,grf", &grf) != 0) {
  103                 return (NULL);
  104         }
  105 
  106         return (grf);
  107 }
  108 
  109 static int
  110 rk_clk_mux_init(struct clknode *clk, device_t dev)
  111 {
  112         uint32_t reg;
  113         struct rk_clk_mux_sc *sc;
  114         int rv;
  115 
  116         sc = clknode_get_softc(clk);
  117 
  118         if ((sc->mux_flags & RK_CLK_MUX_GRF) != 0) {
  119                 sc->grf = rk_clk_mux_get_grf(clk);
  120                 if (sc->grf == NULL)
  121                         panic("clock %s has GRF flag set but no syscon is available",
  122                             clknode_get_name(clk));
  123         }
  124 
  125         DEVICE_LOCK(clk);
  126         if (sc->grf) {
  127                 reg = SYSCON_READ_4(sc->grf, sc->offset);
  128                 rv = 0;
  129         } else
  130                 rv = RD4(clk, sc->offset, &reg);
  131         DEVICE_UNLOCK(clk);
  132         if (rv != 0) {
  133                 return (rv);
  134         }
  135         reg = (reg >> sc->shift) & sc->mask;
  136         clknode_init_parent_idx(clk, reg);
  137         return(0);
  138 }
  139 
  140 static int
  141 rk_clk_mux_set_mux(struct clknode *clk, int idx)
  142 {
  143         uint32_t reg;
  144         struct rk_clk_mux_sc *sc;
  145         int rv;
  146 
  147         sc = clknode_get_softc(clk);
  148 
  149         DEVICE_LOCK(clk);
  150         if (sc->grf)
  151                 rv = SYSCON_MODIFY_4(sc->grf, sc->offset, sc->mask << sc->shift,
  152                   ((idx & sc->mask) << sc->shift) | RK_CLK_MUX_MASK);
  153         else
  154                 rv = MD4(clk, sc->offset, sc->mask << sc->shift,
  155                   ((idx & sc->mask) << sc->shift) | RK_CLK_MUX_MASK);
  156         if (rv != 0) {
  157                 DEVICE_UNLOCK(clk);
  158                 return (rv);
  159         }
  160         if (sc->grf == NULL)
  161                 RD4(clk, sc->offset, &reg);
  162         DEVICE_UNLOCK(clk);
  163 
  164         return(0);
  165 }
  166 
  167 static int
  168 rk_clk_mux_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
  169     int flags, int *stop)
  170 {
  171         struct rk_clk_mux_sc *sc;
  172         struct clknode *p_clk, *p_best_clk;
  173         const char **p_names;
  174         int p_idx, best_parent;
  175         int rv;
  176 
  177         sc = clknode_get_softc(clk);
  178 
  179         if ((sc->mux_flags & RK_CLK_MUX_GRF) != 0) {
  180                 *stop = 1;
  181                 return (ENOTSUP);
  182         }
  183         if ((sc->mux_flags & RK_CLK_MUX_REPARENT) == 0) {
  184                 *stop = 0;
  185                 return (0);
  186         }
  187 
  188         dprintf("Finding best parent for target freq of %ju\n", *fout);
  189         p_names = clknode_get_parent_names(clk);
  190         for (p_idx = 0; p_idx != clknode_get_parents_num(clk); p_idx++) {
  191                 p_clk = clknode_find_by_name(p_names[p_idx]);
  192                 dprintf("Testing with parent %s (%d)\n",
  193                     clknode_get_name(p_clk), p_idx);
  194 
  195                 rv = clknode_set_freq(p_clk, *fout, flags | CLK_SET_DRYRUN, 0);
  196                 dprintf("Testing with parent %s (%d) rv=%d\n",
  197                     clknode_get_name(p_clk), p_idx, rv);
  198                 if (rv == 0) {
  199                         best_parent = p_idx;
  200                         p_best_clk = p_clk;
  201                         *stop = 1;
  202                 }
  203         }
  204 
  205         if (!*stop)
  206                 return (0);
  207 
  208         if ((flags & CLK_SET_DRYRUN) != 0)
  209                 return (0);
  210 
  211         p_idx = clknode_get_parent_idx(clk);
  212         if (p_idx != best_parent) {
  213                 dprintf("Switching parent index from %d to %d\n", p_idx,
  214                     best_parent);
  215                 clknode_set_parent_by_idx(clk, best_parent);
  216         }
  217 
  218         clknode_set_freq(p_best_clk, *fout, flags, 0);
  219         clknode_get_freq(p_best_clk, fout);
  220 
  221         return (0);
  222 }
  223 
  224 int
  225 rk_clk_mux_register(struct clkdom *clkdom, struct rk_clk_mux_def *clkdef)
  226 {
  227         struct clknode *clk;
  228         struct rk_clk_mux_sc *sc;
  229 
  230         clk = clknode_create(clkdom, &rk_clk_mux_class, &clkdef->clkdef);
  231         if (clk == NULL)
  232                 return (1);
  233 
  234         sc = clknode_get_softc(clk);
  235         sc->offset = clkdef->offset;
  236         sc->shift = clkdef->shift;
  237         sc->mask =  (1 << clkdef->width) - 1;
  238         sc->mux_flags = clkdef->mux_flags;
  239 
  240         clknode_register(clkdom, clk);
  241         return (0);
  242 }

Cache object: 06c26c7d0f9b8d8baebe4df3753fdb16


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