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/qoriq/clk/ls1028a_flexspi_clk.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) 2021 Alstom Group.
    5  * Copyright (c) 2021 Semihalf.
    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 #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/ofw/openfirm.h>
   47 #include <dev/ofw/ofw_bus.h>
   48 #include <dev/ofw/ofw_bus_subr.h>
   49 
   50 #include "clkdev_if.h"
   51 #include "syscon_if.h"
   52 
   53 
   54 struct ls1028a_flexspi_clk_softc {
   55         device_t                dev;
   56         struct clkdom           *clkdom;
   57         uint64_t                reg_offset;
   58         struct syscon           *syscon;
   59         struct clk_div_def      clk_def;
   60         struct mtx              mtx;
   61 };
   62 
   63 static struct clk_div_table ls1028a_flexspi_div_tbl[] = {
   64         { .value = 0, .divider = 1, },
   65         { .value = 1, .divider = 2, },
   66         { .value = 2, .divider = 3, },
   67         { .value = 3, .divider = 4, },
   68         { .value = 4, .divider = 5, },
   69         { .value = 5, .divider = 6, },
   70         { .value = 6, .divider = 7, },
   71         { .value = 7, .divider = 8, },
   72         { .value = 11, .divider = 12, },
   73         { .value = 15, .divider = 16, },
   74         { .value = 16, .divider = 20, },
   75         { .value = 17, .divider = 24, },
   76         { .value = 18, .divider = 28, },
   77         { .value = 19, .divider = 32, },
   78         { .value = 20, .divider = 80, },
   79         {}
   80 };
   81 static struct clk_div_table lx2160a_flexspi_div_tbl[] = {
   82         { .value = 1, .divider = 2, },
   83         { .value = 3, .divider = 4, },
   84         { .value = 5, .divider = 6, },
   85         { .value = 7, .divider = 8, },
   86         { .value = 11, .divider = 12, },
   87         { .value = 15, .divider = 16, },
   88         { .value = 16, .divider = 20, },
   89         { .value = 17, .divider = 24, },
   90         { .value = 18, .divider = 28, },
   91         { .value = 19, .divider = 32, },
   92         { .value = 20, .divider = 80, },
   93         {}
   94 };
   95 
   96 static struct ofw_compat_data compat_data[] = {
   97         { "fsl,ls1028a-flexspi-clk",    (uintptr_t)ls1028a_flexspi_div_tbl },
   98         { "fsl,lx2160a-flexspi-clk",    (uintptr_t)lx2160a_flexspi_div_tbl },
   99         { NULL, 0 }
  100 };
  101 
  102 static int
  103 ls1028a_flexspi_clk_probe(device_t dev)
  104 {
  105 
  106         if (!ofw_bus_status_okay(dev))
  107                 return (ENXIO);
  108 
  109         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
  110                 device_set_desc(dev, "NXP FlexSPI clock driver");
  111                 return (BUS_PROBE_DEFAULT);
  112         }
  113 
  114         return (ENXIO);
  115 }
  116 
  117 static int
  118 ls1028a_flexspi_clk_attach(device_t dev)
  119 {
  120         struct ls1028a_flexspi_clk_softc *sc;
  121         const char *oclkname = NULL;
  122         const char *pclkname[1];
  123         uint32_t acells;
  124         uint32_t scells;
  125         pcell_t cells[4];
  126         phandle_t node;
  127         uint64_t reg_size;
  128         int ret;
  129         clk_t clk;
  130 
  131         sc = device_get_softc(dev);
  132         sc->dev = dev;
  133         node = ofw_bus_get_node(dev);
  134 
  135         /* Parse address-cells and size-cells from the parent node as a fallback */
  136         if (OF_getencprop(node, "#address-cells", &acells,
  137             sizeof(acells)) == -1) {
  138                 if (OF_getencprop(OF_parent(node), "#address-cells", &acells,
  139                     sizeof(acells)) == -1) {
  140                         acells = 2;
  141                 }
  142         }
  143         if (OF_getencprop(node, "#size-cells", &scells,
  144             sizeof(scells)) == -1) {
  145                 if (OF_getencprop(OF_parent(node), "#size-cells", &scells,
  146                     sizeof(scells)) == -1) {
  147                         scells = 1;
  148                 }
  149         }
  150         ret = OF_getencprop(node, "reg", cells, (acells + scells) * sizeof(pcell_t));
  151         if (ret < 0) {
  152                 device_printf(dev, "ERROR: failed to read REG property\n");
  153                 return (ENOMEM);
  154         }
  155         sc->reg_offset = (uint64_t)cells[0];
  156         if (acells == 2)
  157                 sc->reg_offset = (sc->reg_offset << 32) | (uint64_t)cells[1];
  158         reg_size = (uint64_t)cells[acells];
  159         if (scells == 2)
  160                 reg_size = (reg_size << 32) | (uint64_t)cells[acells + 1];
  161 
  162         if (reg_size != 4) {
  163                 device_printf(dev, "ERROR, expected only single register\n");
  164                 return (EINVAL);
  165         }
  166         if (sc->reg_offset >> 32UL) {
  167                 device_printf(dev, "ERROR, only 32-bit address offset is supported\n");
  168                 return (EINVAL);
  169         }
  170 
  171         /* Get syscon handle */
  172         ret = SYSCON_GET_HANDLE(dev, &sc->syscon);
  173         if ((ret != 0) || (sc->syscon == NULL)) {
  174                 device_printf(dev, "ERROR: failed to get syscon\n");
  175                 return (EFAULT);
  176         }
  177 
  178         /* Initialize access mutex */
  179         mtx_init(&sc->mtx, "FSL clock mtx", NULL, MTX_DEF);
  180 
  181         /* Get clock names */
  182         ret = clk_get_by_ofw_index(dev, node, 0, &clk);
  183         if (ret) {
  184                 device_printf(dev, "ERROR: failed to get parent clock\n");
  185                 return (EINVAL);
  186         }
  187         pclkname[0] = clk_get_name(clk);
  188         ret = clk_parse_ofw_clk_name(dev, node, &oclkname);
  189         if (ret) {
  190                 device_printf(dev, "ERROR: failed to get output clock name\n");
  191                 return (EINVAL);
  192         }
  193 
  194 #ifdef DEBUG
  195         device_printf(dev, "INFO: pclkname %s, oclkname %s\n", pclkname[0], oclkname);
  196 #endif
  197 
  198         /* Fixup CLK structure */
  199         sc->clk_def.clkdef.name = oclkname;
  200         sc->clk_def.clkdef.parent_names = (const char **)pclkname;
  201         sc->clk_def.offset = (uint32_t)sc->reg_offset;
  202         sc->clk_def.clkdef.id = 1;
  203         sc->clk_def.clkdef.parent_cnt = 1;
  204         sc->clk_def.clkdef.flags =  0;
  205         sc->clk_def.div_flags = CLK_DIV_WITH_TABLE;
  206         sc->clk_def.i_shift = 0;
  207         sc->clk_def.i_width = 5;
  208         sc->clk_def.div_table = (struct clk_div_table*)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
  209 
  210         /* Create clock */
  211         sc->clkdom = clkdom_create(dev);
  212         if (sc->clkdom == NULL)
  213                 panic("clkdom == NULL");
  214         ret = clknode_div_register(sc->clkdom, &sc->clk_def);
  215         if (ret) {
  216                 device_printf(dev, "ERROR: unable to register clock\n");
  217                 return (EINVAL);
  218         }
  219         clkdom_finit(sc->clkdom);
  220 
  221         if (bootverbose)
  222                 clkdom_dump(sc->clkdom);
  223 
  224         return (0);
  225 }
  226 
  227 static int
  228 ls1028a_flexspi_clk_detach(device_t dev)
  229 {
  230 
  231         /* Clock detaching is not supported */
  232         return (EACCES);
  233 }
  234 
  235 static int
  236 ls1028a_flexspi_clk_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
  237 {
  238         struct ls1028a_flexspi_clk_softc *sc;
  239         sc = device_get_softc(dev);
  240 
  241         *val = SYSCON_READ_4(sc->syscon, addr);
  242 
  243         return (0);
  244 }
  245 
  246 static int
  247 ls1028a_flexspi_clk_write_4(device_t dev, bus_addr_t addr, uint32_t val)
  248 {
  249         struct ls1028a_flexspi_clk_softc *sc;
  250         int ret;
  251 
  252         sc = device_get_softc(dev);
  253 
  254         ret = SYSCON_WRITE_4(sc->syscon, addr, val);
  255 
  256         return (ret);
  257 }
  258 
  259 static int
  260 ls1028a_flexspi_clk_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
  261 {
  262         struct ls1028a_flexspi_clk_softc *sc;
  263         int ret;
  264 
  265         sc = device_get_softc(dev);
  266 
  267         ret = SYSCON_MODIFY_4(sc->syscon, addr, clr, set);
  268 
  269         return (ret);
  270 }
  271 
  272 static void
  273 ls1028a_flexspi_clk_device_lock(device_t dev)
  274 {
  275         struct ls1028a_flexspi_clk_softc *sc;
  276         sc = device_get_softc(dev);
  277 
  278         mtx_lock(&sc->mtx);
  279 }
  280 
  281 static void
  282 ls1028a_flexspi_clk_device_unlock(device_t dev)
  283 {
  284         struct ls1028a_flexspi_clk_softc *sc;
  285 
  286         sc = device_get_softc(dev);
  287 
  288         mtx_unlock(&sc->mtx);
  289 }
  290 
  291 static device_method_t ls1028a_flexspi_clk_methods[] = {
  292         /* Device interface */
  293         DEVMETHOD(device_probe,         ls1028a_flexspi_clk_probe),
  294         DEVMETHOD(device_attach,        ls1028a_flexspi_clk_attach),
  295         DEVMETHOD(device_detach,        ls1028a_flexspi_clk_detach),
  296 
  297         DEVMETHOD(clkdev_read_4,        ls1028a_flexspi_clk_read_4),
  298         DEVMETHOD(clkdev_write_4,       ls1028a_flexspi_clk_write_4),
  299         DEVMETHOD(clkdev_modify_4,      ls1028a_flexspi_clk_modify_4),
  300         DEVMETHOD(clkdev_device_lock,   ls1028a_flexspi_clk_device_lock),
  301         DEVMETHOD(clkdev_device_unlock, ls1028a_flexspi_clk_device_unlock),
  302 
  303         DEVMETHOD_END
  304 };
  305 
  306 static DEFINE_CLASS_0(fspi_clk, ls1028a_flexspi_clk_driver, ls1028a_flexspi_clk_methods,
  307     sizeof(struct ls1028a_flexspi_clk_softc));
  308 EARLY_DRIVER_MODULE(ls1028a_flexspi_clk, simple_mfd, ls1028a_flexspi_clk_driver,
  309     NULL, NULL, BUS_PASS_TIMER);

Cache object: 300c7bc919819c0618225e9ce03c0f8f


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