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
57static struct resource_spec amdgpio_spec[] = {
58	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
59	{ -1, 0, 0 }
60};
61
62static inline uint32_t
63amdgpio_read_4(struct amdgpio_softc *sc, bus_size_t off)
64{
65	return (bus_read_4(sc->sc_res[0], off));
66}
67
68static inline void
69amdgpio_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
75static bool
76amdgpio_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
97static device_t
98amdgpio_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
108static int
109amdgpio_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
121static bool
122amdgpio_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
135static int
136amdgpio_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
155static int
156amdgpio_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
173static int
174amdgpio_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
195static int
196amdgpio_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
245static int
246amdgpio_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
283static int
284amdgpio_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
317static int
318amdgpio_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
347static int
348amdgpio_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
362static int
363amdgpio_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
419err_bus:
420	bus_release_resources(dev, amdgpio_spec, sc->sc_res);
421
422err_rsrc:
423	AMDGPIO_LOCK_DESTROY(sc);
424
425	return (ENXIO);
426}
427
428static int
429amdgpio_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
444static 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
464static driver_t amdgpio_driver = {
465	"gpio",
466	amdgpio_methods,
467	sizeof(struct amdgpio_softc),
468};
469
470DRIVER_MODULE(amdgpio, acpi, amdgpio_driver, 0, 0);
471MODULE_DEPEND(amdgpio, acpi, 1, 1, 1);
472MODULE_DEPEND(amdgpio, gpiobus, 1, 1, 1);
473MODULE_VERSION(amdgpio, 1);
474