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 52 enum rk_iodomain_type { 53 RK3328 = 1, 54 RK3399, 55 RK3568, 56 }; 57 58 struct rk_iodomain_supply { 59 char *name; 60 uint32_t bit; 61 }; 62 63 struct rk_iodomain_softc; 64 65 struct 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 73 struct rk_iodomain_softc { 74 device_t dev; 75 struct syscon *grf; 76 phandle_t node; 77 struct rk_iodomain_conf *conf; 78 }; 79 80 static 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 93 static 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 100 static struct rk_iodomain_supply rk3399_supply[] = { 101 {"bt656-supply", 0}, 102 {"audio-supply", 1}, 103 {"sdmmc-supply", 2}, 104 {"gpio1830-supply", 3}, 105 }; 106 107 static 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 114 static struct rk_iodomain_supply rk3399_pmu_supply[] = { 115 {"pmu1830-supply", 9}, 116 }; 117 118 static void rk3399_pmu_init(struct rk_iodomain_softc *sc); 119 static 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 127 static 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 }; 138 static struct rk_iodomain_conf rk3568_pmu_conf = { 139 .supply = rk3568_pmu_supply, 140 .nsupply = nitems(rk3568_pmu_supply), 141 .type = RK3568, 142 }; 143 144 static 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 152 static void 153 rk3399_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 160 static int 161 rk_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, rv; 167 168 for (i = 0; i < sc->conf->nsupply; i++) { 169 rv = regulator_get_by_ofw_property(sc->dev, sc->node, 170 sc->conf->supply[i].name, &supply); 171 172 if (rv == ENOENT) 173 continue; 174 175 if (rv != 0) { 176 device_printf(sc->dev, 177 "Cannot get property for regulator %s\n", 178 sc->conf->supply[i].name); 179 return (ENXIO); 180 } 181 182 if (regulator_get_voltage(supply, &uvolt) != 0) { 183 device_printf(sc->dev, 184 "Cannot get current voltage for regulator %s\n", 185 sc->conf->supply[i].name); 186 return (ENXIO); 187 } 188 189 if (sc->conf->type != RK3568) { 190 /* RK3328 and RK3399 iodomain */ 191 mask |= (1 << sc->conf->supply[i].bit) << 16; 192 if (uvolt == 1800000) 193 reg |= (1 << sc->conf->supply[i].bit); 194 else if (uvolt != 3000000) 195 device_printf(sc->dev, 196 "%s regulator is at %duV, ignoring\n", 197 sc->conf->supply[i].name, uvolt); 198 } else { 199 /* RK3568 iodomain */ 200 if (bootverbose) { 201 device_printf(sc->dev, 202 "Setting regulator %s voltage=%duV\n", 203 sc->conf->supply[i].name, uvolt); 204 } 205 switch(i) { 206 case 0: /* pmuio1 */ 207 break; 208 case 1: /* pmuio2 */ 209 SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL2, 210 (1 << (sc->conf->supply[i].bit + 16)) | 211 (uvolt > MAX_1V8 ? 212 0 : 1 << sc->conf->supply[i].bit)); 213 SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL2, 214 (1 << (sc->conf->supply[i].bit + 4 + 16)) | 215 (uvolt > MAX_1V8 ? 216 1 << (sc->conf->supply[i].bit + 4) : 0)); 217 case 3: /* vccio2 */ 218 break; 219 case 2: /* vccio1 */ 220 case 4: /* vccio3 */ 221 case 5: /* vccio4 */ 222 case 6: /* vccio5 */ 223 case 7: /* vccio6 */ 224 case 8: /* vccio7 */ 225 SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL0, 226 (1 << (sc->conf->supply[i].bit + 16)) | 227 (uvolt > MAX_1V8 ? 228 0 : 1 << sc->conf->supply[i].bit)); 229 SYSCON_WRITE_4(sc->grf, RK3568_PMUGRF_IO_VSEL1, 230 (1 << (sc->conf->supply[i].bit + 16)) | 231 (uvolt > MAX_1V8 ? 232 1 << sc->conf->supply[i].bit : 0)); 233 break; 234 default: 235 device_printf(sc->dev, "Index out of range\n"); 236 } 237 } 238 } 239 if (sc->conf->type != RK3568) 240 SYSCON_WRITE_4(sc->grf, sc->conf->grf_reg, reg | mask); 241 if (sc->conf->init != NULL) 242 sc->conf->init(sc); 243 244 return (0); 245 } 246 247 static int 248 rk_iodomain_probe(device_t dev) 249 { 250 251 if (!ofw_bus_status_okay(dev)) 252 return (ENXIO); 253 254 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 255 return (ENXIO); 256 257 device_set_desc(dev, "RockChip IO Voltage Domain"); 258 return (BUS_PROBE_DEFAULT); 259 } 260 261 static int 262 rk_iodomain_attach(device_t dev) 263 { 264 struct rk_iodomain_softc *sc; 265 int rv; 266 267 sc = device_get_softc(dev); 268 sc->dev = dev; 269 sc->node = ofw_bus_get_node(dev); 270 271 rv = syscon_get_handle_default(dev, &sc->grf); 272 if (rv != 0) { 273 device_printf(dev, "Cannot get grf handle\n"); 274 return (ENXIO); 275 } 276 277 sc->conf = (struct rk_iodomain_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; 278 rv = rk_iodomain_set(sc); 279 280 return (rv); 281 } 282 283 static int 284 rk_iodomain_detach(device_t dev) 285 { 286 287 return (0); 288 } 289 290 static device_method_t rk_iodomain_methods[] = { 291 /* Device interface */ 292 DEVMETHOD(device_probe, rk_iodomain_probe), 293 DEVMETHOD(device_attach, rk_iodomain_attach), 294 DEVMETHOD(device_detach, rk_iodomain_detach), 295 296 DEVMETHOD_END 297 }; 298 299 static driver_t rk_iodomain_driver = { 300 "rk_iodomain", 301 rk_iodomain_methods, 302 sizeof(struct rk_iodomain_softc), 303 }; 304 305 EARLY_DRIVER_MODULE(rk_iodomain, simplebus, rk_iodomain_driver, 0, 0, 306 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); 307