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