xref: /openbsd/sys/dev/acpi/chvgpio.c (revision 244d7b17)
1 /*	$OpenBSD: chvgpio.c,v 1.13 2022/10/20 20:40:57 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2016 Mark Kettenis
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 #define CHVGPIO_INTERRUPT_STATUS	0x0300
29 #define CHVGPIO_INTERRUPT_MASK		0x0380
30 #define CHVGPIO_PAD_CFG0		0x4400
31 #define CHVGPIO_PAD_CFG1		0x4404
32 
33 #define CHVGPIO_PAD_CFG0_GPIORXSTATE		0x00000001
34 #define CHVGPIO_PAD_CFG0_GPIOTXSTATE		0x00000002
35 #define CHVGPIO_PAD_CFG0_INTSEL_MASK		0xf0000000
36 #define CHVGPIO_PAD_CFG0_INTSEL_SHIFT		28
37 
38 #define CHVGPIO_PAD_CFG1_INTWAKECFG_MASK	0x00000007
39 #define CHVGPIO_PAD_CFG1_INTWAKECFG_FALLING	0x00000001
40 #define CHVGPIO_PAD_CFG1_INTWAKECFG_RISING	0x00000002
41 #define CHVGPIO_PAD_CFG1_INTWAKECFG_BOTH	0x00000003
42 #define CHVGPIO_PAD_CFG1_INTWAKECFG_LEVEL	0x00000004
43 #define CHVGPIO_PAD_CFG1_INVRXTX_MASK		0x000000f0
44 #define CHVGPIO_PAD_CFG1_INVRXTX_RXDATA		0x00000040
45 
46 /* OEM defined RegionSpace. */
47 #define CHVGPIO_REGIONSPACE_BASE	0x90
48 
49 struct chvgpio_intrhand {
50 	int (*ih_func)(void *);
51 	void *ih_arg;
52 };
53 
54 struct chvgpio_softc {
55 	struct device sc_dev;
56 	struct acpi_softc *sc_acpi;
57 	struct aml_node *sc_node;
58 
59 	bus_space_tag_t sc_memt;
60 	bus_space_handle_t sc_memh;
61 	bus_size_t sc_size;
62 	void *sc_ih;
63 
64 	const int *sc_pins;
65 	int sc_npins;
66 	int sc_ngroups;
67 
68 	struct chvgpio_intrhand sc_pin_ih[16];
69 
70 	struct acpi_gpio sc_gpio;
71 };
72 
73 static inline int
chvgpio_pad_cfg0_offset(int pin)74 chvgpio_pad_cfg0_offset(int pin)
75 {
76 	return (CHVGPIO_PAD_CFG0 + 1024 * (pin / 15) + 8 * (pin % 15));
77 }
78 
79 static inline int
chvgpio_read_pad_cfg0(struct chvgpio_softc * sc,int pin)80 chvgpio_read_pad_cfg0(struct chvgpio_softc *sc, int pin)
81 {
82 	return bus_space_read_4(sc->sc_memt, sc->sc_memh,
83 	    chvgpio_pad_cfg0_offset(pin));
84 }
85 
86 static inline void
chvgpio_write_pad_cfg0(struct chvgpio_softc * sc,int pin,uint32_t val)87 chvgpio_write_pad_cfg0(struct chvgpio_softc *sc, int pin, uint32_t val)
88 {
89 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
90 	    chvgpio_pad_cfg0_offset(pin), val);
91 }
92 
93 static inline int
chvgpio_read_pad_cfg1(struct chvgpio_softc * sc,int pin)94 chvgpio_read_pad_cfg1(struct chvgpio_softc *sc, int pin)
95 {
96 	return bus_space_read_4(sc->sc_memt, sc->sc_memh,
97 	    chvgpio_pad_cfg0_offset(pin) + 4);
98 }
99 
100 static inline void
chvgpio_write_pad_cfg1(struct chvgpio_softc * sc,int pin,uint32_t val)101 chvgpio_write_pad_cfg1(struct chvgpio_softc *sc, int pin, uint32_t val)
102 {
103 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
104 	    chvgpio_pad_cfg0_offset(pin) + 4, val);
105 }
106 
107 int	chvgpio_match(struct device *, void *, void *);
108 void	chvgpio_attach(struct device *, struct device *, void *);
109 
110 const struct cfattach chvgpio_ca = {
111 	sizeof(struct chvgpio_softc), chvgpio_match, chvgpio_attach
112 };
113 
114 struct cfdriver chvgpio_cd = {
115 	NULL, "chvgpio", DV_DULL
116 };
117 
118 const char *chvgpio_hids[] = {
119 	"INT33FF",
120 	NULL
121 };
122 
123 /*
124  * The pads for the pins are arranged in groups of maximal 15 pins.
125  * The arrays below give the number of pins per group, such that we
126  * can validate the (untrusted) pin numbers from ACPI.
127  */
128 
129 const int chv_southwest_pins[] = {
130 	8, 8, 8, 8, 8, 8, 8, -1
131 };
132 
133 const int chv_north_pins[] = {
134 	9, 13, 12, 12, 13, -1
135 };
136 
137 const int chv_east_pins[] = {
138 	12, 12, -1
139 };
140 
141 const int chv_southeast_pins[] = {
142 	8, 12, 6, 8, 10, 11, -1
143 };
144 
145 int	chvgpio_check_pin(struct chvgpio_softc *, int);
146 int	chvgpio_read_pin(void *, int);
147 void	chvgpio_write_pin(void *, int, int);
148 void	chvgpio_intr_establish(void *, int, int, int (*)(void *), void *);
149 void	chvgpio_intr_enable(void *, int);
150 void	chvgpio_intr_disable(void *, int);
151 int	chvgpio_intr(void *);
152 int	chvgpio_opreg_handler(void *, int, uint64_t, int, uint64_t *);
153 
154 int
chvgpio_match(struct device * parent,void * match,void * aux)155 chvgpio_match(struct device *parent, void *match, void *aux)
156 {
157 	struct acpi_attach_args *aaa = aux;
158 	struct cfdata *cf = match;
159 
160 	if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1)
161 		return 0;
162 	return acpi_matchhids(aaa, chvgpio_hids, cf->cf_driver->cd_name);
163 }
164 
165 void
chvgpio_attach(struct device * parent,struct device * self,void * aux)166 chvgpio_attach(struct device *parent, struct device *self, void *aux)
167 {
168 	struct chvgpio_softc *sc = (struct chvgpio_softc *)self;
169 	struct acpi_attach_args *aaa = aux;
170 	int64_t uid;
171 	int i;
172 
173 	sc->sc_acpi = (struct acpi_softc *)parent;
174 	sc->sc_node = aaa->aaa_node;
175 	printf(" %s", sc->sc_node->name);
176 
177 	if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) {
178 		printf(": can't find uid\n");
179 		return;
180 	}
181 
182 	printf(" uid %lld", uid);
183 
184 	switch (uid) {
185 	case 1:
186 		sc->sc_pins = chv_southwest_pins;
187 		break;
188 	case 2:
189 		sc->sc_pins = chv_north_pins;
190 		break;
191 	case 3:
192 		sc->sc_pins = chv_east_pins;
193 		break;
194 	case 4:
195 		sc->sc_pins = chv_southeast_pins;
196 		break;
197 	default:
198 		printf("\n");
199 		return;
200 	}
201 
202 	for (i = 0; sc->sc_pins[i] >= 0; i++) {
203 		sc->sc_npins += sc->sc_pins[i];
204 		sc->sc_ngroups++;
205 	}
206 
207 	printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
208 	printf(" irq %d", aaa->aaa_irq[0]);
209 
210 	sc->sc_memt = aaa->aaa_bst[0];
211 	sc->sc_size = aaa->aaa_size[0];
212 	if (bus_space_map(sc->sc_memt, aaa->aaa_addr[0], aaa->aaa_size[0],
213 	    0, &sc->sc_memh)) {
214 		printf(": can't map registers\n");
215 		return;
216 	}
217 
218 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
219 	    IPL_BIO, chvgpio_intr, sc, sc->sc_dev.dv_xname);
220 	if (sc->sc_ih == NULL) {
221 		printf(": can't establish interrupt\n");
222 		goto unmap;
223 	}
224 
225 	sc->sc_gpio.cookie = sc;
226 	sc->sc_gpio.read_pin = chvgpio_read_pin;
227 	sc->sc_gpio.write_pin = chvgpio_write_pin;
228 	sc->sc_gpio.intr_establish = chvgpio_intr_establish;
229 	sc->sc_gpio.intr_enable = chvgpio_intr_enable;
230 	sc->sc_gpio.intr_disable = chvgpio_intr_disable;
231 	sc->sc_node->gpio = &sc->sc_gpio;
232 
233 	/* Mask and ack all interrupts. */
234 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
235 	    CHVGPIO_INTERRUPT_MASK, 0);
236 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
237 	    CHVGPIO_INTERRUPT_STATUS, 0xffff);
238 
239 	printf(", %d pins\n", sc->sc_npins);
240 
241 	/* Register OEM defined address space. */
242 	aml_register_regionspace(sc->sc_node, CHVGPIO_REGIONSPACE_BASE + uid,
243 	    sc, chvgpio_opreg_handler);
244 
245 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
246 	return;
247 
248 unmap:
249 	bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_size);
250 }
251 
252 int
chvgpio_check_pin(struct chvgpio_softc * sc,int pin)253 chvgpio_check_pin(struct chvgpio_softc *sc, int pin)
254 {
255 	if (pin < 0)
256 		return EINVAL;
257 	if ((pin / 15) >= sc->sc_ngroups)
258 		return EINVAL;
259 	if ((pin % 15) >= sc->sc_pins[pin / 15])
260 		return EINVAL;
261 
262 	return 0;
263 }
264 
265 int
chvgpio_read_pin(void * cookie,int pin)266 chvgpio_read_pin(void *cookie, int pin)
267 {
268 	struct chvgpio_softc *sc = cookie;
269 	uint32_t reg;
270 
271 	KASSERT(chvgpio_check_pin(sc, pin) == 0);
272 
273 	reg = chvgpio_read_pad_cfg0(sc, pin);
274 	return (reg & CHVGPIO_PAD_CFG0_GPIORXSTATE);
275 }
276 
277 void
chvgpio_write_pin(void * cookie,int pin,int value)278 chvgpio_write_pin(void *cookie, int pin, int value)
279 {
280 	struct chvgpio_softc *sc = cookie;
281 	uint32_t reg;
282 
283 	KASSERT(chvgpio_check_pin(sc, pin) == 0);
284 
285 	reg = chvgpio_read_pad_cfg0(sc, pin);
286 	if (value)
287 		reg |= CHVGPIO_PAD_CFG0_GPIOTXSTATE;
288 	else
289 		reg &= ~CHVGPIO_PAD_CFG0_GPIOTXSTATE;
290 	chvgpio_write_pad_cfg0(sc, pin, reg);
291 }
292 
293 void
chvgpio_intr_establish(void * cookie,int pin,int flags,int (* func)(void *),void * arg)294 chvgpio_intr_establish(void *cookie, int pin, int flags,
295     int (*func)(void *), void *arg)
296 {
297 	struct chvgpio_softc *sc = cookie;
298 	uint32_t reg;
299 	int line;
300 
301 	KASSERT(chvgpio_check_pin(sc, pin) == 0);
302 
303 	reg = chvgpio_read_pad_cfg0(sc, pin);
304 	reg &= CHVGPIO_PAD_CFG0_INTSEL_MASK;
305 	line = reg >> CHVGPIO_PAD_CFG0_INTSEL_SHIFT;
306 
307 	sc->sc_pin_ih[line].ih_func = func;
308 	sc->sc_pin_ih[line].ih_arg = arg;
309 
310 	reg = chvgpio_read_pad_cfg1(sc, pin);
311 	reg &= ~CHVGPIO_PAD_CFG1_INTWAKECFG_MASK;
312 	reg &= ~CHVGPIO_PAD_CFG1_INVRXTX_MASK;
313 	switch (flags & (LR_GPIO_MODE | LR_GPIO_POLARITY)) {
314 	case LR_GPIO_LEVEL | LR_GPIO_ACTLO:
315 		reg |= CHVGPIO_PAD_CFG1_INVRXTX_RXDATA;
316 		/* FALLTHROUGH */
317 	case LR_GPIO_LEVEL | LR_GPIO_ACTHI:
318 		reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_LEVEL;
319 		break;
320 	case LR_GPIO_EDGE | LR_GPIO_ACTLO:
321 		reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_FALLING;
322 		break;
323 	case LR_GPIO_EDGE | LR_GPIO_ACTHI:
324 		reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_RISING;
325 		break;
326 	case LR_GPIO_EDGE | LR_GPIO_ACTBOTH:
327 		reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_BOTH;
328 		break;
329 	default:
330 		printf("%s: unsupported interrupt mode/polarity\n",
331 		    sc->sc_dev.dv_xname);
332 		break;
333 	}
334 	chvgpio_write_pad_cfg1(sc, pin, reg);
335 
336 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
337 	    CHVGPIO_INTERRUPT_MASK);
338 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
339 	    CHVGPIO_INTERRUPT_MASK, reg | (1 << line));
340 }
341 
342 void
chvgpio_intr_enable(void * cookie,int pin)343 chvgpio_intr_enable(void *cookie, int pin)
344 {
345 	struct chvgpio_softc *sc = cookie;
346 	uint32_t reg;
347 	int line;
348 
349 	KASSERT(chvgpio_check_pin(sc, pin) == 0);
350 
351 	reg = chvgpio_read_pad_cfg0(sc, pin);
352 	reg &= CHVGPIO_PAD_CFG0_INTSEL_MASK;
353 	line = reg >> CHVGPIO_PAD_CFG0_INTSEL_SHIFT;
354 
355 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
356 	    CHVGPIO_INTERRUPT_MASK);
357 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
358 	    CHVGPIO_INTERRUPT_MASK, reg | (1 << line));
359 }
360 
361 void
chvgpio_intr_disable(void * cookie,int pin)362 chvgpio_intr_disable(void *cookie, int pin)
363 {
364 	struct chvgpio_softc *sc = cookie;
365 	uint32_t reg;
366 	int line;
367 
368 	KASSERT(chvgpio_check_pin(sc, pin) == 0);
369 
370 	reg = chvgpio_read_pad_cfg0(sc, pin);
371 	reg &= CHVGPIO_PAD_CFG0_INTSEL_MASK;
372 	line = reg >> CHVGPIO_PAD_CFG0_INTSEL_SHIFT;
373 
374 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
375 	    CHVGPIO_INTERRUPT_MASK);
376 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
377 	    CHVGPIO_INTERRUPT_MASK, reg & ~(1 << line));
378 }
379 
380 int
chvgpio_intr(void * arg)381 chvgpio_intr(void *arg)
382 {
383 	struct chvgpio_softc *sc = arg;
384 	uint32_t reg;
385 	int rc = 0;
386 	int line;
387 
388 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
389 	    CHVGPIO_INTERRUPT_STATUS);
390 	for (line = 0; line < 16; line++) {
391 		if ((reg & (1 << line)) == 0)
392 			continue;
393 
394 		bus_space_write_4(sc->sc_memt,sc->sc_memh,
395 		    CHVGPIO_INTERRUPT_STATUS, 1 << line);
396 		if (sc->sc_pin_ih[line].ih_func)
397 			sc->sc_pin_ih[line].ih_func(sc->sc_pin_ih[line].ih_arg);
398 		rc = 1;
399 	}
400 
401 	return rc;
402 }
403 
404 int
chvgpio_opreg_handler(void * cookie,int iodir,uint64_t address,int size,uint64_t * value)405 chvgpio_opreg_handler(void *cookie, int iodir, uint64_t address, int size,
406     uint64_t *value)
407 {
408 	struct chvgpio_softc *sc = cookie;
409 
410 	/* Only allow 32-bit access. */
411 	if (size != 4 || address > sc->sc_size - size)
412 		return -1;
413 
414 	if (iodir == ACPI_IOREAD)
415 		*value = bus_space_read_4(sc->sc_memt, sc->sc_memh, address);
416 	else
417 		bus_space_write_4(sc->sc_memt, sc->sc_memh, address, *value);
418 
419 	return 0;
420 }
421