xref: /openbsd-src/sys/dev/acpi/amdgpio.c (revision c1a45aed656e7d5627c30c92421893a76f370ccb)
1 /*	$OpenBSD: amdgpio.c,v 1.7 2022/04/06 18:59:27 naddy Exp $	*/
2 /*
3  * Copyright (c) 2016 Mark Kettenis
4  * Copyright (c) 2019 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 AMDGPIO_CONF_LEVEL		0x00000100
30 #define AMDGPIO_CONF_ACTLO		0x00000200
31 #define AMDGPIO_CONF_ACTBOTH		0x00000400
32 #define AMDGPIO_CONF_MASK		0x00000600
33 #define AMDGPIO_CONF_INT_EN		0x00000800
34 #define AMDGPIO_CONF_INT_MASK		0x00001000
35 #define AMDGPIO_CONF_RXSTATE		0x00010000
36 #define AMDGPIO_CONF_TXSTATE		0x00400000
37 #define AMDGPIO_CONF_TXSTATE_EN		0x00800000
38 #define AMDGPIO_CONF_INT_STS		0x10000000
39 #define AMDGPIO_IRQ_MASTER_EOI		0x20000000
40 #define AMDGPIO_IRQ_BITS		46
41 #define AMDGPIO_IRQ_PINS		4
42 
43 #define AMDGPIO_IRQ_MASTER		0xfc
44 #define AMDGPIO_IRQ_STS			0x2f8
45 
46 struct amdgpio_intrhand {
47 	int (*ih_func)(void *);
48 	void *ih_arg;
49 };
50 
51 struct amdgpio_softc {
52 	struct device sc_dev;
53 	struct acpi_softc *sc_acpi;
54 	struct aml_node *sc_node;
55 
56 	bus_space_tag_t sc_memt;
57 	bus_space_handle_t sc_memh;
58 	int sc_irq_flags;
59 	void *sc_ih;
60 
61 	int sc_npins;
62 	struct amdgpio_intrhand *sc_pin_ih;
63 
64 	struct acpi_gpio sc_gpio;
65 };
66 
67 int	amdgpio_match(struct device *, void *, void *);
68 void	amdgpio_attach(struct device *, struct device *, void *);
69 
70 const struct cfattach amdgpio_ca = {
71 	sizeof(struct amdgpio_softc), amdgpio_match, amdgpio_attach
72 };
73 
74 struct cfdriver amdgpio_cd = {
75 	NULL, "amdgpio", DV_DULL
76 };
77 
78 const char *amdgpio_hids[] = {
79 	"AMDI0030",
80 	"AMD0030",
81 	NULL
82 };
83 
84 int	amdgpio_read_pin(void *, int);
85 void	amdgpio_write_pin(void *, int, int);
86 void	amdgpio_intr_establish(void *, int, int, int (*)(void *), void *);
87 int	amdgpio_pin_intr(struct amdgpio_softc *, int);
88 int	amdgpio_intr(void *);
89 
90 int
91 amdgpio_match(struct device *parent, void *match, void *aux)
92 {
93 	struct acpi_attach_args *aaa = aux;
94 	struct cfdata *cf = match;
95 
96 	if (aaa->aaa_naddr < 1 || aaa->aaa_nirq < 1)
97 		return 0;
98 	return acpi_matchhids(aaa, amdgpio_hids, cf->cf_driver->cd_name);
99 }
100 
101 void
102 amdgpio_attach(struct device *parent, struct device *self, void *aux)
103 {
104 	struct acpi_attach_args *aaa = aux;
105 	struct amdgpio_softc *sc = (struct amdgpio_softc *)self;
106 	int64_t uid;
107 
108 	sc->sc_acpi = (struct acpi_softc *)parent;
109 	sc->sc_node = aaa->aaa_node;
110 	printf(" %s", sc->sc_node->name);
111 
112 	if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) {
113 		printf(": can't find uid\n");
114 		return;
115 	}
116 
117 	printf(" uid %lld", uid);
118 
119 	switch (uid) {
120 	case 0:
121 		sc->sc_npins = 184;
122 		break;
123 	default:
124 		printf("\n");
125 		return;
126 	}
127 
128 	printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
129 	printf(" irq %d", aaa->aaa_irq[0]);
130 
131 	sc->sc_memt = aaa->aaa_bst[0];
132 	if (bus_space_map(sc->sc_memt, aaa->aaa_addr[0], aaa->aaa_size[0],
133 	    0, &sc->sc_memh)) {
134 		printf(": can't map registers\n");
135 		return;
136 	}
137 
138 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
139 	    M_DEVBUF, M_WAITOK | M_ZERO);
140 
141 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
142 	    IPL_BIO, amdgpio_intr, sc, sc->sc_dev.dv_xname);
143 	if (sc->sc_ih == NULL) {
144 		printf(": can't establish interrupt\n");
145 		goto unmap;
146 	}
147 
148 	sc->sc_gpio.cookie = sc;
149 	sc->sc_gpio.read_pin = amdgpio_read_pin;
150 	sc->sc_gpio.write_pin = amdgpio_write_pin;
151 	sc->sc_gpio.intr_establish = amdgpio_intr_establish;
152 	sc->sc_node->gpio = &sc->sc_gpio;
153 
154 	printf(", %d pins\n", sc->sc_npins);
155 
156 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
157 	return;
158 
159 unmap:
160 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
161 	bus_space_unmap(sc->sc_memt, sc->sc_memh, aaa->aaa_size[0]);
162 }
163 
164 int
165 amdgpio_read_pin(void *cookie, int pin)
166 {
167 	struct amdgpio_softc *sc = cookie;
168 	uint32_t reg;
169 
170 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
171 
172 	return !!(reg & AMDGPIO_CONF_RXSTATE);
173 }
174 
175 void
176 amdgpio_write_pin(void *cookie, int pin, int value)
177 {
178 	struct amdgpio_softc *sc = cookie;
179 	uint32_t reg;
180 
181 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
182 	reg |= AMDGPIO_CONF_TXSTATE_EN;
183 	if (value)
184 		reg |= AMDGPIO_CONF_TXSTATE;
185 	else
186 		reg &= ~AMDGPIO_CONF_TXSTATE;
187 	bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg);
188 }
189 
190 void
191 amdgpio_intr_establish(void *cookie, int pin, int flags,
192     int (*func)(void *), void *arg)
193 {
194 	struct amdgpio_softc *sc = cookie;
195 	uint32_t reg;
196 
197 	KASSERT(pin >= 0 && pin != 63 && pin < sc->sc_npins);
198 
199 	sc->sc_pin_ih[pin].ih_func = func;
200 	sc->sc_pin_ih[pin].ih_arg = arg;
201 
202 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
203 	reg &= ~(AMDGPIO_CONF_MASK | AMDGPIO_CONF_LEVEL |
204 	    AMDGPIO_CONF_TXSTATE_EN);
205 	if ((flags & LR_GPIO_MODE) == 0)
206 		reg |= AMDGPIO_CONF_LEVEL;
207 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO)
208 		reg |= AMDGPIO_CONF_ACTLO;
209 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH)
210 		reg |= AMDGPIO_CONF_ACTBOTH;
211 	reg |= (AMDGPIO_CONF_INT_MASK | AMDGPIO_CONF_INT_EN);
212 	bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg);
213 }
214 
215 int
216 amdgpio_pin_intr(struct amdgpio_softc *sc, int pin)
217 {
218 	uint32_t reg;
219 	int rc = 0;
220 
221 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
222 	if (reg & AMDGPIO_CONF_INT_STS) {
223 		if (sc->sc_pin_ih[pin].ih_func) {
224 			sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
225 
226 			/* Clear interrupt */
227 			reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
228 			    pin * 4);
229 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
230 			    pin * 4, reg);
231 			rc = 1;
232 		} else {
233 			/* Mask unhandled interrupt */
234 			reg &= ~(AMDGPIO_CONF_INT_MASK | AMDGPIO_CONF_INT_EN);
235 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
236 			    pin * 4, reg);
237 		}
238 	}
239 
240 	return rc;
241 }
242 
243 int
244 amdgpio_intr(void *arg)
245 {
246 	struct amdgpio_softc *sc = arg;
247 	uint64_t status;
248 	uint32_t reg;
249 	int rc = 0, pin = 0;
250 	int i, j;
251 
252 	status = bus_space_read_4(sc->sc_memt, sc->sc_memh,
253 	    AMDGPIO_IRQ_STS + 4);
254 	status <<= 32;
255 	status |= bus_space_read_4(sc->sc_memt, sc->sc_memh,
256 	    AMDGPIO_IRQ_STS);
257 
258 	/* One status bit for every four pins */
259 	for (i = 0; i < AMDGPIO_IRQ_BITS; i++, pin += 4) {
260 		if (status & (1ULL << i)) {
261 			for (j = 0; j < AMDGPIO_IRQ_PINS; j++) {
262 				if (amdgpio_pin_intr(sc, pin + j))
263 					rc = 1;
264 			}
265 		}
266 	}
267 
268 	/* Signal end of interrupt */
269 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
270 	    AMDGPIO_IRQ_MASTER);
271 	reg |= AMDGPIO_IRQ_MASTER_EOI;
272 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
273 	    AMDGPIO_IRQ_MASTER, reg);
274 
275 	return rc;
276 }
277