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