Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/arm/nexus.c
Show First 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | |||||
#include "opt_platform.h" | #include "opt_platform.h" | ||||
#ifdef FDT | #ifdef FDT | ||||
#include <dev/fdt/fdt_common.h> | #include <dev/fdt/fdt_common.h> | ||||
#include <machine/fdt.h> | #include <machine/fdt.h> | ||||
#include "ofw_bus_if.h" | #include "ofw_bus_if.h" | ||||
#endif | #endif | ||||
#include "pic_if.h" | |||||
static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device"); | static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device"); | ||||
struct nexus_device { | struct nexus_device { | ||||
struct resource_list nx_resources; | struct resource_list nx_resources; | ||||
}; | }; | ||||
#define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev)) | #define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev)) | ||||
static struct rman mem_rman; | static struct rman mem_rman; | ||||
#if defined(ARM_INTRNG) | |||||
static device_t nexus_dev; | |||||
#endif | |||||
static int nexus_probe(device_t); | static int nexus_probe(device_t); | ||||
static int nexus_attach(device_t); | static int nexus_attach(device_t); | ||||
static int nexus_print_child(device_t, device_t); | static int nexus_print_child(device_t, device_t); | ||||
static device_t nexus_add_child(device_t, u_int, const char *, int); | static device_t nexus_add_child(device_t, u_int, const char *, int); | ||||
static struct resource *nexus_alloc_resource(device_t, device_t, int, int *, | static struct resource *nexus_alloc_resource(device_t, device_t, int, int *, | ||||
u_long, u_long, u_long, u_int); | u_long, u_long, u_long, u_int); | ||||
static int nexus_activate_resource(device_t, device_t, int, int, | static int nexus_activate_resource(device_t, device_t, int, int, | ||||
struct resource *); | struct resource *); | ||||
static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, | static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, | ||||
enum intr_polarity pol); | enum intr_polarity pol); | ||||
static int nexus_deactivate_resource(device_t, device_t, int, int, | static int nexus_deactivate_resource(device_t, device_t, int, int, | ||||
struct resource *); | struct resource *); | ||||
static int nexus_setup_intr(device_t dev, device_t child, struct resource *res, | static int nexus_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); | int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep); | ||||
static int nexus_teardown_intr(device_t, device_t, struct resource *, void *); | static int nexus_teardown_intr(device_t, device_t, struct resource *, void *); | ||||
#if defined(ARM_INTRNG) | |||||
static int nexus_pic_config(device_t, int, enum intr_trigger, enum intr_polarity); | |||||
static void nexus_pic_mask(device_t, int); | |||||
static void nexus_pic_unmask(device_t, int); | |||||
static void nexus_pic_eoi(device_t, int); | |||||
void arm_irq_handler(struct trapframe *tf, int irqnb); | |||||
#endif | |||||
#ifdef FDT | #ifdef FDT | ||||
static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, | static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, | ||||
int icells, pcell_t *intr); | int icells, pcell_t *intr); | ||||
#endif | #endif | ||||
static device_method_t nexus_methods[] = { | static device_method_t nexus_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, nexus_probe), | DEVMETHOD(device_probe, nexus_probe), | ||||
DEVMETHOD(device_attach, nexus_attach), | DEVMETHOD(device_attach, nexus_attach), | ||||
/* Bus interface */ | /* Bus interface */ | ||||
DEVMETHOD(bus_print_child, nexus_print_child), | DEVMETHOD(bus_print_child, nexus_print_child), | ||||
DEVMETHOD(bus_add_child, nexus_add_child), | DEVMETHOD(bus_add_child, nexus_add_child), | ||||
DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), | DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), | ||||
DEVMETHOD(bus_activate_resource, nexus_activate_resource), | DEVMETHOD(bus_activate_resource, nexus_activate_resource), | ||||
DEVMETHOD(bus_config_intr, nexus_config_intr), | DEVMETHOD(bus_config_intr, nexus_config_intr), | ||||
DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), | DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), | ||||
DEVMETHOD(bus_setup_intr, nexus_setup_intr), | DEVMETHOD(bus_setup_intr, nexus_setup_intr), | ||||
DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), | DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), | ||||
#ifdef FDT | #ifdef FDT | ||||
DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr), | DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr), | ||||
#endif | #endif | ||||
#ifdef ARM_INTRNG | |||||
/* PIC interface */ | |||||
DEVMETHOD(pic_config, nexus_pic_config), | |||||
DEVMETHOD(pic_mask, nexus_pic_mask), | |||||
DEVMETHOD(pic_unmask, nexus_pic_unmask), | |||||
DEVMETHOD(pic_eoi, nexus_pic_eoi), | |||||
#endif | |||||
{ 0, 0 } | { 0, 0 } | ||||
}; | }; | ||||
static devclass_t nexus_devclass; | static devclass_t nexus_devclass; | ||||
static driver_t nexus_driver = { | static driver_t nexus_driver = { | ||||
"nexus", | "nexus", | ||||
nexus_methods, | nexus_methods, | ||||
1 /* no softc */ | 1 /* no softc */ | ||||
Show All 20 Lines | nexus_attach(device_t dev) | ||||
mem_rman.rm_start = 0; | mem_rman.rm_start = 0; | ||||
mem_rman.rm_end = ~0ul; | mem_rman.rm_end = ~0ul; | ||||
mem_rman.rm_type = RMAN_ARRAY; | mem_rman.rm_type = RMAN_ARRAY; | ||||
mem_rman.rm_descr = "I/O memory addresses"; | mem_rman.rm_descr = "I/O memory addresses"; | ||||
if (rman_init(&mem_rman) || rman_manage_region(&mem_rman, 0, ~0)) | if (rman_init(&mem_rman) || rman_manage_region(&mem_rman, 0, ~0)) | ||||
panic("nexus_probe mem_rman"); | panic("nexus_probe mem_rman"); | ||||
#if defined(ARM_INTRNG) | |||||
/* Register core interrupt controller */ | |||||
nexus_dev = dev; | |||||
arm_register_pic(dev, 0); | |||||
#endif | |||||
/* | /* | ||||
* First, deal with the children we know about already | * First, deal with the children we know about already | ||||
*/ | */ | ||||
bus_generic_probe(dev); | bus_generic_probe(dev); | ||||
bus_generic_attach(dev); | bus_generic_attach(dev); | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static int | static int | ||||
nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, | nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, | ||||
enum intr_polarity pol) | enum intr_polarity pol) | ||||
{ | { | ||||
int ret = ENODEV; | int ret = ENODEV; | ||||
#ifdef ARM_INTRNG | |||||
ret = arm_intrng_config_irq(irq, trig, pol); | |||||
#else | |||||
if (arm_config_irq) | if (arm_config_irq) | ||||
ret = (*arm_config_irq)(irq, trig, pol); | ret = (*arm_config_irq)(irq, trig, pol); | ||||
#endif | |||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags, | nexus_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) | driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) | ||||
{ | { | ||||
int irq; | int irq; | ||||
ian: I think this might be the place to check for res == NULL and use that to set up the root IC. | |||||
if ((rman_get_flags(res) & RF_SHAREABLE) == 0) | if ((rman_get_flags(res) & RF_SHAREABLE) == 0) | ||||
flags |= INTR_EXCL; | flags |= INTR_EXCL; | ||||
for (irq = rman_get_start(res); irq <= rman_get_end(res); irq++) { | for (irq = rman_get_start(res); irq <= rman_get_end(res); irq++) { | ||||
#if defined(ARM_INTRNG) | |||||
arm_setup_irqhandler(child, | |||||
filt, intr, arg, irq, flags, cookiep); | |||||
#else | |||||
arm_setup_irqhandler(device_get_nameunit(child), | arm_setup_irqhandler(device_get_nameunit(child), | ||||
filt, intr, arg, irq, flags, cookiep); | filt, intr, arg, irq, flags, cookiep); | ||||
arm_unmask_irq(irq); | arm_unmask_irq(irq); | ||||
#endif | |||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih) | nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih) | ||||
{ | { | ||||
return (arm_remove_irqhandler(rman_get_start(r), ih)); | return (arm_remove_irqhandler(rman_get_start(r), ih)); | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
rman_set_virtual(r, NULL); | rman_set_virtual(r, NULL); | ||||
rman_set_bushandle(r, 0); | rman_set_bushandle(r, 0); | ||||
} | } | ||||
return (rman_deactivate_resource(r)); | return (rman_deactivate_resource(r)); | ||||
} | } | ||||
#if defined(ARM_INTRNG) | |||||
static int | |||||
nexus_pic_config(device_t bus, int irq, enum intr_trigger trig, | |||||
enum intr_polarity pol) | |||||
{ | |||||
/* unused */ | |||||
return (0); | |||||
} | |||||
static void | |||||
nexus_pic_mask(device_t bus, int irq) | |||||
{ | |||||
/* unused */ | |||||
} | |||||
static void | |||||
nexus_pic_unmask(device_t bus, int irq) | |||||
{ | |||||
/* unused */ | |||||
} | |||||
static void | |||||
nexus_pic_eoi(device_t bus, int irq) | |||||
{ | |||||
/* unused */ | |||||
} | |||||
void | |||||
arm_irq_handler(struct trapframe *tf, int irqnb) | |||||
{ | |||||
/* Dispatch root interrupt from core */ | |||||
arm_dispatch_irq(nexus_dev, tf, 0); | |||||
} | |||||
#endif | |||||
#ifdef FDT | #ifdef FDT | ||||
static int | static int | ||||
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells, | nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells, | ||||
pcell_t *intr) | pcell_t *intr) | ||||
{ | { | ||||
fdt_pic_decode_t intr_decode; | fdt_pic_decode_t intr_decode; | ||||
phandle_t intr_offset; | phandle_t intr_offset; | ||||
int i, rv, interrupt, trig, pol; | int i, rv, interrupt, trig, pol; | ||||
intr_offset = OF_xref_phandle(iparent); | intr_offset = OF_xref_phandle(iparent); | ||||
for (i = 0; i < icells; i++) | for (i = 0; i < icells; i++) | ||||
intr[i] = cpu_to_fdt32(intr[i]); | intr[i] = cpu_to_fdt32(intr[i]); | ||||
ianAuthorUnsubmitted Not Done Inline ActionsI'm curious why this cpu_to_fdt32() is needed, when the resource loops in simplebus and ofwbus that call this code have already done OF_getencprop() which includes endian-swapping already. ian: I'm curious why this cpu_to_fdt32() is needed, when the resource loops in simplebus and ofwbus… | |||||
for (i = 0; fdt_pic_table[i] != NULL; i++) { | for (i = 0; fdt_pic_table[i] != NULL; i++) { | ||||
intr_decode = fdt_pic_table[i]; | intr_decode = fdt_pic_table[i]; | ||||
rv = intr_decode(intr_offset, intr, &interrupt, &trig, &pol); | rv = intr_decode(intr_offset, intr, &interrupt, &trig, &pol); | ||||
if (rv == 0) { | if (rv == 0) { | ||||
/* This was recognized as our PIC and decoded. */ | /* This was recognized as our PIC and decoded. */ | ||||
interrupt = FDT_MAP_IRQ(intr_parent, interrupt); | interrupt = FDT_MAP_IRQ(iparent, interrupt); | ||||
return (interrupt); | return (interrupt); | ||||
} | } | ||||
} | } | ||||
/* Not in table, so guess */ | /* Not in table, so guess */ | ||||
interrupt = FDT_MAP_IRQ(intr_parent, fdt32_to_cpu(intr[0])); | interrupt = FDT_MAP_IRQ(iparent, fdt32_to_cpu(intr[0])); | ||||
ianAuthorUnsubmitted Not Done Inline Actionssome ICs put the irq number in intr[1]. this is that whole ugly "only the IC driver knows how to decode the interrupts=<...> cell contents" thing. ian: some ICs put the irq number in intr[1]. this is that whole ugly "only the IC driver knows how… | |||||
return (interrupt); | return (interrupt); | ||||
} | } | ||||
#endif | #endif | ||||
I think this might be the place to check for res == NULL and use that to set up the root IC. We can validate that flags includes INTR_CONTROLLER, and perhaps also that no root controller is regigistered already.