xref: /openbsd-src/sys/dev/acpi/amdgpio.c (revision 244d7b1765700fd7cbc9c1a45e8ef15f2ae492a6)
1*244d7b17Skettenis /*	$OpenBSD: amdgpio.c,v 1.10 2022/10/20 20:40:57 kettenis Exp $	*/
2ae3c87c9Skettenis /*
3ae3c87c9Skettenis  * Copyright (c) 2016 Mark Kettenis
4ae3c87c9Skettenis  * Copyright (c) 2019 James Hastings
5ae3c87c9Skettenis  *
6ae3c87c9Skettenis  * Permission to use, copy, modify, and distribute this software for any
7ae3c87c9Skettenis  * purpose with or without fee is hereby granted, provided that the above
8ae3c87c9Skettenis  * copyright notice and this permission notice appear in all copies.
9ae3c87c9Skettenis  *
10ae3c87c9Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11ae3c87c9Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12ae3c87c9Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13ae3c87c9Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14ae3c87c9Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15ae3c87c9Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16ae3c87c9Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17ae3c87c9Skettenis  */
18ae3c87c9Skettenis 
19ae3c87c9Skettenis #include <sys/param.h>
20ae3c87c9Skettenis #include <sys/malloc.h>
21ae3c87c9Skettenis #include <sys/systm.h>
22ae3c87c9Skettenis 
23ae3c87c9Skettenis #include <dev/acpi/acpireg.h>
24ae3c87c9Skettenis #include <dev/acpi/acpivar.h>
25ae3c87c9Skettenis #include <dev/acpi/acpidev.h>
26ae3c87c9Skettenis #include <dev/acpi/amltypes.h>
27ae3c87c9Skettenis #include <dev/acpi/dsdt.h>
28ae3c87c9Skettenis 
29ae3c87c9Skettenis #define AMDGPIO_CONF_LEVEL		0x00000100
30ae3c87c9Skettenis #define AMDGPIO_CONF_ACTLO		0x00000200
31ae3c87c9Skettenis #define AMDGPIO_CONF_ACTBOTH		0x00000400
32ae3c87c9Skettenis #define AMDGPIO_CONF_MASK		0x00000600
33ae3c87c9Skettenis #define AMDGPIO_CONF_INT_EN		0x00000800
34ae3c87c9Skettenis #define AMDGPIO_CONF_INT_MASK		0x00001000
35ae3c87c9Skettenis #define AMDGPIO_CONF_RXSTATE		0x00010000
36ae3c87c9Skettenis #define AMDGPIO_CONF_TXSTATE		0x00400000
37ae3c87c9Skettenis #define AMDGPIO_CONF_TXSTATE_EN		0x00800000
38ae3c87c9Skettenis #define AMDGPIO_CONF_INT_STS		0x10000000
39ae3c87c9Skettenis #define AMDGPIO_IRQ_MASTER_EOI		0x20000000
40ae3c87c9Skettenis #define AMDGPIO_IRQ_BITS		46
41ae3c87c9Skettenis #define AMDGPIO_IRQ_PINS		4
42ae3c87c9Skettenis 
43ae3c87c9Skettenis #define AMDGPIO_IRQ_MASTER		0xfc
44ae3c87c9Skettenis #define AMDGPIO_IRQ_STS			0x2f8
45ae3c87c9Skettenis 
46ae3c87c9Skettenis struct amdgpio_intrhand {
47ae3c87c9Skettenis 	int (*ih_func)(void *);
48ae3c87c9Skettenis 	void *ih_arg;
49ae3c87c9Skettenis };
50ae3c87c9Skettenis 
51a29e15c6Smlarkin struct amdgpio_pincfg {
52a29e15c6Smlarkin 	/* Modeled after pchgpio but we only have one value to save/restore */
53a29e15c6Smlarkin 	uint32_t	pin_cfg;
54a29e15c6Smlarkin };
55a29e15c6Smlarkin 
56ae3c87c9Skettenis struct amdgpio_softc {
57ae3c87c9Skettenis 	struct device sc_dev;
58ae3c87c9Skettenis 	struct acpi_softc *sc_acpi;
59ae3c87c9Skettenis 	struct aml_node *sc_node;
60ae3c87c9Skettenis 
61ae3c87c9Skettenis 	bus_space_tag_t sc_memt;
62ae3c87c9Skettenis 	bus_space_handle_t sc_memh;
63ae3c87c9Skettenis 	int sc_irq_flags;
64ae3c87c9Skettenis 	void *sc_ih;
65ae3c87c9Skettenis 
66ae3c87c9Skettenis 	int sc_npins;
67a29e15c6Smlarkin 	struct amdgpio_pincfg *sc_pin_cfg;
68ae3c87c9Skettenis 	struct amdgpio_intrhand *sc_pin_ih;
69ae3c87c9Skettenis 
70ae3c87c9Skettenis 	struct acpi_gpio sc_gpio;
71ae3c87c9Skettenis };
72ae3c87c9Skettenis 
73ae3c87c9Skettenis int	amdgpio_match(struct device *, void *, void *);
74ae3c87c9Skettenis void	amdgpio_attach(struct device *, struct device *, void *);
75a29e15c6Smlarkin int	amdgpio_activate(struct device *, int);
76ae3c87c9Skettenis 
77471aeecfSnaddy const struct cfattach amdgpio_ca = {
78a29e15c6Smlarkin 	sizeof(struct amdgpio_softc), amdgpio_match, amdgpio_attach,
79a29e15c6Smlarkin 	NULL, amdgpio_activate
80ae3c87c9Skettenis };
81ae3c87c9Skettenis 
82ae3c87c9Skettenis struct cfdriver amdgpio_cd = {
83ae3c87c9Skettenis 	NULL, "amdgpio", DV_DULL
84ae3c87c9Skettenis };
85ae3c87c9Skettenis 
86ae3c87c9Skettenis const char *amdgpio_hids[] = {
87ae3c87c9Skettenis 	"AMDI0030",
88ae3c87c9Skettenis 	"AMD0030",
89ae3c87c9Skettenis 	NULL
90ae3c87c9Skettenis };
91ae3c87c9Skettenis 
92ae3c87c9Skettenis int	amdgpio_read_pin(void *, int);
93ae3c87c9Skettenis void	amdgpio_write_pin(void *, int, int);
94beb775c7Sjsg void	amdgpio_intr_establish(void *, int, int, int (*)(void *), void *);
95*244d7b17Skettenis void	amdgpio_intr_enable(void *, int);
96*244d7b17Skettenis void	amdgpio_intr_disable(void *, int);
97ae3c87c9Skettenis int	amdgpio_pin_intr(struct amdgpio_softc *, int);
98ae3c87c9Skettenis int	amdgpio_intr(void *);
99a29e15c6Smlarkin void	amdgpio_save_pin(struct amdgpio_softc *, int pin);
100a29e15c6Smlarkin void	amdgpio_save(struct amdgpio_softc *);
101a29e15c6Smlarkin void	amdgpio_restore_pin(struct amdgpio_softc *, int pin);
102a29e15c6Smlarkin void	amdgpio_restore(struct amdgpio_softc *);
103ae3c87c9Skettenis 
104ae3c87c9Skettenis int
amdgpio_match(struct device * parent,void * match,void * aux)105ae3c87c9Skettenis amdgpio_match(struct device *parent, void *match, void *aux)
106ae3c87c9Skettenis {
107ae3c87c9Skettenis 	struct acpi_attach_args *aaa = aux;
108ae3c87c9Skettenis 	struct cfdata *cf = match;
109ae3c87c9Skettenis 
11057ec0946Skettenis 	if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1)
11157ec0946Skettenis 		return 0;
112ae3c87c9Skettenis 	return acpi_matchhids(aaa, amdgpio_hids, cf->cf_driver->cd_name);
113ae3c87c9Skettenis }
114ae3c87c9Skettenis 
115ae3c87c9Skettenis void
amdgpio_attach(struct device * parent,struct device * self,void * aux)116ae3c87c9Skettenis amdgpio_attach(struct device *parent, struct device *self, void *aux)
117ae3c87c9Skettenis {
118ae3c87c9Skettenis 	struct acpi_attach_args *aaa = aux;
119ae3c87c9Skettenis 	struct amdgpio_softc *sc = (struct amdgpio_softc *)self;
120ae3c87c9Skettenis 	int64_t uid;
121ae3c87c9Skettenis 
122ae3c87c9Skettenis 	sc->sc_acpi = (struct acpi_softc *)parent;
123ae3c87c9Skettenis 	sc->sc_node = aaa->aaa_node;
1249f1f78b7Skettenis 	printf(" %s", sc->sc_node->name);
1259f1f78b7Skettenis 
126ae3c87c9Skettenis 	if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) {
1279f1f78b7Skettenis 		printf(": can't find uid\n");
128ae3c87c9Skettenis 		return;
129ae3c87c9Skettenis 	}
130ae3c87c9Skettenis 
131ae3c87c9Skettenis 	printf(" uid %lld", uid);
132ae3c87c9Skettenis 
133ae3c87c9Skettenis 	switch (uid) {
134ae3c87c9Skettenis 	case 0:
135ae3c87c9Skettenis 		sc->sc_npins = 184;
136ae3c87c9Skettenis 		break;
137ae3c87c9Skettenis 	default:
138ae3c87c9Skettenis 		printf("\n");
139ae3c87c9Skettenis 		return;
140ae3c87c9Skettenis 	}
141ae3c87c9Skettenis 
1429f1f78b7Skettenis 	printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
1439f1f78b7Skettenis 	printf(" irq %d", aaa->aaa_irq[0]);
144ae3c87c9Skettenis 
1459f1f78b7Skettenis 	sc->sc_memt = aaa->aaa_bst[0];
1469f1f78b7Skettenis 	if (bus_space_map(sc->sc_memt, aaa->aaa_addr[0], aaa->aaa_size[0],
1479f1f78b7Skettenis 	    0, &sc->sc_memh)) {
1489f1f78b7Skettenis 		printf(": can't map registers\n");
149ae3c87c9Skettenis 		return;
150ae3c87c9Skettenis 	}
151ae3c87c9Skettenis 
152a29e15c6Smlarkin 	sc->sc_pin_cfg = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_cfg),
153a29e15c6Smlarkin 	    M_DEVBUF, M_WAITOK);
154ae3c87c9Skettenis 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
1559f1f78b7Skettenis 	    M_DEVBUF, M_WAITOK | M_ZERO);
156ae3c87c9Skettenis 
1579f1f78b7Skettenis 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
1589f1f78b7Skettenis 	    IPL_BIO, amdgpio_intr, sc, sc->sc_dev.dv_xname);
159ae3c87c9Skettenis 	if (sc->sc_ih == NULL) {
1609f1f78b7Skettenis 		printf(": can't establish interrupt\n");
161ae3c87c9Skettenis 		goto unmap;
162ae3c87c9Skettenis 	}
163ae3c87c9Skettenis 
164ae3c87c9Skettenis 	sc->sc_gpio.cookie = sc;
165ae3c87c9Skettenis 	sc->sc_gpio.read_pin = amdgpio_read_pin;
166ae3c87c9Skettenis 	sc->sc_gpio.write_pin = amdgpio_write_pin;
167ae3c87c9Skettenis 	sc->sc_gpio.intr_establish = amdgpio_intr_establish;
168*244d7b17Skettenis 	sc->sc_gpio.intr_enable = amdgpio_intr_enable;
169*244d7b17Skettenis 	sc->sc_gpio.intr_disable = amdgpio_intr_disable;
170ae3c87c9Skettenis 	sc->sc_node->gpio = &sc->sc_gpio;
171ae3c87c9Skettenis 
172ae3c87c9Skettenis 	printf(", %d pins\n", sc->sc_npins);
173ae3c87c9Skettenis 
174ae3c87c9Skettenis 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
175ae3c87c9Skettenis 	return;
176ae3c87c9Skettenis 
177ae3c87c9Skettenis unmap:
178ae3c87c9Skettenis 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
1799f1f78b7Skettenis 	bus_space_unmap(sc->sc_memt, sc->sc_memh, aaa->aaa_size[0]);
180ae3c87c9Skettenis }
181ae3c87c9Skettenis 
182ae3c87c9Skettenis int
amdgpio_activate(struct device * self,int act)183a29e15c6Smlarkin amdgpio_activate(struct device *self, int act)
184a29e15c6Smlarkin {
185a29e15c6Smlarkin 	struct amdgpio_softc *sc = (struct amdgpio_softc *)self;
186a29e15c6Smlarkin 
187a29e15c6Smlarkin 	switch (act) {
188a29e15c6Smlarkin 	case DVACT_SUSPEND:
189a29e15c6Smlarkin 		amdgpio_save(sc);
190a29e15c6Smlarkin 		break;
191a29e15c6Smlarkin 	case DVACT_RESUME:
192a29e15c6Smlarkin 		amdgpio_restore(sc);
193a29e15c6Smlarkin 		break;
194a29e15c6Smlarkin 	}
195a29e15c6Smlarkin 
196a29e15c6Smlarkin 	return 0;
197a29e15c6Smlarkin }
198a29e15c6Smlarkin 
199a29e15c6Smlarkin void
amdgpio_save_pin(struct amdgpio_softc * sc,int pin)200a29e15c6Smlarkin amdgpio_save_pin(struct amdgpio_softc *sc, int pin)
201a29e15c6Smlarkin {
202a29e15c6Smlarkin 	sc->sc_pin_cfg[pin].pin_cfg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
203a29e15c6Smlarkin 	    pin * 4);
204a29e15c6Smlarkin }
205a29e15c6Smlarkin 
206a29e15c6Smlarkin void
amdgpio_save(struct amdgpio_softc * sc)207a29e15c6Smlarkin amdgpio_save(struct amdgpio_softc *sc)
208a29e15c6Smlarkin {
209a29e15c6Smlarkin 	int pin;
210a29e15c6Smlarkin 
211a29e15c6Smlarkin 	for (pin = 0; pin < sc->sc_npins; pin++)
212a29e15c6Smlarkin 		amdgpio_save_pin(sc, pin);
213a29e15c6Smlarkin }
214a29e15c6Smlarkin 
215a29e15c6Smlarkin void
amdgpio_restore_pin(struct amdgpio_softc * sc,int pin)216a29e15c6Smlarkin amdgpio_restore_pin(struct amdgpio_softc *sc, int pin)
217a29e15c6Smlarkin {
218a29e15c6Smlarkin 	if (!sc->sc_pin_ih[pin].ih_func)
219a29e15c6Smlarkin 		return;
220a29e15c6Smlarkin 
221a29e15c6Smlarkin 	bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4,
222a29e15c6Smlarkin 	    sc->sc_pin_cfg[pin].pin_cfg);
223a29e15c6Smlarkin }
224a29e15c6Smlarkin 
225a29e15c6Smlarkin void
amdgpio_restore(struct amdgpio_softc * sc)226a29e15c6Smlarkin amdgpio_restore(struct amdgpio_softc *sc)
227a29e15c6Smlarkin {
228a29e15c6Smlarkin 	int pin;
229a29e15c6Smlarkin 
230a29e15c6Smlarkin 	for (pin = 0; pin < sc->sc_npins; pin++)
231a29e15c6Smlarkin 		amdgpio_restore_pin(sc, pin);
232a29e15c6Smlarkin }
233a29e15c6Smlarkin 
234a29e15c6Smlarkin int
amdgpio_read_pin(void * cookie,int pin)235ae3c87c9Skettenis amdgpio_read_pin(void *cookie, int pin)
236ae3c87c9Skettenis {
237ae3c87c9Skettenis 	struct amdgpio_softc *sc = cookie;
238ae3c87c9Skettenis 	uint32_t reg;
239ae3c87c9Skettenis 
240ae3c87c9Skettenis 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
241ae3c87c9Skettenis 
242ae3c87c9Skettenis 	return !!(reg & AMDGPIO_CONF_RXSTATE);
243ae3c87c9Skettenis }
244ae3c87c9Skettenis 
245ae3c87c9Skettenis void
amdgpio_write_pin(void * cookie,int pin,int value)246ae3c87c9Skettenis amdgpio_write_pin(void *cookie, int pin, int value)
247ae3c87c9Skettenis {
248ae3c87c9Skettenis 	struct amdgpio_softc *sc = cookie;
249ae3c87c9Skettenis 	uint32_t reg;
250ae3c87c9Skettenis 
251ae3c87c9Skettenis 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
252ae3c87c9Skettenis 	reg |= AMDGPIO_CONF_TXSTATE_EN;
253ae3c87c9Skettenis 	if (value)
254ae3c87c9Skettenis 		reg |= AMDGPIO_CONF_TXSTATE;
255ae3c87c9Skettenis 	else
256ae3c87c9Skettenis 		reg &= ~AMDGPIO_CONF_TXSTATE;
257ae3c87c9Skettenis 	bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg);
258ae3c87c9Skettenis }
259ae3c87c9Skettenis 
260ae3c87c9Skettenis void
amdgpio_intr_establish(void * cookie,int pin,int flags,int (* func)(void *),void * arg)261ae3c87c9Skettenis amdgpio_intr_establish(void *cookie, int pin, int flags,
262ae3c87c9Skettenis     int (*func)(void *), void *arg)
263ae3c87c9Skettenis {
264ae3c87c9Skettenis 	struct amdgpio_softc *sc = cookie;
265ae3c87c9Skettenis 	uint32_t reg;
266ae3c87c9Skettenis 
267ae3c87c9Skettenis 	KASSERT(pin >= 0 && pin != 63 && pin < sc->sc_npins);
268ae3c87c9Skettenis 
269ae3c87c9Skettenis 	sc->sc_pin_ih[pin].ih_func = func;
270ae3c87c9Skettenis 	sc->sc_pin_ih[pin].ih_arg = arg;
271ae3c87c9Skettenis 
272ae3c87c9Skettenis 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
273ae3c87c9Skettenis 	reg &= ~(AMDGPIO_CONF_MASK | AMDGPIO_CONF_LEVEL |
274ae3c87c9Skettenis 	    AMDGPIO_CONF_TXSTATE_EN);
275ae3c87c9Skettenis 	if ((flags & LR_GPIO_MODE) == 0)
276ae3c87c9Skettenis 		reg |= AMDGPIO_CONF_LEVEL;
277ae3c87c9Skettenis 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO)
278ae3c87c9Skettenis 		reg |= AMDGPIO_CONF_ACTLO;
279ae3c87c9Skettenis 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH)
280ae3c87c9Skettenis 		reg |= AMDGPIO_CONF_ACTBOTH;
281ae3c87c9Skettenis 	reg |= (AMDGPIO_CONF_INT_MASK | AMDGPIO_CONF_INT_EN);
282ae3c87c9Skettenis 	bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg);
283ae3c87c9Skettenis }
284ae3c87c9Skettenis 
285*244d7b17Skettenis void
amdgpio_intr_enable(void * cookie,int pin)286*244d7b17Skettenis amdgpio_intr_enable(void *cookie, int pin)
287*244d7b17Skettenis {
288*244d7b17Skettenis 	struct amdgpio_softc *sc = cookie;
289*244d7b17Skettenis 	uint32_t reg;
290*244d7b17Skettenis 
291*244d7b17Skettenis 	KASSERT(pin >= 0 && pin != 63 && pin < sc->sc_npins);
292*244d7b17Skettenis 
293*244d7b17Skettenis 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
294*244d7b17Skettenis 	reg |= (AMDGPIO_CONF_INT_MASK | AMDGPIO_CONF_INT_EN);
295*244d7b17Skettenis 	bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg);
296*244d7b17Skettenis }
297*244d7b17Skettenis 
298*244d7b17Skettenis void
amdgpio_intr_disable(void * cookie,int pin)299*244d7b17Skettenis amdgpio_intr_disable(void *cookie, int pin)
300*244d7b17Skettenis {
301*244d7b17Skettenis 	struct amdgpio_softc *sc = cookie;
302*244d7b17Skettenis 	uint32_t reg;
303*244d7b17Skettenis 
304*244d7b17Skettenis 	KASSERT(pin >= 0 && pin != 63 && pin < sc->sc_npins);
305*244d7b17Skettenis 
306*244d7b17Skettenis 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
307*244d7b17Skettenis 	reg &= ~(AMDGPIO_CONF_INT_MASK | AMDGPIO_CONF_INT_EN);
308*244d7b17Skettenis 	bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg);
309*244d7b17Skettenis }
310*244d7b17Skettenis 
311ae3c87c9Skettenis int
amdgpio_pin_intr(struct amdgpio_softc * sc,int pin)312ae3c87c9Skettenis amdgpio_pin_intr(struct amdgpio_softc *sc, int pin)
313ae3c87c9Skettenis {
314ae3c87c9Skettenis 	uint32_t reg;
3158ffdb2b1Sjsg 	int rc = 0;
316ae3c87c9Skettenis 
317ae3c87c9Skettenis 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
3188ffdb2b1Sjsg 	if (reg & AMDGPIO_CONF_INT_STS) {
3198ffdb2b1Sjsg 		if (sc->sc_pin_ih[pin].ih_func) {
320ae3c87c9Skettenis 			sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
321ae3c87c9Skettenis 
322ae3c87c9Skettenis 			/* Clear interrupt */
3238ffdb2b1Sjsg 			reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
3248ffdb2b1Sjsg 			    pin * 4);
3258ffdb2b1Sjsg 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
3268ffdb2b1Sjsg 			    pin * 4, reg);
3278ffdb2b1Sjsg 			rc = 1;
3288ffdb2b1Sjsg 		} else {
3298ffdb2b1Sjsg 			/* Mask unhandled interrupt */
3308ffdb2b1Sjsg 			reg &= ~(AMDGPIO_CONF_INT_MASK | AMDGPIO_CONF_INT_EN);
3318ffdb2b1Sjsg 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
3328ffdb2b1Sjsg 			    pin * 4, reg);
3338ffdb2b1Sjsg 		}
3348ffdb2b1Sjsg 	}
335ae3c87c9Skettenis 
3368ffdb2b1Sjsg 	return rc;
337ae3c87c9Skettenis }
338ae3c87c9Skettenis 
339ae3c87c9Skettenis int
amdgpio_intr(void * arg)340ae3c87c9Skettenis amdgpio_intr(void *arg)
341ae3c87c9Skettenis {
342ae3c87c9Skettenis 	struct amdgpio_softc *sc = arg;
343ae3c87c9Skettenis 	uint64_t status;
344ae3c87c9Skettenis 	uint32_t reg;
345ae3c87c9Skettenis 	int rc = 0, pin = 0;
346ae3c87c9Skettenis 	int i, j;
347ae3c87c9Skettenis 
348ae3c87c9Skettenis 	status = bus_space_read_4(sc->sc_memt, sc->sc_memh,
349ae3c87c9Skettenis 	    AMDGPIO_IRQ_STS + 4);
350ae3c87c9Skettenis 	status <<= 32;
351ae3c87c9Skettenis 	status |= bus_space_read_4(sc->sc_memt, sc->sc_memh,
352ae3c87c9Skettenis 	    AMDGPIO_IRQ_STS);
353ae3c87c9Skettenis 
354ae3c87c9Skettenis 	/* One status bit for every four pins */
355ae3c87c9Skettenis 	for (i = 0; i < AMDGPIO_IRQ_BITS; i++, pin += 4) {
356c0937d19Skrw 		if (status & (1ULL << i)) {
357ae3c87c9Skettenis 			for (j = 0; j < AMDGPIO_IRQ_PINS; j++) {
358ae3c87c9Skettenis 				if (amdgpio_pin_intr(sc, pin + j))
359ae3c87c9Skettenis 					rc = 1;
360ae3c87c9Skettenis 			}
361ae3c87c9Skettenis 		}
362ae3c87c9Skettenis 	}
363ae3c87c9Skettenis 
364ae3c87c9Skettenis 	/* Signal end of interrupt */
365ae3c87c9Skettenis 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
366ae3c87c9Skettenis 	    AMDGPIO_IRQ_MASTER);
367ae3c87c9Skettenis 	reg |= AMDGPIO_IRQ_MASTER_EOI;
368ae3c87c9Skettenis 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
369ae3c87c9Skettenis 	    AMDGPIO_IRQ_MASTER, reg);
370ae3c87c9Skettenis 
371ae3c87c9Skettenis 	return rc;
372ae3c87c9Skettenis }
373