xref: /freebsd/sys/arm/mv/mv_pci_ctrl.c (revision e2340276fc734a1f0bd0d2cf16fcfba7936c9462)
1 /*-
2  * Copyright (c) 2016 Stormshield
3  * Copyright (c) 2016 Semihalf
4  * All rights reserved.
5  *
6  * Developed by Semihalf.
7  *
8  * Portions of this software were developed by Semihalf
9  * under sponsorship from the FreeBSD Foundation.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of MARVELL nor the names of contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 /*
37  * Marvell integrated PCI/PCI-Express Bus Controller Driver.
38  */
39 
40 #include <sys/cdefs.h>
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/module.h>
47 #include <sys/bus.h>
48 #include <sys/rman.h>
49 
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
52 
53 static int mv_pcib_ctrl_probe(device_t);
54 static int mv_pcib_ctrl_attach(device_t);
55 static device_t mv_pcib_ctrl_add_child(device_t, u_int, const char *, int);
56 static const struct ofw_bus_devinfo * mv_pcib_ctrl_get_devinfo(device_t, device_t);
57 static struct resource * mv_pcib_ctrl_alloc_resource(device_t, device_t, int,
58     int *, rman_res_t, rman_res_t, rman_res_t, u_int);
59 void mv_pcib_ctrl_init(device_t, phandle_t);
60 static int mv_pcib_ofw_bus_attach(device_t);
61 
62 struct mv_pcib_ctrl_range {
63 	uint64_t bus;
64 	uint64_t host;
65 	uint64_t size;
66 };
67 
68 typedef int (*get_rl_t)(device_t dev, phandle_t node, pcell_t acells,
69     pcell_t scells, struct resource_list *rl);
70 
71 struct mv_pcib_ctrl_softc {
72 	pcell_t				addr_cells;
73 	pcell_t				size_cells;
74 	int				nranges;
75 	struct mv_pcib_ctrl_range	*ranges;
76 };
77 
78 struct mv_pcib_ctrl_devinfo {
79 	struct ofw_bus_devinfo	di_dinfo;
80 	struct resource_list	di_rl;
81 };
82 
83 static int mv_pcib_ctrl_fill_ranges(phandle_t, struct mv_pcib_ctrl_softc *);
84 
85 /*
86  * Bus interface definitions
87  */
88 static device_method_t mv_pcib_ctrl_methods[] = {
89 	/* Device interface */
90 	DEVMETHOD(device_probe,			mv_pcib_ctrl_probe),
91 	DEVMETHOD(device_attach,		mv_pcib_ctrl_attach),
92 
93 	/* Bus interface */
94 	DEVMETHOD(bus_add_child,		mv_pcib_ctrl_add_child),
95 	DEVMETHOD(bus_alloc_resource,		mv_pcib_ctrl_alloc_resource),
96 	DEVMETHOD(bus_release_resource,		bus_generic_release_resource),
97 	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
98 	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
99 	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
100 
101 	/* ofw_bus interface */
102 	DEVMETHOD(ofw_bus_get_devinfo,		mv_pcib_ctrl_get_devinfo),
103 	DEVMETHOD(ofw_bus_get_compat,		ofw_bus_gen_get_compat),
104 	DEVMETHOD(ofw_bus_get_model,		ofw_bus_gen_get_model),
105 	DEVMETHOD(ofw_bus_get_name,		ofw_bus_gen_get_name),
106 	DEVMETHOD(ofw_bus_get_node,		ofw_bus_gen_get_node),
107 	DEVMETHOD(ofw_bus_get_type,		ofw_bus_gen_get_type),
108 
109 	DEVMETHOD_END
110 };
111 
112 static struct ofw_compat_data mv_pcib_ctrl_compat[] = {
113 	{"mrvl,pcie-ctrl",		(uintptr_t)&ofw_bus_reg_to_rl},
114 	{"marvell,armada-370-pcie",
115 	    (uintptr_t)&ofw_bus_assigned_addresses_to_rl},
116 	{NULL,				(uintptr_t)NULL},
117 };
118 
119 static driver_t mv_pcib_ctrl_driver = {
120 	"pcib_ctrl",
121 	mv_pcib_ctrl_methods,
122 	sizeof(struct mv_pcib_ctrl_softc),
123 };
124 
125 DRIVER_MODULE(pcib_ctrl, simplebus, mv_pcib_ctrl_driver, 0, 0);
126 
127 MALLOC_DEFINE(M_PCIB_CTRL, "PCIe Bus Controller",
128     "Marvell Integrated PCIe Bus Controller");
129 
130 static int
131 mv_pcib_ctrl_probe(device_t dev)
132 {
133 
134 	if (!ofw_bus_status_okay(dev))
135 		return (ENXIO);
136 
137 	if (!ofw_bus_search_compatible(dev, mv_pcib_ctrl_compat)->ocd_data)
138 		return (ENXIO);
139 
140 	device_set_desc(dev, "Marvell Integrated PCIe Bus Controller");
141 	return (BUS_PROBE_DEFAULT);
142 }
143 
144 static int
145 mv_pcib_ctrl_attach(device_t dev)
146 {
147 	int err;
148 
149 	err = mv_pcib_ofw_bus_attach(dev);
150 	if (err != 0)
151 		return (err);
152 
153 	return (bus_generic_attach(dev));
154 }
155 
156 static int
157 mv_pcib_ofw_bus_attach(device_t dev)
158 {
159 	struct mv_pcib_ctrl_devinfo *di;
160 	struct mv_pcib_ctrl_softc *sc;
161 	device_t child;
162 	phandle_t parent, node;
163 	get_rl_t get_rl;
164 
165 	parent = ofw_bus_get_node(dev);
166 	sc = device_get_softc(dev);
167 	if (parent > 0) {
168 		sc->addr_cells = 1;
169 		if (OF_getencprop(parent, "#address-cells", &(sc->addr_cells),
170 		    sizeof(sc->addr_cells)) <= 0)
171 			return(ENXIO);
172 
173 		sc->size_cells = 1;
174 		if (OF_getencprop(parent, "#size-cells", &(sc->size_cells),
175 		    sizeof(sc->size_cells)) <= 0)
176 			return(ENXIO);
177 
178 		for (node = OF_child(parent); node > 0; node = OF_peer(node)) {
179 			di = malloc(sizeof(*di), M_PCIB_CTRL, M_WAITOK | M_ZERO);
180 			if (ofw_bus_gen_setup_devinfo(&di->di_dinfo, node)) {
181 				if (bootverbose) {
182 					device_printf(dev,
183 					    "Could not set up devinfo for PCI\n");
184 				}
185 				free(di, M_PCIB_CTRL);
186 				continue;
187 			}
188 
189 			child = device_add_child(dev, NULL, -1);
190 			if (child == NULL) {
191 				if (bootverbose) {
192 					device_printf(dev,
193 					    "Could not add child: %s\n",
194 					    di->di_dinfo.obd_name);
195 				}
196 				ofw_bus_gen_destroy_devinfo(&di->di_dinfo);
197 				free(di, M_PCIB_CTRL);
198 				continue;
199 			}
200 
201 			resource_list_init(&di->di_rl);
202 			get_rl = (get_rl_t) ofw_bus_search_compatible(dev,
203 			    mv_pcib_ctrl_compat)->ocd_data;
204 			if (get_rl != NULL)
205 				get_rl(child, node, sc->addr_cells,
206 				    sc->size_cells, &di->di_rl);
207 
208 			device_set_ivars(child, di);
209 		}
210 	}
211 
212 	if (mv_pcib_ctrl_fill_ranges(parent, sc) < 0) {
213 		device_printf(dev, "could not get ranges\n");
214 		return (ENXIO);
215 	}
216 
217 	return (0);
218 }
219 
220 static device_t
221 mv_pcib_ctrl_add_child(device_t dev, u_int order, const char *name, int unit)
222 {
223 	device_t cdev;
224 	struct mv_pcib_ctrl_devinfo *di;
225 
226 	cdev = device_add_child_ordered(dev, order, name, unit);
227 	if (cdev == NULL)
228 		return (NULL);
229 
230 	di = malloc(sizeof(*di), M_DEVBUF, M_WAITOK | M_ZERO);
231 	di->di_dinfo.obd_node = -1;
232 	resource_list_init(&di->di_rl);
233 	device_set_ivars(cdev, di);
234 
235 	return (cdev);
236 }
237 
238 static struct resource *
239 mv_pcib_ctrl_alloc_resource(device_t bus, device_t child, int type, int *rid,
240     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
241 {
242 	struct mv_pcib_ctrl_devinfo *di;
243 	struct resource_list_entry *rle;
244 	struct mv_pcib_ctrl_softc *sc;
245 	int i;
246 
247 	if (RMAN_IS_DEFAULT_RANGE(start, end)) {
248 		if ((di = device_get_ivars(child)) == NULL)
249 			return (NULL);
250 		if (type != SYS_RES_MEMORY)
251 			return (NULL);
252 
253 		/* Find defaults for this rid */
254 		rle = resource_list_find(&di->di_rl, type, *rid);
255 
256 		if (rle == NULL)
257 			return (NULL);
258 
259 		start = rle->start;
260 		end = rle->end;
261 		count = rle->count;
262 	}
263 
264 	sc = device_get_softc(bus);
265 	if (type == SYS_RES_MEMORY) {
266 		/* Remap through ranges property */
267 		for (i = 0; i < sc->nranges; i++) {
268 			if (start >= sc->ranges[i].bus && end <
269 			    sc->ranges[i].bus + sc->ranges[i].size) {
270 				start -= sc->ranges[i].bus;
271 				start += sc->ranges[i].host;
272 				end -= sc->ranges[i].bus;
273 				end += sc->ranges[i].host;
274 				break;
275 			}
276 		}
277 
278 		if (i == sc->nranges && sc->nranges != 0) {
279 			device_printf(bus, "Could not map resource "
280 			    "%#llx-%#llx\n", start, end);
281 			return (NULL);
282 		}
283 	}
284 
285 	return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
286 	    count, flags));
287 }
288 
289 static int
290 mv_pcib_ctrl_fill_ranges(phandle_t node, struct mv_pcib_ctrl_softc *sc)
291 {
292 	int host_address_cells;
293 	cell_t *base_ranges;
294 	ssize_t nbase_ranges;
295 	int err;
296 	int i, j, k;
297 
298 	err = OF_searchencprop(OF_parent(node), "#address-cells",
299 	    &host_address_cells, sizeof(host_address_cells));
300 	if (err <= 0)
301 		return (-1);
302 
303 	nbase_ranges = OF_getproplen(node, "ranges");
304 	if (nbase_ranges < 0)
305 		return (-1);
306 	sc->nranges = nbase_ranges / sizeof(cell_t) /
307 	    (sc->addr_cells + host_address_cells + sc->size_cells);
308 	if (sc->nranges == 0)
309 		return (0);
310 
311 	sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]),
312 	    M_DEVBUF, M_WAITOK);
313 	base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
314 	OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
315 
316 	for (i = 0, j = 0; i < sc->nranges; i++) {
317 		sc->ranges[i].bus = 0;
318 		for (k = 0; k < sc->addr_cells; k++) {
319 			sc->ranges[i].bus <<= 32;
320 			sc->ranges[i].bus |= base_ranges[j++];
321 		}
322 		sc->ranges[i].host = 0;
323 		for (k = 0; k < host_address_cells; k++) {
324 			sc->ranges[i].host <<= 32;
325 			sc->ranges[i].host |= base_ranges[j++];
326 		}
327 		sc->ranges[i].size = 0;
328 		for (k = 0; k < sc->size_cells; k++) {
329 			sc->ranges[i].size <<= 32;
330 			sc->ranges[i].size |= base_ranges[j++];
331 		}
332 	}
333 
334 	free(base_ranges, M_DEVBUF);
335 	return (sc->nranges);
336 }
337 
338 static const struct ofw_bus_devinfo *
339 mv_pcib_ctrl_get_devinfo(device_t bus __unused, device_t child)
340 {
341 	struct mv_pcib_ctrl_devinfo *di;
342 
343 	di = device_get_ivars(child);
344 	return (&di->di_dinfo);
345 }
346