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