Home | History | Annotate | Line # | Download | only in starfive
      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