socfpga_gpio.c revision 277968
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 277968 2015-01-31 12:17:07Z 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>
58276533Sbr#include <dev/ofw/openfirm.h>
59276533Sbr#include <dev/ofw/ofw_bus.h>
60276533Sbr#include <dev/ofw/ofw_bus_subr.h>
61276533Sbr
62276533Sbr#include <machine/bus.h>
63276533Sbr#include <machine/fdt.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 */
110276533Sbrstatic int socfpga_gpio_pin_max(device_t, int *);
111276533Sbrstatic int socfpga_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
112276533Sbrstatic int socfpga_gpio_pin_getname(device_t, uint32_t, char *);
113276533Sbrstatic int socfpga_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
114276533Sbrstatic int socfpga_gpio_pin_setflags(device_t, uint32_t, uint32_t);
115276533Sbrstatic int socfpga_gpio_pin_set(device_t, uint32_t, unsigned int);
116276533Sbrstatic int socfpga_gpio_pin_get(device_t, uint32_t, unsigned int *);
117276533Sbrstatic int socfpga_gpio_pin_toggle(device_t, uint32_t pin);
118276533Sbr
119276533Sbrstruct socfpga_gpio_softc {
120276533Sbr	struct resource		*res[1];
121276533Sbr	bus_space_tag_t		bst;
122276533Sbr	bus_space_handle_t	bsh;
123276533Sbr
124276533Sbr	device_t		dev;
125276533Sbr	struct mtx		sc_mtx;
126276533Sbr	int			gpio_npins;
127276533Sbr	struct gpio_pin		gpio_pins[NR_GPIO_MAX];
128276533Sbr};
129276533Sbr
130276533Sbrstruct socfpga_gpio_softc *gpio_sc;
131276533Sbr
132276533Sbrstatic struct resource_spec socfpga_gpio_spec[] = {
133276533Sbr	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
134276533Sbr	{ -1, 0 }
135276533Sbr};
136276533Sbr
137276533Sbrstatic int
138276533Sbrsocfpga_gpio_probe(device_t dev)
139276533Sbr{
140276533Sbr
141276533Sbr	if (!ofw_bus_status_okay(dev))
142276533Sbr		return (ENXIO);
143276533Sbr
144276533Sbr	if (!ofw_bus_is_compatible(dev, "snps,dw-apb-gpio"))
145276533Sbr		return (ENXIO);
146276533Sbr
147276533Sbr	device_set_desc(dev, "DesignWare General-Purpose I/O Interface");
148276533Sbr	return (BUS_PROBE_DEFAULT);
149276533Sbr}
150276533Sbr
151276533Sbrstatic int
152276533Sbrsocfpga_gpio_attach(device_t dev)
153276533Sbr{
154276533Sbr	struct socfpga_gpio_softc *sc;
155276533Sbr	int version;
156276533Sbr	int nr_pins;
157276533Sbr	int cfg2;
158276533Sbr	int i;
159276533Sbr
160276533Sbr	sc = device_get_softc(dev);
161276533Sbr	sc->dev = dev;
162276533Sbr	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
163276533Sbr
164276533Sbr	if (bus_alloc_resources(dev, socfpga_gpio_spec, sc->res)) {
165276533Sbr		device_printf(dev, "could not allocate resources\n");
166277968Sloos		mtx_destroy(&sc->sc_mtx);
167276533Sbr		return (ENXIO);
168276533Sbr	}
169276533Sbr
170276533Sbr	/* Memory interface */
171276533Sbr	sc->bst = rman_get_bustag(sc->res[0]);
172276533Sbr	sc->bsh = rman_get_bushandle(sc->res[0]);
173276533Sbr
174276533Sbr	gpio_sc = sc;
175276533Sbr
176276533Sbr	version =  READ4(sc, GPIO_VER_ID_CODE);
177276533Sbr#if 0
178276533Sbr	device_printf(sc->dev, "Version = 0x%08x\n", version);
179276533Sbr#endif
180276533Sbr
181276533Sbr	/*
182276533Sbr	 * Take number of pins from hardware.
183276533Sbr	 * XXX: Assume we have GPIO port A only.
184276533Sbr	 */
185276533Sbr	cfg2 = READ4(sc, GPIO_CONFIG_REG2);
186276533Sbr	nr_pins = (cfg2 >> ENCODED_ID_PWIDTH_S(PORTA)) & \
187276533Sbr			ENCODED_ID_PWIDTH_M;
188276533Sbr	sc->gpio_npins = nr_pins + 1;
189276533Sbr
190276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
191276533Sbr		sc->gpio_pins[i].gp_pin = i;
192276533Sbr		sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
193276533Sbr		sc->gpio_pins[i].gp_flags =
194276533Sbr		    (READ4(sc, GPIO_SWPORTA_DDR) & (1 << i)) ?
195276533Sbr		    GPIO_PIN_OUTPUT: GPIO_PIN_INPUT;
196276533Sbr		snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
197276533Sbr		    "socfpga_gpio%d.%d", device_get_unit(dev), i);
198276533Sbr	}
199276533Sbr
200276533Sbr	device_add_child(dev, "gpioc", -1);
201276533Sbr	device_add_child(dev, "gpiobus", -1);
202276533Sbr
203276533Sbr	return (bus_generic_attach(dev));
204276533Sbr}
205276533Sbr
206276533Sbrstatic int
207276533Sbrsocfpga_gpio_pin_max(device_t dev, int *maxpin)
208276533Sbr{
209276533Sbr	struct socfpga_gpio_softc *sc;
210276533Sbr
211276533Sbr	sc = device_get_softc(dev);
212276533Sbr
213276533Sbr	*maxpin = sc->gpio_npins - 1;
214276533Sbr
215276533Sbr	return (0);
216276533Sbr}
217276533Sbr
218276533Sbrstatic int
219276533Sbrsocfpga_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
220276533Sbr{
221276533Sbr	struct socfpga_gpio_softc *sc;
222276533Sbr	int i;
223276533Sbr
224276533Sbr	sc = device_get_softc(dev);
225276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
226276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
227276533Sbr			break;
228276533Sbr	}
229276533Sbr
230276533Sbr	if (i >= sc->gpio_npins)
231276533Sbr		return (EINVAL);
232276533Sbr
233276533Sbr	GPIO_LOCK(sc);
234276533Sbr	memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
235276533Sbr	GPIO_UNLOCK(sc);
236276533Sbr
237276533Sbr	return (0);
238276533Sbr}
239276533Sbr
240276533Sbrstatic int
241276533Sbrsocfpga_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
242276533Sbr{
243276533Sbr	struct socfpga_gpio_softc *sc;
244276533Sbr	int i;
245276533Sbr
246276533Sbr	sc = device_get_softc(dev);
247276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
248276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
249276533Sbr			break;
250276533Sbr	}
251276533Sbr
252276533Sbr	if (i >= sc->gpio_npins)
253276533Sbr		return (EINVAL);
254276533Sbr
255276533Sbr	GPIO_LOCK(sc);
256276533Sbr	*caps = sc->gpio_pins[i].gp_caps;
257276533Sbr	GPIO_UNLOCK(sc);
258276533Sbr
259276533Sbr	return (0);
260276533Sbr}
261276533Sbr
262276533Sbrstatic int
263276533Sbrsocfpga_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
264276533Sbr{
265276533Sbr	struct socfpga_gpio_softc *sc;
266276533Sbr	int i;
267276533Sbr
268276533Sbr	sc = device_get_softc(dev);
269276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
270276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
271276533Sbr			break;
272276533Sbr	}
273276533Sbr
274276533Sbr	if (i >= sc->gpio_npins)
275276533Sbr		return (EINVAL);
276276533Sbr
277276533Sbr	GPIO_LOCK(sc);
278276533Sbr	*flags = sc->gpio_pins[i].gp_flags;
279276533Sbr	GPIO_UNLOCK(sc);
280276533Sbr
281276533Sbr	return (0);
282276533Sbr}
283276533Sbr
284276533Sbrstatic int
285276533Sbrsocfpga_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
286276533Sbr{
287276533Sbr	struct socfpga_gpio_softc *sc;
288276533Sbr	int i;
289276533Sbr
290276533Sbr	sc = device_get_softc(dev);
291276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
292276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
293276533Sbr			break;
294276533Sbr	}
295276533Sbr
296276533Sbr	if (i >= sc->gpio_npins)
297276533Sbr		return (EINVAL);
298276533Sbr
299276533Sbr	GPIO_LOCK(sc);
300276533Sbr	*val = (READ4(sc, GPIO_EXT_PORTA) & (1 << i)) ? 1 : 0;
301276533Sbr	GPIO_UNLOCK(sc);
302276533Sbr
303276533Sbr	return (0);
304276533Sbr}
305276533Sbr
306276533Sbrstatic int
307276533Sbrsocfpga_gpio_pin_toggle(device_t dev, uint32_t pin)
308276533Sbr{
309276533Sbr	struct socfpga_gpio_softc *sc;
310276533Sbr	int reg;
311276533Sbr	int i;
312276533Sbr
313276533Sbr	sc = device_get_softc(dev);
314276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
315276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
316276533Sbr			break;
317276533Sbr	}
318276533Sbr
319276533Sbr	if (i >= sc->gpio_npins)
320276533Sbr		return (EINVAL);
321276533Sbr
322276533Sbr	GPIO_LOCK(sc);
323276533Sbr	reg = READ4(sc, GPIO_SWPORTA_DR);
324276533Sbr	if (reg & (1 << i))
325276533Sbr		reg &= ~(1 << i);
326276533Sbr	else
327276533Sbr		reg |= (1 << i);
328276533Sbr	WRITE4(sc, GPIO_SWPORTA_DR, reg);
329276533Sbr	GPIO_UNLOCK(sc);
330276533Sbr
331276533Sbr	return (0);
332276533Sbr}
333276533Sbr
334276533Sbr
335276533Sbrstatic void
336276533Sbrsocfpga_gpio_pin_configure(struct socfpga_gpio_softc *sc,
337276533Sbr    struct gpio_pin *pin, unsigned int flags)
338276533Sbr{
339276533Sbr	int reg;
340276533Sbr
341276533Sbr	GPIO_LOCK(sc);
342276533Sbr
343276533Sbr	/*
344276533Sbr	 * Manage input/output
345276533Sbr	 */
346276533Sbr
347276533Sbr	reg = READ4(sc, GPIO_SWPORTA_DDR);
348276533Sbr	if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
349276533Sbr		pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
350276533Sbr		if (flags & GPIO_PIN_OUTPUT) {
351276533Sbr			pin->gp_flags |= GPIO_PIN_OUTPUT;
352276533Sbr			reg |= (1 << pin->gp_pin);
353276533Sbr		} else {
354276533Sbr			pin->gp_flags |= GPIO_PIN_INPUT;
355276533Sbr			reg &= ~(1 << pin->gp_pin);
356276533Sbr		}
357276533Sbr	}
358276533Sbr
359276533Sbr	WRITE4(sc, GPIO_SWPORTA_DDR, reg);
360276533Sbr	GPIO_UNLOCK(sc);
361276533Sbr}
362276533Sbr
363276533Sbr
364276533Sbrstatic int
365276533Sbrsocfpga_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
366276533Sbr{
367276533Sbr	struct socfpga_gpio_softc *sc;
368276533Sbr	int i;
369276533Sbr
370276533Sbr	sc = device_get_softc(dev);
371276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
372276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
373276533Sbr			break;
374276533Sbr	}
375276533Sbr
376276533Sbr	if (i >= sc->gpio_npins)
377276533Sbr		return (EINVAL);
378276533Sbr
379276533Sbr	socfpga_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);
380276533Sbr
381276533Sbr	return (0);
382276533Sbr}
383276533Sbr
384276533Sbrstatic int
385276533Sbrsocfpga_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
386276533Sbr{
387276533Sbr	struct socfpga_gpio_softc *sc;
388276533Sbr	int reg;
389276533Sbr	int i;
390276533Sbr
391276533Sbr	sc = device_get_softc(dev);
392276533Sbr
393276533Sbr	for (i = 0; i < sc->gpio_npins; i++) {
394276533Sbr		if (sc->gpio_pins[i].gp_pin == pin)
395276533Sbr			break;
396276533Sbr	}
397276533Sbr
398276533Sbr	if (i >= sc->gpio_npins)
399276533Sbr		return (EINVAL);
400276533Sbr
401276533Sbr	GPIO_LOCK(sc);
402276533Sbr	reg = READ4(sc, GPIO_SWPORTA_DR);
403276533Sbr	if (value)
404276533Sbr		reg |= (1 << i);
405276533Sbr	else
406276533Sbr		reg &= ~(1 << i);
407276533Sbr	WRITE4(sc, GPIO_SWPORTA_DR, reg);
408276533Sbr	GPIO_UNLOCK(sc);
409276533Sbr
410276533Sbr	return (0);
411276533Sbr}
412276533Sbr
413276533Sbrstatic device_method_t socfpga_gpio_methods[] = {
414276533Sbr	DEVMETHOD(device_probe,		socfpga_gpio_probe),
415276533Sbr	DEVMETHOD(device_attach,	socfpga_gpio_attach),
416276533Sbr
417276533Sbr	/* GPIO protocol */
418276533Sbr	DEVMETHOD(gpio_pin_max,		socfpga_gpio_pin_max),
419276533Sbr	DEVMETHOD(gpio_pin_getname,	socfpga_gpio_pin_getname),
420276533Sbr	DEVMETHOD(gpio_pin_getcaps,	socfpga_gpio_pin_getcaps),
421276533Sbr	DEVMETHOD(gpio_pin_getflags,	socfpga_gpio_pin_getflags),
422276533Sbr	DEVMETHOD(gpio_pin_get,		socfpga_gpio_pin_get),
423276533Sbr	DEVMETHOD(gpio_pin_toggle,	socfpga_gpio_pin_toggle),
424276533Sbr	DEVMETHOD(gpio_pin_setflags,	socfpga_gpio_pin_setflags),
425276533Sbr	DEVMETHOD(gpio_pin_set,		socfpga_gpio_pin_set),
426276533Sbr	{ 0, 0 }
427276533Sbr};
428276533Sbr
429276533Sbrstatic driver_t socfpga_gpio_driver = {
430276533Sbr	"gpio",
431276533Sbr	socfpga_gpio_methods,
432276533Sbr	sizeof(struct socfpga_gpio_softc),
433276533Sbr};
434276533Sbr
435276533Sbrstatic devclass_t socfpga_gpio_devclass;
436276533Sbr
437276533SbrDRIVER_MODULE(socfpga_gpio, simplebus, socfpga_gpio_driver,
438276533Sbr    socfpga_gpio_devclass, 0, 0);
439