1274656Sbr/*-
2274656Sbr * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
3274656Sbr * All rights reserved.
4274656Sbr *
5274656Sbr * This software was developed by SRI International and the University of
6274656Sbr * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7274656Sbr * ("CTSRD"), as part of the DARPA CRASH research programme.
8274656Sbr *
9274656Sbr * Redistribution and use in source and binary forms, with or without
10274656Sbr * modification, are permitted provided that the following conditions
11274656Sbr * are met:
12274656Sbr * 1. Redistributions of source code must retain the above copyright
13274656Sbr *    notice, this list of conditions and the following disclaimer.
14274656Sbr * 2. Redistributions in binary form must reproduce the above copyright
15274656Sbr *    notice, this list of conditions and the following disclaimer in the
16274656Sbr *    documentation and/or other materials provided with the distribution.
17274656Sbr *
18274656Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19274656Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20274656Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21274656Sbr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22274656Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23274656Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24274656Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25274656Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26274656Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27274656Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28274656Sbr * SUCH DAMAGE.
29274656Sbr */
30274656Sbr
31274656Sbr/*
32274656Sbr * Altera PIO (Parallel IO) device driver
33274656Sbr */
34274656Sbr
35274656Sbr#include <sys/cdefs.h>
36274656Sbr__FBSDID("$FreeBSD: releng/11.0/sys/dev/altera/pio/pio.c 276670 2015-01-04 23:14:04Z br $");
37274656Sbr
38274656Sbr#include <sys/param.h>
39274656Sbr#include <sys/systm.h>
40274656Sbr#include <sys/bus.h>
41274656Sbr#include <sys/kernel.h>
42274656Sbr#include <sys/module.h>
43274656Sbr#include <sys/malloc.h>
44274656Sbr#include <sys/rman.h>
45274656Sbr#include <sys/timeet.h>
46274656Sbr#include <sys/timetc.h>
47274656Sbr
48274656Sbr#include <dev/fdt/fdt_common.h>
49274656Sbr#include <dev/ofw/openfirm.h>
50274656Sbr#include <dev/ofw/ofw_bus.h>
51274656Sbr#include <dev/ofw/ofw_bus_subr.h>
52274656Sbr
53274656Sbr#include <machine/bus.h>
54274656Sbr#include <machine/fdt.h>
55274656Sbr#include <machine/cpu.h>
56274656Sbr
57274656Sbr#include <dev/altera/pio/pio.h>
58274656Sbr#include "pio_if.h"
59274656Sbr
60274656Sbr#define READ4(_sc, _reg) bus_read_4((_sc)->res[0], _reg)
61274656Sbr#define READ2(_sc, _reg) bus_read_2((_sc)->res[0], _reg)
62274656Sbr#define READ1(_sc, _reg) bus_read_1((_sc)->res[0], _reg)
63274656Sbr#define WRITE4(_sc, _reg, _val) bus_write_4((_sc)->res[0], _reg, _val)
64274656Sbr#define WRITE2(_sc, _reg, _val) bus_write_2((_sc)->res[0], _reg, _val)
65274656Sbr#define WRITE1(_sc, _reg, _val) bus_write_1((_sc)->res[0], _reg, _val)
66274656Sbr
67274656Sbrstruct pio_softc {
68274656Sbr	struct resource		*res[2];
69274656Sbr	bus_space_tag_t		bst;
70274656Sbr	bus_space_handle_t	bsh;
71274656Sbr	device_t		dev;
72274656Sbr	void			*ih;
73274656Sbr};
74274656Sbr
75274656Sbrstatic struct resource_spec pio_spec[] = {
76274656Sbr	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
77274656Sbr	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
78274656Sbr	{ -1, 0 }
79274656Sbr};
80274656Sbr
81274656Sbrstatic int
82274656Sbrpio_setup_irq(device_t dev, void *intr_handler, void *ih_user)
83274656Sbr{
84274656Sbr	struct pio_softc *sc;
85274656Sbr
86274656Sbr	sc = device_get_softc(dev);
87274656Sbr
88274656Sbr	/* Setup interrupt handlers */
89274656Sbr	if (bus_setup_intr(sc->dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE,
90274656Sbr		NULL, intr_handler, ih_user, &sc->ih)) {
91274656Sbr		device_printf(sc->dev, "Unable to setup intr\n");
92274656Sbr		return (1);
93274656Sbr	}
94274656Sbr
95274656Sbr	return (0);
96274656Sbr}
97274656Sbr
98274656Sbrstatic int
99274656Sbrpio_teardown_irq(device_t dev)
100274656Sbr{
101274656Sbr	struct pio_softc *sc;
102274656Sbr
103274656Sbr	sc = device_get_softc(dev);
104274656Sbr
105274656Sbr	bus_teardown_intr(sc->dev, sc->res[1], sc->ih);
106274656Sbr
107274656Sbr	return (0);
108274656Sbr}
109274656Sbr
110274656Sbrstatic int
111274656Sbrpio_read(device_t dev)
112274656Sbr{
113274656Sbr	struct pio_softc *sc;
114274656Sbr
115274656Sbr	sc = device_get_softc(dev);
116274656Sbr
117274656Sbr	return (READ4(sc, PIO_DATA));
118274656Sbr}
119274656Sbr
120274656Sbrstatic int
121274656Sbrpio_set(device_t dev, int bit, int enable)
122274656Sbr{
123274656Sbr	struct pio_softc *sc;
124274656Sbr
125274656Sbr	sc = device_get_softc(dev);
126274656Sbr
127274656Sbr	if (enable)
128274656Sbr		WRITE4(sc, PIO_OUTSET, bit);
129274656Sbr	else
130274656Sbr		WRITE4(sc, PIO_OUTCLR, bit);
131274656Sbr
132274656Sbr	return (0);
133274656Sbr}
134274656Sbr
135274656Sbrstatic int
136274656Sbrpio_configure(device_t dev, int dir, int mask)
137274656Sbr{
138274656Sbr	struct pio_softc *sc;
139274656Sbr
140274656Sbr	sc = device_get_softc(dev);
141274656Sbr
142274656Sbr	WRITE4(sc, PIO_INT_MASK, mask);
143274656Sbr	WRITE4(sc, PIO_DIR, dir);
144274656Sbr
145274656Sbr	return (0);
146274656Sbr}
147274656Sbr
148274656Sbrstatic int
149274656Sbrpio_probe(device_t dev)
150274656Sbr{
151274656Sbr
152274656Sbr	if (!ofw_bus_status_okay(dev))
153274656Sbr		return (ENXIO);
154274656Sbr
155274656Sbr	if (!ofw_bus_is_compatible(dev, "altr,pio"))
156274656Sbr		return (ENXIO);
157274656Sbr
158274656Sbr	device_set_desc(dev, "Altera PIO");
159274656Sbr	return (BUS_PROBE_DEFAULT);
160274656Sbr}
161274656Sbr
162274656Sbrstatic int
163274656Sbrpio_attach(device_t dev)
164274656Sbr{
165274656Sbr	struct pio_softc *sc;
166274656Sbr	struct fdt_ic *fic;
167274656Sbr	phandle_t node;
168274656Sbr
169274656Sbr	sc = device_get_softc(dev);
170274656Sbr	sc->dev = dev;
171274656Sbr
172274656Sbr	if (bus_alloc_resources(dev, pio_spec, sc->res)) {
173274656Sbr		device_printf(dev, "could not allocate resources\n");
174274656Sbr		return (ENXIO);
175274656Sbr	}
176274656Sbr
177274656Sbr	/* Memory interface */
178274656Sbr	sc->bst = rman_get_bustag(sc->res[0]);
179274656Sbr	sc->bsh = rman_get_bushandle(sc->res[0]);
180274656Sbr
181274656Sbr	if ((node = ofw_bus_get_node(sc->dev)) == -1)
182274656Sbr		return (ENXIO);
183274656Sbr
184274656Sbr	fic = malloc(sizeof(*fic), M_DEVBUF, M_WAITOK|M_ZERO);
185274656Sbr	fic->iph = node;
186274656Sbr	fic->dev = dev;
187274656Sbr	SLIST_INSERT_HEAD(&fdt_ic_list_head, fic, fdt_ics);
188274656Sbr
189274656Sbr	return (0);
190274656Sbr}
191274656Sbr
192274656Sbrstatic device_method_t pio_methods[] = {
193274656Sbr	DEVMETHOD(device_probe,		pio_probe),
194274656Sbr	DEVMETHOD(device_attach,	pio_attach),
195274656Sbr
196274656Sbr	/* pio_if.m */
197274656Sbr	DEVMETHOD(pio_read,		pio_read),
198274656Sbr	DEVMETHOD(pio_configure,	pio_configure),
199274656Sbr	DEVMETHOD(pio_set,		pio_set),
200274656Sbr	DEVMETHOD(pio_setup_irq,	pio_setup_irq),
201274656Sbr	DEVMETHOD(pio_teardown_irq,	pio_teardown_irq),
202274656Sbr	DEVMETHOD_END
203274656Sbr};
204274656Sbr
205274656Sbrstatic driver_t pio_driver = {
206274656Sbr	"altera_pio",
207274656Sbr	pio_methods,
208274656Sbr	sizeof(struct pio_softc),
209274656Sbr};
210274656Sbr
211274656Sbrstatic devclass_t pio_devclass;
212274656Sbr
213274656SbrDRIVER_MODULE(altera_pio, simplebus, pio_driver, pio_devclass, 0, 0);
214