Date: Wed, 22 Nov 2017 20:27:46 +0000 (UTC) From: "Landon J. Fuller" <landonf@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r326102 - in head/sys: conf dev/bhnd dev/bhnd/bcma dev/bhnd/bhndb dev/bhnd/cores/chipc dev/bhnd/cores/chipc/pwrctl dev/bhnd/cores/pmu dev/bhnd/siba mips/broadcom modules/bhnd modules/bh... Message-ID: <201711222027.vAMKRkTc077837@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: landonf Date: Wed Nov 22 20:27:46 2017 New Revision: 326102 URL: https://svnweb.freebsd.org/changeset/base/326102 Log: bhnd(4): extend the PMU APIs to support bwn(4) The bwn(4) driver requires a number of extensions to the bhnd(4) PMU interface to support external configuration of PLLs, LDOs, and other parameters that require chipset or PHY-specific workarounds. These changes add support for: - Writing raw voltage register values to PHY-specific LDO regulator registers (required by LP-PHY). - Enabling/disabling PHY-specific LDOs (required by LP-PHY) - Writing to arbitrary PMU chipctrl registers (required for common PHY PLL reset support). - Requesting chipset/PLL-specific spurious signal avoidance modes. - Querying clock frequency and latency. Additionally, rather than updating legacy PWRCTL support to conform to the new PMU interface: - PWRCTL API is now provided by a bhnd_pwrctl_if.m interface. - Since PWRCTL is only found in older SSB-based chipsets, translation from bhnd(4) bus APIs to corresponding PWRCTL operations is now handled entirely within the siba(4) driver. - The PWRCTL-specific host bridge clock gating APIs in bhnd_bus_if.m have been lifted out into a standalone bhnd_pwrctl_hostb_if.m interface. Approved by: adrian (mentor, implicit) Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D12664 Added: head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h (contents, props changed) head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_hostb_if.m (contents, props changed) head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_if.m (contents, props changed) head/sys/dev/bhnd/cores/pmu/bhnd_pmu_types.h (contents, props changed) Modified: head/sys/conf/files head/sys/dev/bhnd/bcma/bcma.c head/sys/dev/bhnd/bcma/bcmavar.h head/sys/dev/bhnd/bhnd.c head/sys/dev/bhnd/bhnd.h head/sys/dev/bhnd/bhnd_bus_if.m head/sys/dev/bhnd/bhnd_private.h head/sys/dev/bhnd/bhnd_subr.c head/sys/dev/bhnd/bhnd_types.h head/sys/dev/bhnd/bhndb/bhnd_bhndb.c head/sys/dev/bhnd/bhndb/bhndb_pci.c head/sys/dev/bhnd/bhndreg.h head/sys/dev/bhnd/bhndvar.h head/sys/dev/bhnd/cores/chipc/chipc.c head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c head/sys/dev/bhnd/cores/pmu/bhnd_pmu.c head/sys/dev/bhnd/cores/pmu/bhnd_pmu.h head/sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c head/sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m head/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c head/sys/dev/bhnd/cores/pmu/bhnd_pmureg.h head/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h head/sys/dev/bhnd/siba/siba.c head/sys/dev/bhnd/siba/siba_bhndb.c head/sys/dev/bhnd/siba/siba_subr.c head/sys/dev/bhnd/siba/sibavar.h head/sys/mips/broadcom/siba_nexus.c head/sys/modules/bhnd/Makefile head/sys/modules/bhnd/bhndb/Makefile head/sys/modules/bhnd/bhndb_pci/Makefile head/sys/modules/bhnd/siba/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Wed Nov 22 19:58:29 2017 (r326101) +++ head/sys/conf/files Wed Nov 22 20:27:46 2017 (r326102) @@ -1250,6 +1250,8 @@ dev/bhnd/cores/chipc/chipc_slicer.c optional bhnd cfi dev/bhnd/cores/chipc/chipc_spi.c optional bhnd spibus dev/bhnd/cores/chipc/chipc_subr.c optional bhnd dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c optional bhnd +dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_if.m optional bhnd +dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_hostb_if.m optional bhnd dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c optional bhnd dev/bhnd/cores/pci/bhnd_pci.c optional bhnd pci dev/bhnd/cores/pci/bhnd_pci_hostb.c optional bhndb bhnd pci Modified: head/sys/dev/bhnd/bcma/bcma.c ============================================================================== --- head/sys/dev/bhnd/bcma/bcma.c Wed Nov 22 19:58:29 2017 (r326101) +++ head/sys/dev/bhnd/bcma/bcma.c Wed Nov 22 20:27:46 2017 (r326102) @@ -193,7 +193,7 @@ bcma_write_ivar(device_t dev, device_t child, int inde case BHND_IVAR_CORE_UNIT: return (EINVAL); case BHND_IVAR_PMU_INFO: - dinfo->pmu_info = (struct bhnd_core_pmu_info *) value; + dinfo->pmu_info = (void *)value; return (0); default: return (ENOENT); @@ -349,17 +349,15 @@ bcma_reset_hw(device_t dev, device_t child, uint16_t i static int bcma_suspend_hw(device_t dev, device_t child) { - struct bcma_devinfo *dinfo; - struct bhnd_core_pmu_info *pm; - struct bhnd_resource *r; - uint32_t rst; - int error; + struct bcma_devinfo *dinfo; + struct bhnd_resource *r; + uint32_t rst; + int error; if (device_get_parent(child) != dev) return (EINVAL); dinfo = device_get_ivars(child); - pm = dinfo->pmu_info; /* Can't suspend the core without access to the agent registers */ if ((r = dinfo->res_agent) == NULL) @@ -381,12 +379,6 @@ bcma_suspend_hw(device_t dev, device_t child) /* Clear core flags */ if ((error = bhnd_write_ioctl(child, 0x0, UINT16_MAX))) return (error); - - /* Inform PMU that all outstanding request state should be discarded */ - if (pm != NULL) { - if ((error = BHND_PMU_CORE_RELEASE(pm->pm_pmu, pm))) - return (error); - } return (0); } Modified: head/sys/dev/bhnd/bcma/bcmavar.h ============================================================================== --- head/sys/dev/bhnd/bcma/bcmavar.h Wed Nov 22 19:58:29 2017 (r326101) +++ head/sys/dev/bhnd/bcma/bcmavar.h Wed Nov 22 20:27:46 2017 (r326102) @@ -175,17 +175,17 @@ struct bcma_corecfg { * BCMA per-device info */ struct bcma_devinfo { - struct resource_list resources; /**< Slave port memory regions. */ - struct bcma_corecfg *corecfg; /**< IP core/block config */ + struct resource_list resources; /**< Slave port memory regions. */ + struct bcma_corecfg *corecfg; /**< IP core/block config */ - struct bhnd_resource *res_agent; /**< Agent (wrapper) resource, or NULL. Not - * all bcma(4) cores have or require an agent. */ - int rid_agent; /**< Agent resource ID, or -1 */ + struct bhnd_resource *res_agent; /**< Agent (wrapper) resource, or NULL. Not + * all bcma(4) cores have or require an agent. */ + int rid_agent; /**< Agent resource ID, or -1 */ - u_int num_intrs; /**< number of interrupt descriptors. */ - struct bcma_intr_list intrs; /**< interrupt descriptors */ + u_int num_intrs; /**< number of interrupt descriptors. */ + struct bcma_intr_list intrs; /**< interrupt descriptors */ - struct bhnd_core_pmu_info *pmu_info; /**< Bus-managed PMU state, or NULL */ + void *pmu_info; /**< Bus-managed PMU state, or NULL */ }; Modified: head/sys/dev/bhnd/bhnd.c ============================================================================== --- head/sys/dev/bhnd/bhnd.c Wed Nov 22 19:58:29 2017 (r326101) +++ head/sys/dev/bhnd/bhnd.c Wed Nov 22 20:27:46 2017 (r326102) @@ -62,15 +62,13 @@ __FBSDID("$FreeBSD$"); #include <sys/rman.h> #include <machine/resource.h> -#include <dev/bhnd/cores/chipc/chipcvar.h> - #include <dev/bhnd/cores/pmu/bhnd_pmu.h> -#include <dev/bhnd/cores/pmu/bhnd_pmureg.h> #include "bhnd_chipc_if.h" #include "bhnd_nvram_if.h" #include "bhnd.h" +#include "bhndreg.h" #include "bhndvar.h" #include "bhnd_private.h" @@ -363,24 +361,28 @@ int bhnd_generic_alloc_pmu(device_t dev, device_t child) { struct bhnd_softc *sc; - struct bhnd_resource *br; - struct bhnd_core_pmu_info *pm; + struct bhnd_resource *r; + struct bhnd_core_clkctl *clkctl; struct resource_list *rl; struct resource_list_entry *rle; device_t pmu_dev; bhnd_addr_t r_addr; bhnd_size_t r_size; bus_size_t pmu_regs; + u_int max_latency; int error; GIANT_REQUIRED; /* for newbus */ - + + if (device_get_parent(child) != dev) + return (EINVAL); + sc = device_get_softc(dev); - pm = bhnd_get_pmu_info(child); + clkctl = bhnd_get_pmu_info(child); pmu_regs = BHND_CLK_CTL_ST; /* already allocated? */ - if (pm != NULL) { + if (clkctl != NULL) { panic("duplicate PMU allocation for %s", device_get_nameunit(child)); } @@ -440,36 +442,38 @@ bhnd_generic_alloc_pmu(device_t dev, device_t child) else pmu_regs -= r_addr - rman_get_start(rle->res); - /* Retain PMU reference on behalf of our caller */ + /* Retain a PMU reference for the clkctl instance state */ pmu_dev = bhnd_retain_provider(child, BHND_SERVICE_PMU); if (pmu_dev == NULL) { - device_printf(sc->dev, - "pmu unavailable; cannot allocate request state\n"); + device_printf(sc->dev, "PMU not found\n"); return (ENXIO); } - /* Allocate and initialize PMU info */ - br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT); - if (br == NULL) { + /* Fetch the maximum transition latency from our PMU */ + max_latency = bhnd_pmu_get_max_transition_latency(pmu_dev); + + /* Allocate a new bhnd_resource wrapping the standard resource we + * fetched from the resource list; we'll free this in + * bhnd_generic_release_pmu() */ + r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT); + if (r == NULL) { bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU); return (ENOMEM); } - br->res = rle->res; - br->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0); + r->res = rle->res; + r->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0); - pm = malloc(sizeof(*pm), M_BHND, M_NOWAIT); - if (pm == NULL) { + /* Allocate the clkctl instance */ + clkctl = bhnd_alloc_core_clkctl(child, pmu_dev, r, pmu_regs, + max_latency); + if (clkctl == NULL) { + free(r, M_BHND); bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU); - free(br, M_BHND); return (ENOMEM); } - pm->pm_dev = child; - pm->pm_res = br; - pm->pm_regs = pmu_regs; - pm->pm_pmu = pmu_dev; - bhnd_set_pmu_info(child, pm); + bhnd_set_pmu_info(child, clkctl); return (0); } @@ -479,48 +483,148 @@ bhnd_generic_alloc_pmu(device_t dev, device_t child) int bhnd_generic_release_pmu(device_t dev, device_t child) { - struct bhnd_softc *sc; - struct bhnd_core_pmu_info *pm; - int error; + struct bhnd_softc *sc; + struct bhnd_core_clkctl *clkctl; + struct bhnd_resource *r; + device_t pmu_dev; GIANT_REQUIRED; /* for newbus */ sc = device_get_softc(dev); - /* dispatch release request */ - pm = bhnd_get_pmu_info(child); - if (pm == NULL) + if (device_get_parent(child) != dev) + return (EINVAL); + + clkctl = bhnd_get_pmu_info(child); + if (clkctl == NULL) panic("pmu over-release for %s", device_get_nameunit(child)); - if ((error = BHND_PMU_CORE_RELEASE(pm->pm_pmu, pm))) - return (error); + /* Clear all FORCE, AREQ, and ERSRC flags, unless we're already in + * RESET. Suspending a core clears clkctl automatically (and attempting + * to access the PMU registers in a suspended core will trigger a + * system livelock). */ + if (!bhnd_is_hw_suspended(clkctl->cc_dev)) { + BHND_CLKCTL_LOCK(clkctl); - /* free PMU info */ + /* Clear all FORCE, AREQ, and ERSRC flags */ + BHND_CLKCTL_SET_4(clkctl, 0x0, BHND_CCS_FORCE_MASK | + BHND_CCS_AREQ_MASK | BHND_CCS_ERSRC_REQ_MASK); + + BHND_CLKCTL_UNLOCK(clkctl); + } + + /* Clear child's PMU info reference */ bhnd_set_pmu_info(child, NULL); - bhnd_release_provider(pm->pm_dev, pm->pm_pmu, BHND_SERVICE_PMU); - free(pm->pm_res, M_BHND); - free(pm, M_BHND); + /* Before freeing the clkctl instance, save a pointer to resources we + * need to clean up manually */ + r = clkctl->cc_res; + pmu_dev = clkctl->cc_pmu_dev; + /* Free the clkctl instance */ + bhnd_free_core_clkctl(clkctl); + + /* Free the child's bhnd resource wrapper */ + free(r, M_BHND); + + /* Release the child's PMU provider reference */ + bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU); + return (0); } /** + * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_LATENCY(). + */ +int +bhnd_generic_get_clock_latency(device_t dev, device_t child, bhnd_clock clock, + u_int *latency) +{ + struct bhnd_core_clkctl *clkctl; + + if (device_get_parent(child) != dev) + return (EINVAL); + + if ((clkctl = bhnd_get_pmu_info(child)) == NULL) + panic("no active PMU allocation"); + + return (bhnd_pmu_get_clock_latency(clkctl->cc_pmu_dev, clock, latency)); +} + +/** + * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_FREQ(). + */ +int +bhnd_generic_get_clock_freq(device_t dev, device_t child, bhnd_clock clock, + u_int *freq) +{ + struct bhnd_core_clkctl *clkctl; + + if (device_get_parent(child) != dev) + return (EINVAL); + + if ((clkctl = bhnd_get_pmu_info(child)) == NULL) + panic("no active PMU allocation"); + + return (bhnd_pmu_get_clock_freq(clkctl->cc_pmu_dev, clock, freq)); +} + +/** * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_CLOCK(). */ int bhnd_generic_request_clock(device_t dev, device_t child, bhnd_clock clock) { - struct bhnd_softc *sc; - struct bhnd_core_pmu_info *pm; + struct bhnd_softc *sc; + struct bhnd_core_clkctl *clkctl; + uint32_t avail; + uint32_t req; + int error; sc = device_get_softc(dev); - if ((pm = bhnd_get_pmu_info(child)) == NULL) - panic("no active PMU request state"); + if (device_get_parent(child) != dev) + return (EINVAL); - /* dispatch request to PMU */ - return (BHND_PMU_CORE_REQ_CLOCK(pm->pm_pmu, pm, clock)); + if ((clkctl = bhnd_get_pmu_info(child)) == NULL) + panic("no active PMU allocation"); + + BHND_ASSERT_CLKCTL_AVAIL(clkctl); + + avail = 0x0; + req = 0x0; + + switch (clock) { + case BHND_CLOCK_DYN: + break; + case BHND_CLOCK_ILP: + req |= BHND_CCS_FORCEILP; + break; + case BHND_CLOCK_ALP: + req |= BHND_CCS_FORCEALP; + avail |= BHND_CCS_ALPAVAIL; + break; + case BHND_CLOCK_HT: + req |= BHND_CCS_FORCEHT; + avail |= BHND_CCS_HTAVAIL; + break; + default: + device_printf(dev, "%s requested unknown clock: %#x\n", + device_get_nameunit(clkctl->cc_dev), clock); + return (ENODEV); + } + + BHND_CLKCTL_LOCK(clkctl); + + /* Issue request */ + BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_FORCE_MASK); + + /* Wait for clock availability */ + error = bhnd_core_clkctl_wait(clkctl, avail, avail); + + BHND_CLKCTL_UNLOCK(clkctl); + + return (error); } /** @@ -529,16 +633,64 @@ bhnd_generic_request_clock(device_t dev, device_t chil int bhnd_generic_enable_clocks(device_t dev, device_t child, uint32_t clocks) { - struct bhnd_softc *sc; - struct bhnd_core_pmu_info *pm; + struct bhnd_softc *sc; + struct bhnd_core_clkctl *clkctl; + uint32_t avail; + uint32_t req; + int error; sc = device_get_softc(dev); - if ((pm = bhnd_get_pmu_info(child)) == NULL) - panic("no active PMU request state"); + if (device_get_parent(child) != dev) + return (EINVAL); - /* dispatch request to PMU */ - return (BHND_PMU_CORE_EN_CLOCKS(pm->pm_pmu, pm, clocks)); + if ((clkctl = bhnd_get_pmu_info(child)) == NULL) + panic("no active PMU allocation"); + + BHND_ASSERT_CLKCTL_AVAIL(clkctl); + + sc = device_get_softc(dev); + + avail = 0x0; + req = 0x0; + + /* Build clock request flags */ + if (clocks & BHND_CLOCK_DYN) /* nothing to enable */ + clocks &= ~BHND_CLOCK_DYN; + + if (clocks & BHND_CLOCK_ILP) /* nothing to enable */ + clocks &= ~BHND_CLOCK_ILP; + + if (clocks & BHND_CLOCK_ALP) { + req |= BHND_CCS_ALPAREQ; + avail |= BHND_CCS_ALPAVAIL; + clocks &= ~BHND_CLOCK_ALP; + } + + if (clocks & BHND_CLOCK_HT) { + req |= BHND_CCS_HTAREQ; + avail |= BHND_CCS_HTAVAIL; + clocks &= ~BHND_CLOCK_HT; + } + + /* Check for unknown clock values */ + if (clocks != 0x0) { + device_printf(dev, "%s requested unknown clocks: %#x\n", + device_get_nameunit(clkctl->cc_dev), clocks); + return (ENODEV); + } + + BHND_CLKCTL_LOCK(clkctl); + + /* Issue request */ + BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_AREQ_MASK); + + /* Wait for clock availability */ + error = bhnd_core_clkctl_wait(clkctl, avail, avail); + + BHND_CLKCTL_UNLOCK(clkctl); + + return (error); } /** @@ -547,16 +699,41 @@ bhnd_generic_enable_clocks(device_t dev, device_t chil int bhnd_generic_request_ext_rsrc(device_t dev, device_t child, u_int rsrc) { - struct bhnd_softc *sc; - struct bhnd_core_pmu_info *pm; + struct bhnd_softc *sc; + struct bhnd_core_clkctl *clkctl; + uint32_t req; + uint32_t avail; + int error; sc = device_get_softc(dev); - if ((pm = bhnd_get_pmu_info(child)) == NULL) - panic("no active PMU request state"); + if (device_get_parent(child) != dev) + return (EINVAL); - /* dispatch request to PMU */ - return (BHND_PMU_CORE_REQ_EXT_RSRC(pm->pm_pmu, pm, rsrc)); + if ((clkctl = bhnd_get_pmu_info(child)) == NULL) + panic("no active PMU allocation"); + + BHND_ASSERT_CLKCTL_AVAIL(clkctl); + + sc = device_get_softc(dev); + + if (rsrc > BHND_CCS_ERSRC_MAX) + return (EINVAL); + + req = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ); + avail = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_STS); + + BHND_CLKCTL_LOCK(clkctl); + + /* Write request */ + BHND_CLKCTL_SET_4(clkctl, req, req); + + /* Wait for resource availability */ + error = bhnd_core_clkctl_wait(clkctl, avail, avail); + + BHND_CLKCTL_UNLOCK(clkctl); + + return (error); } /** @@ -565,19 +742,36 @@ bhnd_generic_request_ext_rsrc(device_t dev, device_t c int bhnd_generic_release_ext_rsrc(device_t dev, device_t child, u_int rsrc) { - struct bhnd_softc *sc; - struct bhnd_core_pmu_info *pm; + struct bhnd_softc *sc; + struct bhnd_core_clkctl *clkctl; + uint32_t mask; sc = device_get_softc(dev); - if ((pm = bhnd_get_pmu_info(child)) == NULL) - panic("no active PMU request state"); + if (device_get_parent(child) != dev) + return (EINVAL); - /* dispatch request to PMU */ - return (BHND_PMU_CORE_RELEASE_EXT_RSRC(pm->pm_pmu, pm, rsrc)); -} + if ((clkctl = bhnd_get_pmu_info(child)) == NULL) + panic("no active PMU allocation"); + BHND_ASSERT_CLKCTL_AVAIL(clkctl); + + sc = device_get_softc(dev); + + if (rsrc > BHND_CCS_ERSRC_MAX) + return (EINVAL); + + mask = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ); + + /* Clear request */ + BHND_CLKCTL_LOCK(clkctl); + BHND_CLKCTL_SET_4(clkctl, 0x0, mask); + BHND_CLKCTL_UNLOCK(clkctl); + + return (0); +} + /** * Default bhnd(4) bus driver implementation of BHND_BUS_IS_REGION_VALID(). * @@ -954,6 +1148,8 @@ static device_method_t bhnd_methods[] = { DEVMETHOD(bhnd_bus_enable_clocks, bhnd_generic_enable_clocks), DEVMETHOD(bhnd_bus_request_ext_rsrc, bhnd_generic_request_ext_rsrc), DEVMETHOD(bhnd_bus_release_ext_rsrc, bhnd_generic_release_ext_rsrc), + DEVMETHOD(bhnd_bus_get_clock_latency, bhnd_generic_get_clock_latency), + DEVMETHOD(bhnd_bus_get_clock_freq, bhnd_generic_get_clock_freq), DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid), DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_generic_get_nvram_var), Modified: head/sys/dev/bhnd/bhnd.h ============================================================================== --- head/sys/dev/bhnd/bhnd.h Wed Nov 22 19:58:29 2017 (r326101) +++ head/sys/dev/bhnd/bhnd.h Wed Nov 22 20:27:46 2017 (r326102) @@ -52,8 +52,6 @@ #include "nvram/bhnd_nvram.h" -struct bhnd_core_pmu_info; - extern devclass_t bhnd_devclass; extern devclass_t bhnd_hostb_devclass; extern devclass_t bhnd_nvram_devclass; @@ -155,7 +153,7 @@ BHND_ACCESSOR(vendor_name, VENDOR_NAME, const char *); BHND_ACCESSOR(device_name, DEVICE_NAME, const char *); BHND_ACCESSOR(core_index, CORE_INDEX, u_int); BHND_ACCESSOR(core_unit, CORE_UNIT, int); -BHND_ACCESSOR(pmu_info, PMU_INFO, struct bhnd_core_pmu_info *); +BHND_ACCESSOR(pmu_info, PMU_INFO, void *); #undef BHND_ACCESSOR @@ -859,67 +857,6 @@ bhnd_suspend_hw(device_t dev) } /** - * If supported by the chipset, return the clock source for the given clock. - * - * This function is only supported on early PWRCTL-equipped chipsets - * that expose clock management via their host bridge interface. Currently, - * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. - * - * @param dev A bhnd bus child device. - * @param clock The clock for which a clock source will be returned. - * - * @retval bhnd_clksrc The clock source for @p clock. - * @retval BHND_CLKSRC_UNKNOWN If @p clock is unsupported, or its - * clock source is not known to the bus. - */ -static inline bhnd_clksrc -bhnd_pwrctl_get_clksrc(device_t dev, bhnd_clock clock) -{ - return (BHND_BUS_PWRCTL_GET_CLKSRC(device_get_parent(dev), dev, clock)); -} - -/** - * If supported by the chipset, gate @p clock - * - * This function is only supported on early PWRCTL-equipped chipsets - * that expose clock management via their host bridge interface. Currently, - * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. - * - * @param dev A bhnd bus child device. - * @param clock The clock to be disabled. - * - * @retval 0 success - * @retval ENODEV If bus-level clock source management is not supported. - * @retval ENXIO If bus-level management of @p clock is not supported. - */ -static inline int -bhnd_pwrctl_gate_clock(device_t dev, bhnd_clock clock) -{ - return (BHND_BUS_PWRCTL_GATE_CLOCK(device_get_parent(dev), dev, clock)); -} - -/** - * If supported by the chipset, ungate @p clock - * - * This function is only supported on early PWRCTL-equipped chipsets - * that expose clock management via their host bridge interface. Currently, - * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. - * - * @param dev A bhnd bus child device. - * @param clock The clock to be enabled. - * - * @retval 0 success - * @retval ENODEV If bus-level clock source management is not supported. - * @retval ENXIO If bus-level management of @p clock is not supported. - */ -static inline int -bhnd_pwrctl_ungate_clock(device_t dev, bhnd_clock clock) -{ - return (BHND_BUS_PWRCTL_UNGATE_CLOCK(device_get_parent(dev), dev, - clock)); -} - -/** * Return the BHND attachment type of the parent bhnd bus. * * @param dev A bhnd bus child device. @@ -1066,8 +1003,7 @@ bhnd_unmap_intr(device_t dev, rman_res_t irq) * calling bhnd_alloc_pmu(), and must not be released until after * calling bhnd_release_pmu(). * - * @param dev The parent of @p child. - * @param child The requesting bhnd device. + * @param dev The requesting bhnd device. * * @retval 0 success * @retval non-zero If allocating PMU request state otherwise fails, a @@ -1083,8 +1019,7 @@ bhnd_alloc_pmu(device_t dev) * Release any per-core PMU resources allocated for @p child. Any outstanding * PMU requests are are discarded. * - * @param dev The parent of @p child. - * @param child The requesting bhnd device. + * @param dev The requesting bhnd device. * * @retval 0 success * @retval non-zero If releasing PMU request state otherwise fails, a @@ -1095,6 +1030,51 @@ static inline int bhnd_release_pmu(device_t dev) { return (BHND_BUS_RELEASE_PMU(device_get_parent(dev), dev)); +} + +/** + * Return the transition latency required for @p clock in microseconds, if + * known. + * + * The BHND_CLOCK_HT latency value is suitable for use as the D11 core's + * 'fastpwrup_dly' value. + * + * @note A driver must ask the bhnd bus to allocate PMU request state + * via BHND_BUS_ALLOC_PMU() before querying PMU clocks. + * + * @param dev The requesting bhnd device. + * @param clock The clock to be queried for transition latency. + * @param[out] latency On success, the transition latency of @p clock in + * microseconds. + * + * @retval 0 success + * @retval ENODEV If the transition latency for @p clock is not available. + */ +static inline int +bhnd_get_clock_latency(device_t dev, bhnd_clock clock, u_int *latency) +{ + return (BHND_BUS_GET_CLOCK_LATENCY(device_get_parent(dev), dev, clock, + latency)); +} + +/** + * Return the frequency for @p clock in Hz, if known. + * + * @param dev The requesting bhnd device. + * @param clock The clock to be queried. + * @param[out] freq On success, the frequency of @p clock in Hz. + * + * @note A driver must ask the bhnd bus to allocate PMU request state + * via BHND_BUS_ALLOC_PMU() before querying PMU clocks. + * + * @retval 0 success + * @retval ENODEV If the frequency for @p clock is not available. + */ +static inline int +bhnd_get_clock_freq(device_t dev, bhnd_clock clock, u_int *freq) +{ + return (BHND_BUS_GET_CLOCK_FREQ(device_get_parent(dev), dev, clock, + freq)); } /** Modified: head/sys/dev/bhnd/bhnd_bus_if.m ============================================================================== --- head/sys/dev/bhnd/bhnd_bus_if.m Wed Nov 22 19:58:29 2017 (r326101) +++ head/sys/dev/bhnd/bhnd_bus_if.m Wed Nov 22 20:27:46 2017 (r326102) @@ -114,28 +114,7 @@ CODE { panic("bhnd_bus_get_attach_type unimplemented"); } - static bhnd_clksrc - bhnd_bus_null_pwrctl_get_clksrc(device_t dev, device_t child, - bhnd_clock clock) - { - return (BHND_CLKSRC_UNKNOWN); - } - static int - bhnd_bus_null_pwrctl_gate_clock(device_t dev, device_t child, - bhnd_clock clock) - { - return (ENODEV); - } - - static int - bhnd_bus_null_pwrctl_ungate_clock(device_t dev, device_t child, - bhnd_clock clock) - { - return (ENODEV); - } - - static int bhnd_bus_null_read_board_info(device_t dev, device_t child, struct bhnd_board_info *info) { @@ -160,6 +139,20 @@ CODE { } static int + bhnd_bus_null_get_clock_latency(device_t dev, device_t child, + bhnd_clock clock, u_int *latency) + { + panic("bhnd_pmu_get_clock_latency unimplemented"); + } + + static int + bhnd_bus_null_get_clock_freq(device_t dev, device_t child, + bhnd_clock clock, u_int *freq) + { + panic("bhnd_pmu_get_clock_freq unimplemented"); + } + + static int bhnd_bus_null_request_clock(device_t dev, device_t child, bhnd_clock clock) { @@ -671,95 +664,83 @@ METHOD int suspend_hw { } DEFAULT bhnd_bus_null_suspend_hw; /** - * If supported by the chipset, return the clock source for the given clock. + * Allocate per-core PMU resources and enable PMU request handling for @p child. * - * This function is only supported on early PWRCTL-equipped chipsets - * that expose clock management via their host bridge interface. Currently, - * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. + * The region containing the core's PMU register block (if any) must be + * allocated via bus_alloc_resource(9) (or bhnd_alloc_resource) before + * calling BHND_BUS_ALLOC_PMU(), and must not be released until after + * calling BHND_BUS_RELEASE_PMU(). * * @param dev The parent of @p child. - * @param child The bhnd device requesting a clock source. - * @param clock The clock for which a clock source will be returned. + * @param child The requesting bhnd device. * - * @retval bhnd_clksrc The clock source for @p clock. - * @retval BHND_CLKSRC_UNKNOWN If @p clock is unsupported, or its - * clock source is not known to the bus. + * @retval 0 success + * @retval non-zero if enabling per-core PMU request handling fails, a + * regular unix error code will be returned. */ -METHOD bhnd_clksrc pwrctl_get_clksrc { +METHOD int alloc_pmu { device_t dev; device_t child; - bhnd_clock clock; -} DEFAULT bhnd_bus_null_pwrctl_get_clksrc; +} DEFAULT bhnd_bus_null_alloc_pmu; /** - * If supported by the chipset, gate the clock source for @p clock + * Release per-core PMU resources allocated for @p child. Any + * outstanding PMU requests are discarded. * - * This function is only supported on early PWRCTL-equipped chipsets - * that expose clock management via their host bridge interface. Currently, - * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. - * * @param dev The parent of @p child. - * @param child The bhnd device requesting clock gating. - * @param clock The clock to be disabled. - * - * @retval 0 success - * @retval ENODEV If bus-level clock source management is not supported. - * @retval ENXIO If bus-level management of @p clock is not supported. + * @param child The requesting bhnd device. */ -METHOD int pwrctl_gate_clock { +METHOD int release_pmu { device_t dev; device_t child; - bhnd_clock clock; -} DEFAULT bhnd_bus_null_pwrctl_gate_clock; +} DEFAULT bhnd_bus_null_release_pmu; /** - * If supported by the chipset, ungate the clock source for @p clock + * Return the transition latency required for @p clock in microseconds, if + * known. * - * This function is only supported on early PWRCTL-equipped chipsets - * that expose clock management via their host bridge interface. Currently, - * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9. + * The BHND_CLOCK_HT latency value is suitable for use as the D11 core's + * 'fastpwrup_dly' value. * - * @param dev The parent of @p child. - * @param child The bhnd device requesting clock gating. - * @param clock The clock to be enabled. + * @note A driver must ask the bhnd bus to allocate PMU request state + * via BHND_BUS_ALLOC_PMU() before querying PMU clocks. * - * @retval 0 success - * @retval ENODEV If bus-level clock source management is not supported. - * @retval ENXIO If bus-level management of @p clock is not supported. - */ -METHOD int pwrctl_ungate_clock { - device_t dev; - device_t child; - bhnd_clock clock; -} DEFAULT bhnd_bus_null_pwrctl_ungate_clock; - -/** - * Allocate and enable per-core PMU request handling for @p child. - * - * The region containing the core's PMU register block (if any) must be - * allocated via bus_alloc_resource(9) (or bhnd_alloc_resource) before - * calling BHND_BUS_ALLOC_PMU(), and must not be released until after - * calling BHND_BUS_RELEASE_PMU(). - * * @param dev The parent of @p child. * @param child The requesting bhnd device. + * @param clock The clock to be queried for transition latency. + * @param[out] latency On success, the transition latency of @p clock in + * microseconds. + * + * @retval 0 success + * @retval ENODEV If the transition latency for @p clock is not available. */ -METHOD int alloc_pmu { +METHOD int get_clock_latency { device_t dev; device_t child; -} DEFAULT bhnd_bus_null_alloc_pmu; + bhnd_clock clock; + u_int *latency; +} DEFAULT bhnd_bus_null_get_clock_latency; /** - * Release per-core PMU resources allocated for @p child. Any - * outstanding PMU requests are discarded. + * Return the frequency for @p clock in Hz, if known. * * @param dev The parent of @p child. * @param child The requesting bhnd device. + * @param clock The clock to be queried. + * @param[out] freq On success, the frequency of @p clock in Hz. + * + * @note A driver must ask the bhnd bus to allocate PMU request state + * via BHND_BUS_ALLOC_PMU() before querying PMU clocks. + * + * @retval 0 success + * @retval ENODEV If the frequency for @p clock is not available. */ -METHOD int release_pmu { +METHOD int get_clock_freq { device_t dev; device_t child; -} DEFAULT bhnd_bus_null_release_pmu; + bhnd_clock clock; + u_int *freq; +} DEFAULT bhnd_bus_null_get_clock_freq; /** * Request that @p clock (or faster) be routed to @p child. @@ -772,11 +753,13 @@ METHOD int release_pmu { * * @param dev The parent of @p child. * @param child The bhnd device requesting @p clock. - * @param clock The requested clock source. + * @param clock The requested clock source. * - * @retval 0 success - * @retval ENODEV If an unsupported clock was requested. - * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable. + * @retval 0 success + * @retval ENODEV If an unsupported clock was requested. + * @retval ETIMEDOUT If the clock request succeeds, but the clock is not + * detected as ready within the PMU's maximum transition + * delay. This should not occur in normal operation. */ METHOD int request_clock { device_t dev; @@ -801,9 +784,11 @@ METHOD int request_clock { * @param child The bhnd device requesting @p clock. * @param clock The requested clock source. * - * @retval 0 success - * @retval ENODEV If an unsupported clock was requested. - * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable. + * @retval 0 success + * @retval ENODEV If an unsupported clock was requested. + * @retval ETIMEDOUT If the clock request succeeds, but the clock is not + * detected as ready within the PMU's maximum transition + * delay. This should not occur in normal operation. */ METHOD int enable_clocks { device_t dev; @@ -824,9 +809,11 @@ METHOD int enable_clocks { * @param child The bhnd device requesting @p rsrc. * @param rsrc The core-specific external resource identifier. * - * @retval 0 success - * @retval ENODEV If the PMU does not support @p rsrc. - * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable. + * @retval 0 success + * @retval ENODEV If the PMU does not support @p rsrc. + * @retval ETIMEDOUT If the clock request succeeds, but the clock is not + * detected as ready within the PMU's maximum transition + * delay. This should not occur in normal operation. */ METHOD int request_ext_rsrc { device_t dev; @@ -844,9 +831,11 @@ METHOD int request_ext_rsrc { * @param child The bhnd device requesting @p rsrc. * @param rsrc The core-specific external resource number. * - * @retval 0 success - * @retval ENODEV If the PMU does not support @p rsrc. - * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable. + * @retval 0 success + * @retval ENODEV If the PMU does not support @p rsrc. + * @retval ETIMEDOUT If the clock request succeeds, but the clock is not + * detected as ready within the PMU's maximum transition + * delay. This should not occur in normal operation. */ METHOD int release_ext_rsrc { device_t dev; Modified: head/sys/dev/bhnd/bhnd_private.h ============================================================================== --- head/sys/dev/bhnd/bhnd_private.h Wed Nov 22 19:58:29 2017 (r326101) +++ head/sys/dev/bhnd/bhnd_private.h Wed Nov 22 20:27:46 2017 (r326102) @@ -54,4 +54,49 @@ struct bhnd_service_entry { STAILQ_ENTRY(bhnd_service_entry) link; }; +/** + * bhnd(4) per-core PMU clkctl quirks. + */ +enum { + /** On BCM4328-derived chipsets, the CLK_CTL_ST register CCS_HTAVAIL + * and CCS_ALPAVAIL bits are swapped in the ChipCommon and PCMCIA + * cores; the BHND_CCS0_* constants should be used. */ + BHND_CLKCTL_QUIRK_CCS0 = 1 +}; + +/** + * Per-core bhnd(4) PMU clkctl registers. + */ +struct bhnd_core_clkctl { + device_t cc_dev; /**< core device */ + device_t cc_pmu_dev; /**< pmu device */ + uint32_t cc_quirks; /**< core-specific clkctl quirks */ + struct bhnd_resource *cc_res; /**< resource mapping core's clkctl register */ + bus_size_t cc_res_offset; /**< offset to clkctl register */ + u_int cc_max_latency; /**< maximum PMU transition latency, in microseconds */ + struct mtx cc_mtx; /**< register read/modify/write lock */ +}; + +#define BHND_ASSERT_CLKCTL_AVAIL(_clkctl) \ + KASSERT(!bhnd_is_hw_suspended((_clkctl)->cc_dev), \ + ("reading clkctl on suspended core will trigger system livelock")) + +#define BHND_CLKCTL_LOCK_INIT(_clkctl) mtx_init(&(_clkctl)->cc_mtx, \ + device_get_nameunit((_clkctl)->cc_dev), NULL, MTX_DEF) +#define BHND_CLKCTL_LOCK(_clkctl) mtx_lock(&(_clkctl)->cc_mtx) +#define BHND_CLKCTL_UNLOCK(_clkctl) mtx_unlock(&(_clkctl)->cc_mtx) +#define BHND_CLKCTL_LOCK_ASSERT(_clkctl, what) \ + mtx_assert(&(_clkctl)->cc_mtx, what) +#define BHND_CLKCTL_LOCK_DESTROY(_clkctl) mtx_destroy(&(_clkctl->cc_mtx)) + +#define BHND_CLKCTL_READ_4(_clkctl) \ + bhnd_bus_read_4((_clkctl)->cc_res, (_clkctl)->cc_res_offset) + +#define BHND_CLKCTL_WRITE_4(_clkctl, _val) \ + bhnd_bus_write_4((_clkctl)->cc_res, (_clkctl)->cc_res_offset, (_val)) + +#define BHND_CLKCTL_SET_4(_clkctl, _val, _mask) \ + BHND_CLKCTL_WRITE_4((_clkctl), \ + ((_val) & (_mask)) | (BHND_CLKCTL_READ_4(_clkctl) & ~(_mask))) + #endif /* _BHND_BHND_PRIVATE_H_ */ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201711222027.vAMKRkTc077837>