xref: /openbsd-src/sys/dev/fdt/rkgpio.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: rkgpio.c,v 1.2 2019/05/11 14:56:12 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, int (*)(void *),
100 	    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 
106 int
107 rkgpio_match(struct device *parent, void *match, void *aux)
108 {
109 	struct fdt_attach_args *faa = aux;
110 
111 	return OF_is_compatible(faa->fa_node, "rockchip,gpio-bank");
112 }
113 
114 void
115 rkgpio_attach(struct device *parent, struct device *self, void *aux)
116 {
117 	struct rkgpio_softc *sc = (struct rkgpio_softc *)self;
118 	struct fdt_attach_args *faa = aux;
119 
120 	if (faa->fa_nreg < 1) {
121 		printf(": no registers\n");
122 		return;
123 	}
124 
125 	sc->sc_node = faa->fa_node;
126 	sc->sc_iot = faa->fa_iot;
127 
128 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
129 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
130 		printf(": can't map registers\n");
131 		return;
132 	}
133 
134 	sc->sc_gc.gc_node = faa->fa_node;
135 	sc->sc_gc.gc_cookie = sc;
136 	sc->sc_gc.gc_config_pin = rkgpio_config_pin;
137 	sc->sc_gc.gc_get_pin = rkgpio_get_pin;
138 	sc->sc_gc.gc_set_pin = rkgpio_set_pin;
139 	gpio_controller_register(&sc->sc_gc);
140 
141 	sc->sc_ipl = IPL_NONE;
142 	HWRITE4(sc, GPIO_INTMASK, ~0);
143 	HWRITE4(sc, GPIO_INTEN, ~0);
144 
145 	sc->sc_ic.ic_node = faa->fa_node;
146 	sc->sc_ic.ic_cookie = sc;
147 	sc->sc_ic.ic_establish = rkgpio_intr_establish;
148 	sc->sc_ic.ic_disestablish = rkgpio_intr_disestablish;
149 	sc->sc_ic.ic_enable = rkgpio_intr_enable;
150 	sc->sc_ic.ic_disable = rkgpio_intr_disable;
151 	fdt_intr_register(&sc->sc_ic);
152 
153 	printf("\n");
154 }
155 
156 void
157 rkgpio_config_pin(void *cookie, uint32_t *cells, int config)
158 {
159 	struct rkgpio_softc *sc = cookie;
160 	uint32_t pin = cells[0];
161 
162 	if (pin > 32)
163 		return;
164 
165 	if (config & GPIO_CONFIG_OUTPUT)
166 		HSET4(sc, GPIO_SWPORTA_DDR, (1 << pin));
167 	else
168 		HCLR4(sc, GPIO_SWPORTA_DDR, (1 << pin));
169 }
170 
171 int
172 rkgpio_get_pin(void *cookie, uint32_t *cells)
173 {
174 	struct rkgpio_softc *sc = cookie;
175 	uint32_t pin = cells[0];
176 	uint32_t flags = cells[1];
177 	uint32_t reg;
178 	int val;
179 
180 	if (pin > 32)
181 		return 0;
182 
183 	reg = HREAD4(sc, GPIO_EXT_PORTA);
184 	reg &= (1 << pin);
185 	val = (reg >> pin) & 1;
186 	if (flags & GPIO_ACTIVE_LOW)
187 		val = !val;
188 	return val;
189 }
190 
191 void
192 rkgpio_set_pin(void *cookie, uint32_t *cells, int val)
193 {
194 	struct rkgpio_softc *sc = cookie;
195 	uint32_t pin = cells[0];
196 	uint32_t flags = cells[1];
197 
198 	if (pin > 32)
199 		return;
200 
201 	if (flags & GPIO_ACTIVE_LOW)
202 		val = !val;
203 	if (val)
204 		HSET4(sc, GPIO_SWPORTA_DR, (1 << pin));
205 	else
206 		HCLR4(sc, GPIO_SWPORTA_DR, (1 << pin));
207 }
208 
209 int
210 rkgpio_intr(void *cookie)
211 {
212 	struct rkgpio_softc	*sc = (struct rkgpio_softc *)cookie;
213 	struct intrhand		*ih;
214 	uint32_t		 status, pending;
215 	int			 pin, s;
216 
217 	status = HREAD4(sc, GPIO_INT_STATUS);
218 	pending = status;
219 
220 	while (pending) {
221 		pin = ffs(pending) - 1;
222 
223 		if ((ih = sc->sc_handlers[pin]) != NULL) {
224 			s = splraise(ih->ih_ipl);
225 			if (ih->ih_func(ih->ih_arg))
226 				ih->ih_count.ec_count++;
227 			splx(s);
228 		}
229 
230 		pending &= ~(1 << pin);
231 	}
232 
233 	HWRITE4(sc, GPIO_PORTS_EOI, status);
234 
235 	return 1;
236 }
237 
238 void *
239 rkgpio_intr_establish(void *cookie, int *cells, int ipl,
240     int (*func)(void *), void *arg, char *name)
241 {
242 	struct rkgpio_softc	*sc = (struct rkgpio_softc *)cookie;
243 	struct intrhand		*ih;
244 	int			 irqno = cells[0];
245 	int			 level = cells[1];
246 	int			 s;
247 
248 	if (irqno < 0 || irqno >= GPIO_NUM_PINS)
249 		panic("%s: bogus irqnumber %d: %s", __func__,
250 		     irqno, name);
251 
252 	if (sc->sc_handlers[irqno] != NULL)
253 		panic("%s: irqnumber %d reused: %s", __func__,
254 		     irqno, name);
255 
256 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
257 	ih->ih_func = func;
258 	ih->ih_arg = arg;
259 	ih->ih_ipl = ipl;
260 	ih->ih_irq = irqno;
261 	ih->ih_name = name;
262 	ih->ih_level = level;
263 	ih->ih_sc = sc;
264 
265 	s = splhigh();
266 
267 	sc->sc_handlers[irqno] = ih;
268 
269 	if (name != NULL)
270 		evcount_attach(&ih->ih_count, name, &ih->ih_irq);
271 
272 #ifdef DEBUG_INTC
273 	printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl,
274 	    ih->ih_name);
275 #endif
276 
277 	rkgpio_recalc_ipl(sc);
278 
279 	switch (level) {
280 	case 1: /* rising */
281 		HSET4(sc, GPIO_INTTYPE_LEVEL, 1 << irqno);
282 		HSET4(sc, GPIO_INT_POLARITY, 1 << irqno);
283 		break;
284 	case 2: /* falling */
285 		HSET4(sc, GPIO_INTTYPE_LEVEL, 1 << irqno);
286 		HCLR4(sc, GPIO_INT_POLARITY, 1 << irqno);
287 		break;
288 	case 4: /* high */
289 		HCLR4(sc, GPIO_INTTYPE_LEVEL, 1 << irqno);
290 		HSET4(sc, GPIO_INT_POLARITY, 1 << irqno);
291 		break;
292 	case 8: /* low */
293 		HCLR4(sc, GPIO_INTTYPE_LEVEL, 1 << irqno);
294 		HCLR4(sc, GPIO_INT_POLARITY, 1 << irqno);
295 		break;
296 	default:
297 		panic("%s: unsupported trigger type", __func__);
298 	}
299 
300 	HCLR4(sc, GPIO_SWPORTA_DDR, 1 << irqno);
301 	HCLR4(sc, GPIO_INTMASK, 1 << irqno);
302 
303 	splx(s);
304 	return (ih);
305 }
306 
307 void
308 rkgpio_intr_disestablish(void *cookie)
309 {
310 	struct intrhand		*ih = cookie;
311 	struct rkgpio_softc	*sc = ih->ih_sc;
312 	int			 s;
313 
314 	s = splhigh();
315 
316 #ifdef DEBUG_INTC
317 	printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl,
318 	    ih->ih_name);
319 #endif
320 
321 	HSET4(sc, GPIO_INTMASK, 1 << ih->ih_irq);
322 
323 	sc->sc_handlers[ih->ih_irq] = NULL;
324 	if (ih->ih_name != NULL)
325 		evcount_detach(&ih->ih_count);
326 	free(ih, M_DEVBUF, sizeof(*ih));
327 
328 	rkgpio_recalc_ipl(sc);
329 
330 	splx(s);
331 }
332 
333 void
334 rkgpio_recalc_ipl(struct rkgpio_softc *sc)
335 {
336 	struct intrhand		*ih;
337 	int			 pin;
338 	int			 max = IPL_NONE;
339 	int			 min = IPL_HIGH;
340 
341 	for (pin = 0; pin < GPIO_NUM_PINS; pin++) {
342 		ih = sc->sc_handlers[pin];
343 		if (ih == NULL)
344 			continue;
345 
346 		if (ih->ih_ipl > max)
347 			max = ih->ih_ipl;
348 
349 		if (ih->ih_ipl < min)
350 			min = ih->ih_ipl;
351 	}
352 
353 	if (max == IPL_NONE)
354 		min = IPL_NONE;
355 
356 	if (sc->sc_ipl != max) {
357 		sc->sc_ipl = max;
358 
359 		if (sc->sc_ih != NULL)
360 			fdt_intr_disestablish(sc->sc_ih);
361 
362 		if (sc->sc_ipl != IPL_NONE)
363 			sc->sc_ih = fdt_intr_establish(sc->sc_node,
364 			    sc->sc_ipl, rkgpio_intr, sc, sc->sc_dev.dv_xname);
365 	}
366 }
367 
368 void
369 rkgpio_intr_enable(void *cookie)
370 {
371 	struct intrhand		*ih = cookie;
372 	struct rkgpio_softc	*sc = ih->ih_sc;
373 	int			 s;
374 
375 	s = splhigh();
376 	HCLR4(sc, GPIO_INTMASK, 1 << ih->ih_irq);
377 	splx(s);
378 }
379 
380 void
381 rkgpio_intr_disable(void *cookie)
382 {
383 	struct intrhand		*ih = cookie;
384 	struct rkgpio_softc	*sc = ih->ih_sc;
385 	int			 s;
386 
387 	s = splhigh();
388 	HSET4(sc, GPIO_INTMASK, 1 << ih->ih_irq);
389 	splx(s);
390 }
391