xref: /openbsd-src/sys/dev/acpi/amdgpio.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: amdgpio.c,v 1.2 2020/01/26 00:11:42 jsg 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 	bus_addr_t sc_addr;
59 	bus_size_t sc_size;
60 
61 	int sc_irq;
62 	int sc_irq_flags;
63 	void *sc_ih;
64 
65 	int sc_npins;
66 	struct amdgpio_intrhand *sc_pin_ih;
67 
68 	struct acpi_gpio sc_gpio;
69 };
70 
71 int	amdgpio_match(struct device *, void *, void *);
72 void	amdgpio_attach(struct device *, struct device *, void *);
73 
74 struct cfattach amdgpio_ca = {
75 	sizeof(struct amdgpio_softc), amdgpio_match, amdgpio_attach
76 };
77 
78 struct cfdriver amdgpio_cd = {
79 	NULL, "amdgpio", DV_DULL
80 };
81 
82 const char *amdgpio_hids[] = {
83 	"AMDI0030",
84 	"AMD0030",
85 	NULL
86 };
87 
88 int	amdgpio_parse_resources(int, union acpi_resource *, void *);
89 int	amdgpio_read_pin(void *, int);
90 void	amdgpio_write_pin(void *, int, int);
91 void	amdgpio_intr_establish(void *, int, int, int (*)(), void *);
92 int	amdgpio_pin_intr(struct amdgpio_softc *, int);
93 int	amdgpio_intr(void *);
94 
95 int
96 amdgpio_match(struct device *parent, void *match, void *aux)
97 {
98 	struct acpi_attach_args *aaa = aux;
99 	struct cfdata *cf = match;
100 
101 	return acpi_matchhids(aaa, amdgpio_hids, cf->cf_driver->cd_name);
102 }
103 
104 void
105 amdgpio_attach(struct device *parent, struct device *self, void *aux)
106 {
107 	struct acpi_attach_args *aaa = aux;
108 	struct amdgpio_softc *sc = (struct amdgpio_softc *)self;
109 	struct aml_value res;
110 	int64_t uid;
111 
112 	sc->sc_acpi = (struct acpi_softc *)parent;
113 	sc->sc_node = aaa->aaa_node;
114 	printf(": %s", sc->sc_node->name);
115 
116 	if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) {
117 		printf(", can't find uid\n");
118 		return;
119 	}
120 
121 	printf(" uid %lld", uid);
122 
123 	switch (uid) {
124 	case 0:
125 		sc->sc_npins = 184;
126 		break;
127 	default:
128 		printf("\n");
129 		return;
130 	}
131 
132 	if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) {
133 		printf(", can't find registers\n");
134 		return;
135 	}
136 
137 	aml_parse_resource(&res, amdgpio_parse_resources, sc);
138 	aml_freevalue(&res);
139 	printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size);
140 	if (sc->sc_addr == 0 || sc->sc_size == 0) {
141 		printf("\n");
142 		return;
143 	}
144 
145 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
146 	    M_DEVBUF, M_NOWAIT | M_ZERO);
147 	if (sc->sc_pin_ih == NULL) {
148 		printf("\n");
149 		return;
150 	}
151 
152 	printf(" irq %d", sc->sc_irq);
153 
154 	sc->sc_memt = aaa->aaa_memt;
155 	if (bus_space_map(sc->sc_memt, sc->sc_addr, sc->sc_size, 0,
156 	    &sc->sc_memh)) {
157 		printf(", can't map registers\n");
158 		goto free;
159 	}
160 
161 	sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_BIO,
162 	    amdgpio_intr, sc, sc->sc_dev.dv_xname);
163 	if (sc->sc_ih == NULL) {
164 		printf(", can't establish interrupt\n");
165 		goto unmap;
166 	}
167 
168 	sc->sc_gpio.cookie = sc;
169 	sc->sc_gpio.read_pin = amdgpio_read_pin;
170 	sc->sc_gpio.write_pin = amdgpio_write_pin;
171 	sc->sc_gpio.intr_establish = amdgpio_intr_establish;
172 	sc->sc_node->gpio = &sc->sc_gpio;
173 
174 	printf(", %d pins\n", sc->sc_npins);
175 
176 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
177 	return;
178 
179 unmap:
180 	bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_size);
181 free:
182 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
183 }
184 
185 int
186 amdgpio_parse_resources(int crsidx, union acpi_resource *crs, void *arg)
187 {
188 	struct amdgpio_softc *sc = arg;
189 	int type = AML_CRSTYPE(crs);
190 
191 	switch (type) {
192 	case LR_MEM32FIXED:
193 		sc->sc_addr = crs->lr_m32fixed._bas;
194 		sc->sc_size = crs->lr_m32fixed._len;
195 		break;
196 	case LR_EXTIRQ:
197 		sc->sc_irq = crs->lr_extirq.irq[0];
198 		sc->sc_irq_flags = crs->lr_extirq.flags;
199 		break;
200 	default:
201 		printf(" type 0x%x\n", type);
202 		break;
203 	}
204 
205 	return 0;
206 }
207 
208 int
209 amdgpio_read_pin(void *cookie, int pin)
210 {
211 	struct amdgpio_softc *sc = cookie;
212 	uint32_t reg;
213 
214 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
215 
216 	return !!(reg & AMDGPIO_CONF_RXSTATE);
217 }
218 
219 void
220 amdgpio_write_pin(void *cookie, int pin, int value)
221 {
222 	struct amdgpio_softc *sc = cookie;
223 	uint32_t reg;
224 
225 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
226 	reg |= AMDGPIO_CONF_TXSTATE_EN;
227 	if (value)
228 		reg |= AMDGPIO_CONF_TXSTATE;
229 	else
230 		reg &= ~AMDGPIO_CONF_TXSTATE;
231 	bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg);
232 }
233 
234 void
235 amdgpio_intr_establish(void *cookie, int pin, int flags,
236     int (*func)(void *), void *arg)
237 {
238 	struct amdgpio_softc *sc = cookie;
239 	uint32_t reg;
240 
241 	KASSERT(pin >= 0 && pin != 63 && pin < sc->sc_npins);
242 
243 	sc->sc_pin_ih[pin].ih_func = func;
244 	sc->sc_pin_ih[pin].ih_arg = arg;
245 
246 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
247 	reg &= ~(AMDGPIO_CONF_MASK | AMDGPIO_CONF_LEVEL |
248 	    AMDGPIO_CONF_TXSTATE_EN);
249 	if ((flags & LR_GPIO_MODE) == 0)
250 		reg |= AMDGPIO_CONF_LEVEL;
251 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO)
252 		reg |= AMDGPIO_CONF_ACTLO;
253 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH)
254 		reg |= AMDGPIO_CONF_ACTBOTH;
255 	reg |= (AMDGPIO_CONF_INT_MASK | AMDGPIO_CONF_INT_EN);
256 	bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg);
257 }
258 
259 int
260 amdgpio_pin_intr(struct amdgpio_softc *sc, int pin)
261 {
262 	uint32_t reg;
263 	int rc = 0;
264 
265 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
266 	if (reg & AMDGPIO_CONF_INT_STS) {
267 		if (sc->sc_pin_ih[pin].ih_func) {
268 			sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
269 
270 			/* Clear interrupt */
271 			reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
272 			    pin * 4);
273 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
274 			    pin * 4, reg);
275 			rc = 1;
276 		} else {
277 			/* Mask unhandled interrupt */
278 			reg &= ~(AMDGPIO_CONF_INT_MASK | AMDGPIO_CONF_INT_EN);
279 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
280 			    pin * 4, reg);
281 		}
282 	}
283 
284 	return rc;
285 }
286 
287 int
288 amdgpio_intr(void *arg)
289 {
290 	struct amdgpio_softc *sc = arg;
291 	uint64_t status;
292 	uint32_t reg;
293 	int rc = 0, pin = 0;
294 	int i, j;
295 
296 	status = bus_space_read_4(sc->sc_memt, sc->sc_memh,
297 	    AMDGPIO_IRQ_STS + 4);
298 	status <<= 32;
299 	status |= bus_space_read_4(sc->sc_memt, sc->sc_memh,
300 	    AMDGPIO_IRQ_STS);
301 
302 	/* One status bit for every four pins */
303 	for (i = 0; i < AMDGPIO_IRQ_BITS; i++, pin += 4) {
304 		if (status & (1 << i)) {
305 			for (j = 0; j < AMDGPIO_IRQ_PINS; j++) {
306 				if (amdgpio_pin_intr(sc, pin + j))
307 					rc = 1;
308 			}
309 		}
310 	}
311 
312 	/* Signal end of interrupt */
313 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
314 	    AMDGPIO_IRQ_MASTER);
315 	reg |= AMDGPIO_IRQ_MASTER_EOI;
316 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
317 	    AMDGPIO_IRQ_MASTER, reg);
318 
319 	return rc;
320 }
321