1 /* $OpenBSD: stfpinctrl.c,v 1.3 2023/07/05 11:07:37 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2022 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 #include <sys/evcount.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/fdt.h> 32 33 /* Registers. */ 34 35 #define GPIODIN(pin) (0x0048 + (((pin) / 32) * 4)) 36 #define GPIO_DOUT_CFG(pin) (0x0050 + ((pin) * 8)) 37 #define GPIO_DOEN_CFG(pin) (0x0054 + ((pin) * 8)) 38 #define GPO_ENABLE 0 39 #define GPO_DISABLE 1 40 41 #define PAD_GPIO(pin) (0x0000 + (((pin) / 2) * 4)) 42 #define PAD_INPUT_ENABLE (1 << 7) 43 #define PAD_INPUT_SCHMITT_ENABLE (1 << 6) 44 #define PAD_SHIFT(pin) ((pin % 2) * 16) 45 #define PAD_FUNC_SHARE(pin) (0x0080 + (((pin) / 2) * 4)) 46 #define IO_PADSHARE_SEL 0x01a0 47 48 #define JH7110_DOEN(pin) (0x0000 + (((pin) / 4) * 4)) 49 #define JH7110_DOEN_SHIFT(pin) (((pin) % 4) * 8) 50 #define JH7110_DOEN_MASK 0x3f 51 #define JH7110_DOEN_ENABLE 0 52 #define JH7110_DOEN_DISABLE 1 53 #define JH7110_DOUT(pin) (0x0040 + (((pin) / 4) * 4)) 54 #define JH7110_DOUT_SHIFT(pin) (((pin) % 4) * 8) 55 #define JH7110_DOUT_MASK 0x7f 56 #define JH7110_GPIOIN(pin) (0x0118 + (((pin) / 32) * 4)) 57 #define JH7110_PADCFG(pin) (0x0120 + ((pin) * 4)) 58 #define JH7110_PADCFG_IE (1 << 0) 59 #define JH7110_PADCFG_PU (1 << 3) 60 #define JH7110_PADCFG_PD (1 << 4) 61 #define JH7110_PADCFG_SMT (1 << 6) 62 63 #define GPIO_NUM_PINS 64 64 65 struct stfpinctrl_softc { 66 struct device sc_dev; 67 bus_space_tag_t sc_iot; 68 bus_space_handle_t sc_gpio_ioh; 69 bus_space_handle_t sc_padctl_ioh; 70 bus_size_t sc_padctl_gpio; 71 int sc_node; 72 73 struct gpio_controller sc_gc; 74 }; 75 76 int stfpinctrl_match(struct device *, void *, void *); 77 void stfpinctrl_attach(struct device *, struct device *, void *); 78 79 const struct cfattach stfpinctrl_ca = { 80 sizeof (struct stfpinctrl_softc), stfpinctrl_match, stfpinctrl_attach 81 }; 82 83 struct cfdriver stfpinctrl_cd = { 84 NULL, "stfpinctrl", DV_DULL 85 }; 86 87 void stfpinctrl_jh7100_config_pin(void *, uint32_t *, int); 88 int stfpinctrl_jh7100_get_pin(void *, uint32_t *); 89 void stfpinctrl_jh7100_set_pin(void *, uint32_t *, int); 90 91 void stfpinctrl_jh7110_config_pin(void *, uint32_t *, int); 92 int stfpinctrl_jh7110_get_pin(void *, uint32_t *); 93 void stfpinctrl_jh7110_set_pin(void *, uint32_t *, int); 94 95 int 96 stfpinctrl_match(struct device *parent, void *match, void *aux) 97 { 98 struct fdt_attach_args *faa = aux; 99 100 return OF_is_compatible(faa->fa_node, "starfive,jh7100-pinctrl") || 101 OF_is_compatible(faa->fa_node, "starfive,jh7110-sys-pinctrl"); 102 } 103 104 void 105 stfpinctrl_attach(struct device *parent, struct device *self, void *aux) 106 { 107 struct stfpinctrl_softc *sc = (struct stfpinctrl_softc *)self; 108 struct fdt_attach_args *faa = aux; 109 uint32_t sel; 110 111 if (faa->fa_nreg < 1) { 112 printf(": no registers\n"); 113 return; 114 } 115 116 if (OF_is_compatible(faa->fa_node, "starfive,jh7100-pinctrl") && 117 faa->fa_nreg < 2) { 118 printf(": no padctl registers\n"); 119 return; 120 } 121 122 sc->sc_node = faa->fa_node; 123 sc->sc_iot = faa->fa_iot; 124 125 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 126 faa->fa_reg[0].size, 0, &sc->sc_gpio_ioh)) { 127 printf(": can't map registers\n"); 128 return; 129 } 130 131 if (OF_is_compatible(faa->fa_node, "starfive,jh7100-pinctrl") && 132 bus_space_map(sc->sc_iot, faa->fa_reg[1].addr, 133 faa->fa_reg[1].size, 0, &sc->sc_padctl_ioh)) { 134 bus_space_unmap(sc->sc_iot, sc->sc_gpio_ioh, 135 faa->fa_reg[0].size); 136 printf(": can't map registers\n"); 137 return; 138 } 139 140 printf("\n"); 141 142 if (OF_is_compatible(faa->fa_node, "starfive,jh7100-pinctrl")) { 143 sel = bus_space_read_4(sc->sc_iot, sc->sc_padctl_ioh, 144 IO_PADSHARE_SEL); 145 switch (sel) { 146 case 0: 147 default: 148 /* No GPIOs available. */ 149 return; 150 case 1: 151 sc->sc_padctl_gpio = PAD_GPIO(0); 152 break; 153 case 2: 154 sc->sc_padctl_gpio = PAD_FUNC_SHARE(72); 155 break; 156 case 3: 157 sc->sc_padctl_gpio = PAD_FUNC_SHARE(70); 158 break; 159 case 4: 160 case 5: 161 case 6: 162 sc->sc_padctl_gpio = PAD_FUNC_SHARE(0); 163 break; 164 } 165 } else { 166 reset_deassert(faa->fa_node, NULL); 167 clock_enable(faa->fa_node, NULL); 168 } 169 170 sc->sc_gc.gc_node = faa->fa_node; 171 sc->sc_gc.gc_cookie = sc; 172 if (OF_is_compatible(faa->fa_node, "starfive,jh7100-pinctrl")) { 173 sc->sc_gc.gc_config_pin = stfpinctrl_jh7100_config_pin; 174 sc->sc_gc.gc_get_pin = stfpinctrl_jh7100_get_pin; 175 sc->sc_gc.gc_set_pin = stfpinctrl_jh7100_set_pin; 176 } else { 177 sc->sc_gc.gc_config_pin = stfpinctrl_jh7110_config_pin; 178 sc->sc_gc.gc_get_pin = stfpinctrl_jh7110_get_pin; 179 sc->sc_gc.gc_set_pin = stfpinctrl_jh7110_set_pin; 180 } 181 gpio_controller_register(&sc->sc_gc); 182 } 183 184 /* JH7100 */ 185 186 void 187 stfpinctrl_jh7100_config_pin(void *cookie, uint32_t *cells, int config) 188 { 189 struct stfpinctrl_softc *sc = cookie; 190 uint32_t pin = cells[0]; 191 uint32_t reg; 192 193 if (pin >= GPIO_NUM_PINS) 194 return; 195 196 if (config & GPIO_CONFIG_OUTPUT) { 197 bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, 198 GPIO_DOEN_CFG(pin), GPO_ENABLE); 199 } else { 200 reg = bus_space_read_4(sc->sc_iot, sc->sc_padctl_ioh, 201 sc->sc_padctl_gpio + PAD_GPIO(pin)); 202 reg |= (PAD_INPUT_ENABLE << PAD_SHIFT(pin)); 203 reg |= (PAD_INPUT_SCHMITT_ENABLE << PAD_SHIFT(pin)); 204 bus_space_write_4(sc->sc_iot, sc->sc_padctl_ioh, 205 sc->sc_padctl_gpio + PAD_GPIO(pin), reg); 206 bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, 207 GPIO_DOEN_CFG(pin), GPO_DISABLE); 208 } 209 } 210 211 int 212 stfpinctrl_jh7100_get_pin(void *cookie, uint32_t *cells) 213 { 214 struct stfpinctrl_softc *sc = cookie; 215 uint32_t pin = cells[0]; 216 uint32_t flags = cells[1]; 217 uint32_t reg; 218 int val; 219 220 if (pin >= GPIO_NUM_PINS) 221 return 0; 222 223 reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, GPIODIN(pin)); 224 val = (reg >> (pin % 32)) & 1; 225 if (flags & GPIO_ACTIVE_LOW) 226 val = !val; 227 return val; 228 } 229 230 void 231 stfpinctrl_jh7100_set_pin(void *cookie, uint32_t *cells, int val) 232 { 233 struct stfpinctrl_softc *sc = cookie; 234 uint32_t pin = cells[0]; 235 uint32_t flags = cells[1]; 236 237 if (pin >= GPIO_NUM_PINS) 238 return; 239 240 if (flags & GPIO_ACTIVE_LOW) 241 val = !val; 242 bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, 243 GPIO_DOUT_CFG(pin), val); 244 } 245 246 /* JH7110 */ 247 248 void 249 stfpinctrl_jh7110_config_pin(void *cookie, uint32_t *cells, int config) 250 { 251 struct stfpinctrl_softc *sc = cookie; 252 uint32_t pin = cells[0]; 253 uint32_t doen, padcfg; 254 255 if (pin >= GPIO_NUM_PINS) 256 return; 257 258 doen = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, JH7110_DOEN(pin)); 259 padcfg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, 260 JH7110_PADCFG(pin)); 261 doen &= ~(JH7110_DOEN_MASK << JH7110_DOEN_SHIFT(pin)); 262 if (config & GPIO_CONFIG_OUTPUT) { 263 doen |= (JH7110_DOEN_ENABLE << JH7110_DOEN_SHIFT(pin)); 264 bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, 265 JH7110_DOEN(pin), doen); 266 /* Disable input, Schmitt trigger and bias. */ 267 padcfg &= ~(JH7110_PADCFG_IE | JH7110_PADCFG_SMT); 268 padcfg &= ~(JH7110_PADCFG_PU | JH7110_PADCFG_PD); 269 bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, 270 JH7110_PADCFG(pin), padcfg); 271 } else { 272 /* Enable input and Schmitt trigger. */ 273 padcfg |= JH7110_PADCFG_IE | JH7110_PADCFG_SMT; 274 bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, 275 JH7110_PADCFG(pin), padcfg); 276 doen |= (JH7110_DOEN_DISABLE << JH7110_DOEN_SHIFT(pin)); 277 bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, 278 JH7110_DOEN(pin), doen); 279 } 280 } 281 282 int 283 stfpinctrl_jh7110_get_pin(void *cookie, uint32_t *cells) 284 { 285 struct stfpinctrl_softc *sc = cookie; 286 uint32_t pin = cells[0]; 287 uint32_t flags = cells[1]; 288 uint32_t reg; 289 int val; 290 291 if (pin >= GPIO_NUM_PINS) 292 return 0; 293 294 reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, 295 JH7110_GPIOIN(pin)); 296 val = (reg >> (pin % 32)) & 1; 297 if (flags & GPIO_ACTIVE_LOW) 298 val = !val; 299 return val; 300 } 301 302 void 303 stfpinctrl_jh7110_set_pin(void *cookie, uint32_t *cells, int val) 304 { 305 struct stfpinctrl_softc *sc = cookie; 306 uint32_t pin = cells[0]; 307 uint32_t flags = cells[1]; 308 uint32_t reg; 309 310 if (pin >= GPIO_NUM_PINS) 311 return; 312 313 if (flags & GPIO_ACTIVE_LOW) 314 val = !val; 315 316 reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, JH7110_DOUT(pin)); 317 reg &= ~(JH7110_DOUT_MASK << JH7110_DOUT_SHIFT(pin)); 318 reg |= (val << JH7110_DOUT_SHIFT(pin)); 319 bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, JH7110_DOUT(pin), reg); 320 } 321