/** * Populate platform configuration data. */ static int bcm_init_platform_data(struct bcm_platform *bp) { bus_addr_t bus_addr, bus_size; bus_space_tag_t erom_bst; bus_space_handle_t erom_bsh; bool aob, pmu; int error; bus_addr = bcm_get_bus_addr(); bus_size = bcm_get_bus_size(); #ifdef CFE /* Fetch CFE console handle (if any). Must be initialized before * any calls to printf/early_putc. */ if ((bp->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0) bp->cfe_console = -1; /* Probe CFE NVRAM sources */ bp->nvram_io = &bcm_cfe_nvram.io; error = bcm_nvram_find_cfedev(&bcm_cfe_nvram, &bp->nvram_cls); if (error) { bp->nvram_io = NULL; bp->nvram_cls = NULL; } #endif /* CFE */ /* Probe and attach device table provider, populating our * chip identification */ erom_bst = mips_bus_space_generic; erom_bsh = BCM_SOC_BSH(bus_addr, 0); error = bhnd_erom_iobus_init(&bp->erom_io, bus_addr, bus_size, erom_bst, erom_bsh); if (error) { BCM_ERR("failed to initialize erom I/O callbacks: %d\n", error); return (error); } error = bcm_erom_probe_and_attach(&bp->erom_impl, &bp->erom_ops, &bp->erom.obj, sizeof(bp->erom), &bp->erom_io.eio, &bp->cid); if (error) { BCM_ERR("error attaching erom parser: %d\n", error); bhnd_erom_io_fini(&bp->erom_io.eio); return (error); } if (bootverbose) bhnd_erom_dump(&bp->erom.obj); /* Fetch chipcommon core info */ error = bcm_find_core(bp, bcm_chipc_cores, nitems(bcm_chipc_cores), &bp->cc_id, &bp->cc_addr); if (error) { BCM_ERR("error locating chipc core: %d\n", error); return (error); } /* Fetch chipc capability flags */ bp->cc_caps = BCM_SOC_READ_4(bp->cc_addr, CHIPC_CAPABILITIES); bp->cc_caps_ext = 0x0; if (CHIPC_HWREV_HAS_CAP_EXT(bp->cc_id.hwrev)) bp->cc_caps_ext = BCM_CHIPC_READ_4(bp, CHIPC_CAPABILITIES_EXT); /* Fetch PMU info */ pmu = CHIPC_GET_FLAG(bp->cc_caps, CHIPC_CAP_PMU); aob = CHIPC_GET_FLAG(bp->cc_caps_ext, CHIPC_CAP2_AOB); if (pmu && aob) { /* PMU block mapped to a PMU core on the Always-on-Bus (aob) */ error = bcm_find_core(bp, bcm_pmu_cores, nitems(bcm_pmu_cores), &bp->pmu_id, &bp->pmu_addr); if (error) { BCM_ERR("error locating pmu core: %d\n", error); return (error); } } else if (pmu) { /* PMU block mapped to chipc */ bp->pmu_addr = bp->cc_addr; bp->pmu_id = bp->cc_id; } else { /* No PMU */ bp->pmu_addr = 0x0; memset(&bp->pmu_id, 0, sizeof(bp->pmu_id)); } /* Initialize PMU query state */ if (pmu) { error = bhnd_pmu_query_init(&bp->pmu, NULL, bp->cid, &bcm_pmu_soc_io, bp); if (error) { BCM_ERR("bhnd_pmu_query_init() failed: %d\n", error); return (error); } } /* Find CPU core info */ error = bcm_find_core(bp, bcm_cpu0_cores, nitems(bcm_cpu0_cores), &bp->cpu_id, &bp->cpu_addr); if (error) { BCM_ERR("error locating CPU core: %d\n", error); return (error); } /* Initialize our platform service registry */ if ((error = bhnd_service_registry_init(&bp->services))) { BCM_ERR("error initializing service registry: %d\n", error); return (error); } bcm_platform_data_avail = true; return (0); }
/** * Default bhnd_pmu driver implementation of DEVICE_ATTACH(). * * @param dev PMU device. * @param res The PMU device registers. The driver will maintain a borrowed * reference to this resource for the lifetime of the device. */ int bhnd_pmu_attach(device_t dev, struct bhnd_resource *res) { struct bhnd_pmu_softc *sc; struct sysctl_ctx_list *ctx; struct sysctl_oid *tree; devclass_t bhnd_class; device_t core, bus; int error; sc = device_get_softc(dev); sc->dev = dev; sc->quirks = 0; sc->res = res; /* Fetch capability flags */ sc->caps = bhnd_bus_read_4(sc->res, BHND_PMU_CAP); /* Find the bus-attached core */ bhnd_class = devclass_find("bhnd"); core = sc->dev; while ((bus = device_get_parent(core)) != NULL) { if (device_get_devclass(bus) == bhnd_class) break; core = bus; } if (core == NULL) { device_printf(sc->dev, "bhnd bus not found\n"); return (ENXIO); } /* Fetch chip and board info */ sc->cid = *bhnd_get_chipid(core); if ((error = bhnd_read_board_info(core, &sc->board))) { device_printf(sc->dev, "error fetching board info: %d\n", error); return (ENXIO); } /* Locate ChipCommon device */ sc->chipc_dev = bhnd_find_child(bus, BHND_DEVCLASS_CC, 0); if (sc->chipc_dev == NULL) { device_printf(sc->dev, "chipcommon device not found\n"); return (ENXIO); } /* Initialize query state */ error = bhnd_pmu_query_init(&sc->query, dev, sc->cid, &bhnd_pmu_res_io, sc); if (error) return (error); sc->io = sc->query.io; sc->io_ctx = sc->query.io_ctx; BPMU_LOCK_INIT(sc); /* Set quirk flags */ switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4328: case BHND_CHIPID_BCM5354: /* HTAVAIL/ALPAVAIL are bitswapped in CLKCTL */ sc->quirks |= BPMU_QUIRK_CLKCTL_CCS0; break; default: break; } /* Initialize PMU */ if ((error = bhnd_pmu_init(sc))) { device_printf(sc->dev, "PMU init failed: %d\n", error); goto failed; } /* Set up sysctl nodes */ ctx = device_get_sysctl_ctx(dev); tree = device_get_sysctl_tree(dev); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "bus_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0, bhnd_pmu_sysctl_bus_freq, "IU", "Bus clock frequency"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "cpu_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0, bhnd_pmu_sysctl_cpu_freq, "IU", "CPU clock frequency"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "mem_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0, bhnd_pmu_sysctl_mem_freq, "IU", "Memory clock frequency"); return (0); failed: BPMU_LOCK_DESTROY(sc); bhnd_pmu_query_fini(&sc->query); return (error); }