xref: /openbsd/sys/arch/riscv64/dev/sfgpio.c (revision e309ca49)
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