11.1Sskrll/* $NetBSD: apple_pinctrl.c,v 1.1 2022/04/27 07:59:18 skrll Exp $ */ 21.1Sskrll/* $OpenBSD: aplpinctrl.c,v 1.4 2022/04/06 18:59:26 naddy Exp $ */ 31.1Sskrll 41.1Sskrll/*- 51.1Sskrll * Copyright (c) 2022 The NetBSD Foundation, Inc. 61.1Sskrll * All rights reserved. 71.1Sskrll * 81.1Sskrll * This code is derived from software contributed to The NetBSD Foundation 91.1Sskrll * by Nick Hudson 101.1Sskrll * 111.1Sskrll * Redistribution and use in source and binary forms, with or without 121.1Sskrll * modification, are permitted provided that the following conditions 131.1Sskrll * are met: 141.1Sskrll * 1. Redistributions of source code must retain the above copyright 151.1Sskrll * notice, this list of conditions and the following disclaimer. 161.1Sskrll * 2. Redistributions in binary form must reproduce the above copyright 171.1Sskrll * notice, this list of conditions and the following disclaimer in the 181.1Sskrll * documentation and/or other materials provided with the distribution. 191.1Sskrll * 201.1Sskrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 211.1Sskrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 221.1Sskrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 231.1Sskrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 241.1Sskrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 251.1Sskrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 261.1Sskrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 271.1Sskrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 281.1Sskrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 291.1Sskrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 301.1Sskrll * POSSIBILITY OF SUCH DAMAGE. 311.1Sskrll */ 321.1Sskrll 331.1Sskrll/* 341.1Sskrll * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org> 351.1Sskrll * 361.1Sskrll * Permission to use, copy, modify, and distribute this software for any 371.1Sskrll * purpose with or without fee is hereby granted, provided that the above 381.1Sskrll * copyright notice and this permission notice appear in all copies. 391.1Sskrll * 401.1Sskrll * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 411.1Sskrll * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 421.1Sskrll * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 431.1Sskrll * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 441.1Sskrll * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 451.1Sskrll * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 461.1Sskrll * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 471.1Sskrll */ 481.1Sskrll 491.1Sskrll#include <sys/cdefs.h> 501.1Sskrll__KERNEL_RCSID(0, "$NetBSD: apple_pinctrl.c,v 1.1 2022/04/27 07:59:18 skrll Exp $"); 511.1Sskrll 521.1Sskrll#include <sys/param.h> 531.1Sskrll#include <sys/bus.h> 541.1Sskrll#include <sys/device.h> 551.1Sskrll#include <sys/kmem.h> 561.1Sskrll 571.1Sskrll#include <dev/fdt/fdtvar.h> 581.1Sskrll 591.1Sskrll#include <arm/pic/picvar.h> 601.1Sskrll 611.1Sskrll#define APPLE_PIN(pinmux) __SHIFTOUT((pinmux), __BITS(15, 0)) 621.1Sskrll#define APPLE_FUNC(pinmux) __SHIFTOUT((pinmux), __BITS(31, 16)) 631.1Sskrll 641.1Sskrll#define GPIO_PIN(pin) ((pin) * 4) 651.1Sskrll#define GPIO_PIN_GROUP_MASK __BITS(18, 16) 661.1Sskrll#define GPIO_PIN_INPUT_ENABLE __BIT(9) 671.1Sskrll#define GPIO_PIN_FUNC_MASK __BITS(6, 5) 681.1Sskrll#define GPIO_PIN_MODE_MASK __BITS(3, 1) 691.1Sskrll#define GPIO_PIN_MODE_INPUT __SHIFTIN(0, GPIO_PIN_MODE_MASK); 701.1Sskrll#define GPIO_PIN_MODE_OUTPUT __SHIFTIN(1, GPIO_PIN_MODE_MASK); 711.1Sskrll#define GPIO_PIN_MODE_IRQ_HI __SHIFTIN(2, GPIO_PIN_MODE_MASK); 721.1Sskrll#define GPIO_PIN_MODE_IRQ_LO __SHIFTIN(3, GPIO_PIN_MODE_MASK); 731.1Sskrll#define GPIO_PIN_MODE_IRQ_UP __SHIFTIN(4, GPIO_PIN_MODE_MASK); 741.1Sskrll#define GPIO_PIN_MODE_IRQ_DN __SHIFTIN(5, GPIO_PIN_MODE_MASK); 751.1Sskrll#define GPIO_PIN_MODE_IRQ_ANY __SHIFTIN(6, GPIO_PIN_MODE_MASK); 761.1Sskrll#define GPIO_PIN_MODE_IRQ_OFF __SHIFTIN(7, GPIO_PIN_MODE_MASK); 771.1Sskrll#define GPIO_PIN_DATA __BIT(0) 781.1Sskrll#define GPIO_IRQ(grp, pin) (0x800 + (grp) * 64 + ((pin) >> 5) * 4) 791.1Sskrll 801.1Sskrll#define PINCTRL_READ(sc, reg) \ 811.1Sskrll (bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))) 821.1Sskrll#define PINCTRL_WRITE(sc, reg, val) \ 831.1Sskrll bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 841.1Sskrll#define PINCTRL_SET(sc, reg, bits) \ 851.1Sskrll PINCTRL_WRITE((sc), (reg), PINCTRL_READ((sc), (reg)) | (bits)) 861.1Sskrll#define PINCTRL_CLR(sc, reg, bits) \ 871.1Sskrll PINCTRL_WRITE((sc), (reg), PINCTRL_READ((sc), (reg)) & ~(bits)) 881.1Sskrll 891.1Sskrll 901.1Sskrllstruct apple_pinctrl_softc { 911.1Sskrll device_t sc_dev; 921.1Sskrll int sc_phandle; 931.1Sskrll bus_space_tag_t sc_bst; 941.1Sskrll bus_space_handle_t sc_bsh; 951.1Sskrll u_int sc_npins; 961.1Sskrll}; 971.1Sskrll 981.1Sskrllstruct apple_gpio_pin { 991.1Sskrll int pin_no; 1001.1Sskrll u_int pin_flags; 1011.1Sskrll bool pin_actlo; 1021.1Sskrll}; 1031.1Sskrll 1041.1Sskrllstatic const struct device_compatible_entry compat_data[] = { 1051.1Sskrll { .compat = "apple,pinctrl" }, 1061.1Sskrll DEVICE_COMPAT_EOL 1071.1Sskrll}; 1081.1Sskrll 1091.1Sskrllstatic void 1101.1Sskrllapple_gpio_pin_ctl(void *cookie, int pin, int flags) 1111.1Sskrll{ 1121.1Sskrll struct apple_pinctrl_softc * const sc = cookie; 1131.1Sskrll 1141.1Sskrll KASSERT(pin < sc->sc_npins); 1151.1Sskrll 1161.1Sskrll uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pin)); 1171.1Sskrll reg &= ~GPIO_PIN_FUNC_MASK; 1181.1Sskrll reg &= ~GPIO_PIN_MODE_MASK; 1191.1Sskrll 1201.1Sskrll if (flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) { 1211.1Sskrll if (flags & GPIO_PIN_INPUT) { 1221.1Sskrll /* for safety INPUT will override output */ 1231.1Sskrll reg |= GPIO_PIN_MODE_INPUT; 1241.1Sskrll } else { 1251.1Sskrll reg |= GPIO_PIN_MODE_OUTPUT; 1261.1Sskrll } 1271.1Sskrll } 1281.1Sskrll PINCTRL_WRITE(sc, GPIO_PIN(pin), reg); 1291.1Sskrll} 1301.1Sskrll 1311.1Sskrllstatic void * 1321.1Sskrllapple_pinctrl_gpio_acquire(device_t dev, const void *data, size_t len, int flags) 1331.1Sskrll{ 1341.1Sskrll struct apple_pinctrl_softc * const sc = device_private(dev); 1351.1Sskrll struct apple_gpio_pin *pin; 1361.1Sskrll const u_int *gpio = data; 1371.1Sskrll 1381.1Sskrll if (len != 12) 1391.1Sskrll return NULL; 1401.1Sskrll 1411.1Sskrll const u_int pinno = be32toh(gpio[1]); 1421.1Sskrll const bool actlo = be32toh(gpio[2]) & 1; 1431.1Sskrll 1441.1Sskrll if (pinno >= sc->sc_npins) 1451.1Sskrll return NULL; 1461.1Sskrll 1471.1Sskrll pin = kmem_alloc(sizeof(*pin), KM_SLEEP); 1481.1Sskrll pin->pin_no = pinno; 1491.1Sskrll pin->pin_flags = flags; 1501.1Sskrll pin->pin_actlo = actlo; 1511.1Sskrll 1521.1Sskrll apple_gpio_pin_ctl(sc, pin->pin_no, pin->pin_flags); 1531.1Sskrll 1541.1Sskrll return pin; 1551.1Sskrll} 1561.1Sskrll 1571.1Sskrllstatic void 1581.1Sskrllapple_pinctrl_gpio_release(device_t dev, void *priv) 1591.1Sskrll{ 1601.1Sskrll struct apple_pinctrl_softc * const sc = device_private(dev); 1611.1Sskrll struct apple_gpio_pin *pin = priv; 1621.1Sskrll 1631.1Sskrll apple_gpio_pin_ctl(sc, pin->pin_no, GPIO_PIN_INPUT); 1641.1Sskrll kmem_free(pin, sizeof(*pin)); 1651.1Sskrll} 1661.1Sskrll 1671.1Sskrllstatic int 1681.1Sskrllapple_pinctrl_gpio_read(device_t dev, void *priv, bool raw) 1691.1Sskrll{ 1701.1Sskrll struct apple_pinctrl_softc * const sc = device_private(dev); 1711.1Sskrll struct apple_gpio_pin *pin = priv; 1721.1Sskrll 1731.1Sskrll KASSERT(pin->pin_no < sc->sc_npins); 1741.1Sskrll 1751.1Sskrll uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pin->pin_no)); 1761.1Sskrll int val = __SHIFTOUT(reg, GPIO_PIN_DATA); 1771.1Sskrll if (!raw && pin->pin_actlo) 1781.1Sskrll val = !val; 1791.1Sskrll 1801.1Sskrll return val; 1811.1Sskrll} 1821.1Sskrll 1831.1Sskrllstatic void 1841.1Sskrllapple_pinctrl_gpio_write(device_t dev, void *priv, int val, bool raw) 1851.1Sskrll{ 1861.1Sskrll struct apple_pinctrl_softc * const sc = device_private(dev); 1871.1Sskrll struct apple_gpio_pin *pin = priv; 1881.1Sskrll 1891.1Sskrll KASSERT(pin->pin_no < sc->sc_npins); 1901.1Sskrll 1911.1Sskrll if (!raw && pin->pin_actlo) 1921.1Sskrll val = !val; 1931.1Sskrll 1941.1Sskrll if (val) 1951.1Sskrll PINCTRL_SET(sc, GPIO_PIN(pin->pin_no), GPIO_PIN_DATA); 1961.1Sskrll else 1971.1Sskrll PINCTRL_CLR(sc, GPIO_PIN(pin->pin_no), GPIO_PIN_DATA); 1981.1Sskrll} 1991.1Sskrll 2001.1Sskrllstatic int 2011.1Sskrllapple_pinctrl_set_config(device_t dev, const void *data, size_t len) 2021.1Sskrll{ 2031.1Sskrll struct apple_pinctrl_softc * const sc = device_private(dev); 2041.1Sskrll 2051.1Sskrll if (len != 4) 2061.1Sskrll return -1; 2071.1Sskrll 2081.1Sskrll int pins_len; 2091.1Sskrll const int phandle = fdtbus_get_phandle_from_native(be32dec(data)); 2101.1Sskrll const u_int *pins = fdtbus_get_prop(phandle, "pinmux", &pins_len); 2111.1Sskrll 2121.1Sskrll if (pins == NULL) 2131.1Sskrll return -1; 2141.1Sskrll 2151.1Sskrll const u_int npins = pins_len / sizeof(uint32_t); 2161.1Sskrll 2171.1Sskrll for (u_int i = 0; i < npins; i++) { 2181.1Sskrll uint32_t pinmux = be32dec(&pins[i]); 2191.1Sskrll u_int pinno = APPLE_PIN(pinmux); 2201.1Sskrll u_int func = APPLE_FUNC(pinmux); 2211.1Sskrll 2221.1Sskrll uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pinno)); 2231.1Sskrll reg &= ~GPIO_PIN_FUNC_MASK; 2241.1Sskrll reg |= __SHIFTIN(func, GPIO_PIN_FUNC_MASK); 2251.1Sskrll 2261.1Sskrll PINCTRL_WRITE(sc, GPIO_PIN(pinno), reg); 2271.1Sskrll } 2281.1Sskrll 2291.1Sskrll return 0; 2301.1Sskrll} 2311.1Sskrll 2321.1Sskrllstatic struct fdtbus_gpio_controller_func apple_pinctrl_gpio_funcs = { 2331.1Sskrll .acquire = apple_pinctrl_gpio_acquire, 2341.1Sskrll .release = apple_pinctrl_gpio_release, 2351.1Sskrll .read = apple_pinctrl_gpio_read, 2361.1Sskrll .write = apple_pinctrl_gpio_write 2371.1Sskrll}; 2381.1Sskrll 2391.1Sskrllstatic struct fdtbus_pinctrl_controller_func apple_pinctrl_funcs = { 2401.1Sskrll .set_config = apple_pinctrl_set_config, 2411.1Sskrll}; 2421.1Sskrll 2431.1Sskrllstatic int 2441.1Sskrllapple_pinctrl_match(device_t parent, cfdata_t cf, void *aux) 2451.1Sskrll{ 2461.1Sskrll struct fdt_attach_args * const faa = aux; 2471.1Sskrll 2481.1Sskrll return of_compatible_match(faa->faa_phandle, compat_data); 2491.1Sskrll} 2501.1Sskrll 2511.1Sskrllstatic void 2521.1Sskrllapple_pinctrl_attach(device_t parent, device_t self, void *aux) 2531.1Sskrll{ 2541.1Sskrll struct apple_pinctrl_softc * const sc = device_private(self); 2551.1Sskrll struct fdt_attach_args * const faa = aux; 2561.1Sskrll const int phandle = faa->faa_phandle; 2571.1Sskrll bus_addr_t addr; 2581.1Sskrll bus_size_t size; 2591.1Sskrll 2601.1Sskrll if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 2611.1Sskrll aprint_error(": couldn't get registers\n"); 2621.1Sskrll return; 2631.1Sskrll } 2641.1Sskrll 2651.1Sskrll sc->sc_dev = self; 2661.1Sskrll sc->sc_bst = faa->faa_bst; 2671.1Sskrll 2681.1Sskrll if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 2691.1Sskrll aprint_error(": couldn't map registers\n"); 2701.1Sskrll return; 2711.1Sskrll } 2721.1Sskrll 2731.1Sskrll if (of_getprop_uint32(phandle, "apple,npins", &sc->sc_npins)) { 2741.1Sskrll aprint_error(": couldn't get number of pins\n"); 2751.1Sskrll return; 2761.1Sskrll } 2771.1Sskrll 2781.1Sskrll if (!of_hasprop(phandle, "gpio-controller")) { 2791.1Sskrll aprint_error(": no gpio controller"); 2801.1Sskrll return; 2811.1Sskrll } 2821.1Sskrll 2831.1Sskrll aprint_naive("\n"); 2841.1Sskrll aprint_normal(": Apple Pinctrl\n"); 2851.1Sskrll 2861.1Sskrll fdtbus_register_gpio_controller(self, phandle, &apple_pinctrl_gpio_funcs); 2871.1Sskrll 2881.1Sskrll for (int child = OF_child(phandle); child; child = OF_peer(child)) { 2891.1Sskrll if (!of_hasprop(child, "pinmux")) 2901.1Sskrll continue; 2911.1Sskrll fdtbus_register_pinctrl_config(self, child, 2921.1Sskrll &apple_pinctrl_funcs); 2931.1Sskrll 2941.1Sskrll } 2951.1Sskrll} 2961.1Sskrll 2971.1SskrllCFATTACH_DECL_NEW(apple_pinctrl, sizeof(struct apple_pinctrl_softc), 2981.1Sskrll apple_pinctrl_match, apple_pinctrl_attach, NULL, NULL); 2991.1Sskrll 300