xref: /openbsd-src/sys/dev/acpi/qcgpio.c (revision 3374c67d44f9b75b98444cbf63020f777792342e)
1 /*	$OpenBSD: qcgpio.c,v 1.8 2022/12/18 10:00:53 mglocker 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 <dev/acpi/acpireg.h>
23 #include <dev/acpi/acpivar.h>
24 #include <dev/acpi/acpidev.h>
25 #include <dev/acpi/amltypes.h>
26 #include <dev/acpi/dsdt.h>
27 
28 /* Registers. */
29 #define TLMM_GPIO_IN_OUT(pin)		(0x0004 + 0x1000 * (pin))
30 #define  TLMM_GPIO_IN_OUT_GPIO_IN			(1 << 0)
31 #define  TLMM_GPIO_IN_OUT_GPIO_OUT			(1 << 1)
32 #define TLMM_GPIO_INTR_CFG(pin)		(0x0008 + 0x1000 * (pin))
33 #define  TLMM_GPIO_INTR_CFG_TARGET_PROC_MASK		(0x7 << 5)
34 #define  TLMM_GPIO_INTR_CFG_TARGET_PROC_RPM		(0x3 << 5)
35 #define  TLMM_GPIO_INTR_CFG_INTR_RAW_STATUS_EN		(1 << 4)
36 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_MASK		(0x3 << 2)
37 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL		(0x0 << 2)
38 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_POS	(0x1 << 2)
39 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_NEG	(0x2 << 2)
40 #define  TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_BOTH	(0x3 << 2)
41 #define  TLMM_GPIO_INTR_CFG_INTR_POL_CTL		(1 << 1)
42 #define  TLMM_GPIO_INTR_CFG_INTR_ENABLE			(1 << 0)
43 #define TLMM_GPIO_INTR_STATUS(pin)	(0x000c + 0x1000 * (pin))
44 #define  TLMM_GPIO_INTR_STATUS_INTR_STATUS		(1 << 0)
45 
46 /* SC7180 has multiple tiles */
47 #define QCGPIO_SC7180_WEST	0x00100000
48 #define QCGPIO_SC7180_NORTH	0x00500000
49 #define QCGPIO_SC7180_SOUTH	0x00900000
50 
51 #define HREAD4(sc, reg)							\
52 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
53 #define HWRITE4(sc, reg, val)						\
54 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
55 #define HSET4(sc, reg, bits)						\
56 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
57 #define HCLR4(sc, reg, bits)						\
58 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
59 
60 struct qcgpio_intrhand {
61 	int (*ih_func)(void *);
62 	void *ih_arg;
63 };
64 
65 struct qcgpio_softc {
66 	struct device		sc_dev;
67 	struct acpi_softc	*sc_acpi;
68 	struct aml_node		*sc_node;
69 
70 	bus_space_tag_t		sc_iot;
71 	bus_space_handle_t	sc_ioh;
72 
73 	void			*sc_ih;
74 
75 	uint32_t		sc_npins;
76 	int			(*sc_pin_map)(int, bus_size_t *);
77 	struct qcgpio_intrhand	*sc_pin_ih;
78 
79 	struct acpi_gpio sc_gpio;
80 };
81 
82 int	qcgpio_acpi_match(struct device *, void *, void *);
83 void	qcgpio_acpi_attach(struct device *, struct device *, void *);
84 
85 const struct cfattach qcgpio_acpi_ca = {
86 	sizeof(struct qcgpio_softc), qcgpio_acpi_match, qcgpio_acpi_attach
87 };
88 
89 struct cfdriver qcgpio_cd = {
90 	NULL, "qcgpio", DV_DULL
91 };
92 
93 const char *qcgpio_hids[] = {
94 	"QCOM060C",
95 	"QCOM080D",
96 	NULL
97 };
98 
99 int	qcgpio_sc7180_pin_map(int, bus_size_t *);
100 int	qcgpio_sc8280xp_pin_map(int, bus_size_t *);
101 
102 int	qcgpio_read_pin(void *, int);
103 void	qcgpio_write_pin(void *, int, int);
104 void	qcgpio_intr_establish(void *, int, int, int (*)(void *), void *);
105 void	qcgpio_intr_enable(void *, int);
106 void	qcgpio_intr_disable(void *, int);
107 int	qcgpio_pin_intr(struct qcgpio_softc *, int);
108 int	qcgpio_intr(void *);
109 
110 int
111 qcgpio_acpi_match(struct device *parent, void *match, void *aux)
112 {
113 	struct acpi_attach_args *aaa = aux;
114 	struct cfdata *cf = match;
115 
116 	if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1)
117 		return 0;
118 	return acpi_matchhids(aaa, qcgpio_hids, cf->cf_driver->cd_name);
119 }
120 
121 void
122 qcgpio_acpi_attach(struct device *parent, struct device *self, void *aux)
123 {
124 	struct acpi_attach_args *aaa = aux;
125 	struct qcgpio_softc *sc = (struct qcgpio_softc *)self;
126 
127 	sc->sc_acpi = (struct acpi_softc *)parent;
128 	sc->sc_node = aaa->aaa_node;
129 	printf(" %s", sc->sc_node->name);
130 
131 	printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
132 
133 	sc->sc_iot = aaa->aaa_bst[0];
134 	if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0],
135 	    0, &sc->sc_ioh)) {
136 		printf(": can't map registers\n");
137 		return;
138 	}
139 
140 	if (strcmp(aaa->aaa_dev, "QCOM080D") == 0) {
141 		sc->sc_npins = 119;
142 		sc->sc_pin_map = qcgpio_sc7180_pin_map;
143 	} else if (strcmp(aaa->aaa_dev, "QCOM060C") == 0) {
144 		sc->sc_npins = 228;
145 		sc->sc_pin_map = qcgpio_sc8280xp_pin_map;
146 	}
147 	KASSERT(sc->sc_npins != 0);
148 
149 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
150 	    M_DEVBUF, M_WAITOK | M_ZERO);
151 
152 	printf(" irq %d", aaa->aaa_irq[0]);
153 
154 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0],
155 	    aaa->aaa_irq_flags[0], IPL_BIO, qcgpio_intr,
156 	    sc, sc->sc_dev.dv_xname);
157 	if (sc->sc_ih == NULL) {
158 		printf(": can't establish interrupt\n");
159 		goto unmap;
160 	}
161 
162 	sc->sc_gpio.cookie = sc;
163 	sc->sc_gpio.read_pin = qcgpio_read_pin;
164 	sc->sc_gpio.write_pin = qcgpio_write_pin;
165 	sc->sc_gpio.intr_establish = qcgpio_intr_establish;
166 	sc->sc_gpio.intr_enable = qcgpio_intr_enable;
167 	sc->sc_gpio.intr_disable = qcgpio_intr_disable;
168 	sc->sc_node->gpio = &sc->sc_gpio;
169 
170 	printf("\n");
171 
172 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
173 	return;
174 
175 unmap:
176 	if (sc->sc_ih)
177 		acpi_intr_disestablish(sc->sc_ih);
178 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
179 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, aaa->aaa_size[0]);
180 }
181 
182 int
183 qcgpio_sc7180_pin_map(int pin, bus_size_t *off)
184 {
185 	switch (pin) {
186 	case 30:
187 		*off = QCGPIO_SC7180_SOUTH;
188 		return 30;
189 #if 0
190 	/* XXX: Disable until we can fix the interrupt storm. */
191 	case 32:
192 	case 0x140:
193 		*off = QCGPIO_SC7180_NORTH;
194 		return 32;
195 #endif
196 	case 33:
197 	case 0x180:
198 		*off = QCGPIO_SC7180_NORTH;
199 		return 33;
200 	case 94:
201 	case 0x1c0:
202 		*off = QCGPIO_SC7180_SOUTH;
203 		return 94;
204 	default:
205 		return -1;
206 	}
207 }
208 
209 int
210 qcgpio_sc8280xp_pin_map(int pin, bus_size_t *off)
211 {
212 	switch (pin) {
213 	case 107:
214 	case 175:
215 		return pin;
216 	case 0x2c0:
217 		return 107;
218 	case 0x340:
219 		return 104;
220 	case 0x380:
221 		return 182;
222 	default:
223 		return -1;
224 	}
225 }
226 
227 int
228 qcgpio_read_pin(void *cookie, int pin)
229 {
230 	struct qcgpio_softc *sc = cookie;
231 	bus_size_t off = 0;
232 	uint32_t reg;
233 
234 	pin = sc->sc_pin_map(pin, &off);
235 	if (pin < 0 || pin >= sc->sc_npins)
236 		return 0;
237 
238 	reg = HREAD4(sc, off + TLMM_GPIO_IN_OUT(pin));
239 	return !!(reg & TLMM_GPIO_IN_OUT_GPIO_IN);
240 }
241 
242 void
243 qcgpio_write_pin(void *cookie, int pin, int val)
244 {
245 	struct qcgpio_softc *sc = cookie;
246 	bus_size_t off = 0;
247 
248 	pin = sc->sc_pin_map(pin, &off);
249 	if (pin < 0 || pin >= sc->sc_npins)
250 		return;
251 
252 	if (val) {
253 		HSET4(sc, off + TLMM_GPIO_IN_OUT(pin),
254 		    TLMM_GPIO_IN_OUT_GPIO_OUT);
255 	} else {
256 		HCLR4(sc, off + TLMM_GPIO_IN_OUT(pin),
257 		    TLMM_GPIO_IN_OUT_GPIO_OUT);
258 	}
259 }
260 
261 void
262 qcgpio_intr_establish(void *cookie, int pin, int flags,
263     int (*func)(void *), void *arg)
264 {
265 	struct qcgpio_softc *sc = cookie;
266 	bus_size_t off = 0;
267 	uint32_t reg;
268 
269 	pin = sc->sc_pin_map(pin, &off);
270 	if (pin < 0 || pin >= sc->sc_npins)
271 		return;
272 
273 	sc->sc_pin_ih[pin].ih_func = func;
274 	sc->sc_pin_ih[pin].ih_arg = arg;
275 
276 	reg = HREAD4(sc, off + TLMM_GPIO_INTR_CFG(pin));
277 	reg &= ~TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_MASK;
278 	reg &= ~TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
279 	switch (flags & (LR_GPIO_MODE | LR_GPIO_POLARITY)) {
280 	case LR_GPIO_LEVEL | LR_GPIO_ACTLO:
281 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL;
282 		break;
283 	case LR_GPIO_LEVEL | LR_GPIO_ACTHI:
284 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_LEVEL |
285 		    TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
286 		break;
287 	case LR_GPIO_EDGE | LR_GPIO_ACTLO:
288 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_NEG |
289 		    TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
290 		break;
291 	case LR_GPIO_EDGE | LR_GPIO_ACTHI:
292 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_POS |
293 		    TLMM_GPIO_INTR_CFG_INTR_POL_CTL;
294 		break;
295 	case LR_GPIO_EDGE | LR_GPIO_ACTBOTH:
296 		reg |= TLMM_GPIO_INTR_CFG_INTR_DECT_CTL_EDGE_BOTH;
297 		break;
298 	default:
299 		printf("%s: unsupported interrupt mode/polarity\n",
300 		    sc->sc_dev.dv_xname);
301 		break;
302 	}
303 	reg &= ~TLMM_GPIO_INTR_CFG_TARGET_PROC_MASK;
304 	reg |= TLMM_GPIO_INTR_CFG_TARGET_PROC_RPM;
305 	reg |= TLMM_GPIO_INTR_CFG_INTR_RAW_STATUS_EN;
306 	reg |= TLMM_GPIO_INTR_CFG_INTR_ENABLE;
307 	HWRITE4(sc, off + TLMM_GPIO_INTR_CFG(pin), reg);
308 }
309 
310 void
311 qcgpio_intr_enable(void *cookie, int pin)
312 {
313 	struct qcgpio_softc *sc = cookie;
314 	bus_size_t off = 0;
315 
316 	pin = sc->sc_pin_map(pin, &off);
317 	if (pin < 0 || pin >= sc->sc_npins)
318 		return;
319 
320 	HSET4(sc, off + TLMM_GPIO_INTR_CFG(pin),
321 	    TLMM_GPIO_INTR_CFG_INTR_ENABLE);
322 }
323 
324 void
325 qcgpio_intr_disable(void *cookie, int pin)
326 {
327 	struct qcgpio_softc *sc = cookie;
328 	bus_size_t off = 0;
329 
330 	pin = sc->sc_pin_map(pin, &off);
331 	if (pin < 0 || pin >= sc->sc_npins)
332 		return;
333 
334 	HCLR4(sc, off + TLMM_GPIO_INTR_CFG(pin),
335 	    TLMM_GPIO_INTR_CFG_INTR_ENABLE);
336 }
337 
338 int
339 qcgpio_intr(void *arg)
340 {
341 	struct qcgpio_softc *sc = arg;
342 	int pin, handled = 0;
343 	bus_size_t off = 0;
344 	uint32_t stat;
345 
346 	for (pin = 0; pin < sc->sc_npins; pin++) {
347 		if (sc->sc_pin_ih[pin].ih_func == NULL)
348 			continue;
349 
350 		sc->sc_pin_map(pin, &off);
351 
352 		stat = HREAD4(sc, off + TLMM_GPIO_INTR_STATUS(pin));
353 		if (stat & TLMM_GPIO_INTR_STATUS_INTR_STATUS) {
354 			sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
355 			handled = 1;
356 		}
357 		HWRITE4(sc, off + TLMM_GPIO_INTR_STATUS(pin),
358 		    stat & ~TLMM_GPIO_INTR_STATUS_INTR_STATUS);
359 	}
360 
361 	return handled;
362 }
363