pchgpio.c revision 1.6
1/*	$OpenBSD: pchgpio.c,v 1.6 2021/09/18 19:21:16 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		4
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
41struct pchgpio_group {
42	uint8_t		bar;
43	uint8_t		bank;
44	uint16_t	base;
45	uint16_t	limit;
46	int16_t		gpiobase;
47};
48
49struct 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
58struct pchgpio_match {
59	const char	*hid;
60	const struct pchgpio_device *device;
61};
62
63struct pchgpio_pincfg {
64	uint32_t	pad_cfg_dw0;
65	uint32_t	pad_cfg_dw1;
66};
67
68struct pchgpio_intrhand {
69	int (*ih_func)(void *);
70	void *ih_arg;
71};
72
73struct pchgpio_softc {
74	struct device sc_dev;
75	struct acpi_softc *sc_acpi;
76	struct aml_node *sc_node;
77
78	bus_space_tag_t sc_memt[PCHGPIO_MAXCOM];
79	bus_space_handle_t sc_memh[PCHGPIO_MAXCOM];
80	void *sc_ih;
81	int sc_naddr;
82
83	const struct pchgpio_device *sc_device;
84	uint16_t sc_padbar[PCHGPIO_MAXCOM];
85	uint16_t sc_padbase[PCHGPIO_MAXCOM];
86	int sc_padsize;
87
88	int sc_npins;
89	struct pchgpio_pincfg *sc_pin_cfg;
90	struct pchgpio_intrhand *sc_pin_ih;
91
92	struct acpi_gpio sc_gpio;
93};
94
95int	pchgpio_match(struct device *, void *, void *);
96void	pchgpio_attach(struct device *, struct device *, void *);
97int	pchgpio_activate(struct device *, int);
98
99struct cfattach pchgpio_ca = {
100	sizeof(struct pchgpio_softc), pchgpio_match, pchgpio_attach,
101	NULL, pchgpio_activate
102};
103
104struct cfdriver pchgpio_cd = {
105	NULL, "pchgpio", DV_DULL
106};
107
108const char *pchgpio_hids[] = {
109	"INT34BB",
110	"INT34C5",
111	NULL
112};
113
114const struct pchgpio_group cnl_lp_groups[] =
115{
116	/* Community 0 */
117	{ 0, 0, 0, 24, 0 },		/* GPP_A */
118	{ 0, 1, 25, 50, 32 },		/* GPP_B */
119	{ 0, 2, 51, 58, 64 },		/* GPP_G */
120
121	/* Community 1 */
122	{ 1, 0, 68, 92, 96 },		/* GPP_D */
123	{ 1, 1, 93, 116, 128 },		/* GPP_F */
124	{ 1, 2, 117, 140, 160 },	/* GPP_H */
125
126	/* Community 4 */
127	{ 2, 0, 181, 204, 256 },	/* GPP_C */
128	{ 2, 1, 205, 228, 288 },	/* GPP_E */
129};
130
131const struct pchgpio_device cnl_lp_device =
132{
133	.pad_size = 16,
134	.gpi_is = 0x100,
135	.gpi_ie = 0x120,
136	.groups = cnl_lp_groups,
137	.ngroups = nitems(cnl_lp_groups),
138	.npins = 320,
139};
140
141const struct pchgpio_group tgl_lp_groups[] =
142{
143	/* Community 0 */
144	{ 0, 0, 0, 25, 0 },		/* GPP_B */
145	{ 0, 1, 26, 41, 32 },		/* GPP_T */
146	{ 0, 2, 42, 66, 64 },		/* GPP_A */
147
148	/* Community 1 */
149	{ 1, 0, 67, 74, 96 },		/* GPP_S */
150	{ 1, 1, 75, 98, 128 },		/* GPP_H */
151	{ 1, 2, 99, 119, 160 },		/* GPP_D */
152	{ 1, 3, 120, 143, 192 },	/* GPP_U */
153
154	/* Community 4 */
155	{ 2, 0, 171, 194, 256 },	/* GPP_C */
156	{ 2, 1, 195, 219, 288 },	/* GPP_F */
157	{ 2, 3, 226, 250, 320 },	/* GPP_E */
158
159	/* Community 5 */
160	{ 3, 0, 260, 267, 352 },	/* GPP_R */
161};
162
163const struct pchgpio_device tgl_lp_device =
164{
165	.pad_size = 16,
166	.gpi_is = 0x100,
167	.gpi_ie = 0x120,
168	.groups = tgl_lp_groups,
169	.ngroups = nitems(tgl_lp_groups),
170	.npins = 360,
171};
172
173struct pchgpio_match pchgpio_devices[] = {
174	{ "INT34BB", &cnl_lp_device },
175	{ "INT34C5", &tgl_lp_device },
176};
177
178int	pchgpio_read_pin(void *, int);
179void	pchgpio_write_pin(void *, int, int);
180void	pchgpio_intr_establish(void *, int, int, int (*)(void *), void *);
181int	pchgpio_intr(void *);
182void	pchgpio_save(struct pchgpio_softc *);
183void	pchgpio_restore(struct pchgpio_softc *);
184
185int
186pchgpio_match(struct device *parent, void *match, void *aux)
187{
188	struct acpi_attach_args *aaa = aux;
189	struct cfdata *cf = match;
190
191	return acpi_matchhids(aaa, pchgpio_hids, cf->cf_driver->cd_name);
192}
193
194void
195pchgpio_attach(struct device *parent, struct device *self, void *aux)
196{
197	struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
198	struct acpi_attach_args *aaa = aux;
199	uint16_t bar;
200	int i;
201
202	sc->sc_acpi = (struct acpi_softc *)parent;
203	sc->sc_node = aaa->aaa_node;
204	printf(" %s", sc->sc_node->name);
205
206	if (aaa->aaa_naddr < 1) {
207		printf(": no registers\n");
208		return;
209	}
210
211	if (aaa->aaa_nirq < 1) {
212		printf(": no interrupt\n");
213		return;
214	}
215
216	printf(" addr");
217
218	for (i = 0; i < aaa->aaa_naddr; i++) {
219		printf(" 0x%llx/0x%llx", aaa->aaa_addr[i], aaa->aaa_size[i]);
220
221		sc->sc_memt[i] = aaa->aaa_bst[i];
222		if (bus_space_map(sc->sc_memt[i], aaa->aaa_addr[i],
223		    aaa->aaa_size[i], 0, &sc->sc_memh[i])) {
224			printf(": can't map registers\n");
225			goto unmap;
226		}
227
228		sc->sc_padbar[i] = bus_space_read_4(sc->sc_memt[i],
229		    sc->sc_memh[i], PCHGPIO_PADBAR);
230		sc->sc_naddr++;
231	}
232
233	printf(" irq %d", aaa->aaa_irq[0]);
234
235	for (i = 0; i < nitems(pchgpio_devices); i++) {
236		if (strcmp(pchgpio_devices[i].hid, aaa->aaa_dev) == 0) {
237			sc->sc_device = pchgpio_devices[i].device;
238			break;
239		}
240	}
241	KASSERT(sc->sc_device);
242
243	/* Figure out the first pin for each community. */
244	bar = -1;
245	for (i = 0; i < sc->sc_device->ngroups; i++) {
246		if (sc->sc_device->groups[i].bar != bar) {
247			bar = sc->sc_device->groups[i].bar;
248			sc->sc_padbase[bar] = sc->sc_device->groups[i].base;
249		}
250	}
251
252	sc->sc_padsize = sc->sc_device->pad_size;
253	sc->sc_npins = sc->sc_device->npins;
254	sc->sc_pin_cfg = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_cfg),
255	    M_DEVBUF, M_WAITOK);
256	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
257	    M_DEVBUF, M_WAITOK | M_ZERO);
258
259	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
260	    IPL_BIO, pchgpio_intr, sc, sc->sc_dev.dv_xname);
261	if (sc->sc_ih == NULL) {
262		printf(": can't establish interrupt\n");
263		goto unmap;
264	}
265
266	sc->sc_gpio.cookie = sc;
267	sc->sc_gpio.read_pin = pchgpio_read_pin;
268	sc->sc_gpio.write_pin = pchgpio_write_pin;
269	sc->sc_gpio.intr_establish = pchgpio_intr_establish;
270	sc->sc_node->gpio = &sc->sc_gpio;
271
272	printf(", %d pins\n", sc->sc_npins);
273
274	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
275	return;
276
277unmap:
278	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
279	free(sc->sc_pin_cfg, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_cfg));
280	for (i = 0; i < sc->sc_naddr; i++)
281		bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i],
282		    aaa->aaa_size[i]);
283}
284
285int
286pchgpio_activate(struct device *self, int act)
287{
288	struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
289
290	switch (act) {
291	case DVACT_SUSPEND:
292		pchgpio_save(sc);
293		break;
294	case DVACT_RESUME:
295		pchgpio_restore(sc);
296		break;
297	}
298
299	return 0;
300}
301
302const struct pchgpio_group *
303pchgpio_find_group(struct pchgpio_softc *sc, int pin)
304{
305	int i, npads;
306
307	for (i = 0; i < sc->sc_device->ngroups; i++) {
308		npads = 1 + sc->sc_device->groups[i].limit -
309		    sc->sc_device->groups[i].base;
310
311		if (pin >= sc->sc_device->groups[i].gpiobase &&
312		    pin < sc->sc_device->groups[i].gpiobase + npads)
313			return &sc->sc_device->groups[i];
314	}
315	return NULL;
316}
317
318int
319pchgpio_read_pin(void *cookie, int pin)
320{
321	struct pchgpio_softc *sc = cookie;
322	const struct pchgpio_group *group;
323	uint32_t reg;
324	uint16_t pad;
325	uint8_t bar;
326
327	group = pchgpio_find_group(sc, pin);
328	bar = group->bar;
329	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
330
331	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
332	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
333
334	return !!(reg & PCHGPIO_CONF_RXSTATE);
335}
336
337void
338pchgpio_write_pin(void *cookie, int pin, int value)
339{
340	struct pchgpio_softc *sc = cookie;
341	const struct pchgpio_group *group;
342	uint32_t reg;
343	uint16_t pad;
344	uint8_t bar;
345
346	group = pchgpio_find_group(sc, pin);
347	bar = group->bar;
348	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
349
350	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
351	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
352	if (value)
353		reg |= PCHGPIO_CONF_TXSTATE;
354	else
355		reg &= ~PCHGPIO_CONF_TXSTATE;
356	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
357	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
358}
359
360void
361pchgpio_intr_establish(void *cookie, int pin, int flags,
362    int (*func)(void *), void *arg)
363{
364	struct pchgpio_softc *sc = cookie;
365	const struct pchgpio_group *group;
366	uint32_t reg;
367	uint16_t pad;
368	uint8_t bank, bar;
369
370	KASSERT(pin >= 0);
371
372	group = pchgpio_find_group(sc, pin);
373	if (group == NULL)
374		return;
375
376	bar = group->bar;
377	bank = group->bank;
378	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
379
380	sc->sc_pin_ih[pin].ih_func = func;
381	sc->sc_pin_ih[pin].ih_arg = arg;
382
383	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
384	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
385	reg &= ~(PCHGPIO_CONF_RXEV_MASK | PCHGPIO_CONF_RXINV);
386	if ((flags & LR_GPIO_MODE) == 1)
387		reg |= PCHGPIO_CONF_RXEV_EDGE;
388	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO)
389		reg |= PCHGPIO_CONF_RXINV;
390	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH)
391		reg |= PCHGPIO_CONF_RXEV_EDGE | PCHGPIO_CONF_RXEV_ZERO;
392	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
393	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
394
395	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
396	    sc->sc_device->gpi_ie + bank * 4);
397	reg |= (1 << (pin - group->gpiobase));
398	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
399	    sc->sc_device->gpi_ie + bank * 4, reg);
400}
401
402int
403pchgpio_intr(void *arg)
404{
405	struct pchgpio_softc *sc = arg;
406	uint32_t status, enable;
407	int gpiobase, group, bit, pin, handled = 0;
408	uint16_t base, limit;
409	uint8_t bank, bar;
410
411	for (group = 0; group < sc->sc_device->ngroups; group++) {
412		bar = sc->sc_device->groups[group].bar;
413		bank = sc->sc_device->groups[group].bank;
414		base = sc->sc_device->groups[group].base;
415		limit = sc->sc_device->groups[group].limit;
416		gpiobase = sc->sc_device->groups[group].gpiobase;
417
418		status = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
419		    sc->sc_device->gpi_is + bank * 4);
420		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
421		    sc->sc_device->gpi_is + bank * 4, status);
422		enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
423		    sc->sc_device->gpi_ie + bank * 4);
424		status &= enable;
425		if (status == 0)
426			continue;
427
428		for (bit = 0; bit <= (limit - base); bit++) {
429			pin = gpiobase + bit;
430			if (status & (1 << bit) && sc->sc_pin_ih[pin].ih_func)
431				sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
432			handled = 1;
433		}
434	}
435
436	return handled;
437}
438
439void
440pchgpio_save_pin(struct pchgpio_softc *sc, int pin)
441{
442	const struct pchgpio_group *group;
443	uint16_t pad;
444	uint8_t bar;
445
446	group = pchgpio_find_group(sc, pin);
447	if (group == NULL)
448		return;
449
450	bar = group->bar;
451	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
452
453	sc->sc_pin_cfg[pin].pad_cfg_dw0 =
454	    bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
455		sc->sc_padbar[bar] + pad * sc->sc_padsize);
456	sc->sc_pin_cfg[pin].pad_cfg_dw1 =
457	    bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
458		sc->sc_padbar[bar] + pad * sc->sc_padsize + 4);
459}
460
461void
462pchgpio_save(struct pchgpio_softc *sc)
463{
464	int pin;
465
466	for (pin = 0; pin < sc->sc_npins; pin++)
467		pchgpio_save_pin(sc, pin);
468}
469
470void
471pchgpio_restore_pin(struct pchgpio_softc *sc, int pin)
472{
473	const struct pchgpio_group *group;
474	uint32_t pad_cfg_dw0;
475	uint16_t pad;
476	uint8_t bar;
477
478	group = pchgpio_find_group(sc, pin);
479	if (group == NULL)
480		return;
481
482	bar = group->bar;
483	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
484
485	pad_cfg_dw0 = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
486	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
487
488	/*
489	 * The BIOS on Lenovo Thinkpads based on Intel's Tiger Lake
490	 * platform have a bug where the GPIO pin that is used for the
491	 * touchpad interrupt gets reset when entering S3 and isn't
492	 * properly restored upon resume.  We detect this issue by
493	 * comparing the bits in the PAD_CFG_DW0 register PADRSTCFG
494	 * field before suspend and after resume and restore the pin
495	 * configuration if the bits don't match.
496	 */
497	if ((sc->sc_pin_cfg[pin].pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK) !=
498	    (pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK)) {
499		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
500		    sc->sc_padbar[bar] + pad * sc->sc_padsize,
501		    sc->sc_pin_cfg[pin].pad_cfg_dw0);
502		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
503		    sc->sc_padbar[bar] + pad * sc->sc_padsize + 4,
504		    sc->sc_pin_cfg[pin].pad_cfg_dw1);
505	}
506}
507
508void
509pchgpio_restore(struct pchgpio_softc *sc)
510{
511	int pin;
512
513	for (pin = 0; pin < sc->sc_npins; pin++)
514		pchgpio_restore_pin(sc, pin);
515}
516