xref: /openbsd-src/sys/dev/acpi/pchgpio.c (revision c1a45aed656e7d5627c30c92421893a76f370ccb)
1 /*	$OpenBSD: pchgpio.c,v 1.12 2022/04/06 18:59:27 naddy 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 	NULL
118 };
119 
120 /* Sunrisepoint-LP */
121 
122 const struct pchgpio_group spt_lp_groups[] =
123 {
124 	/* Community 0 */
125 	{ 0, 0, 0, 23, 0 },		/* GPP_A */
126 	{ 0, 1, 24, 47, 24 },		/* GPP_B */
127 
128 	/* Community 1 */
129 	{ 1, 0, 48, 71, 48 },		/* GPP_C */
130 	{ 1, 1, 72, 95, 72 },		/* GPP_D */
131 	{ 1, 2, 96, 119, 96 },		/* GPP_E */
132 
133 	/* Community 3 */
134 	{ 2, 0, 120, 143, 120 },	/* GPP_F */
135 	{ 2, 1, 144, 151, 144 },	/* GPP_G */
136 };
137 
138 const struct pchgpio_device spt_lp_device =
139 {
140 	.pad_size = 8,
141 	.gpi_is = 0x100,
142 	.gpi_ie = 0x120,
143 	.groups = spt_lp_groups,
144 	.ngroups = nitems(spt_lp_groups),
145 	.npins = 176,
146 };
147 
148 /* Sunrisepoint-H */
149 
150 const struct pchgpio_group spt_h_groups[] =
151 {
152 	/* Community 0 */
153 	{ 0, 0, 0, 23, 0 },		/* GPP_A */
154 	{ 0, 1, 24, 47, 24 },		/* GPP_B */
155 
156 	/* Community 1 */
157 	{ 1, 0, 48, 71, 48 },		/* GPP_C */
158 	{ 1, 1, 72, 95, 72 },		/* GPP_D */
159 	{ 1, 2, 96, 108, 96 },		/* GPP_E */
160 	{ 1, 3, 109, 132, 120 },	/* GPP_F */
161 	{ 1, 4, 133, 156, 144 },	/* GPP_G */
162 	{ 1, 5, 157, 180, 168 },	/* GPP_H */
163 
164 	/* Community 3 */
165 	{ 2, 0, 181, 191, 192 },	/* GPP_I */
166 };
167 
168 const struct pchgpio_device spt_h_device =
169 {
170 	.pad_size = 8,
171 	.gpi_is = 0x100,
172 	.gpi_ie = 0x120,
173 	.groups = spt_h_groups,
174 	.ngroups = nitems(spt_h_groups),
175 	.npins = 224,
176 };
177 
178 /* Cannon Lake-H */
179 
180 const struct pchgpio_group cnl_h_groups[] =
181 {
182 	/* Community 0 */
183 	{ 0, 0, 0, 24, 0 },		/* GPP_A */
184 	{ 0, 1, 25, 50, 32 },		/* GPP_B */
185 
186 	/* Community 1 */
187 	{ 1, 0, 51, 74, 64 },		/* GPP_C */
188 	{ 1, 1, 75, 98, 96 },		/* GPP_D */
189 	{ 1, 2, 99, 106, 128 },		/* GPP_G */
190 
191 	/* Community 3 */
192 	{ 2, 0, 155, 178, 192 },	/* GPP_K */
193 	{ 2, 1, 179, 202, 224 },	/* GPP_H */
194 	{ 2, 2, 203, 215, 256 },	/* GPP_E */
195 	{ 2, 3, 216, 239, 288 },	/* GPP_F */
196 
197 	/* Community 4 */
198 	{ 3, 2, 269, 286, 320 },	/* GPP_I */
199 	{ 3, 3, 287, 298, 352 },	/* GPP_J */
200 };
201 
202 const struct pchgpio_device cnl_h_device =
203 {
204 	.pad_size = 16,
205 	.gpi_is = 0x100,
206 	.gpi_ie = 0x120,
207 	.groups = cnl_h_groups,
208 	.ngroups = nitems(cnl_h_groups),
209 	.npins = 384,
210 };
211 
212 /* Cannon Lake-LP */
213 
214 const struct pchgpio_group cnl_lp_groups[] =
215 {
216 	/* Community 0 */
217 	{ 0, 0, 0, 24, 0 },		/* GPP_A */
218 	{ 0, 1, 25, 50, 32 },		/* GPP_B */
219 	{ 0, 2, 51, 58, 64 },		/* GPP_G */
220 
221 	/* Community 1 */
222 	{ 1, 0, 68, 92, 96 },		/* GPP_D */
223 	{ 1, 1, 93, 116, 128 },		/* GPP_F */
224 	{ 1, 2, 117, 140, 160 },	/* GPP_H */
225 
226 	/* Community 4 */
227 	{ 2, 0, 181, 204, 256 },	/* GPP_C */
228 	{ 2, 1, 205, 228, 288 },	/* GPP_E */
229 };
230 
231 const struct pchgpio_device cnl_lp_device =
232 {
233 	.pad_size = 16,
234 	.gpi_is = 0x100,
235 	.gpi_ie = 0x120,
236 	.groups = cnl_lp_groups,
237 	.ngroups = nitems(cnl_lp_groups),
238 	.npins = 320,
239 };
240 
241 /* Tiger Lake-LP */
242 
243 const struct pchgpio_group tgl_lp_groups[] =
244 {
245 	/* Community 0 */
246 	{ 0, 0, 0, 25, 0 },		/* GPP_B */
247 	{ 0, 1, 26, 41, 32 },		/* GPP_T */
248 	{ 0, 2, 42, 66, 64 },		/* GPP_A */
249 
250 	/* Community 1 */
251 	{ 1, 0, 67, 74, 96 },		/* GPP_S */
252 	{ 1, 1, 75, 98, 128 },		/* GPP_H */
253 	{ 1, 2, 99, 119, 160 },		/* GPP_D */
254 	{ 1, 3, 120, 143, 192 },	/* GPP_U */
255 
256 	/* Community 4 */
257 	{ 2, 0, 171, 194, 256 },	/* GPP_C */
258 	{ 2, 1, 195, 219, 288 },	/* GPP_F */
259 	{ 2, 3, 226, 250, 320 },	/* GPP_E */
260 
261 	/* Community 5 */
262 	{ 3, 0, 260, 267, 352 },	/* GPP_R */
263 };
264 
265 const struct pchgpio_device tgl_lp_device =
266 {
267 	.pad_size = 16,
268 	.gpi_is = 0x100,
269 	.gpi_ie = 0x120,
270 	.groups = tgl_lp_groups,
271 	.ngroups = nitems(tgl_lp_groups),
272 	.npins = 360,
273 };
274 
275 /* Tiger Lake-H */
276 
277 const struct pchgpio_group tgl_h_groups[] =
278 {
279 	/* Community 0 */
280 	{ 0, 0, 0, 24, 0 },		/* GPP_A */
281 	{ 0, 1, 25, 44, 32 },		/* GPP_R */
282 	{ 0, 2, 45, 70, 64 },		/* GPP_B */
283 
284 	/* Community 1 */
285 	{ 1, 0, 79, 104, 128 },		/* GPP_D */
286 	{ 1, 1, 105, 128, 160 },	/* GPP_C */
287 	{ 1, 2, 129, 136, 192 },	/* GPP_S */
288 	{ 1, 3, 137, 153, 224 },	/* GPP_G */
289 
290 	/* Community 3 */
291 	{ 2, 0, 181, 193, 288 },	/* GPP_E */
292 	{ 2, 1, 194, 217, 320 },	/* GPP_F */
293 
294 	/* Community 4 */
295 	{ 2, 0, 218, 241, 352 },	/* GPP_H */
296 	{ 2, 1, 242, 251, 384 },	/* GPP_J */
297 	{ 2, 2, 252, 266, 416 },	/* GPP_K */
298 
299 	/* Community 5 */
300 	{ 3, 0, 267, 281, 448 },	/* GPP_I */
301 };
302 
303 const struct pchgpio_device tgl_h_device =
304 {
305 	.pad_size = 16,
306 	.gpi_is = 0x100,
307 	.gpi_ie = 0x120,
308 	.groups = tgl_h_groups,
309 	.ngroups = nitems(tgl_h_groups),
310 	.npins = 480,
311 };
312 
313 struct pchgpio_match pchgpio_devices[] = {
314 	{ "INT344B", &spt_lp_device },
315 	{ "INT3450", &cnl_h_device },
316 	{ "INT3451", &spt_h_device },
317 	{ "INT345D", &spt_h_device },
318 	{ "INT34BB", &cnl_lp_device },
319 	{ "INT34C5", &tgl_lp_device },
320 	{ "INT34C6", &tgl_h_device },
321 };
322 
323 int	pchgpio_read_pin(void *, int);
324 void	pchgpio_write_pin(void *, int, int);
325 void	pchgpio_intr_establish(void *, int, int, int (*)(void *), void *);
326 int	pchgpio_intr(void *);
327 void	pchgpio_save(struct pchgpio_softc *);
328 void	pchgpio_restore(struct pchgpio_softc *);
329 
330 int
331 pchgpio_match(struct device *parent, void *match, void *aux)
332 {
333 	struct acpi_attach_args *aaa = aux;
334 	struct cfdata *cf = match;
335 
336 	if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1)
337 		return 0;
338 	return acpi_matchhids(aaa, pchgpio_hids, cf->cf_driver->cd_name);
339 }
340 
341 void
342 pchgpio_attach(struct device *parent, struct device *self, void *aux)
343 {
344 	struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
345 	struct acpi_attach_args *aaa = aux;
346 	uint16_t bar;
347 	int i;
348 
349 	sc->sc_acpi = (struct acpi_softc *)parent;
350 	sc->sc_node = aaa->aaa_node;
351 	printf(" %s", sc->sc_node->name);
352 
353 	printf(" addr");
354 
355 	for (i = 0; i < aaa->aaa_naddr; i++) {
356 		printf(" 0x%llx/0x%llx", aaa->aaa_addr[i], aaa->aaa_size[i]);
357 
358 		sc->sc_memt[i] = aaa->aaa_bst[i];
359 		if (bus_space_map(sc->sc_memt[i], aaa->aaa_addr[i],
360 		    aaa->aaa_size[i], 0, &sc->sc_memh[i])) {
361 			printf(": can't map registers\n");
362 			goto unmap;
363 		}
364 
365 		sc->sc_padbar[i] = bus_space_read_4(sc->sc_memt[i],
366 		    sc->sc_memh[i], PCHGPIO_PADBAR);
367 		sc->sc_naddr++;
368 	}
369 
370 	printf(" irq %d", aaa->aaa_irq[0]);
371 
372 	for (i = 0; i < nitems(pchgpio_devices); i++) {
373 		if (strcmp(pchgpio_devices[i].hid, aaa->aaa_dev) == 0) {
374 			sc->sc_device = pchgpio_devices[i].device;
375 			break;
376 		}
377 	}
378 	KASSERT(sc->sc_device);
379 
380 	/* Figure out the first pin for each community. */
381 	bar = -1;
382 	for (i = 0; i < sc->sc_device->ngroups; i++) {
383 		if (sc->sc_device->groups[i].bar != bar) {
384 			bar = sc->sc_device->groups[i].bar;
385 			sc->sc_padbase[bar] = sc->sc_device->groups[i].base;
386 		}
387 	}
388 
389 	sc->sc_padsize = sc->sc_device->pad_size;
390 	sc->sc_npins = sc->sc_device->npins;
391 	sc->sc_pin_cfg = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_cfg),
392 	    M_DEVBUF, M_WAITOK);
393 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
394 	    M_DEVBUF, M_WAITOK | M_ZERO);
395 
396 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
397 	    IPL_BIO, pchgpio_intr, sc, sc->sc_dev.dv_xname);
398 	if (sc->sc_ih == NULL) {
399 		printf(": can't establish interrupt\n");
400 		goto unmap;
401 	}
402 
403 	sc->sc_gpio.cookie = sc;
404 	sc->sc_gpio.read_pin = pchgpio_read_pin;
405 	sc->sc_gpio.write_pin = pchgpio_write_pin;
406 	sc->sc_gpio.intr_establish = pchgpio_intr_establish;
407 	sc->sc_node->gpio = &sc->sc_gpio;
408 
409 	printf(", %d pins\n", sc->sc_npins);
410 
411 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
412 	return;
413 
414 unmap:
415 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
416 	free(sc->sc_pin_cfg, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_cfg));
417 	for (i = 0; i < sc->sc_naddr; i++)
418 		bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i],
419 		    aaa->aaa_size[i]);
420 }
421 
422 int
423 pchgpio_activate(struct device *self, int act)
424 {
425 	struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
426 
427 	switch (act) {
428 	case DVACT_SUSPEND:
429 		pchgpio_save(sc);
430 		break;
431 	case DVACT_RESUME:
432 		pchgpio_restore(sc);
433 		break;
434 	}
435 
436 	return 0;
437 }
438 
439 const struct pchgpio_group *
440 pchgpio_find_group(struct pchgpio_softc *sc, int pin)
441 {
442 	int i, npads;
443 
444 	for (i = 0; i < sc->sc_device->ngroups; i++) {
445 		npads = 1 + sc->sc_device->groups[i].limit -
446 		    sc->sc_device->groups[i].base;
447 
448 		if (pin >= sc->sc_device->groups[i].gpiobase &&
449 		    pin < sc->sc_device->groups[i].gpiobase + npads)
450 			return &sc->sc_device->groups[i];
451 	}
452 	return NULL;
453 }
454 
455 int
456 pchgpio_read_pin(void *cookie, int pin)
457 {
458 	struct pchgpio_softc *sc = cookie;
459 	const struct pchgpio_group *group;
460 	uint32_t reg;
461 	uint16_t pad;
462 	uint8_t bar;
463 
464 	group = pchgpio_find_group(sc, pin);
465 	bar = group->bar;
466 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
467 
468 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
469 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
470 
471 	return !!(reg & PCHGPIO_CONF_RXSTATE);
472 }
473 
474 void
475 pchgpio_write_pin(void *cookie, int pin, int value)
476 {
477 	struct pchgpio_softc *sc = cookie;
478 	const struct pchgpio_group *group;
479 	uint32_t reg;
480 	uint16_t pad;
481 	uint8_t bar;
482 
483 	group = pchgpio_find_group(sc, pin);
484 	bar = group->bar;
485 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
486 
487 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
488 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
489 	if (value)
490 		reg |= PCHGPIO_CONF_TXSTATE;
491 	else
492 		reg &= ~PCHGPIO_CONF_TXSTATE;
493 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
494 	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
495 }
496 
497 void
498 pchgpio_intr_establish(void *cookie, int pin, int flags,
499     int (*func)(void *), void *arg)
500 {
501 	struct pchgpio_softc *sc = cookie;
502 	const struct pchgpio_group *group;
503 	uint32_t reg;
504 	uint16_t pad;
505 	uint8_t bank, bar;
506 
507 	KASSERT(pin >= 0);
508 
509 	group = pchgpio_find_group(sc, pin);
510 	if (group == NULL)
511 		return;
512 
513 	bar = group->bar;
514 	bank = group->bank;
515 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
516 
517 	sc->sc_pin_ih[pin].ih_func = func;
518 	sc->sc_pin_ih[pin].ih_arg = arg;
519 
520 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
521 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
522 	reg &= ~(PCHGPIO_CONF_RXEV_MASK | PCHGPIO_CONF_RXINV);
523 	if ((flags & LR_GPIO_MODE) == 1)
524 		reg |= PCHGPIO_CONF_RXEV_EDGE;
525 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO)
526 		reg |= PCHGPIO_CONF_RXINV;
527 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH)
528 		reg |= PCHGPIO_CONF_RXEV_EDGE | PCHGPIO_CONF_RXEV_ZERO;
529 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
530 	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
531 
532 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
533 	    sc->sc_device->gpi_ie + bank * 4);
534 	reg |= (1 << (pin - group->gpiobase));
535 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
536 	    sc->sc_device->gpi_ie + bank * 4, reg);
537 }
538 
539 int
540 pchgpio_intr_handle(struct pchgpio_softc *sc, int group, int bit)
541 {
542 	uint32_t enable;
543 	int gpiobase, pin, handled = 0;
544 	uint8_t bank, bar;
545 
546 	bar = sc->sc_device->groups[group].bar;
547 	bank = sc->sc_device->groups[group].bank;
548 	gpiobase = sc->sc_device->groups[group].gpiobase;
549 
550 	pin = gpiobase + bit;
551 	if (sc->sc_pin_ih[pin].ih_func) {
552 		sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
553 		handled = 1;
554 	} else {
555 		/* Mask unhandled interrupt */
556 		enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
557 		    sc->sc_device->gpi_ie + bank * 4);
558 		enable &= ~(1 << bit);
559 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
560 		    sc->sc_device->gpi_ie + bank * 4, enable);
561 	}
562 
563 	return handled;
564 }
565 
566 int
567 pchgpio_intr(void *arg)
568 {
569 	struct pchgpio_softc *sc = arg;
570 	uint32_t status, enable;
571 	int group, bit, handled = 0;
572 	uint16_t base, limit;
573 	uint8_t bank, bar;
574 
575 	for (group = 0; group < sc->sc_device->ngroups; group++) {
576 		bar = sc->sc_device->groups[group].bar;
577 		bank = sc->sc_device->groups[group].bank;
578 		base = sc->sc_device->groups[group].base;
579 		limit = sc->sc_device->groups[group].limit;
580 
581 		status = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
582 		    sc->sc_device->gpi_is + bank * 4);
583 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
584 		    sc->sc_device->gpi_is + bank * 4, status);
585 		enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
586 		    sc->sc_device->gpi_ie + bank * 4);
587 		status &= enable;
588 		if (status == 0)
589 			continue;
590 
591 		for (bit = 0; bit <= (limit - base); bit++) {
592 			if (status & (1 << bit))
593 				handled |= pchgpio_intr_handle(sc, group, bit);
594 		}
595 	}
596 
597 	return handled;
598 }
599 
600 void
601 pchgpio_save_pin(struct pchgpio_softc *sc, int pin)
602 {
603 	const struct pchgpio_group *group;
604 	uint32_t gpi_ie;
605 	uint16_t pad;
606 	uint8_t bank, bar;
607 
608 	group = pchgpio_find_group(sc, pin);
609 	if (group == NULL)
610 		return;
611 
612 	bar = group->bar;
613 	bank = group->bank;
614 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
615 
616 	sc->sc_pin_cfg[pin].pad_cfg_dw0 =
617 	    bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
618 		sc->sc_padbar[bar] + pad * sc->sc_padsize);
619 	sc->sc_pin_cfg[pin].pad_cfg_dw1 =
620 	    bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
621 		sc->sc_padbar[bar] + pad * sc->sc_padsize + 4);
622 
623 	gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
624 	    sc->sc_device->gpi_ie + bank * 4);
625 	sc->sc_pin_cfg[pin].gpi_ie = (gpi_ie & (1 << (pin - group->gpiobase)));
626 }
627 
628 void
629 pchgpio_save(struct pchgpio_softc *sc)
630 {
631 	int pin;
632 
633 	for (pin = 0; pin < sc->sc_npins; pin++)
634 		pchgpio_save_pin(sc, pin);
635 }
636 
637 void
638 pchgpio_restore_pin(struct pchgpio_softc *sc, int pin)
639 {
640 	const struct pchgpio_group *group;
641 	int restore = 0;
642 	uint32_t pad_cfg_dw0, gpi_ie;
643 	uint16_t pad;
644 	uint8_t bank, bar;
645 
646 	group = pchgpio_find_group(sc, pin);
647 	if (group == NULL)
648 		return;
649 
650 	bar = group->bar;
651 	bank = group->bank;
652 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
653 
654 	pad_cfg_dw0 = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
655 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
656 
657 	if (sc->sc_pin_ih[pin].ih_func)
658 		restore = 1;
659 
660 	/*
661 	 * The BIOS on Lenovo Thinkpads based on Intel's Tiger Lake
662 	 * platform have a bug where the GPIO pin that is used for the
663 	 * touchpad interrupt gets reset when entering S3 and isn't
664 	 * properly restored upon resume.  We detect this issue by
665 	 * comparing the bits in the PAD_CFG_DW0 register PADRSTCFG
666 	 * field before suspend and after resume and restore the pin
667 	 * configuration if the bits don't match.
668 	 */
669 	if ((sc->sc_pin_cfg[pin].pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK) !=
670 	    (pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK))
671 		restore = 1;
672 
673 	if (restore) {
674 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
675 		    sc->sc_padbar[bar] + pad * sc->sc_padsize,
676 		    sc->sc_pin_cfg[pin].pad_cfg_dw0);
677 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
678 		    sc->sc_padbar[bar] + pad * sc->sc_padsize + 4,
679 		    sc->sc_pin_cfg[pin].pad_cfg_dw1);
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 		if (sc->sc_pin_cfg[pin].gpi_ie)
684 			gpi_ie |= (1 << (pin - group->gpiobase));
685 		else
686 			gpi_ie &= ~(1 << (pin - group->gpiobase));
687 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
688 		    sc->sc_device->gpi_ie + bank * 4, gpi_ie);
689 	}
690 }
691 
692 void
693 pchgpio_restore(struct pchgpio_softc *sc)
694 {
695 	int pin;
696 
697 	for (pin = 0; pin < sc->sc_npins; pin++)
698 		pchgpio_restore_pin(sc, pin);
699 }
700