xref: /openbsd-src/sys/dev/acpi/pchgpio.c (revision 3374c67d44f9b75b98444cbf63020f777792342e)
1 /*	$OpenBSD: pchgpio.c,v 1.14 2022/10/20 20:40:57 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2020 Mark Kettenis
4  * Copyright (c) 2020 James Hastings
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/malloc.h>
21 #include <sys/systm.h>
22 
23 #include <dev/acpi/acpireg.h>
24 #include <dev/acpi/acpivar.h>
25 #include <dev/acpi/acpidev.h>
26 #include <dev/acpi/amltypes.h>
27 #include <dev/acpi/dsdt.h>
28 
29 #define PCHGPIO_MAXCOM		5
30 
31 #define PCHGPIO_CONF_TXSTATE		0x00000001
32 #define PCHGPIO_CONF_RXSTATE		0x00000002
33 #define PCHGPIO_CONF_RXINV		0x00800000
34 #define PCHGPIO_CONF_RXEV_EDGE		0x02000000
35 #define PCHGPIO_CONF_RXEV_ZERO		0x04000000
36 #define PCHGPIO_CONF_RXEV_MASK		0x06000000
37 #define PCHGPIO_CONF_PADRSTCFG_MASK	0xc0000000
38 
39 #define PCHGPIO_PADBAR		0x00c
40 
41 struct pchgpio_group {
42 	uint8_t		bar;
43 	uint8_t		bank;
44 	uint16_t	base;
45 	uint16_t	limit;
46 	int16_t		gpiobase;
47 };
48 
49 struct pchgpio_device {
50 	uint16_t	pad_size;
51 	uint16_t	gpi_is;
52 	uint16_t	gpi_ie;
53 	const struct pchgpio_group *groups;
54 	int		ngroups;
55 	int		npins;
56 };
57 
58 struct pchgpio_match {
59 	const char	*hid;
60 	const struct pchgpio_device *device;
61 };
62 
63 struct pchgpio_pincfg {
64 	uint32_t	pad_cfg_dw0;
65 	uint32_t	pad_cfg_dw1;
66 	int		gpi_ie;
67 };
68 
69 struct pchgpio_intrhand {
70 	int (*ih_func)(void *);
71 	void *ih_arg;
72 };
73 
74 struct pchgpio_softc {
75 	struct device sc_dev;
76 	struct acpi_softc *sc_acpi;
77 	struct aml_node *sc_node;
78 
79 	bus_space_tag_t sc_memt[PCHGPIO_MAXCOM];
80 	bus_space_handle_t sc_memh[PCHGPIO_MAXCOM];
81 	void *sc_ih;
82 	int sc_naddr;
83 
84 	const struct pchgpio_device *sc_device;
85 	uint16_t sc_padbar[PCHGPIO_MAXCOM];
86 	uint16_t sc_padbase[PCHGPIO_MAXCOM];
87 	int sc_padsize;
88 
89 	int sc_npins;
90 	struct pchgpio_pincfg *sc_pin_cfg;
91 	struct pchgpio_intrhand *sc_pin_ih;
92 
93 	struct acpi_gpio sc_gpio;
94 };
95 
96 int	pchgpio_match(struct device *, void *, void *);
97 void	pchgpio_attach(struct device *, struct device *, void *);
98 int	pchgpio_activate(struct device *, int);
99 
100 const struct cfattach pchgpio_ca = {
101 	sizeof(struct pchgpio_softc), pchgpio_match, pchgpio_attach,
102 	NULL, pchgpio_activate
103 };
104 
105 struct cfdriver pchgpio_cd = {
106 	NULL, "pchgpio", DV_DULL
107 };
108 
109 const char *pchgpio_hids[] = {
110 	"INT344B",
111 	"INT3450",
112 	"INT3451",
113 	"INT345D",
114 	"INT34BB",
115 	"INT34C5",
116 	"INT34C6",
117 	"INTC1055",
118 	NULL
119 };
120 
121 /* Sunrisepoint-LP */
122 
123 const struct pchgpio_group spt_lp_groups[] =
124 {
125 	/* Community 0 */
126 	{ 0, 0, 0, 23, 0 },		/* GPP_A */
127 	{ 0, 1, 24, 47, 24 },		/* GPP_B */
128 
129 	/* Community 1 */
130 	{ 1, 0, 48, 71, 48 },		/* GPP_C */
131 	{ 1, 1, 72, 95, 72 },		/* GPP_D */
132 	{ 1, 2, 96, 119, 96 },		/* GPP_E */
133 
134 	/* Community 3 */
135 	{ 2, 0, 120, 143, 120 },	/* GPP_F */
136 	{ 2, 1, 144, 151, 144 },	/* GPP_G */
137 };
138 
139 const struct pchgpio_device spt_lp_device =
140 {
141 	.pad_size = 8,
142 	.gpi_is = 0x100,
143 	.gpi_ie = 0x120,
144 	.groups = spt_lp_groups,
145 	.ngroups = nitems(spt_lp_groups),
146 	.npins = 176,
147 };
148 
149 /* Sunrisepoint-H */
150 
151 const struct pchgpio_group spt_h_groups[] =
152 {
153 	/* Community 0 */
154 	{ 0, 0, 0, 23, 0 },		/* GPP_A */
155 	{ 0, 1, 24, 47, 24 },		/* GPP_B */
156 
157 	/* Community 1 */
158 	{ 1, 0, 48, 71, 48 },		/* GPP_C */
159 	{ 1, 1, 72, 95, 72 },		/* GPP_D */
160 	{ 1, 2, 96, 108, 96 },		/* GPP_E */
161 	{ 1, 3, 109, 132, 120 },	/* GPP_F */
162 	{ 1, 4, 133, 156, 144 },	/* GPP_G */
163 	{ 1, 5, 157, 180, 168 },	/* GPP_H */
164 
165 	/* Community 3 */
166 	{ 2, 0, 181, 191, 192 },	/* GPP_I */
167 };
168 
169 const struct pchgpio_device spt_h_device =
170 {
171 	.pad_size = 8,
172 	.gpi_is = 0x100,
173 	.gpi_ie = 0x120,
174 	.groups = spt_h_groups,
175 	.ngroups = nitems(spt_h_groups),
176 	.npins = 224,
177 };
178 
179 /* Cannon Lake-H */
180 
181 const struct pchgpio_group cnl_h_groups[] =
182 {
183 	/* Community 0 */
184 	{ 0, 0, 0, 24, 0 },		/* GPP_A */
185 	{ 0, 1, 25, 50, 32 },		/* GPP_B */
186 
187 	/* Community 1 */
188 	{ 1, 0, 51, 74, 64 },		/* GPP_C */
189 	{ 1, 1, 75, 98, 96 },		/* GPP_D */
190 	{ 1, 2, 99, 106, 128 },		/* GPP_G */
191 
192 	/* Community 3 */
193 	{ 2, 0, 155, 178, 192 },	/* GPP_K */
194 	{ 2, 1, 179, 202, 224 },	/* GPP_H */
195 	{ 2, 2, 203, 215, 256 },	/* GPP_E */
196 	{ 2, 3, 216, 239, 288 },	/* GPP_F */
197 
198 	/* Community 4 */
199 	{ 3, 2, 269, 286, 320 },	/* GPP_I */
200 	{ 3, 3, 287, 298, 352 },	/* GPP_J */
201 };
202 
203 const struct pchgpio_device cnl_h_device =
204 {
205 	.pad_size = 16,
206 	.gpi_is = 0x100,
207 	.gpi_ie = 0x120,
208 	.groups = cnl_h_groups,
209 	.ngroups = nitems(cnl_h_groups),
210 	.npins = 384,
211 };
212 
213 /* Cannon Lake-LP */
214 
215 const struct pchgpio_group cnl_lp_groups[] =
216 {
217 	/* Community 0 */
218 	{ 0, 0, 0, 24, 0 },		/* GPP_A */
219 	{ 0, 1, 25, 50, 32 },		/* GPP_B */
220 	{ 0, 2, 51, 58, 64 },		/* GPP_G */
221 
222 	/* Community 1 */
223 	{ 1, 0, 68, 92, 96 },		/* GPP_D */
224 	{ 1, 1, 93, 116, 128 },		/* GPP_F */
225 	{ 1, 2, 117, 140, 160 },	/* GPP_H */
226 
227 	/* Community 4 */
228 	{ 2, 0, 181, 204, 256 },	/* GPP_C */
229 	{ 2, 1, 205, 228, 288 },	/* GPP_E */
230 };
231 
232 const struct pchgpio_device cnl_lp_device =
233 {
234 	.pad_size = 16,
235 	.gpi_is = 0x100,
236 	.gpi_ie = 0x120,
237 	.groups = cnl_lp_groups,
238 	.ngroups = nitems(cnl_lp_groups),
239 	.npins = 320,
240 };
241 
242 /* Tiger Lake-LP */
243 
244 const struct pchgpio_group tgl_lp_groups[] =
245 {
246 	/* Community 0 */
247 	{ 0, 0, 0, 25, 0 },		/* GPP_B */
248 	{ 0, 1, 26, 41, 32 },		/* GPP_T */
249 	{ 0, 2, 42, 66, 64 },		/* GPP_A */
250 
251 	/* Community 1 */
252 	{ 1, 0, 67, 74, 96 },		/* GPP_S */
253 	{ 1, 1, 75, 98, 128 },		/* GPP_H */
254 	{ 1, 2, 99, 119, 160 },		/* GPP_D */
255 	{ 1, 3, 120, 143, 192 },	/* GPP_U */
256 
257 	/* Community 4 */
258 	{ 2, 0, 171, 194, 256 },	/* GPP_C */
259 	{ 2, 1, 195, 219, 288 },	/* GPP_F */
260 	{ 2, 3, 226, 250, 320 },	/* GPP_E */
261 
262 	/* Community 5 */
263 	{ 3, 0, 260, 267, 352 },	/* GPP_R */
264 };
265 
266 const struct pchgpio_device tgl_lp_device =
267 {
268 	.pad_size = 16,
269 	.gpi_is = 0x100,
270 	.gpi_ie = 0x120,
271 	.groups = tgl_lp_groups,
272 	.ngroups = nitems(tgl_lp_groups),
273 	.npins = 360,
274 };
275 
276 /* Tiger Lake-H */
277 
278 const struct pchgpio_group tgl_h_groups[] =
279 {
280 	/* Community 0 */
281 	{ 0, 0, 0, 24, 0 },		/* GPP_A */
282 	{ 0, 1, 25, 44, 32 },		/* GPP_R */
283 	{ 0, 2, 45, 70, 64 },		/* GPP_B */
284 
285 	/* Community 1 */
286 	{ 1, 0, 79, 104, 128 },		/* GPP_D */
287 	{ 1, 1, 105, 128, 160 },	/* GPP_C */
288 	{ 1, 2, 129, 136, 192 },	/* GPP_S */
289 	{ 1, 3, 137, 153, 224 },	/* GPP_G */
290 
291 	/* Community 3 */
292 	{ 2, 0, 181, 193, 288 },	/* GPP_E */
293 	{ 2, 1, 194, 217, 320 },	/* GPP_F */
294 
295 	/* Community 4 */
296 	{ 2, 0, 218, 241, 352 },	/* GPP_H */
297 	{ 2, 1, 242, 251, 384 },	/* GPP_J */
298 	{ 2, 2, 252, 266, 416 },	/* GPP_K */
299 
300 	/* Community 5 */
301 	{ 3, 0, 267, 281, 448 },	/* GPP_I */
302 };
303 
304 const struct pchgpio_device tgl_h_device =
305 {
306 	.pad_size = 16,
307 	.gpi_is = 0x100,
308 	.gpi_ie = 0x120,
309 	.groups = tgl_h_groups,
310 	.ngroups = nitems(tgl_h_groups),
311 	.npins = 480,
312 };
313 
314 struct pchgpio_match pchgpio_devices[] = {
315 	{ "INT344B", &spt_lp_device },
316 	{ "INT3450", &cnl_h_device },
317 	{ "INT3451", &spt_h_device },
318 	{ "INT345D", &spt_h_device },
319 	{ "INT34BB", &cnl_lp_device },
320 	{ "INT34C5", &tgl_lp_device },
321 	{ "INT34C6", &tgl_h_device },
322 	{ "INTC1055", &tgl_lp_device },
323 };
324 
325 int	pchgpio_read_pin(void *, int);
326 void	pchgpio_write_pin(void *, int, int);
327 void	pchgpio_intr_establish(void *, int, int, int (*)(void *), void *);
328 void	pchgpio_intr_enable(void *, int);
329 void	pchgpio_intr_disable(void *, int);
330 int	pchgpio_intr(void *);
331 void	pchgpio_save(struct pchgpio_softc *);
332 void	pchgpio_restore(struct pchgpio_softc *);
333 
334 int
335 pchgpio_match(struct device *parent, void *match, void *aux)
336 {
337 	struct acpi_attach_args *aaa = aux;
338 	struct cfdata *cf = match;
339 
340 	if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1)
341 		return 0;
342 	return acpi_matchhids(aaa, pchgpio_hids, cf->cf_driver->cd_name);
343 }
344 
345 void
346 pchgpio_attach(struct device *parent, struct device *self, void *aux)
347 {
348 	struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
349 	struct acpi_attach_args *aaa = aux;
350 	uint16_t bar;
351 	int i;
352 
353 	sc->sc_acpi = (struct acpi_softc *)parent;
354 	sc->sc_node = aaa->aaa_node;
355 	printf(" %s", sc->sc_node->name);
356 
357 	printf(" addr");
358 
359 	for (i = 0; i < aaa->aaa_naddr; i++) {
360 		printf(" 0x%llx/0x%llx", aaa->aaa_addr[i], aaa->aaa_size[i]);
361 
362 		sc->sc_memt[i] = aaa->aaa_bst[i];
363 		if (bus_space_map(sc->sc_memt[i], aaa->aaa_addr[i],
364 		    aaa->aaa_size[i], 0, &sc->sc_memh[i])) {
365 			printf(": can't map registers\n");
366 			goto unmap;
367 		}
368 
369 		sc->sc_padbar[i] = bus_space_read_4(sc->sc_memt[i],
370 		    sc->sc_memh[i], PCHGPIO_PADBAR);
371 		sc->sc_naddr++;
372 	}
373 
374 	printf(" irq %d", aaa->aaa_irq[0]);
375 
376 	for (i = 0; i < nitems(pchgpio_devices); i++) {
377 		if (strcmp(pchgpio_devices[i].hid, aaa->aaa_dev) == 0) {
378 			sc->sc_device = pchgpio_devices[i].device;
379 			break;
380 		}
381 	}
382 	KASSERT(sc->sc_device);
383 
384 	/* Figure out the first pin for each community. */
385 	bar = -1;
386 	for (i = 0; i < sc->sc_device->ngroups; i++) {
387 		if (sc->sc_device->groups[i].bar != bar) {
388 			bar = sc->sc_device->groups[i].bar;
389 			sc->sc_padbase[bar] = sc->sc_device->groups[i].base;
390 		}
391 	}
392 
393 	sc->sc_padsize = sc->sc_device->pad_size;
394 	sc->sc_npins = sc->sc_device->npins;
395 	sc->sc_pin_cfg = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_cfg),
396 	    M_DEVBUF, M_WAITOK);
397 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
398 	    M_DEVBUF, M_WAITOK | M_ZERO);
399 
400 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
401 	    IPL_BIO, pchgpio_intr, sc, sc->sc_dev.dv_xname);
402 	if (sc->sc_ih == NULL) {
403 		printf(": can't establish interrupt\n");
404 		goto unmap;
405 	}
406 
407 	sc->sc_gpio.cookie = sc;
408 	sc->sc_gpio.read_pin = pchgpio_read_pin;
409 	sc->sc_gpio.write_pin = pchgpio_write_pin;
410 	sc->sc_gpio.intr_establish = pchgpio_intr_establish;
411 	sc->sc_gpio.intr_enable = pchgpio_intr_enable;
412 	sc->sc_gpio.intr_disable = pchgpio_intr_disable;
413 	sc->sc_node->gpio = &sc->sc_gpio;
414 
415 	printf(", %d pins\n", sc->sc_npins);
416 
417 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
418 	return;
419 
420 unmap:
421 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
422 	free(sc->sc_pin_cfg, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_cfg));
423 	for (i = 0; i < sc->sc_naddr; i++)
424 		bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i],
425 		    aaa->aaa_size[i]);
426 }
427 
428 int
429 pchgpio_activate(struct device *self, int act)
430 {
431 	struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
432 
433 	switch (act) {
434 	case DVACT_SUSPEND:
435 		pchgpio_save(sc);
436 		break;
437 	case DVACT_RESUME:
438 		pchgpio_restore(sc);
439 		break;
440 	}
441 
442 	return 0;
443 }
444 
445 const struct pchgpio_group *
446 pchgpio_find_group(struct pchgpio_softc *sc, int pin)
447 {
448 	int i, npads;
449 
450 	for (i = 0; i < sc->sc_device->ngroups; i++) {
451 		npads = 1 + sc->sc_device->groups[i].limit -
452 		    sc->sc_device->groups[i].base;
453 
454 		if (pin >= sc->sc_device->groups[i].gpiobase &&
455 		    pin < sc->sc_device->groups[i].gpiobase + npads)
456 			return &sc->sc_device->groups[i];
457 	}
458 	return NULL;
459 }
460 
461 int
462 pchgpio_read_pin(void *cookie, int pin)
463 {
464 	struct pchgpio_softc *sc = cookie;
465 	const struct pchgpio_group *group;
466 	uint32_t reg;
467 	uint16_t pad;
468 	uint8_t bar;
469 
470 	group = pchgpio_find_group(sc, pin);
471 	bar = group->bar;
472 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
473 
474 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
475 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
476 
477 	return !!(reg & PCHGPIO_CONF_RXSTATE);
478 }
479 
480 void
481 pchgpio_write_pin(void *cookie, int pin, int value)
482 {
483 	struct pchgpio_softc *sc = cookie;
484 	const struct pchgpio_group *group;
485 	uint32_t reg;
486 	uint16_t pad;
487 	uint8_t bar;
488 
489 	group = pchgpio_find_group(sc, pin);
490 	bar = group->bar;
491 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
492 
493 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
494 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
495 	if (value)
496 		reg |= PCHGPIO_CONF_TXSTATE;
497 	else
498 		reg &= ~PCHGPIO_CONF_TXSTATE;
499 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
500 	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
501 }
502 
503 void
504 pchgpio_intr_establish(void *cookie, int pin, int flags,
505     int (*func)(void *), void *arg)
506 {
507 	struct pchgpio_softc *sc = cookie;
508 	const struct pchgpio_group *group;
509 	uint32_t reg;
510 	uint16_t pad;
511 	uint8_t bank, bar;
512 
513 	KASSERT(pin >= 0);
514 
515 	group = pchgpio_find_group(sc, pin);
516 	if (group == NULL)
517 		return;
518 
519 	bar = group->bar;
520 	bank = group->bank;
521 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
522 
523 	sc->sc_pin_ih[pin].ih_func = func;
524 	sc->sc_pin_ih[pin].ih_arg = arg;
525 
526 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
527 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
528 	reg &= ~(PCHGPIO_CONF_RXEV_MASK | PCHGPIO_CONF_RXINV);
529 	if ((flags & LR_GPIO_MODE) == 1)
530 		reg |= PCHGPIO_CONF_RXEV_EDGE;
531 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO)
532 		reg |= PCHGPIO_CONF_RXINV;
533 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH)
534 		reg |= PCHGPIO_CONF_RXEV_EDGE | PCHGPIO_CONF_RXEV_ZERO;
535 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
536 	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
537 
538 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
539 	    sc->sc_device->gpi_ie + bank * 4);
540 	reg |= (1 << (pin - group->gpiobase));
541 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
542 	    sc->sc_device->gpi_ie + bank * 4, reg);
543 }
544 
545 void
546 pchgpio_intr_enable(void *cookie, int pin)
547 {
548 	struct pchgpio_softc *sc = cookie;
549 	const struct pchgpio_group *group;
550 	uint32_t reg;
551 	uint16_t pad;
552 	uint8_t bank, bar;
553 
554 	KASSERT(pin >= 0);
555 
556 	group = pchgpio_find_group(sc, pin);
557 	if (group == NULL)
558 		return;
559 
560 	bar = group->bar;
561 	bank = group->bank;
562 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
563 
564 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
565 	    sc->sc_device->gpi_ie + bank * 4);
566 	reg |= (1 << (pin - group->gpiobase));
567 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
568 	    sc->sc_device->gpi_ie + bank * 4, reg);
569 }
570 
571 void
572 pchgpio_intr_disable(void *cookie, int pin)
573 {
574 	struct pchgpio_softc *sc = cookie;
575 	const struct pchgpio_group *group;
576 	uint32_t reg;
577 	uint16_t pad;
578 	uint8_t bank, bar;
579 
580 	KASSERT(pin >= 0);
581 
582 	group = pchgpio_find_group(sc, pin);
583 	if (group == NULL)
584 		return;
585 
586 	bar = group->bar;
587 	bank = group->bank;
588 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
589 
590 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
591 	    sc->sc_device->gpi_ie + bank * 4);
592 	reg &= ~(1 << (pin - group->gpiobase));
593 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
594 	    sc->sc_device->gpi_ie + bank * 4, reg);
595 }
596 
597 int
598 pchgpio_intr_handle(struct pchgpio_softc *sc, int group, int bit)
599 {
600 	uint32_t enable;
601 	int gpiobase, pin, handled = 0;
602 	uint8_t bank, bar;
603 
604 	bar = sc->sc_device->groups[group].bar;
605 	bank = sc->sc_device->groups[group].bank;
606 	gpiobase = sc->sc_device->groups[group].gpiobase;
607 
608 	pin = gpiobase + bit;
609 	if (sc->sc_pin_ih[pin].ih_func) {
610 		sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
611 		handled = 1;
612 	} else {
613 		/* Mask unhandled interrupt */
614 		enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
615 		    sc->sc_device->gpi_ie + bank * 4);
616 		enable &= ~(1 << bit);
617 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
618 		    sc->sc_device->gpi_ie + bank * 4, enable);
619 	}
620 
621 	return handled;
622 }
623 
624 int
625 pchgpio_intr(void *arg)
626 {
627 	struct pchgpio_softc *sc = arg;
628 	uint32_t status, enable;
629 	int group, bit, handled = 0;
630 	uint16_t base, limit;
631 	uint8_t bank, bar;
632 
633 	for (group = 0; group < sc->sc_device->ngroups; group++) {
634 		bar = sc->sc_device->groups[group].bar;
635 		bank = sc->sc_device->groups[group].bank;
636 		base = sc->sc_device->groups[group].base;
637 		limit = sc->sc_device->groups[group].limit;
638 
639 		status = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
640 		    sc->sc_device->gpi_is + bank * 4);
641 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
642 		    sc->sc_device->gpi_is + bank * 4, status);
643 		enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
644 		    sc->sc_device->gpi_ie + bank * 4);
645 		status &= enable;
646 		if (status == 0)
647 			continue;
648 
649 		for (bit = 0; bit <= (limit - base); bit++) {
650 			if (status & (1 << bit))
651 				handled |= pchgpio_intr_handle(sc, group, bit);
652 		}
653 	}
654 
655 	return handled;
656 }
657 
658 void
659 pchgpio_save_pin(struct pchgpio_softc *sc, int pin)
660 {
661 	const struct pchgpio_group *group;
662 	uint32_t gpi_ie;
663 	uint16_t pad;
664 	uint8_t bank, bar;
665 
666 	group = pchgpio_find_group(sc, pin);
667 	if (group == NULL)
668 		return;
669 
670 	bar = group->bar;
671 	bank = group->bank;
672 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
673 
674 	sc->sc_pin_cfg[pin].pad_cfg_dw0 =
675 	    bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
676 		sc->sc_padbar[bar] + pad * sc->sc_padsize);
677 	sc->sc_pin_cfg[pin].pad_cfg_dw1 =
678 	    bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
679 		sc->sc_padbar[bar] + pad * sc->sc_padsize + 4);
680 
681 	gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
682 	    sc->sc_device->gpi_ie + bank * 4);
683 	sc->sc_pin_cfg[pin].gpi_ie = (gpi_ie & (1 << (pin - group->gpiobase)));
684 }
685 
686 void
687 pchgpio_save(struct pchgpio_softc *sc)
688 {
689 	int pin;
690 
691 	for (pin = 0; pin < sc->sc_npins; pin++)
692 		pchgpio_save_pin(sc, pin);
693 }
694 
695 void
696 pchgpio_restore_pin(struct pchgpio_softc *sc, int pin)
697 {
698 	const struct pchgpio_group *group;
699 	int restore = 0;
700 	uint32_t pad_cfg_dw0, gpi_ie;
701 	uint16_t pad;
702 	uint8_t bank, bar;
703 
704 	group = pchgpio_find_group(sc, pin);
705 	if (group == NULL)
706 		return;
707 
708 	bar = group->bar;
709 	bank = group->bank;
710 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
711 
712 	pad_cfg_dw0 = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
713 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
714 
715 	if (sc->sc_pin_ih[pin].ih_func)
716 		restore = 1;
717 
718 	/*
719 	 * The BIOS on Lenovo Thinkpads based on Intel's Tiger Lake
720 	 * platform have a bug where the GPIO pin that is used for the
721 	 * touchpad interrupt gets reset when entering S3 and isn't
722 	 * properly restored upon resume.  We detect this issue by
723 	 * comparing the bits in the PAD_CFG_DW0 register PADRSTCFG
724 	 * field before suspend and after resume and restore the pin
725 	 * configuration if the bits don't match.
726 	 */
727 	if ((sc->sc_pin_cfg[pin].pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK) !=
728 	    (pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK))
729 		restore = 1;
730 
731 	if (restore) {
732 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
733 		    sc->sc_padbar[bar] + pad * sc->sc_padsize,
734 		    sc->sc_pin_cfg[pin].pad_cfg_dw0);
735 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
736 		    sc->sc_padbar[bar] + pad * sc->sc_padsize + 4,
737 		    sc->sc_pin_cfg[pin].pad_cfg_dw1);
738 
739 		gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
740 		    sc->sc_device->gpi_ie + bank * 4);
741 		if (sc->sc_pin_cfg[pin].gpi_ie)
742 			gpi_ie |= (1 << (pin - group->gpiobase));
743 		else
744 			gpi_ie &= ~(1 << (pin - group->gpiobase));
745 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
746 		    sc->sc_device->gpi_ie + bank * 4, gpi_ie);
747 	}
748 }
749 
750 void
751 pchgpio_restore(struct pchgpio_softc *sc)
752 {
753 	int pin;
754 
755 	for (pin = 0; pin < sc->sc_npins; pin++)
756 		pchgpio_restore_pin(sc, pin);
757 }
758