tangled
alpha
login
or
join now
jcs.org
/
openbsd-src
0
fork
atom
jcs's openbsd hax
openbsd
0
fork
atom
overview
issues
pulls
pipelines
Add support for GPIO interrupts.
ok mglocker@, bmercer@
kettenis
7 months ago
3ee3bddf
0c042fb4
+261
-10
1 changed file
expand all
collapse all
unified
split
sys
dev
fdt
bcmstbgpio.c
+261
-10
sys/dev/fdt/bcmstbgpio.c
reviewed
···
1
1
-
/* $OpenBSD: bcmstbgpio.c,v 1.1 2025/08/09 14:42:48 kettenis Exp $ */
1
1
+
/* $OpenBSD: bcmstbgpio.c,v 1.2 2025/09/08 19:32:18 kettenis Exp $ */
2
2
/*
3
3
* Copyright (c) 2025 Mark Kettenis <kettenis@openbsd.org>
4
4
*
···
18
18
#include <sys/param.h>
19
19
#include <sys/systm.h>
20
20
#include <sys/device.h>
21
21
+
#include <sys/evcount.h>
22
22
+
#include <sys/malloc.h>
21
23
22
24
#include <machine/intr.h>
23
25
#include <machine/bus.h>
···
30
32
/* Registers. */
31
33
#define GIO_DATA(_bank) (0x04 + (_bank) * 32)
32
34
#define GIO_IODIR(_bank) (0x08 + (_bank) * 32)
35
35
+
#define GIO_EC(_bank) (0x0c + (_bank) * 32)
36
36
+
#define GIO_EI(_bank) (0x10 + (_bank) * 32)
37
37
+
#define GIO_MASK(_bank) (0x14 + (_bank) * 32)
38
38
+
#define GIO_LEVEL(_bank) (0x18 + (_bank) * 32)
39
39
+
#define GIO_STAT(_bank) (0x1c + (_bank) * 32)
33
40
34
41
#define HREAD4(sc, reg) \
35
42
(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
···
40
47
#define HCLR4(sc, reg, bits) \
41
48
HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
42
49
50
50
+
struct intrhand {
51
51
+
int (*ih_func)(void *);
52
52
+
void *ih_arg;
53
53
+
int ih_ipl;
54
54
+
int ih_irq;
55
55
+
int ih_edge;
56
56
+
struct evcount ih_count;
57
57
+
char *ih_name;
58
58
+
void *ih_sc;
59
59
+
};
60
60
+
43
61
struct bcmstbgpio_softc {
44
62
struct device sc_dev;
45
63
bus_space_tag_t sc_iot;
46
64
bus_space_handle_t sc_ioh;
47
65
u_int sc_nbanks;
66
66
+
int sc_node;
67
67
+
68
68
+
void *sc_ih;
69
69
+
int sc_ipl;
70
70
+
struct intrhand **sc_handlers;
71
71
+
struct interrupt_controller sc_ic;
48
72
49
73
struct gpio_controller sc_gc;
50
74
};
···
63
87
void bcmstbgpio_config_pin(void *, uint32_t *, int);
64
88
int bcmstbgpio_get_pin(void *, uint32_t *);
65
89
void bcmstbgpio_set_pin(void *, uint32_t *, int);
90
90
+
void *bcmstbgpio_intr_establish_pin(void *, uint32_t *, int,
91
91
+
struct cpu_info *, int (*)(void *), void *, char *);
92
92
+
93
93
+
int bcmstbgpio_intr(void *);
94
94
+
void *bcmstbgpio_intr_establish(void *, int *, int, struct cpu_info *,
95
95
+
int (*)(void *), void *, char *);
96
96
+
void bcmstbgpio_intr_enable(void *);
97
97
+
void bcmstbgpio_intr_disable(void *);
98
98
+
void bcmstbgpio_intr_barrier(void *);
66
99
67
100
int
68
101
bcmstbgpio_match(struct device *parent, void *match, void *aux)
···
77
110
{
78
111
struct bcmstbgpio_softc *sc = (struct bcmstbgpio_softc *)self;
79
112
struct fdt_attach_args *faa = aux;
113
113
+
u_int bank;
80
114
81
115
if (faa->fa_nreg < 1) {
82
116
printf(": no registers\n");
···
90
124
return;
91
125
}
92
126
sc->sc_nbanks = faa->fa_reg[0].size / 32;
127
127
+
sc->sc_node = faa->fa_node;
128
128
+
129
129
+
sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_NONE,
130
130
+
bcmstbgpio_intr, sc, sc->sc_dev.dv_xname);
131
131
+
sc->sc_ipl = IPL_NONE;
132
132
+
133
133
+
printf("\n");
134
134
+
135
135
+
for (bank = 0; bank < sc->sc_nbanks; bank++)
136
136
+
HWRITE4(sc, GIO_MASK(bank), 0);
137
137
+
138
138
+
sc->sc_handlers = mallocarray(sc->sc_nbanks * 32,
139
139
+
sizeof(struct intrhand *), M_DEVBUF, M_WAITOK | M_ZERO);
140
140
+
141
141
+
sc->sc_ic.ic_node = faa->fa_node;
142
142
+
sc->sc_ic.ic_cookie = sc;
143
143
+
sc->sc_ic.ic_establish = bcmstbgpio_intr_establish;
144
144
+
sc->sc_ic.ic_enable = bcmstbgpio_intr_enable;
145
145
+
sc->sc_ic.ic_disable = bcmstbgpio_intr_enable;
146
146
+
sc->sc_ic.ic_barrier = bcmstbgpio_intr_barrier;
147
147
+
fdt_intr_register(&sc->sc_ic);
93
148
94
149
sc->sc_gc.gc_node = faa->fa_node;
95
150
sc->sc_gc.gc_cookie = sc;
96
151
sc->sc_gc.gc_config_pin = bcmstbgpio_config_pin;
97
152
sc->sc_gc.gc_get_pin = bcmstbgpio_get_pin;
98
153
sc->sc_gc.gc_set_pin = bcmstbgpio_set_pin;
154
154
+
sc->sc_gc.gc_intr_establish = bcmstbgpio_intr_establish_pin;
99
155
gpio_controller_register(&sc->sc_gc);
100
100
-
101
101
-
printf("\n");
102
156
}
103
157
104
158
void
105
159
bcmstbgpio_config_pin(void *cookie, uint32_t *cells, int config)
106
160
{
107
161
struct bcmstbgpio_softc *sc = cookie;
108
108
-
uint32_t bank = cells[0] / 32;;
109
109
-
uint32_t pin = cells[0] % 32;
162
162
+
u_int bank = cells[0] / 32;
163
163
+
u_int pin = cells[0] % 32;
110
164
111
165
if (bank >= sc->sc_nbanks)
112
166
return;
113
167
114
168
if (config & GPIO_CONFIG_OUTPUT)
115
115
-
HCLR4(sc, GIO_IODIR(bank), (1U << pin));
169
169
+
HCLR4(sc, GIO_IODIR(bank), 1U << pin);
116
170
else
117
117
-
HSET4(sc, GIO_IODIR(bank), (1U << pin));
171
171
+
HSET4(sc, GIO_IODIR(bank), 1U << pin);
118
172
}
119
173
120
174
int
121
175
bcmstbgpio_get_pin(void *cookie, uint32_t *cells)
122
176
{
123
177
struct bcmstbgpio_softc *sc = cookie;
124
124
-
uint32_t bank = cells[0] / 32;;
178
178
+
uint32_t bank = cells[0] / 32;
125
179
uint32_t pin = cells[0] % 32;
126
180
uint32_t flags = cells[1];
127
181
uint32_t reg;
···
151
205
if (flags & GPIO_ACTIVE_LOW)
152
206
val = !val;
153
207
if (val)
154
154
-
HSET4(sc, GIO_DATA(bank), (1U << pin));
208
208
+
HSET4(sc, GIO_DATA(bank), 1U << pin);
155
209
else
156
156
-
HCLR4(sc, GIO_DATA(bank), (1U << pin));
210
210
+
HCLR4(sc, GIO_DATA(bank), 1U << pin);
211
211
+
}
212
212
+
213
213
+
void *
214
214
+
bcmstbgpio_intr_establish_pin(void *cookie, uint32_t *cells, int ipl,
215
215
+
struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
216
216
+
{
217
217
+
struct bcmstbgpio_softc *sc = cookie;
218
218
+
uint32_t icells[2];
219
219
+
220
220
+
icells[0] = cells[0];
221
221
+
icells[1] = 3; /* both edges */
222
222
+
223
223
+
return bcmstbgpio_intr_establish(sc, icells, ipl, ci, func, arg, name);
224
224
+
}
225
225
+
226
226
+
int
227
227
+
bcmstbgpio_intr(void *arg)
228
228
+
{
229
229
+
struct bcmstbgpio_softc *sc = arg;
230
230
+
u_int bank;
231
231
+
int handled = 0;
232
232
+
233
233
+
for (bank = 0; bank < sc->sc_nbanks; bank++) {
234
234
+
struct intrhand *ih;
235
235
+
uint32_t mask, stat;
236
236
+
u_int pin;
237
237
+
int s;
238
238
+
239
239
+
mask = HREAD4(sc, GIO_MASK(bank));
240
240
+
stat = HREAD4(sc, GIO_STAT(bank)) & mask;
241
241
+
if (stat == 0)
242
242
+
continue;
243
243
+
244
244
+
while (stat) {
245
245
+
pin = ffs(stat) - 1;
246
246
+
stat &= ~(1U << pin);
247
247
+
248
248
+
ih = sc->sc_handlers[bank * 32 + pin];
249
249
+
KASSERT(ih);
250
250
+
251
251
+
if (ih->ih_edge)
252
252
+
HWRITE4(sc, GIO_STAT(bank), 1U << pin);
253
253
+
254
254
+
s = splraise(ih->ih_ipl);
255
255
+
if (ih->ih_func(ih->ih_arg))
256
256
+
ih->ih_count.ec_count++;
257
257
+
splx(s);
258
258
+
259
259
+
if (!ih->ih_edge)
260
260
+
HWRITE4(sc, GIO_STAT(bank), 1U << pin);
261
261
+
262
262
+
handled = 1;
263
263
+
}
264
264
+
}
265
265
+
266
266
+
return handled;
267
267
+
}
268
268
+
269
269
+
void
270
270
+
bcmstbgpio_recalc_ipl(struct bcmstbgpio_softc *sc)
271
271
+
{
272
272
+
struct intrhand *ih;
273
273
+
int max = IPL_NONE;
274
274
+
int min = IPL_HIGH;
275
275
+
int irq;
276
276
+
277
277
+
for (irq = 0; irq < sc->sc_nbanks * 32; irq++) {
278
278
+
ih = sc->sc_handlers[irq];
279
279
+
if (ih == NULL)
280
280
+
continue;
281
281
+
282
282
+
if (ih->ih_ipl > max)
283
283
+
max = ih->ih_ipl;
284
284
+
285
285
+
if (ih->ih_ipl < min)
286
286
+
min = ih->ih_ipl;
287
287
+
}
288
288
+
289
289
+
if (max == IPL_NONE)
290
290
+
min = IPL_NONE;
291
291
+
292
292
+
if (sc->sc_ipl != max) {
293
293
+
sc->sc_ipl = max;
294
294
+
295
295
+
fdt_intr_disestablish(sc->sc_ih);
296
296
+
sc->sc_ih = fdt_intr_establish(sc->sc_node,
297
297
+
sc->sc_ipl, bcmstbgpio_intr, sc, sc->sc_dev.dv_xname);
298
298
+
KASSERT(sc->sc_ih);
299
299
+
}
300
300
+
}
301
301
+
302
302
+
void *
303
303
+
bcmstbgpio_intr_establish(void *cookie, int *cells, int ipl,
304
304
+
struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
305
305
+
{
306
306
+
struct bcmstbgpio_softc *sc = cookie;
307
307
+
struct intrhand *ih;
308
308
+
int irq = cells[0];
309
309
+
int type = cells[1];
310
310
+
u_int bank = irq / 32;;
311
311
+
u_int pin = irq % 32;
312
312
+
uint32_t ec, ei, level;
313
313
+
int edge = 0;
314
314
+
315
315
+
/* Interrupt handling is an optional feature. */
316
316
+
if (sc->sc_ih == NULL)
317
317
+
return NULL;
318
318
+
319
319
+
if (bank >= sc->sc_nbanks)
320
320
+
return NULL;
321
321
+
322
322
+
/* We don't support interrupt sharing. */
323
323
+
if (sc->sc_handlers[irq])
324
324
+
return NULL;
325
325
+
326
326
+
ec = HREAD4(sc, GIO_EC(bank)) & ~(1U << pin);
327
327
+
ei = HREAD4(sc, GIO_EI(bank)) & ~(1U << pin);
328
328
+
level = HREAD4(sc, GIO_LEVEL(bank)) & ~(1U << pin);
329
329
+
330
330
+
switch (type) {
331
331
+
case 1: /* rising */
332
332
+
ec |= (1U << pin);
333
333
+
edge = 1;
334
334
+
break;
335
335
+
case 2: /* falling */
336
336
+
edge = 1;
337
337
+
break;
338
338
+
case 3: /* both */
339
339
+
ei |= (1U << pin);
340
340
+
edge = 1;
341
341
+
break;
342
342
+
case 4: /* high */
343
343
+
ec |= (1U << pin);
344
344
+
level |= (1U << pin);
345
345
+
break;
346
346
+
case 8: /* low */
347
347
+
level |= (1U << pin);
348
348
+
break;
349
349
+
default:
350
350
+
return NULL;
351
351
+
}
352
352
+
353
353
+
ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
354
354
+
ih->ih_func = func;
355
355
+
ih->ih_arg = arg;
356
356
+
ih->ih_ipl = ipl & IPL_IRQMASK;
357
357
+
ih->ih_irq = irq;
358
358
+
ih->ih_edge = edge;
359
359
+
ih->ih_name = name;
360
360
+
ih->ih_sc = sc;
361
361
+
362
362
+
if (name)
363
363
+
evcount_attach(&ih->ih_count, name, &ih->ih_irq);
364
364
+
365
365
+
sc->sc_handlers[ih->ih_irq] = ih;
366
366
+
367
367
+
bcmstbgpio_recalc_ipl(sc);
368
368
+
369
369
+
HWRITE4(sc, GIO_EC(bank), ec);
370
370
+
HWRITE4(sc, GIO_EI(bank), ei);
371
371
+
HWRITE4(sc, GIO_LEVEL(bank), level);
372
372
+
373
373
+
HWRITE4(sc, GIO_STAT(bank), 1U << pin);
374
374
+
HSET4(sc, GIO_MASK(bank), 1U << pin);
375
375
+
376
376
+
return ih;
377
377
+
}
378
378
+
379
379
+
void
380
380
+
bcmstbgpio_intr_enable(void *cookie)
381
381
+
{
382
382
+
struct intrhand *ih = cookie;
383
383
+
struct bcmstbgpio_softc *sc = ih->ih_sc;
384
384
+
uint32_t bank = ih->ih_irq / 32;
385
385
+
uint32_t pin = ih->ih_irq % 32;
386
386
+
387
387
+
HSET4(sc, GIO_MASK(bank), 1U << pin);
388
388
+
}
389
389
+
390
390
+
void
391
391
+
bcmstbgpio_intr_disable(void *cookie)
392
392
+
{
393
393
+
struct intrhand *ih = cookie;
394
394
+
struct bcmstbgpio_softc *sc = ih->ih_sc;
395
395
+
uint32_t bank = ih->ih_irq / 32;
396
396
+
uint32_t pin = ih->ih_irq % 32;
397
397
+
398
398
+
HCLR4(sc, GIO_MASK(bank), 1U << pin);
399
399
+
}
400
400
+
401
401
+
void
402
402
+
bcmstbgpio_intr_barrier(void *cookie)
403
403
+
{
404
404
+
struct intrhand *ih = cookie;
405
405
+
struct bcmstbgpio_softc *sc = ih->ih_sc;
406
406
+
407
407
+
intr_barrier(sc->sc_ih);
157
408
}