xref: /freebsd/sys/dev/amdgpio/amdgpio.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2018 Advanced Micro Devices
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 #include "opt_acpi.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/gpio.h>
36 #include <sys/interrupt.h>
37 #include <sys/kernel.h>
38 #include <sys/lock.h>
39 #include <sys/module.h>
40 #include <sys/mutex.h>
41 #include <sys/proc.h>
42 #include <sys/rman.h>
43 #include <sys/sysctl.h>
44 
45 #include <machine/bus.h>
46 #include <machine/resource.h>
47 
48 #include <contrib/dev/acpica/include/acpi.h>
49 #include <contrib/dev/acpica/include/accommon.h>
50 
51 #include <dev/acpica/acpivar.h>
52 #include <dev/gpio/gpiobusvar.h>
53 
54 #include "gpio_if.h"
55 #include "amdgpio.h"
56 
57 static struct resource_spec amdgpio_spec[] = {
58 	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
59 	{ -1, 0, 0 }
60 };
61 
62 static inline uint32_t
63 amdgpio_read_4(struct amdgpio_softc *sc, bus_size_t off)
64 {
65 	return (bus_read_4(sc->sc_res[0], off));
66 }
67 
68 static inline void
69 amdgpio_write_4(struct amdgpio_softc *sc, bus_size_t off,
70 		uint32_t val)
71 {
72 	bus_write_4(sc->sc_res[0], off, val);
73 }
74 
75 static bool
76 amdgpio_is_pin_output(struct amdgpio_softc *sc, uint32_t pin)
77 {
78 	uint32_t reg, val;
79 	bool ret;
80 
81 	/* Get the current pin state */
82 	AMDGPIO_LOCK(sc);
83 
84 	reg = AMDGPIO_PIN_REGISTER(pin);
85 	val = amdgpio_read_4(sc, reg);
86 
87 	if (val & BIT(OUTPUT_ENABLE_OFF))
88 		ret = true;
89 	else
90 		ret = false;
91 
92 	AMDGPIO_UNLOCK(sc);
93 
94 	return (ret);
95 }
96 
97 static device_t
98 amdgpio_get_bus(device_t dev)
99 {
100 	struct amdgpio_softc *sc;
101 
102 	sc = device_get_softc(dev);
103 
104 	dprintf("busdev %p\n", sc->sc_busdev);
105 	return (sc->sc_busdev);
106 }
107 
108 static int
109 amdgpio_pin_max(device_t dev, int *maxpin)
110 {
111 	struct amdgpio_softc *sc;
112 
113 	sc = device_get_softc(dev);
114 
115 	*maxpin = sc->sc_npins - 1;
116 	dprintf("npins %d maxpin %d\n", sc->sc_npins, *maxpin);
117 
118 	return (0);
119 }
120 
121 static bool
122 amdgpio_valid_pin(struct amdgpio_softc *sc, int pin)
123 {
124 	dprintf("pin %d\n", pin);
125 	if (sc->sc_res[0] == NULL)
126 		return (false);
127 
128 	if ((sc->sc_gpio_pins[pin].gp_pin == pin) &&
129 		(sc->sc_gpio_pins[pin].gp_caps != 0))
130 		return (true);
131 
132 	return (false);
133 }
134 
135 static int
136 amdgpio_pin_getname(device_t dev, uint32_t pin, char *name)
137 {
138 	struct amdgpio_softc *sc;
139 
140 	dprintf("pin %d\n", pin);
141 	sc = device_get_softc(dev);
142 
143 	if (!amdgpio_valid_pin(sc, pin))
144 		return (EINVAL);
145 
146 	/* Set a very simple name */
147 	snprintf(name, GPIOMAXNAME, "%s", sc->sc_gpio_pins[pin].gp_name);
148 	name[GPIOMAXNAME - 1] = '\0';
149 
150 	dprintf("pin %d name %s\n", pin, name);
151 
152 	return (0);
153 }
154 
155 static int
156 amdgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
157 {
158 	struct amdgpio_softc *sc;
159 
160 	sc = device_get_softc(dev);
161 
162 	dprintf("pin %d\n", pin);
163 	if (!amdgpio_valid_pin(sc, pin))
164 		return (EINVAL);
165 
166 	*caps = sc->sc_gpio_pins[pin].gp_caps;
167 
168 	dprintf("pin %d caps 0x%x\n", pin, *caps);
169 
170 	return (0);
171 }
172 
173 static int
174 amdgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
175 {
176 	struct amdgpio_softc *sc;
177 
178 	sc = device_get_softc(dev);
179 
180 	dprintf("pin %d\n", pin);
181 	if (!amdgpio_valid_pin(sc, pin))
182 		return (EINVAL);
183 
184 	AMDGPIO_LOCK(sc);
185 
186 	*flags = sc->sc_gpio_pins[pin].gp_flags;
187 
188 	dprintf("pin %d flags 0x%x\n", pin, *flags);
189 
190 	AMDGPIO_UNLOCK(sc);
191 
192 	return (0);
193 }
194 
195 static int
196 amdgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
197 {
198 	struct amdgpio_softc *sc;
199 	uint32_t reg, val, allowed;
200 
201 	sc = device_get_softc(dev);
202 
203 	dprintf("pin %d flags 0x%x\n", pin, flags);
204 	if (!amdgpio_valid_pin(sc, pin))
205 		return (EINVAL);
206 
207 	allowed = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
208 
209 	/*
210 	 * Only directtion flag allowed
211 	 */
212 	if (flags & ~allowed)
213 		return (EINVAL);
214 
215 	/*
216 	 * Not both directions simultaneously
217 	 */
218 	if ((flags & allowed) == allowed)
219 		return (EINVAL);
220 
221 	/* Set the GPIO mode and state */
222 	AMDGPIO_LOCK(sc);
223 
224 	reg = AMDGPIO_PIN_REGISTER(pin);
225 	val = amdgpio_read_4(sc, reg);
226 
227 	if (flags & GPIO_PIN_INPUT) {
228 		val &= ~BIT(OUTPUT_ENABLE_OFF);
229 		sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_INPUT;
230 	} else {
231 		val |= BIT(OUTPUT_ENABLE_OFF);
232 		sc->sc_gpio_pins[pin].gp_flags = GPIO_PIN_OUTPUT;
233 	}
234 
235 	amdgpio_write_4(sc, reg, val);
236 
237 	dprintf("pin %d flags 0x%x val 0x%x gp_flags 0x%x\n",
238 		pin, flags, val, sc->sc_gpio_pins[pin].gp_flags);
239 
240 	AMDGPIO_UNLOCK(sc);
241 
242 	return (0);
243 }
244 
245 static int
246 amdgpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
247 {
248 	struct amdgpio_softc *sc;
249 	uint32_t reg, val;
250 
251 	sc = device_get_softc(dev);
252 
253 	dprintf("pin %d\n", pin);
254 	if (!amdgpio_valid_pin(sc, pin))
255 		return (EINVAL);
256 
257 	*value = 0;
258 
259 	AMDGPIO_LOCK(sc);
260 
261 	reg = AMDGPIO_PIN_REGISTER(pin);
262 	val = amdgpio_read_4(sc, reg);
263 
264 	if ((sc->sc_gpio_pins[pin].gp_flags & GPIO_PIN_OUTPUT) != 0) {
265 		if (val & BIT(OUTPUT_VALUE_OFF))
266 			*value = GPIO_PIN_HIGH;
267 		else
268 			*value = GPIO_PIN_LOW;
269 	} else {
270 		if (val & BIT(PIN_STS_OFF))
271 			*value = GPIO_PIN_HIGH;
272 		else
273 			*value = GPIO_PIN_LOW;
274 	}
275 
276 	dprintf("pin %d value 0x%x\n", pin, *value);
277 
278 	AMDGPIO_UNLOCK(sc);
279 
280 	return (0);
281 }
282 
283 static int
284 amdgpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
285 {
286 	struct amdgpio_softc *sc;
287 	uint32_t reg, val;
288 
289 	sc = device_get_softc(dev);
290 
291 	dprintf("pin %d value 0x%x\n", pin, value);
292 	if (!amdgpio_valid_pin(sc, pin))
293 		return (EINVAL);
294 
295 	if (!amdgpio_is_pin_output(sc, pin))
296 		return (EINVAL);
297 
298 	AMDGPIO_LOCK(sc);
299 
300 	reg = AMDGPIO_PIN_REGISTER(pin);
301 	val = amdgpio_read_4(sc, reg);
302 
303 	if (value == GPIO_PIN_LOW)
304 		val &= ~BIT(OUTPUT_VALUE_OFF);
305 	else
306 		val |= BIT(OUTPUT_VALUE_OFF);
307 
308 	amdgpio_write_4(sc, reg, val);
309 
310 	dprintf("pin %d value 0x%x val 0x%x\n", pin, value, val);
311 
312 	AMDGPIO_UNLOCK(sc);
313 
314 	return (0);
315 }
316 
317 static int
318 amdgpio_pin_toggle(device_t dev, uint32_t pin)
319 {
320 	struct amdgpio_softc *sc;
321 	uint32_t reg, val;
322 
323 	sc = device_get_softc(dev);
324 
325 	dprintf("pin %d\n", pin);
326 	if (!amdgpio_valid_pin(sc, pin))
327 		return (EINVAL);
328 
329 	if (!amdgpio_is_pin_output(sc, pin))
330 		return (EINVAL);
331 
332 	/* Toggle the pin */
333 	AMDGPIO_LOCK(sc);
334 
335 	reg = AMDGPIO_PIN_REGISTER(pin);
336 	val = amdgpio_read_4(sc, reg);
337 	dprintf("pin %d value before 0x%x\n", pin, val);
338 	val = val ^ BIT(OUTPUT_VALUE_OFF);
339 	dprintf("pin %d value after 0x%x\n", pin, val);
340 	amdgpio_write_4(sc, reg, val);
341 
342 	AMDGPIO_UNLOCK(sc);
343 
344 	return (0);
345 }
346 
347 static int
348 amdgpio_probe(device_t dev)
349 {
350 	static char *gpio_ids[] = { "AMD0030", "AMDI0030", NULL };
351 	int rv;
352 
353 	if (acpi_disabled("gpio"))
354 		return (ENXIO);
355 	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, gpio_ids, NULL);
356 	if (rv <= 0)
357 		device_set_desc(dev, "AMD GPIO Controller");
358 
359 	return (rv);
360 }
361 
362 static int
363 amdgpio_attach(device_t dev)
364 {
365 	struct amdgpio_softc *sc;
366 	int i, pin, bank;
367 
368 	sc = device_get_softc(dev);
369 	sc->sc_dev = dev;
370 	sc->sc_handle = acpi_get_handle(dev);
371 
372 	AMDGPIO_LOCK_INIT(sc);
373 
374 	sc->sc_nbanks = AMD_GPIO_NUM_PIN_BANK;
375 	sc->sc_npins = AMD_GPIO_PINS_MAX;
376 	sc->sc_bank_prefix = AMD_GPIO_PREFIX;
377 	sc->sc_pin_info = kernzp_pins;
378 	sc->sc_ngroups = nitems(kernzp_groups);
379 	sc->sc_groups = kernzp_groups;
380 
381 	if (bus_alloc_resources(dev, amdgpio_spec, sc->sc_res)) {
382 		device_printf(dev, "could not allocate resources\n");
383 		goto err_rsrc;
384 	}
385 
386 	sc->sc_bst = rman_get_bustag(sc->sc_res[0]);
387 	sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);
388 
389 	/* Initialize all possible pins to be Invalid */
390 	for (i = 0; i < AMD_GPIO_PINS_MAX ; i++) {
391 		snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME,
392 			"Unexposed PIN %d", i);
393 		sc->sc_gpio_pins[i].gp_pin = -1;
394 		sc->sc_gpio_pins[i].gp_caps = 0;
395 		sc->sc_gpio_pins[i].gp_flags = 0;
396 	}
397 
398 	/* Initialize only driver exposed pins with appropriate capabilities */
399 	for (i = 0; i < AMD_GPIO_PINS_EXPOSED ; i++) {
400 		pin = kernzp_pins[i].pin_num;
401 		bank = pin/AMD_GPIO_PINS_PER_BANK;
402 		snprintf(sc->sc_gpio_pins[pin].gp_name, GPIOMAXNAME, "%s%d_%s",
403 			AMD_GPIO_PREFIX, bank, kernzp_pins[i].pin_name);
404 		sc->sc_gpio_pins[pin].gp_pin = pin;
405 		sc->sc_gpio_pins[pin].gp_caps = AMDGPIO_DEFAULT_CAPS;
406 		sc->sc_gpio_pins[pin].gp_flags =
407 		    amdgpio_is_pin_output(sc, pin) ?
408 		    GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
409 	}
410 
411 	sc->sc_busdev = gpiobus_attach_bus(dev);
412 	if (sc->sc_busdev == NULL) {
413 		device_printf(dev, "could not attach gpiobus\n");
414 		goto err_bus;
415 	}
416 
417 	return (0);
418 
419 err_bus:
420 	bus_release_resources(dev, amdgpio_spec, sc->sc_res);
421 
422 err_rsrc:
423 	AMDGPIO_LOCK_DESTROY(sc);
424 
425 	return (ENXIO);
426 }
427 
428 static int
429 amdgpio_detach(device_t dev)
430 {
431 	struct amdgpio_softc *sc;
432 	sc = device_get_softc(dev);
433 
434 	if (sc->sc_busdev)
435 		gpiobus_detach_bus(dev);
436 
437 	bus_release_resources(dev, amdgpio_spec, sc->sc_res);
438 
439 	AMDGPIO_LOCK_DESTROY(sc);
440 
441 	return (0);
442 }
443 
444 static device_method_t amdgpio_methods[] = {
445 	/* Device interface */
446 	DEVMETHOD(device_probe, amdgpio_probe),
447 	DEVMETHOD(device_attach, amdgpio_attach),
448 	DEVMETHOD(device_detach, amdgpio_detach),
449 
450 	/* GPIO protocol */
451 	DEVMETHOD(gpio_get_bus, amdgpio_get_bus),
452 	DEVMETHOD(gpio_pin_max, amdgpio_pin_max),
453 	DEVMETHOD(gpio_pin_getname, amdgpio_pin_getname),
454 	DEVMETHOD(gpio_pin_getcaps, amdgpio_pin_getcaps),
455 	DEVMETHOD(gpio_pin_getflags, amdgpio_pin_getflags),
456 	DEVMETHOD(gpio_pin_setflags, amdgpio_pin_setflags),
457 	DEVMETHOD(gpio_pin_get, amdgpio_pin_get),
458 	DEVMETHOD(gpio_pin_set, amdgpio_pin_set),
459 	DEVMETHOD(gpio_pin_toggle, amdgpio_pin_toggle),
460 
461 	DEVMETHOD_END
462 };
463 
464 static driver_t amdgpio_driver = {
465 	"gpio",
466 	amdgpio_methods,
467 	sizeof(struct amdgpio_softc),
468 };
469 
470 DRIVER_MODULE(amdgpio, acpi, amdgpio_driver, 0, 0);
471 MODULE_DEPEND(amdgpio, acpi, 1, 1, 1);
472 MODULE_DEPEND(amdgpio, gpiobus, 1, 1, 1);
473 MODULE_VERSION(amdgpio, 1);
474