1 /*-
2 * Copyright (c) 2014 Ruslan Bukin <[email protected]>
3 * All rights reserved.
4 *
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /*
32 * Altera PIO (Parallel IO) device driver
33 */
34
35 #include <sys/cdefs.h>
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/malloc.h>
42 #include <sys/rman.h>
43 #include <sys/timeet.h>
44 #include <sys/timetc.h>
45
46 #include <dev/fdt/fdt_common.h>
47 #include <dev/ofw/openfirm.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
50
51 #include <machine/bus.h>
52 #include <machine/fdt.h>
53 #include <machine/cpu.h>
54
55 #include <dev/altera/pio/pio.h>
56 #include "pio_if.h"
57
58 #define READ4(_sc, _reg) bus_read_4((_sc)->res[0], _reg)
59 #define READ2(_sc, _reg) bus_read_2((_sc)->res[0], _reg)
60 #define READ1(_sc, _reg) bus_read_1((_sc)->res[0], _reg)
61 #define WRITE4(_sc, _reg, _val) bus_write_4((_sc)->res[0], _reg, _val)
62 #define WRITE2(_sc, _reg, _val) bus_write_2((_sc)->res[0], _reg, _val)
63 #define WRITE1(_sc, _reg, _val) bus_write_1((_sc)->res[0], _reg, _val)
64
65 struct pio_softc {
66 struct resource *res[2];
67 bus_space_tag_t bst;
68 bus_space_handle_t bsh;
69 device_t dev;
70 void *ih;
71 };
72
73 static struct resource_spec pio_spec[] = {
74 { SYS_RES_MEMORY, 0, RF_ACTIVE },
75 { SYS_RES_IRQ, 0, RF_ACTIVE },
76 { -1, 0 }
77 };
78
79 static int
pio_setup_irq(device_t dev,void * intr_handler,void * ih_user)80 pio_setup_irq(device_t dev, void *intr_handler, void *ih_user)
81 {
82 struct pio_softc *sc;
83
84 sc = device_get_softc(dev);
85
86 /* Setup interrupt handlers */
87 if (bus_setup_intr(sc->dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE,
88 NULL, intr_handler, ih_user, &sc->ih)) {
89 device_printf(sc->dev, "Unable to setup intr\n");
90 return (1);
91 }
92
93 return (0);
94 }
95
96 static int
pio_teardown_irq(device_t dev)97 pio_teardown_irq(device_t dev)
98 {
99 struct pio_softc *sc;
100
101 sc = device_get_softc(dev);
102
103 bus_teardown_intr(sc->dev, sc->res[1], sc->ih);
104
105 return (0);
106 }
107
108 static int
pio_read(device_t dev)109 pio_read(device_t dev)
110 {
111 struct pio_softc *sc;
112
113 sc = device_get_softc(dev);
114
115 return (READ4(sc, PIO_DATA));
116 }
117
118 static int
pio_set(device_t dev,int bit,int enable)119 pio_set(device_t dev, int bit, int enable)
120 {
121 struct pio_softc *sc;
122
123 sc = device_get_softc(dev);
124
125 if (enable)
126 WRITE4(sc, PIO_OUTSET, bit);
127 else
128 WRITE4(sc, PIO_OUTCLR, bit);
129
130 return (0);
131 }
132
133 static int
pio_configure(device_t dev,int dir,int mask)134 pio_configure(device_t dev, int dir, int mask)
135 {
136 struct pio_softc *sc;
137
138 sc = device_get_softc(dev);
139
140 WRITE4(sc, PIO_INT_MASK, mask);
141 WRITE4(sc, PIO_DIR, dir);
142
143 return (0);
144 }
145
146 static int
pio_probe(device_t dev)147 pio_probe(device_t dev)
148 {
149
150 if (!ofw_bus_status_okay(dev))
151 return (ENXIO);
152
153 if (!ofw_bus_is_compatible(dev, "altr,pio"))
154 return (ENXIO);
155
156 device_set_desc(dev, "Altera PIO");
157 return (BUS_PROBE_DEFAULT);
158 }
159
160 static int
pio_attach(device_t dev)161 pio_attach(device_t dev)
162 {
163 struct pio_softc *sc;
164 struct fdt_ic *fic;
165 phandle_t node;
166
167 sc = device_get_softc(dev);
168 sc->dev = dev;
169
170 if (bus_alloc_resources(dev, pio_spec, sc->res)) {
171 device_printf(dev, "could not allocate resources\n");
172 return (ENXIO);
173 }
174
175 /* Memory interface */
176 sc->bst = rman_get_bustag(sc->res[0]);
177 sc->bsh = rman_get_bushandle(sc->res[0]);
178
179 if ((node = ofw_bus_get_node(sc->dev)) == -1)
180 return (ENXIO);
181
182 fic = malloc(sizeof(*fic), M_DEVBUF, M_WAITOK|M_ZERO);
183 fic->iph = node;
184 fic->dev = dev;
185 SLIST_INSERT_HEAD(&fdt_ic_list_head, fic, fdt_ics);
186
187 return (0);
188 }
189
190 static device_method_t pio_methods[] = {
191 DEVMETHOD(device_probe, pio_probe),
192 DEVMETHOD(device_attach, pio_attach),
193
194 /* pio_if.m */
195 DEVMETHOD(pio_read, pio_read),
196 DEVMETHOD(pio_configure, pio_configure),
197 DEVMETHOD(pio_set, pio_set),
198 DEVMETHOD(pio_setup_irq, pio_setup_irq),
199 DEVMETHOD(pio_teardown_irq, pio_teardown_irq),
200 DEVMETHOD_END
201 };
202
203 static driver_t pio_driver = {
204 "altera_pio",
205 pio_methods,
206 sizeof(struct pio_softc),
207 };
208
209 DRIVER_MODULE(altera_pio, simplebus, pio_driver, 0, 0);
210