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
52 struct 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
70 int mpfgpio_match(struct device *, void *, void*);
71 void mpfgpio_attach(struct device *, struct device *, void *);
72
73 void mpfgpio_config_pin(void *, uint32_t *, int);
74 int mpfgpio_get_pin(void *, uint32_t *);
75 void mpfgpio_set_pin(void *, uint32_t *, int);
76
77 int mpfgpio_pin_read(void *, int);
78 void mpfgpio_pin_write(void *, int, int);
79 void mpfgpio_pin_ctl(void *, int, int);
80 void mpfgpio_attach_gpio(struct device *);
81
82 const struct cfattach mpfgpio_ca = {
83 sizeof(struct mpfgpio_softc), mpfgpio_match, mpfgpio_attach
84 };
85
86 struct cfdriver mpfgpio_cd = {
87 NULL, "mpfgpio", DV_DULL
88 };
89
90 int
mpfgpio_match(struct device * parent,void * match,void * aux)91 mpfgpio_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
100 void
mpfgpio_attach(struct device * parent,struct device * self,void * aux)101 mpfgpio_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
148 void
mpfgpio_config_pin(void * cookie,uint32_t * cells,int config)149 mpfgpio_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
172 int
mpfgpio_get_pin(void * cookie,uint32_t * cells)173 mpfgpio_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
189 void
mpfgpio_set_pin(void * cookie,uint32_t * cells,int val)190 mpfgpio_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
208 int
mpfgpio_pin_read(void * cookie,int pin)209 mpfgpio_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
220 void
mpfgpio_pin_write(void * cookie,int pin,int val)221 mpfgpio_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
232 void
mpfgpio_pin_ctl(void * cookie,int pin,int flags)233 mpfgpio_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
248 static 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
254 void
mpfgpio_attach_gpio(struct device * parent)255 mpfgpio_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