1 /* $OpenBSD: pinctrl.c,v 1.4 2021/02/01 14:30:01 jsg Exp $ */ 2 /* 3 * Copyright (c) 2018, 2019 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/malloc.h> 22 23 #include <machine/intr.h> 24 #include <machine/bus.h> 25 #include <machine/fdt.h> 26 27 #include <dev/ofw/openfirm.h> 28 #include <dev/ofw/ofw_misc.h> 29 #include <dev/ofw/ofw_pinctrl.h> 30 #include <dev/ofw/fdt.h> 31 32 #define HREAD2(sc, reg) \ 33 (bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg))) 34 #define HWRITE2(sc, reg, val) \ 35 bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 36 #define HREAD4(sc, reg) \ 37 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 38 #define HWRITE4(sc, reg, val) \ 39 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 40 41 struct pinctrl_softc { 42 struct device sc_dev; 43 bus_space_tag_t sc_iot; 44 bus_space_handle_t sc_ioh; 45 46 uint32_t sc_reg_width; 47 uint32_t sc_func_mask; 48 uint32_t sc_ncells; 49 }; 50 51 int pinctrl_match(struct device *, void *, void *); 52 void pinctrl_attach(struct device *, struct device *, void *); 53 54 struct cfattach pinctrl_ca = { 55 sizeof (struct pinctrl_softc), pinctrl_match, pinctrl_attach 56 }; 57 58 struct cfdriver pinctrl_cd = { 59 NULL, "pinctrl", DV_DULL 60 }; 61 62 int pinctrl_pinctrl(uint32_t, void *); 63 64 int 65 pinctrl_match(struct device *parent, void *match, void *aux) 66 { 67 struct fdt_attach_args *faa = aux; 68 69 return (OF_is_compatible(faa->fa_node, "pinctrl-single") || 70 OF_is_compatible(faa->fa_node, "pinconf-single")); 71 } 72 73 void 74 pinctrl_attach(struct device *parent, struct device *self, void *aux) 75 { 76 struct pinctrl_softc *sc = (struct pinctrl_softc *)self; 77 struct fdt_attach_args *faa = aux; 78 79 if (faa->fa_nreg < 1) { 80 printf(": no registers\n"); 81 return; 82 } 83 84 sc->sc_reg_width = OF_getpropint(faa->fa_node, 85 "pinctrl-single,register-width", 0); 86 if (sc->sc_reg_width != 16 && 87 sc->sc_reg_width != 32) { 88 printf(": unsupported register width\n"); 89 return; 90 } 91 92 sc->sc_ncells = OF_getpropint(faa->fa_node, "#pinctrl-cells", 1); 93 sc->sc_func_mask = OF_getpropint(faa->fa_node, 94 "pinctrl-single,function-mask", 0); 95 96 sc->sc_iot = faa->fa_iot; 97 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 98 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 99 printf(": can't map registers\n"); 100 return; 101 } 102 103 pinctrl_register(faa->fa_node, pinctrl_pinctrl, sc); 104 105 printf("\n"); 106 } 107 108 uint32_t 109 pinctrl_set2(int node, char *setting, uint32_t val) 110 { 111 uint32_t values[2]; 112 113 if (OF_getpropintarray(node, setting, values, sizeof(values)) != 114 sizeof(values)) 115 return val; 116 117 val &= ~values[1]; 118 val |= (values[0] & values[1]); 119 return val; 120 } 121 122 uint32_t 123 pinctrl_set4(int node, char *setting, uint32_t val) 124 { 125 uint32_t values[4]; 126 127 if (OF_getpropintarray(node, setting, values, sizeof(values)) != 128 sizeof(values)) 129 return val; 130 131 val &= ~values[3]; 132 val |= (values[0] & values[3]); 133 return val; 134 } 135 136 int 137 pinctrl_pinctrl(uint32_t phandle, void *cookie) 138 { 139 struct pinctrl_softc *sc = cookie; 140 uint32_t *pins; 141 int node, len, i; 142 143 node = OF_getnodebyphandle(phandle); 144 if (node == 0) 145 return -1; 146 147 len = OF_getproplen(node, "pinctrl-single,pins"); 148 if (len <= 0) 149 return -1; 150 151 pins = malloc(len, M_TEMP, M_WAITOK); 152 OF_getpropintarray(node, "pinctrl-single,pins", pins, len); 153 154 for (i = 0; i < len / sizeof(uint32_t); i += (1 + sc->sc_ncells)) { 155 uint32_t reg = pins[i]; 156 uint32_t func = pins[i + 1]; 157 uint32_t val = 0; 158 159 if (sc->sc_ncells == 2) 160 func |= pins[i + 2]; 161 162 if (sc->sc_reg_width == 16) 163 val = HREAD2(sc, reg); 164 else if (sc->sc_reg_width == 32) 165 val = HREAD4(sc, reg); 166 167 val &= ~sc->sc_func_mask; 168 val |= (func & sc->sc_func_mask); 169 170 val = pinctrl_set2(node, "pinctrl-single,drive-strength", val); 171 val = pinctrl_set4(node, "pinctrl-single,bias-pulldown", val); 172 val = pinctrl_set4(node, "pinctrl-single,bias-pullup", val); 173 174 if (sc->sc_reg_width == 16) 175 HWRITE2(sc, reg, val); 176 else if (sc->sc_reg_width == 32) 177 HWRITE4(sc, reg, val); 178 } 179 180 free(pins, M_TEMP, len); 181 return 0; 182 } 183