Index: head/sys/dev/bhnd/bhnd_bus_if.m =================================================================== --- head/sys/dev/bhnd/bhnd_bus_if.m +++ head/sys/dev/bhnd/bhnd_bus_if.m @@ -55,6 +55,12 @@ panic("bhnd_bus_get_chipid unimplemented"); } + static bhnd_attach_type + bhnd_bus_null_get_attach_type(device_t dev, device_t child) + { + panic("bhnd_bus_get_attach_type unimplemented"); + } + static int bhnd_bus_null_read_board_info(device_t dev, device_t child, struct bhnd_board_info *info) @@ -197,7 +203,7 @@ METHOD bhnd_attach_type get_attach_type { device_t dev; device_t child; -} DEFAULT bhnd_bus_generic_get_attach_type; +} DEFAULT bhnd_bus_null_get_attach_type; /** * Attempt to read the BHND board identification from the parent bus. Index: head/sys/dev/bhnd/bhnd_subr.c =================================================================== --- head/sys/dev/bhnd/bhnd_subr.c +++ head/sys/dev/bhnd/bhnd_subr.c @@ -1159,21 +1159,3 @@ return (EINVAL); }; -/** - * Helper function for implementing BHND_BUS_GET_ATTACH_TYPE(). - * - * This implementation of BHND_BUS_GET_ATTACH_TYPE() simply calls the - * BHND_BUS_GET_ATTACH_TYPE() method of the parent of @p dev. - */ -bhnd_attach_type -bhnd_bus_generic_get_attach_type(device_t dev, device_t child) -{ - /* iterate from cores via bhnd to bridge or SoC */ - if (device_get_parent(dev) != NULL) - return (BHND_BUS_GET_ATTACH_TYPE(device_get_parent(dev), - child)); - - panic("bhnd_bus_get_attach_type unimplemented"); - /* Unreachable */ - return (BHND_ATTACH_ADAPTER); -} Index: head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m =================================================================== --- head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m +++ head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m @@ -36,32 +36,16 @@ # HEADER { - #include /* forward declarations */ struct chipc_caps; - struct chipc_caps *bhnd_chipc_generic_get_caps(device_t dev); } CODE { - - /** - * Helper function for implementing BHND_CHIPC_GET_CAPS(). - * - * This implementation of BHND_CHIPC_GET_CAPS() simply calls the - * BHND_CHIPC_GET_CAPS() method of the parent of @p dev. - */ - struct chipc_caps* - bhnd_chipc_generic_get_caps(device_t dev) + static struct chipc_caps * + bhnd_chipc_null_get_caps(device_t dev) { - - if (device_get_parent(dev) != NULL) - return (BHND_CHIPC_GET_CAPS(device_get_parent(dev))); - panic("bhnd_chipc_generic_get_caps unimplemented"); - /* Unreachable */ - return (NULL); } - } /** @@ -91,7 +75,7 @@ */ METHOD struct chipc_caps * get_caps { device_t dev; -} DEFAULT bhnd_chipc_generic_get_caps; +} DEFAULT bhnd_chipc_null_get_caps; /** * Enable hardware access to the SPROM/OTP source. @@ -114,12 +98,3 @@ METHOD void disable_sprom { device_t dev; } - -/** - * Return the flash configuration register value - * - * @param dev A bhnd(4) ChipCommon device - */ -METHOD uint32_t get_flash_cfg { - device_t dev; -} Index: head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c +++ head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c @@ -54,22 +54,6 @@ #define CHIPC_VALID_SPROM_SRC(_src) \ ((_src) == BHND_NVRAM_SRC_SPROM || (_src) == BHND_NVRAM_SRC_OTP) -static void -chipc_sprom_identify(driver_t *driver, device_t parent) -{ - struct chipc_caps *caps; - - caps = BHND_CHIPC_GET_CAPS(parent); - if (!CHIPC_VALID_SPROM_SRC(caps->nvram_src)) - return; - - if (device_find_child(parent, "bhnd_nvram", 0) != NULL) - return; - - if (BUS_ADD_CHILD(parent, 0, "bhnd_nvram", 0) == NULL) - device_printf(parent, "add bhnd_nvram failed\n"); -} - static int chipc_sprom_probe(device_t dev) { @@ -113,7 +97,6 @@ static device_method_t chipc_sprom_methods[] = { /* Device interface */ - DEVMETHOD(device_identify, chipc_sprom_identify), DEVMETHOD(device_probe, chipc_sprom_probe), DEVMETHOD(device_attach, chipc_sprom_attach), DEVMETHOD_END Index: head/sys/dev/bhnd/cores/chipc/chipc.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc.c +++ head/sys/dev/bhnd/cores/chipc/chipc.c @@ -37,25 +37,8 @@ * With the exception of some very early chipsets, the ChipCommon core * has been included in all HND SoCs and chipsets based on the siba(4) * and bcma(4) interconnects, providing a common interface to chipset - * identification, bus enumeration, UARTs, clocks, watchdog interrupts, GPIO, - * flash, etc. - * - * The purpose of this driver is memory resource management for ChipCommon drivers - * like UART, PMU, flash. ChipCommon core has several memory regions. - * - * ChipCommon driver has memory resource manager. Driver - * gets information about BHND core ports/regions and map them - * into drivers' resources. - * - * Here is overview of mapping: - * - * ------------------------------------------------------ - * | Port.Region| Purpose | - * ------------------------------------------------------ - * | 0.0 | PMU, SPI(0x40), UART(0x300) | - * | 1.0 | ? | - * | 1.1 | MMIO flash (SPI & CFI) | - * ------------------------------------------------------ + * identification, bus enumeration, UARTs, clocks, watchdog interrupts, + * GPIO, flash, etc. */ #include @@ -76,6 +59,7 @@ #include "chipcreg.h" #include "chipcvar.h" + #include "chipc_private.h" devclass_t bhnd_chipc_devclass; /**< bhnd(4) chipcommon device class */ @@ -123,49 +107,10 @@ BHND_DEVICE_QUIRK_END }; +// FIXME: IRQ shouldn't be hard-coded +#define CHIPC_MIPS_IRQ 2 -/* - * Here is resource configuration hints for child devices - * - * [Flash] There are 2 flash resources: - * - resource ID (rid) = 0: memory-mapped flash memory - * - resource ID (rid) = 1: memory-mapped flash registers (i.e for SPI) - * - * [UART] Uses IRQ and memory resources: - * - resource ID (rid) = 0: memory-mapped registers - * - IRQ resource ID (rid) = 0: shared IRQ line for Tx/Rx. - */ - -static const struct chipc_hint { - const char *name; - int unit; - int type; - int rid; - rman_res_t base; /* relative to parent resource */ - rman_res_t size; - u_int port; /* ignored if SYS_RES_IRQ */ - u_int region; -} chipc_hints[] = { - // FIXME: cfg/spi port1.1 mapping on siba(4) SoCs - // FIXME: IRQ shouldn't be hardcoded - /* device unit type rid base size port,region */ - { "bhnd_nvram", 0, SYS_RES_MEMORY, 0, CHIPC_SPROM_OTP, CHIPC_SPROM_OTP_SIZE, 0,0 }, - { "uart", 0, SYS_RES_MEMORY, 0, CHIPC_UART0_BASE, CHIPC_UART_SIZE, 0,0 }, - { "uart", 0, SYS_RES_IRQ, 0, 2, 1 }, - { "uart", 1, SYS_RES_MEMORY, 0, CHIPC_UART1_BASE, CHIPC_UART_SIZE, 0,0 }, - { "uart", 1, SYS_RES_IRQ, 0, 2, 1 }, - { "spi", 0, SYS_RES_MEMORY, 0, 0, RM_MAX_END, 1,1 }, - { "spi", 0, SYS_RES_MEMORY, 1, CHIPC_SFLASH_BASE, CHIPC_SFLASH_SIZE, 0,0 }, - { "cfi", 0, SYS_RES_MEMORY, 0, 0, RM_MAX_END, 1,1}, - { "cfi", 0, SYS_RES_MEMORY, 1, CHIPC_SFLASH_BASE, CHIPC_SFLASH_SIZE, 0,0 }, - { NULL } -}; - - -static int chipc_try_activate_resource( - struct chipc_softc *sc, device_t child, - int type, int rid, struct resource *r, - bool req_direct); +static int chipc_add_children(struct chipc_softc *sc); static bhnd_nvram_src chipc_find_nvram_src(struct chipc_softc *sc, struct chipc_caps *caps); @@ -175,6 +120,11 @@ static bool chipc_should_enable_sprom( struct chipc_softc *sc); +static int chipc_try_activate_resource( + struct chipc_softc *sc, device_t child, + int type, int rid, struct resource *r, + bool req_direct); + static int chipc_init_rman(struct chipc_softc *sc); static void chipc_free_rman(struct chipc_softc *sc); static struct rman *chipc_get_rman(struct chipc_softc *sc, @@ -210,9 +160,6 @@ chipc_attach(device_t dev) { struct chipc_softc *sc; - bhnd_addr_t enum_addr; - uint32_t ccid_reg; - uint8_t chip_type; int error; sc = device_get_softc(dev); @@ -231,7 +178,7 @@ goto failed; } - /* Allocate the region containing our core registers */ + /* Allocate the region containing the chipc register block */ if ((sc->core_region = chipc_find_region_by_rid(sc, 0)) == NULL) { error = ENXIO; goto failed; @@ -242,30 +189,10 @@ if (error) { sc->core_region = NULL; goto failed; - } else { - sc->core = sc->core_region->cr_res; } - /* Fetch our chipset identification data */ - ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID); - chip_type = CHIPC_GET_BITS(ccid_reg, CHIPC_ID_BUS); - - switch (chip_type) { - case BHND_CHIPTYPE_SIBA: - /* enumeration space starts at the ChipCommon register base. */ - enum_addr = rman_get_start(sc->core->res); - break; - case BHND_CHIPTYPE_BCMA: - case BHND_CHIPTYPE_BCMA_ALT: - enum_addr = bhnd_bus_read_4(sc->core, CHIPC_EROMPTR); - break; - default: - device_printf(dev, "unsupported chip type %hhu\n", chip_type); - error = ENODEV; - goto failed; - } - - sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr); + /* Save a direct reference to our chipc registers */ + sc->core = sc->core_region->cr_res; /* Fetch and parse capability register(s) */ if ((error = chipc_read_caps(sc, &sc->caps))) @@ -274,8 +201,10 @@ if (bootverbose) chipc_print_caps(sc->dev, &sc->caps); - /* Probe and attach children */ - bus_generic_probe(dev); + /* Attach all supported child devices */ + if ((error = chipc_add_children(sc))) + goto failed; + if ((error = bus_generic_attach(dev))) goto failed; @@ -313,6 +242,119 @@ return (0); } +static int +chipc_add_children(struct chipc_softc *sc) +{ + device_t child; + const char *flash_bus; + int error; + + /* SPROM/OTP */ + if (sc->caps.nvram_src == BHND_NVRAM_SRC_SPROM || + sc->caps.nvram_src == BHND_NVRAM_SRC_OTP) + { + child = BUS_ADD_CHILD(sc->dev, 0, "bhnd_nvram", -1); + if (child == NULL) { + device_printf(sc->dev, "failed to add nvram device\n"); + return (ENXIO); + } + + /* Both OTP and external SPROM are mapped at CHIPC_SPROM_OTP */ + error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0, + CHIPC_SPROM_OTP, CHIPC_SPROM_OTP_SIZE, 0, 0); + if (error) + return (error); + } + +#ifdef notyet + /* + * PMU/SLOWCLK/INSTACLK + * + * On AOB ("Always on Bus") devices, a PMU core (if it exists) is + * enumerated directly by the bhnd(4) bus -- not chipc. + * + * Otherwise, we always add a PMU child device, and let the + * chipc bhnd_pmu drivers probe for it. If the core supports an + * earlier non-PMU clock/power register interface, one of the instaclk, + * powerctl, or null bhnd_pmu drivers will claim the device. + */ + if (!sc->caps.aob || (sc->caps.aob && !sc->caps.pmu)) { + child = BUS_ADD_CHILD(sc->dev, 0, "bhnd_pmu", -1); + if (child == NULL) { + device_printf(sc->dev, "failed to add pmu\n"); + return (ENXIO); + } + + /* Associate the applicable register block */ + error = 0; + if (sc->caps.pmu) { + error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0, + CHIPC_PMU, CHIPC_PMU_SIZE, 0, 0); + } else if (sc->caps.power_control) { + error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0, + CHIPC_PWRCTL, CHIPC_PWRCTL_SIZE, 0, 0); + } + + if (error) + return (error); + + } +#endif /* notyet */ + + /* All remaining devices are SoC-only */ + if (bhnd_get_attach_type(sc->dev) != BHND_ATTACH_NATIVE) + return (0); + + /* UARTs */ + for (u_int i = 0; i < min(sc->caps.num_uarts, CHIPC_UART_MAX); i++) { + child = BUS_ADD_CHILD(sc->dev, 0, "uart", -1); + if (child == NULL) { + device_printf(sc->dev, "failed to add uart%u\n", i); + return (ENXIO); + } + + /* Shared IRQ */ + error = bus_set_resource(child, SYS_RES_IRQ, 0, CHIPC_MIPS_IRQ, + 1); + if (error) { + device_printf(sc->dev, "failed to set uart%u irq %u\n", + i, CHIPC_MIPS_IRQ); + return (error); + } + + /* UART registers are mapped sequentially */ + error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0, + CHIPC_UART(i), CHIPC_UART_SIZE, 0, 0); + if (error) + return (error); + } + + /* Flash */ + flash_bus = chipc_flash_bus_name(sc->caps.flash_type); + if (flash_bus != NULL) { + child = BUS_ADD_CHILD(sc->dev, 0, flash_bus, -1); + if (child == NULL) { + device_printf(sc->dev, "failed to add %s device\n", + flash_bus); + return (ENXIO); + } + + /* flash memory mapping */ + error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0, + 0, RM_MAX_END, 1, 1); + if (error) + return (error); + + /* flashctrl registers */ + error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 1, + CHIPC_SFLASH_BASE, CHIPC_SFLASH_SIZE, 0, 0); + if (error) + return (error); + } + + return (0); +} + /** * Determine the NVRAM data source for this device. * @@ -411,7 +453,6 @@ /* Determine flash type and parameters */ caps->cfi_width = 0; - switch (CHIPC_GET_BITS(cap_reg, CHIPC_CAP_FLASH)) { case CHIPC_CAP_SFLASH_ST: caps->flash_type = CHIPC_SFLASH_ST; @@ -420,6 +461,7 @@ caps->flash_type = CHIPC_SFLASH_AT; break; case CHIPC_CAP_NFLASH: + /* unimplemented */ caps->flash_type = CHIPC_NFLASH; break; case CHIPC_CAP_PFLASH: @@ -548,33 +590,16 @@ static device_t chipc_add_child(device_t dev, u_int order, const char *name, int unit) { + struct chipc_softc *sc; struct chipc_devinfo *dinfo; - const struct chipc_hint *hint; device_t child; - devclass_t child_dc; - int error; - int busrel_unit; + + sc = device_get_softc(dev); child = device_add_child_ordered(dev, order, name, unit); if (child == NULL) return (NULL); - /* system-wide device unit */ - unit = device_get_unit(child); - child_dc = device_get_devclass(child); - - busrel_unit = 0; - for (int i = 0; i < unit; i++) { - device_t tmp; - - tmp = devclass_get_device(child_dc, i); - if (tmp != NULL && (device_get_parent(tmp) == dev)) - busrel_unit++; - } - - /* bus-wide device unit (override unit for further hint matching) */ - unit = busrel_unit; - dinfo = malloc(sizeof(struct chipc_devinfo), M_BHND, M_NOWAIT); if (dinfo == NULL) { device_delete_child(dev, child); @@ -584,93 +609,7 @@ resource_list_init(&dinfo->resources); device_set_ivars(child, dinfo); - /* Hint matching requires a device name */ - if (name == NULL) - return (child); - - /* Use hint table to set child resources */ - for (hint = chipc_hints; hint->name != NULL; hint++) { - bhnd_addr_t region_addr; - bhnd_size_t region_size; - - /* Check device name */ - if (strcmp(hint->name, name) != 0) - continue; - - /* Check device unit */ - if (hint->unit >= 0 && unit != hint->unit) - continue; - - switch (hint->type) { - case SYS_RES_IRQ: - /* Add child resource */ - error = bus_set_resource(child, hint->type, hint->rid, - hint->base, hint->size); - if (error) { - device_printf(dev, - "bus_set_resource() failed for %s: %d\n", - device_get_nameunit(child), error); - goto failed; - } - break; - - case SYS_RES_MEMORY: - /* Fetch region address and size */ - error = bhnd_get_region_addr(dev, BHND_PORT_DEVICE, - hint->port, hint->region, ®ion_addr, - ®ion_size); - if (error) { - device_printf(dev, - "lookup of %s%u.%u failed: %d\n", - bhnd_port_type_name(BHND_PORT_DEVICE), - hint->port, hint->region, error); - goto failed; - } - - /* Verify requested range is mappable */ - if (hint->base > region_size || - (hint->size != RM_MAX_END && - (hint->size > region_size || - region_size - hint->base < hint->size ))) - { - device_printf(dev, - "%s%u.%u region cannot map requested range " - "%#jx+%#jx\n", - bhnd_port_type_name(BHND_PORT_DEVICE), - hint->port, hint->region, hint->base, - hint->size); - } - - /* - * Add child resource. If hint doesn't define the end - * of resource window (RX_MAX_END), use end of region. - */ - - error = bus_set_resource(child, - hint->type, - hint->rid, region_addr + hint->base, - (hint->size == RM_MAX_END) ? - region_size - hint->base : - hint->size); - if (error) { - device_printf(dev, - "bus_set_resource() failed for %s: %d\n", - device_get_nameunit(child), error); - goto failed; - } - break; - default: - device_printf(child, "unknown hint resource type: %d\n", - hint->type); - break; - } - } - return (child); - -failed: - device_delete_child(dev, child); - return (NULL); } static void @@ -705,7 +644,7 @@ u_int num_regions; int error; - num_regions = bhnd_get_region_count(sc->dev, port, port); + num_regions = bhnd_get_region_count(sc->dev, type, port); for (u_int region = 0; region < num_regions; region++) { /* Allocate new region record */ cr = chipc_alloc_region(sc, type, port, region); @@ -1349,15 +1288,6 @@ return (&sc->caps); } -static uint32_t -chipc_get_flash_cfg(device_t dev) -{ - struct chipc_softc *sc; - - sc = device_get_softc(dev); - return (bhnd_bus_read_4(sc->core, CHIPC_FLASH_CFG)); -} - static device_method_t chipc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, chipc_probe), @@ -1399,7 +1329,6 @@ DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom_pins), DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom_pins), DEVMETHOD(bhnd_chipc_get_caps, chipc_get_caps), - DEVMETHOD(bhnd_chipc_get_flash_cfg, chipc_get_flash_cfg), DEVMETHOD_END }; Index: head/sys/dev/bhnd/cores/chipc/chipc_cfi.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_cfi.c +++ head/sys/dev/bhnd/cores/chipc/chipc_cfi.c @@ -40,90 +40,39 @@ #include -#include #include #include "bhnd_chipc_if.h" -#include "chipc_slicer.h" + #include "chipcreg.h" #include "chipcvar.h" - -/* - * **************************** PROTOTYPES **************************** - */ - -static void chipc_cfi_identify(driver_t *driver, device_t parent); -static int chipc_cfi_probe(device_t dev); -static int chipc_cfi_attach(device_t dev); - -/* - * **************************** IMPLEMENTATION ************************ - */ - -static void -chipc_cfi_identify(driver_t *driver, device_t parent) -{ - struct chipc_caps *caps; - - if (device_find_child(parent, cfi_driver_name, -1) != NULL) - return; - - caps = BHND_CHIPC_GET_CAPS(parent); - if (caps == NULL) - return; - - if (caps->flash_type != CHIPC_PFLASH_CFI) - return; - - BUS_ADD_CHILD(parent, 0, cfi_driver_name, -1); - return; -} +#include "chipc_slicer.h" static int chipc_cfi_probe(device_t dev) { - int error; - int enabled; - int byteswap; - uint32_t flash_config; struct cfi_softc *sc; + int error; sc = device_get_softc(dev); - flash_config = BHND_CHIPC_GET_FLASH_CFG(device_get_parent(dev)); - - enabled = (flash_config & CHIPC_CF_EN); - byteswap = (flash_config & CHIPC_CF_BS); - - if (enabled == 0) - device_disable(dev); - - BHND_DEBUG_DEV(dev, "trying attach flash enabled=%d swapbytes=%d", - enabled, byteswap); - sc->sc_width = 0; - error = cfi_probe(dev); - if (error == 0) - device_set_desc(dev, "ChipCommon CFI"); + if ((error = cfi_probe(dev)) > 0) + return (error); + + device_set_desc(dev, "Broadcom ChipCommon CFI"); return (error); } static int chipc_cfi_attach(device_t dev) { - int error; - - error = cfi_attach(dev); - if (error) - return (error); - - flash_register_slicer(chipc_slicer_cfi); - return (0); + chipc_register_slicer(CHIPC_PFLASH_CFI); + return (cfi_attach(dev)); } static device_method_t chipc_cfi_methods[] = { /* device interface */ - DEVMETHOD(device_identify, chipc_cfi_identify), DEVMETHOD(device_probe, chipc_cfi_probe), DEVMETHOD(device_attach, chipc_cfi_attach), DEVMETHOD(device_detach, cfi_detach), @@ -138,4 +87,3 @@ }; DRIVER_MODULE(cfi, bhnd_chipc, chipc_cfi_driver, cfi_devclass, 0, 0); - Index: head/sys/dev/bhnd/cores/chipc/chipc_private.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_private.h +++ head/sys/dev/bhnd/cores/chipc/chipc_private.h @@ -55,6 +55,11 @@ struct resource *parent, bhnd_size_t offset, bhnd_size_t size); +int chipc_set_resource(struct chipc_softc *sc, + device_t child, int type, int rid, + rman_res_t start, rman_res_t count, u_int port, + u_int region); + struct chipc_region *chipc_alloc_region(struct chipc_softc *sc, bhnd_port_type type, u_int port, u_int region); Index: head/sys/dev/bhnd/cores/chipc/chipc_slicer.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_slicer.h +++ head/sys/dev/bhnd/cores/chipc/chipc_slicer.h @@ -34,10 +34,13 @@ #include +#include "chipcvar.h" + #define TRX_MAGIC 0x30524448 #define CFE_MAGIC 0x43464531 #define NVRAM_MAGIC 0x48534C46 +void chipc_register_slicer(chipc_flash flash_type); int chipc_slicer_spi(device_t dev, struct flash_slice *slices, int *nslices); int chipc_slicer_cfi(device_t dev, struct flash_slice *slices, Index: head/sys/dev/bhnd/cores/chipc/chipc_slicer.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_slicer.c +++ head/sys/dev/bhnd/cores/chipc/chipc_slicer.c @@ -54,58 +54,88 @@ #include #include "chipc_spi.h" -static int chipc_slicer_walk(device_t dev, struct resource* res, +static int chipc_slicer_walk(device_t dev, struct resource *res, struct flash_slice *slices, int *nslices); +void +chipc_register_slicer(chipc_flash flash_type) +{ + switch (flash_type) { + case CHIPC_SFLASH_AT: + case CHIPC_SFLASH_ST: + flash_register_slicer(chipc_slicer_spi); + break; + case CHIPC_PFLASH_CFI: + flash_register_slicer(chipc_slicer_cfi); + break; + default: + /* Unsupported */ + break; + } +} + int chipc_slicer_cfi(device_t dev, struct flash_slice *slices, int *nslices) { struct cfi_softc *sc; + device_t parent; - if (strcmp("cfi", device_get_name(dev)) != 0) - return (0); + /* must be CFI flash */ + if (device_get_devclass(dev) != devclass_find("cfi")) + return (ENXIO); + + /* must be attached to chipc */ + if ((parent = device_get_parent(dev)) == NULL) { + BHND_ERROR_DEV(dev, "no found ChipCommon device"); + return (ENXIO); + } - sc = device_get_softc(dev); + if (device_get_devclass(parent) != devclass_find("bhnd_chipc")) { + BHND_ERROR_DEV(dev, "no found ChipCommon device"); + return (ENXIO); + } + sc = device_get_softc(dev); return (chipc_slicer_walk(dev, sc->sc_res, slices, nslices)); } int chipc_slicer_spi(device_t dev, struct flash_slice *slices, int *nslices) { - /* flash(mx25l) <- spibus <- chipc_spi */ - device_t spibus; - device_t chipc_spi; struct chipc_spi_softc *sc; + device_t chipc, spi, spibus; BHND_DEBUG_DEV(dev, "initting SPI slicer: %s", device_get_name(dev)); - if (strcmp("mx25l", device_get_name(dev)) != 0) - return (EINVAL); - + /* must be SPI-attached flash */ spibus = device_get_parent(dev); if (spibus == NULL) { BHND_ERROR_DEV(dev, "no found ChipCommon SPI BUS device"); - return (EINVAL); + return (ENXIO); } - chipc_spi = device_get_parent(spibus); - if (chipc_spi == NULL) { - BHND_ERROR_DEV(spibus, "no found ChipCommon SPI device"); - return (EINVAL); + spi = device_get_parent(spibus); + if (spi == NULL) { + BHND_ERROR_DEV(dev, "no found ChipCommon SPI device"); + return (ENXIO); } - sc = device_get_softc(chipc_spi); + chipc = device_get_parent(spi); + if (device_get_devclass(chipc) != devclass_find("bhnd_chipc")) { + BHND_ERROR_DEV(dev, "no found ChipCommon device"); + return (ENXIO); + } - return (chipc_slicer_walk(dev, sc->sc_res, slices, nslices)); + sc = device_get_softc(spi); + return (chipc_slicer_walk(dev, sc->sc_flash_res, slices, nslices)); } /* * Main processing part */ static int -chipc_slicer_walk(device_t dev, struct resource* res, - struct flash_slice *slices, int *nslices) +chipc_slicer_walk(device_t dev, struct resource *res, + struct flash_slice *slices, int *nslices) { uint32_t fw_len; uint32_t fs_ofs; Index: head/sys/dev/bhnd/cores/chipc/chipc_spi.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_spi.h +++ head/sys/dev/bhnd/cores/chipc/chipc_spi.h @@ -62,28 +62,26 @@ #define CHIPC_SPI_FLASHDATA 0x08 struct chipc_spi_softc { - device_t dev; + device_t sc_dev; + struct resource *sc_res; /**< SPI registers */ + int sc_rid; - /* SPI registers */ - struct resource *sc_mem_res; - - /* MMIO flash */ - struct resource *sc_res; + struct resource *sc_flash_res; /**< flash shadow */ + int sc_flash_rid; }; /* register space access macros */ -#define SPI_BARRIER_WRITE(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \ +#define SPI_BARRIER_WRITE(sc) bus_barrier((sc)->sc_res, 0, 0, \ BUS_SPACE_BARRIER_WRITE) -#define SPI_BARRIER_READ(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \ +#define SPI_BARRIER_READ(sc) bus_barrier((sc)->sc_res, 0, 0, \ BUS_SPACE_BARRIER_READ) -#define SPI_BARRIER_RW(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \ - BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE) +#define SPI_BARRIER_RW(sc) bus_barrier((sc)->sc_res, 0, 0, \ + BUS_SPACE_BARRIER_READ | \ + BUS_SPACE_BARRIER_WRITE) -#define SPI_WRITE(sc, reg, val) do { \ - bus_write_4(sc->sc_mem_res, (reg), (val)); \ - } while (0) +#define SPI_WRITE(sc, reg, val) bus_write_4(sc->sc_res, (reg), (val)); -#define SPI_READ(sc, reg) bus_read_4(sc->sc_mem_res, (reg)) +#define SPI_READ(sc, reg) bus_read_4(sc->sc_res, (reg)) #define SPI_SET_BITS(sc, reg, bits) \ SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits)) Index: head/sys/dev/bhnd/cores/chipc/chipc_spi.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_spi.c +++ head/sys/dev/bhnd/cores/chipc/chipc_spi.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2016 Michael Zhilin + * Copyright (c) 2016 Landon Fuller * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,135 +42,134 @@ #include #include -/* - * SPI BUS interface - */ + #include +#include "bhnd_chipc_if.h" + #include "spibus_if.h" #include "chipcreg.h" #include "chipcvar.h" -#include "chipc_spi.h" -#include "bhnd_chipc_if.h" - -/* - * Flash slicer - */ #include "chipc_slicer.h" -/* - * **************************** PROTOTYPES **************************** - */ +#include "chipc_spi.h" -static void chipc_spi_identify(driver_t *driver, device_t parent); static int chipc_spi_probe(device_t dev); static int chipc_spi_attach(device_t dev); +static int chipc_spi_detach(device_t dev); static int chipc_spi_transfer(device_t dev, device_t child, struct spi_command *cmd); static int chipc_spi_txrx(struct chipc_spi_softc *sc, uint8_t in, uint8_t* out); static int chipc_spi_wait(struct chipc_spi_softc *sc); -/* - * **************************** IMPLEMENTATION ************************ - */ +static int +chipc_spi_probe(device_t dev) +{ + device_set_desc(dev, "Broadcom ChipCommon SPI"); + return (BUS_PROBE_NOWILDCARD); +} -static void -chipc_spi_identify(driver_t *driver, device_t parent) +static int +chipc_spi_attach(device_t dev) { - struct chipc_caps *caps; - device_t spidev; - device_t spibus; - device_t flash; - char* flash_name; - int err; - - flash_name = NULL; - - if (device_find_child(parent, "spi", -1) != NULL) - return; - - caps = BHND_CHIPC_GET_CAPS(parent); - if (caps == NULL) { - BHND_ERROR_DEV(parent, "can't retrieve ChipCommon capabilities"); - return; - } + struct chipc_spi_softc *sc; + struct chipc_caps *ccaps; + device_t flash_dev; + device_t spibus; + const char *flash_name; + int error; - switch (caps->flash_type) { - case CHIPC_SFLASH_AT: - flash_name = "at45d"; - break; - case CHIPC_SFLASH_ST: - flash_name = "mx25l"; - break; - default: - return; - } + sc = device_get_softc(dev); - spidev = BUS_ADD_CHILD(parent, 0, "spi", -1); - if (spidev == NULL) { - BHND_ERROR_DEV(parent, "can't add chipc_spi to ChipCommon"); - return; + /* Allocate SPI controller registers */ + sc->sc_rid = 1; + sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, + RF_ACTIVE); + if (sc->sc_res == NULL) { + device_printf(dev, "failed to allocate device registers\n"); + return (ENXIO); } - err = device_probe_and_attach(spidev); - if (err) { - BHND_ERROR_DEV(spidev, "failed attach chipc_spi: %d", err); - return; + /* Allocate flash shadow region */ + sc->sc_flash_rid = 0; + sc->sc_flash_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->sc_flash_rid, RF_ACTIVE); + if (sc->sc_flash_res == NULL) { + device_printf(dev, "failed to allocate flash region\n"); + error = ENXIO; + goto failed; } - spibus = device_find_child(spidev, "spibus", -1); - if (spibus == NULL) { - BHND_ERROR_DEV(spidev, "can't find spibus under chipc_spi"); - return; + /* + * Add flash device + * + * XXX: This should be replaced with a DEVICE_IDENTIFY implementation + * in chipc-specific subclasses of the mx25l and at45d drivers. + */ + if ((spibus = device_add_child(dev, "spibus", -1)) == NULL) { + device_printf(dev, "failed to add spibus\n"); + error = ENXIO; + goto failed; } - flash = BUS_ADD_CHILD(spibus, 0, flash_name, -1); - if (flash == NULL) { - BHND_ERROR_DEV(spibus, "can't add %s to spibus", flash_name); - return; + /* Let spibus perform full attach before we try to call + * BUS_ADD_CHILD() */ + if ((error = bus_generic_attach(dev))) + goto failed; + + /* Determine flash type and add the flash child */ + ccaps = BHND_CHIPC_GET_CAPS(device_get_parent(dev)); + flash_name = chipc_sflash_device_name(ccaps->flash_type); + if (flash_name != NULL) { + flash_dev = BUS_ADD_CHILD(spibus, 0, flash_name, -1); + if (flash_dev == NULL) { + device_printf(dev, "failed to add %s\n", flash_name); + error = ENXIO; + goto failed; + } + + chipc_register_slicer(ccaps->flash_type); + + if ((error = device_probe_and_attach(flash_dev))) { + device_printf(dev, "failed to attach %s: %d\n", + flash_name, error); + goto failed; + } } - err = device_probe_and_attach(flash); - if (err) - BHND_ERROR_DEV(flash, "failed attach flash %s: %d", flash_name, - err); + return (0); - return; -} +failed: + device_delete_children(dev); -static int -chipc_spi_probe(device_t dev) -{ - device_set_desc(dev, "ChipCommon SPI"); - return (BUS_PROBE_DEFAULT); -} + if (sc->sc_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, + sc->sc_res); + + if (sc->sc_flash_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_flash_rid, + sc->sc_flash_res); -struct resource_spec spec_mem[] = { - {SYS_RES_MEMORY, 0, RF_ACTIVE}, - {SYS_RES_MEMORY, 1, RF_ACTIVE}, - { -1, -1, 0 } - }; + return (error); +} static int -chipc_spi_attach(device_t dev) +chipc_spi_detach(device_t dev) { - int err; struct chipc_spi_softc *sc; - struct resource *mem[2]; + int error; sc = device_get_softc(dev); - err = bus_alloc_resources(dev, spec_mem, mem); - if (err != 0) - return (ENXIO); - sc->sc_res = mem[0]; - sc->sc_mem_res = mem[1]; + if ((error = bus_generic_detach(dev))) + return (error); - flash_register_slicer(chipc_slicer_spi); - device_add_child(dev, "spibus", 0); - return (bus_generic_attach(dev)); + bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); + bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_flash_rid, + sc->sc_flash_res); + return (0); } static int @@ -184,7 +184,7 @@ if (i > 0) return (0); - BHND_DEBUG_DEV(sc->dev, "busy"); + BHND_DEBUG_DEV(sc->sc_dev, "busy"); return (-1); } @@ -256,13 +256,11 @@ return (0); } -/* - * **************************** METADATA ************************ - */ static device_method_t chipc_spi_methods[] = { - DEVMETHOD(device_identify, chipc_spi_identify), DEVMETHOD(device_probe, chipc_spi_probe), DEVMETHOD(device_attach, chipc_spi_attach), + DEVMETHOD(device_detach, chipc_spi_detach), + /* SPI */ DEVMETHOD(spibus_transfer, chipc_spi_transfer), DEVMETHOD_END @@ -277,4 +275,4 @@ static devclass_t chipc_spi_devclass; DRIVER_MODULE(chipc_spi, bhnd_chipc, chipc_spi_driver, chipc_spi_devclass, - 0, 0); + 0, 0); Index: head/sys/dev/bhnd/cores/chipc/chipc_subr.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_subr.c +++ head/sys/dev/bhnd/cores/chipc/chipc_subr.c @@ -38,6 +38,93 @@ #include "chipcvar.h" /** + * Return a human-readable name for the given flash @p type. + */ +const char * +chipc_flash_name(chipc_flash type) +{ + switch (type) { + case CHIPC_PFLASH_CFI: + return ("CFI Flash"); + + case CHIPC_SFLASH_ST: + case CHIPC_SFLASH_AT: + return ("SPI Flash"); + + case CHIPC_QSFLASH_ST: + case CHIPC_QSFLASH_AT: + return ("QSPI Flash"); + + case CHIPC_NFLASH: + case CHIPC_NFLASH_4706: + return ("NAND"); + + case CHIPC_FLASH_NONE: + default: + return ("unknown"); + } +} + +/** + * Return the name of the bus device class used by flash @p type, + * or NULL if @p type is unsupported. + */ +const char * +chipc_flash_bus_name(chipc_flash type) +{ + switch (type) { + case CHIPC_PFLASH_CFI: + return ("cfi"); + + case CHIPC_SFLASH_ST: + case CHIPC_SFLASH_AT: + return ("spi"); + + case CHIPC_QSFLASH_ST: + case CHIPC_QSFLASH_AT: + /* unimplemented; spi? */ + return (NULL); + + case CHIPC_NFLASH: + case CHIPC_NFLASH_4706: + /* unimplemented; nandbus? */ + return (NULL); + + case CHIPC_FLASH_NONE: + default: + return (NULL); + } +} + +/** + * Return the name of the flash device class for SPI flash @p type, + * or NULL if @p type does not use SPI, or is unsupported. + */ +const char * +chipc_sflash_device_name(chipc_flash type) +{ + switch (type) { + case CHIPC_SFLASH_ST: + return ("mx25l"); + + case CHIPC_SFLASH_AT: + return ("at45d"); + + case CHIPC_QSFLASH_ST: + case CHIPC_QSFLASH_AT: + /* unimplemented */ + return (NULL); + + case CHIPC_PFLASH_CFI: + case CHIPC_NFLASH: + case CHIPC_NFLASH_4706: + case CHIPC_FLASH_NONE: + default: + return (NULL); + } +} + +/** * Initialize child resource @p r with a virtual address, tag, and handle * copied from @p parent, adjusted to contain only the range defined by * @p offsize and @p size. @@ -74,6 +161,72 @@ return (0); } +/** + * Associate a resource with a given resource ID, relative to the given + * port and region. + * + * This function behaves identically to bus_set_resource() for all resource + * types other than SYS_RES_MEMORY. + * + * For SYS_RES_MEMORY resources, the specified @p region's address and size + * will be fetched from the bhnd(4) bus, and bus_set_resource() will be called + * with @p start added the region's actual base address. + * + * To use the default region values for @p start and @p count, specify + * a @p start value of 0ul, and an end value of RMAN_MAX_END + * + * @param sc chipc driver state. + * @param child The device to set the resource on. + * @param type The resource type. + * @param rid The resource ID. + * @param start The resource start address (if SYS_RES_MEMORY, this is + * relative to @p region's base address). + * @param count The length of the resource. + * @param port The mapping port number (ignored if not SYS_RES_MEMORY). + * @param region The mapping region number (ignored if not SYS_RES_MEMORY). + */ +int +chipc_set_resource(struct chipc_softc *sc, device_t child, int type, int rid, + rman_res_t start, rman_res_t count, u_int port, u_int region) +{ + bhnd_addr_t region_addr; + bhnd_size_t region_size; + bool isdefault; + int error; + + if (type != SYS_RES_MEMORY) + return (bus_set_resource(child, type, rid, start, count)); + + isdefault = RMAN_IS_DEFAULT_RANGE(start, count); + + /* Fetch region address and size */ + error = bhnd_get_region_addr(sc->dev, BHND_PORT_DEVICE, port, + region, ®ion_addr, ®ion_size); + if (error) { + device_printf(sc->dev, + "lookup of %s%u.%u failed: %d\n", + bhnd_port_type_name(BHND_PORT_DEVICE), port, region, error); + return (error); + } + + /* Populate defaults */ + if (isdefault) { + start = 0; + count = region_size; + } + + /* Verify requested range is mappable */ + if (start > region_size || region_size - start < count) { + device_printf(sc->dev, + "%s%u.%u region cannot map requested range %#jx+%#jx\n", + bhnd_port_type_name(BHND_PORT_DEVICE), port, region, start, + count); + return (ERANGE); + } + + return (bus_set_resource(child, type, rid, region_addr + start, count)); +} + /* * Print a capability structure. Index: head/sys/dev/bhnd/cores/chipc/chipcreg.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipcreg.h +++ head/sys/dev/bhnd/cores/chipc/chipcreg.h @@ -175,8 +175,8 @@ #define CHIPC_UART_BASE 0x300 #define CHIPC_UART_SIZE 0x100 -#define CHIPC_UART0_BASE CHIPC_UART_BASE -#define CHIPC_UART1_BASE (CHIPC_UART_BASE + CHIPC_UART_SIZE) +#define CHIPC_UART_MAX 3 /**< max UART blocks */ +#define CHIPC_UART(_n) (CHIPC_UART_BASE + (CHIPC_UART_SIZE*_n)) /* PMU registers (rev >= 20) */ #define CHIPC_PMU_BASE 0x600 Index: head/sys/dev/bhnd/cores/chipc/chipcvar.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipcvar.h +++ head/sys/dev/bhnd/cores/chipc/chipcvar.h @@ -59,6 +59,10 @@ CHIPC_NFLASH_4706 = 7 /**< BCM4706 NAND flash */ } chipc_flash; +const char *chipc_flash_name(chipc_flash type); +const char *chipc_flash_bus_name(chipc_flash type); +const char *chipc_sflash_device_name(chipc_flash type); + /** * ChipCommon capability flags; */ @@ -69,15 +73,16 @@ uint8_t uart_gpio; /**< UARTs own GPIO pins 12-15 */ uint8_t extbus_type; /**< ExtBus type (CHIPC_CAP_EXTBUS_*) */ - chipc_flash flash_type; /**< Flash type */ - bhnd_nvram_src nvram_src; /**< identified NVRAM source */ + chipc_flash flash_type; /**< flash type */ + uint8_t cfi_width; /**< CFI bus width, 0 if unknown or CFI + not present */ + + bhnd_nvram_src nvram_src; /**< identified NVRAM source */ bus_size_t sprom_offset; /**< Offset to SPROM data within SPROM/OTP, 0 if unknown or not present */ uint8_t otp_size; /**< OTP (row?) size, 0 if not present */ - uint8_t cfi_width; /**< CFI bus width, 0 if unknown or CFI - not present */ uint8_t pll_type; /**< PLL type */ bool power_control; /**< Power control available */ @@ -200,7 +205,6 @@ struct bhnd_resource *core; /**< core registers. */ struct chipc_region *core_region; /**< region containing core registers */ - struct bhnd_chipid ccid; /**< chip identification */ uint32_t quirks; /**< chipc quirk flags */ struct chipc_caps caps; /**< chipc capabilities */ Index: head/sys/mips/broadcom/uart_bus_chipc.c =================================================================== --- head/sys/mips/broadcom/uart_bus_chipc.c +++ head/sys/mips/broadcom/uart_bus_chipc.c @@ -45,84 +45,29 @@ #include #include -#include - #include "uart_if.h" #include "bhnd_chipc_if.h" +#include "bcm_socinfo.h" -static int uart_chipc_probe(device_t dev); - -extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; - -static void -uart_chipc_identify(driver_t *driver, device_t parent) -{ - struct chipc_caps *caps; - - if (device_find_child(parent, "uart", -1) != NULL) - return; - - caps = BHND_CHIPC_GET_CAPS(parent); - - if (caps == NULL) { - device_printf(parent, "error: can't retrieve ChipCommon " - "capabilities\n"); - return; - } - - if (caps->num_uarts == 0) - return; - - /* - * TODO: add more than one UART - */ - BUS_ADD_CHILD(parent, 0, "uart", -1); -} static int uart_chipc_probe(device_t dev) { struct uart_softc *sc; - struct resource *res; - int rid; - int err; - - rid = 0; - res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (res == NULL) { - device_printf(dev, "can't allocate main resource\n"); - return (ENXIO); - } + struct bcm_socinfo *socinfo; sc = device_get_softc(dev); sc->sc_class = &uart_ns8250_class; - sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); - if (sc->sc_sysdev == NULL) { - device_printf(dev, "missing sysdev\n"); - return (EINVAL); - } - - bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); - - sc->sc_sysdev->bas.bst = rman_get_bustag(res); - sc->sc_sysdev->bas.bsh = rman_get_bushandle(res); - sc->sc_bas.bst = sc->sc_sysdev->bas.bst; - sc->sc_bas.bsh = sc->sc_sysdev->bas.bsh; - - err = bus_release_resource(dev, SYS_RES_MEMORY, rid, res); - if (err) { - device_printf(dev, "can't release resource [%d]\n", rid); - return (ENXIO); - } - /* We use internal SoC clock generator with non-standart freq MHz */ - return (uart_bus_probe(dev, 0, sc->sc_sysdev->bas.rclk, 0, 0)); + /* TODO: UART rate should be calculated from CPU clock speed + * as fetched from bhnd bus */ + socinfo = bcm_get_socinfo(); + return (uart_bus_probe(dev, 0, socinfo->uartrate, 0, 0)); } static device_method_t uart_chipc_methods[] = { /* Device interface */ - DEVMETHOD(device_identify, uart_chipc_identify), DEVMETHOD(device_probe, uart_chipc_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach),