1276533Sbr/*-
2276533Sbr * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
3276533Sbr * All rights reserved.
4276533Sbr *
5276533Sbr * This software was developed by SRI International and the University of
6276533Sbr * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7276533Sbr * ("CTSRD"), as part of the DARPA CRASH research programme.
8276533Sbr *
9276533Sbr * Redistribution and use in source and binary forms, with or without
10276533Sbr * modification, are permitted provided that the following conditions
11276533Sbr * are met:
12276533Sbr * 1. Redistributions of source code must retain the above copyright
13276533Sbr *    notice, this list of conditions and the following disclaimer.
14276533Sbr * 2. Redistributions in binary form must reproduce the above copyright
15276533Sbr *    notice, this list of conditions and the following disclaimer in the
16276533Sbr *    documentation and/or other materials provided with the distribution.
17276533Sbr *
18276533Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19276533Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20276533Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21276533Sbr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22276533Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23276533Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24276533Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25276533Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26276533Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27276533Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28276533Sbr * SUCH DAMAGE.
29276533Sbr */
30276533Sbr
31276533Sbr/*
32276533Sbr * SOCFPGA General-Purpose I/O Interface.
33276533Sbr * Chapter 22, Cyclone V Device Handbook (CV-5V2 2014.07.22)
34276533Sbr */
35276533Sbr
36276533Sbr/*
37276533Sbr * The GPIO modules are instances of the Synopsys�� DesignWare�� APB General
38276533Sbr * Purpose Programming I/O (DW_apb_gpio) peripheral.
39276533Sbr */
40276533Sbr
41276533Sbr#include <sys/cdefs.h>
42276533Sbr__FBSDID("$FreeBSD: releng/11.0/sys/arm/altera/socfpga/socfpga_gpio.c 281085 2015-04-04 21:34:26Z andrew $");
43276533Sbr
44276533Sbr#include <sys/param.h>
45276533Sbr#include <sys/systm.h>
46276533Sbr#include <sys/bus.h>
47276533Sbr#include <sys/kernel.h>
48276533Sbr#include <sys/module.h>
49276533Sbr#include <sys/malloc.h>
50276533Sbr#include <sys/rman.h>
51276533Sbr#include <sys/timeet.h>
52276533Sbr#include <sys/timetc.h>
53276533Sbr#include <sys/watchdog.h>
54276533Sbr#include <sys/mutex.h>
55276533Sbr#include <sys/gpio.h>
56276533Sbr
57276533Sbr#include <dev/fdt/fdt_common.h>
58277996Sloos#include <dev/gpio/gpiobusvar.h>
59276533Sbr#include <dev/ofw/openfirm.h>
60276533Sbr#include <dev/ofw/ofw_bus.h>
61276533Sbr#include <dev/ofw/ofw_bus_subr.h>
62276533Sbr
63276533Sbr#include <machine/bus.h>
64276533Sbr#include <machine/cpu.h>
65276533Sbr#include <machine/intr.h>
66276533Sbr
67276533Sbr#include "gpio_if.h"
68276533Sbr
69276533Sbr#define READ4(_sc, _reg) \
70276533Sbr	bus_read_4((_sc)->res[0], _reg)
71276533Sbr#define WRITE4(_sc, _reg, _val) \
72276533Sbr	bus_write_4((_sc)->res[0], _reg, _val)
73276533Sbr
74276533Sbr#define	GPIO_SWPORTA_DR		0x00	/* Port A Data Register */
75276533Sbr#define	GPIO_SWPORTA_DDR	0x04	/* Port A Data Direction Register */
76276533Sbr#define	GPIO_INTEN		0x30	/* Interrupt Enable Register */
77276533Sbr#define	GPIO_INTMASK		0x34	/* Interrupt Mask Register */
78276533Sbr#define	GPIO_INTTYPE_LEVEL	0x38	/* Interrupt Level Register */
79276533Sbr#define	GPIO_INT_POLARITY	0x3C	/* Interrupt Polarity Register */
80276533Sbr#define	GPIO_INTSTATUS		0x40	/* Interrupt Status Register */
81276533Sbr#define	GPIO_RAW_INTSTATUS	0x44	/* Raw Interrupt Status Register */
82276533Sbr#define	GPIO_DEBOUNCE		0x48	/* Debounce Enable Register */
83276533Sbr#define	GPIO_PORTA_EOI		0x4C	/* Clear Interrupt Register */
84276533Sbr#define	GPIO_EXT_PORTA		0x50	/* External Port A Register */
85276533Sbr#define	GPIO_LS_SYNC		0x60	/* Synchronization Level Register */
86276533Sbr#define	GPIO_ID_CODE		0x64	/* ID Code Register */
87276533Sbr#define	GPIO_VER_ID_CODE	0x6C	/* GPIO Version Register */
88276533Sbr#define	GPIO_CONFIG_REG2	0x70	/* Configuration Register 2 */
89276533Sbr#define	 ENCODED_ID_PWIDTH_M	0x1f	/* Width of GPIO Port N Mask */
90276533Sbr#define	 ENCODED_ID_PWIDTH_S(n)	(5 * n)	/* Width of GPIO Port N Shift */
91276533Sbr#define	GPIO_CONFIG_REG1	0x74	/* Configuration Register 1 */
92276533Sbr
93276533Sbrenum port_no {
94276533Sbr	PORTA,
95276533Sbr	PORTB,
96276533Sbr	PORTC,
97276533Sbr	PORTD,
98276533Sbr};
99276533Sbr
100276533Sbr#define	NR_GPIO_MAX	32	/* Maximum pins per port */
101276533Sbr
102276533Sbr#define	GPIO_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
103276533Sbr#define	GPIO_UNLOCK(_sc)	mtx_unlock(&(_sc)->sc_mtx)
104276533Sbr
105276533Sbr#define	DEFAULT_CAPS	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
106276533Sbr
107276533Sbr/*
108276533Sbr * GPIO interface
109276533Sbr */
110277996Sloosstatic device_t socfpga_gpio_get_bus(device_t);
111276533Sbrstatic int socfpga_gpio_pin_max(device_t, int *);
112276533Sbrstatic int socfpga_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
113276533Sbrstatic int socfpga_gpio_pin_getname(device_t, uint32_t, char *);
114276533Sbrstatic int socfpga_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
115276533Sbrstatic int socfpga_gpio_pin_setflags(device_t, uint32_t, uint32_t);
116276533Sbrstatic int socfpga_gpio_pin_set(device_t, uint32_t, unsigned int);
117276533Sbrstatic int socfpga_gpio_pin_get(device_t, uint32_t, unsigned int *);
118276533Sbrstatic int socfpga_gpio_pin_toggle(device_t, uint32_t pin);
119276533Sbr
120276533Sbrstruct socfpga_gpio_softc {
121276533Sbr	struct resource		*res[1];
122276533Sbr	bus_space_tag_t		bst;
123276533Sbr	bus_space_handle_t	bsh;
124276533Sbr
125276533Sbr	device_t		dev;
126277996Sloos	device_t		busdev;
127276533Sbr	struct mtx		sc_mtx;
128276533Sbr	int			gpio_npins;
129276533Sbr	struct gpio_pin		gpio_pins[NR_GPIO_MAX];
130276533Sbr};
131276533Sbr
132276533Sbrstruct socfpga_gpio_softc *gpio_sc;
133276533Sbr
134276533Sbrstatic struct resource_spec socfpga_gpio_spec[] = {
135276533Sbr	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
136276533Sbr	{ -1, 0 }
137276533Sbr};
138276533Sbr
139276533Sbrstatic int
140276533Sbrsocfpga_gpio_probe(device_t dev)
141276533Sbr{
142276533Sbr
143276533Sbr	if (!ofw_bus_status_okay(dev))
144276533Sbr		return (ENXIO);
145276533Sbr
146276533Sbr	if (!ofw_bus_is_compatible(dev, "snps,dw-apb-gpio"))
147276533Sbr		return (ENXIO);
148276533Sbr
149276533Sbr	device_set_desc(dev, "DesignWare General-Purpose I/O Interface");
150276533Sbr	return (BUS_PROBE_DEFAULT);
151276533Sbr}
152276533Sbr
153276533Sbrstatic int
154276533Sbrsocfpga_gpio_attach(device_t dev)
155276533Sbr{
156276533Sbr	struct socfpga_gpio_softc *sc;
157276533Sbr	int version;
158276533Sbr	int nr_pins;
159276533Sbr	int cfg2;
160276533Sbr	int i;
161276533Sbr
162276533Sbr	sc = device_get_softc(dev);
163276533Sbr	sc->dev = dev;
164276533Sbr	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
165276533Sbr
166276533Sbr	if (bus_alloc_resources(dev, socfpga_gpio_spec, sc->res)) {
167276533Sbr		device_printf(dev, "could not allocate resources\n");
168277968Sloos		mtx_destroy(&sc->sc_mtx);
169276533Sbr		return (ENXIO);
170276533Sbr	}
171276533Sbr
172276533Sbr	/* Memory interface */
173276533Sbr	sc->bst = rman_get_bustag(sc->res[0]);
174276533Sbr	sc->bsh = rman_get_bushandle(sc->res[0]);
175276533Sbr
176276533Sbr	gpio_sc = sc;
177276533Sbr
178276533Sbr	version =  READ4(sc, GPIO_VER_ID_CODE);
179276533Sbr#if 0
180276533Sbr	device_printf(sc->dev, "Version = 0x%08x\n", version);
181276533Sbr#endif
182276533Sbr
183276533Sbr	/*
184276533Sbr	 * Take number of pins from hardware.
185276533Sbr	 * XXX: Assume we have GPIO port A only.
186276533Sbr	 */
187276533Sbr	cfg2 = READ4(sc, GPIO_CONFIG_REG2);
188276533Sbr	nr_pins = (cfg2 >> ENCODED_ID_PWIDTH_S(PORTA)) & \
189276533Sbr			ENCODED_ID_PWIDTH_M;
190276533Sbr	sc->gpio_npins = nr_pins + 1;
191276533Sbr
192276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
193276533Sbr		sc->gpio_pins[i].gp_pin = i;
194276533Sbr		sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
195276533Sbr		sc->gpio_pins[i].gp_flags =
196276533Sbr		    (READ4(sc, GPIO_SWPORTA_DDR) & (1 << i)) ?
197276533Sbr		    GPIO_PIN_OUTPUT: GPIO_PIN_INPUT;
198276533Sbr		snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
199276533Sbr		    "socfpga_gpio%d.%d", device_get_unit(dev), i);
200276533Sbr	}
201277996Sloos	sc->busdev = gpiobus_attach_bus(dev);
202277996Sloos	if (sc->busdev == NULL) {
203277996Sloos		bus_release_resources(dev, socfpga_gpio_spec, sc->res);
204277996Sloos		mtx_destroy(&sc->sc_mtx);
205277996Sloos		return (ENXIO);
206277996Sloos	}
207276533Sbr
208277996Sloos	return (0);
209277996Sloos}
210276533Sbr
211277996Sloosstatic device_t
212277996Sloossocfpga_gpio_get_bus(device_t dev)
213277996Sloos{
214277996Sloos	struct socfpga_gpio_softc *sc;
215277996Sloos
216277996Sloos	sc = device_get_softc(dev);
217277996Sloos
218277996Sloos	return (sc->busdev);
219276533Sbr}
220276533Sbr
221276533Sbrstatic int
222276533Sbrsocfpga_gpio_pin_max(device_t dev, int *maxpin)
223276533Sbr{
224276533Sbr	struct socfpga_gpio_softc *sc;
225276533Sbr
226276533Sbr	sc = device_get_softc(dev);
227276533Sbr
228276533Sbr	*maxpin = sc->gpio_npins - 1;
229276533Sbr
230276533Sbr	return (0);
231276533Sbr}
232276533Sbr
233276533Sbrstatic int
234276533Sbrsocfpga_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
235276533Sbr{
236276533Sbr	struct socfpga_gpio_softc *sc;
237276533Sbr	int i;
238276533Sbr
239276533Sbr	sc = device_get_softc(dev);
240276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
241276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
242276533Sbr			break;
243276533Sbr	}
244276533Sbr
245276533Sbr	if (i >= sc->gpio_npins)
246276533Sbr		return (EINVAL);
247276533Sbr
248276533Sbr	GPIO_LOCK(sc);
249276533Sbr	memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
250276533Sbr	GPIO_UNLOCK(sc);
251276533Sbr
252276533Sbr	return (0);
253276533Sbr}
254276533Sbr
255276533Sbrstatic int
256276533Sbrsocfpga_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
257276533Sbr{
258276533Sbr	struct socfpga_gpio_softc *sc;
259276533Sbr	int i;
260276533Sbr
261276533Sbr	sc = device_get_softc(dev);
262276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
263276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
264276533Sbr			break;
265276533Sbr	}
266276533Sbr
267276533Sbr	if (i >= sc->gpio_npins)
268276533Sbr		return (EINVAL);
269276533Sbr
270276533Sbr	GPIO_LOCK(sc);
271276533Sbr	*caps = sc->gpio_pins[i].gp_caps;
272276533Sbr	GPIO_UNLOCK(sc);
273276533Sbr
274276533Sbr	return (0);
275276533Sbr}
276276533Sbr
277276533Sbrstatic int
278276533Sbrsocfpga_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
279276533Sbr{
280276533Sbr	struct socfpga_gpio_softc *sc;
281276533Sbr	int i;
282276533Sbr
283276533Sbr	sc = device_get_softc(dev);
284276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
285276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
286276533Sbr			break;
287276533Sbr	}
288276533Sbr
289276533Sbr	if (i >= sc->gpio_npins)
290276533Sbr		return (EINVAL);
291276533Sbr
292276533Sbr	GPIO_LOCK(sc);
293276533Sbr	*flags = sc->gpio_pins[i].gp_flags;
294276533Sbr	GPIO_UNLOCK(sc);
295276533Sbr
296276533Sbr	return (0);
297276533Sbr}
298276533Sbr
299276533Sbrstatic int
300276533Sbrsocfpga_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
301276533Sbr{
302276533Sbr	struct socfpga_gpio_softc *sc;
303276533Sbr	int i;
304276533Sbr
305276533Sbr	sc = device_get_softc(dev);
306276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
307276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
308276533Sbr			break;
309276533Sbr	}
310276533Sbr
311276533Sbr	if (i >= sc->gpio_npins)
312276533Sbr		return (EINVAL);
313276533Sbr
314276533Sbr	GPIO_LOCK(sc);
315276533Sbr	*val = (READ4(sc, GPIO_EXT_PORTA) & (1 << i)) ? 1 : 0;
316276533Sbr	GPIO_UNLOCK(sc);
317276533Sbr
318276533Sbr	return (0);
319276533Sbr}
320276533Sbr
321276533Sbrstatic int
322276533Sbrsocfpga_gpio_pin_toggle(device_t dev, uint32_t pin)
323276533Sbr{
324276533Sbr	struct socfpga_gpio_softc *sc;
325276533Sbr	int reg;
326276533Sbr	int i;
327276533Sbr
328276533Sbr	sc = device_get_softc(dev);
329276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
330276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
331276533Sbr			break;
332276533Sbr	}
333276533Sbr
334276533Sbr	if (i >= sc->gpio_npins)
335276533Sbr		return (EINVAL);
336276533Sbr
337276533Sbr	GPIO_LOCK(sc);
338276533Sbr	reg = READ4(sc, GPIO_SWPORTA_DR);
339276533Sbr	if (reg & (1 << i))
340276533Sbr		reg &= ~(1 << i);
341276533Sbr	else
342276533Sbr		reg |= (1 << i);
343276533Sbr	WRITE4(sc, GPIO_SWPORTA_DR, reg);
344276533Sbr	GPIO_UNLOCK(sc);
345276533Sbr
346276533Sbr	return (0);
347276533Sbr}
348276533Sbr
349276533Sbr
350276533Sbrstatic void
351276533Sbrsocfpga_gpio_pin_configure(struct socfpga_gpio_softc *sc,
352276533Sbr    struct gpio_pin *pin, unsigned int flags)
353276533Sbr{
354276533Sbr	int reg;
355276533Sbr
356276533Sbr	GPIO_LOCK(sc);
357276533Sbr
358276533Sbr	/*
359276533Sbr	 * Manage input/output
360276533Sbr	 */
361276533Sbr
362276533Sbr	reg = READ4(sc, GPIO_SWPORTA_DDR);
363276533Sbr	if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
364276533Sbr		pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
365276533Sbr		if (flags & GPIO_PIN_OUTPUT) {
366276533Sbr			pin->gp_flags |= GPIO_PIN_OUTPUT;
367276533Sbr			reg |= (1 << pin->gp_pin);
368276533Sbr		} else {
369276533Sbr			pin->gp_flags |= GPIO_PIN_INPUT;
370276533Sbr			reg &= ~(1 << pin->gp_pin);
371276533Sbr		}
372276533Sbr	}
373276533Sbr
374276533Sbr	WRITE4(sc, GPIO_SWPORTA_DDR, reg);
375276533Sbr	GPIO_UNLOCK(sc);
376276533Sbr}
377276533Sbr
378276533Sbr
379276533Sbrstatic int
380276533Sbrsocfpga_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
381276533Sbr{
382276533Sbr	struct socfpga_gpio_softc *sc;
383276533Sbr	int i;
384276533Sbr
385276533Sbr	sc = device_get_softc(dev);
386276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
387276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
388276533Sbr			break;
389276533Sbr	}
390276533Sbr
391276533Sbr	if (i >= sc->gpio_npins)
392276533Sbr		return (EINVAL);
393276533Sbr
394276533Sbr	socfpga_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);
395276533Sbr
396276533Sbr	return (0);
397276533Sbr}
398276533Sbr
399276533Sbrstatic int
400276533Sbrsocfpga_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
401276533Sbr{
402276533Sbr	struct socfpga_gpio_softc *sc;
403276533Sbr	int reg;
404276533Sbr	int i;
405276533Sbr
406276533Sbr	sc = device_get_softc(dev);
407276533Sbr
408276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
409276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
410276533Sbr			break;
411276533Sbr	}
412276533Sbr
413276533Sbr	if (i >= sc->gpio_npins)
414276533Sbr		return (EINVAL);
415276533Sbr
416276533Sbr	GPIO_LOCK(sc);
417276533Sbr	reg = READ4(sc, GPIO_SWPORTA_DR);
418276533Sbr	if (value)
419276533Sbr		reg |= (1 << i);
420276533Sbr	else
421276533Sbr		reg &= ~(1 << i);
422276533Sbr	WRITE4(sc, GPIO_SWPORTA_DR, reg);
423276533Sbr	GPIO_UNLOCK(sc);
424276533Sbr
425276533Sbr	return (0);
426276533Sbr}
427276533Sbr
428276533Sbrstatic device_method_t socfpga_gpio_methods[] = {
429276533Sbr	DEVMETHOD(device_probe,		socfpga_gpio_probe),
430276533Sbr	DEVMETHOD(device_attach,	socfpga_gpio_attach),
431276533Sbr
432276533Sbr	/* GPIO protocol */
433277996Sloos	DEVMETHOD(gpio_get_bus,		socfpga_gpio_get_bus),
434276533Sbr	DEVMETHOD(gpio_pin_max,		socfpga_gpio_pin_max),
435276533Sbr	DEVMETHOD(gpio_pin_getname,	socfpga_gpio_pin_getname),
436276533Sbr	DEVMETHOD(gpio_pin_getcaps,	socfpga_gpio_pin_getcaps),
437276533Sbr	DEVMETHOD(gpio_pin_getflags,	socfpga_gpio_pin_getflags),
438276533Sbr	DEVMETHOD(gpio_pin_get,		socfpga_gpio_pin_get),
439276533Sbr	DEVMETHOD(gpio_pin_toggle,	socfpga_gpio_pin_toggle),
440276533Sbr	DEVMETHOD(gpio_pin_setflags,	socfpga_gpio_pin_setflags),
441276533Sbr	DEVMETHOD(gpio_pin_set,		socfpga_gpio_pin_set),
442276533Sbr	{ 0, 0 }
443276533Sbr};
444276533Sbr
445276533Sbrstatic driver_t socfpga_gpio_driver = {
446276533Sbr	"gpio",
447276533Sbr	socfpga_gpio_methods,
448276533Sbr	sizeof(struct socfpga_gpio_softc),
449276533Sbr};
450276533Sbr
451276533Sbrstatic devclass_t socfpga_gpio_devclass;
452276533Sbr
453276533SbrDRIVER_MODULE(socfpga_gpio, simplebus, socfpga_gpio_driver,
454276533Sbr    socfpga_gpio_devclass, 0, 0);
455