1 /* $OpenBSD: mvpinctrl.c,v 1.6 2019/04/30 20:06:32 patrick Exp $ */ 2 /* 3 * Copyright (c) 2013,2016 Patrick Wildt <patrick@blueri.se> 4 * Copyright (c) 2016 Mark Kettenis <kettenis@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 #include <sys/malloc.h> 23 24 #include <machine/intr.h> 25 #include <machine/bus.h> 26 #include <machine/fdt.h> 27 28 #include <dev/ofw/openfirm.h> 29 #include <dev/ofw/ofw_gpio.h> 30 #include <dev/ofw/ofw_misc.h> 31 #include <dev/ofw/ofw_pinctrl.h> 32 #include <dev/ofw/fdt.h> 33 34 /* Armada 3700 Registers */ 35 #define GPIO_DIRECTION 0x00 36 #define GPIO_INPUT 0x10 37 #define GPIO_OUTPUT 0x18 38 39 #define HREAD4(sc, reg) \ 40 (regmap_read_4((sc)->sc_rm, (reg))) 41 #define HWRITE4(sc, reg, val) \ 42 regmap_write_4((sc)->sc_rm, (reg), (val)) 43 #define HSET4(sc, reg, bits) \ 44 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 45 #define HCLR4(sc, reg, bits) \ 46 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 47 48 struct mvpinctrl_pin { 49 char *pin; 50 char *function; 51 int value; 52 int pid; 53 }; 54 55 struct mvpinctrl_softc { 56 struct device sc_dev; 57 bus_space_tag_t sc_iot; 58 bus_space_handle_t sc_ioh; 59 struct regmap *sc_rm; 60 struct mvpinctrl_pin *sc_pins; 61 int sc_npins; 62 struct gpio_controller sc_gc; 63 }; 64 65 int mvpinctrl_match(struct device *, void *, void *); 66 void mvpinctrl_attach(struct device *, struct device *, void *); 67 int mvpinctrl_pinctrl(uint32_t, void *); 68 69 void mvpinctrl_config_pin(void *, uint32_t *, int); 70 int mvpinctrl_get_pin(void *, uint32_t *); 71 void mvpinctrl_set_pin(void *, uint32_t *, int); 72 73 struct cfattach mvpinctrl_ca = { 74 sizeof (struct mvpinctrl_softc), mvpinctrl_match, mvpinctrl_attach 75 }; 76 77 struct cfdriver mvpinctrl_cd = { 78 NULL, "mvpinctrl", DV_DULL 79 }; 80 81 #define STR_HELPER(x) #x 82 #define STR(x) STR_HELPER(x) 83 #define MPP(id, func, val) { STR(mpp ## id), func, val, id } 84 85 #include "mvpinctrl_pins.h" 86 87 struct mvpinctrl_pins { 88 const char *compat; 89 struct mvpinctrl_pin *pins; 90 int npins; 91 }; 92 93 struct mvpinctrl_pins mvpinctrl_pins[] = { 94 { 95 "marvell,mv88f6810-pinctrl", 96 armada_38x_pins, nitems(armada_38x_pins) 97 }, 98 { 99 "marvell,mv88f6820-pinctrl", 100 armada_38x_pins, nitems(armada_38x_pins) 101 }, 102 { 103 "marvell,mv88f6828-pinctrl", 104 armada_38x_pins, nitems(armada_38x_pins) 105 }, 106 { 107 "marvell,ap806-pinctrl", 108 armada_ap806_pins, nitems(armada_ap806_pins) 109 }, 110 { 111 "marvell,cp110-pinctrl", 112 armada_cp110_pins, nitems(armada_cp110_pins) 113 }, 114 { 115 "marvell,armada-7k-pinctrl", 116 armada_cp110_pins, nitems(armada_cp110_pins) 117 }, 118 { 119 "marvell,armada-8k-cpm-pinctrl", 120 armada_cp110_pins, nitems(armada_cp110_pins) 121 }, 122 { 123 "marvell,armada-8k-cps-pinctrl", 124 armada_cp110_pins, nitems(armada_cp110_pins) 125 }, 126 }; 127 128 int 129 mvpinctrl_match(struct device *parent, void *match, void *aux) 130 { 131 struct fdt_attach_args *faa = aux; 132 int i; 133 134 for (i = 0; i < nitems(mvpinctrl_pins); i++) { 135 if (OF_is_compatible(faa->fa_node, mvpinctrl_pins[i].compat)) 136 return 10; 137 } 138 139 if (OF_is_compatible(faa->fa_node, "marvell,armada3710-sb-pinctrl")) 140 return 10; 141 142 return 0; 143 } 144 145 void 146 mvpinctrl_attach(struct device *parent, struct device *self, void *aux) 147 { 148 struct mvpinctrl_softc *sc = (struct mvpinctrl_softc *)self; 149 struct fdt_attach_args *faa = aux; 150 int i, node; 151 152 if (faa->fa_nreg > 0) { 153 sc->sc_iot = faa->fa_iot; 154 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 155 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 156 printf(": can't map registers\n"); 157 return; 158 } 159 160 regmap_register(faa->fa_node, sc->sc_iot, sc->sc_ioh, 161 faa->fa_reg[0].size); 162 sc->sc_rm = regmap_bynode(faa->fa_node); 163 } else { 164 /* No registers; use regmap provided by parent. */ 165 sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node)); 166 } 167 168 if (sc->sc_rm == NULL) { 169 printf(": no registers\n"); 170 return; 171 } 172 173 printf("\n"); 174 175 if (OF_is_compatible(faa->fa_node, "marvell,armada3710-sb-pinctrl")) { 176 for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) { 177 if (OF_getproplen(node, "gpio-controller") == 0) 178 break; 179 } 180 KASSERT(node != 0); 181 sc->sc_gc.gc_node = node; 182 sc->sc_gc.gc_cookie = sc; 183 sc->sc_gc.gc_config_pin = mvpinctrl_config_pin; 184 sc->sc_gc.gc_get_pin = mvpinctrl_get_pin; 185 sc->sc_gc.gc_set_pin = mvpinctrl_set_pin; 186 gpio_controller_register(&sc->sc_gc); 187 return; 188 } 189 190 for (i = 0; i < nitems(mvpinctrl_pins); i++) { 191 if (OF_is_compatible(faa->fa_node, mvpinctrl_pins[i].compat)) { 192 sc->sc_pins = mvpinctrl_pins[i].pins; 193 sc->sc_npins = mvpinctrl_pins[i].npins; 194 break; 195 } 196 } 197 198 KASSERT(sc->sc_pins); 199 pinctrl_register(faa->fa_node, mvpinctrl_pinctrl, sc); 200 } 201 202 int 203 mvpinctrl_pinctrl(uint32_t phandle, void *cookie) 204 { 205 struct mvpinctrl_softc *sc = cookie; 206 char *pins, *pin, *func; 207 int i, flen, plen, node; 208 209 node = OF_getnodebyphandle(phandle); 210 if (node == 0) 211 return -1; 212 213 flen = OF_getproplen(node, "marvell,function"); 214 if (flen <= 0) 215 return -1; 216 217 func = malloc(flen, M_TEMP, M_WAITOK); 218 OF_getprop(node, "marvell,function", func, flen); 219 220 plen = OF_getproplen(node, "marvell,pins"); 221 if (plen <= 0) 222 return -1; 223 224 pin = pins = malloc(plen, M_TEMP, M_WAITOK); 225 OF_getprop(node, "marvell,pins", pins, plen); 226 227 while (plen > 0) { 228 for (i = 0; i < sc->sc_npins; i++) { 229 uint32_t off, shift; 230 231 if (strcmp(sc->sc_pins[i].pin, pin)) 232 continue; 233 if (strcmp(sc->sc_pins[i].function, func)) 234 continue; 235 236 off = (sc->sc_pins[i].pid / 8) * sizeof(uint32_t); 237 shift = (sc->sc_pins[i].pid % 8) * 4; 238 239 HWRITE4(sc, off, (HREAD4(sc, off) & ~(0xf << shift)) | 240 (sc->sc_pins[i].value << shift)); 241 break; 242 } 243 244 if (i == sc->sc_npins) 245 printf("%s: unsupported pin %s function %s\n", 246 sc->sc_dev.dv_xname, pin, func); 247 248 plen -= strlen(pin) + 1; 249 pin += strlen(pin) + 1; 250 } 251 252 free(func, M_TEMP, flen); 253 free(pins, M_TEMP, plen); 254 return 0; 255 } 256 257 void 258 mvpinctrl_config_pin(void *cookie, uint32_t *cells, int config) 259 { 260 struct mvpinctrl_softc *sc = cookie; 261 uint32_t pin = cells[0]; 262 263 if (pin > 32) 264 return; 265 266 if (config & GPIO_CONFIG_OUTPUT) 267 HSET4(sc, GPIO_DIRECTION, (1 << pin)); 268 else 269 HCLR4(sc, GPIO_DIRECTION, (1 << pin)); 270 } 271 272 int 273 mvpinctrl_get_pin(void *cookie, uint32_t *cells) 274 { 275 struct mvpinctrl_softc *sc = cookie; 276 uint32_t pin = cells[0]; 277 uint32_t flags = cells[1]; 278 uint32_t reg; 279 int val; 280 281 if (pin > 32) 282 return 0; 283 284 reg = HREAD4(sc, GPIO_INPUT); 285 reg &= (1 << pin); 286 val = (reg >> pin) & 1; 287 if (flags & GPIO_ACTIVE_LOW) 288 val = !val; 289 return val; 290 } 291 292 void 293 mvpinctrl_set_pin(void *cookie, uint32_t *cells, int val) 294 { 295 struct mvpinctrl_softc *sc = cookie; 296 uint32_t pin = cells[0]; 297 uint32_t flags = cells[1]; 298 299 if (pin > 32) 300 return; 301 302 if (flags & GPIO_ACTIVE_LOW) 303 val = !val; 304 if (val) 305 HSET4(sc, GPIO_OUTPUT, (1 << pin)); 306 else 307 HCLR4(sc, GPIO_OUTPUT, (1 << pin)); 308 } 309