1 /* $NetBSD: apple_pinctrl.c,v 1.1 2022/04/27 07:59:18 skrll Exp $ */ 2 /* $OpenBSD: aplpinctrl.c,v 1.4 2022/04/06 18:59:26 naddy Exp $ */ 3 4 /*- 5 * Copyright (c) 2022 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Nick Hudson 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org> 35 * 36 * Permission to use, copy, modify, and distribute this software for any 37 * purpose with or without fee is hereby granted, provided that the above 38 * copyright notice and this permission notice appear in all copies. 39 * 40 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 41 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 42 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 43 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 44 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 45 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 46 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 47 */ 48 49 #include <sys/cdefs.h> 50 __KERNEL_RCSID(0, "$NetBSD: apple_pinctrl.c,v 1.1 2022/04/27 07:59:18 skrll Exp $"); 51 52 #include <sys/param.h> 53 #include <sys/bus.h> 54 #include <sys/device.h> 55 #include <sys/kmem.h> 56 57 #include <dev/fdt/fdtvar.h> 58 59 #include <arm/pic/picvar.h> 60 61 #define APPLE_PIN(pinmux) __SHIFTOUT((pinmux), __BITS(15, 0)) 62 #define APPLE_FUNC(pinmux) __SHIFTOUT((pinmux), __BITS(31, 16)) 63 64 #define GPIO_PIN(pin) ((pin) * 4) 65 #define GPIO_PIN_GROUP_MASK __BITS(18, 16) 66 #define GPIO_PIN_INPUT_ENABLE __BIT(9) 67 #define GPIO_PIN_FUNC_MASK __BITS(6, 5) 68 #define GPIO_PIN_MODE_MASK __BITS(3, 1) 69 #define GPIO_PIN_MODE_INPUT __SHIFTIN(0, GPIO_PIN_MODE_MASK); 70 #define GPIO_PIN_MODE_OUTPUT __SHIFTIN(1, GPIO_PIN_MODE_MASK); 71 #define GPIO_PIN_MODE_IRQ_HI __SHIFTIN(2, GPIO_PIN_MODE_MASK); 72 #define GPIO_PIN_MODE_IRQ_LO __SHIFTIN(3, GPIO_PIN_MODE_MASK); 73 #define GPIO_PIN_MODE_IRQ_UP __SHIFTIN(4, GPIO_PIN_MODE_MASK); 74 #define GPIO_PIN_MODE_IRQ_DN __SHIFTIN(5, GPIO_PIN_MODE_MASK); 75 #define GPIO_PIN_MODE_IRQ_ANY __SHIFTIN(6, GPIO_PIN_MODE_MASK); 76 #define GPIO_PIN_MODE_IRQ_OFF __SHIFTIN(7, GPIO_PIN_MODE_MASK); 77 #define GPIO_PIN_DATA __BIT(0) 78 #define GPIO_IRQ(grp, pin) (0x800 + (grp) * 64 + ((pin) >> 5) * 4) 79 80 #define PINCTRL_READ(sc, reg) \ 81 (bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))) 82 #define PINCTRL_WRITE(sc, reg, val) \ 83 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 84 #define PINCTRL_SET(sc, reg, bits) \ 85 PINCTRL_WRITE((sc), (reg), PINCTRL_READ((sc), (reg)) | (bits)) 86 #define PINCTRL_CLR(sc, reg, bits) \ 87 PINCTRL_WRITE((sc), (reg), PINCTRL_READ((sc), (reg)) & ~(bits)) 88 89 90 struct apple_pinctrl_softc { 91 device_t sc_dev; 92 int sc_phandle; 93 bus_space_tag_t sc_bst; 94 bus_space_handle_t sc_bsh; 95 u_int sc_npins; 96 }; 97 98 struct apple_gpio_pin { 99 int pin_no; 100 u_int pin_flags; 101 bool pin_actlo; 102 }; 103 104 static const struct device_compatible_entry compat_data[] = { 105 { .compat = "apple,pinctrl" }, 106 DEVICE_COMPAT_EOL 107 }; 108 109 static void 110 apple_gpio_pin_ctl(void *cookie, int pin, int flags) 111 { 112 struct apple_pinctrl_softc * const sc = cookie; 113 114 KASSERT(pin < sc->sc_npins); 115 116 uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pin)); 117 reg &= ~GPIO_PIN_FUNC_MASK; 118 reg &= ~GPIO_PIN_MODE_MASK; 119 120 if (flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) { 121 if (flags & GPIO_PIN_INPUT) { 122 /* for safety INPUT will override output */ 123 reg |= GPIO_PIN_MODE_INPUT; 124 } else { 125 reg |= GPIO_PIN_MODE_OUTPUT; 126 } 127 } 128 PINCTRL_WRITE(sc, GPIO_PIN(pin), reg); 129 } 130 131 static void * 132 apple_pinctrl_gpio_acquire(device_t dev, const void *data, size_t len, int flags) 133 { 134 struct apple_pinctrl_softc * const sc = device_private(dev); 135 struct apple_gpio_pin *pin; 136 const u_int *gpio = data; 137 138 if (len != 12) 139 return NULL; 140 141 const u_int pinno = be32toh(gpio[1]); 142 const bool actlo = be32toh(gpio[2]) & 1; 143 144 if (pinno >= sc->sc_npins) 145 return NULL; 146 147 pin = kmem_alloc(sizeof(*pin), KM_SLEEP); 148 pin->pin_no = pinno; 149 pin->pin_flags = flags; 150 pin->pin_actlo = actlo; 151 152 apple_gpio_pin_ctl(sc, pin->pin_no, pin->pin_flags); 153 154 return pin; 155 } 156 157 static void 158 apple_pinctrl_gpio_release(device_t dev, void *priv) 159 { 160 struct apple_pinctrl_softc * const sc = device_private(dev); 161 struct apple_gpio_pin *pin = priv; 162 163 apple_gpio_pin_ctl(sc, pin->pin_no, GPIO_PIN_INPUT); 164 kmem_free(pin, sizeof(*pin)); 165 } 166 167 static int 168 apple_pinctrl_gpio_read(device_t dev, void *priv, bool raw) 169 { 170 struct apple_pinctrl_softc * const sc = device_private(dev); 171 struct apple_gpio_pin *pin = priv; 172 173 KASSERT(pin->pin_no < sc->sc_npins); 174 175 uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pin->pin_no)); 176 int val = __SHIFTOUT(reg, GPIO_PIN_DATA); 177 if (!raw && pin->pin_actlo) 178 val = !val; 179 180 return val; 181 } 182 183 static void 184 apple_pinctrl_gpio_write(device_t dev, void *priv, int val, bool raw) 185 { 186 struct apple_pinctrl_softc * const sc = device_private(dev); 187 struct apple_gpio_pin *pin = priv; 188 189 KASSERT(pin->pin_no < sc->sc_npins); 190 191 if (!raw && pin->pin_actlo) 192 val = !val; 193 194 if (val) 195 PINCTRL_SET(sc, GPIO_PIN(pin->pin_no), GPIO_PIN_DATA); 196 else 197 PINCTRL_CLR(sc, GPIO_PIN(pin->pin_no), GPIO_PIN_DATA); 198 } 199 200 static int 201 apple_pinctrl_set_config(device_t dev, const void *data, size_t len) 202 { 203 struct apple_pinctrl_softc * const sc = device_private(dev); 204 205 if (len != 4) 206 return -1; 207 208 int pins_len; 209 const int phandle = fdtbus_get_phandle_from_native(be32dec(data)); 210 const u_int *pins = fdtbus_get_prop(phandle, "pinmux", &pins_len); 211 212 if (pins == NULL) 213 return -1; 214 215 const u_int npins = pins_len / sizeof(uint32_t); 216 217 for (u_int i = 0; i < npins; i++) { 218 uint32_t pinmux = be32dec(&pins[i]); 219 u_int pinno = APPLE_PIN(pinmux); 220 u_int func = APPLE_FUNC(pinmux); 221 222 uint32_t reg = PINCTRL_READ(sc, GPIO_PIN(pinno)); 223 reg &= ~GPIO_PIN_FUNC_MASK; 224 reg |= __SHIFTIN(func, GPIO_PIN_FUNC_MASK); 225 226 PINCTRL_WRITE(sc, GPIO_PIN(pinno), reg); 227 } 228 229 return 0; 230 } 231 232 static struct fdtbus_gpio_controller_func apple_pinctrl_gpio_funcs = { 233 .acquire = apple_pinctrl_gpio_acquire, 234 .release = apple_pinctrl_gpio_release, 235 .read = apple_pinctrl_gpio_read, 236 .write = apple_pinctrl_gpio_write 237 }; 238 239 static struct fdtbus_pinctrl_controller_func apple_pinctrl_funcs = { 240 .set_config = apple_pinctrl_set_config, 241 }; 242 243 static int 244 apple_pinctrl_match(device_t parent, cfdata_t cf, void *aux) 245 { 246 struct fdt_attach_args * const faa = aux; 247 248 return of_compatible_match(faa->faa_phandle, compat_data); 249 } 250 251 static void 252 apple_pinctrl_attach(device_t parent, device_t self, void *aux) 253 { 254 struct apple_pinctrl_softc * const sc = device_private(self); 255 struct fdt_attach_args * const faa = aux; 256 const int phandle = faa->faa_phandle; 257 bus_addr_t addr; 258 bus_size_t size; 259 260 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 261 aprint_error(": couldn't get registers\n"); 262 return; 263 } 264 265 sc->sc_dev = self; 266 sc->sc_bst = faa->faa_bst; 267 268 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 269 aprint_error(": couldn't map registers\n"); 270 return; 271 } 272 273 if (of_getprop_uint32(phandle, "apple,npins", &sc->sc_npins)) { 274 aprint_error(": couldn't get number of pins\n"); 275 return; 276 } 277 278 if (!of_hasprop(phandle, "gpio-controller")) { 279 aprint_error(": no gpio controller"); 280 return; 281 } 282 283 aprint_naive("\n"); 284 aprint_normal(": Apple Pinctrl\n"); 285 286 fdtbus_register_gpio_controller(self, phandle, &apple_pinctrl_gpio_funcs); 287 288 for (int child = OF_child(phandle); child; child = OF_peer(child)) { 289 if (!of_hasprop(child, "pinmux")) 290 continue; 291 fdtbus_register_pinctrl_config(self, child, 292 &apple_pinctrl_funcs); 293 294 } 295 } 296 297 CFATTACH_DECL_NEW(apple_pinctrl, sizeof(struct apple_pinctrl_softc), 298 apple_pinctrl_match, apple_pinctrl_attach, NULL, NULL); 299 300