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