Changeset View
Changeset View
Standalone View
Standalone View
sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c
| Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
| #include <machine/intr.h> | #include <machine/intr.h> | ||||
| #include <dev/fdt/fdt_common.h> | #include <dev/fdt/fdt_common.h> | ||||
| #include <dev/ofw/openfirm.h> | #include <dev/ofw/openfirm.h> | ||||
| #include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
| #include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
| #include <machine/bus.h> | #include <machine/bus.h> | ||||
| /* XXXMDC Is this necessary at all? */ | |||||
| #if defined(__aarch64__) | |||||
| #else | |||||
| #include <machine/fdt.h> | #include <machine/fdt.h> | ||||
| #endif | |||||
| #include "vchiq_arm.h" | #include "vchiq_arm.h" | ||||
| #include "vchiq_2835.h" | #include "vchiq_2835.h" | ||||
| #define VCHIQ_LOCK do { \ | #define VCHIQ_LOCK do { \ | ||||
| mtx_lock(&bcm_vchiq_sc->lock); \ | mtx_lock(&bcm_vchiq_sc->lock); \ | ||||
| } while(0) | } while(0) | ||||
| Show All 14 Lines | struct bcm_vchiq_softc { | ||||
| void* intr_hl; | void* intr_hl; | ||||
| bus_space_tag_t bst; | bus_space_tag_t bst; | ||||
| bus_space_handle_t bsh; | bus_space_handle_t bsh; | ||||
| int regs_offset; | int regs_offset; | ||||
| }; | }; | ||||
| static struct bcm_vchiq_softc *bcm_vchiq_sc = NULL; | static struct bcm_vchiq_softc *bcm_vchiq_sc = NULL; | ||||
| #define BSD_DTB 1 | |||||
| #define UPSTREAM_DTB 2 | #define CONFIG_INVALID 0 | ||||
| #define CONFIG_VALID 1 << 0 | |||||
| #define BSD_REG_ADDRS 1 << 1 | |||||
| #define LONG_BULK_SPACE 1 << 2 | |||||
| /* | |||||
| * Also controls the use of the standard VC address offset for bulk data DMA | |||||
| * (normal bulks use that offset; bulks for long address spaces use physical | |||||
| * page addresses) | |||||
| */ | |||||
| extern unsigned int g_long_bulk_space; | |||||
| /* | |||||
| * XXXMDC | |||||
| * The man page for ofw_bus_is_compatible describes ``features'' | |||||
| * as ``can be used''. Here we use understand them as ``must be used'' | |||||
| */ | |||||
| static struct ofw_compat_data compat_data[] = { | static struct ofw_compat_data compat_data[] = { | ||||
| {"broadcom,bcm2835-vchiq", BSD_DTB}, | {"broadcom,bcm2835-vchiq", BSD_REG_ADDRS | CONFIG_VALID}, | ||||
| {"brcm,bcm2835-vchiq", UPSTREAM_DTB}, | {"brcm,bcm2835-vchiq", CONFIG_VALID}, | ||||
| {"brcm,bcm2711-vchiq", UPSTREAM_DTB}, | {"brcm,bcm2711-vchiq", LONG_BULK_SPACE | CONFIG_VALID}, | ||||
| {NULL, 0} | {NULL, CONFIG_INVALID} | ||||
| }; | }; | ||||
| #define vchiq_read_4(reg) \ | #define vchiq_read_4(reg) \ | ||||
| bus_space_read_4(bcm_vchiq_sc->bst, bcm_vchiq_sc->bsh, (reg) + \ | bus_space_read_4(bcm_vchiq_sc->bst, bcm_vchiq_sc->bsh, (reg) + \ | ||||
| bcm_vchiq_sc->regs_offset) | bcm_vchiq_sc->regs_offset) | ||||
| #define vchiq_write_4(reg, val) \ | #define vchiq_write_4(reg, val) \ | ||||
| bus_space_write_4(bcm_vchiq_sc->bst, bcm_vchiq_sc->bsh, (reg) + \ | bus_space_write_4(bcm_vchiq_sc->bst, bcm_vchiq_sc->bsh, (reg) + \ | ||||
| bcm_vchiq_sc->regs_offset, val) | bcm_vchiq_sc->regs_offset, val) | ||||
| Show All 18 Lines | bcm_vchiq_intr(void *arg) | ||||
| if (status & 0x4) { /* Was the doorbell rung? */ | if (status & 0x4) { /* Was the doorbell rung? */ | ||||
| remote_event_pollall(state); | remote_event_pollall(state); | ||||
| } | } | ||||
| } | } | ||||
| void | void | ||||
| remote_event_signal(REMOTE_EVENT_T *event) | remote_event_signal(REMOTE_EVENT_T *event) | ||||
| { | { | ||||
| event->fired = 1; | |||||
| wmb(); | |||||
| event->fired = 1; | |||||
| /* The test on the next line also ensures the write on the previous line | /* The test on the next line also ensures the write on the previous line | ||||
| has completed */ | has completed */ | ||||
| /* UPDATE: not on arm64, it would seem... */ | |||||
| #if defined(__aarch64__) | |||||
| dsb(sy); | |||||
| #endif | |||||
| if (event->armed) { | if (event->armed) { | ||||
| /* trigger vc interrupt */ | /* trigger vc interrupt */ | ||||
| #if defined(__aarch64__) | |||||
| dsb(sy); | |||||
| #else | |||||
| dsb(); | dsb(); | ||||
| #endif | |||||
| vchiq_write_4(0x48, 0); | vchiq_write_4(0x48, 0); | ||||
| } | } | ||||
| } | } | ||||
| static int | static int | ||||
| bcm_vchiq_probe(device_t dev) | bcm_vchiq_probe(device_t dev) | ||||
| { | { | ||||
| if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) | if ((ofw_bus_search_compatible(dev, compat_data)->ocd_data & CONFIG_VALID) == 0) | ||||
| return (ENXIO); | return (ENXIO); | ||||
| device_set_desc(dev, "BCM2835 VCHIQ"); | device_set_desc(dev, "BCM2835 VCHIQ"); | ||||
| return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
| } | } | ||||
| /* debug_sysctl */ | |||||
| extern int vchiq_core_log_level; | |||||
| extern int vchiq_arm_log_level; | |||||
| static int | static int | ||||
| bcm_vchiq_attach(device_t dev) | bcm_vchiq_attach(device_t dev) | ||||
| { | { | ||||
| struct bcm_vchiq_softc *sc = device_get_softc(dev); | struct bcm_vchiq_softc *sc = device_get_softc(dev); | ||||
| phandle_t node; | phandle_t node; | ||||
| pcell_t cell; | pcell_t cell; | ||||
| int rid = 0; | int rid = 0; | ||||
| Show All 11 Lines | bcm_vchiq_attach(device_t dev) | ||||
| rid = 0; | rid = 0; | ||||
| sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); | sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); | ||||
| if (sc->irq_res == NULL) { | if (sc->irq_res == NULL) { | ||||
| device_printf(dev, "could not allocate interrupt resource\n"); | device_printf(dev, "could not allocate interrupt resource\n"); | ||||
| return (ENXIO); | return (ENXIO); | ||||
| } | } | ||||
| if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == UPSTREAM_DTB) | uintptr_t dev_compat_d = ofw_bus_search_compatible(dev, compat_data)->ocd_data; | ||||
| /* XXXMDC: shouldn't happen (checked for in probe)--but, for symmetry */ | |||||
| if ((dev_compat_d & CONFIG_VALID) == 0){ | |||||
| device_printf(dev, "attempting to attach using invalid config.\n"); | |||||
| bus_release_resource(dev, SYS_RES_IRQ, rid, sc->irq_res); | |||||
| return (EINVAL); | |||||
| } | |||||
| if ((dev_compat_d & BSD_REG_ADDRS) == 0) | |||||
| sc->regs_offset = -0x40; | sc->regs_offset = -0x40; | ||||
| if(dev_compat_d & LONG_BULK_SPACE) | |||||
| g_long_bulk_space = 1; | |||||
| node = ofw_bus_get_node(dev); | node = ofw_bus_get_node(dev); | ||||
| if ((OF_getencprop(node, "cache-line-size", &cell, sizeof(cell))) > 0) | if ((OF_getencprop(node, "cache-line-size", &cell, sizeof(cell))) > 0) | ||||
| g_cache_line_size = cell; | g_cache_line_size = cell; | ||||
| vchiq_core_initialize(); | vchiq_core_initialize(); | ||||
| /* debug_sysctl */ | |||||
| struct sysctl_ctx_list *ctx_l = device_get_sysctl_ctx(dev); | |||||
| struct sysctl_oid *tree_node = device_get_sysctl_tree(dev); | |||||
| struct sysctl_oid_list *tree = SYSCTL_CHILDREN(tree_node); | |||||
| SYSCTL_ADD_INT( | |||||
| ctx_l, tree, OID_AUTO, "log", CTLFLAG_RW, | |||||
| &vchiq_core_log_level, vchiq_core_log_level, "log level" | |||||
| ); | |||||
| SYSCTL_ADD_INT( | |||||
| ctx_l, tree, OID_AUTO, "arm_log", CTLFLAG_RW, | |||||
| &vchiq_arm_log_level, vchiq_arm_log_level, "arm log level" | |||||
| ); | |||||
| /* Setup and enable the timer */ | /* Setup and enable the timer */ | ||||
| if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, | if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, | ||||
| NULL, bcm_vchiq_intr, sc, | NULL, bcm_vchiq_intr, sc, | ||||
| &sc->intr_hl) != 0) { | &sc->intr_hl) != 0) { | ||||
| bus_release_resource(dev, SYS_RES_IRQ, rid, | bus_release_resource(dev, SYS_RES_IRQ, rid, | ||||
| sc->irq_res); | sc->irq_res); | ||||
| device_printf(dev, "Unable to setup the clock irq handler.\n"); | device_printf(dev, "Unable to setup the clock irq handler.\n"); | ||||
| ▲ Show 20 Lines • Show All 53 Lines • Show Last 20 Lines | |||||