Hi,
based on the other changes this diff is a draft to make ampintc, the
generic interrupt controller code, FDT aware.
It basically only needs to see if the compatible string matches and
then read out two rows of regs/addresses.
Still, it needs to take care of the address- and size-cell sizes, as
the address and size values can be either of size 32-bit or 64-bit.
To make extraction of memory addresses easier I had implemented
fdt_get_memory_address(). As we want to use the OF_* API, would it make
sense to expose and implement that function as OF_* function, or should
I just do it manually like in this diff?
The code will probably be duplicated in every driver. Most only need
one "reg" row though, which shortens the code a bit.
Patrick
diff --git sys/arch/arm/cortex/ampintc.c sys/arch/arm/cortex/ampintc.c
index 774b909..84294c4 100644
--- sys/arch/arm/cortex/ampintc.c
+++ sys/arch/arm/cortex/ampintc.c
@@ -29,6 +29,9 @@
#include <arm/cpufunc.h>
#include <machine/bus.h>
#include <arm/cortex/cortex.h>
+#include <arm/fdt.h>
+
+#include <dev/ofw/openfirm.h>
/* offset from periphbase */
#define ICP_ADDR 0x100
@@ -166,7 +169,10 @@ struct intrq {
int ampintc_match(struct device *, void *, void *);
+int ampintc_match_fdt(struct device *, void *, void *);
void ampintc_attach(struct device *, struct device *, void *);
+void ampintc_attach_cortex(struct device *, struct device *, void
*);
+void ampintc_attach_fdt(struct device *, struct device *, void *);
int ampintc_spllower(int);
void ampintc_splx(int);
int ampintc_splraise(int);
@@ -187,36 +193,63 @@ void ampintc_intr_disable(int);
void ampintc_route(int, int , int);
struct cfattach ampintc_ca = {
- sizeof (struct ampintc_softc), ampintc_match, ampintc_attach
+ sizeof (struct ampintc_softc), ampintc_match, ampintc_attach_cortex
+};
+
+struct cfattach ampintc_fdt_ca = {
+ sizeof (struct ampintc_softc), ampintc_match_fdt, ampintc_attach_fdt
};
struct cfdriver ampintc_cd = {
NULL, "ampintc", DV_DULL
};
+static char *ampintc_compatibles[] = {
+ "arm,gic",
+ "arm,cortex-a7-gic",
+ "arm,cortex-a9-gic",
+ "arm,cortex-a15-gic",
+ NULL
+};
+
int
ampintc_match(struct device *parent, void *cfdata, void *aux)
{
return (1);
}
+int
+ampintc_match_fdt(struct device *parent, void *cfdata, void *aux)
+{
+ struct fdt_attach_args *fa = (struct fdt_attach_args *)aux;
+ char buffer[128];
+ int i;
+
+ if (fa->fa_node == 0)
+ return (0);
+
+ if (!OF_getprop(fa->fa_node, "compatible", buffer,
+ sizeof(buffer)))
+ return (0);
+
+ for (i = 0; ampintc_compatibles[i]; i++)
+ if (!strcmp(buffer, ampintc_compatibles[i]))
+ return (1);
+
+ return (0);
+}
+
paddr_t gic_dist_base, gic_cpu_base, gic_dist_size, gic_cpu_size;
void
-ampintc_attach(struct device *parent, struct device *self, void *args)
+ampintc_attach_cortex(struct device *parent, struct device *self,
+ void *args)
{
struct ampintc_softc *sc = (struct ampintc_softc *)self;
struct cortex_attach_args *ia = args;
- int i, nintr;
- bus_space_tag_t iot;
- bus_space_handle_t d_ioh, p_ioh;
- uint32_t icp, icpsize, icd, icdsize;
+ uint32_t icp, icpsize, icd, icdsize;
- ampintc = sc;
-
- arm_init_smask();
-
- iot = ia->ca_iot;
+ sc->sc_iot = ia->ca_iot;
icp = ia->ca_periphbase + ICP_ADDR;
icpsize = ICP_SIZE;
icd = ia->ca_periphbase + ICD_ADDR;
@@ -241,15 +274,104 @@ ampintc_attach(struct device *parent, struct device
*self, void *args)
if (gic_dist_size)
icdsize = gic_dist_size;
- if (bus_space_map(iot, icp, icpsize, 0, &p_ioh))
+ if (bus_space_map(sc->sc_iot, icp, icpsize, 0, &sc->sc_p_ioh))
panic("ampintc_attach: ICP bus_space_map failed!");
- if (bus_space_map(iot, icd, icdsize, 0, &d_ioh))
+ if (bus_space_map(sc->sc_iot, icd, icdsize, 0, &sc->sc_d_ioh))
panic("ampintc_attach: ICD bus_space_map failed!");
- sc->sc_iot = iot;
- sc->sc_d_ioh = d_ioh;
- sc->sc_p_ioh = p_ioh;
+ ampintc_attach(parent, self, args);
+}
+
+void
+ampintc_attach_fdt(struct device *parent, struct device *self,
+ void *args)
+{
+ struct ampintc_softc *sc = (struct ampintc_softc *)self;
+ struct fdt_attach_args *fa = args;
+ uint32_t icp, icpsize, icd, icdsize;
+ int nac, nsc, inlen, pnode, off;
+ uint32_t buffer[8];
+
+ sc->sc_iot = fa->fa_iot;
+
+ if ((pnode = OF_parent(fa->fa_node)) == 0)
+ panic("ampintc_attach: cannot get device tree parent");
+
+ inlen = OF_getprop(pnode, "#address-cells", buffer,
+ sizeof(buffer));
+ if (inlen != sizeof(uint32_t))
+ panic("ampintc_attach: cannot get address cells");
+ nac = betoh32(buffer[0]);
+
+ inlen = OF_getprop(pnode, "#size-cells", buffer,
+ sizeof(buffer));
+ if (inlen != sizeof(uint32_t))
+ panic("ampintc_attach: cannot get size cells");
+ nsc = betoh32(buffer[0]);
+
+ inlen = OF_getprop(fa->fa_node, "reg", buffer,
+ sizeof(buffer));
+ if (inlen < 2 * (nac+nsc) * sizeof(uint32_t))
+ panic("ampintc_attach: cannot extract both rows");
+
+ /* XXX: try to cope with 64-byte bus addresses */
+ /* First row: ICD */
+ off = 0;
+ if (nac == 1)
+ icd = betoh32(buffer[off]);
+ else if (nac == 2)
+ icd = betoh32(buffer[off + 1]);
+ else
+ panic("ampintc_attach: invalid address cells");
+
+ if (nsc == 1)
+ icdsize = betoh32(buffer[off + nac]);
+ else if (nsc == 2)
+ icdsize = betoh32(buffer[off + nac + 1]);
+ else
+ panic("ampintc_attach: invalid size cells");
+
+ /* Second row: ICP */
+ off = nac + nsc;
+ if (nac == 1)
+ icp = betoh32(buffer[off]);
+ else if (nac == 2)
+ icp = betoh32(buffer[off + 1]);
+ else
+ panic("ampintc_attach: invalid address cells");
+
+ if (nsc == 1)
+ icpsize = betoh32(buffer[off + nac]);
+ else if (nsc == 2)
+ icpsize = betoh32(buffer[off + nac + 1]);
+ else
+ panic("ampintc_attach: invalid size cells");
+
+ if (bus_space_map(sc->sc_iot, icp, icpsize, 0, &sc->sc_p_ioh))
+ panic("ampintc_attach: ICP bus_space_map failed!");
+
+ if (bus_space_map(sc->sc_iot, icd, icdsize, 0, &sc->sc_d_ioh))
+ panic("ampintc_attach: ICD bus_space_map failed!");
+
+ ampintc_attach(parent, self, args);
+}
+
+void
+ampintc_attach(struct device *parent, struct device *self, void *args)
+{
+ struct ampintc_softc *sc = (struct ampintc_softc *)self;
+ int i, nintr;
+ bus_space_tag_t iot;
+ bus_space_handle_t d_ioh, p_ioh;
+
+ ampintc = sc;
+
+ iot = sc->sc_iot;
+ d_ioh = sc->sc_d_ioh;
+ p_ioh = sc->sc_p_ioh;
+
+ arm_init_smask();
evcount_attach(&sc->sc_spur, "irq1023/spur", NULL);
diff --git sys/arch/arm/cortex/files.cortex sys/arch/arm/cortex/files.cortex
index 052acfd..12273ef 100644
--- sys/arch/arm/cortex/files.cortex
+++ sys/arch/arm/cortex/files.cortex
@@ -7,7 +7,8 @@ file arch/arm/cortex/cortex.c cortex
device ampintc
attach ampintc at cortex
-file arch/arm/cortex/ampintc.c ampintc
+attach ampintc at fdt with ampintc_fdt
+file arch/arm/cortex/ampintc.c ampintc | ampintc_fdt
device amptimer
attach amptimer at cortex
diff --git sys/arch/armv7/conf/GENERIC sys/arch/armv7/conf/GENERIC
index 019c0ef..ee972fb 100644
--- sys/arch/armv7/conf/GENERIC
+++ sys/arch/armv7/conf/GENERIC
@@ -34,6 +34,7 @@ cpu0 at mainbus?
# Cortex-A9
cortex0 at mainbus?
ampintc* at cortex?
+ampintc* at fdt?
amptimer* at cortex?
agtimer* at cortex?
armliicc* at cortex?
diff --git sys/arch/armv7/conf/RAMDISK sys/arch/armv7/conf/RAMDISK
index 9c1b1b8..310c6c6 100644
--- sys/arch/armv7/conf/RAMDISK
+++ sys/arch/armv7/conf/RAMDISK
@@ -33,6 +33,7 @@ cpu0 at mainbus?
# Cortex-A9
cortex0 at mainbus?
ampintc* at cortex?
+ampintc* at fdt?
amptimer* at cortex?
agtimer* at cortex?
armliicc* at cortex?