1/* $OpenBSD: mpfgpio.c,v 1.1 2022/02/18 10:51:43 visa Exp $ */ 2 3/* 4 * Copyright (c) 2022 Visa Hankala 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/* 20 * Driver for PolarFire SoC MSS GPIO controller. 21 */ 22 23#include <sys/param.h> 24#include <sys/systm.h> 25#include <sys/device.h> 26#include <sys/gpio.h> 27 28#include <machine/bus.h> 29#include <machine/fdt.h> 30 31#include <dev/gpio/gpiovar.h> 32 33#include <dev/ofw/fdt.h> 34#include <dev/ofw/openfirm.h> 35#include <dev/ofw/ofw_clock.h> 36#include <dev/ofw/ofw_gpio.h> 37 38#include "gpio.h" 39 40#define MPFGPIO_CONFIG(i) (0x0000 + (i) * 4) 41#define MPFGPIO_CONFIG_EN_INT (1 << 3) 42#define MPFGPIO_CONFIG_EN_OE_BUF (1 << 2) 43#define MPFGPIO_CONFIG_EN_IN (1 << 1) 44#define MPFGPIO_CONFIG_EN_OUT (1 << 0) 45#define MPFGPIO_GPIN 0x0084 46#define MPFGPIO_GPOUT 0x0088 47#define MPFGPIO_CLEAR_BITS 0x00a0 48#define MPFGPIO_SET_BITS 0x00a4 49 50#define MPFGPIO_MAX_PINS 32 51 52struct mpfgpio_softc { 53 struct device sc_dev; 54 bus_space_tag_t sc_iot; 55 bus_space_handle_t sc_ioh; 56 uint32_t sc_npins; 57 58 struct gpio_controller sc_gc; 59 60 struct gpio_chipset_tag sc_gpio_tag; 61 gpio_pin_t sc_gpio_pins[MPFGPIO_MAX_PINS]; 62 uint8_t sc_gpio_claimed[MPFGPIO_MAX_PINS]; 63}; 64 65#define HREAD4(sc, reg) \ 66 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 67#define HWRITE4(sc, reg, val) \ 68 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 69 70int mpfgpio_match(struct device *, void *, void*); 71void mpfgpio_attach(struct device *, struct device *, void *); 72 73void mpfgpio_config_pin(void *, uint32_t *, int); 74int mpfgpio_get_pin(void *, uint32_t *); 75void mpfgpio_set_pin(void *, uint32_t *, int); 76 77int mpfgpio_pin_read(void *, int); 78void mpfgpio_pin_write(void *, int, int); 79void mpfgpio_pin_ctl(void *, int, int); 80void mpfgpio_attach_gpio(struct device *); 81 82const struct cfattach mpfgpio_ca = { 83 sizeof(struct mpfgpio_softc), mpfgpio_match, mpfgpio_attach 84}; 85 86struct cfdriver mpfgpio_cd = { 87 NULL, "mpfgpio", DV_DULL 88}; 89 90int 91mpfgpio_match(struct device *parent, void *match, void *aux) 92{ 93 struct fdt_attach_args *faa = aux; 94 95 if (faa->fa_nreg < 1) 96 return 0; 97 return OF_is_compatible(faa->fa_node, "microchip,mpfs-gpio"); 98} 99 100void 101mpfgpio_attach(struct device *parent, struct device *self, void *aux) 102{ 103 struct fdt_attach_args *faa = aux; 104 struct mpfgpio_softc *sc = (struct mpfgpio_softc *)self; 105 unsigned int unit; 106 107 sc->sc_iot = faa->fa_iot; 108 109 unit = (faa->fa_reg[0].addr >> 12) & 0x3; 110 switch (unit) { 111 case 0: 112 sc->sc_npins = 14; 113 break; 114 case 1: 115 sc->sc_npins = 24; 116 break; 117 case 2: 118 sc->sc_npins = 32; 119 break; 120 default: 121 printf(": unexpected GPIO unit %u\n", unit); 122 return; 123 } 124 KASSERT(sc->sc_npins <= MPFGPIO_MAX_PINS); 125 126 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size, 127 0, &sc->sc_ioh) != 0) { 128 printf(": can't map registers\n"); 129 return; 130 } 131 132 clock_enable_all(faa->fa_node); 133 134 printf(": unit %u\n", unit); 135 136 sc->sc_gc.gc_node = faa->fa_node; 137 sc->sc_gc.gc_cookie = sc; 138 sc->sc_gc.gc_config_pin = mpfgpio_config_pin; 139 sc->sc_gc.gc_get_pin = mpfgpio_get_pin; 140 sc->sc_gc.gc_set_pin = mpfgpio_set_pin; 141 gpio_controller_register(&sc->sc_gc); 142 143#if NGPIO > 0 144 config_mountroot(self, mpfgpio_attach_gpio); 145#endif 146} 147 148void 149mpfgpio_config_pin(void *cookie, uint32_t *cells, int config) 150{ 151 struct mpfgpio_softc *sc = cookie; 152 uint32_t pin = cells[0]; 153 uint32_t val; 154 155 if (pin >= sc->sc_npins) 156 return; 157 158 val = HREAD4(sc, MPFGPIO_CONFIG(pin)); 159 if (config & GPIO_CONFIG_OUTPUT) { 160 val &= ~MPFGPIO_CONFIG_EN_IN; 161 val |= MPFGPIO_CONFIG_EN_OUT; 162 } else { 163 val |= MPFGPIO_CONFIG_EN_IN; 164 val &= ~MPFGPIO_CONFIG_EN_OUT; 165 } 166 val &= ~MPFGPIO_CONFIG_EN_INT; 167 HWRITE4(sc, MPFGPIO_CONFIG(pin), val); 168 169 sc->sc_gpio_claimed[pin] = 1; 170} 171 172int 173mpfgpio_get_pin(void *cookie, uint32_t *cells) 174{ 175 struct mpfgpio_softc *sc = cookie; 176 uint32_t pin = cells[0]; 177 uint32_t flags = cells[1]; 178 int val; 179 180 if (pin >= sc->sc_npins) 181 return 0; 182 183 val = (HREAD4(sc, MPFGPIO_GPIN) >> pin) & 1; 184 if (flags & GPIO_ACTIVE_LOW) 185 val = !val; 186 return val; 187} 188 189void 190mpfgpio_set_pin(void *cookie, uint32_t *cells, int val) 191{ 192 struct mpfgpio_softc *sc = cookie; 193 uint32_t pin = cells[0]; 194 uint32_t flags = cells[1]; 195 196 if (pin >= sc->sc_npins) 197 return; 198 199 if (flags & GPIO_ACTIVE_LOW) 200 val = !val; 201 if (val) 202 HWRITE4(sc, MPFGPIO_SET_BITS, (1U << (pin % 32))); 203 else 204 HWRITE4(sc, MPFGPIO_CLEAR_BITS, (1U << (pin % 32))); 205} 206 207#if NGPIO > 0 208int 209mpfgpio_pin_read(void *cookie, int pin) 210{ 211 struct mpfgpio_softc *sc = cookie; 212 uint32_t cells[2]; 213 214 cells[0] = pin; 215 cells[1] = 0; 216 217 return mpfgpio_get_pin(sc, cells) ? GPIO_PIN_HIGH : GPIO_PIN_LOW; 218} 219 220void 221mpfgpio_pin_write(void *cookie, int pin, int val) 222{ 223 struct mpfgpio_softc *sc = cookie; 224 uint32_t cells[2]; 225 226 cells[0] = pin; 227 cells[1] = 0; 228 229 mpfgpio_set_pin(sc, cells, val); 230} 231 232void 233mpfgpio_pin_ctl(void *cookie, int pin, int flags) 234{ 235 struct mpfgpio_softc *sc = cookie; 236 uint32_t cells[2]; 237 uint32_t config = 0; 238 239 cells[0] = pin; 240 cells[1] = 0; 241 242 if (flags & GPIO_PIN_OUTPUT) 243 config |= GPIO_CONFIG_OUTPUT; 244 245 mpfgpio_config_pin(sc, cells, config); 246} 247 248static const struct gpio_chipset_tag mpfgpio_gpio_tag = { 249 .gp_pin_read = mpfgpio_pin_read, 250 .gp_pin_write = mpfgpio_pin_write, 251 .gp_pin_ctl = mpfgpio_pin_ctl, 252}; 253 254void 255mpfgpio_attach_gpio(struct device *parent) 256{ 257 struct gpiobus_attach_args gba; 258 struct mpfgpio_softc *sc = (struct mpfgpio_softc *)parent; 259 uint32_t cfgreg, pin; 260 int flags, state; 261 262 for (pin = 0; pin < sc->sc_npins; pin++) { 263 /* Skip pins claimed by other devices. */ 264 if (sc->sc_gpio_claimed[pin]) 265 continue; 266 267 cfgreg = HREAD4(sc, MPFGPIO_CONFIG(pin)); 268 if (cfgreg & MPFGPIO_CONFIG_EN_OUT) 269 flags = GPIO_PIN_SET | GPIO_PIN_OUTPUT; 270 else if (cfgreg & MPFGPIO_CONFIG_EN_IN) 271 flags = GPIO_PIN_SET | GPIO_PIN_INPUT; 272 else 273 flags = GPIO_PIN_SET; 274 275 state = (HREAD4(sc, MPFGPIO_GPIN) >> pin) & 1; 276 277 sc->sc_gpio_pins[pin].pin_caps = 278 GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; 279 sc->sc_gpio_pins[pin].pin_flags = flags; 280 sc->sc_gpio_pins[pin].pin_state = state; 281 sc->sc_gpio_pins[pin].pin_num = pin; 282 } 283 284 sc->sc_gpio_tag = mpfgpio_gpio_tag; 285 sc->sc_gpio_tag.gp_cookie = sc; 286 287 gba.gba_name = "gpio"; 288 gba.gba_gc = &sc->sc_gpio_tag; 289 gba.gba_pins = sc->sc_gpio_pins; 290 gba.gba_npins = sc->sc_npins; 291 292 config_found(&sc->sc_dev, &gba, gpiobus_print); 293} 294#endif 295