xref: /openbsd-src/sys/dev/acpi/chvgpio.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /*	$OpenBSD: chvgpio.c,v 1.9 2020/05/22 10:16:37 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
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
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
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
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
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 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 *);
149 int	chvgpio_intr(void *);
150 int	chvgpio_opreg_handler(void *, int, uint64_t, int, uint64_t *);
151 
152 int
153 chvgpio_match(struct device *parent, void *match, void *aux)
154 {
155 	struct acpi_attach_args *aaa = aux;
156 	struct cfdata *cf = match;
157 
158 	return acpi_matchhids(aaa, chvgpio_hids, cf->cf_driver->cd_name);
159 }
160 
161 void
162 chvgpio_attach(struct device *parent, struct device *self, void *aux)
163 {
164 	struct chvgpio_softc *sc = (struct chvgpio_softc *)self;
165 	struct acpi_attach_args *aaa = aux;
166 	int64_t uid;
167 	int i;
168 
169 	sc->sc_acpi = (struct acpi_softc *)parent;
170 	sc->sc_node = aaa->aaa_node;
171 	printf(" %s", sc->sc_node->name);
172 
173 	if (aaa->aaa_naddr < 1) {
174 		printf(": no registers\n");
175 		return;
176 	}
177 
178 	if (aaa->aaa_nirq < 1) {
179 		printf(": no interrupt\n");
180 		return;
181 	}
182 
183 	if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) {
184 		printf(": can't find uid\n");
185 		return;
186 	}
187 
188 	printf(" uid %lld", uid);
189 
190 	switch (uid) {
191 	case 1:
192 		sc->sc_pins = chv_southwest_pins;
193 		break;
194 	case 2:
195 		sc->sc_pins = chv_north_pins;
196 		break;
197 	case 3:
198 		sc->sc_pins = chv_east_pins;
199 		break;
200 	case 4:
201 		sc->sc_pins = chv_southeast_pins;
202 		break;
203 	default:
204 		printf("\n");
205 		return;
206 	}
207 
208 	for (i = 0; sc->sc_pins[i] >= 0; i++) {
209 		sc->sc_npins += sc->sc_pins[i];
210 		sc->sc_ngroups++;
211 	}
212 
213 	printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
214 	printf(" irq %d", aaa->aaa_irq[0]);
215 
216 	sc->sc_memt = aaa->aaa_bst[0];
217 	sc->sc_size = aaa->aaa_size[0];
218 	if (bus_space_map(sc->sc_memt, aaa->aaa_addr[0], aaa->aaa_size[0],
219 	    0, &sc->sc_memh)) {
220 		printf(": can't map registers\n");
221 		return;
222 	}
223 
224 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
225 	    IPL_BIO, chvgpio_intr, sc, sc->sc_dev.dv_xname);
226 	if (sc->sc_ih == NULL) {
227 		printf(": can't establish interrupt\n");
228 		goto unmap;
229 	}
230 
231 	sc->sc_gpio.cookie = sc;
232 	sc->sc_gpio.read_pin = chvgpio_read_pin;
233 	sc->sc_gpio.write_pin = chvgpio_write_pin;
234 	sc->sc_gpio.intr_establish = chvgpio_intr_establish;
235 	sc->sc_node->gpio = &sc->sc_gpio;
236 
237 	/* Mask and ack all interrupts. */
238 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
239 	    CHVGPIO_INTERRUPT_MASK, 0);
240 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
241 	    CHVGPIO_INTERRUPT_STATUS, 0xffff);
242 
243 	printf(", %d pins\n", sc->sc_npins);
244 
245 	/* Register OEM defined address space. */
246 	aml_register_regionspace(sc->sc_node, CHVGPIO_REGIONSPACE_BASE + uid,
247 	    sc, chvgpio_opreg_handler);
248 
249 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
250 	return;
251 
252 unmap:
253 	bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_size);
254 }
255 
256 int
257 chvgpio_check_pin(struct chvgpio_softc *sc, int pin)
258 {
259 	if (pin < 0)
260 		return EINVAL;
261 	if ((pin / 15) >= sc->sc_ngroups)
262 		return EINVAL;
263 	if ((pin % 15) >= sc->sc_pins[pin / 15])
264 		return EINVAL;
265 
266 	return 0;
267 }
268 
269 int
270 chvgpio_read_pin(void *cookie, int pin)
271 {
272 	struct chvgpio_softc *sc = cookie;
273 	uint32_t reg;
274 
275 	KASSERT(chvgpio_check_pin(sc, pin) == 0);
276 
277 	reg = chvgpio_read_pad_cfg0(sc, pin);
278 	return (reg & CHVGPIO_PAD_CFG0_GPIORXSTATE);
279 }
280 
281 void
282 chvgpio_write_pin(void *cookie, int pin, int value)
283 {
284 	struct chvgpio_softc *sc = cookie;
285 	uint32_t reg;
286 
287 	KASSERT(chvgpio_check_pin(sc, pin) == 0);
288 
289 	reg = chvgpio_read_pad_cfg0(sc, pin);
290 	if (value)
291 		reg |= CHVGPIO_PAD_CFG0_GPIOTXSTATE;
292 	else
293 		reg &= ~CHVGPIO_PAD_CFG0_GPIOTXSTATE;
294 	chvgpio_write_pad_cfg0(sc, pin, reg);
295 }
296 
297 void
298 chvgpio_intr_establish(void *cookie, int pin, int flags,
299     int (*func)(void *), void *arg)
300 {
301 	struct chvgpio_softc *sc = cookie;
302 	uint32_t reg;
303 	int line;
304 
305 	KASSERT(chvgpio_check_pin(sc, pin) == 0);
306 
307 	reg = chvgpio_read_pad_cfg0(sc, pin);
308 	reg &= CHVGPIO_PAD_CFG0_INTSEL_MASK;
309 	line = reg >> CHVGPIO_PAD_CFG0_INTSEL_SHIFT;
310 
311 	sc->sc_pin_ih[line].ih_func = func;
312 	sc->sc_pin_ih[line].ih_arg = arg;
313 
314 	reg = chvgpio_read_pad_cfg1(sc, pin);
315 	reg &= ~CHVGPIO_PAD_CFG1_INTWAKECFG_MASK;
316 	reg &= ~CHVGPIO_PAD_CFG1_INVRXTX_MASK;
317 	switch (flags & (LR_GPIO_MODE | LR_GPIO_POLARITY)) {
318 	case LR_GPIO_LEVEL | LR_GPIO_ACTLO:
319 		reg |= CHVGPIO_PAD_CFG1_INVRXTX_RXDATA;
320 		/* FALLTHROUGH */
321 	case LR_GPIO_LEVEL | LR_GPIO_ACTHI:
322 		reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_LEVEL;
323 		break;
324 	case LR_GPIO_EDGE | LR_GPIO_ACTLO:
325 		reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_FALLING;
326 		break;
327 	case LR_GPIO_EDGE | LR_GPIO_ACTHI:
328 		reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_RISING;
329 		break;
330 	case LR_GPIO_EDGE | LR_GPIO_ACTBOTH:
331 		reg |= CHVGPIO_PAD_CFG1_INTWAKECFG_BOTH;
332 		break;
333 	default:
334 		printf("%s: unsupported interrupt mode/polarity\n",
335 		    sc->sc_dev.dv_xname);
336 		break;
337 	}
338 	chvgpio_write_pad_cfg1(sc, pin, reg);
339 
340 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
341 	    CHVGPIO_INTERRUPT_MASK);
342 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
343 	    CHVGPIO_INTERRUPT_MASK, reg | (1 << line));
344 }
345 
346 int
347 chvgpio_intr(void *arg)
348 {
349 	struct chvgpio_softc *sc = arg;
350 	uint32_t reg;
351 	int rc = 0;
352 	int line;
353 
354 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
355 	    CHVGPIO_INTERRUPT_STATUS);
356 	for (line = 0; line < 16; line++) {
357 		if ((reg & (1 << line)) == 0)
358 			continue;
359 
360 		bus_space_write_4(sc->sc_memt,sc->sc_memh,
361 		    CHVGPIO_INTERRUPT_STATUS, 1 << line);
362 		if (sc->sc_pin_ih[line].ih_func)
363 			sc->sc_pin_ih[line].ih_func(sc->sc_pin_ih[line].ih_arg);
364 		rc = 1;
365 	}
366 
367 	return rc;
368 }
369 
370 int
371 chvgpio_opreg_handler(void *cookie, int iodir, uint64_t address, int size,
372     uint64_t *value)
373 {
374 	struct chvgpio_softc *sc = cookie;
375 
376 	/* Only allow 32-bit access. */
377 	if (size != 4 || address > sc->sc_size - size)
378 		return -1;
379 
380 	if (iodir == ACPI_IOREAD)
381 		*value = bus_space_read_4(sc->sc_memt, sc->sc_memh, address);
382 	else
383 		bus_space_write_4(sc->sc_memt, sc->sc_memh, address, *value);
384 
385 	return 0;
386 }
387