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/rk_iodomain.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) 2019 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 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 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/bus.h>
   35 #include <sys/kernel.h>
   36 #include <sys/module.h>
   37 
   38 #include <dev/ofw/ofw_bus.h>
   39 #include <dev/ofw/ofw_bus_subr.h>
   40 
   41 #include <dev/extres/syscon/syscon.h>
   42 #include <dev/extres/regulator/regulator.h>
   43 
   44 #include "syscon_if.h"
   45 
   46 #define RK3288_GRF_IO_VSEL              0x380
   47 #define RK3399_GRF_IO_VSEL              0xe640
   48 #define RK3399_PMUGRF_SOC_CON0          0x180
   49 #define RK3568_PMUGRF_IO_VSEL0          0x0140
   50 #define RK3568_PMUGRF_IO_VSEL1          0x0144
   51 #define RK3568_PMUGRF_IO_VSEL2          0x0148
   52 
   53 #define MAX_1V8                         1850000
   54 
   55 enum rk_iodomain_type {
   56         RK3328 = 1,
   57         RK3399,
   58         RK3568,
   59 };
   60 
   61 struct rk_iodomain_supply {
   62         char            *name;
   63         uint32_t        bit;
   64 };
   65 
   66 struct rk_iodomain_softc;
   67 
   68 struct rk_iodomain_conf {
   69         struct rk_iodomain_supply       *supply;
   70         int                             nsupply;
   71         uint32_t                        grf_reg;
   72         void                            (*init)(struct rk_iodomain_softc *sc);
   73         enum rk_iodomain_type           type;
   74 };
   75 
   76 struct rk_iodomain_softc {
   77         device_t                        dev;
   78         struct syscon                   *grf;
   79         phandle_t                       node;
   80         struct rk_iodomain_conf         *conf;
   81 };
   82 
   83 static struct rk_iodomain_supply rk3288_supply[] = {
   84         {"lcdc-supply", 0},
   85         {"dvp-supply", 1},
   86         {"flash0-supply", 2},
   87         {"flash1-supply", 3},
   88         {"wifi-supply", 4},
   89         {"bb-supply", 5},
   90         {"audio-supply", 6},
   91         {"sdcard-supply", 7},
   92         {"gpio30-supply", 8},
   93         {"gpio1830-supply", 9},
   94 };
   95 
   96 static struct rk_iodomain_conf rk3288_conf = {
   97         .supply = rk3288_supply,
   98         .nsupply = nitems(rk3288_supply),
   99         .grf_reg = RK3288_GRF_IO_VSEL,
  100         .type = RK3328,
  101 };
  102 
  103 static struct rk_iodomain_supply rk3399_supply[] = {
  104         {"bt656-supply", 0},
  105         {"audio-supply", 1},
  106         {"sdmmc-supply", 2},
  107         {"gpio1830-supply", 3},
  108 };
  109 
  110 static struct rk_iodomain_conf rk3399_conf = {
  111         .supply = rk3399_supply,
  112         .nsupply = nitems(rk3399_supply),
  113         .grf_reg = RK3399_GRF_IO_VSEL,
  114         .type = RK3399,
  115 };
  116 
  117 static struct rk_iodomain_supply rk3399_pmu_supply[] = {
  118         {"pmu1830-supply", 9},
  119 };
  120 
  121 static void rk3399_pmu_init(struct rk_iodomain_softc *sc);
  122 static struct rk_iodomain_conf rk3399_pmu_conf = {
  123         .supply = rk3399_pmu_supply,
  124         .nsupply = nitems(rk3399_pmu_supply),
  125         .grf_reg = RK3399_PMUGRF_SOC_CON0,
  126         .init = rk3399_pmu_init,
  127         .type = RK3399,
  128 };
  129 
  130 static struct rk_iodomain_supply rk3568_pmu_supply[] = {
  131         {"pmuio1-supply", 0},
  132         {"pmuio2-supply", 1},
  133         {"vccio1-supply", 1},
  134         {"vccio2-supply", 2},
  135         {"vccio3-supply", 3},
  136         {"vccio4-supply", 4},
  137         {"vccio5-supply", 5},
  138         {"vccio6-supply", 6},
  139         {"vccio7-supply", 7},
  140 };
  141 static struct rk_iodomain_conf rk3568_pmu_conf = {
  142         .supply = rk3568_pmu_supply,
  143         .nsupply = nitems(rk3568_pmu_supply),
  144         .type = RK3568,
  145 };
  146 
  147 static struct ofw_compat_data compat_data[] = {
  148         {"rockchip,rk3288-io-voltage-domain", (uintptr_t)&rk3288_conf},
  149         {"rockchip,rk3399-io-voltage-domain", (uintptr_t)&rk3399_conf},
  150         {"rockchip,rk3399-pmu-io-voltage-domain", (uintptr_t)&rk3399_pmu_conf},
  151         {"rockchip,rk3568-pmu-io-voltage-domain", (uintptr_t)&rk3568_pmu_conf},
  152         {NULL,             0}
  153 };
  154 
  155 static void
  156 rk3399_pmu_init(struct rk_iodomain_softc *sc)
  157 {
  158 
  159         SYSCON_WRITE_4(sc->grf, RK3399_PMUGRF_SOC_CON0,
  160             (1 << 8) | (1 << (8 + 16)));        /* set pmu1830_volsel */
  161 }
  162 
  163 static int
  164 rk_iodomain_set(struct rk_iodomain_softc *sc)
  165 {
  166         regulator_t supply;
  167         uint32_t reg = 0;
  168         uint32_t mask = 0;
  169         int uvolt, i;
  170 
  171         for (i = 0; i < sc->conf->nsupply; i++) {
  172                 if (regulator_get_by_ofw_property(sc->dev, sc->node,
  173                     sc->conf->supply[i].name, &supply) != 0) {
  174                         device_printf(sc->dev,
  175                             "Cannot get property for regulator %s\n",
  176                             sc->conf->supply[i].name);
  177                         return (ENXIO);
  178                 }
  179 
  180                 if (regulator_get_voltage(supply, &uvolt) != 0) {
  181                         device_printf(sc->dev,
  182                             "Cannot get current voltage for regulator %s\n",
  183                             sc->conf->supply[i].name);
  184                         return (ENXIO);
  185                 }
  186 
  187                 if (sc->conf->type != RK3568) {
  188                         /* RK3328 and RK3399 iodomain */
  189                         mask |= (1 << sc->conf->supply[i].bit) << 16;
  190                         if (uvolt == 1800000)
  191                                 reg |= (1 << sc->conf->supply[i].bit);
  192                         else if (uvolt != 3000000)
  193                                 device_printf(sc->dev,
  194                                     "%s regulator is at %duV, ignoring\n",
  195                                     sc->conf->supply[i].name, uvolt);
  196                 } else {
  197                         /* RK3568 iodomain */
  198                         if (bootverbose) {
  199                                 device_printf(sc->dev,
  200                                     "Setting regulator %s voltage=%duV\n",
  201                                     sc->conf->supply[i].name, uvolt);
  202                         }
  203                         switch(i) {
  204                         case 0: /* pmuio1 */
  205                                 break;
  206                         case 1: /* pmuio2 */
  207                                 SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL2,
  208                                     (1 << (sc->conf->supply[i].bit + 16)) |
  209                                     (uvolt > MAX_1V8 ?
  210                                     0 : 1 << sc->conf->supply[i].bit));
  211                                 SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL2,
  212                                     (1 << (sc->conf->supply[i].bit + 4 + 16)) |
  213                                     (uvolt > MAX_1V8 ?
  214                                     1 << (sc->conf->supply[i].bit + 4) : 0));
  215                         case 3: /* vccio2 */
  216                                 break;
  217                         case 2: /* vccio1 */
  218                         case 4: /* vccio3 */
  219                         case 5: /* vccio4 */
  220                         case 6: /* vccio5 */
  221                         case 7: /* vccio6 */
  222                         case 8: /* vccio7 */
  223                                 SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL0,
  224                                     (1 << (sc->conf->supply[i].bit + 16)) |
  225                                     (uvolt > MAX_1V8 ?
  226                                     0 : 1 << sc->conf->supply[i].bit));
  227                                 SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL1,
  228                                     (1 << (sc->conf->supply[i].bit + 16)) |
  229                                     (uvolt > MAX_1V8 ?
  230                                     1 << sc->conf->supply[i].bit : 0));
  231                                 break;
  232                         default:
  233                                 device_printf(sc->dev, "Index out of range\n");
  234                         }
  235                 }
  236         }
  237         if (sc->conf->type != RK3568)
  238                 SYSCON_WRITE_4(sc->grf, sc->conf->grf_reg, reg | mask);
  239         if (sc->conf->init != NULL)
  240                  sc->conf->init(sc);
  241 
  242         return (0);
  243 }
  244 
  245 static int
  246 rk_iodomain_probe(device_t dev)
  247 {
  248 
  249         if (!ofw_bus_status_okay(dev))
  250                 return (ENXIO);
  251 
  252         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  253                 return (ENXIO);
  254 
  255         device_set_desc(dev, "RockChip IO Voltage Domain");
  256         return (BUS_PROBE_DEFAULT);
  257 }
  258 
  259 static int
  260 rk_iodomain_attach(device_t dev)
  261 {
  262         struct rk_iodomain_softc *sc;
  263         int rv;
  264 
  265         sc = device_get_softc(dev);
  266         sc->dev = dev;
  267         sc->node = ofw_bus_get_node(dev);
  268 
  269         rv = syscon_get_handle_default(dev, &sc->grf);
  270         if (rv != 0) {
  271                 device_printf(dev, "Cannot get grf handle\n");
  272                 return (ENXIO);
  273         }
  274 
  275         sc->conf = (struct rk_iodomain_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
  276         rv = rk_iodomain_set(sc);
  277 
  278         return (rv);
  279 }
  280 
  281 static int
  282 rk_iodomain_detach(device_t dev)
  283 {
  284 
  285         return (0);
  286 }
  287 
  288 static device_method_t rk_iodomain_methods[] = {
  289         /* Device interface */
  290         DEVMETHOD(device_probe,         rk_iodomain_probe),
  291         DEVMETHOD(device_attach,        rk_iodomain_attach),
  292         DEVMETHOD(device_detach,        rk_iodomain_detach),
  293 
  294         DEVMETHOD_END
  295 };
  296 
  297 static driver_t rk_iodomain_driver = {
  298         "rk_iodomain",
  299         rk_iodomain_methods,
  300         sizeof(struct rk_iodomain_softc),
  301 };
  302 
  303 EARLY_DRIVER_MODULE(rk_iodomain, simplebus, rk_iodomain_driver, 0, 0,
  304     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);

Cache object: 8d22a8cd040daefc859df7015a02b0a5


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