Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/bhnd/cores/chipc/chipc.c
| Show All 31 Lines | |||||
| __FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
| /* | /* | ||||
| * Broadcom ChipCommon driver. | * Broadcom ChipCommon driver. | ||||
| * | * | ||||
| * With the exception of some very early chipsets, the ChipCommon core | * 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) | * has been included in all HND SoCs and chipsets based on the siba(4) | ||||
| * and bcma(4) interconnects, providing a common interface to chipset | * and bcma(4) interconnects, providing a common interface to chipset | ||||
| * identification, bus enumeration, UARTs, clocks, watchdog interrupts, GPIO, | * identification, bus enumeration, UARTs, clocks, watchdog interrupts, | ||||
| * flash, etc. | * 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) | | |||||
| * ------------------------------------------------------ | |||||
| */ | */ | ||||
| #include <sys/param.h> | #include <sys/param.h> | ||||
| #include <sys/kernel.h> | #include <sys/kernel.h> | ||||
| #include <sys/lock.h> | #include <sys/lock.h> | ||||
| #include <sys/bus.h> | #include <sys/bus.h> | ||||
| #include <sys/rman.h> | #include <sys/rman.h> | ||||
| #include <sys/malloc.h> | #include <sys/malloc.h> | ||||
| #include <sys/module.h> | #include <sys/module.h> | ||||
| #include <sys/mutex.h> | #include <sys/mutex.h> | ||||
| #include <sys/systm.h> | #include <sys/systm.h> | ||||
| #include <machine/bus.h> | #include <machine/bus.h> | ||||
| #include <machine/resource.h> | #include <machine/resource.h> | ||||
| #include <dev/bhnd/bhnd.h> | #include <dev/bhnd/bhnd.h> | ||||
| #include <dev/bhnd/bhndvar.h> | #include <dev/bhnd/bhndvar.h> | ||||
| #include "chipcreg.h" | #include "chipcreg.h" | ||||
| #include "chipcvar.h" | #include "chipcvar.h" | ||||
| #include "chipc_private.h" | #include "chipc_private.h" | ||||
| devclass_t bhnd_chipc_devclass; /**< bhnd(4) chipcommon device class */ | devclass_t bhnd_chipc_devclass; /**< bhnd(4) chipcommon device class */ | ||||
| static struct bhnd_device_quirk chipc_quirks[]; | static struct bhnd_device_quirk chipc_quirks[]; | ||||
| /* Supported device identifiers */ | /* Supported device identifiers */ | ||||
| static const struct bhnd_device chipc_devices[] = { | static const struct bhnd_device chipc_devices[] = { | ||||
| Show All 31 Lines | static struct bhnd_device_quirk chipc_quirks[] = { | ||||
| BHND_CHIP_QUIRK (4352, HWREV_LTE(2), CHIPC_QUIRK_4360_FEM_MUX_SPROM), | BHND_CHIP_QUIRK (4352, HWREV_LTE(2), CHIPC_QUIRK_4360_FEM_MUX_SPROM), | ||||
| BHND_CHIP_QUIRK (43460, HWREV_LTE(2), CHIPC_QUIRK_4360_FEM_MUX_SPROM), | BHND_CHIP_QUIRK (43460, HWREV_LTE(2), CHIPC_QUIRK_4360_FEM_MUX_SPROM), | ||||
| BHND_CHIP_QUIRK (43462, HWREV_LTE(2), CHIPC_QUIRK_4360_FEM_MUX_SPROM), | BHND_CHIP_QUIRK (43462, HWREV_LTE(2), CHIPC_QUIRK_4360_FEM_MUX_SPROM), | ||||
| BHND_CHIP_QUIRK (43602, HWREV_LTE(2), CHIPC_QUIRK_4360_FEM_MUX_SPROM), | BHND_CHIP_QUIRK (43602, HWREV_LTE(2), CHIPC_QUIRK_4360_FEM_MUX_SPROM), | ||||
| BHND_DEVICE_QUIRK_END | BHND_DEVICE_QUIRK_END | ||||
| }; | }; | ||||
| // FIXME: IRQ shouldn't be hard-coded | |||||
| #define CHIPC_MIPS_IRQ 2 | |||||
| /* | static int chipc_add_children(struct chipc_softc *sc); | ||||
| * 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 bhnd_nvram_src chipc_find_nvram_src(struct chipc_softc *sc, | static bhnd_nvram_src chipc_find_nvram_src(struct chipc_softc *sc, | ||||
| struct chipc_caps *caps); | struct chipc_caps *caps); | ||||
| static int chipc_read_caps(struct chipc_softc *sc, | static int chipc_read_caps(struct chipc_softc *sc, | ||||
| struct chipc_caps *caps); | struct chipc_caps *caps); | ||||
| static bool chipc_should_enable_sprom( | static bool chipc_should_enable_sprom( | ||||
| struct chipc_softc *sc); | 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 int chipc_init_rman(struct chipc_softc *sc); | ||||
| static void chipc_free_rman(struct chipc_softc *sc); | static void chipc_free_rman(struct chipc_softc *sc); | ||||
| static struct rman *chipc_get_rman(struct chipc_softc *sc, | static struct rman *chipc_get_rman(struct chipc_softc *sc, | ||||
| int type); | int type); | ||||
| /* quirk and capability flag convenience macros */ | /* quirk and capability flag convenience macros */ | ||||
| #define CHIPC_QUIRK(_sc, _name) \ | #define CHIPC_QUIRK(_sc, _name) \ | ||||
| ((_sc)->quirks & CHIPC_QUIRK_ ## _name) | ((_sc)->quirks & CHIPC_QUIRK_ ## _name) | ||||
| Show All 19 Lines | chipc_probe(device_t dev) | ||||
| bhnd_set_default_core_desc(dev); | bhnd_set_default_core_desc(dev); | ||||
| return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
| } | } | ||||
| static int | static int | ||||
| chipc_attach(device_t dev) | chipc_attach(device_t dev) | ||||
| { | { | ||||
| struct chipc_softc *sc; | struct chipc_softc *sc; | ||||
| bhnd_addr_t enum_addr; | |||||
| uint32_t ccid_reg; | |||||
| uint8_t chip_type; | |||||
| int error; | int error; | ||||
| sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
| sc->dev = dev; | sc->dev = dev; | ||||
| sc->quirks = bhnd_device_quirks(dev, chipc_devices, | sc->quirks = bhnd_device_quirks(dev, chipc_devices, | ||||
| sizeof(chipc_devices[0])); | sizeof(chipc_devices[0])); | ||||
| sc->sprom_refcnt = 0; | sc->sprom_refcnt = 0; | ||||
| CHIPC_LOCK_INIT(sc); | CHIPC_LOCK_INIT(sc); | ||||
| STAILQ_INIT(&sc->mem_regions); | STAILQ_INIT(&sc->mem_regions); | ||||
| /* Set up resource management */ | /* Set up resource management */ | ||||
| if ((error = chipc_init_rman(sc))) { | if ((error = chipc_init_rman(sc))) { | ||||
| device_printf(sc->dev, | device_printf(sc->dev, | ||||
| "failed to initialize chipc resource state: %d\n", error); | "failed to initialize chipc resource state: %d\n", error); | ||||
| goto failed; | 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) { | if ((sc->core_region = chipc_find_region_by_rid(sc, 0)) == NULL) { | ||||
| error = ENXIO; | error = ENXIO; | ||||
| goto failed; | goto failed; | ||||
| } | } | ||||
| error = chipc_retain_region(sc, sc->core_region, | error = chipc_retain_region(sc, sc->core_region, | ||||
| RF_ALLOCATED|RF_ACTIVE); | RF_ALLOCATED|RF_ACTIVE); | ||||
| if (error) { | if (error) { | ||||
| sc->core_region = NULL; | sc->core_region = NULL; | ||||
| goto failed; | goto failed; | ||||
| } else { | |||||
| sc->core = sc->core_region->cr_res; | |||||
| } | } | ||||
| /* Fetch our chipset identification data */ | /* Save a direct reference to our chipc registers */ | ||||
| ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID); | sc->core = sc->core_region->cr_res; | ||||
| 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); | |||||
| /* Fetch and parse capability register(s) */ | /* Fetch and parse capability register(s) */ | ||||
| if ((error = chipc_read_caps(sc, &sc->caps))) | if ((error = chipc_read_caps(sc, &sc->caps))) | ||||
| goto failed; | goto failed; | ||||
| if (bootverbose) | if (bootverbose) | ||||
| chipc_print_caps(sc->dev, &sc->caps); | chipc_print_caps(sc->dev, &sc->caps); | ||||
| /* Probe and attach children */ | /* Attach all supported child devices */ | ||||
| bus_generic_probe(dev); | if ((error = chipc_add_children(sc))) | ||||
| goto failed; | |||||
| if ((error = bus_generic_attach(dev))) | if ((error = bus_generic_attach(dev))) | ||||
| goto failed; | goto failed; | ||||
| return (0); | return (0); | ||||
| failed: | failed: | ||||
| device_delete_children(sc->dev); | device_delete_children(sc->dev); | ||||
| Show All 21 Lines | chipc_detach(device_t dev) | ||||
| chipc_release_region(sc, sc->core_region, RF_ALLOCATED|RF_ACTIVE); | chipc_release_region(sc, sc->core_region, RF_ALLOCATED|RF_ACTIVE); | ||||
| chipc_free_rman(sc); | chipc_free_rman(sc); | ||||
| CHIPC_LOCK_DESTROY(sc); | CHIPC_LOCK_DESTROY(sc); | ||||
| return (0); | 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); | |||||
| } | |||||
mizhka: BTW, it may be more straigthforward to define 2 different resources (RID=0 / RID=1), isn't it? | |||||
| 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. | * Determine the NVRAM data source for this device. | ||||
| * | * | ||||
| * The SPROM, OTP, and flash capability flags must be fully populated in | * The SPROM, OTP, and flash capability flags must be fully populated in | ||||
| * @p caps. | * @p caps. | ||||
| * | * | ||||
| * @param sc chipc driver state. | * @param sc chipc driver state. | ||||
| * @param caps capability flags to be used to derive NVRAM configuration. | * @param caps capability flags to be used to derive NVRAM configuration. | ||||
| ▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps) | ||||
| /* Fetch OTP size for later IPX controller revisions */ | /* Fetch OTP size for later IPX controller revisions */ | ||||
| if (CHIPC_QUIRK(sc, IPX_OTPL_SIZE)) { | if (CHIPC_QUIRK(sc, IPX_OTPL_SIZE)) { | ||||
| regval = bhnd_bus_read_4(sc->core, CHIPC_OTPLAYOUT); | regval = bhnd_bus_read_4(sc->core, CHIPC_OTPLAYOUT); | ||||
| caps->otp_size = CHIPC_GET_BITS(regval, CHIPC_OTPL_SIZE); | caps->otp_size = CHIPC_GET_BITS(regval, CHIPC_OTPL_SIZE); | ||||
| } | } | ||||
| /* Determine flash type and parameters */ | /* Determine flash type and parameters */ | ||||
| caps->cfi_width = 0; | caps->cfi_width = 0; | ||||
| switch (CHIPC_GET_BITS(cap_reg, CHIPC_CAP_FLASH)) { | switch (CHIPC_GET_BITS(cap_reg, CHIPC_CAP_FLASH)) { | ||||
| case CHIPC_CAP_SFLASH_ST: | case CHIPC_CAP_SFLASH_ST: | ||||
| caps->flash_type = CHIPC_SFLASH_ST; | caps->flash_type = CHIPC_SFLASH_ST; | ||||
| break; | break; | ||||
| case CHIPC_CAP_SFLASH_AT: | case CHIPC_CAP_SFLASH_AT: | ||||
| caps->flash_type = CHIPC_SFLASH_AT; | caps->flash_type = CHIPC_SFLASH_AT; | ||||
| break; | break; | ||||
| case CHIPC_CAP_NFLASH: | case CHIPC_CAP_NFLASH: | ||||
| /* unimplemented */ | |||||
| caps->flash_type = CHIPC_NFLASH; | caps->flash_type = CHIPC_NFLASH; | ||||
| break; | break; | ||||
| case CHIPC_CAP_PFLASH: | case CHIPC_CAP_PFLASH: | ||||
| caps->flash_type = CHIPC_PFLASH_CFI; | caps->flash_type = CHIPC_PFLASH_CFI; | ||||
| /* determine cfi width */ | /* determine cfi width */ | ||||
| regval = bhnd_bus_read_4(sc->core, CHIPC_FLASH_CFG); | regval = bhnd_bus_read_4(sc->core, CHIPC_FLASH_CFG); | ||||
| if (CHIPC_GET_FLAG(regval, CHIPC_FLASH_CFG_DS)) | if (CHIPC_GET_FLAG(regval, CHIPC_FLASH_CFG_DS)) | ||||
| ▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | chipc_child_location_str(device_t dev, device_t child, char *buf, | ||||
| *buf = '\0'; | *buf = '\0'; | ||||
| return (ENXIO); | return (ENXIO); | ||||
| } | } | ||||
| static device_t | static device_t | ||||
| chipc_add_child(device_t dev, u_int order, const char *name, int unit) | chipc_add_child(device_t dev, u_int order, const char *name, int unit) | ||||
| { | { | ||||
| struct chipc_softc *sc; | |||||
| struct chipc_devinfo *dinfo; | struct chipc_devinfo *dinfo; | ||||
| const struct chipc_hint *hint; | |||||
| device_t child; | 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); | child = device_add_child_ordered(dev, order, name, unit); | ||||
| if (child == NULL) | if (child == NULL) | ||||
| return (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); | dinfo = malloc(sizeof(struct chipc_devinfo), M_BHND, M_NOWAIT); | ||||
| if (dinfo == NULL) { | if (dinfo == NULL) { | ||||
| device_delete_child(dev, child); | device_delete_child(dev, child); | ||||
| return (NULL); | return (NULL); | ||||
| } | } | ||||
| resource_list_init(&dinfo->resources); | resource_list_init(&dinfo->resources); | ||||
| device_set_ivars(child, dinfo); | device_set_ivars(child, dinfo); | ||||
| /* Hint matching requires a device name */ | |||||
| if (name == NULL) | |||||
| return (child); | 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 | static void | ||||
| chipc_child_deleted(device_t dev, device_t child) | chipc_child_deleted(device_t dev, device_t child) | ||||
| { | { | ||||
| struct chipc_devinfo *dinfo = device_get_ivars(child); | struct chipc_devinfo *dinfo = device_get_ivars(child); | ||||
| if (dinfo != NULL) { | if (dinfo != NULL) { | ||||
| resource_list_free(&dinfo->resources); | resource_list_free(&dinfo->resources); | ||||
| free(dinfo, M_BHND); | free(dinfo, M_BHND); | ||||
| Show All 16 Lines | |||||
| chipc_rman_init_regions (struct chipc_softc *sc, bhnd_port_type type, | chipc_rman_init_regions (struct chipc_softc *sc, bhnd_port_type type, | ||||
| u_int port) | u_int port) | ||||
| { | { | ||||
| struct chipc_region *cr; | struct chipc_region *cr; | ||||
| rman_res_t start, end; | rman_res_t start, end; | ||||
| u_int num_regions; | u_int num_regions; | ||||
| int error; | 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++) { | for (u_int region = 0; region < num_regions; region++) { | ||||
| /* Allocate new region record */ | /* Allocate new region record */ | ||||
| cr = chipc_alloc_region(sc, type, port, region); | cr = chipc_alloc_region(sc, type, port, region); | ||||
| if (cr == NULL) | if (cr == NULL) | ||||
| return (ENODEV); | return (ENODEV); | ||||
| /* Can't manage regions that cannot be allocated */ | /* Can't manage regions that cannot be allocated */ | ||||
| if (cr->cr_rid < 0) { | if (cr->cr_rid < 0) { | ||||
| ▲ Show 20 Lines • Show All 627 Lines • ▼ Show 20 Lines | |||||
| chipc_get_caps(device_t dev) | chipc_get_caps(device_t dev) | ||||
| { | { | ||||
| struct chipc_softc *sc; | struct chipc_softc *sc; | ||||
| sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
| return (&sc->caps); | 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[] = { | static device_method_t chipc_methods[] = { | ||||
| /* Device interface */ | /* Device interface */ | ||||
| DEVMETHOD(device_probe, chipc_probe), | DEVMETHOD(device_probe, chipc_probe), | ||||
| DEVMETHOD(device_attach, chipc_attach), | DEVMETHOD(device_attach, chipc_attach), | ||||
| DEVMETHOD(device_detach, chipc_detach), | DEVMETHOD(device_detach, chipc_detach), | ||||
| DEVMETHOD(device_suspend, chipc_suspend), | DEVMETHOD(device_suspend, chipc_suspend), | ||||
| DEVMETHOD(device_resume, chipc_resume), | DEVMETHOD(device_resume, chipc_resume), | ||||
| Show All 25 Lines | static device_method_t chipc_methods[] = { | ||||
| /* BHND bus inteface */ | /* BHND bus inteface */ | ||||
| DEVMETHOD(bhnd_bus_activate_resource, chipc_activate_bhnd_resource), | DEVMETHOD(bhnd_bus_activate_resource, chipc_activate_bhnd_resource), | ||||
| /* ChipCommon interface */ | /* ChipCommon interface */ | ||||
| DEVMETHOD(bhnd_chipc_write_chipctrl, chipc_write_chipctrl), | DEVMETHOD(bhnd_chipc_write_chipctrl, chipc_write_chipctrl), | ||||
| DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom_pins), | DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom_pins), | ||||
| DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom_pins), | DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom_pins), | ||||
| DEVMETHOD(bhnd_chipc_get_caps, chipc_get_caps), | DEVMETHOD(bhnd_chipc_get_caps, chipc_get_caps), | ||||
| DEVMETHOD(bhnd_chipc_get_flash_cfg, chipc_get_flash_cfg), | |||||
| DEVMETHOD_END | DEVMETHOD_END | ||||
| }; | }; | ||||
| DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc)); | DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc)); | ||||
| EARLY_DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0, | EARLY_DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0, | ||||
| BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); | BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); | ||||
| MODULE_DEPEND(bhnd_chipc, bhnd, 1, 1, 1); | MODULE_DEPEND(bhnd_chipc, bhnd, 1, 1, 1); | ||||
| MODULE_VERSION(bhnd_chipc, 1); | MODULE_VERSION(bhnd_chipc, 1); | ||||
BTW, it may be more straigthforward to define 2 different resources (RID=0 / RID=1), isn't it?