1 /* $NetBSD: jh7100_pinctrl.c,v 1.3 2024/09/18 08:31:50 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2023 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Nick Hudson 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: jh7100_pinctrl.c,v 1.3 2024/09/18 08:31:50 skrll Exp $"); 34 35 #include <sys/param.h> 36 37 #include <sys/kmem.h> 38 39 #include <dev/fdt/fdtvar.h> 40 41 struct jh7100_pinctrl_softc { 42 device_t sc_dev; 43 bus_space_tag_t sc_bst; 44 bus_space_handle_t sc_gpio_bsh; 45 bus_space_handle_t sc_padctl_bsh; 46 int sc_phandle; 47 48 kmutex_t sc_lock; 49 u_int sc_padctl_gpio; 50 }; 51 52 struct jh7100_pinctrl_gpio_pin { 53 struct jh7100_pinctrl_softc *pin_sc; 54 u_int pin_no; 55 bool pin_actlo; 56 }; 57 58 #define GPIORD4(sc, reg) \ 59 bus_space_read_4((sc)->sc_bst, (sc)->sc_gpio_bsh, (reg)) 60 #define GPIOWR4(sc, reg, val) \ 61 bus_space_write_4((sc)->sc_bst, (sc)->sc_gpio_bsh, (reg), (val)) 62 63 #define GPIO_DIN(pin) (0x0048 + (((pin) / 32) * 4)) 64 65 #define GPO_DOUT_CFG(pin) (0x0050 + ((pin) * 8)) 66 #define GPO_DOUT_REVERSE __BIT(31) 67 #define GPO_DOUT_MASK __BITS(30, 0) 68 #define GPO_DOEN_CFG(pin) (0x0054 + ((pin) * 8)) 69 #define GPO_DOEN_REVERSE __BIT(31) 70 #define GPO_DOEN_MASK __BITS(30, 0) 71 #define GPO_ENABLE 0 72 #define GPO_DISABLE 1 73 #define GPI_DIN(din) (0x0250 + ((din) * 4)) 74 #define GPI_NONE 0xff 75 76 77 #define PCTLRD4(sc, reg) \ 78 bus_space_read_4((sc)->sc_bst, (sc)->sc_padctl_bsh, (reg)) 79 #define PCTLWR4(sc, reg, val) \ 80 bus_space_write_4((sc)->sc_bst, (sc)->sc_padctl_bsh, (reg), (val)) 81 82 #define PAD_GPIO(pin) (0x0000 + (((pin) / 2) * 4)) 83 #define PAD_SHIFT(pin) ((pin % 2) * 16) 84 #define PAD_SLEW_RATE_MASK __BITS(11, 9) 85 #define PAD_BIAS_STRONG_PULLUP __BIT(8) 86 #define PAD_INPUT_ENABLE __BIT(7) 87 #define PAD_INPUT_SCHMITT_ENABLE __BIT(6) 88 #define PAD_BIAS_DISABLE __BIT(5) 89 #define PAD_BIAS_PULLDOWN __BIT(4) 90 #define PAD_DRIVE_STRENGTH_MASK __BITS( 3, 0) 91 92 #define PAD_BIAS_MASK (PAD_BIAS_STRONG_PULLUP | \ 93 PAD_BIAS_DISABLE | \ 94 PAD_BIAS_PULLDOWN) 95 96 #define PAD_DS_MAX __SHIFTOUT_MASK(PAD_DRIVE_STRENGTH_MASK) 97 #define GPIO_DS_TO_MA(ds) ((ds) * 7 + 14) 98 #define GPIO_DS_MIN GPIO_DS_TO_MA(0) 99 #define GPIO_DS_MAX GPIO_DS_TO_MA(PAD_DS_MAX) 100 101 #define PAD_FUNC_SHARE(pad) (GPIO_NPINS + (pad)) 102 #define IO_PADSHARE_SEL 0x01a0 103 104 #define GPIO_NPINS 64 105 106 107 /* Device Tree encoding */ 108 #define DT_GPIOMUX_DOUT_MASK __BITS(31, 24) 109 #define DT_GPIOMUX_DOEN_MASK __BITS(23, 16) 110 #define DT_GPIOMUX_DIN_MASK __BITS(15, 8) 111 #define DT_GPIOMUX_DOUTREV_MASK __BIT(7) 112 #define DT_GPIOMUX_DOENREV_MASK __BIT(6) 113 #define DT_GPIOMUX_GPIO_MASK __BITS( 5, 0) 114 115 #define DT_PAD_GPIO(x) ((x) & (GPIO_NPINS - 1)) 116 #define DT_PAD_FUNC_SHARE(x) ((x) - GPIO_NPINS) 117 118 119 static const struct device_compatible_entry compat_data[] = { 120 { .compat = "starfive,jh7100-pinctrl" }, 121 DEVICE_COMPAT_EOL 122 }; 123 124 125 static inline void 126 jh7100_padctl_rmw(struct jh7100_pinctrl_softc * const sc, u_int pad_no, 127 uint16_t val, uint16_t mask) 128 { 129 const bus_size_t regoff = PAD_GPIO(pad_no); 130 const u_int shift = PAD_SHIFT(pad_no); 131 const uint32_t regmask = mask << shift; 132 const uint32_t regval = val << shift; 133 134 mutex_enter(&sc->sc_lock); 135 uint32_t reg = PCTLRD4(sc, regoff); 136 uint32_t oreg = reg; 137 reg &= ~regmask; 138 reg |= regval; 139 PCTLWR4(sc, regoff, reg); 140 mutex_exit(&sc->sc_lock); 141 142 aprint_debug_dev(sc->sc_dev, "pad %d (pin %d) %08x -> %08x (%#" 143 PRIxBUSSIZE ")\n", pad_no, pad_no - sc->sc_padctl_gpio, 144 oreg, reg, regoff); 145 } 146 147 static int 148 jh7100_parse_slew_rate(int phandle) 149 { 150 int slew_rate; 151 152 if (of_getprop_uint32(phandle, "slew-rate", &slew_rate) == 0) 153 return slew_rate; 154 155 return -1; 156 } 157 158 static void 159 jh7100_pinctrl_pin_properties(struct jh7100_pinctrl_softc *sc, int phandle, 160 uint16_t *val, uint16_t *mask) 161 { 162 *mask = 0; 163 *val = 0; 164 165 const int bias = fdtbus_pinctrl_parse_bias(phandle, NULL); 166 const int drive_strength = fdtbus_pinctrl_parse_drive_strength(phandle); 167 const int slew_rate = jh7100_parse_slew_rate(phandle); 168 169 switch (bias) { 170 case 0: 171 *mask |= PAD_BIAS_MASK; 172 *val |= PAD_BIAS_DISABLE; 173 break; 174 case GPIO_PIN_PULLUP: 175 *mask |= PAD_BIAS_MASK; 176 break; 177 case GPIO_PIN_PULLDOWN: 178 *mask |= PAD_BIAS_MASK; 179 *val |= PAD_BIAS_PULLDOWN; 180 break; 181 case -1: 182 default: 183 break; 184 } 185 186 switch (drive_strength) { 187 case GPIO_DS_MIN ... GPIO_DS_MAX: { 188 const u_int ds = (drive_strength - 14) / 7; 189 *mask |= PAD_DRIVE_STRENGTH_MASK; 190 *val |= __SHIFTIN(ds, PAD_DRIVE_STRENGTH_MASK); 191 break; 192 } 193 case -1: 194 break; 195 default: 196 aprint_error_dev(sc->sc_dev, "phandle %d invalid drive " 197 "strength %d\n", phandle, drive_strength); 198 } 199 200 if (of_hasprop(phandle, "input-enable")) { 201 *mask |= PAD_INPUT_ENABLE; 202 *val |= PAD_INPUT_ENABLE; 203 } 204 if (of_hasprop(phandle, "input-disable")) { 205 *mask |= PAD_INPUT_ENABLE; 206 *val &= ~PAD_INPUT_ENABLE; 207 } 208 if (of_hasprop(phandle, "input-schmitt-enable")) { 209 *mask |= PAD_INPUT_SCHMITT_ENABLE; 210 *val |= PAD_INPUT_SCHMITT_ENABLE; 211 } 212 if (of_hasprop(phandle, "input-schmitt-disable")) { 213 *mask |= PAD_INPUT_SCHMITT_ENABLE; 214 *val &= ~PAD_INPUT_SCHMITT_ENABLE; 215 } 216 217 switch (slew_rate) { 218 case 0 ... __SHIFTOUT_MASK(PAD_SLEW_RATE_MASK): 219 *mask |= PAD_SLEW_RATE_MASK; 220 *val |= __SHIFTIN(slew_rate, PAD_SLEW_RATE_MASK); 221 break; 222 case -1: 223 break; 224 default: 225 aprint_error_dev(sc->sc_dev, "invalid slew rate\n"); 226 } 227 228 if (of_hasprop(phandle, "starfive,strong-pull-up")) { 229 *mask |= PAD_BIAS_MASK; 230 *val |= PAD_BIAS_STRONG_PULLUP; 231 } 232 } 233 234 static void 235 jh7100_pinctrl_set_config_group(struct jh7100_pinctrl_softc *sc, int group) 236 { 237 int pins_len, pinmux_len; 238 const u_int *pins = fdtbus_get_prop(group, "pins", &pins_len); 239 const u_int *pinmux = fdtbus_get_prop(group, "pinmux", &pinmux_len); 240 size_t plen; 241 const u_int *parray; 242 243 aprint_debug_dev(sc->sc_dev, "set_config: group %d\n", group); 244 245 if (pins == NULL && pinmux == NULL) { 246 aprint_debug_dev(sc->sc_dev, "group %d neither 'pins' nor " 247 "'pinmux' exist\n", group); 248 return; 249 } else if (pins != NULL && pinmux != NULL) { 250 aprint_debug_dev(sc->sc_dev, "group %d both 'pins' and " 251 "'pinmux' exist\n", group); 252 return; 253 } 254 255 if (pins != NULL) { 256 KASSERT(pinmux == NULL); 257 plen = pins_len; 258 parray = pins; 259 } 260 if (pinmux != NULL) { 261 KASSERT(pins == NULL); 262 plen = pinmux_len; 263 parray = pinmux; 264 } 265 const size_t npins = plen / sizeof(uint32_t); 266 267 uint16_t val, mask; 268 jh7100_pinctrl_pin_properties(sc, group, &val, &mask); 269 270 aprint_debug_dev(sc->sc_dev, "set_config: group %d, len %zu " 271 "value %#6x mask %#6x\n", group, plen, val, mask); 272 273 for (size_t i = 0; i < npins; i++) { 274 uint32_t p = be32dec(&parray[i]); 275 u_int pin_no; 276 277 if (pins != NULL) { 278 pin_no = p; 279 aprint_debug_dev(sc->sc_dev, "set_config: group %d" 280 ", gpio %d doen %#x\n", group, pin_no, 281 GPIORD4(sc, GPO_DOEN_CFG(pin_no))); 282 GPIOWR4(sc, GPO_DOEN_CFG(pin_no), GPO_DISABLE); 283 jh7100_padctl_rmw(sc, pin_no, 284 val, mask); 285 } 286 if (pinmux != NULL) { 287 pin_no = __SHIFTOUT(p, DT_GPIOMUX_GPIO_MASK); 288 u_int dout = __SHIFTOUT(p, DT_GPIOMUX_DOUT_MASK); 289 u_int doen = __SHIFTOUT(p, DT_GPIOMUX_DOEN_MASK); 290 u_int din = __SHIFTOUT(p, DT_GPIOMUX_DIN_MASK); 291 u_int doutrev = __SHIFTOUT(p, DT_GPIOMUX_DOUTREV_MASK); 292 u_int doenrev = __SHIFTOUT(p, DT_GPIOMUX_DOENREV_MASK); 293 294 uint32_t doutval = 295 __SHIFTIN(doutrev, GPO_DOUT_REVERSE) | 296 __SHIFTIN(dout, GPO_DOUT_MASK); 297 uint32_t doenval = 298 __SHIFTIN(doenrev, GPO_DOEN_REVERSE) | 299 __SHIFTIN(doen, GPO_DOEN_MASK); 300 301 aprint_debug_dev(sc->sc_dev, "set_config: group %d" 302 ", gpio %d dout %#x/%#x doen %#x/%#x din %#x/%#x\n", 303 group, pin_no, 304 doutval, GPIORD4(sc, GPO_DOUT_CFG(pin_no)), 305 doenval, GPIORD4(sc, GPO_DOEN_CFG(pin_no)), 306 din != GPI_NONE ? pin_no + 2 : 0, GPIORD4(sc, GPI_DIN(din))); 307 308 mutex_enter(&sc->sc_lock); 309 GPIOWR4(sc, GPO_DOUT_CFG(pin_no), doutval); 310 GPIOWR4(sc, GPO_DOEN_CFG(pin_no), doenval); 311 if (din != GPI_NONE) { 312 /* 313 * 0 is digital 0, 314 * 1 is digital 1, 315 * 2 is PAD_GPIO[0] 316 * ... 317 * 65 is PAD_GPIO[63] 318 */ 319 GPIOWR4(sc, GPI_DIN(din), pin_no + 2); 320 } 321 mutex_exit(&sc->sc_lock); 322 jh7100_padctl_rmw(sc, sc->sc_padctl_gpio + pin_no, 323 val, mask); 324 } 325 } 326 } 327 328 static int 329 jh7100_pinctrl_set_config(device_t dev, const void *data, size_t len) 330 { 331 struct jh7100_pinctrl_softc * const sc = device_private(dev); 332 333 if (len != 4) 334 return -1; 335 336 const int phandle = fdtbus_get_phandle_from_native(be32dec(data)); 337 aprint_debug_dev(sc->sc_dev, "set_config: phandle %d\n", phandle); 338 339 for (int child = OF_child(phandle); child; child = OF_peer(child)) { 340 jh7100_pinctrl_set_config_group(sc, child); 341 } 342 343 return 0; 344 } 345 346 static struct fdtbus_pinctrl_controller_func jh7100_pinctrl_funcs = { 347 .set_config = jh7100_pinctrl_set_config, 348 }; 349 350 351 static void * 352 jh7100_pinctrl_gpio_acquire(device_t dev, const void *data, size_t len, int flags) 353 { 354 struct jh7100_pinctrl_softc * const sc = device_private(dev); 355 356 if (len != 12) 357 return NULL; 358 359 const u_int *gpio = data; 360 const u_int pin_no = be32toh(gpio[1]); 361 const bool actlo = be32toh(gpio[2]) & 1; 362 363 if (pin_no >= GPIO_NPINS) 364 return NULL; 365 366 // XXXNH twiddle something?? 367 struct jh7100_pinctrl_gpio_pin *pin = 368 kmem_zalloc(sizeof(*pin), KM_SLEEP); 369 pin->pin_sc = sc; 370 pin->pin_no = pin_no; 371 pin->pin_actlo = actlo; 372 373 return pin; 374 } 375 376 static void 377 jh7100_pinctrl_gpio_release(device_t dev, void *priv) 378 { 379 struct jh7100_pinctrl_softc * const sc = device_private(dev); 380 struct jh7100_pinctrl_gpio_pin *pin = priv; 381 382 KASSERT(sc == pin->pin_sc); 383 // XXXNH untwiddle something? 384 kmem_free(pin, sizeof(*pin)); 385 } 386 387 static int 388 jh7100_pinctrl_gpio_read(device_t dev, void *priv, bool raw) 389 { 390 struct jh7100_pinctrl_softc * const sc = device_private(dev); 391 struct jh7100_pinctrl_gpio_pin *pin = priv; 392 const u_int pin_no = pin ->pin_no; 393 const uint32_t bank = GPIORD4(sc, GPIO_DIN(pin_no)); 394 const uint32_t mask = pin_no % (sizeof(bank) * NBBY); 395 396 int val = __SHIFTOUT(bank, mask); 397 if (!raw && pin->pin_actlo) 398 val = !val; 399 400 return val; 401 } 402 403 static void 404 jh7100_pinctrl_gpio_write(device_t dev, void *priv, int val, bool raw) 405 { 406 struct jh7100_pinctrl_softc * const sc = device_private(dev); 407 struct jh7100_pinctrl_gpio_pin *pin = priv; 408 const u_int pin_no = pin ->pin_no; 409 410 if (!raw && pin->pin_actlo) 411 val = !val; 412 413 mutex_enter(&sc->sc_lock); 414 GPIOWR4(sc, GPO_DOUT_CFG(pin_no), val); 415 mutex_exit(&sc->sc_lock); 416 } 417 418 static struct fdtbus_gpio_controller_func jh7100_pinctrl_gpio_funcs = { 419 .acquire = jh7100_pinctrl_gpio_acquire, 420 .release = jh7100_pinctrl_gpio_release, 421 .read = jh7100_pinctrl_gpio_read, 422 .write = jh7100_pinctrl_gpio_write, 423 }; 424 425 426 static int 427 jh7100_pinctrl_match(device_t parent, cfdata_t cf, void *aux) 428 { 429 struct fdt_attach_args * const faa = aux; 430 431 return of_compatible_match(faa->faa_phandle, compat_data); 432 } 433 434 static void 435 jh7100_pinctrl_attach(device_t parent, device_t self, void *aux) 436 { 437 struct jh7100_pinctrl_softc *sc = device_private(self); 438 struct fdt_attach_args * const faa = aux; 439 const int phandle = faa->faa_phandle; 440 bus_addr_t addr; 441 bus_size_t size; 442 443 sc->sc_dev = self; 444 sc->sc_phandle = phandle; 445 sc->sc_bst = faa->faa_bst; 446 447 if (!of_hasprop(phandle, "gpio-controller")) { 448 aprint_error(": no gpio controller\n"); 449 return; 450 } 451 452 if (fdtbus_get_reg_byname(phandle, "gpio", &addr, &size) != 0 || 453 bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_gpio_bsh) != 0) { 454 aprint_error(": couldn't map gpio registers\n"); 455 return; 456 } 457 if (fdtbus_get_reg_byname(phandle, "padctl", &addr, &size) != 0 || 458 bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_padctl_bsh) != 0) { 459 aprint_error(": couldn't map padctl registers\n"); 460 return; 461 } 462 463 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM); 464 465 aprint_naive("\n"); 466 aprint_normal(": Pin Controller\n"); 467 468 u_int sel; 469 int ret; 470 ret = of_getprop_uint32(phandle, "starfive,signal-group", 471 &sel); 472 if (ret < 0) { 473 sel = PCTLRD4(sc, IO_PADSHARE_SEL); 474 } else { 475 PCTLWR4(sc, IO_PADSHARE_SEL, sel); 476 } 477 478 switch (sel) { 479 case 0: 480 // invalid gpio 481 sc->sc_padctl_gpio = -1; 482 break; 483 case 1: 484 sc->sc_padctl_gpio = PAD_GPIO(0); 485 break; 486 case 2: 487 sc->sc_padctl_gpio = PAD_FUNC_SHARE(72); 488 break; 489 case 3: 490 sc->sc_padctl_gpio = PAD_FUNC_SHARE(70); 491 break; 492 case 4 ... 6: 493 sc->sc_padctl_gpio = PAD_FUNC_SHARE(0); 494 break; 495 default: 496 aprint_error_dev(sc->sc_dev, "invalid signal group %u\n", sel); 497 return; 498 } 499 500 aprint_verbose_dev(self, "selector %d\n", sel); 501 502 fdtbus_register_gpio_controller(sc->sc_dev, sc->sc_phandle, 503 &jh7100_pinctrl_gpio_funcs); 504 505 for (int child = OF_child(phandle); child; child = OF_peer(child)) { 506 fdtbus_register_pinctrl_config(self, child, 507 &jh7100_pinctrl_funcs); 508 } 509 } 510 511 CFATTACH_DECL_NEW(jh7100_pinctrl, sizeof(struct jh7100_pinctrl_softc), 512 jh7100_pinctrl_match, jh7100_pinctrl_attach, NULL, NULL); 513