1282867Szbb/*-
2282867Szbb * Copyright (c) 2015 The FreeBSD Foundation
3282867Szbb * All rights reserved.
4282867Szbb *
5282867Szbb * This software was developed by Semihalf under
6282867Szbb * the sponsorship of the FreeBSD Foundation.
7282867Szbb *
8282867Szbb * Redistribution and use in source and binary forms, with or without
9282867Szbb * modification, are permitted provided that the following conditions
10282867Szbb * are met:
11282867Szbb * 1. Redistributions of source code must retain the above copyright
12282867Szbb *    notice, this list of conditions and the following disclaimer.
13282867Szbb * 2. Redistributions in binary form must reproduce the above copyright
14282867Szbb *    notice, this list of conditions and the following disclaimer in the
15282867Szbb *    documentation and/or other materials provided with the distribution.
16282867Szbb *
17282867Szbb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18282867Szbb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19282867Szbb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20282867Szbb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21282867Szbb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22282867Szbb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23282867Szbb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24282867Szbb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25282867Szbb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26282867Szbb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27282867Szbb * SUCH DAMAGE.
28282867Szbb */
29282867Szbb
30282867Szbb#include <sys/cdefs.h>
31282867Szbb__FBSDID("$FreeBSD$");
32282867Szbb
33282867Szbb#include <sys/param.h>
34294572Sandrew#include <sys/systm.h>
35299124Szbb#include <sys/bitstring.h>
36282867Szbb#include <sys/bus.h>
37282867Szbb#include <sys/kernel.h>
38282867Szbb#include <sys/module.h>
39295832Sjhibbits#include <sys/rman.h>
40282867Szbb
41299944Sandrew#include <machine/intr.h>
42285213Szbb#include <machine/resource.h>
43285213Szbb
44282867Szbb#include <dev/ofw/openfirm.h>
45282867Szbb#include <dev/ofw/ofw_bus.h>
46282867Szbb#include <dev/ofw/ofw_bus_subr.h>
47282867Szbb
48282867Szbb#include "gic_v3_reg.h"
49282867Szbb#include "gic_v3_var.h"
50282867Szbb
51282867Szbb/*
52282867Szbb * FDT glue.
53282867Szbb */
54282867Szbbstatic int gic_v3_fdt_probe(device_t);
55282867Szbbstatic int gic_v3_fdt_attach(device_t);
56305529Sandrewstatic int gic_v3_fdt_print_child(device_t, device_t);
57282867Szbb
58285213Szbbstatic struct resource *gic_v3_ofw_bus_alloc_res(device_t, device_t, int, int *,
59294883Sjhibbits    rman_res_t, rman_res_t, rman_res_t, u_int);
60285213Szbbstatic const struct ofw_bus_devinfo *gic_v3_ofw_get_devinfo(device_t, device_t);
61285213Szbb
62282867Szbbstatic device_method_t gic_v3_fdt_methods[] = {
63282867Szbb	/* Device interface */
64282867Szbb	DEVMETHOD(device_probe,		gic_v3_fdt_probe),
65282867Szbb	DEVMETHOD(device_attach,	gic_v3_fdt_attach),
66282867Szbb
67285213Szbb	/* Bus interface */
68305529Sandrew	DEVMETHOD(bus_print_child,		gic_v3_fdt_print_child),
69285213Szbb	DEVMETHOD(bus_alloc_resource,		gic_v3_ofw_bus_alloc_res),
70285213Szbb	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
71285213Szbb
72285213Szbb	/* ofw_bus interface */
73285213Szbb	DEVMETHOD(ofw_bus_get_devinfo,	gic_v3_ofw_get_devinfo),
74285213Szbb	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
75285213Szbb	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
76285213Szbb	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
77285213Szbb	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
78285213Szbb	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
79285213Szbb
80282867Szbb	/* End */
81282867Szbb	DEVMETHOD_END
82282867Szbb};
83282867Szbb
84294731SzbbDEFINE_CLASS_1(gic, gic_v3_fdt_driver, gic_v3_fdt_methods,
85282867Szbb    sizeof(struct gic_v3_softc), gic_v3_driver);
86282867Szbb
87282867Szbbstatic devclass_t gic_v3_fdt_devclass;
88282867Szbb
89282867SzbbEARLY_DRIVER_MODULE(gic_v3, simplebus, gic_v3_fdt_driver, gic_v3_fdt_devclass,
90282867Szbb    0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
91282867SzbbEARLY_DRIVER_MODULE(gic_v3, ofwbus, gic_v3_fdt_driver, gic_v3_fdt_devclass,
92282867Szbb    0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
93282867Szbb
94282867Szbb/*
95285213Szbb * Helper functions declarations.
96285213Szbb */
97285213Szbbstatic int gic_v3_ofw_bus_attach(device_t);
98285213Szbb
99285213Szbb/*
100282867Szbb * Device interface.
101282867Szbb */
102282867Szbbstatic int
103282867Szbbgic_v3_fdt_probe(device_t dev)
104282867Szbb{
105282867Szbb
106282867Szbb	if (!ofw_bus_status_okay(dev))
107282867Szbb		return (ENXIO);
108282867Szbb
109282867Szbb	if (!ofw_bus_is_compatible(dev, "arm,gic-v3"))
110282867Szbb		return (ENXIO);
111282867Szbb
112282867Szbb	device_set_desc(dev, GIC_V3_DEVSTR);
113282867Szbb	return (BUS_PROBE_DEFAULT);
114282867Szbb}
115282867Szbb
116282867Szbbstatic int
117282867Szbbgic_v3_fdt_attach(device_t dev)
118282867Szbb{
119282867Szbb	struct gic_v3_softc *sc;
120282867Szbb	pcell_t redist_regions;
121299944Sandrew	intptr_t xref;
122282867Szbb	int err;
123282867Szbb
124282867Szbb	sc = device_get_softc(dev);
125282867Szbb	sc->dev = dev;
126282867Szbb
127282867Szbb	/*
128282867Szbb	 * Recover number of the Re-Distributor regions.
129282867Szbb	 */
130282867Szbb	if (OF_getencprop(ofw_bus_get_node(dev), "#redistributor-regions",
131282867Szbb	    &redist_regions, sizeof(redist_regions)) <= 0)
132282867Szbb		sc->gic_redists.nregions = 1;
133282867Szbb	else
134282867Szbb		sc->gic_redists.nregions = redist_regions;
135282867Szbb
136282867Szbb	err = gic_v3_attach(dev);
137299944Sandrew	if (err != 0)
138282867Szbb		goto error;
139299944Sandrew
140299944Sandrew	xref = OF_xref_from_node(ofw_bus_get_node(dev));
141301265Sandrew	sc->gic_pic = intr_pic_register(dev, xref);
142301265Sandrew	if (sc->gic_pic == NULL) {
143299944Sandrew		device_printf(dev, "could not register PIC\n");
144301112Szbb		err = ENXIO;
145299944Sandrew		goto error;
146299944Sandrew	}
147299944Sandrew
148299944Sandrew	if (intr_pic_claim_root(dev, xref, arm_gic_v3_intr, sc,
149299944Sandrew	    GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) {
150301112Szbb		err = ENXIO;
151299944Sandrew		goto error;
152299944Sandrew	}
153299944Sandrew
154285213Szbb	/*
155285213Szbb	 * Try to register ITS to this GIC.
156285213Szbb	 * GIC will act as a bus in that case.
157285213Szbb	 * Failure here will not affect main GIC functionality.
158285213Szbb	 */
159285213Szbb	if (gic_v3_ofw_bus_attach(dev) != 0) {
160285213Szbb		if (bootverbose) {
161285213Szbb			device_printf(dev,
162285213Szbb			    "Failed to attach ITS to this GIC\n");
163285213Szbb		}
164285213Szbb	}
165282867Szbb
166301265Sandrew	if (device_get_children(dev, &sc->gic_children, &sc->gic_nchildren) != 0)
167301265Sandrew		sc->gic_nchildren = 0;
168301265Sandrew
169282867Szbb	return (err);
170282867Szbb
171282867Szbberror:
172282867Szbb	if (bootverbose) {
173282867Szbb		device_printf(dev,
174282867Szbb		    "Failed to attach. Error %d\n", err);
175282867Szbb	}
176282867Szbb	/* Failure so free resources */
177282867Szbb	gic_v3_detach(dev);
178282867Szbb
179301112Szbb	return (err);
180282867Szbb}
181285213Szbb
182285213Szbb/* OFW bus interface */
183285213Szbbstruct gic_v3_ofw_devinfo {
184285213Szbb	struct ofw_bus_devinfo	di_dinfo;
185285213Szbb	struct resource_list	di_rl;
186285213Szbb};
187285213Szbb
188305529Sandrewstatic int
189305529Sandrewgic_v3_fdt_print_child(device_t bus, device_t child)
190305529Sandrew{
191305529Sandrew	struct gic_v3_ofw_devinfo *di = device_get_ivars(child);
192305529Sandrew	struct resource_list *rl = &di->di_rl;
193305529Sandrew	int retval = 0;
194305529Sandrew
195305529Sandrew	retval += bus_print_child_header(bus, child);
196305529Sandrew	retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
197305529Sandrew	retval += bus_print_child_footer(bus, child);
198305529Sandrew
199305529Sandrew	return (retval);
200305529Sandrew}
201305529Sandrew
202285213Szbbstatic const struct ofw_bus_devinfo *
203285213Szbbgic_v3_ofw_get_devinfo(device_t bus __unused, device_t child)
204285213Szbb{
205285213Szbb	struct gic_v3_ofw_devinfo *di;
206285213Szbb
207285213Szbb	di = device_get_ivars(child);
208285213Szbb	return (&di->di_dinfo);
209285213Szbb}
210285213Szbb
211285213Szbbstatic struct resource *
212285213Szbbgic_v3_ofw_bus_alloc_res(device_t bus, device_t child, int type, int *rid,
213294883Sjhibbits    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
214285213Szbb{
215285213Szbb	struct gic_v3_ofw_devinfo *di;
216285213Szbb	struct resource_list_entry *rle;
217285213Szbb	int ranges_len;
218285213Szbb
219295832Sjhibbits	if (RMAN_IS_DEFAULT_RANGE(start, end)) {
220285213Szbb		if ((di = device_get_ivars(child)) == NULL)
221285213Szbb			return (NULL);
222285213Szbb		if (type != SYS_RES_MEMORY)
223285213Szbb			return (NULL);
224285213Szbb
225285213Szbb		/* Find defaults for this rid */
226285213Szbb		rle = resource_list_find(&di->di_rl, type, *rid);
227285213Szbb		if (rle == NULL)
228285213Szbb			return (NULL);
229285213Szbb
230285213Szbb		start = rle->start;
231285213Szbb		end = rle->end;
232285213Szbb		count = rle->count;
233285213Szbb	}
234285213Szbb	/*
235285213Szbb	 * XXX: No ranges remap!
236285213Szbb	 *	Absolute address is expected.
237285213Szbb	 */
238285213Szbb	if (ofw_bus_has_prop(bus, "ranges")) {
239285213Szbb		ranges_len = OF_getproplen(ofw_bus_get_node(bus), "ranges");
240285213Szbb		if (ranges_len != 0) {
241285213Szbb			if (bootverbose) {
242285213Szbb				device_printf(child,
243285213Szbb				    "Ranges remap not supported\n");
244285213Szbb			}
245285213Szbb			return (NULL);
246285213Szbb		}
247285213Szbb	}
248285213Szbb	return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
249285213Szbb	    count, flags));
250285213Szbb}
251285213Szbb
252285213Szbb/* Helper functions */
253285213Szbb
254285213Szbb/*
255285213Szbb * Bus capability support for GICv3.
256285213Szbb * Collects and configures device informations and finally
257285213Szbb * adds ITS device as a child of GICv3 in Newbus hierarchy.
258285213Szbb */
259285213Szbbstatic int
260285213Szbbgic_v3_ofw_bus_attach(device_t dev)
261285213Szbb{
262285213Szbb	struct gic_v3_ofw_devinfo *di;
263285213Szbb	device_t child;
264285213Szbb	phandle_t parent, node;
265285213Szbb	pcell_t addr_cells, size_cells;
266285213Szbb
267285213Szbb	parent = ofw_bus_get_node(dev);
268285213Szbb	if (parent > 0) {
269285213Szbb		addr_cells = 2;
270285213Szbb		OF_getencprop(parent, "#address-cells", &addr_cells,
271285213Szbb		    sizeof(addr_cells));
272285213Szbb		size_cells = 2;
273285213Szbb		OF_getencprop(parent, "#size-cells", &size_cells,
274285213Szbb		    sizeof(size_cells));
275285213Szbb		/* Iterate through all GIC subordinates */
276285213Szbb		for (node = OF_child(parent); node > 0; node = OF_peer(node)) {
277285213Szbb			/* Allocate and populate devinfo. */
278285213Szbb			di = malloc(sizeof(*di), M_GIC_V3, M_WAITOK | M_ZERO);
279285213Szbb			if (ofw_bus_gen_setup_devinfo(&di->di_dinfo, node)) {
280285213Szbb				if (bootverbose) {
281285213Szbb					device_printf(dev,
282285213Szbb					    "Could not set up devinfo for ITS\n");
283285213Szbb				}
284285213Szbb				free(di, M_GIC_V3);
285285213Szbb				continue;
286285213Szbb			}
287285213Szbb
288285213Szbb			/* Initialize and populate resource list. */
289285213Szbb			resource_list_init(&di->di_rl);
290285213Szbb			ofw_bus_reg_to_rl(dev, node, addr_cells, size_cells,
291285213Szbb			    &di->di_rl);
292285213Szbb
293285213Szbb			/* Should not have any interrupts, so don't add any */
294285213Szbb
295285213Szbb			/* Add newbus device for this FDT node */
296285213Szbb			child = device_add_child(dev, NULL, -1);
297285213Szbb			if (!child) {
298285213Szbb				if (bootverbose) {
299285213Szbb					device_printf(dev,
300285213Szbb					    "Could not add child: %s\n",
301285213Szbb					    di->di_dinfo.obd_name);
302285213Szbb				}
303285213Szbb				resource_list_free(&di->di_rl);
304285213Szbb				ofw_bus_gen_destroy_devinfo(&di->di_dinfo);
305285213Szbb				free(di, M_GIC_V3);
306285213Szbb				continue;
307285213Szbb			}
308285213Szbb
309285213Szbb			device_set_ivars(child, di);
310285213Szbb		}
311285213Szbb	}
312285213Szbb
313285213Szbb	return (bus_generic_attach(dev));
314285213Szbb}
315