xref: /openbsd/sys/dev/acpi/amdgpio.c (revision d89ec533)
1 /*	$OpenBSD: amdgpio.c,v 1.5 2021/05/16 08:50:59 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 	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 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 	return acpi_matchhids(aaa, amdgpio_hids, cf->cf_driver->cd_name);
97 }
98 
99 void
100 amdgpio_attach(struct device *parent, struct device *self, void *aux)
101 {
102 	struct acpi_attach_args *aaa = aux;
103 	struct amdgpio_softc *sc = (struct amdgpio_softc *)self;
104 	int64_t uid;
105 
106 	sc->sc_acpi = (struct acpi_softc *)parent;
107 	sc->sc_node = aaa->aaa_node;
108 	printf(" %s", sc->sc_node->name);
109 
110 	if (aaa->aaa_naddr < 1) {
111 		printf(": no registers\n");
112 		return;
113 	}
114 
115 	if (aaa->aaa_nirq < 1) {
116 		printf(": no interrupt\n");
117 		return;
118 	}
119 
120 	if (aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid)) {
121 		printf(": can't find uid\n");
122 		return;
123 	}
124 
125 	printf(" uid %lld", uid);
126 
127 	switch (uid) {
128 	case 0:
129 		sc->sc_npins = 184;
130 		break;
131 	default:
132 		printf("\n");
133 		return;
134 	}
135 
136 	printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]);
137 	printf(" irq %d", aaa->aaa_irq[0]);
138 
139 	sc->sc_memt = aaa->aaa_bst[0];
140 	if (bus_space_map(sc->sc_memt, aaa->aaa_addr[0], aaa->aaa_size[0],
141 	    0, &sc->sc_memh)) {
142 		printf(": can't map registers\n");
143 		return;
144 	}
145 
146 	sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
147 	    M_DEVBUF, M_WAITOK | M_ZERO);
148 
149 	sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0],
150 	    IPL_BIO, amdgpio_intr, sc, sc->sc_dev.dv_xname);
151 	if (sc->sc_ih == NULL) {
152 		printf(": can't establish interrupt\n");
153 		goto unmap;
154 	}
155 
156 	sc->sc_gpio.cookie = sc;
157 	sc->sc_gpio.read_pin = amdgpio_read_pin;
158 	sc->sc_gpio.write_pin = amdgpio_write_pin;
159 	sc->sc_gpio.intr_establish = amdgpio_intr_establish;
160 	sc->sc_node->gpio = &sc->sc_gpio;
161 
162 	printf(", %d pins\n", sc->sc_npins);
163 
164 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
165 	return;
166 
167 unmap:
168 	free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
169 	bus_space_unmap(sc->sc_memt, sc->sc_memh, aaa->aaa_size[0]);
170 }
171 
172 int
173 amdgpio_read_pin(void *cookie, int pin)
174 {
175 	struct amdgpio_softc *sc = cookie;
176 	uint32_t reg;
177 
178 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
179 
180 	return !!(reg & AMDGPIO_CONF_RXSTATE);
181 }
182 
183 void
184 amdgpio_write_pin(void *cookie, int pin, int value)
185 {
186 	struct amdgpio_softc *sc = cookie;
187 	uint32_t reg;
188 
189 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
190 	reg |= AMDGPIO_CONF_TXSTATE_EN;
191 	if (value)
192 		reg |= AMDGPIO_CONF_TXSTATE;
193 	else
194 		reg &= ~AMDGPIO_CONF_TXSTATE;
195 	bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg);
196 }
197 
198 void
199 amdgpio_intr_establish(void *cookie, int pin, int flags,
200     int (*func)(void *), void *arg)
201 {
202 	struct amdgpio_softc *sc = cookie;
203 	uint32_t reg;
204 
205 	KASSERT(pin >= 0 && pin != 63 && pin < sc->sc_npins);
206 
207 	sc->sc_pin_ih[pin].ih_func = func;
208 	sc->sc_pin_ih[pin].ih_arg = arg;
209 
210 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
211 	reg &= ~(AMDGPIO_CONF_MASK | AMDGPIO_CONF_LEVEL |
212 	    AMDGPIO_CONF_TXSTATE_EN);
213 	if ((flags & LR_GPIO_MODE) == 0)
214 		reg |= AMDGPIO_CONF_LEVEL;
215 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTLO)
216 		reg |= AMDGPIO_CONF_ACTLO;
217 	if ((flags & LR_GPIO_POLARITY) == LR_GPIO_ACTBOTH)
218 		reg |= AMDGPIO_CONF_ACTBOTH;
219 	reg |= (AMDGPIO_CONF_INT_MASK | AMDGPIO_CONF_INT_EN);
220 	bus_space_write_4(sc->sc_memt, sc->sc_memh, pin * 4, reg);
221 }
222 
223 int
224 amdgpio_pin_intr(struct amdgpio_softc *sc, int pin)
225 {
226 	uint32_t reg;
227 	int rc = 0;
228 
229 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh, pin * 4);
230 	if (reg & AMDGPIO_CONF_INT_STS) {
231 		if (sc->sc_pin_ih[pin].ih_func) {
232 			sc->sc_pin_ih[pin].ih_func(sc->sc_pin_ih[pin].ih_arg);
233 
234 			/* Clear interrupt */
235 			reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
236 			    pin * 4);
237 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
238 			    pin * 4, reg);
239 			rc = 1;
240 		} else {
241 			/* Mask unhandled interrupt */
242 			reg &= ~(AMDGPIO_CONF_INT_MASK | AMDGPIO_CONF_INT_EN);
243 			bus_space_write_4(sc->sc_memt, sc->sc_memh,
244 			    pin * 4, reg);
245 		}
246 	}
247 
248 	return rc;
249 }
250 
251 int
252 amdgpio_intr(void *arg)
253 {
254 	struct amdgpio_softc *sc = arg;
255 	uint64_t status;
256 	uint32_t reg;
257 	int rc = 0, pin = 0;
258 	int i, j;
259 
260 	status = bus_space_read_4(sc->sc_memt, sc->sc_memh,
261 	    AMDGPIO_IRQ_STS + 4);
262 	status <<= 32;
263 	status |= bus_space_read_4(sc->sc_memt, sc->sc_memh,
264 	    AMDGPIO_IRQ_STS);
265 
266 	/* One status bit for every four pins */
267 	for (i = 0; i < AMDGPIO_IRQ_BITS; i++, pin += 4) {
268 		if (status & (1ULL << i)) {
269 			for (j = 0; j < AMDGPIO_IRQ_PINS; j++) {
270 				if (amdgpio_pin_intr(sc, pin + j))
271 					rc = 1;
272 			}
273 		}
274 	}
275 
276 	/* Signal end of interrupt */
277 	reg = bus_space_read_4(sc->sc_memt, sc->sc_memh,
278 	    AMDGPIO_IRQ_MASTER);
279 	reg |= AMDGPIO_IRQ_MASTER_EOI;
280 	bus_space_write_4(sc->sc_memt, sc->sc_memh,
281 	    AMDGPIO_IRQ_MASTER, reg);
282 
283 	return rc;
284 }
285