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