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