1 /* $OpenBSD: mvpinctrl.c,v 1.8 2021/05/07 01:54:17 jsg 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_clock.h> 30 #include <dev/ofw/ofw_gpio.h> 31 #include <dev/ofw/ofw_misc.h> 32 #include <dev/ofw/ofw_pinctrl.h> 33 #include <dev/ofw/fdt.h> 34 35 /* Armada 3700 Registers */ 36 #define GPIO_DIRECTION 0x00 37 #define GPIO_INPUT 0x10 38 #define GPIO_OUTPUT 0x18 39 40 #define HREAD4(sc, reg) \ 41 (regmap_read_4((sc)->sc_rm, (reg))) 42 #define HWRITE4(sc, reg, val) \ 43 regmap_write_4((sc)->sc_rm, (reg), (val)) 44 #define HSET4(sc, reg, bits) \ 45 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 46 #define HCLR4(sc, reg, bits) \ 47 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 48 49 struct mvpinctrl_pin { 50 char *pin; 51 char *function; 52 int value; 53 int pid; 54 }; 55 56 struct mvpinctrl_softc { 57 struct device sc_dev; 58 bus_space_tag_t sc_iot; 59 bus_space_handle_t sc_ioh; 60 struct regmap *sc_rm; 61 struct mvpinctrl_pin *sc_pins; 62 int sc_npins; 63 struct gpio_controller sc_gc; 64 struct clock_device sc_cd_xtal; 65 }; 66 67 int mvpinctrl_match(struct device *, void *, void *); 68 void mvpinctrl_attach(struct device *, struct device *, void *); 69 int mvpinctrl_pinctrl(uint32_t, void *); 70 71 void mvpinctrl_config_pin(void *, uint32_t *, int); 72 int mvpinctrl_get_pin(void *, uint32_t *); 73 void mvpinctrl_set_pin(void *, uint32_t *, int); 74 75 uint32_t a3700_xtal_get_frequency(void *, uint32_t *); 76 77 struct cfattach mvpinctrl_ca = { 78 sizeof (struct mvpinctrl_softc), mvpinctrl_match, mvpinctrl_attach 79 }; 80 81 struct cfdriver mvpinctrl_cd = { 82 NULL, "mvpinctrl", DV_DULL 83 }; 84 85 #define STR_HELPER(x) #x 86 #define STR(x) STR_HELPER(x) 87 #define MPP(id, func, val) { STR(mpp ## id), func, val, id } 88 89 #include "mvpinctrl_pins.h" 90 91 struct mvpinctrl_pins { 92 const char *compat; 93 struct mvpinctrl_pin *pins; 94 int npins; 95 }; 96 97 struct mvpinctrl_pins mvpinctrl_pins[] = { 98 { 99 "marvell,mv88f6810-pinctrl", 100 armada_38x_pins, nitems(armada_38x_pins) 101 }, 102 { 103 "marvell,mv88f6820-pinctrl", 104 armada_38x_pins, nitems(armada_38x_pins) 105 }, 106 { 107 "marvell,mv88f6828-pinctrl", 108 armada_38x_pins, nitems(armada_38x_pins) 109 }, 110 { 111 "marvell,ap806-pinctrl", 112 armada_ap806_pins, nitems(armada_ap806_pins) 113 }, 114 { 115 "marvell,cp110-pinctrl", 116 armada_cp110_pins, nitems(armada_cp110_pins) 117 }, 118 { 119 "marvell,armada-7k-pinctrl", 120 armada_cp110_pins, nitems(armada_cp110_pins) 121 }, 122 { 123 "marvell,armada-8k-cpm-pinctrl", 124 armada_cp110_pins, nitems(armada_cp110_pins) 125 }, 126 { 127 "marvell,armada-8k-cps-pinctrl", 128 armada_cp110_pins, nitems(armada_cp110_pins) 129 }, 130 }; 131 132 int 133 mvpinctrl_match(struct device *parent, void *match, void *aux) 134 { 135 struct fdt_attach_args *faa = aux; 136 int i; 137 138 for (i = 0; i < nitems(mvpinctrl_pins); i++) { 139 if (OF_is_compatible(faa->fa_node, mvpinctrl_pins[i].compat)) 140 return 10; 141 } 142 143 if (OF_is_compatible(faa->fa_node, "marvell,armada3710-nb-pinctrl") || 144 OF_is_compatible(faa->fa_node, "marvell,armada3710-sb-pinctrl")) 145 return 10; 146 147 return 0; 148 } 149 150 void 151 mvpinctrl_attach(struct device *parent, struct device *self, void *aux) 152 { 153 struct mvpinctrl_softc *sc = (struct mvpinctrl_softc *)self; 154 struct fdt_attach_args *faa = aux; 155 int i, node; 156 157 if (faa->fa_nreg > 0) { 158 sc->sc_iot = faa->fa_iot; 159 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 160 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 161 printf(": can't map registers\n"); 162 return; 163 } 164 165 regmap_register(faa->fa_node, sc->sc_iot, sc->sc_ioh, 166 faa->fa_reg[0].size); 167 sc->sc_rm = regmap_bynode(faa->fa_node); 168 } else { 169 /* No registers; use regmap provided by parent. */ 170 sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node)); 171 } 172 173 if (sc->sc_rm == NULL) { 174 printf(": no registers\n"); 175 return; 176 } 177 178 printf("\n"); 179 180 if (OF_is_compatible(faa->fa_node, "marvell,armada3710-nb-pinctrl")) { 181 for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) { 182 if (OF_is_compatible(node, "marvell,armada-3700-xtal-clock")) 183 break; 184 } 185 KASSERT(node != 0); 186 sc->sc_cd_xtal.cd_node = node; 187 sc->sc_cd_xtal.cd_cookie = sc; 188 sc->sc_cd_xtal.cd_get_frequency = a3700_xtal_get_frequency; 189 clock_register(&sc->sc_cd_xtal); 190 } 191 192 if (OF_is_compatible(faa->fa_node, "marvell,armada3710-nb-pinctrl") || 193 OF_is_compatible(faa->fa_node, "marvell,armada3710-sb-pinctrl")) { 194 for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) { 195 if (OF_getproplen(node, "gpio-controller") == 0) 196 break; 197 } 198 KASSERT(node != 0); 199 sc->sc_gc.gc_node = node; 200 sc->sc_gc.gc_cookie = sc; 201 sc->sc_gc.gc_config_pin = mvpinctrl_config_pin; 202 sc->sc_gc.gc_get_pin = mvpinctrl_get_pin; 203 sc->sc_gc.gc_set_pin = mvpinctrl_set_pin; 204 gpio_controller_register(&sc->sc_gc); 205 return; 206 } 207 208 for (i = 0; i < nitems(mvpinctrl_pins); i++) { 209 if (OF_is_compatible(faa->fa_node, mvpinctrl_pins[i].compat)) { 210 sc->sc_pins = mvpinctrl_pins[i].pins; 211 sc->sc_npins = mvpinctrl_pins[i].npins; 212 break; 213 } 214 } 215 216 KASSERT(sc->sc_pins); 217 pinctrl_register(faa->fa_node, mvpinctrl_pinctrl, sc); 218 } 219 220 int 221 mvpinctrl_pinctrl(uint32_t phandle, void *cookie) 222 { 223 struct mvpinctrl_softc *sc = cookie; 224 char *pins, *pin, *func; 225 int i, flen, plen, node; 226 227 node = OF_getnodebyphandle(phandle); 228 if (node == 0) 229 return -1; 230 231 flen = OF_getproplen(node, "marvell,function"); 232 if (flen <= 0) 233 return -1; 234 235 func = malloc(flen, M_TEMP, M_WAITOK); 236 OF_getprop(node, "marvell,function", func, flen); 237 238 plen = OF_getproplen(node, "marvell,pins"); 239 if (plen <= 0) 240 return -1; 241 242 pin = pins = malloc(plen, M_TEMP, M_WAITOK); 243 OF_getprop(node, "marvell,pins", pins, plen); 244 245 while (plen > 0) { 246 for (i = 0; i < sc->sc_npins; i++) { 247 uint32_t off, shift; 248 249 if (strcmp(sc->sc_pins[i].pin, pin)) 250 continue; 251 if (strcmp(sc->sc_pins[i].function, func)) 252 continue; 253 254 off = (sc->sc_pins[i].pid / 8) * sizeof(uint32_t); 255 shift = (sc->sc_pins[i].pid % 8) * 4; 256 257 HWRITE4(sc, off, (HREAD4(sc, off) & ~(0xf << shift)) | 258 (sc->sc_pins[i].value << shift)); 259 break; 260 } 261 262 if (i == sc->sc_npins) 263 printf("%s: unsupported pin %s function %s\n", 264 sc->sc_dev.dv_xname, pin, func); 265 266 plen -= strlen(pin) + 1; 267 pin += strlen(pin) + 1; 268 } 269 270 free(func, M_TEMP, flen); 271 free(pins, M_TEMP, plen); 272 return 0; 273 } 274 275 void 276 mvpinctrl_config_pin(void *cookie, uint32_t *cells, int config) 277 { 278 struct mvpinctrl_softc *sc = cookie; 279 uint32_t pin = cells[0]; 280 281 if (pin >= 32) 282 return; 283 284 if (config & GPIO_CONFIG_OUTPUT) 285 HSET4(sc, GPIO_DIRECTION, (1 << pin)); 286 else 287 HCLR4(sc, GPIO_DIRECTION, (1 << pin)); 288 } 289 290 int 291 mvpinctrl_get_pin(void *cookie, uint32_t *cells) 292 { 293 struct mvpinctrl_softc *sc = cookie; 294 uint32_t pin = cells[0]; 295 uint32_t flags = cells[1]; 296 uint32_t reg; 297 int val; 298 299 if (pin >= 32) 300 return 0; 301 302 reg = HREAD4(sc, GPIO_INPUT); 303 reg &= (1 << pin); 304 val = (reg >> pin) & 1; 305 if (flags & GPIO_ACTIVE_LOW) 306 val = !val; 307 return val; 308 } 309 310 void 311 mvpinctrl_set_pin(void *cookie, uint32_t *cells, int val) 312 { 313 struct mvpinctrl_softc *sc = cookie; 314 uint32_t pin = cells[0]; 315 uint32_t flags = cells[1]; 316 317 if (pin >= 32) 318 return; 319 320 if (flags & GPIO_ACTIVE_LOW) 321 val = !val; 322 if (val) 323 HSET4(sc, GPIO_OUTPUT, (1 << pin)); 324 else 325 HCLR4(sc, GPIO_OUTPUT, (1 << pin)); 326 } 327 328 /* Armada 3700 XTAL block */ 329 330 #define XTAL 0xc 331 #define XTAL_MODE (1 << 31) 332 333 uint32_t 334 a3700_xtal_get_frequency(void *cookie, uint32_t *cells) 335 { 336 struct mvpinctrl_softc *sc = cookie; 337 338 if (regmap_read_4(sc->sc_rm, XTAL) & XTAL_MODE) 339 return 40000000; 340 else 341 return 25000000; 342 } 343