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