xref: /openbsd-src/sys/dev/acpi/pchgpio.c (revision ffcef06798eb7b98532e76a80212f0772bebc4f6)
1 /*	$OpenBSD: pchgpio.c,v 1.5 2021/08/30 18:40:19 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 
38 #define PCHGPIO_PADBAR		0x00c
39 
40 struct pchgpio_group {
41 	uint8_t		bar;
42 	uint8_t		bank;
43 	uint16_t	base;
44 	uint16_t	limit;
45 	int16_t		gpiobase;
46 };
47 
48 struct pchgpio_device {
49 	uint16_t	pad_size;
50 	uint16_t	gpi_is;
51 	uint16_t	gpi_ie;
52 	const struct pchgpio_group *groups;
53 	int		ngroups;
54 	int		npins;
55 };
56 
57 struct pchgpio_match {
58 	const char	*hid;
59 	const struct pchgpio_device *device;
60 };
61 
62 struct pchgpio_intrhand {
63 	int (*ih_func)(void *);
64 	void *ih_arg;
65 };
66 
67 struct pchgpio_softc {
68 	struct device sc_dev;
69 	struct acpi_softc *sc_acpi;
70 	struct aml_node *sc_node;
71 
72 	bus_space_tag_t sc_memt[PCHGPIO_MAXCOM];
73 	bus_space_handle_t sc_memh[PCHGPIO_MAXCOM];
74 	void *sc_ih;
75 	int sc_naddr;
76 
77 	const struct pchgpio_device *sc_device;
78 	uint16_t sc_padbar[PCHGPIO_MAXCOM];
79 	uint16_t sc_padbase[PCHGPIO_MAXCOM];
80 	int sc_padsize;
81 
82 	int sc_npins;
83 	struct pchgpio_intrhand *sc_pin_ih;
84 
85 	struct acpi_gpio sc_gpio;
86 };
87 
88 int	pchgpio_match(struct device *, void *, void *);
89 void	pchgpio_attach(struct device *, struct device *, void *);
90 
91 struct cfattach pchgpio_ca = {
92 	sizeof(struct pchgpio_softc), pchgpio_match, pchgpio_attach
93 };
94 
95 struct cfdriver pchgpio_cd = {
96 	NULL, "pchgpio", DV_DULL
97 };
98 
99 const char *pchgpio_hids[] = {
100 	"INT34BB",
101 	"INT34C5",
102 	NULL
103 };
104 
105 const struct pchgpio_group cnl_lp_groups[] =
106 {
107 	/* Community 0 */
108 	{ 0, 0, 0, 24, 0 },		/* GPP_A */
109 	{ 0, 1, 25, 50, 32 },		/* GPP_B */
110 	{ 0, 2, 51, 58, 64 },		/* GPP_G */
111 
112 	/* Community 1 */
113 	{ 1, 0, 68, 92, 96 },		/* GPP_D */
114 	{ 1, 1, 93, 116, 128 },		/* GPP_F */
115 	{ 1, 2, 117, 140, 160 },	/* GPP_H */
116 
117 	/* Community 4 */
118 	{ 2, 0, 181, 204, 256 },	/* GPP_C */
119 	{ 2, 1, 205, 228, 288 },	/* GPP_E */
120 };
121 
122 const struct pchgpio_device cnl_lp_device =
123 {
124 	.pad_size = 16,
125 	.gpi_is = 0x100,
126 	.gpi_ie = 0x120,
127 	.groups = cnl_lp_groups,
128 	.ngroups = nitems(cnl_lp_groups),
129 	.npins = 320,
130 };
131 
132 const struct pchgpio_group tgl_lp_groups[] =
133 {
134 	/* Community 0 */
135 	{ 0, 0, 0, 25, 0 },		/* GPP_B */
136 	{ 0, 1, 26, 41, 32 },		/* GPP_T */
137 	{ 0, 2, 42, 66, 64 },		/* GPP_A */
138 
139 	/* Community 1 */
140 	{ 1, 0, 67, 74, 96 },		/* GPP_S */
141 	{ 1, 1, 75, 98, 128 },		/* GPP_H */
142 	{ 1, 2, 99, 119, 160 },		/* GPP_D */
143 	{ 1, 3, 120, 143, 192 },	/* GPP_U */
144 
145 	/* Community 4 */
146 	{ 2, 0, 171, 194, 256 },	/* GPP_C */
147 	{ 2, 1, 195, 219, 288 },	/* GPP_F */
148 	{ 2, 3, 226, 250, 320 },	/* GPP_E */
149 
150 	/* Community 5 */
151 	{ 3, 0, 260, 267, 352 },	/* GPP_R */
152 };
153 
154 const struct pchgpio_device tgl_lp_device =
155 {
156 	.pad_size = 16,
157 	.gpi_is = 0x100,
158 	.gpi_ie = 0x120,
159 	.groups = tgl_lp_groups,
160 	.ngroups = nitems(tgl_lp_groups),
161 	.npins = 360,
162 };
163 
164 struct pchgpio_match pchgpio_devices[] = {
165 	{ "INT34BB", &cnl_lp_device },
166 	{ "INT34C5", &tgl_lp_device },
167 };
168 
169 int	pchgpio_read_pin(void *, int);
170 void	pchgpio_write_pin(void *, int, int);
171 void	pchgpio_intr_establish(void *, int, int, int (*)(void *), void *);
172 int	pchgpio_intr(void *);
173 
174 int
175 pchgpio_match(struct device *parent, void *match, void *aux)
176 {
177 	struct acpi_attach_args *aaa = aux;
178 	struct cfdata *cf = match;
179 
180 	return acpi_matchhids(aaa, pchgpio_hids, cf->cf_driver->cd_name);
181 }
182 
183 void
184 pchgpio_attach(struct device *parent, struct device *self, void *aux)
185 {
186 	struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
187 	struct acpi_attach_args *aaa = aux;
188 	uint16_t bar;
189 	int i;
190 
191 	sc->sc_acpi = (struct acpi_softc *)parent;
192 	sc->sc_node = aaa->aaa_node;
193 	printf(" %s", sc->sc_node->name);
194 
195 	if (aaa->aaa_naddr < 1) {
196 		printf(": no registers\n");
197 		return;
198 	}
199 
200 	if (aaa->aaa_nirq < 1) {
201 		printf(": no interrupt\n");
202 		return;
203 	}
204 
205 	printf(" addr");
206 
207 	for (i = 0; i < aaa->aaa_naddr; i++) {
208 		printf(" 0x%llx/0x%llx", aaa->aaa_addr[i], aaa->aaa_size[i]);
209 
210 		sc->sc_memt[i] = aaa->aaa_bst[i];
211 		if (bus_space_map(sc->sc_memt[i], aaa->aaa_addr[i],
212 		    aaa->aaa_size[i], 0, &sc->sc_memh[i])) {
213 			printf(": can't map registers\n");
214 			goto unmap;
215 		}
216 
217 		sc->sc_padbar[i] = bus_space_read_4(sc->sc_memt[i],
218 		    sc->sc_memh[i], PCHGPIO_PADBAR);
219 		sc->sc_naddr++;
220 	}
221 
222 	printf(" irq %d", aaa->aaa_irq[0]);
223 
224 	for (i = 0; i < nitems(pchgpio_devices); i++) {
225 		if (strcmp(pchgpio_devices[i].hid, aaa->aaa_dev) == 0) {
226 			sc->sc_device = pchgpio_devices[i].device;
227 			break;
228 		}
229 	}
230 	KASSERT(sc->sc_device);
231 
232 	/* Figure out the first pin for each community. */
233 	bar = -1;
234 	for (i = 0; i < sc->sc_device->ngroups; i++) {
235 		if (sc->sc_device->groups[i].bar != bar) {
236 			bar = sc->sc_device->groups[i].bar;
237 			sc->sc_padbase[bar] = sc->sc_device->groups[i].base;
238 		}
239 	}
240 
241 	sc->sc_padsize = sc->sc_device->pad_size;
242 	sc->sc_npins = sc->sc_device->npins;
243 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
244 	    M_DEVBUF, M_WAITOK | M_ZERO);
245 
246 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
247 	    IPL_BIO, pchgpio_intr, sc, sc->sc_dev.dv_xname);
248 	if (sc->sc_ih == NULL) {
249 		printf(": can't establish interrupt\n");
250 		goto unmap;
251 	}
252 
253 	sc->sc_gpio.cookie = sc;
254 	sc->sc_gpio.read_pin = pchgpio_read_pin;
255 	sc->sc_gpio.write_pin = pchgpio_write_pin;
256 	sc->sc_gpio.intr_establish = pchgpio_intr_establish;
257 	sc->sc_node->gpio = &sc->sc_gpio;
258 
259 	printf(", %d pins\n", sc->sc_npins);
260 
261 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
262 	return;
263 
264 unmap:
265 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
266 	for (i = 0; i < sc->sc_naddr; i++)
267 		bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i],
268 		    aaa->aaa_size[i]);
269 }
270 
271 const struct pchgpio_group *
272 pchgpio_find_group(struct pchgpio_softc *sc, int pin)
273 {
274 	int i, npads;
275 
276 	for (i = 0; i < sc->sc_device->ngroups; i++) {
277 		npads = 1 + sc->sc_device->groups[i].limit -
278 		    sc->sc_device->groups[i].base;
279 
280 		if (pin >= sc->sc_device->groups[i].gpiobase &&
281 		    pin < sc->sc_device->groups[i].gpiobase + npads)
282 			return &sc->sc_device->groups[i];
283 	}
284 	return NULL;
285 }
286 
287 int
288 pchgpio_read_pin(void *cookie, int pin)
289 {
290 	struct pchgpio_softc *sc = cookie;
291 	const struct pchgpio_group *group;
292 	uint32_t reg;
293 	uint16_t pad;
294 	uint8_t bar;
295 
296 	group = pchgpio_find_group(sc, pin);
297 	bar = group->bar;
298 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
299 
300 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
301 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
302 
303 	return !!(reg & PCHGPIO_CONF_RXSTATE);
304 }
305 
306 void
307 pchgpio_write_pin(void *cookie, int pin, int value)
308 {
309 	struct pchgpio_softc *sc = cookie;
310 	const struct pchgpio_group *group;
311 	uint32_t reg;
312 	uint16_t pad;
313 	uint8_t bar;
314 
315 	group = pchgpio_find_group(sc, pin);
316 	bar = group->bar;
317 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
318 
319 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
320 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
321 	if (value)
322 		reg |= PCHGPIO_CONF_TXSTATE;
323 	else
324 		reg &= ~PCHGPIO_CONF_TXSTATE;
325 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
326 	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
327 }
328 
329 void
330 pchgpio_intr_establish(void *cookie, int pin, int flags,
331     int (*func)(void *), void *arg)
332 {
333 	struct pchgpio_softc *sc = cookie;
334 	const struct pchgpio_group *group;
335 	uint32_t reg;
336 	uint16_t pad;
337 	uint8_t bank, bar;
338 
339 	KASSERT(pin >= 0);
340 
341 	group = pchgpio_find_group(sc, pin);
342 	if (group == NULL)
343 		return;
344 
345 	bar = group->bar;
346 	bank = group->bank;
347 	pad = group->base + (pin - group->gpiobase) - sc->sc_padbase[bar];
348 
349 	sc->sc_pin_ih[pin].ih_func = func;
350 	sc->sc_pin_ih[pin].ih_arg = arg;
351 
352 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
353 	    sc->sc_padbar[bar] + pad * sc->sc_padsize);
354 	reg &= ~(PCHGPIO_CONF_RXEV_MASK | PCHGPIO_CONF_RXINV);
355 	if ((flags & LR_GPIO_MODE) == 1)
356 		reg |= PCHGPIO_CONF_RXEV_EDGE;
357 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO)
358 		reg |= PCHGPIO_CONF_RXINV;
359 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH)
360 		reg |= PCHGPIO_CONF_RXEV_EDGE | PCHGPIO_CONF_RXEV_ZERO;
361 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
362 	    sc->sc_padbar[bar] + pad * sc->sc_padsize, reg);
363 
364 	reg = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
365 	    sc->sc_device->gpi_ie + bank * 4);
366 	reg |= (1 << (pin - group->gpiobase));
367 	bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
368 	    sc->sc_device->gpi_ie + bank * 4, reg);
369 }
370 
371 int
372 pchgpio_intr(void *arg)
373 {
374 	struct pchgpio_softc *sc = arg;
375 	uint32_t status, enable;
376 	int gpiobase, group, bit, pin, handled = 0;
377 	uint16_t base, limit;
378 	uint8_t bank, bar;
379 
380 	for (group = 0; group < sc->sc_device->ngroups; group++) {
381 		bar = sc->sc_device->groups[group].bar;
382 		bank = sc->sc_device->groups[group].bank;
383 		base = sc->sc_device->groups[group].base;
384 		limit = sc->sc_device->groups[group].limit;
385 		gpiobase = sc->sc_device->groups[group].gpiobase;
386 
387 		status = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
388 		    sc->sc_device->gpi_is + bank * 4);
389 		bus_space_write_4(sc->sc_memt[bar], sc->sc_memh[bar],
390 		    sc->sc_device->gpi_is + bank * 4, status);
391 		enable = bus_space_read_4(sc->sc_memt[bar], sc->sc_memh[bar],
392 		    sc->sc_device->gpi_ie + bank * 4);
393 		status &= enable;
394 		if (status == 0)
395 			continue;
396 
397 		for (bit = 0; bit <= (limit - base); bit++) {
398 			pin = gpiobase + bit;
399 			if (status & (1 << bit) && sc->sc_pin_ih[pin].ih_func)
400 				sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
401 			handled = 1;
402 		}
403 	}
404 
405 	return handled;
406 }
407