xref: /openbsd/sys/dev/acpi/pchgpio.c (revision 0e595994)
1 /*	$OpenBSD: pchgpio.c,v 1.16 2024/08/18 11:10:10 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 	"INTC1056",
119 	"INTC1057",
120 	"INTC1082",
121 	"INTC1083",
122 	"INTC1085",
123 	NULL
124 };
125 
126 /* Sunrisepoint-LP */
127 
128 const struct pchgpio_group spt_lp_groups[] =
129 {
130 	/* Community 0 */
131 	{ 0, 0, 0, 23, 0 },		/* GPP_A */
132 	{ 0, 1, 24, 47, 24 },		/* GPP_B */
133 
134 	/* Community 1 */
135 	{ 1, 0, 48, 71, 48 },		/* GPP_C */
136 	{ 1, 1, 72, 95, 72 },		/* GPP_D */
137 	{ 1, 2, 96, 119, 96 },		/* GPP_E */
138 
139 	/* Community 3 */
140 	{ 2, 0, 120, 143, 120 },	/* GPP_F */
141 	{ 2, 1, 144, 151, 144 },	/* GPP_G */
142 };
143 
144 const struct pchgpio_device spt_lp_device =
145 {
146 	.pad_size = 8,
147 	.gpi_is = 0x100,
148 	.gpi_ie = 0x120,
149 	.groups = spt_lp_groups,
150 	.ngroups = nitems(spt_lp_groups),
151 	.npins = 176,
152 };
153 
154 /* Sunrisepoint-H */
155 
156 const struct pchgpio_group spt_h_groups[] =
157 {
158 	/* Community 0 */
159 	{ 0, 0, 0, 23, 0 },		/* GPP_A */
160 	{ 0, 1, 24, 47, 24 },		/* GPP_B */
161 
162 	/* Community 1 */
163 	{ 1, 0, 48, 71, 48 },		/* GPP_C */
164 	{ 1, 1, 72, 95, 72 },		/* GPP_D */
165 	{ 1, 2, 96, 108, 96 },		/* GPP_E */
166 	{ 1, 3, 109, 132, 120 },	/* GPP_F */
167 	{ 1, 4, 133, 156, 144 },	/* GPP_G */
168 	{ 1, 5, 157, 180, 168 },	/* GPP_H */
169 
170 	/* Community 3 */
171 	{ 2, 0, 181, 191, 192 },	/* GPP_I */
172 };
173 
174 const struct pchgpio_device spt_h_device =
175 {
176 	.pad_size = 8,
177 	.gpi_is = 0x100,
178 	.gpi_ie = 0x120,
179 	.groups = spt_h_groups,
180 	.ngroups = nitems(spt_h_groups),
181 	.npins = 224,
182 };
183 
184 /* Cannon Lake-H */
185 
186 const struct pchgpio_group cnl_h_groups[] =
187 {
188 	/* Community 0 */
189 	{ 0, 0, 0, 24, 0 },		/* GPP_A */
190 	{ 0, 1, 25, 50, 32 },		/* GPP_B */
191 
192 	/* Community 1 */
193 	{ 1, 0, 51, 74, 64 },		/* GPP_C */
194 	{ 1, 1, 75, 98, 96 },		/* GPP_D */
195 	{ 1, 2, 99, 106, 128 },		/* GPP_G */
196 
197 	/* Community 3 */
198 	{ 2, 0, 155, 178, 192 },	/* GPP_K */
199 	{ 2, 1, 179, 202, 224 },	/* GPP_H */
200 	{ 2, 2, 203, 215, 256 },	/* GPP_E */
201 	{ 2, 3, 216, 239, 288 },	/* GPP_F */
202 
203 	/* Community 4 */
204 	{ 3, 2, 269, 286, 320 },	/* GPP_I */
205 	{ 3, 3, 287, 298, 352 },	/* GPP_J */
206 };
207 
208 const struct pchgpio_device cnl_h_device =
209 {
210 	.pad_size = 16,
211 	.gpi_is = 0x100,
212 	.gpi_ie = 0x120,
213 	.groups = cnl_h_groups,
214 	.ngroups = nitems(cnl_h_groups),
215 	.npins = 384,
216 };
217 
218 /* Cannon Lake-LP */
219 
220 const struct pchgpio_group cnl_lp_groups[] =
221 {
222 	/* Community 0 */
223 	{ 0, 0, 0, 24, 0 },		/* GPP_A */
224 	{ 0, 1, 25, 50, 32 },		/* GPP_B */
225 	{ 0, 2, 51, 58, 64 },		/* GPP_G */
226 
227 	/* Community 1 */
228 	{ 1, 0, 68, 92, 96 },		/* GPP_D */
229 	{ 1, 1, 93, 116, 128 },		/* GPP_F */
230 	{ 1, 2, 117, 140, 160 },	/* GPP_H */
231 
232 	/* Community 4 */
233 	{ 2, 0, 181, 204, 256 },	/* GPP_C */
234 	{ 2, 1, 205, 228, 288 },	/* GPP_E */
235 };
236 
237 const struct pchgpio_device cnl_lp_device =
238 {
239 	.pad_size = 16,
240 	.gpi_is = 0x100,
241 	.gpi_ie = 0x120,
242 	.groups = cnl_lp_groups,
243 	.ngroups = nitems(cnl_lp_groups),
244 	.npins = 320,
245 };
246 
247 /* Tiger Lake-LP */
248 
249 const struct pchgpio_group tgl_lp_groups[] =
250 {
251 	/* Community 0 */
252 	{ 0, 0, 0, 25, 0 },		/* GPP_B */
253 	{ 0, 1, 26, 41, 32 },		/* GPP_T */
254 	{ 0, 2, 42, 66, 64 },		/* GPP_A */
255 
256 	/* Community 1 */
257 	{ 1, 0, 67, 74, 96 },		/* GPP_S */
258 	{ 1, 1, 75, 98, 128 },		/* GPP_H */
259 	{ 1, 2, 99, 119, 160 },		/* GPP_D */
260 	{ 1, 3, 120, 143, 192 },	/* GPP_U */
261 
262 	/* Community 4 */
263 	{ 2, 0, 171, 194, 256 },	/* GPP_C */
264 	{ 2, 1, 195, 219, 288 },	/* GPP_F */
265 	{ 2, 3, 226, 250, 320 },	/* GPP_E */
266 
267 	/* Community 5 */
268 	{ 3, 0, 260, 267, 352 },	/* GPP_R */
269 };
270 
271 const struct pchgpio_device tgl_lp_device =
272 {
273 	.pad_size = 16,
274 	.gpi_is = 0x100,
275 	.gpi_ie = 0x120,
276 	.groups = tgl_lp_groups,
277 	.ngroups = nitems(tgl_lp_groups),
278 	.npins = 360,
279 };
280 
281 /* Tiger Lake-H */
282 
283 const struct pchgpio_group tgl_h_groups[] =
284 {
285 	/* Community 0 */
286 	{ 0, 0, 0, 24, 0 },		/* GPP_A */
287 	{ 0, 1, 25, 44, 32 },		/* GPP_R */
288 	{ 0, 2, 45, 70, 64 },		/* GPP_B */
289 
290 	/* Community 1 */
291 	{ 1, 0, 79, 104, 128 },		/* GPP_D */
292 	{ 1, 1, 105, 128, 160 },	/* GPP_C */
293 	{ 1, 2, 129, 136, 192 },	/* GPP_S */
294 	{ 1, 3, 137, 153, 224 },	/* GPP_G */
295 
296 	/* Community 3 */
297 	{ 2, 0, 181, 193, 288 },	/* GPP_E */
298 	{ 2, 1, 194, 217, 320 },	/* GPP_F */
299 
300 	/* Community 4 */
301 	{ 2, 0, 218, 241, 352 },	/* GPP_H */
302 	{ 2, 1, 242, 251, 384 },	/* GPP_J */
303 	{ 2, 2, 252, 266, 416 },	/* GPP_K */
304 
305 	/* Community 5 */
306 	{ 3, 0, 267, 281, 448 },	/* GPP_I */
307 };
308 
309 const struct pchgpio_device tgl_h_device =
310 {
311 	.pad_size = 16,
312 	.gpi_is = 0x100,
313 	.gpi_ie = 0x120,
314 	.groups = tgl_h_groups,
315 	.ngroups = nitems(tgl_h_groups),
316 	.npins = 480,
317 };
318 
319 /* Alder Lake-S */
320 
321 const struct pchgpio_group adl_s_groups[] =
322 {
323 	/* Community 0 */
324 	{ 0, 0, 0, 24, 0 },		/* GPP_I */
325 	{ 0, 1, 25, 47, 32 },		/* GPP_R */
326 	{ 0, 2, 48, 59, 64 },		/* GPP_J */
327 
328 	/* Community 1 */
329 	{ 1, 0, 95, 118, 160 },		/* GPP_B */
330 	{ 1, 1, 119, 126, 192 },	/* GPP_G */
331 	{ 1, 2, 127, 150, 224 },	/* GPP_H */
332 
333 	/* Community 3 */
334 	{ 2, 1, 160, 175, 256 },	/* GPP_A */
335 	{ 2, 2, 176, 199, 288 },	/* GPP_C */
336 
337 	/* Community 4 */
338 	{ 3, 0, 200, 207, 320 },	/* GPP_S */
339 	{ 3, 1, 208, 230, 352 },	/* GPP_E */
340 	{ 3, 2, 231, 245, 384 },	/* GPP_K */
341 	{ 3, 3, 246, 269, 416 },	/* GPP_F */
342 
343 	/* Community 5 */
344 	{ 4, 0, 270, 294, 448 },	/* GPP_D */
345 };
346 
347 const struct pchgpio_device adl_s_device =
348 {
349 	.pad_size = 16,
350 	.gpi_is = 0x200,
351 	.gpi_ie = 0x220,
352 	.groups = adl_s_groups,
353 	.ngroups = nitems(adl_s_groups),
354 	.npins = 480,
355 };
356 
357 /* Alder Lake-N */
358 
359 const struct pchgpio_group adl_n_groups[] =
360 {
361 	/* Community 0 */
362 	{ 0, 0, 0, 25, 0 },		/* GPP_B */
363 	{ 0, 1, 26, 41, 32 },		/* GPP_T */
364 	{ 0, 2, 42, 66, 64 },		/* GPP_A */
365 
366 	/* Community 1 */
367 	{ 1, 0, 67, 74, 96 },		/* GPP_S */
368 	{ 1, 1, 75, 94, 128 },		/* GPP_I */
369 	{ 1, 2, 95, 118, 160 },		/* GPP_H */
370 	{ 1, 3, 119, 139, 192 },	/* GPP_D */
371 
372 	/* Community 4 */
373 	{ 2, 0, 169, 192, 256 },	/* GPP_C */
374 	{ 2, 1, 193, 217, 288 },	/* GPP_F */
375 	{ 2, 3, 224, 248, 320 },	/* GPP_E */
376 
377 	/* Community 5 */
378 	{ 3, 0, 249, 256, 352 },	/* GPP_R */
379 };
380 
381 const struct pchgpio_device adl_n_device =
382 {
383 	.pad_size = 16,
384 	.gpi_is = 0x100,
385 	.gpi_ie = 0x120,
386 	.groups = adl_n_groups,
387 	.ngroups = nitems(adl_n_groups),
388 	.npins = 384,
389 };
390 
391 /* Meteor Lake-P */
392 
393 const struct pchgpio_group mtl_p_groups[] =
394 {
395 	/* Community 0 */
396 	{ 0, 1, 5, 28, 32 },		/* GPP_V */
397 	{ 0, 2, 29, 52, 64 },		/* GPP_C */
398 
399 	/* Community 1 */
400 	{ 1, 0, 53, 77, 96 },		/* GPP_A */
401 	{ 1, 1, 78, 102, 128 },		/* GPP_E */
402 
403 	/* Community 3 */
404 	{ 2, 0, 103, 128, 160 },	/* GPP_H */
405 	{ 2, 1, 129, 154, 192 },	/* GPP_F */
406 
407 	/* Community 4 */
408 	{ 3, 0, 184, 191, 288 },	/* GPP_S */
409 
410 	/* Community 5 */
411 	{ 4, 0, 204, 228, 352 },	/* GPP_B */
412 	{ 4, 1, 229, 253, 384 },	/* GPP_D */
413 };
414 
415 const struct pchgpio_device mtl_p_device =
416 {
417 	.pad_size = 16,
418 	.gpi_is = 0x200,
419 	.gpi_ie = 0x210,
420 	.groups = mtl_p_groups,
421 	.ngroups = nitems(mtl_p_groups),
422 	.npins = 416,
423 };
424 
425 /* Meteor Lake-S */
426 
427 const struct pchgpio_group mtl_s_groups[] =
428 {
429 	/* Community 0 */
430 	{ 0, 0, 0, 27, 0 },		/* GPP_A */
431 	{ 0, 2, 47, 73, 64 },		/* GPP_C */
432 
433 	/* Community 1 */
434 	{ 1, 0, 74, 93, 96 },		/* GPP_B */
435 	{ 1, 2, 96, 119, 160 },		/* GPP_D */
436 };
437 
438 const struct pchgpio_device mtl_s_device =
439 {
440 	.pad_size = 16,
441 	.gpi_is = 0x200,
442 	.gpi_ie = 0x210,
443 	.groups = mtl_s_groups,
444 	.ngroups = nitems(mtl_s_groups),
445 	.npins = 192,
446 };
447 
448 struct pchgpio_match pchgpio_devices[] = {
449 	{ "INT344B", &spt_lp_device },
450 	{ "INT3450", &cnl_h_device },
451 	{ "INT3451", &spt_h_device },
452 	{ "INT345D", &spt_h_device },
453 	{ "INT34BB", &cnl_lp_device },
454 	{ "INT34C5", &tgl_lp_device },
455 	{ "INT34C6", &tgl_h_device },
456 	{ "INTC1055", &tgl_lp_device },
457 	{ "INTC1056", &adl_s_device },
458 	{ "INTC1057", &adl_n_device },
459 	{ "INTC1085", &adl_s_device },
460 	{ "INTC1082", &mtl_s_device },
461 	{ "INTC1083", &mtl_p_device },
462 };
463 
464 int	pchgpio_read_pin(void *, int);
465 void	pchgpio_write_pin(void *, int, int);
466 void	pchgpio_intr_establish(void *, int, int, int (*)(void *), void *);
467 void	pchgpio_intr_enable(void *, int);
468 void	pchgpio_intr_disable(void *, int);
469 int	pchgpio_intr(void *);
470 void	pchgpio_save(struct pchgpio_softc *);
471 void	pchgpio_restore(struct pchgpio_softc *);
472 
473 int
pchgpio_match(struct device * parent,void * match,void * aux)474 pchgpio_match(struct device *parent, void *match, void *aux)
475 {
476 	struct acpi_attach_args *aaa = aux;
477 	struct cfdata *cf = match;
478 
479 	if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1)
480 		return 0;
481 	return acpi_matchhids(aaa, pchgpio_hids, cf->cf_driver->cd_name);
482 }
483 
484 void
pchgpio_attach(struct device * parent,struct device * self,void * aux)485 pchgpio_attach(struct device *parent, struct device *self, void *aux)
486 {
487 	struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
488 	struct acpi_attach_args *aaa = aux;
489 	uint16_t bar;
490 	int i;
491 
492 	sc->sc_acpi = (struct acpi_softc *)parent;
493 	sc->sc_node = aaa->aaa_node;
494 	printf(" %s", sc->sc_node->name);
495 
496 	printf(" addr");
497 
498 	for (i = 0; i < aaa->aaa_naddr; i++) {
499 		printf(" 0x%llx/0x%llx", aaa->aaa_addr[i], aaa->aaa_size[i]);
500 
501 		sc->sc_memt[i] = aaa->aaa_bst[i];
502 		if (bus_space_map(sc->sc_memt[i], aaa->aaa_addr[i],
503 		    aaa->aaa_size[i], 0, &sc->sc_memh[i])) {
504 			printf(": can't map registers\n");
505 			goto unmap;
506 		}
507 
508 		sc->sc_padbar[i] = bus_space_read_4(sc->sc_memt[i],
509 		    sc->sc_memh[i], PCHGPIO_PADBAR);
510 		sc->sc_naddr++;
511 	}
512 
513 	printf(" irq %d", aaa->aaa_irq[0]);
514 
515 	for (i = 0; i < nitems(pchgpio_devices); i++) {
516 		if (strcmp(pchgpio_devices[i].hid, aaa->aaa_dev) == 0) {
517 			sc->sc_device = pchgpio_devices[i].device;
518 			break;
519 		}
520 	}
521 	KASSERT(sc->sc_device);
522 
523 	/* Figure out the first pin for each community. */
524 	bar = -1;
525 	for (i = 0; i < sc->sc_device->ngroups; i++) {
526 		if (sc->sc_device->groups[i].bar != bar) {
527 			bar = sc->sc_device->groups[i].bar;
528 			sc->sc_padbase[bar] = sc->sc_device->groups[i].base;
529 		}
530 	}
531 
532 	sc->sc_padsize = sc->sc_device->pad_size;
533 	sc->sc_npins = sc->sc_device->npins;
534 	sc->sc_pin_cfg = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_cfg),
535 	    M_DEVBUF, M_WAITOK);
536 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
537 	    M_DEVBUF, M_WAITOK | M_ZERO);
538 
539 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
540 	    IPL_BIO, pchgpio_intr, sc, sc->sc_dev.dv_xname);
541 	if (sc->sc_ih == NULL) {
542 		printf(": can't establish interrupt\n");
543 		goto unmap;
544 	}
545 
546 	sc->sc_gpio.cookie = sc;
547 	sc->sc_gpio.read_pin = pchgpio_read_pin;
548 	sc->sc_gpio.write_pin = pchgpio_write_pin;
549 	sc->sc_gpio.intr_establish = pchgpio_intr_establish;
550 	sc->sc_gpio.intr_enable = pchgpio_intr_enable;
551 	sc->sc_gpio.intr_disable = pchgpio_intr_disable;
552 	sc->sc_node->gpio = &sc->sc_gpio;
553 
554 	printf(", %d pins\n", sc->sc_npins);
555 
556 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
557 	return;
558 
559 unmap:
560 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
561 	free(sc->sc_pin_cfg, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_cfg));
562 	for (i = 0; i < sc->sc_naddr; i++)
563 		bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i],
564 		    aaa->aaa_size[i]);
565 }
566 
567 int
pchgpio_activate(struct device * self,int act)568 pchgpio_activate(struct device *self, int act)
569 {
570 	struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
571 
572 	switch (act) {
573 	case DVACT_SUSPEND:
574 		pchgpio_save(sc);
575 		break;
576 	case DVACT_RESUME:
577 		pchgpio_restore(sc);
578 		break;
579 	}
580 
581 	return 0;
582 }
583 
584 const struct pchgpio_group *
pchgpio_find_group(struct pchgpio_softc * sc,int pin)585 pchgpio_find_group(struct pchgpio_softc *sc, int pin)
586 {
587 	int i, npads;
588 
589 	for (i = 0; i < sc->sc_device->ngroups; i++) {
590 		npads = 1 + sc->sc_device->groups[i].limit -
591 		    sc->sc_device->groups[i].base;
592 
593 		if (pin >= sc->sc_device->groups[i].gpiobase &&
594 		    pin < sc->sc_device->groups[i].gpiobase + npads)
595 			return &sc->sc_device->groups[i];
596 	}
597 	return NULL;
598 }
599 
600 int
pchgpio_read_pin(void * cookie,int pin)601 pchgpio_read_pin(void *cookie, int pin)
602 {
603 	struct pchgpio_softc *sc = cookie;
604 	const struct pchgpio_group *group;
605 	uint32_t reg;
606 	uint16_t pad;
607 	uint8_t bar;
608 
609 	group = pchgpio_find_group(sc, pin);
610 	bar = group->bar;
611 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
612 
613 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
614 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
615 
616 	return !!(reg & PCHGPIO_CONF_RXSTATE);
617 }
618 
619 void
pchgpio_write_pin(void * cookie,int pin,int value)620 pchgpio_write_pin(void *cookie, int pin, int value)
621 {
622 	struct pchgpio_softc *sc = cookie;
623 	const struct pchgpio_group *group;
624 	uint32_t reg;
625 	uint16_t pad;
626 	uint8_t bar;
627 
628 	group = pchgpio_find_group(sc, pin);
629 	bar = group->bar;
630 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
631 
632 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
633 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
634 	if (value)
635 		reg |= PCHGPIO_CONF_TXSTATE;
636 	else
637 		reg &= ~PCHGPIO_CONF_TXSTATE;
638 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
639 	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
640 }
641 
642 void
pchgpio_intr_establish(void * cookie,int pin,int flags,int (* func)(void *),void * arg)643 pchgpio_intr_establish(void *cookie, int pin, int flags,
644     int (*func)(void *), void *arg)
645 {
646 	struct pchgpio_softc *sc = cookie;
647 	const struct pchgpio_group *group;
648 	uint32_t reg;
649 	uint16_t pad;
650 	uint8_t bank, bar;
651 
652 	KASSERT(pin >= 0);
653 
654 	group = pchgpio_find_group(sc, pin);
655 	if (group == NULL)
656 		return;
657 
658 	bar = group->bar;
659 	bank = group->bank;
660 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
661 
662 	sc->sc_pin_ih[pin].ih_func = func;
663 	sc->sc_pin_ih[pin].ih_arg = arg;
664 
665 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
666 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
667 	reg &= ~(PCHGPIO_CONF_RXEV_MASK | PCHGPIO_CONF_RXINV);
668 	if ((flags & LR_GPIO_MODE) == 1)
669 		reg |= PCHGPIO_CONF_RXEV_EDGE;
670 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO)
671 		reg |= PCHGPIO_CONF_RXINV;
672 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH)
673 		reg |= PCHGPIO_CONF_RXEV_EDGE | PCHGPIO_CONF_RXEV_ZERO;
674 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
675 	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
676 
677 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
678 	    sc->sc_device->gpi_ie + bank * 4);
679 	reg |= (1 << (pin - group->gpiobase));
680 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
681 	    sc->sc_device->gpi_ie + bank * 4, reg);
682 }
683 
684 void
pchgpio_intr_enable(void * cookie,int pin)685 pchgpio_intr_enable(void *cookie, int pin)
686 {
687 	struct pchgpio_softc *sc = cookie;
688 	const struct pchgpio_group *group;
689 	uint32_t reg;
690 	uint16_t pad;
691 	uint8_t bank, bar;
692 
693 	KASSERT(pin >= 0);
694 
695 	group = pchgpio_find_group(sc, pin);
696 	if (group == NULL)
697 		return;
698 
699 	bar = group->bar;
700 	bank = group->bank;
701 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
702 
703 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
704 	    sc->sc_device->gpi_ie + bank * 4);
705 	reg |= (1 << (pin - group->gpiobase));
706 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
707 	    sc->sc_device->gpi_ie + bank * 4, reg);
708 }
709 
710 void
pchgpio_intr_disable(void * cookie,int pin)711 pchgpio_intr_disable(void *cookie, int pin)
712 {
713 	struct pchgpio_softc *sc = cookie;
714 	const struct pchgpio_group *group;
715 	uint32_t reg;
716 	uint16_t pad;
717 	uint8_t bank, bar;
718 
719 	KASSERT(pin >= 0);
720 
721 	group = pchgpio_find_group(sc, pin);
722 	if (group == NULL)
723 		return;
724 
725 	bar = group->bar;
726 	bank = group->bank;
727 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
728 
729 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
730 	    sc->sc_device->gpi_ie + bank * 4);
731 	reg &= ~(1 << (pin - group->gpiobase));
732 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
733 	    sc->sc_device->gpi_ie + bank * 4, reg);
734 }
735 
736 int
pchgpio_intr_handle(struct pchgpio_softc * sc,int group,int bit)737 pchgpio_intr_handle(struct pchgpio_softc *sc, int group, int bit)
738 {
739 	uint32_t enable;
740 	int gpiobase, pin, handled = 0;
741 	uint8_t bank, bar;
742 
743 	bar = sc->sc_device->groups[group].bar;
744 	bank = sc->sc_device->groups[group].bank;
745 	gpiobase = sc->sc_device->groups[group].gpiobase;
746 
747 	pin = gpiobase + bit;
748 	if (sc->sc_pin_ih[pin].ih_func) {
749 		sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
750 		handled = 1;
751 	} else {
752 		/* Mask unhandled interrupt */
753 		enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
754 		    sc->sc_device->gpi_ie + bank * 4);
755 		enable &= ~(1 << bit);
756 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
757 		    sc->sc_device->gpi_ie + bank * 4, enable);
758 	}
759 
760 	return handled;
761 }
762 
763 int
pchgpio_intr(void * arg)764 pchgpio_intr(void *arg)
765 {
766 	struct pchgpio_softc *sc = arg;
767 	uint32_t status, enable;
768 	int group, bit, handled = 0;
769 	uint16_t base, limit;
770 	uint8_t bank, bar;
771 
772 	for (group = 0; group < sc->sc_device->ngroups; group++) {
773 		bar = sc->sc_device->groups[group].bar;
774 		bank = sc->sc_device->groups[group].bank;
775 		base = sc->sc_device->groups[group].base;
776 		limit = sc->sc_device->groups[group].limit;
777 
778 		status = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
779 		    sc->sc_device->gpi_is + bank * 4);
780 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
781 		    sc->sc_device->gpi_is + bank * 4, status);
782 		enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
783 		    sc->sc_device->gpi_ie + bank * 4);
784 		status &= enable;
785 		if (status == 0)
786 			continue;
787 
788 		for (bit = 0; bit <= (limit - base); bit++) {
789 			if (status & (1 << bit))
790 				handled |= pchgpio_intr_handle(sc, group, bit);
791 		}
792 	}
793 
794 	return handled;
795 }
796 
797 void
pchgpio_save_pin(struct pchgpio_softc * sc,int pin)798 pchgpio_save_pin(struct pchgpio_softc *sc, int pin)
799 {
800 	const struct pchgpio_group *group;
801 	uint32_t gpi_ie;
802 	uint16_t pad;
803 	uint8_t bank, bar;
804 
805 	group = pchgpio_find_group(sc, pin);
806 	if (group == NULL)
807 		return;
808 
809 	bar = group->bar;
810 	bank = group->bank;
811 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
812 
813 	sc->sc_pin_cfg[pin].pad_cfg_dw0 =
814 	    bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
815 		sc->sc_padbar[bar] + pad * sc->sc_padsize);
816 	sc->sc_pin_cfg[pin].pad_cfg_dw1 =
817 	    bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
818 		sc->sc_padbar[bar] + pad * sc->sc_padsize + 4);
819 
820 	gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
821 	    sc->sc_device->gpi_ie + bank * 4);
822 	sc->sc_pin_cfg[pin].gpi_ie = (gpi_ie & (1 << (pin - group->gpiobase)));
823 }
824 
825 void
pchgpio_save(struct pchgpio_softc * sc)826 pchgpio_save(struct pchgpio_softc *sc)
827 {
828 	int pin;
829 
830 	for (pin = 0; pin < sc->sc_npins; pin++)
831 		pchgpio_save_pin(sc, pin);
832 }
833 
834 void
pchgpio_restore_pin(struct pchgpio_softc * sc,int pin)835 pchgpio_restore_pin(struct pchgpio_softc *sc, int pin)
836 {
837 	const struct pchgpio_group *group;
838 	int restore = 0;
839 	uint32_t pad_cfg_dw0, gpi_ie;
840 	uint16_t pad;
841 	uint8_t bank, bar;
842 
843 	group = pchgpio_find_group(sc, pin);
844 	if (group == NULL)
845 		return;
846 
847 	bar = group->bar;
848 	bank = group->bank;
849 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
850 
851 	pad_cfg_dw0 = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
852 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
853 
854 	if (sc->sc_pin_ih[pin].ih_func)
855 		restore = 1;
856 
857 	/*
858 	 * The BIOS on Lenovo Thinkpads based on Intel's Tiger Lake
859 	 * platform have a bug where the GPIO pin that is used for the
860 	 * touchpad interrupt gets reset when entering S3 and isn't
861 	 * properly restored upon resume.  We detect this issue by
862 	 * comparing the bits in the PAD_CFG_DW0 register PADRSTCFG
863 	 * field before suspend and after resume and restore the pin
864 	 * configuration if the bits don't match.
865 	 */
866 	if ((sc->sc_pin_cfg[pin].pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK) !=
867 	    (pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK))
868 		restore = 1;
869 
870 	if (restore) {
871 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
872 		    sc->sc_padbar[bar] + pad * sc->sc_padsize,
873 		    sc->sc_pin_cfg[pin].pad_cfg_dw0);
874 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
875 		    sc->sc_padbar[bar] + pad * sc->sc_padsize + 4,
876 		    sc->sc_pin_cfg[pin].pad_cfg_dw1);
877 
878 		gpi_ie = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
879 		    sc->sc_device->gpi_ie + bank * 4);
880 		if (sc->sc_pin_cfg[pin].gpi_ie)
881 			gpi_ie |= (1 << (pin - group->gpiobase));
882 		else
883 			gpi_ie &= ~(1 << (pin - group->gpiobase));
884 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
885 		    sc->sc_device->gpi_ie + bank * 4, gpi_ie);
886 	}
887 }
888 
889 void
pchgpio_restore(struct pchgpio_softc * sc)890 pchgpio_restore(struct pchgpio_softc *sc)
891 {
892 	int pin;
893 
894 	for (pin = 0; pin < sc->sc_npins; pin++)
895 		pchgpio_restore_pin(sc, pin);
896 }
897