socfpga_gpio.c revision 277996
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: head/sys/arm/altera/socfpga/socfpga_gpio.c 277996 2015-01-31 19:32:14Z loos $");
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/fdt.h>
65276533Sbr#include <machine/cpu.h>
66276533Sbr#include <machine/intr.h>
67276533Sbr
68276533Sbr#include "gpio_if.h"
69276533Sbr
70276533Sbr#define READ4(_sc, _reg) \
71276533Sbr	bus_read_4((_sc)->res[0], _reg)
72276533Sbr#define WRITE4(_sc, _reg, _val) \
73276533Sbr	bus_write_4((_sc)->res[0], _reg, _val)
74276533Sbr
75276533Sbr#define	GPIO_SWPORTA_DR		0x00	/* Port A Data Register */
76276533Sbr#define	GPIO_SWPORTA_DDR	0x04	/* Port A Data Direction Register */
77276533Sbr#define	GPIO_INTEN		0x30	/* Interrupt Enable Register */
78276533Sbr#define	GPIO_INTMASK		0x34	/* Interrupt Mask Register */
79276533Sbr#define	GPIO_INTTYPE_LEVEL	0x38	/* Interrupt Level Register */
80276533Sbr#define	GPIO_INT_POLARITY	0x3C	/* Interrupt Polarity Register */
81276533Sbr#define	GPIO_INTSTATUS		0x40	/* Interrupt Status Register */
82276533Sbr#define	GPIO_RAW_INTSTATUS	0x44	/* Raw Interrupt Status Register */
83276533Sbr#define	GPIO_DEBOUNCE		0x48	/* Debounce Enable Register */
84276533Sbr#define	GPIO_PORTA_EOI		0x4C	/* Clear Interrupt Register */
85276533Sbr#define	GPIO_EXT_PORTA		0x50	/* External Port A Register */
86276533Sbr#define	GPIO_LS_SYNC		0x60	/* Synchronization Level Register */
87276533Sbr#define	GPIO_ID_CODE		0x64	/* ID Code Register */
88276533Sbr#define	GPIO_VER_ID_CODE	0x6C	/* GPIO Version Register */
89276533Sbr#define	GPIO_CONFIG_REG2	0x70	/* Configuration Register 2 */
90276533Sbr#define	 ENCODED_ID_PWIDTH_M	0x1f	/* Width of GPIO Port N Mask */
91276533Sbr#define	 ENCODED_ID_PWIDTH_S(n)	(5 * n)	/* Width of GPIO Port N Shift */
92276533Sbr#define	GPIO_CONFIG_REG1	0x74	/* Configuration Register 1 */
93276533Sbr
94276533Sbrenum port_no {
95276533Sbr	PORTA,
96276533Sbr	PORTB,
97276533Sbr	PORTC,
98276533Sbr	PORTD,
99276533Sbr};
100276533Sbr
101276533Sbr#define	NR_GPIO_MAX	32	/* Maximum pins per port */
102276533Sbr
103276533Sbr#define	GPIO_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
104276533Sbr#define	GPIO_UNLOCK(_sc)	mtx_unlock(&(_sc)->sc_mtx)
105276533Sbr
106276533Sbr#define	DEFAULT_CAPS	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
107276533Sbr
108276533Sbr/*
109276533Sbr * GPIO interface
110276533Sbr */
111277996Sloosstatic device_t socfpga_gpio_get_bus(device_t);
112276533Sbrstatic int socfpga_gpio_pin_max(device_t, int *);
113276533Sbrstatic int socfpga_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
114276533Sbrstatic int socfpga_gpio_pin_getname(device_t, uint32_t, char *);
115276533Sbrstatic int socfpga_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
116276533Sbrstatic int socfpga_gpio_pin_setflags(device_t, uint32_t, uint32_t);
117276533Sbrstatic int socfpga_gpio_pin_set(device_t, uint32_t, unsigned int);
118276533Sbrstatic int socfpga_gpio_pin_get(device_t, uint32_t, unsigned int *);
119276533Sbrstatic int socfpga_gpio_pin_toggle(device_t, uint32_t pin);
120276533Sbr
121276533Sbrstruct socfpga_gpio_softc {
122276533Sbr	struct resource		*res[1];
123276533Sbr	bus_space_tag_t		bst;
124276533Sbr	bus_space_handle_t	bsh;
125276533Sbr
126276533Sbr	device_t		dev;
127277996Sloos	device_t		busdev;
128276533Sbr	struct mtx		sc_mtx;
129276533Sbr	int			gpio_npins;
130276533Sbr	struct gpio_pin		gpio_pins[NR_GPIO_MAX];
131276533Sbr};
132276533Sbr
133276533Sbrstruct socfpga_gpio_softc *gpio_sc;
134276533Sbr
135276533Sbrstatic struct resource_spec socfpga_gpio_spec[] = {
136276533Sbr	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
137276533Sbr	{ -1, 0 }
138276533Sbr};
139276533Sbr
140276533Sbrstatic int
141276533Sbrsocfpga_gpio_probe(device_t dev)
142276533Sbr{
143276533Sbr
144276533Sbr	if (!ofw_bus_status_okay(dev))
145276533Sbr		return (ENXIO);
146276533Sbr
147276533Sbr	if (!ofw_bus_is_compatible(dev, "snps,dw-apb-gpio"))
148276533Sbr		return (ENXIO);
149276533Sbr
150276533Sbr	device_set_desc(dev, "DesignWare General-Purpose I/O Interface");
151276533Sbr	return (BUS_PROBE_DEFAULT);
152276533Sbr}
153276533Sbr
154276533Sbrstatic int
155276533Sbrsocfpga_gpio_attach(device_t dev)
156276533Sbr{
157276533Sbr	struct socfpga_gpio_softc *sc;
158276533Sbr	int version;
159276533Sbr	int nr_pins;
160276533Sbr	int cfg2;
161276533Sbr	int i;
162276533Sbr
163276533Sbr	sc = device_get_softc(dev);
164276533Sbr	sc->dev = dev;
165276533Sbr	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
166276533Sbr
167276533Sbr	if (bus_alloc_resources(dev, socfpga_gpio_spec, sc->res)) {
168276533Sbr		device_printf(dev, "could not allocate resources\n");
169277968Sloos		mtx_destroy(&sc->sc_mtx);
170276533Sbr		return (ENXIO);
171276533Sbr	}
172276533Sbr
173276533Sbr	/* Memory interface */
174276533Sbr	sc->bst = rman_get_bustag(sc->res[0]);
175276533Sbr	sc->bsh = rman_get_bushandle(sc->res[0]);
176276533Sbr
177276533Sbr	gpio_sc = sc;
178276533Sbr
179276533Sbr	version =  READ4(sc, GPIO_VER_ID_CODE);
180276533Sbr#if 0
181276533Sbr	device_printf(sc->dev, "Version = 0x%08x\n", version);
182276533Sbr#endif
183276533Sbr
184276533Sbr	/*
185276533Sbr	 * Take number of pins from hardware.
186276533Sbr	 * XXX: Assume we have GPIO port A only.
187276533Sbr	 */
188276533Sbr	cfg2 = READ4(sc, GPIO_CONFIG_REG2);
189276533Sbr	nr_pins = (cfg2 >> ENCODED_ID_PWIDTH_S(PORTA)) & \
190276533Sbr			ENCODED_ID_PWIDTH_M;
191276533Sbr	sc->gpio_npins = nr_pins + 1;
192276533Sbr
193276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
194276533Sbr		sc->gpio_pins[i].gp_pin = i;
195276533Sbr		sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
196276533Sbr		sc->gpio_pins[i].gp_flags =
197276533Sbr		    (READ4(sc, GPIO_SWPORTA_DDR) & (1 << i)) ?
198276533Sbr		    GPIO_PIN_OUTPUT: GPIO_PIN_INPUT;
199276533Sbr		snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
200276533Sbr		    "socfpga_gpio%d.%d", device_get_unit(dev), i);
201276533Sbr	}
202277996Sloos	sc->busdev = gpiobus_attach_bus(dev);
203277996Sloos	if (sc->busdev == NULL) {
204277996Sloos		bus_release_resources(dev, socfpga_gpio_spec, sc->res);
205277996Sloos		mtx_destroy(&sc->sc_mtx);
206277996Sloos		return (ENXIO);
207277996Sloos	}
208276533Sbr
209277996Sloos	return (0);
210277996Sloos}
211276533Sbr
212277996Sloosstatic device_t
213277996Sloossocfpga_gpio_get_bus(device_t dev)
214277996Sloos{
215277996Sloos	struct socfpga_gpio_softc *sc;
216277996Sloos
217277996Sloos	sc = device_get_softc(dev);
218277996Sloos
219277996Sloos	return (sc->busdev);
220276533Sbr}
221276533Sbr
222276533Sbrstatic int
223276533Sbrsocfpga_gpio_pin_max(device_t dev, int *maxpin)
224276533Sbr{
225276533Sbr	struct socfpga_gpio_softc *sc;
226276533Sbr
227276533Sbr	sc = device_get_softc(dev);
228276533Sbr
229276533Sbr	*maxpin = sc->gpio_npins - 1;
230276533Sbr
231276533Sbr	return (0);
232276533Sbr}
233276533Sbr
234276533Sbrstatic int
235276533Sbrsocfpga_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
236276533Sbr{
237276533Sbr	struct socfpga_gpio_softc *sc;
238276533Sbr	int i;
239276533Sbr
240276533Sbr	sc = device_get_softc(dev);
241276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
242276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
243276533Sbr			break;
244276533Sbr	}
245276533Sbr
246276533Sbr	if (i >= sc->gpio_npins)
247276533Sbr		return (EINVAL);
248276533Sbr
249276533Sbr	GPIO_LOCK(sc);
250276533Sbr	memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
251276533Sbr	GPIO_UNLOCK(sc);
252276533Sbr
253276533Sbr	return (0);
254276533Sbr}
255276533Sbr
256276533Sbrstatic int
257276533Sbrsocfpga_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
258276533Sbr{
259276533Sbr	struct socfpga_gpio_softc *sc;
260276533Sbr	int i;
261276533Sbr
262276533Sbr	sc = device_get_softc(dev);
263276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
264276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
265276533Sbr			break;
266276533Sbr	}
267276533Sbr
268276533Sbr	if (i >= sc->gpio_npins)
269276533Sbr		return (EINVAL);
270276533Sbr
271276533Sbr	GPIO_LOCK(sc);
272276533Sbr	*caps = sc->gpio_pins[i].gp_caps;
273276533Sbr	GPIO_UNLOCK(sc);
274276533Sbr
275276533Sbr	return (0);
276276533Sbr}
277276533Sbr
278276533Sbrstatic int
279276533Sbrsocfpga_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
280276533Sbr{
281276533Sbr	struct socfpga_gpio_softc *sc;
282276533Sbr	int i;
283276533Sbr
284276533Sbr	sc = device_get_softc(dev);
285276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
286276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
287276533Sbr			break;
288276533Sbr	}
289276533Sbr
290276533Sbr	if (i >= sc->gpio_npins)
291276533Sbr		return (EINVAL);
292276533Sbr
293276533Sbr	GPIO_LOCK(sc);
294276533Sbr	*flags = sc->gpio_pins[i].gp_flags;
295276533Sbr	GPIO_UNLOCK(sc);
296276533Sbr
297276533Sbr	return (0);
298276533Sbr}
299276533Sbr
300276533Sbrstatic int
301276533Sbrsocfpga_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
302276533Sbr{
303276533Sbr	struct socfpga_gpio_softc *sc;
304276533Sbr	int i;
305276533Sbr
306276533Sbr	sc = device_get_softc(dev);
307276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
308276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
309276533Sbr			break;
310276533Sbr	}
311276533Sbr
312276533Sbr	if (i >= sc->gpio_npins)
313276533Sbr		return (EINVAL);
314276533Sbr
315276533Sbr	GPIO_LOCK(sc);
316276533Sbr	*val = (READ4(sc, GPIO_EXT_PORTA) & (1 << i)) ? 1 : 0;
317276533Sbr	GPIO_UNLOCK(sc);
318276533Sbr
319276533Sbr	return (0);
320276533Sbr}
321276533Sbr
322276533Sbrstatic int
323276533Sbrsocfpga_gpio_pin_toggle(device_t dev, uint32_t pin)
324276533Sbr{
325276533Sbr	struct socfpga_gpio_softc *sc;
326276533Sbr	int reg;
327276533Sbr	int i;
328276533Sbr
329276533Sbr	sc = device_get_softc(dev);
330276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
331276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
332276533Sbr			break;
333276533Sbr	}
334276533Sbr
335276533Sbr	if (i >= sc->gpio_npins)
336276533Sbr		return (EINVAL);
337276533Sbr
338276533Sbr	GPIO_LOCK(sc);
339276533Sbr	reg = READ4(sc, GPIO_SWPORTA_DR);
340276533Sbr	if (reg & (1 << i))
341276533Sbr		reg &= ~(1 << i);
342276533Sbr	else
343276533Sbr		reg |= (1 << i);
344276533Sbr	WRITE4(sc, GPIO_SWPORTA_DR, reg);
345276533Sbr	GPIO_UNLOCK(sc);
346276533Sbr
347276533Sbr	return (0);
348276533Sbr}
349276533Sbr
350276533Sbr
351276533Sbrstatic void
352276533Sbrsocfpga_gpio_pin_configure(struct socfpga_gpio_softc *sc,
353276533Sbr    struct gpio_pin *pin, unsigned int flags)
354276533Sbr{
355276533Sbr	int reg;
356276533Sbr
357276533Sbr	GPIO_LOCK(sc);
358276533Sbr
359276533Sbr	/*
360276533Sbr	 * Manage input/output
361276533Sbr	 */
362276533Sbr
363276533Sbr	reg = READ4(sc, GPIO_SWPORTA_DDR);
364276533Sbr	if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
365276533Sbr		pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
366276533Sbr		if (flags & GPIO_PIN_OUTPUT) {
367276533Sbr			pin->gp_flags |= GPIO_PIN_OUTPUT;
368276533Sbr			reg |= (1 << pin->gp_pin);
369276533Sbr		} else {
370276533Sbr			pin->gp_flags |= GPIO_PIN_INPUT;
371276533Sbr			reg &= ~(1 << pin->gp_pin);
372276533Sbr		}
373276533Sbr	}
374276533Sbr
375276533Sbr	WRITE4(sc, GPIO_SWPORTA_DDR, reg);
376276533Sbr	GPIO_UNLOCK(sc);
377276533Sbr}
378276533Sbr
379276533Sbr
380276533Sbrstatic int
381276533Sbrsocfpga_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
382276533Sbr{
383276533Sbr	struct socfpga_gpio_softc *sc;
384276533Sbr	int i;
385276533Sbr
386276533Sbr	sc = device_get_softc(dev);
387276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
388276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
389276533Sbr			break;
390276533Sbr	}
391276533Sbr
392276533Sbr	if (i >= sc->gpio_npins)
393276533Sbr		return (EINVAL);
394276533Sbr
395276533Sbr	socfpga_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);
396276533Sbr
397276533Sbr	return (0);
398276533Sbr}
399276533Sbr
400276533Sbrstatic int
401276533Sbrsocfpga_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
402276533Sbr{
403276533Sbr	struct socfpga_gpio_softc *sc;
404276533Sbr	int reg;
405276533Sbr	int i;
406276533Sbr
407276533Sbr	sc = device_get_softc(dev);
408276533Sbr
409276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
410276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
411276533Sbr			break;
412276533Sbr	}
413276533Sbr
414276533Sbr	if (i >= sc->gpio_npins)
415276533Sbr		return (EINVAL);
416276533Sbr
417276533Sbr	GPIO_LOCK(sc);
418276533Sbr	reg = READ4(sc, GPIO_SWPORTA_DR);
419276533Sbr	if (value)
420276533Sbr		reg |= (1 << i);
421276533Sbr	else
422276533Sbr		reg &= ~(1 << i);
423276533Sbr	WRITE4(sc, GPIO_SWPORTA_DR, reg);
424276533Sbr	GPIO_UNLOCK(sc);
425276533Sbr
426276533Sbr	return (0);
427276533Sbr}
428276533Sbr
429276533Sbrstatic device_method_t socfpga_gpio_methods[] = {
430276533Sbr	DEVMETHOD(device_probe,		socfpga_gpio_probe),
431276533Sbr	DEVMETHOD(device_attach,	socfpga_gpio_attach),
432276533Sbr
433276533Sbr	/* GPIO protocol */
434277996Sloos	DEVMETHOD(gpio_get_bus,		socfpga_gpio_get_bus),
435276533Sbr	DEVMETHOD(gpio_pin_max,		socfpga_gpio_pin_max),
436276533Sbr	DEVMETHOD(gpio_pin_getname,	socfpga_gpio_pin_getname),
437276533Sbr	DEVMETHOD(gpio_pin_getcaps,	socfpga_gpio_pin_getcaps),
438276533Sbr	DEVMETHOD(gpio_pin_getflags,	socfpga_gpio_pin_getflags),
439276533Sbr	DEVMETHOD(gpio_pin_get,		socfpga_gpio_pin_get),
440276533Sbr	DEVMETHOD(gpio_pin_toggle,	socfpga_gpio_pin_toggle),
441276533Sbr	DEVMETHOD(gpio_pin_setflags,	socfpga_gpio_pin_setflags),
442276533Sbr	DEVMETHOD(gpio_pin_set,		socfpga_gpio_pin_set),
443276533Sbr	{ 0, 0 }
444276533Sbr};
445276533Sbr
446276533Sbrstatic driver_t socfpga_gpio_driver = {
447276533Sbr	"gpio",
448276533Sbr	socfpga_gpio_methods,
449276533Sbr	sizeof(struct socfpga_gpio_softc),
450276533Sbr};
451276533Sbr
452276533Sbrstatic devclass_t socfpga_gpio_devclass;
453276533Sbr
454276533SbrDRIVER_MODULE(socfpga_gpio, simplebus, socfpga_gpio_driver,
455276533Sbr    socfpga_gpio_devclass, 0, 0);
456