xref: /openbsd-src/sys/dev/acpi/pchgpio.c (revision 25c4e8bd056e974b28f4a0ffd39d76c190a56013)
1 /*	$OpenBSD: pchgpio.c,v 1.13 2022/06/29 01:05:18 jsg 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 int	pchgpio_intr(void *);
329 void	pchgpio_save(struct pchgpio_softc *);
330 void	pchgpio_restore(struct pchgpio_softc *);
331 
332 int
333 pchgpio_match(struct device *parent, void *match, void *aux)
334 {
335 	struct acpi_attach_args *aaa = aux;
336 	struct cfdata *cf = match;
337 
338 	if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1)
339 		return 0;
340 	return acpi_matchhids(aaa, pchgpio_hids, cf->cf_driver->cd_name);
341 }
342 
343 void
344 pchgpio_attach(struct device *parent, struct device *self, void *aux)
345 {
346 	struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
347 	struct acpi_attach_args *aaa = aux;
348 	uint16_t bar;
349 	int i;
350 
351 	sc->sc_acpi = (struct acpi_softc *)parent;
352 	sc->sc_node = aaa->aaa_node;
353 	printf(" %s", sc->sc_node->name);
354 
355 	printf(" addr");
356 
357 	for (i = 0; i < aaa->aaa_naddr; i++) {
358 		printf(" 0x%llx/0x%llx", aaa->aaa_addr[i], aaa->aaa_size[i]);
359 
360 		sc->sc_memt[i] = aaa->aaa_bst[i];
361 		if (bus_space_map(sc->sc_memt[i], aaa->aaa_addr[i],
362 		    aaa->aaa_size[i], 0, &sc->sc_memh[i])) {
363 			printf(": can't map registers\n");
364 			goto unmap;
365 		}
366 
367 		sc->sc_padbar[i] = bus_space_read_4(sc->sc_memt[i],
368 		    sc->sc_memh[i], PCHGPIO_PADBAR);
369 		sc->sc_naddr++;
370 	}
371 
372 	printf(" irq %d", aaa->aaa_irq[0]);
373 
374 	for (i = 0; i < nitems(pchgpio_devices); i++) {
375 		if (strcmp(pchgpio_devices[i].hid, aaa->aaa_dev) == 0) {
376 			sc->sc_device = pchgpio_devices[i].device;
377 			break;
378 		}
379 	}
380 	KASSERT(sc->sc_device);
381 
382 	/* Figure out the first pin for each community. */
383 	bar = -1;
384 	for (i = 0; i < sc->sc_device->ngroups; i++) {
385 		if (sc->sc_device->groups[i].bar != bar) {
386 			bar = sc->sc_device->groups[i].bar;
387 			sc->sc_padbase[bar] = sc->sc_device->groups[i].base;
388 		}
389 	}
390 
391 	sc->sc_padsize = sc->sc_device->pad_size;
392 	sc->sc_npins = sc->sc_device->npins;
393 	sc->sc_pin_cfg = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_cfg),
394 	    M_DEVBUF, M_WAITOK);
395 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
396 	    M_DEVBUF, M_WAITOK | M_ZERO);
397 
398 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
399 	    IPL_BIO, pchgpio_intr, sc, sc->sc_dev.dv_xname);
400 	if (sc->sc_ih == NULL) {
401 		printf(": can't establish interrupt\n");
402 		goto unmap;
403 	}
404 
405 	sc->sc_gpio.cookie = sc;
406 	sc->sc_gpio.read_pin = pchgpio_read_pin;
407 	sc->sc_gpio.write_pin = pchgpio_write_pin;
408 	sc->sc_gpio.intr_establish = pchgpio_intr_establish;
409 	sc->sc_node->gpio = &sc->sc_gpio;
410 
411 	printf(", %d pins\n", sc->sc_npins);
412 
413 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
414 	return;
415 
416 unmap:
417 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
418 	free(sc->sc_pin_cfg, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_cfg));
419 	for (i = 0; i < sc->sc_naddr; i++)
420 		bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i],
421 		    aaa->aaa_size[i]);
422 }
423 
424 int
425 pchgpio_activate(struct device *self, int act)
426 {
427 	struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
428 
429 	switch (act) {
430 	case DVACT_SUSPEND:
431 		pchgpio_save(sc);
432 		break;
433 	case DVACT_RESUME:
434 		pchgpio_restore(sc);
435 		break;
436 	}
437 
438 	return 0;
439 }
440 
441 const struct pchgpio_group *
442 pchgpio_find_group(struct pchgpio_softc *sc, int pin)
443 {
444 	int i, npads;
445 
446 	for (i = 0; i < sc->sc_device->ngroups; i++) {
447 		npads = 1 + sc->sc_device->groups[i].limit -
448 		    sc->sc_device->groups[i].base;
449 
450 		if (pin >= sc->sc_device->groups[i].gpiobase &&
451 		    pin < sc->sc_device->groups[i].gpiobase + npads)
452 			return &sc->sc_device->groups[i];
453 	}
454 	return NULL;
455 }
456 
457 int
458 pchgpio_read_pin(void *cookie, int pin)
459 {
460 	struct pchgpio_softc *sc = cookie;
461 	const struct pchgpio_group *group;
462 	uint32_t reg;
463 	uint16_t pad;
464 	uint8_t bar;
465 
466 	group = pchgpio_find_group(sc, pin);
467 	bar = group->bar;
468 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
469 
470 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
471 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
472 
473 	return !!(reg & PCHGPIO_CONF_RXSTATE);
474 }
475 
476 void
477 pchgpio_write_pin(void *cookie, int pin, int value)
478 {
479 	struct pchgpio_softc *sc = cookie;
480 	const struct pchgpio_group *group;
481 	uint32_t reg;
482 	uint16_t pad;
483 	uint8_t bar;
484 
485 	group = pchgpio_find_group(sc, pin);
486 	bar = group->bar;
487 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
488 
489 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
490 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
491 	if (value)
492 		reg |= PCHGPIO_CONF_TXSTATE;
493 	else
494 		reg &= ~PCHGPIO_CONF_TXSTATE;
495 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
496 	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
497 }
498 
499 void
500 pchgpio_intr_establish(void *cookie, int pin, int flags,
501     int (*func)(void *), void *arg)
502 {
503 	struct pchgpio_softc *sc = cookie;
504 	const struct pchgpio_group *group;
505 	uint32_t reg;
506 	uint16_t pad;
507 	uint8_t bank, bar;
508 
509 	KASSERT(pin >= 0);
510 
511 	group = pchgpio_find_group(sc, pin);
512 	if (group == NULL)
513 		return;
514 
515 	bar = group->bar;
516 	bank = group->bank;
517 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
518 
519 	sc->sc_pin_ih[pin].ih_func = func;
520 	sc->sc_pin_ih[pin].ih_arg = arg;
521 
522 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
523 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
524 	reg &= ~(PCHGPIO_CONF_RXEV_MASK | PCHGPIO_CONF_RXINV);
525 	if ((flags & LR_GPIO_MODE) == 1)
526 		reg |= PCHGPIO_CONF_RXEV_EDGE;
527 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO)
528 		reg |= PCHGPIO_CONF_RXINV;
529 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH)
530 		reg |= PCHGPIO_CONF_RXEV_EDGE | PCHGPIO_CONF_RXEV_ZERO;
531 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
532 	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
533 
534 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
535 	    sc->sc_device->gpi_ie + bank * 4);
536 	reg |= (1 << (pin - group->gpiobase));
537 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
538 	    sc->sc_device->gpi_ie + bank * 4, reg);
539 }
540 
541 int
542 pchgpio_intr_handle(struct pchgpio_softc *sc, int group, int bit)
543 {
544 	uint32_t enable;
545 	int gpiobase, pin, handled = 0;
546 	uint8_t bank, bar;
547 
548 	bar = sc->sc_device->groups[group].bar;
549 	bank = sc->sc_device->groups[group].bank;
550 	gpiobase = sc->sc_device->groups[group].gpiobase;
551 
552 	pin = gpiobase + bit;
553 	if (sc->sc_pin_ih[pin].ih_func) {
554 		sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
555 		handled = 1;
556 	} else {
557 		/* Mask unhandled interrupt */
558 		enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
559 		    sc->sc_device->gpi_ie + bank * 4);
560 		enable &= ~(1 << bit);
561 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
562 		    sc->sc_device->gpi_ie + bank * 4, enable);
563 	}
564 
565 	return handled;
566 }
567 
568 int
569 pchgpio_intr(void *arg)
570 {
571 	struct pchgpio_softc *sc = arg;
572 	uint32_t status, enable;
573 	int group, bit, handled = 0;
574 	uint16_t base, limit;
575 	uint8_t bank, bar;
576 
577 	for (group = 0; group < sc->sc_device->ngroups; group++) {
578 		bar = sc->sc_device->groups[group].bar;
579 		bank = sc->sc_device->groups[group].bank;
580 		base = sc->sc_device->groups[group].base;
581 		limit = sc->sc_device->groups[group].limit;
582 
583 		status = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
584 		    sc->sc_device->gpi_is + bank * 4);
585 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
586 		    sc->sc_device->gpi_is + bank * 4, status);
587 		enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
588 		    sc->sc_device->gpi_ie + bank * 4);
589 		status &= enable;
590 		if (status == 0)
591 			continue;
592 
593 		for (bit = 0; bit <= (limit - base); bit++) {
594 			if (status & (1 << bit))
595 				handled |= pchgpio_intr_handle(sc, group, bit);
596 		}
597 	}
598 
599 	return handled;
600 }
601 
602 void
603 pchgpio_save_pin(struct pchgpio_softc *sc, int pin)
604 {
605 	const struct pchgpio_group *group;
606 	uint32_t gpi_ie;
607 	uint16_t pad;
608 	uint8_t bank, bar;
609 
610 	group = pchgpio_find_group(sc, pin);
611 	if (group == NULL)
612 		return;
613 
614 	bar = group->bar;
615 	bank = group->bank;
616 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
617 
618 	sc->sc_pin_cfg[pin].pad_cfg_dw0 =
619 	    bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
620 		sc->sc_padbar[bar] + pad * sc->sc_padsize);
621 	sc->sc_pin_cfg[pin].pad_cfg_dw1 =
622 	    bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
623 		sc->sc_padbar[bar] + pad * sc->sc_padsize + 4);
624 
625 	gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
626 	    sc->sc_device->gpi_ie + bank * 4);
627 	sc->sc_pin_cfg[pin].gpi_ie = (gpi_ie & (1 << (pin - group->gpiobase)));
628 }
629 
630 void
631 pchgpio_save(struct pchgpio_softc *sc)
632 {
633 	int pin;
634 
635 	for (pin = 0; pin < sc->sc_npins; pin++)
636 		pchgpio_save_pin(sc, pin);
637 }
638 
639 void
640 pchgpio_restore_pin(struct pchgpio_softc *sc, int pin)
641 {
642 	const struct pchgpio_group *group;
643 	int restore = 0;
644 	uint32_t pad_cfg_dw0, gpi_ie;
645 	uint16_t pad;
646 	uint8_t bank, bar;
647 
648 	group = pchgpio_find_group(sc, pin);
649 	if (group == NULL)
650 		return;
651 
652 	bar = group->bar;
653 	bank = group->bank;
654 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
655 
656 	pad_cfg_dw0 = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
657 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
658 
659 	if (sc->sc_pin_ih[pin].ih_func)
660 		restore = 1;
661 
662 	/*
663 	 * The BIOS on Lenovo Thinkpads based on Intel's Tiger Lake
664 	 * platform have a bug where the GPIO pin that is used for the
665 	 * touchpad interrupt gets reset when entering S3 and isn't
666 	 * properly restored upon resume.  We detect this issue by
667 	 * comparing the bits in the PAD_CFG_DW0 register PADRSTCFG
668 	 * field before suspend and after resume and restore the pin
669 	 * configuration if the bits don't match.
670 	 */
671 	if ((sc->sc_pin_cfg[pin].pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK) !=
672 	    (pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK))
673 		restore = 1;
674 
675 	if (restore) {
676 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
677 		    sc->sc_padbar[bar] + pad * sc->sc_padsize,
678 		    sc->sc_pin_cfg[pin].pad_cfg_dw0);
679 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
680 		    sc->sc_padbar[bar] + pad * sc->sc_padsize + 4,
681 		    sc->sc_pin_cfg[pin].pad_cfg_dw1);
682 
683 		gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
684 		    sc->sc_device->gpi_ie + bank * 4);
685 		if (sc->sc_pin_cfg[pin].gpi_ie)
686 			gpi_ie |= (1 << (pin - group->gpiobase));
687 		else
688 			gpi_ie &= ~(1 << (pin - group->gpiobase));
689 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
690 		    sc->sc_device->gpi_ie + bank * 4, gpi_ie);
691 	}
692 }
693 
694 void
695 pchgpio_restore(struct pchgpio_softc *sc)
696 {
697 	int pin;
698 
699 	for (pin = 0; pin < sc->sc_npins; pin++)
700 		pchgpio_restore_pin(sc, pin);
701 }
702