1 /* $OpenBSD: mvpinctrl.c,v 1.4 2018/03/21 09:17:21 kettenis 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_misc.h> 30 #include <dev/ofw/ofw_pinctrl.h> 31 #include <dev/ofw/fdt.h> 32 33 #define HREAD4(sc, reg) \ 34 (regmap_read_4((sc)->sc_rm, (reg))) 35 #define HWRITE4(sc, reg, val) \ 36 regmap_write_4((sc)->sc_rm, (reg), (val)) 37 38 struct mvpinctrl_pin { 39 char *pin; 40 char *function; 41 int value; 42 int pid; 43 }; 44 45 struct mvpinctrl_softc { 46 struct device sc_dev; 47 bus_space_tag_t sc_iot; 48 bus_space_handle_t sc_ioh; 49 struct regmap *sc_rm; 50 struct mvpinctrl_pin *sc_pins; 51 int sc_npins; 52 }; 53 54 int mvpinctrl_match(struct device *, void *, void *); 55 void mvpinctrl_attach(struct device *, struct device *, void *); 56 int mvpinctrl_pinctrl(uint32_t, void *); 57 58 struct cfattach mvpinctrl_ca = { 59 sizeof (struct mvpinctrl_softc), mvpinctrl_match, mvpinctrl_attach 60 }; 61 62 struct cfdriver mvpinctrl_cd = { 63 NULL, "mvpinctrl", DV_DULL 64 }; 65 66 #define STR_HELPER(x) #x 67 #define STR(x) STR_HELPER(x) 68 #define MPP(id, func, val) { STR(mpp ## id), func, val, id } 69 70 #include "mvpinctrl_pins.h" 71 72 struct mvpinctrl_pins { 73 const char *compat; 74 struct mvpinctrl_pin *pins; 75 int npins; 76 }; 77 78 struct mvpinctrl_pins mvpinctrl_pins[] = { 79 { 80 "marvell,mv88f6810-pinctrl", 81 armada_38x_pins, nitems(armada_38x_pins) 82 }, 83 { 84 "marvell,mv88f6820-pinctrl", 85 armada_38x_pins, nitems(armada_38x_pins) 86 }, 87 { 88 "marvell,mv88f6828-pinctrl", 89 armada_38x_pins, nitems(armada_38x_pins) 90 }, 91 { 92 "marvell,ap806-pinctrl", 93 armada_ap806_pins, nitems(armada_ap806_pins) 94 }, 95 { 96 "marvell,cp110-pinctrl", 97 armada_cp110_pins, nitems(armada_cp110_pins) 98 }, 99 }; 100 101 int 102 mvpinctrl_match(struct device *parent, void *match, void *aux) 103 { 104 struct fdt_attach_args *faa = aux; 105 int i; 106 107 for (i = 0; i < nitems(mvpinctrl_pins); i++) { 108 if (OF_is_compatible(faa->fa_node, mvpinctrl_pins[i].compat)) 109 return 1; 110 } 111 112 return 0; 113 } 114 115 void 116 mvpinctrl_attach(struct device *parent, struct device *self, void *aux) 117 { 118 struct mvpinctrl_softc *sc = (struct mvpinctrl_softc *)self; 119 struct fdt_attach_args *faa = aux; 120 int i; 121 122 if (faa->fa_nreg > 0) { 123 sc->sc_iot = faa->fa_iot; 124 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 125 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 126 printf(": can't map registers\n"); 127 return; 128 } 129 130 regmap_register(faa->fa_node, sc->sc_iot, sc->sc_ioh, 131 faa->fa_reg[0].size); 132 sc->sc_rm = regmap_bynode(faa->fa_node); 133 } else { 134 /* No registers; use regmap provided by parent. */ 135 sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node)); 136 } 137 138 if (sc->sc_rm == NULL) { 139 printf(": no registers\n"); 140 return; 141 } 142 143 printf("\n"); 144 145 for (i = 0; i < nitems(mvpinctrl_pins); i++) { 146 if (OF_is_compatible(faa->fa_node, mvpinctrl_pins[i].compat)) { 147 sc->sc_pins = mvpinctrl_pins[i].pins; 148 sc->sc_npins = mvpinctrl_pins[i].npins; 149 break; 150 } 151 } 152 153 KASSERT(sc->sc_pins); 154 pinctrl_register(faa->fa_node, mvpinctrl_pinctrl, sc); 155 } 156 157 int 158 mvpinctrl_pinctrl(uint32_t phandle, void *cookie) 159 { 160 struct mvpinctrl_softc *sc = cookie; 161 char *pins, *pin, *func; 162 int i, flen, plen, node; 163 164 node = OF_getnodebyphandle(phandle); 165 if (node == 0) 166 return -1; 167 168 flen = OF_getproplen(node, "marvell,function"); 169 if (flen <= 0) 170 return -1; 171 172 func = malloc(flen, M_TEMP, M_WAITOK); 173 OF_getprop(node, "marvell,function", func, flen); 174 175 plen = OF_getproplen(node, "marvell,pins"); 176 if (plen <= 0) 177 return -1; 178 179 pin = pins = malloc(plen, M_TEMP, M_WAITOK); 180 OF_getprop(node, "marvell,pins", pins, plen); 181 182 while (plen > 0) { 183 for (i = 0; i < sc->sc_npins; i++) { 184 uint32_t off, shift; 185 186 if (strcmp(sc->sc_pins[i].pin, pin)) 187 continue; 188 if (strcmp(sc->sc_pins[i].function, func)) 189 continue; 190 191 off = (sc->sc_pins[i].pid / 8) * sizeof(uint32_t); 192 shift = (sc->sc_pins[i].pid % 8) * 4; 193 194 HWRITE4(sc, off, (HREAD4(sc, off) & ~(0xf << shift)) | 195 (sc->sc_pins[i].value << shift)); 196 break; 197 } 198 199 if (i == sc->sc_npins) 200 printf("%s: unsupported pin %s function %s\n", 201 sc->sc_dev.dv_xname, pin, func); 202 203 plen -= strlen(pin) + 1; 204 pin += strlen(pin) + 1; 205 } 206 207 free(func, M_TEMP, flen); 208 free(pins, M_TEMP, plen); 209 return 0; 210 } 211