xref: /openbsd-src/sys/dev/fdt/rkgpio.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*	$OpenBSD: rkgpio.c,v 1.6 2020/07/17 08:07:34 patrick Exp $	*/
2 /*
3  * Copyright (c) 2017 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 #include <sys/evcount.h>
24 
25 #include <machine/intr.h>
26 #include <machine/bus.h>
27 #include <machine/fdt.h>
28 
29 #include <dev/ofw/openfirm.h>
30 #include <dev/ofw/ofw_gpio.h>
31 #include <dev/ofw/fdt.h>
32 
33 /* Registers. */
34 #define GPIO_SWPORTA_DR		0x0000
35 #define GPIO_SWPORTA_DDR	0x0004
36 #define GPIO_INTEN		0x0030
37 #define GPIO_INTMASK		0x0034
38 #define GPIO_INTTYPE_LEVEL	0x0038
39 #define GPIO_INT_POLARITY	0x003c
40 #define GPIO_INT_STATUS		0x0040
41 #define GPIO_INT_RAWSTATUS	0x0044
42 #define GPIO_DEBOUNCE		0x0048
43 #define GPIO_PORTS_EOI		0x004c
44 #define GPIO_EXT_PORTA		0x0050
45 
46 #define GPIO_NUM_PINS		32
47 
48 #define HREAD4(sc, reg)							\
49 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
50 #define HWRITE4(sc, reg, val)						\
51 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
52 #define HSET4(sc, reg, bits)						\
53 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
54 #define HCLR4(sc, reg, bits)						\
55 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
56 
57 struct intrhand {
58 	int (*ih_func)(void *);		/* handler */
59 	void *ih_arg;			/* arg for handler */
60 	int ih_ipl;			/* IPL_* */
61 	int ih_irq;			/* IRQ number */
62 	int ih_level;			/* GPIO level */
63 	struct evcount	ih_count;
64 	char *ih_name;
65 	void *ih_sc;
66 };
67 
68 struct rkgpio_softc {
69 	struct device		sc_dev;
70 	bus_space_tag_t		sc_iot;
71 	bus_space_handle_t	sc_ioh;
72 	int			sc_node;
73 
74 	void			*sc_ih;
75 	int			sc_ipl;
76 	int			sc_irq;
77 	struct intrhand		*sc_handlers[GPIO_NUM_PINS];
78 	struct interrupt_controller sc_ic;
79 
80 	struct gpio_controller	sc_gc;
81 };
82 
83 int rkgpio_match(struct device *, void *, void *);
84 void rkgpio_attach(struct device *, struct device *, void *);
85 
86 struct cfattach	rkgpio_ca = {
87 	sizeof (struct rkgpio_softc), rkgpio_match, rkgpio_attach
88 };
89 
90 struct cfdriver rkgpio_cd = {
91 	NULL, "rkgpio", DV_DULL
92 };
93 
94 void	rkgpio_config_pin(void *, uint32_t *, int);
95 int	rkgpio_get_pin(void *, uint32_t *);
96 void	rkgpio_set_pin(void *, uint32_t *, int);
97 
98 int	rkgpio_intr(void *);
99 void	*rkgpio_intr_establish(void *, int *, int, struct cpu_info *,
100 	    int (*)(void *), void *, char *);
101 void	rkgpio_intr_disestablish(void *);
102 void	rkgpio_recalc_ipl(struct rkgpio_softc *);
103 void	rkgpio_intr_enable(void *);
104 void	rkgpio_intr_disable(void *);
105 void	rkgpio_intr_barrier(void *);
106 
107 int
108 rkgpio_match(struct device *parent, void *match, void *aux)
109 {
110 	struct fdt_attach_args *faa = aux;
111 
112 	return OF_is_compatible(faa->fa_node, "rockchip,gpio-bank");
113 }
114 
115 void
116 rkgpio_attach(struct device *parent, struct device *self, void *aux)
117 {
118 	struct rkgpio_softc *sc = (struct rkgpio_softc *)self;
119 	struct fdt_attach_args *faa = aux;
120 
121 	if (faa->fa_nreg < 1) {
122 		printf(": no registers\n");
123 		return;
124 	}
125 
126 	sc->sc_node = faa->fa_node;
127 	sc->sc_iot = faa->fa_iot;
128 
129 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
130 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
131 		printf(": can't map registers\n");
132 		return;
133 	}
134 
135 	sc->sc_gc.gc_node = faa->fa_node;
136 	sc->sc_gc.gc_cookie = sc;
137 	sc->sc_gc.gc_config_pin = rkgpio_config_pin;
138 	sc->sc_gc.gc_get_pin = rkgpio_get_pin;
139 	sc->sc_gc.gc_set_pin = rkgpio_set_pin;
140 	gpio_controller_register(&sc->sc_gc);
141 
142 	sc->sc_ipl = IPL_NONE;
143 	HWRITE4(sc, GPIO_INTMASK, ~0);
144 	HWRITE4(sc, GPIO_INTEN, ~0);
145 
146 	sc->sc_ic.ic_node = faa->fa_node;
147 	sc->sc_ic.ic_cookie = sc;
148 	sc->sc_ic.ic_establish = rkgpio_intr_establish;
149 	sc->sc_ic.ic_disestablish = rkgpio_intr_disestablish;
150 	sc->sc_ic.ic_enable = rkgpio_intr_enable;
151 	sc->sc_ic.ic_disable = rkgpio_intr_disable;
152 	sc->sc_ic.ic_barrier = rkgpio_intr_barrier;
153 	fdt_intr_register(&sc->sc_ic);
154 
155 	printf("\n");
156 }
157 
158 void
159 rkgpio_config_pin(void *cookie, uint32_t *cells, int config)
160 {
161 	struct rkgpio_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_SWPORTA_DDR, (1 << pin));
169 	else
170 		HCLR4(sc, GPIO_SWPORTA_DDR, (1 << pin));
171 }
172 
173 int
174 rkgpio_get_pin(void *cookie, uint32_t *cells)
175 {
176 	struct rkgpio_softc *sc = cookie;
177 	uint32_t pin = cells[0];
178 	uint32_t flags = cells[1];
179 	uint32_t reg;
180 	int val;
181 
182 	if (pin >= GPIO_NUM_PINS)
183 		return 0;
184 
185 	reg = HREAD4(sc, GPIO_EXT_PORTA);
186 	val = (reg >> pin) & 1;
187 	if (flags & GPIO_ACTIVE_LOW)
188 		val = !val;
189 	return val;
190 }
191 
192 void
193 rkgpio_set_pin(void *cookie, uint32_t *cells, int val)
194 {
195 	struct rkgpio_softc *sc = cookie;
196 	uint32_t pin = cells[0];
197 	uint32_t flags = cells[1];
198 
199 	if (pin >= GPIO_NUM_PINS)
200 		return;
201 
202 	if (flags & GPIO_ACTIVE_LOW)
203 		val = !val;
204 	if (val)
205 		HSET4(sc, GPIO_SWPORTA_DR, (1 << pin));
206 	else
207 		HCLR4(sc, GPIO_SWPORTA_DR, (1 << pin));
208 }
209 
210 int
211 rkgpio_intr(void *cookie)
212 {
213 	struct rkgpio_softc	*sc = (struct rkgpio_softc *)cookie;
214 	struct intrhand		*ih;
215 	uint32_t		 status, pending;
216 	int			 pin, s;
217 
218 	status = HREAD4(sc, GPIO_INT_STATUS);
219 	pending = status;
220 
221 	while (pending) {
222 		pin = ffs(pending) - 1;
223 
224 		if ((ih = sc->sc_handlers[pin]) != NULL) {
225 			s = splraise(ih->ih_ipl);
226 			if (ih->ih_func(ih->ih_arg))
227 				ih->ih_count.ec_count++;
228 			splx(s);
229 		}
230 
231 		pending &= ~(1 << pin);
232 	}
233 
234 	HWRITE4(sc, GPIO_PORTS_EOI, status);
235 
236 	return 1;
237 }
238 
239 void *
240 rkgpio_intr_establish(void *cookie, int *cells, int ipl,
241     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
242 {
243 	struct rkgpio_softc	*sc = (struct rkgpio_softc *)cookie;
244 	struct intrhand		*ih;
245 	int			 irqno = cells[0];
246 	int			 level = cells[1];
247 	int			 s;
248 
249 	if (irqno < 0 || irqno >= GPIO_NUM_PINS)
250 		panic("%s: bogus irqnumber %d: %s", __func__,
251 		     irqno, name);
252 
253 	if (sc->sc_handlers[irqno] != NULL)
254 		panic("%s: irqnumber %d reused: %s", __func__,
255 		     irqno, name);
256 
257 	if (ci != NULL && !CPU_IS_PRIMARY(ci))
258 		return NULL;
259 
260 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
261 	ih->ih_func = func;
262 	ih->ih_arg = arg;
263 	ih->ih_ipl = ipl;
264 	ih->ih_irq = irqno;
265 	ih->ih_name = name;
266 	ih->ih_level = level;
267 	ih->ih_sc = sc;
268 
269 	s = splhigh();
270 
271 	sc->sc_handlers[irqno] = ih;
272 
273 	if (name != NULL)
274 		evcount_attach(&ih->ih_count, name, &ih->ih_irq);
275 
276 #ifdef DEBUG_INTC
277 	printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl,
278 	    ih->ih_name);
279 #endif
280 
281 	rkgpio_recalc_ipl(sc);
282 
283 	switch (level) {
284 	case 1: /* rising */
285 		HSET4(sc, GPIO_INTTYPE_LEVEL, 1 << irqno);
286 		HSET4(sc, GPIO_INT_POLARITY, 1 << irqno);
287 		break;
288 	case 2: /* falling */
289 		HSET4(sc, GPIO_INTTYPE_LEVEL, 1 << irqno);
290 		HCLR4(sc, GPIO_INT_POLARITY, 1 << irqno);
291 		break;
292 	case 4: /* high */
293 		HCLR4(sc, GPIO_INTTYPE_LEVEL, 1 << irqno);
294 		HSET4(sc, GPIO_INT_POLARITY, 1 << irqno);
295 		break;
296 	case 8: /* low */
297 		HCLR4(sc, GPIO_INTTYPE_LEVEL, 1 << irqno);
298 		HCLR4(sc, GPIO_INT_POLARITY, 1 << irqno);
299 		break;
300 	default:
301 		panic("%s: unsupported trigger type", __func__);
302 	}
303 
304 	HCLR4(sc, GPIO_SWPORTA_DDR, 1 << irqno);
305 	HCLR4(sc, GPIO_INTMASK, 1 << irqno);
306 
307 	splx(s);
308 	return (ih);
309 }
310 
311 void
312 rkgpio_intr_disestablish(void *cookie)
313 {
314 	struct intrhand		*ih = cookie;
315 	struct rkgpio_softc	*sc = ih->ih_sc;
316 	int			 s;
317 
318 	s = splhigh();
319 
320 #ifdef DEBUG_INTC
321 	printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl,
322 	    ih->ih_name);
323 #endif
324 
325 	HSET4(sc, GPIO_INTMASK, 1 << ih->ih_irq);
326 
327 	sc->sc_handlers[ih->ih_irq] = NULL;
328 	if (ih->ih_name != NULL)
329 		evcount_detach(&ih->ih_count);
330 	free(ih, M_DEVBUF, sizeof(*ih));
331 
332 	rkgpio_recalc_ipl(sc);
333 
334 	splx(s);
335 }
336 
337 void
338 rkgpio_recalc_ipl(struct rkgpio_softc *sc)
339 {
340 	struct intrhand		*ih;
341 	int			 pin;
342 	int			 max = IPL_NONE;
343 	int			 min = IPL_HIGH;
344 
345 	for (pin = 0; pin < GPIO_NUM_PINS; pin++) {
346 		ih = sc->sc_handlers[pin];
347 		if (ih == NULL)
348 			continue;
349 
350 		if (ih->ih_ipl > max)
351 			max = ih->ih_ipl;
352 
353 		if (ih->ih_ipl < min)
354 			min = ih->ih_ipl;
355 	}
356 
357 	if (max == IPL_NONE)
358 		min = IPL_NONE;
359 
360 	if (sc->sc_ipl != max) {
361 		sc->sc_ipl = max;
362 
363 		if (sc->sc_ih != NULL)
364 			fdt_intr_disestablish(sc->sc_ih);
365 
366 		if (sc->sc_ipl != IPL_NONE)
367 			sc->sc_ih = fdt_intr_establish(sc->sc_node,
368 			    sc->sc_ipl, rkgpio_intr, sc, sc->sc_dev.dv_xname);
369 	}
370 }
371 
372 void
373 rkgpio_intr_enable(void *cookie)
374 {
375 	struct intrhand		*ih = cookie;
376 	struct rkgpio_softc	*sc = ih->ih_sc;
377 	int			 s;
378 
379 	s = splhigh();
380 	HCLR4(sc, GPIO_INTMASK, 1 << ih->ih_irq);
381 	splx(s);
382 }
383 
384 void
385 rkgpio_intr_disable(void *cookie)
386 {
387 	struct intrhand		*ih = cookie;
388 	struct rkgpio_softc	*sc = ih->ih_sc;
389 	int			 s;
390 
391 	s = splhigh();
392 	HSET4(sc, GPIO_INTMASK, 1 << ih->ih_irq);
393 	splx(s);
394 }
395 
396 void
397 rkgpio_intr_barrier(void *cookie)
398 {
399 	struct intrhand		*ih = cookie;
400 	struct rkgpio_softc	*sc = ih->ih_sc;
401 
402 	intr_barrier(sc->sc_ih);
403 }
404