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/extres/syscon/syscon.h> 39 #include <dev/extres/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; 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 242 static int 243 rk_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 256 static int 257 rk_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 278 static int 279 rk_iodomain_detach(device_t dev) 280 { 281 282 return (0); 283 } 284 285 static 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 294 static driver_t rk_iodomain_driver = { 295 "rk_iodomain", 296 rk_iodomain_methods, 297 sizeof(struct rk_iodomain_softc), 298 }; 299 300 EARLY_DRIVER_MODULE(rk_iodomain, simplebus, rk_iodomain_driver, 0, 0, 301 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); 302