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...
Landon J. Fuller
landonf at FreeBSD.org
Wed Nov 22 20:27:48 UTC 2017
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 ***
More information about the svn-src-all
mailing list