1 /* $OpenBSD: sfgpio.c,v 1.3 2024/10/17 01:57:18 jsg Exp $ */
2 /*
3 * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
4 * Copyright (c) 2019 Patrick Wildt <patrick@blueri.se>
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 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/device.h>
22 #include <sys/malloc.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_gpio.h>
30 #include <dev/ofw/fdt.h>
31
32 /* Registers. */
33 #define GPIO_INPUT_VAL 0x0000
34 #define GPIO_INPUT_EN 0x0004
35 #define GPIO_OUTPUT_EN 0x0008
36 #define GPIO_OUTPUT_VAL 0x000c
37 #define GPIO_PUE 0x0010
38 #define GPIO_DS 0x0014
39 #define GPIO_RISE_IE 0x0018
40 #define GPIO_RISE_IP 0x001c
41 #define GPIO_FALL_IE 0x0020
42 #define GPIO_FALL_IP 0x0024
43 #define GPIO_HIGH_IE 0x0028
44 #define GPIO_HIGH_IP 0x002c
45 #define GPIO_LOW_IE 0x0030
46 #define GPIO_LOW_IP 0x0034
47 #define GPIO_IOF_EN 0x0038
48 #define GPIO_IOF_SEL 0x003C
49 #define GPIO_OUT_XOR 0x0040
50
51 #define GPIO_NUM_PINS 16
52
53 #define HREAD4(sc, reg) \
54 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
55 #define HWRITE4(sc, reg, val) \
56 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
57 #define HSET4(sc, reg, bits) \
58 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
59 #define HCLR4(sc, reg, bits) \
60 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
61
62 struct intrhand {
63 int (*ih_func)(void *); /* handler */
64 void *ih_arg; /* arg for handler */
65 int ih_pin; /* pin number */
66 int ih_level; /* trigger level */
67 void *ih_sc;
68 };
69
70 struct sfgpio_softc {
71 struct device sc_dev;
72 bus_space_tag_t sc_iot;
73 bus_space_handle_t sc_ioh;
74 int sc_node;
75
76 void *sc_ih[GPIO_NUM_PINS];
77 struct interrupt_controller sc_ic;
78
79 struct gpio_controller sc_gc;
80 };
81
82 int sfgpio_match(struct device *, void *, void *);
83 void sfgpio_attach(struct device *, struct device *, void *);
84
85 const struct cfattach sfgpio_ca = {
86 sizeof (struct sfgpio_softc), sfgpio_match, sfgpio_attach
87 };
88
89 struct cfdriver sfgpio_cd = {
90 NULL, "sfgpio", DV_DULL
91 };
92
93 void sfgpio_config_pin(void *, uint32_t *, int);
94 int sfgpio_get_pin(void *, uint32_t *);
95 void sfgpio_set_pin(void *, uint32_t *, int);
96
97 int sfgpio_intr(void *);
98 void *sfgpio_intr_establish(void *, int *, int, struct cpu_info *,
99 int (*)(void *), void *, char *);
100 void sfgpio_intr_disestablish(void *);
101 void sfgpio_intr_enable(void *);
102 void sfgpio_intr_disable(void *);
103 void sfgpio_intr_barrier(void *);
104
105 int
sfgpio_match(struct device * parent,void * match,void * aux)106 sfgpio_match(struct device *parent, void *match, void *aux)
107 {
108 struct fdt_attach_args *faa = aux;
109
110 return OF_is_compatible(faa->fa_node, "sifive,gpio0");
111 }
112
113 void
sfgpio_attach(struct device * parent,struct device * self,void * aux)114 sfgpio_attach(struct device *parent, struct device *self, void *aux)
115 {
116 struct sfgpio_softc *sc = (struct sfgpio_softc *)self;
117 struct fdt_attach_args *faa = aux;
118
119 if (faa->fa_nreg < 1) {
120 printf(": no registers\n");
121 return;
122 }
123
124 sc->sc_node = faa->fa_node;
125 sc->sc_iot = faa->fa_iot;
126
127 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
128 faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
129 printf(": can't map registers\n");
130 return;
131 }
132
133 printf("\n");
134
135 sc->sc_gc.gc_node = faa->fa_node;
136 sc->sc_gc.gc_cookie = sc;
137 sc->sc_gc.gc_config_pin = sfgpio_config_pin;
138 sc->sc_gc.gc_get_pin = sfgpio_get_pin;
139 sc->sc_gc.gc_set_pin = sfgpio_set_pin;
140 gpio_controller_register(&sc->sc_gc);
141
142 /* Disable all interrupts. */
143 HWRITE4(sc, GPIO_RISE_IE, 0);
144 HWRITE4(sc, GPIO_FALL_IE, 0);
145 HWRITE4(sc, GPIO_HIGH_IE, 0);
146 HWRITE4(sc, GPIO_LOW_IE, 0);
147
148 sc->sc_ic.ic_node = faa->fa_node;
149 sc->sc_ic.ic_cookie = sc;
150 sc->sc_ic.ic_establish = sfgpio_intr_establish;
151 sc->sc_ic.ic_disestablish = sfgpio_intr_disestablish;
152 sc->sc_ic.ic_enable = sfgpio_intr_enable;
153 sc->sc_ic.ic_disable = sfgpio_intr_disable;
154 sc->sc_ic.ic_barrier = sfgpio_intr_barrier;
155 fdt_intr_register(&sc->sc_ic);
156 }
157
158 void
sfgpio_config_pin(void * cookie,uint32_t * cells,int config)159 sfgpio_config_pin(void *cookie, uint32_t *cells, int config)
160 {
161 struct sfgpio_softc *sc = cookie;
162 uint32_t pin = cells[0];
163
164 if (pin >= GPIO_NUM_PINS)
165 return;
166
167 if (config & GPIO_CONFIG_OUTPUT) {
168 HSET4(sc, GPIO_OUTPUT_EN, (1 << pin));
169 HCLR4(sc, GPIO_INPUT_EN, (1 << pin));
170 } else {
171 HSET4(sc, GPIO_INPUT_EN, (1 << pin));
172 HCLR4(sc, GPIO_OUTPUT_EN, (1 << pin));
173 }
174 }
175
176 int
sfgpio_get_pin(void * cookie,uint32_t * cells)177 sfgpio_get_pin(void *cookie, uint32_t *cells)
178 {
179 struct sfgpio_softc *sc = cookie;
180 uint32_t pin = cells[0];
181 uint32_t flags = cells[1];
182 uint32_t reg;
183 int val;
184
185 if (pin >= GPIO_NUM_PINS)
186 return 0;
187
188 reg = HREAD4(sc, GPIO_INPUT_VAL);
189 val = (reg >> pin) & 1;
190 if (flags & GPIO_ACTIVE_LOW)
191 val = !val;
192 return val;
193 }
194
195 void
sfgpio_set_pin(void * cookie,uint32_t * cells,int val)196 sfgpio_set_pin(void *cookie, uint32_t *cells, int val)
197 {
198 struct sfgpio_softc *sc = cookie;
199 uint32_t pin = cells[0];
200 uint32_t flags = cells[1];
201
202 if (pin >= GPIO_NUM_PINS)
203 return;
204
205 if (flags & GPIO_ACTIVE_LOW)
206 val = !val;
207 if (val)
208 HSET4(sc, GPIO_OUTPUT_VAL, (1 << pin));
209 else
210 HCLR4(sc, GPIO_OUTPUT_VAL, (1 << pin));
211 }
212
213 int
sfgpio_intr(void * cookie)214 sfgpio_intr(void *cookie)
215 {
216 struct intrhand *ih = cookie;
217 struct sfgpio_softc *sc = ih->ih_sc;
218 int handled;
219
220 handled = ih->ih_func(ih->ih_arg);
221
222 switch (ih->ih_level) {
223 case 1: /* rising */
224 HSET4(sc, GPIO_RISE_IP, (1 << ih->ih_pin));
225 break;
226 case 2: /* falling */
227 HSET4(sc, GPIO_FALL_IP, (1 << ih->ih_pin));
228 break;
229 case 4: /* high */
230 HSET4(sc, GPIO_HIGH_IP, (1 << ih->ih_pin));
231 break;
232 case 8: /* low */
233 HSET4(sc, GPIO_LOW_IP, (1 << ih->ih_pin));
234 break;
235 }
236
237 return handled;
238 }
239
240 void *
sfgpio_intr_establish(void * cookie,int * cells,int ipl,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)241 sfgpio_intr_establish(void *cookie, int *cells, int ipl,
242 struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
243 {
244 struct sfgpio_softc *sc = (struct sfgpio_softc *)cookie;
245 struct intrhand *ih;
246 int pin = cells[0];
247 int level = cells[1];
248
249 if (pin < 0 || pin >= GPIO_NUM_PINS)
250 panic("%s: bogus pin %d: %s", __func__, pin, name);
251
252 if (sc->sc_ih[pin] != NULL)
253 panic("%s: pin %d reused: %s", __func__, pin, name);
254
255 ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
256 ih->ih_func = func;
257 ih->ih_arg = arg;
258 ih->ih_pin = pin;
259 ih->ih_level = level;
260 ih->ih_sc = sc;
261
262 sc->sc_ih[pin] = fdt_intr_establish_idx_cpu(sc->sc_node, pin, ipl,
263 ci, sfgpio_intr, ih, name);
264 if (sc->sc_ih[pin] == NULL) {
265 free(ih, M_DEVBUF, sizeof(*ih));
266 return NULL;
267 }
268
269 HSET4(sc, GPIO_INPUT_EN, (1 << pin));
270
271 switch (level) {
272 case 1: /* rising */
273 HSET4(sc, GPIO_RISE_IP, (1 << pin));
274 HSET4(sc, GPIO_RISE_IE, (1 << pin));
275 break;
276 case 2: /* falling */
277 HSET4(sc, GPIO_FALL_IP, (1 << pin));
278 HSET4(sc, GPIO_FALL_IE, (1 << pin));
279 break;
280 case 4: /* high */
281 HSET4(sc, GPIO_HIGH_IP, (1 << pin));
282 HSET4(sc, GPIO_HIGH_IE, (1 << pin));
283 break;
284 case 8: /* low */
285 HSET4(sc, GPIO_LOW_IP, (1 << pin));
286 HSET4(sc, GPIO_LOW_IE, (1 << pin));
287 break;
288 default:
289 panic("%s: unsupported trigger type", __func__);
290 }
291
292 return ih;
293 }
294
295 void
sfgpio_intr_disestablish(void * cookie)296 sfgpio_intr_disestablish(void *cookie)
297 {
298 struct intrhand *ih = cookie;
299 struct sfgpio_softc *sc = ih->ih_sc;
300
301 sfgpio_intr_disable(ih);
302
303 fdt_intr_disestablish(sc->sc_ih[ih->ih_pin]);
304 sc->sc_ih[ih->ih_pin] = NULL;
305 free(ih, M_DEVBUF, sizeof(*ih));
306 }
307
308 void
sfgpio_intr_enable(void * cookie)309 sfgpio_intr_enable(void *cookie)
310 {
311 struct intrhand *ih = cookie;
312 struct sfgpio_softc *sc = ih->ih_sc;
313
314 switch (ih->ih_level) {
315 case 1: /* rising */
316 HSET4(sc, GPIO_RISE_IE, (1 << ih->ih_pin));
317 break;
318 case 2: /* falling */
319 HSET4(sc, GPIO_FALL_IE, (1 << ih->ih_pin));
320 break;
321 case 4: /* high */
322 HSET4(sc, GPIO_HIGH_IE, (1 << ih->ih_pin));
323 break;
324 case 8: /* low */
325 HSET4(sc, GPIO_LOW_IE, (1 << ih->ih_pin));
326 break;
327 }
328 }
329
330 void
sfgpio_intr_disable(void * cookie)331 sfgpio_intr_disable(void *cookie)
332 {
333 struct intrhand *ih = cookie;
334 struct sfgpio_softc *sc = ih->ih_sc;
335
336 switch (ih->ih_level) {
337 case 1: /* rising */
338 HCLR4(sc, GPIO_RISE_IE, (1 << ih->ih_pin));
339 break;
340 case 2: /* falling */
341 HCLR4(sc, GPIO_FALL_IE, (1 << ih->ih_pin));
342 break;
343 case 4: /* high */
344 HCLR4(sc, GPIO_HIGH_IE, (1 << ih->ih_pin));
345 break;
346 case 8: /* low */
347 HCLR4(sc, GPIO_LOW_IE, (1 << ih->ih_pin));
348 break;
349 }
350 }
351
352 void
sfgpio_intr_barrier(void * cookie)353 sfgpio_intr_barrier(void *cookie)
354 {
355 struct intrhand *ih = cookie;
356 struct sfgpio_softc *sc = ih->ih_sc;
357
358 intr_barrier(sc->sc_ih[ih->ih_pin]);
359 }
360