xref: /openbsd/sys/dev/fdt/qcgpio_fdt.c (revision 3bef86f7)
1 /*	$OpenBSD: qcgpio_fdt.c,v 1.2 2022/11/08 11:51:34 patrick Exp $	*/
2 /*
3  * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/malloc.h>
20 #include <sys/systm.h>
21 
22 #include <machine/fdt.h>
23 
24 #include <dev/ofw/openfirm.h>
25 #include <dev/ofw/ofw_gpio.h>
26 #include <dev/ofw/fdt.h>
27 
28 /* Registers. */
29 #define TLMM_GPIO_CFG(pin)		(0x0000 + 0x1000 * (pin))
30 #define  TLMM_GPIO_CFG_OUT_EN				(1 << 9)
31 #define TLMM_GPIO_IN_OUT(pin)		(0x0004 + 0x1000 * (pin))
32 #define  TLMM_GPIO_IN_OUT_GPIO_IN			(1 << 0)
33 #define  TLMM_GPIO_IN_OUT_GPIO_OUT			(1 << 1)
34 #define TLMM_GPIO_INTR_CFG(pin)		(0x0008 + 0x1000 * (pin))
35 #define  TLMM_GPIO_INTR_CFG_TARGET_PROC_MASK		(0x7 << 5)
36 #define  TLMM_GPIO_INTR_CFG_TARGET_PROC_RPM		(0x3 << 5)
37 #define  TLMM_GPIO_INTR_CFG_INTR_RAW_STATUS_EN		(1 << 4)
38 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_MASK		(0x3 << 2)
39 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL		(0x0 << 2)
40 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_POS	(0x1 << 2)
41 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_NEG	(0x2 << 2)
42 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_BOTH	(0x3 << 2)
43 #define  TLMM_GPIO_INTR_CFG_INTR_POL_CTL		(1 << 1)
44 #define  TLMM_GPIO_INTR_CFG_INTR_ENABLE			(1 << 0)
45 #define TLMM_GPIO_INTR_STATUS(pin)	(0x000c + 0x1000 * (pin))
46 #define  TLMM_GPIO_INTR_STATUS_INTR_STATUS		(1 << 0)
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 qcgpio_intrhand {
58 	int (*ih_func)(void *);
59 	void *ih_arg;
60 	void *ih_sc;
61 	int ih_pin;
62 };
63 
64 struct qcgpio_softc {
65 	struct device		sc_dev;
66 
67 	bus_space_tag_t		sc_iot;
68 	bus_space_handle_t	sc_ioh;
69 
70 	void			*sc_ih;
71 
72 	uint32_t		sc_npins;
73 	struct qcgpio_intrhand	*sc_pin_ih;
74 
75 	struct gpio_controller	sc_gc;
76 	struct interrupt_controller sc_ic;
77 };
78 
79 int	qcgpio_fdt_match(struct device *, void *, void *);
80 void	qcgpio_fdt_attach(struct device *, struct device *, void *);
81 
82 const struct cfattach qcgpio_fdt_ca = {
83 	sizeof(struct qcgpio_softc), qcgpio_fdt_match, qcgpio_fdt_attach
84 };
85 
86 void	qcgpio_fdt_config_pin(void *, uint32_t *, int);
87 int	qcgpio_fdt_get_pin(void *, uint32_t *);
88 void	qcgpio_fdt_set_pin(void *, uint32_t *, int);
89 
90 void	*qcgpio_fdt_intr_establish(void *, int *, int, struct cpu_info *,
91 	    int (*)(void *), void *, char *);
92 void	qcgpio_fdt_intr_disestablish(void *);
93 void	qcgpio_fdt_intr_enable(void *);
94 void	qcgpio_fdt_intr_disable(void *);
95 void	qcgpio_fdt_intr_barrier(void *);
96 int	qcgpio_fdt_pin_intr(struct qcgpio_softc *, int);
97 int	qcgpio_fdt_intr(void *);
98 
99 int
100 qcgpio_fdt_match(struct device *parent, void *match, void *aux)
101 {
102 	struct fdt_attach_args *faa = aux;
103 
104 	return OF_is_compatible(faa->fa_node, "qcom,sc8280xp-tlmm");
105 }
106 
107 void
108 qcgpio_fdt_attach(struct device *parent, struct device *self, void *aux)
109 {
110 	struct fdt_attach_args *faa = aux;
111 	struct qcgpio_softc *sc = (struct qcgpio_softc *)self;
112 
113 	sc->sc_iot = faa->fa_iot;
114 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
115 	    0, &sc->sc_ioh)) {
116 		printf(": can't map registers\n");
117 		return;
118 	}
119 
120 	sc->sc_npins = 230;
121 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
122 	    M_DEVBUF, M_WAITOK | M_ZERO);
123 
124 	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO, qcgpio_fdt_intr,
125 	    sc, sc->sc_dev.dv_xname);
126 	if (sc->sc_ih == NULL) {
127 		printf(": can't establish interrupt\n");
128 		goto unmap;
129 	}
130 
131 	sc->sc_gc.gc_node = faa->fa_node;
132 	sc->sc_gc.gc_cookie = sc;
133 	sc->sc_gc.gc_config_pin = qcgpio_fdt_config_pin;
134 	sc->sc_gc.gc_get_pin = qcgpio_fdt_get_pin;
135 	sc->sc_gc.gc_set_pin = qcgpio_fdt_set_pin;
136 	gpio_controller_register(&sc->sc_gc);
137 
138 	sc->sc_ic.ic_node = faa->fa_node;
139 	sc->sc_ic.ic_cookie = sc;
140 	sc->sc_ic.ic_establish = qcgpio_fdt_intr_establish;
141 	sc->sc_ic.ic_disestablish = qcgpio_fdt_intr_disestablish;
142 	sc->sc_ic.ic_enable = qcgpio_fdt_intr_enable;
143 	sc->sc_ic.ic_disable = qcgpio_fdt_intr_disable;
144 	sc->sc_ic.ic_barrier = qcgpio_fdt_intr_barrier;
145 	fdt_intr_register(&sc->sc_ic);
146 
147 	printf("\n");
148 	return;
149 
150 unmap:
151 	if (sc->sc_ih)
152 		fdt_intr_disestablish(sc->sc_ih);
153 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
154 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
155 }
156 
157 void
158 qcgpio_fdt_config_pin(void *cookie, uint32_t *cells, int config)
159 {
160 	struct qcgpio_softc *sc = cookie;
161 	uint32_t pin = cells[0];
162 
163 	if (pin >= sc->sc_npins)
164 		return;
165 
166 	if (config & GPIO_CONFIG_OUTPUT)
167 		HSET4(sc, TLMM_GPIO_CFG(pin), TLMM_GPIO_CFG_OUT_EN);
168 	else
169 		HCLR4(sc, TLMM_GPIO_CFG(pin), TLMM_GPIO_CFG_OUT_EN);
170 }
171 
172 int
173 qcgpio_fdt_get_pin(void *cookie, uint32_t *cells)
174 {
175 	struct qcgpio_softc *sc = cookie;
176 	uint32_t pin = cells[0];
177 	uint32_t flags = cells[1];
178 	uint32_t reg;
179 	int val;
180 
181 	if (pin >= sc->sc_npins)
182 		return 0;
183 
184 	reg = HREAD4(sc, TLMM_GPIO_IN_OUT(pin));
185 	val = !!(reg & TLMM_GPIO_IN_OUT_GPIO_IN);
186 	if (flags & GPIO_ACTIVE_LOW)
187 		val = !val;
188 	return val;
189 }
190 
191 void
192 qcgpio_fdt_set_pin(void *cookie, uint32_t *cells, int val)
193 {
194 	struct qcgpio_softc *sc = cookie;
195 	uint32_t pin = cells[0];
196 	uint32_t flags = cells[1];
197 
198 	if (pin >= sc->sc_npins)
199 		return;
200 
201 	if (flags & GPIO_ACTIVE_LOW)
202 		val = !val;
203 
204 	if (val) {
205 		HSET4(sc, TLMM_GPIO_IN_OUT(pin),
206 		    TLMM_GPIO_IN_OUT_GPIO_OUT);
207 	} else {
208 		HCLR4(sc, TLMM_GPIO_IN_OUT(pin),
209 		    TLMM_GPIO_IN_OUT_GPIO_OUT);
210 	}
211 }
212 
213 void *
214 qcgpio_fdt_intr_establish(void *cookie, int *cells, int ipl,
215     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
216 {
217 	struct qcgpio_softc *sc = cookie;
218 	uint32_t reg;
219 	int pin = cells[0];
220 	int level = cells[1];
221 
222 	if (pin < 0 || pin >= sc->sc_npins)
223 		return NULL;
224 
225 	sc->sc_pin_ih[pin].ih_func = func;
226 	sc->sc_pin_ih[pin].ih_arg = arg;
227 	sc->sc_pin_ih[pin].ih_pin = pin;
228 	sc->sc_pin_ih[pin].ih_sc = sc;
229 
230 	reg = HREAD4(sc, TLMM_GPIO_INTR_CFG(pin));
231 	reg &= ~TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_MASK;
232 	reg &= ~TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
233 	switch (level) {
234 	case 1:
235 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_POS |
236 		    TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
237 		break;
238 	case 2:
239 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_NEG |
240 		    TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
241 		break;
242 	case 3:
243 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_BOTH;
244 		break;
245 	case 4:
246 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL |
247 		    TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
248 		break;
249 	case 8:
250 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL;
251 		break;
252 	default:
253 		printf("%s: unsupported interrupt mode/polarity\n",
254 		    sc->sc_dev.dv_xname);
255 		break;
256 	}
257 	reg &= ~TLMM_GPIO_INTR_CFG_TARGET_PROC_MASK;
258 	reg |= TLMM_GPIO_INTR_CFG_TARGET_PROC_RPM;
259 	reg |= TLMM_GPIO_INTR_CFG_INTR_RAW_STATUS_EN;
260 	reg |= TLMM_GPIO_INTR_CFG_INTR_ENABLE;
261 	HWRITE4(sc, TLMM_GPIO_INTR_CFG(pin), reg);
262 
263 	return &sc->sc_pin_ih[pin];
264 }
265 
266 void
267 qcgpio_fdt_intr_disestablish(void *cookie)
268 {
269 	struct qcgpio_intrhand *ih = cookie;
270 
271 	qcgpio_fdt_intr_disable(cookie);
272 	ih->ih_func = NULL;
273 }
274 
275 void
276 qcgpio_fdt_intr_enable(void *cookie)
277 {
278 	struct qcgpio_intrhand *ih = cookie;
279 	struct qcgpio_softc *sc = ih->ih_sc;
280 	int pin = ih->ih_pin;
281 
282 	if (pin < 0 || pin >= sc->sc_npins)
283 		return;
284 
285 	HSET4(sc, TLMM_GPIO_INTR_CFG(pin),
286 	    TLMM_GPIO_INTR_CFG_INTR_ENABLE);
287 }
288 
289 void
290 qcgpio_fdt_intr_disable(void *cookie)
291 {
292 	struct qcgpio_intrhand *ih = cookie;
293 	struct qcgpio_softc *sc = ih->ih_sc;
294 	int pin = ih->ih_pin;
295 
296 	if (pin < 0 || pin >= sc->sc_npins)
297 		return;
298 
299 	HCLR4(sc, TLMM_GPIO_INTR_CFG(pin),
300 	    TLMM_GPIO_INTR_CFG_INTR_ENABLE);
301 }
302 
303 void
304 qcgpio_fdt_intr_barrier(void *cookie)
305 {
306 	struct qcgpio_intrhand *ih = cookie;
307 	struct qcgpio_softc *sc = ih->ih_sc;
308 
309 	intr_barrier(sc->sc_ih);
310 }
311 
312 int
313 qcgpio_fdt_intr(void *arg)
314 {
315 	struct qcgpio_softc *sc = arg;
316 	int pin, handled = 0;
317 	uint32_t stat;
318 
319 	for (pin = 0; pin < sc->sc_npins; pin++) {
320 		if (sc->sc_pin_ih[pin].ih_func == NULL)
321 			continue;
322 
323 		stat = HREAD4(sc, TLMM_GPIO_INTR_STATUS(pin));
324 		if (stat & TLMM_GPIO_INTR_STATUS_INTR_STATUS) {
325 			sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
326 			handled = 1;
327 		}
328 		HWRITE4(sc, TLMM_GPIO_INTR_STATUS(pin),
329 		    stat & ~TLMM_GPIO_INTR_STATUS_INTR_STATUS);
330 	}
331 
332 	return handled;
333 }
334