]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/nlm/xlp_simplebus.c
Update llvm, clang and lldb to release_38 branch r260756.
[FreeBSD/FreeBSD.git] / sys / mips / nlm / xlp_simplebus.c
1 /*-
2  * Copyright (c) 2015 Broadcom Corporation
3  * (based on sys/dev/fdt/simplebus.c)
4  * Copyright (c) 2013 Nathan Whitehorn
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/module.h>
34 #include <sys/bus.h>
35 #include <sys/conf.h>
36 #include <sys/kernel.h>
37 #include <sys/rman.h>
38
39 #include <vm/vm.h>
40 #include <vm/vm_param.h>
41 #include <vm/pmap.h>
42
43 #include <machine/bus.h>
44 #include <machine/pmap.h>
45 #include <machine/intr_machdep.h>
46
47 #include <mips/nlm/hal/haldefs.h>
48 #include <mips/nlm/interrupt.h>
49 #include <mips/nlm/hal/iomap.h>
50 #include <mips/nlm/hal/mips-extns.h>
51 #include <mips/nlm/hal/pcibus.h>
52 #include <mips/nlm/xlp.h>
53
54 #include <dev/ofw/openfirm.h>
55 #include <dev/ofw/ofw_bus.h>
56 #include <dev/ofw/ofw_bus_subr.h>
57
58 #include <dev/fdt/simplebus.h>
59
60 /* flash memory region for chipselects */
61 #define GBU_MEM_BASE    0x16000000UL
62 #define GBU_MEM_LIMIT   0x17ffffffUL
63
64 /*
65  * Device registers in pci ecfg memory region for devices without regular PCI BARs
66  */
67 #define PCI_ECFG_BASE   XLP_DEFAULT_IO_BASE
68 #define PCI_ECFG_LIMIT  (XLP_DEFAULT_IO_BASE + 0x0fffffff)
69
70 /*
71  * Bus interface.
72  */
73 static int              xlp_simplebus_probe(device_t dev);
74 static struct resource *xlp_simplebus_alloc_resource(device_t, device_t, int,
75     int *, rman_res_t, rman_res_t, rman_res_t, u_int);
76 static int              xlp_simplebus_activate_resource(device_t, device_t, int,
77     int, struct resource *);
78 static int              xlp_simplebus_setup_intr(device_t, device_t,
79     struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **);
80
81 /*
82  * ofw_bus interface
83  */
84 static int              xlp_simplebus_ofw_map_intr(device_t, device_t, phandle_t,
85     int, pcell_t *);
86
87 static devclass_t simplebus_devclass;
88 static device_method_t xlp_simplebus_methods[] = {
89         /* Device interface */
90         DEVMETHOD(device_probe,         xlp_simplebus_probe),
91
92         DEVMETHOD(bus_alloc_resource,   xlp_simplebus_alloc_resource),
93         DEVMETHOD(bus_activate_resource, xlp_simplebus_activate_resource),
94         DEVMETHOD(bus_setup_intr,       xlp_simplebus_setup_intr),
95
96         DEVMETHOD(ofw_bus_map_intr,     xlp_simplebus_ofw_map_intr),
97         DEVMETHOD_END
98 };
99
100 DEFINE_CLASS_1(simplebus, xlp_simplebus_driver, xlp_simplebus_methods,
101     sizeof(struct simplebus_softc), simplebus_driver);
102 DRIVER_MODULE(xlp_simplebus, ofwbus, xlp_simplebus_driver, simplebus_devclass,
103     0, 0);
104
105 static struct rman irq_rman, port_rman, mem_rman, pci_ecfg_rman, gbu_rman;
106
107 static void
108 xlp_simplebus_init_resources(void)
109 {
110         irq_rman.rm_start = 0;
111         irq_rman.rm_end = 255;
112         irq_rman.rm_type = RMAN_ARRAY;
113         irq_rman.rm_descr = "PCI Mapped Interrupts";
114         if (rman_init(&irq_rman)
115             || rman_manage_region(&irq_rman, 0, 255))
116                 panic("xlp_simplebus_init_resources irq_rman");
117
118         port_rman.rm_start = 0;
119         port_rman.rm_end = ~0ul;
120         port_rman.rm_type = RMAN_ARRAY;
121         port_rman.rm_descr = "I/O ports";
122         if (rman_init(&port_rman)
123             || rman_manage_region(&port_rman, PCIE_IO_BASE, PCIE_IO_LIMIT))
124                 panic("xlp_simplebus_init_resources port_rman");
125
126         mem_rman.rm_start = 0;
127         mem_rman.rm_end = ~0ul;
128         mem_rman.rm_type = RMAN_ARRAY;
129         mem_rman.rm_descr = "I/O memory";
130         if (rman_init(&mem_rman)
131             || rman_manage_region(&mem_rman, PCIE_MEM_BASE, PCIE_MEM_LIMIT))
132                 panic("xlp_simplebus_init_resources mem_rman");
133
134         pci_ecfg_rman.rm_start = 0;
135         pci_ecfg_rman.rm_end = ~0ul;
136         pci_ecfg_rman.rm_type = RMAN_ARRAY;
137         pci_ecfg_rman.rm_descr = "PCI ECFG IO";
138         if (rman_init(&pci_ecfg_rman) || rman_manage_region(&pci_ecfg_rman,
139             PCI_ECFG_BASE, PCI_ECFG_LIMIT))
140                 panic("xlp_simplebus_init_resources pci_ecfg_rman");
141
142         gbu_rman.rm_start = 0;
143         gbu_rman.rm_end = ~0ul;
144         gbu_rman.rm_type = RMAN_ARRAY;
145         gbu_rman.rm_descr = "Flash region";
146         if (rman_init(&gbu_rman)
147             || rman_manage_region(&gbu_rman, GBU_MEM_BASE, GBU_MEM_LIMIT))
148                 panic("xlp_simplebus_init_resources gbu_rman");
149 }
150
151 static int
152 xlp_simplebus_probe(device_t dev)
153 {
154
155         if (!ofw_bus_status_okay(dev))
156                 return (ENXIO);
157
158         /*
159          * FDT data puts a "simple-bus" compatible string on many things that
160          * have children but aren't really busses in our world.  Without a
161          * ranges property we will fail to attach, so just fail to probe too.
162          */
163         if (!(ofw_bus_is_compatible(dev, "simple-bus") &&
164             ofw_bus_has_prop(dev, "ranges")) &&
165             (ofw_bus_get_type(dev) == NULL || strcmp(ofw_bus_get_type(dev),
166              "soc") != 0))
167                 return (ENXIO);
168
169         xlp_simplebus_init_resources();
170         device_set_desc(dev, "XLP SoC bus");
171
172         return (BUS_PROBE_SPECIFIC);
173 }
174
175 static struct resource *
176 xlp_simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
177     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
178 {
179         struct rman                     *rm;
180         struct resource                 *rv;
181         struct resource_list_entry      *rle;
182         struct simplebus_softc          *sc;
183         struct simplebus_devinfo        *di;
184         bus_space_tag_t                 bustag;
185         int j, isdefault, passthrough, needsactivate;
186
187         passthrough = (device_get_parent(child) != bus);
188         needsactivate = flags & RF_ACTIVE;
189         sc = device_get_softc(bus);
190         di = device_get_ivars(child);
191         rle = NULL;
192         bustag = NULL;
193
194         if (!passthrough) {
195                 isdefault = (start == 0UL && end == ~0UL);
196                 if (isdefault) {
197                         rle = resource_list_find(&di->rl, type, *rid);
198                         if (rle == NULL)
199                                 return (NULL);
200                         if (rle->res != NULL)
201                                 panic("%s: resource entry is busy", __func__);
202                         start = rle->start;
203                         count = ulmax(count, rle->count);
204                         end = ulmax(rle->end, start + count - 1);
205                 }
206                 if (type == SYS_RES_MEMORY) {
207                         /* Remap through ranges property */
208                         for (j = 0; j < sc->nranges; j++) {
209                                 if (start >= sc->ranges[j].bus && end <
210                                     sc->ranges[j].bus + sc->ranges[j].size) {
211                                         start -= sc->ranges[j].bus;
212                                         start += sc->ranges[j].host;
213                                         end -= sc->ranges[j].bus;
214                                         end += sc->ranges[j].host;
215                                         break;
216                                 }
217                         }
218                         if (j == sc->nranges && sc->nranges != 0) {
219                                 if (bootverbose)
220                                         device_printf(bus, "Could not map resource "
221                                             "%#lx-%#lx\n", start, end);
222                                 return (NULL);
223                         }
224                 }
225         }
226         switch (type) {
227         case SYS_RES_IRQ:
228                 rm = &irq_rman;
229                 break;
230         case SYS_RES_IOPORT:
231                 rm = &port_rman;
232                 bustag = rmi_bus_space;
233                 break;
234         case SYS_RES_MEMORY:
235                 if (start >= GBU_MEM_BASE && end <= GBU_MEM_LIMIT) {
236                         rm = &gbu_rman;
237                         bustag = rmi_bus_space;
238                 } else if (start >= PCI_ECFG_BASE && end <= PCI_ECFG_LIMIT) {
239                         rm = &pci_ecfg_rman;
240                         bustag = rmi_uart_bus_space;
241                 } else if (start >= PCIE_MEM_BASE && end <= PCIE_MEM_LIMIT) {
242                         rm = &mem_rman;
243                         bustag = rmi_bus_space;
244                 } else {
245                         if (bootverbose)
246                                 device_printf(bus, "Invalid MEM range"
247                                             "%#lx-%#lx\n", start, end);
248                         return (NULL);
249                 }
250                 break;
251         default:
252                 return (NULL);
253         }
254
255         rv = rman_reserve_resource(rm, start, end, count, flags, child);
256         if (rv == 0) {
257                 device_printf(bus, "%s: could not reserve resource for %s\n",
258                     __func__, device_get_nameunit(child));
259                 return (NULL);
260         }
261
262         rman_set_rid(rv, *rid);
263         if (bustag != NULL)
264                 rman_set_bustag(rv, bustag);
265
266         if (needsactivate) {
267                 if (bus_activate_resource(child, type, *rid, rv)) {
268                         device_printf(bus, "%s: could not activate resource\n",
269                             __func__);
270                         rman_release_resource(rv);
271                         return (NULL);
272                 }
273         }
274
275         return (rv);
276 }
277
278 static int
279 xlp_simplebus_activate_resource(device_t bus, device_t child, int type, int rid,
280     struct resource *r)
281 {
282         void *vaddr;
283         vm_paddr_t paddr;
284         vm_size_t psize;
285
286         /*
287          * If this is a memory resource, use pmap_mapdev to map it.
288          */
289         if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
290                 paddr = rman_get_start(r);
291                 psize = rman_get_size(r);
292                 vaddr = pmap_mapdev(paddr, psize);
293
294                 rman_set_virtual(r, vaddr);
295                 rman_set_bushandle(r, (bus_space_handle_t)(uintptr_t)vaddr);
296         }
297
298         return (rman_activate_resource(r));
299 }
300
301 static int
302 xlp_simplebus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
303     driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
304 {
305         register_t s;
306         int irq;
307
308         /* setup irq */
309         s = intr_disable();
310         irq = rman_get_start(res);
311         cpu_establish_hardintr(device_get_nameunit(child), filt, intr, arg,
312             irq, flags, cookiep);
313         intr_restore(s);
314         return (0);
315 }
316
317 static int
318 xlp_simplebus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
319     pcell_t *irq)
320 {
321
322         return ((int)irq[0]);
323 }