xref: /f-stack/freebsd/mips/nlm/xlp_simplebus.c (revision a9643ea8)
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/intr_machdep.h>
45 
46 #include <mips/nlm/hal/haldefs.h>
47 #include <mips/nlm/interrupt.h>
48 #include <mips/nlm/hal/iomap.h>
49 #include <mips/nlm/hal/mips-extns.h>
50 #include <mips/nlm/hal/pcibus.h>
51 #include <mips/nlm/xlp.h>
52 
53 #include <dev/ofw/openfirm.h>
54 #include <dev/ofw/ofw_bus.h>
55 #include <dev/ofw/ofw_bus_subr.h>
56 
57 #include <dev/fdt/simplebus.h>
58 
59 /* flash memory region for chipselects */
60 #define	GBU_MEM_BASE	0x16000000UL
61 #define	GBU_MEM_LIMIT	0x17ffffffUL
62 
63 /*
64  * Device registers in pci ecfg memory region for devices without regular PCI BARs
65  */
66 #define	PCI_ECFG_BASE	XLP_DEFAULT_IO_BASE
67 #define	PCI_ECFG_LIMIT	(XLP_DEFAULT_IO_BASE + 0x0fffffff)
68 
69 /*
70  * Bus interface.
71  */
72 static int		xlp_simplebus_probe(device_t dev);
73 static struct resource *xlp_simplebus_alloc_resource(device_t, device_t, int,
74     int *, rman_res_t, rman_res_t, rman_res_t, u_int);
75 static int		xlp_simplebus_activate_resource(device_t, device_t, int,
76     int, struct resource *);
77 static int		xlp_simplebus_setup_intr(device_t, device_t,
78     struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **);
79 
80 /*
81  * ofw_bus interface
82  */
83 static int		xlp_simplebus_ofw_map_intr(device_t, device_t, phandle_t,
84     int, pcell_t *);
85 
86 static devclass_t simplebus_devclass;
87 static device_method_t xlp_simplebus_methods[] = {
88 	/* Device interface */
89 	DEVMETHOD(device_probe,		xlp_simplebus_probe),
90 
91 	DEVMETHOD(bus_alloc_resource,	xlp_simplebus_alloc_resource),
92 	DEVMETHOD(bus_activate_resource, xlp_simplebus_activate_resource),
93 	DEVMETHOD(bus_setup_intr,	xlp_simplebus_setup_intr),
94 
95 	DEVMETHOD(ofw_bus_map_intr,	xlp_simplebus_ofw_map_intr),
96 	DEVMETHOD_END
97 };
98 
99 DEFINE_CLASS_1(simplebus, xlp_simplebus_driver, xlp_simplebus_methods,
100     sizeof(struct simplebus_softc), simplebus_driver);
101 DRIVER_MODULE(xlp_simplebus, ofwbus, xlp_simplebus_driver, simplebus_devclass,
102     0, 0);
103 
104 static struct rman irq_rman, port_rman, mem_rman, pci_ecfg_rman, gbu_rman;
105 
106 static void
xlp_simplebus_init_resources(void)107 xlp_simplebus_init_resources(void)
108 {
109 	irq_rman.rm_start = 0;
110 	irq_rman.rm_end = 255;
111 	irq_rman.rm_type = RMAN_ARRAY;
112 	irq_rman.rm_descr = "PCI Mapped Interrupts";
113 	if (rman_init(&irq_rman)
114 	    || rman_manage_region(&irq_rman, 0, 255))
115 		panic("xlp_simplebus_init_resources irq_rman");
116 
117 	port_rman.rm_type = RMAN_ARRAY;
118 	port_rman.rm_descr = "I/O ports";
119 	if (rman_init(&port_rman)
120 	    || rman_manage_region(&port_rman, PCIE_IO_BASE, PCIE_IO_LIMIT))
121 		panic("xlp_simplebus_init_resources port_rman");
122 
123 	mem_rman.rm_type = RMAN_ARRAY;
124 	mem_rman.rm_descr = "I/O memory";
125 	if (rman_init(&mem_rman)
126 	    || rman_manage_region(&mem_rman, PCIE_MEM_BASE, PCIE_MEM_LIMIT))
127 		panic("xlp_simplebus_init_resources mem_rman");
128 
129 	pci_ecfg_rman.rm_type = RMAN_ARRAY;
130 	pci_ecfg_rman.rm_descr = "PCI ECFG IO";
131 	if (rman_init(&pci_ecfg_rman) || rman_manage_region(&pci_ecfg_rman,
132 	    PCI_ECFG_BASE, PCI_ECFG_LIMIT))
133 		panic("xlp_simplebus_init_resources pci_ecfg_rman");
134 
135 	gbu_rman.rm_type = RMAN_ARRAY;
136 	gbu_rman.rm_descr = "Flash region";
137 	if (rman_init(&gbu_rman)
138 	    || rman_manage_region(&gbu_rman, GBU_MEM_BASE, GBU_MEM_LIMIT))
139 		panic("xlp_simplebus_init_resources gbu_rman");
140 }
141 
142 static int
xlp_simplebus_probe(device_t dev)143 xlp_simplebus_probe(device_t dev)
144 {
145 
146 	if (!ofw_bus_status_okay(dev))
147 		return (ENXIO);
148 
149 	/*
150 	 * FDT data puts a "simple-bus" compatible string on many things that
151 	 * have children but aren't really busses in our world.  Without a
152 	 * ranges property we will fail to attach, so just fail to probe too.
153 	 */
154 	if (!(ofw_bus_is_compatible(dev, "simple-bus") &&
155 	    ofw_bus_has_prop(dev, "ranges")) &&
156 	    (ofw_bus_get_type(dev) == NULL || strcmp(ofw_bus_get_type(dev),
157 	     "soc") != 0))
158 		return (ENXIO);
159 
160 	xlp_simplebus_init_resources();
161 	device_set_desc(dev, "XLP SoC bus");
162 
163 	return (BUS_PROBE_SPECIFIC);
164 }
165 
166 static struct resource *
xlp_simplebus_alloc_resource(device_t bus,device_t child,int type,int * rid,rman_res_t start,rman_res_t end,rman_res_t count,u_int flags)167 xlp_simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
168     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
169 {
170 	struct rman			*rm;
171 	struct resource			*rv;
172 	struct resource_list_entry	*rle;
173 	struct simplebus_softc		*sc;
174 	struct simplebus_devinfo	*di;
175 	bus_space_tag_t			bustag;
176 	int j, isdefault, passthrough, needsactivate;
177 
178 	passthrough = (device_get_parent(child) != bus);
179 	needsactivate = flags & RF_ACTIVE;
180 	sc = device_get_softc(bus);
181         di = device_get_ivars(child);
182 	rle = NULL;
183 	bustag = NULL;
184 
185 	if (!passthrough) {
186 		isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
187 		if (isdefault) {
188 			rle = resource_list_find(&di->rl, type, *rid);
189 			if (rle == NULL)
190 				return (NULL);
191 			if (rle->res != NULL)
192 				panic("%s: resource entry is busy", __func__);
193 			start = rle->start;
194 			count = ulmax(count, rle->count);
195 			end = ulmax(rle->end, start + count - 1);
196 		}
197 		if (type == SYS_RES_MEMORY) {
198 			/* Remap through ranges property */
199 			for (j = 0; j < sc->nranges; j++) {
200 				if (start >= sc->ranges[j].bus && end <
201 				    sc->ranges[j].bus + sc->ranges[j].size) {
202 					start -= sc->ranges[j].bus;
203 					start += sc->ranges[j].host;
204 					end -= sc->ranges[j].bus;
205 					end += sc->ranges[j].host;
206 					break;
207 				}
208 			}
209 			if (j == sc->nranges && sc->nranges != 0) {
210 				if (bootverbose)
211 					device_printf(bus, "Could not map resource "
212 					    "%#jx-%#jx\n", start, end);
213 				return (NULL);
214 			}
215 		}
216 	}
217 	switch (type) {
218 	case SYS_RES_IRQ:
219 		rm = &irq_rman;
220 		break;
221 	case SYS_RES_IOPORT:
222 		rm = &port_rman;
223 		bustag = rmi_bus_space;
224 		break;
225 	case SYS_RES_MEMORY:
226 		if (start >= GBU_MEM_BASE && end <= GBU_MEM_LIMIT) {
227 			rm = &gbu_rman;
228 			bustag = rmi_bus_space;
229 		} else if (start >= PCI_ECFG_BASE && end <= PCI_ECFG_LIMIT) {
230 			rm = &pci_ecfg_rman;
231 			bustag = rmi_uart_bus_space;
232 		} else if (start >= PCIE_MEM_BASE && end <= PCIE_MEM_LIMIT) {
233 			rm = &mem_rman;
234 			bustag = rmi_bus_space;
235 		} else {
236 			if (bootverbose)
237 				device_printf(bus, "Invalid MEM range"
238 					    "%#jx-%#jx\n", start, end);
239 			return (NULL);
240 		}
241 		break;
242 	default:
243 		return (NULL);
244 	}
245 
246 	rv = rman_reserve_resource(rm, start, end, count, flags, child);
247 	if (rv == NULL) {
248 		device_printf(bus, "%s: could not reserve resource for %s\n",
249 		    __func__, device_get_nameunit(child));
250 		return (NULL);
251 	}
252 
253 	rman_set_rid(rv, *rid);
254 	if (bustag != NULL)
255 		rman_set_bustag(rv, bustag);
256 
257 	if (needsactivate) {
258 		if (bus_activate_resource(child, type, *rid, rv)) {
259 			device_printf(bus, "%s: could not activate resource\n",
260 			    __func__);
261 			rman_release_resource(rv);
262 			return (NULL);
263 		}
264 	}
265 
266 	return (rv);
267 }
268 
269 static int
xlp_simplebus_activate_resource(device_t bus,device_t child,int type,int rid,struct resource * r)270 xlp_simplebus_activate_resource(device_t bus, device_t child, int type, int rid,
271     struct resource *r)
272 {
273 	void *vaddr;
274 	vm_paddr_t paddr;
275 	vm_size_t psize;
276 
277 	/*
278 	 * If this is a memory resource, use pmap_mapdev to map it.
279 	 */
280 	if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
281 		paddr = rman_get_start(r);
282 		psize = rman_get_size(r);
283 		vaddr = pmap_mapdev(paddr, psize);
284 
285 		rman_set_virtual(r, vaddr);
286 		rman_set_bushandle(r, (bus_space_handle_t)(uintptr_t)vaddr);
287 	}
288 
289 	return (rman_activate_resource(r));
290 }
291 
292 static int
xlp_simplebus_setup_intr(device_t dev,device_t child,struct resource * res,int flags,driver_filter_t * filt,driver_intr_t * intr,void * arg,void ** cookiep)293 xlp_simplebus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
294     driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
295 {
296 	register_t s;
297 	int irq;
298 
299 	/* setup irq */
300 	s = intr_disable();
301 	irq = rman_get_start(res);
302 	cpu_establish_hardintr(device_get_nameunit(child), filt, intr, arg,
303 	    irq, flags, cookiep);
304 	intr_restore(s);
305 	return (0);
306 }
307 
308 static int
xlp_simplebus_ofw_map_intr(device_t dev,device_t child,phandle_t iparent,int icells,pcell_t * irq)309 xlp_simplebus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
310     pcell_t *irq)
311 {
312 
313 	return ((int)irq[0]);
314 }
315