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