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?