aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/bhnd
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/bhnd')
-rw-r--r--sys/dev/bhnd/bcma/bcma.c18
-rw-r--r--sys/dev/bhnd/bcma/bcmavar.h16
-rw-r--r--sys/dev/bhnd/bhnd.c318
-rw-r--r--sys/dev/bhnd/bhnd.h116
-rw-r--r--sys/dev/bhnd/bhnd_bus_if.m171
-rw-r--r--sys/dev/bhnd/bhnd_private.h45
-rw-r--r--sys/dev/bhnd/bhnd_subr.c143
-rw-r--r--sys/dev/bhnd/bhnd_types.h1
-rw-r--r--sys/dev/bhnd/bhndb/bhnd_bhndb.c31
-rw-r--r--sys/dev/bhnd/bhndb/bhndb_pci.c34
-rw-r--r--sys/dev/bhnd/bhndreg.h89
-rw-r--r--sys/dev/bhnd/bhndvar.h20
-rw-r--r--sys/dev/bhnd/cores/chipc/chipc.c26
-rw-r--r--sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c150
-rw-r--r--sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h94
-rw-r--r--sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_hostb_if.m129
-rw-r--r--sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_if.m98
-rw-r--r--sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h71
-rw-r--r--sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c14
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu.c392
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu.h233
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c8
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m338
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h20
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c379
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu_types.h53
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmureg.h24
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h25
-rw-r--r--sys/dev/bhnd/siba/siba.c442
-rw-r--r--sys/dev/bhnd/siba/siba_bhndb.c4
-rw-r--r--sys/dev/bhnd/siba/siba_subr.c1
-rw-r--r--sys/dev/bhnd/siba/sibavar.h50
32 files changed, 2683 insertions, 870 deletions
diff --git a/sys/dev/bhnd/bcma/bcma.c b/sys/dev/bhnd/bcma/bcma.c
index 59f944786ddf..09d88a98b519 100644
--- a/sys/dev/bhnd/bcma/bcma.c
+++ b/sys/dev/bhnd/bcma/bcma.c
@@ -193,7 +193,7 @@ bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
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 ioctl)
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)
@@ -382,12 +380,6 @@ bcma_suspend_hw(device_t dev, device_t child)
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);
}
diff --git a/sys/dev/bhnd/bcma/bcmavar.h b/sys/dev/bhnd/bcma/bcmavar.h
index dba976841917..f543b6e03d78 100644
--- a/sys/dev/bhnd/bcma/bcmavar.h
+++ b/sys/dev/bhnd/bcma/bcmavar.h
@@ -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 */
};
diff --git a/sys/dev/bhnd/bhnd.c b/sys/dev/bhnd/bhnd.c
index 1a3b0246fea4..3e42c141dd86 100644
--- a/sys/dev/bhnd/bhnd.c
+++ b/sys/dev/bhnd/bhnd.c
@@ -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);
+
+ /* 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);
+ }
- /* free PMU info */
+ /* 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);
+
+ 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);
- /* dispatch request to PMU */
- return (BHND_PMU_CORE_REQ_CLOCK(pm->pm_pmu, pm, clock));
+ /* 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 child, bhnd_clock clock)
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 (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
+ panic("no active PMU allocation");
+
+ BHND_ASSERT_CLKCTL_AVAIL(clkctl);
sc = device_get_softc(dev);
- if ((pm = bhnd_get_pmu_info(child)) == NULL)
- panic("no active PMU request state");
+ 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;
- /* dispatch request to PMU */
- return (BHND_PMU_CORE_EN_CLOCKS(pm->pm_pmu, pm, clocks));
+ 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 child, uint32_t clocks)
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 (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
+ panic("no active PMU allocation");
+
+ BHND_ASSERT_CLKCTL_AVAIL(clkctl);
sc = device_get_softc(dev);
- if ((pm = bhnd_get_pmu_info(child)) == NULL)
- panic("no active PMU request state");
+ 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);
- /* dispatch request to PMU */
- return (BHND_PMU_CORE_REQ_EXT_RSRC(pm->pm_pmu, pm, rsrc));
+ /* 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 child, u_int rsrc)
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),
diff --git a/sys/dev/bhnd/bhnd.h b/sys/dev/bhnd/bhnd.h
index b4e441b92d78..96e8e93a6a24 100644
--- a/sys/dev/bhnd/bhnd.h
+++ b/sys/dev/bhnd/bhnd.h
@@ -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
@@ -1097,6 +1032,51 @@ 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));
+}
+
/**
* Request that @p clock (or faster) be routed to @p dev.
*
diff --git a/sys/dev/bhnd/bhnd_bus_if.m b/sys/dev/bhnd/bhnd_bus_if.m
index 07c37d509b13..08346840413e 100644
--- a/sys/dev/bhnd/bhnd_bus_if.m
+++ b/sys/dev/bhnd/bhnd_bus_if.m
@@ -114,27 +114,6 @@ 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
- *
- * 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.
+ * Release per-core PMU resources allocated for @p child. Any
+ * outstanding PMU requests are discarded.
*
* @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
- *
- * 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 enabled.
+ * Return the transition latency required for @p clock in microseconds, if
+ * known.
*
- * @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 BHND_CLOCK_HT latency value is suitable for use as the D11 core's
+ * 'fastpwrup_dly' value.
*
- * 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().
+ * @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 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;
diff --git a/sys/dev/bhnd/bhnd_private.h b/sys/dev/bhnd/bhnd_private.h
index 9c2ed900fa15..26c239b7f1bb 100644
--- a/sys/dev/bhnd/bhnd_private.h
+++ b/sys/dev/bhnd/bhnd_private.h
@@ -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 --git a/sys/dev/bhnd/bhnd_subr.c b/sys/dev/bhnd/bhnd_subr.c
index c5ca57ace376..3fad4a830cad 100644
--- a/sys/dev/bhnd/bhnd_subr.c
+++ b/sys/dev/bhnd/bhnd_subr.c
@@ -171,6 +171,34 @@ static const struct bhnd_core_desc {
{ 0, 0, 0, NULL }
};
+static const struct bhnd_device_quirk bhnd_chipc_clkctl_quirks[];
+static const struct bhnd_device_quirk bhnd_pcmcia_clkctl_quirks[];
+
+/**
+ * Device table entries for core-specific CLKCTL quirk lookup.
+ */
+static const struct bhnd_device bhnd_clkctl_devices[] = {
+ BHND_DEVICE(BCM, CC, NULL, bhnd_chipc_clkctl_quirks),
+ BHND_DEVICE(BCM, PCMCIA, NULL, bhnd_pcmcia_clkctl_quirks),
+ BHND_DEVICE_END,
+};
+
+/** ChipCommon CLKCTL quirks */
+static const struct bhnd_device_quirk bhnd_chipc_clkctl_quirks[] = {
+ /* HTAVAIL/ALPAVAIL are bitswapped in chipc's CLKCTL */
+ BHND_CHIP_QUIRK(4328, HWREV_ANY, BHND_CLKCTL_QUIRK_CCS0),
+ BHND_CHIP_QUIRK(5354, HWREV_ANY, BHND_CLKCTL_QUIRK_CCS0),
+ BHND_DEVICE_QUIRK_END
+};
+
+/** PCMCIA CLKCTL quirks */
+static const struct bhnd_device_quirk bhnd_pcmcia_clkctl_quirks[] = {
+ /* HTAVAIL/ALPAVAIL are bitswapped in pcmcia's CLKCTL */
+ BHND_CHIP_QUIRK(4328, HWREV_ANY, BHND_CLKCTL_QUIRK_CCS0),
+ BHND_CHIP_QUIRK(5354, HWREV_ANY, BHND_CLKCTL_QUIRK_CCS0),
+ BHND_DEVICE_QUIRK_END
+};
+
/**
* Return the name for a given JEP106 manufacturer ID.
*
@@ -1181,6 +1209,119 @@ cleanup:
}
/**
+ * Allocate and return a new per-core PMU clock control/status (clkctl)
+ * instance for @p dev.
+ *
+ * @param dev The bhnd(4) core device mapped by @p r.
+ * @param pmu_dev The bhnd(4) PMU device, implmenting the bhnd_pmu_if
+ * interface. The caller is responsible for ensuring that
+ * this reference remains valid for the lifetime of the
+ * returned clkctl instance.
+ * @param r A resource mapping the core's clock control register
+ * (see BHND_CLK_CTL_ST). The caller is responsible for
+ * ensuring that this resource remains valid for the
+ * lifetime of the returned clkctl instance.
+ * @param offset The offset to the clock control register within @p r.
+ * @param max_latency The PMU's maximum state transition latency in
+ * microseconds; this upper bound will be used to busy-wait
+ * on PMU state transitions.
+ *
+ * @retval non-NULL success
+ * @retval NULL if allocation fails.
+ *
+ */
+struct bhnd_core_clkctl *
+bhnd_alloc_core_clkctl(device_t dev, device_t pmu_dev, struct bhnd_resource *r,
+ bus_size_t offset, u_int max_latency)
+{
+ struct bhnd_core_clkctl *clkctl;
+
+ clkctl = malloc(sizeof(*clkctl), M_BHND, M_ZERO | M_NOWAIT);
+ if (clkctl == NULL)
+ return (NULL);
+
+ clkctl->cc_dev = dev;
+ clkctl->cc_pmu_dev = pmu_dev;
+ clkctl->cc_res = r;
+ clkctl->cc_res_offset = offset;
+ clkctl->cc_max_latency = max_latency;
+ clkctl->cc_quirks = bhnd_device_quirks(dev, bhnd_clkctl_devices,
+ sizeof(bhnd_clkctl_devices[0]));
+
+ BHND_CLKCTL_LOCK_INIT(clkctl);
+
+ return (clkctl);
+}
+
+/**
+ * Free a clkctl instance previously allocated via bhnd_alloc_core_clkctl().
+ *
+ * @param clkctl The clkctl instance to be freed.
+ */
+void
+bhnd_free_core_clkctl(struct bhnd_core_clkctl *clkctl)
+{
+ BHND_CLKCTL_LOCK_DESTROY(clkctl);
+
+ free(clkctl, M_BHND);
+}
+
+/**
+ * Wait for the per-core clock status to be equal to @p value after
+ * applying @p mask, timing out after the maximum transition latency is reached.
+ *
+ * @param clkctl Per-core clkctl state to be queryied.
+ * @param value Value to wait for.
+ * @param mask Mask to apply prior to value comparison.
+ *
+ * @retval 0 success
+ * @retval ETIMEDOUT if the PMU's maximum transition delay is reached before
+ * the clock status matches @p value and @p mask.
+ */
+int
+bhnd_core_clkctl_wait(struct bhnd_core_clkctl *clkctl, uint32_t value,
+ uint32_t mask)
+{
+ uint32_t clkst;
+
+ BHND_CLKCTL_LOCK_ASSERT(clkctl, MA_OWNED);
+
+ /* Bitswapped HTAVAIL/ALPAVAIL work-around */
+ if (clkctl->cc_quirks & BHND_CLKCTL_QUIRK_CCS0) {
+ uint32_t fmask, fval;
+
+ fmask = mask & ~(BHND_CCS_HTAVAIL | BHND_CCS_ALPAVAIL);
+ fval = value & ~(BHND_CCS_HTAVAIL | BHND_CCS_ALPAVAIL);
+
+ if (mask & BHND_CCS_HTAVAIL)
+ fmask |= BHND_CCS0_HTAVAIL;
+ if (value & BHND_CCS_HTAVAIL)
+ fval |= BHND_CCS0_HTAVAIL;
+
+ if (mask & BHND_CCS_ALPAVAIL)
+ fmask |= BHND_CCS0_ALPAVAIL;
+ if (value & BHND_CCS_ALPAVAIL)
+ fval |= BHND_CCS0_ALPAVAIL;
+
+ mask = fmask;
+ value = fval;
+ }
+
+ for (u_int i = 0; i < clkctl->cc_max_latency; i += 10) {
+ clkst = bhnd_bus_read_4(clkctl->cc_res, clkctl->cc_res_offset);
+ if ((clkst & mask) == (value & mask))
+ return (0);
+
+ DELAY(10);
+ }
+
+ device_printf(clkctl->cc_dev, "clkst wait timeout (value=%#x, "
+ "mask=%#x)\n", value, mask);
+
+ return (ETIMEDOUT);
+}
+
+/**
* Read an NVRAM variable's NUL-terminated string value.
*
* @param dev A bhnd bus child device.
@@ -2351,4 +2492,4 @@ uintptr_t
bhnd_bus_generic_get_intr_domain(device_t dev, device_t child, bool self)
{
return ((uintptr_t)dev);
-} \ No newline at end of file
+}
diff --git a/sys/dev/bhnd/bhnd_types.h b/sys/dev/bhnd/bhnd_types.h
index d819afedbecb..1ac164f4fd82 100644
--- a/sys/dev/bhnd/bhnd_types.h
+++ b/sys/dev/bhnd/bhnd_types.h
@@ -72,6 +72,7 @@ typedef enum {
/** bhnd(4) platform services. */
typedef enum {
BHND_SERVICE_CHIPC, /**< chipcommon service; implements the bhnd_chipc interface */
+ BHND_SERVICE_PWRCTL, /**< legacy pwrctl service; implements the bhnd_pwrctl interface */
BHND_SERVICE_PMU, /**< pmu service; implements the bhnd_pmu interface */
BHND_SERVICE_NVRAM, /**< nvram service; implements the bhnd_nvram interface */
diff --git a/sys/dev/bhnd/bhndb/bhnd_bhndb.c b/sys/dev/bhnd/bhndb/bhnd_bhndb.c
index 8b93050ee7ab..ffcfef3db0f9 100644
--- a/sys/dev/bhnd/bhndb/bhnd_bhndb.c
+++ b/sys/dev/bhnd/bhndb/bhnd_bhndb.c
@@ -42,6 +42,8 @@ __FBSDID("$FreeBSD$");
#include <dev/bhnd/bhnd_ids.h>
#include <dev/bhnd/bhnd.h>
+#include "bhnd_pwrctl_hostb_if.h"
+
#include "bhndbvar.h"
/*
@@ -116,7 +118,7 @@ bhnd_bhndb_pwrctl_get_clksrc(device_t dev, device_t child,
bhnd_clock clock)
{
/* Delegate to parent bridge */
- return (BHND_BUS_PWRCTL_GET_CLKSRC(device_get_parent(dev), child,
+ return (BHND_PWRCTL_HOSTB_GET_CLKSRC(device_get_parent(dev), child,
clock));
}
@@ -125,7 +127,7 @@ bhnd_bhndb_pwrctl_gate_clock(device_t dev, device_t child,
bhnd_clock clock)
{
/* Delegate to parent bridge */
- return (BHND_BUS_PWRCTL_GATE_CLOCK(device_get_parent(dev), child,
+ return (BHND_PWRCTL_HOSTB_GATE_CLOCK(device_get_parent(dev), child,
clock));
}
@@ -134,7 +136,7 @@ bhnd_bhndb_pwrctl_ungate_clock(device_t dev, device_t child,
bhnd_clock clock)
{
/* Delegate to parent bridge */
- return (BHND_BUS_PWRCTL_UNGATE_CLOCK(device_get_parent(dev), child,
+ return (BHND_PWRCTL_HOSTB_UNGATE_CLOCK(device_get_parent(dev), child,
clock));
}
@@ -171,19 +173,20 @@ bhnd_bhndb_setup_intr(device_t dev, device_t child, struct resource *irq,
static device_method_t bhnd_bhndb_methods[] = {
/* Bus interface */
- DEVMETHOD(bus_setup_intr, bhnd_bhndb_setup_intr),
+ DEVMETHOD(bus_setup_intr, bhnd_bhndb_setup_intr),
/* BHND interface */
- DEVMETHOD(bhnd_bus_get_attach_type, bhnd_bhndb_get_attach_type),
- DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bhndb_is_hw_disabled),
- DEVMETHOD(bhnd_bus_find_hostb_device, bhnd_bhndb_find_hostb_device),
- DEVMETHOD(bhnd_bus_read_board_info, bhnd_bhndb_read_board_info),
- DEVMETHOD(bhnd_bus_map_intr, bhnd_bhndb_map_intr),
- DEVMETHOD(bhnd_bus_unmap_intr, bhnd_bhndb_unmap_intr),
-
- DEVMETHOD(bhnd_bus_pwrctl_get_clksrc, bhnd_bhndb_pwrctl_get_clksrc),
- DEVMETHOD(bhnd_bus_pwrctl_gate_clock, bhnd_bhndb_pwrctl_gate_clock),
- DEVMETHOD(bhnd_bus_pwrctl_ungate_clock, bhnd_bhndb_pwrctl_ungate_clock),
+ DEVMETHOD(bhnd_bus_get_attach_type, bhnd_bhndb_get_attach_type),
+ DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bhndb_is_hw_disabled),
+ DEVMETHOD(bhnd_bus_find_hostb_device, bhnd_bhndb_find_hostb_device),
+ DEVMETHOD(bhnd_bus_read_board_info, bhnd_bhndb_read_board_info),
+ DEVMETHOD(bhnd_bus_map_intr, bhnd_bhndb_map_intr),
+ DEVMETHOD(bhnd_bus_unmap_intr, bhnd_bhndb_unmap_intr),
+
+ /* BHND PWRCTL hostb interface */
+ DEVMETHOD(bhnd_pwrctl_hostb_get_clksrc, bhnd_bhndb_pwrctl_get_clksrc),
+ DEVMETHOD(bhnd_pwrctl_hostb_gate_clock, bhnd_bhndb_pwrctl_gate_clock),
+ DEVMETHOD(bhnd_pwrctl_hostb_ungate_clock, bhnd_bhndb_pwrctl_ungate_clock),
DEVMETHOD_END
};
diff --git a/sys/dev/bhnd/bhndb/bhndb_pci.c b/sys/dev/bhnd/bhndb/bhndb_pci.c
index e6a392ce34ec..ef0a0ea81fe8 100644
--- a/sys/dev/bhnd/bhndb/bhndb_pci.c
+++ b/sys/dev/bhnd/bhndb/bhndb_pci.c
@@ -68,6 +68,8 @@ __FBSDID("$FreeBSD$");
#include <dev/bhnd/cores/pci/bhnd_pcireg.h>
+#include "bhnd_pwrctl_hostb_if.h"
+
#include "bhndb_pcireg.h"
#include "bhndb_pcivar.h"
#include "bhndb_private.h"
@@ -1136,11 +1138,11 @@ bhndb_pci_pwrctl_get_clksrc(device_t dev, device_t child,
/* Only supported on PCI devices */
if (bhndb_is_pcie_attached(sc->dev))
- return (ENODEV);
+ return (BHND_CLKSRC_UNKNOWN);
/* Only ILP is supported */
if (clock != BHND_CLOCK_ILP)
- return (ENXIO);
+ return (BHND_CLKSRC_UNKNOWN);
gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4);
if (gpio_out & BHNDB_PCI_GPIO_SCS)
@@ -1451,22 +1453,22 @@ bhndb_pci_eio_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width)
static device_method_t bhndb_pci_methods[] = {
/* Device interface */
- DEVMETHOD(device_probe, bhndb_pci_probe),
- DEVMETHOD(device_attach, bhndb_pci_attach),
- DEVMETHOD(device_resume, bhndb_pci_resume),
- DEVMETHOD(device_suspend, bhndb_pci_suspend),
- DEVMETHOD(device_detach, bhndb_pci_detach),
-
- /* BHND interface */
- DEVMETHOD(bhnd_bus_pwrctl_get_clksrc, bhndb_pci_pwrctl_get_clksrc),
- DEVMETHOD(bhnd_bus_pwrctl_gate_clock, bhndb_pci_pwrctl_gate_clock),
- DEVMETHOD(bhnd_bus_pwrctl_ungate_clock, bhndb_pci_pwrctl_ungate_clock),
+ DEVMETHOD(device_probe, bhndb_pci_probe),
+ DEVMETHOD(device_attach, bhndb_pci_attach),
+ DEVMETHOD(device_resume, bhndb_pci_resume),
+ DEVMETHOD(device_suspend, bhndb_pci_suspend),
+ DEVMETHOD(device_detach, bhndb_pci_detach),
/* BHNDB interface */
- DEVMETHOD(bhndb_set_window_addr, bhndb_pci_set_window_addr),
- DEVMETHOD(bhndb_populate_board_info, bhndb_pci_populate_board_info),
- DEVMETHOD(bhndb_map_intr_isrc, bhndb_pci_map_intr_isrc),
- DEVMETHOD(bhndb_route_interrupts, bhndb_pci_route_interrupts),
+ DEVMETHOD(bhndb_set_window_addr, bhndb_pci_set_window_addr),
+ DEVMETHOD(bhndb_populate_board_info, bhndb_pci_populate_board_info),
+ DEVMETHOD(bhndb_map_intr_isrc, bhndb_pci_map_intr_isrc),
+ DEVMETHOD(bhndb_route_interrupts, bhndb_pci_route_interrupts),
+
+ /* BHND PWRCTL hostb interface */
+ DEVMETHOD(bhnd_pwrctl_hostb_get_clksrc, bhndb_pci_pwrctl_get_clksrc),
+ DEVMETHOD(bhnd_pwrctl_hostb_gate_clock, bhndb_pci_pwrctl_gate_clock),
+ DEVMETHOD(bhnd_pwrctl_hostb_ungate_clock, bhndb_pci_pwrctl_ungate_clock),
DEVMETHOD_END
};
diff --git a/sys/dev/bhnd/bhndreg.h b/sys/dev/bhnd/bhndreg.h
index 1fbcccae7416..be295c408fd1 100644
--- a/sys/dev/bhnd/bhndreg.h
+++ b/sys/dev/bhnd/bhndreg.h
@@ -1,31 +1,24 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2010 Broadcom Corporation
* All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
- * redistribution must be conditioned upon including a substantially
- * similar Disclaimer requirement for further binary redistribution.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGES.
+ * Portions of this file were derived from the sbchipc.h header contributed by
+ * Broadcom to to the Linux staging repository, as well as later revisions of
+ * sbchipc.h distributed with the Asus RT-N16 firmware source code release.
*
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
* $FreeBSD$
*/
@@ -49,4 +42,50 @@
*/
#define BHND_DEFAULT_ENUM_SIZE 0x00100000
-#endif /* _BHND_BHNDREG_H_ */ \ No newline at end of file
+/*
+ * Common per-core clock control/status register available on PMU-equipped
+ * devices.
+ *
+ * Clock Mode Name Description
+ * High Throughput (HT) Full bandwidth, low latency. Generally supplied
+ * from PLL.
+ * Active Low Power (ALP) Register access, low speed DMA.
+ * Idle Low Power (ILP) No interconnect activity, or if long latency
+ * is permitted.
+ */
+#define BHND_CLK_CTL_ST 0x1e0 /**< clock control and status */
+#define BHND_CCS_FORCEALP 0x00000001 /**< force ALP request */
+#define BHND_CCS_FORCEHT 0x00000002 /**< force HT request */
+#define BHND_CCS_FORCEILP 0x00000004 /**< force ILP request */
+#define BHND_CCS_FORCE_MASK 0x0000000F
+
+#define BHND_CCS_ALPAREQ 0x00000008 /**< ALP Avail Request */
+#define BHND_CCS_HTAREQ 0x00000010 /**< HT Avail Request */
+#define BHND_CCS_AREQ_MASK 0x00000018
+
+#define BHND_CCS_FORCEHWREQOFF 0x00000020 /**< Force HW Clock Request Off */
+
+#define BHND_CCS_ERSRC_REQ_MASK 0x00000700 /**< external resource requests */
+#define BHND_CCS_ERSRC_REQ_SHIFT 8
+#define BHND_CCS_ERSRC_MAX 2 /**< maximum ERSRC value (corresponding to bits 0-2) */
+
+#define BHND_CCS_ALPAVAIL 0x00010000 /**< ALP is available */
+#define BHND_CCS_HTAVAIL 0x00020000 /**< HT is available */
+#define BHND_CCS_AVAIL_MASK 0x00030000
+
+#define BHND_CCS_BP_ON_APL 0x00040000 /**< RO: Backplane is running on ALP clock */
+#define BHND_CCS_BP_ON_HT 0x00080000 /**< RO: Backplane is running on HT clock */
+#define BHND_CCS_ERSRC_STS_MASK 0x07000000 /**< external resource status */
+#define BHND_CCS_ERSRC_STS_SHIFT 24
+
+#define BHND_CCS0_HTAVAIL 0x00010000 /**< HT avail in chipc and pcmcia on 4328a0 */
+#define BHND_CCS0_ALPAVAIL 0x00020000 /**< ALP avail in chipc and pcmcia on 4328a0 */
+
+#define BHND_CCS_GET_FLAG(_value, _flag) \
+ (((_value) & _flag) != 0)
+#define BHND_CCS_GET_BITS(_value, _field) \
+ (((_value) & _field ## _MASK) >> _field ## _SHIFT)
+#define BHND_CCS_SET_BITS(_value, _field) \
+ (((_value) << _field ## _SHIFT) & _field ## _MASK)
+
+#endif /* _BHND_BHNDREG_H_ */
diff --git a/sys/dev/bhnd/bhndvar.h b/sys/dev/bhnd/bhndvar.h
index 777a96b46167..6e03baae85c2 100644
--- a/sys/dev/bhnd/bhndvar.h
+++ b/sys/dev/bhnd/bhndvar.h
@@ -38,10 +38,7 @@
#include <sys/param.h>
#include <sys/bus.h>
-#include <sys/lock.h>
#include <sys/malloc.h>
-#include <sys/queue.h>
-#include <sys/sx.h>
#include "bhnd.h"
@@ -52,6 +49,17 @@
MALLOC_DECLARE(M_BHND);
DECLARE_CLASS(bhnd_driver);
+struct bhnd_core_clkctl;
+
+struct bhnd_core_clkctl *bhnd_alloc_core_clkctl(device_t dev,
+ device_t pmu_dev, struct bhnd_resource *r,
+ bus_size_t offset, u_int max_latency);
+void bhnd_free_core_clkctl(
+ struct bhnd_core_clkctl *clkctl);
+int bhnd_core_clkctl_wait(
+ struct bhnd_core_clkctl *clkctl,
+ uint32_t value, uint32_t mask);
+
int bhnd_generic_attach(device_t dev);
int bhnd_generic_detach(device_t dev);
int bhnd_generic_shutdown(device_t dev);
@@ -65,6 +73,12 @@ int bhnd_generic_alloc_pmu(device_t dev,
device_t child);
int bhnd_generic_release_pmu(device_t dev,
device_t child);
+int bhnd_generic_get_clock_latency(device_t dev,
+ device_t child, bhnd_clock clock,
+ u_int *latency);
+int bhnd_generic_get_clock_freq(device_t dev,
+ device_t child, bhnd_clock clock,
+ u_int *freq);
int bhnd_generic_request_clock(device_t dev,
device_t child, bhnd_clock clock);
int bhnd_generic_enable_clocks(device_t dev,
diff --git a/sys/dev/bhnd/cores/chipc/chipc.c b/sys/dev/bhnd/cores/chipc/chipc.c
index cead2afbf33f..157f80114b07 100644
--- a/sys/dev/bhnd/cores/chipc/chipc.c
+++ b/sys/dev/bhnd/cores/chipc/chipc.c
@@ -4,8 +4,8 @@
* Copyright (c) 2017 The FreeBSD Foundation
* All rights reserved.
*
- * This software was developed by Landon Fuller under sponsorship from
- * the FreeBSD Foundation.
+ * Portions of this software were developed by Landon Fuller
+ * under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -209,11 +209,17 @@ chipc_attach(device_t dev)
if ((error = chipc_add_children(sc)))
goto failed;
- if ((error = bus_generic_attach(dev)))
+ /*
+ * Register ourselves with the bus; we're fully initialized and can
+ * response to ChipCommin API requests.
+ *
+ * Since our children may need access to ChipCommon, this must be done
+ * before attaching our children below (via bus_generic_attach).
+ */
+ if ((error = bhnd_register_provider(dev, BHND_SERVICE_CHIPC)))
goto failed;
- /* Register ourselves with the bus */
- if ((error = bhnd_register_provider(dev, BHND_SERVICE_CHIPC)))
+ if ((error = bus_generic_attach(dev)))
goto failed;
return (0);
@@ -286,12 +292,18 @@ chipc_add_children(struct chipc_softc *sc)
* On AOB ("Always on Bus") devices, the PMU core (if it exists) is
* attached directly to the bhnd(4) bus -- not chipc.
*/
- if (sc->caps.pwr_ctrl || (sc->caps.pmu && !sc->caps.aob)) {
- child = BUS_ADD_CHILD(sc->dev, 0, "bhnd_pmu", -1);
+ if (sc->caps.pmu && !sc->caps.aob) {
+ child = BUS_ADD_CHILD(sc->dev, 0, "bhnd_pmu", 0);
if (child == NULL) {
device_printf(sc->dev, "failed to add pmu\n");
return (ENXIO);
}
+ } else if (sc->caps.pwr_ctrl) {
+ child = BUS_ADD_CHILD(sc->dev, 0, "bhnd_pwrctl", 0);
+ if (child == NULL) {
+ device_printf(sc->dev, "failed to add pwrctl\n");
+ return (ENXIO);
+ }
}
/* All remaining devices are SoC-only */
diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c
index 90155418ed7f..006f31452db6 100644
--- a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c
+++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c
@@ -4,11 +4,11 @@
* Copyright (c) 2017 The FreeBSD Foundation
* All rights reserved.
*
- * This software was developed by Landon Fuller under sponsorship from
- * the FreeBSD Foundation.
+ * Portions of this software were developed by Landon Fuller
+ * under sponsorship from the FreeBSD Foundation.
*
- * This file is derived from the siutils.c source distributed with the
- * Asus RT-N16 firmware source code release.
+ * Portions of this file were derived from the siutils.c source distributed with
+ * the Asus RT-N16 firmware source code release.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -45,14 +45,16 @@ __FBSDID("$FreeBSD$");
#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
#include "bhnd_chipc_if.h"
+#include "bhnd_pwrctl_if.h"
+#include "bhnd_pwrctl_hostb_if.h"
#include "bhnd_pwrctl_private.h"
/*
* ChipCommon Power Control.
*
- * Provides a bhnd_pmu_if-compatible interface to device clocking and
- * power management on non-PMU chipsets.
+ * Provides a runtime interface to device clocking and power management on
+ * legacy non-PMU chipsets.
*/
typedef enum {
@@ -125,9 +127,6 @@ bhnd_pwrctl_attach(device_t dev)
sc = device_get_softc(dev);
- /* TODO: Need further testing on actual PWRCTL hardware */
- device_printf(dev, "WARNING: Using untested PWRCTL support\n");
-
sc->dev = dev;
sc->chipc_dev = device_get_parent(dev);
sc->quirks = bhnd_device_quirks(sc->chipc_dev, pwrctl_devices,
@@ -184,10 +183,10 @@ bhnd_pwrctl_attach(device_t dev)
PWRCTL_UNLOCK(sc);
- /* Register as the bus PMU provider */
- if ((error = bhnd_register_provider(dev, BHND_SERVICE_PMU))) {
- device_printf(sc->dev, "failed to register PMU with bus : %d\n",
- error);
+ /* Register as the bus PWRCTL provider */
+ if ((error = bhnd_register_provider(dev, BHND_SERVICE_PWRCTL))) {
+ device_printf(sc->dev, "failed to register PWRCTL with bus : "
+ "%d\n", error);
goto cleanup;
}
@@ -268,22 +267,61 @@ cleanup:
return (error);
}
+static int
+bhnd_pwrctl_get_clock_latency(device_t dev, bhnd_clock clock,
+ u_int *latency)
+{
+ struct bhnd_pwrctl_softc *sc = device_get_softc(dev);
+
+ switch (clock) {
+ case BHND_CLOCK_HT:
+ PWRCTL_LOCK(sc);
+ *latency = bhnd_pwrctl_fast_pwrup_delay(sc);
+ PWRCTL_UNLOCK(sc);
+
+ return (0);
+
+ default:
+ return (ENODEV);
+ }
+}
+
+static int
+bhnd_pwrctl_get_clock_freq(device_t dev, bhnd_clock clock, u_int *freq)
+{
+ struct bhnd_pwrctl_softc *sc = device_get_softc(dev);
+
+ switch (clock) {
+ case BHND_CLOCK_ALP:
+ BPMU_LOCK(sc);
+ *freq = bhnd_pwrctl_getclk_speed(sc);
+ BPMU_UNLOCK(sc);
+
+ return (0);
+
+ case BHND_CLOCK_HT:
+ case BHND_CLOCK_ILP:
+ case BHND_CLOCK_DYN:
+ default:
+ return (ENODEV);
+ }
+}
+
/**
- * Find the clock reservation associated with @p pinfo, if any.
+ * Find the clock reservation associated with @p owner, if any.
*
* @param sc Driver instance state.
- * @param pinfo PMU info for device.
+ * @param owner The owning device.
*/
static struct bhnd_pwrctl_clkres *
-bhnd_pwrctl_find_res(struct bhnd_pwrctl_softc *sc,
- struct bhnd_core_pmu_info *pinfo)
+bhnd_pwrctl_find_res(struct bhnd_pwrctl_softc *sc, device_t owner)
{
struct bhnd_pwrctl_clkres *clkres;
PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
STAILQ_FOREACH(clkres, &sc->clkres_list, cr_link) {
- if (clkres->owner == pinfo->pm_dev)
+ if (clkres->owner == owner)
return (clkres);
}
@@ -357,9 +395,9 @@ bhnd_pwrctl_updateclk(struct bhnd_pwrctl_softc *sc, bhnd_pwrctl_wars wars)
return (bhnd_pwrctl_setclk(sc, clock));
}
+/* BHND_PWRCTL_REQUEST_CLOCK() */
static int
-bhnd_pwrctl_core_req_clock(device_t dev, struct bhnd_core_pmu_info *pinfo,
- bhnd_clock clock)
+bhnd_pwrctl_request_clock(device_t dev, device_t child, bhnd_clock clock)
{
struct bhnd_pwrctl_softc *sc;
struct bhnd_pwrctl_clkres *clkres;
@@ -370,7 +408,7 @@ bhnd_pwrctl_core_req_clock(device_t dev, struct bhnd_core_pmu_info *pinfo,
PWRCTL_LOCK(sc);
- clkres = bhnd_pwrctl_find_res(sc, pinfo);
+ clkres = bhnd_pwrctl_find_res(sc, child);
/* BHND_CLOCK_DYN discards the clock reservation entirely */
if (clock == BHND_CLOCK_DYN) {
@@ -409,12 +447,12 @@ bhnd_pwrctl_core_req_clock(device_t dev, struct bhnd_core_pmu_info *pinfo,
if (clkres == NULL)
return (ENOMEM);
- clkres->owner = pinfo->pm_dev;
+ clkres->owner = child;
clkres->clock = clock;
STAILQ_INSERT_TAIL(&sc->clkres_list, clkres, cr_link);
} else {
- KASSERT(clkres->owner == pinfo->pm_dev, ("invalid owner"));
+ KASSERT(clkres->owner == child, ("invalid owner"));
clkres->clock = clock;
}
@@ -430,68 +468,24 @@ bhnd_pwrctl_core_req_clock(device_t dev, struct bhnd_core_pmu_info *pinfo,
return (error);
}
-static int
-bhnd_pwrctl_core_req_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo,
- u_int rsrc)
-{
- /* HW does not support per-core external resources */
- return (ENODEV);
-}
-
-static int
-bhnd_pwrctl_core_release_ext_rsrc(device_t dev,
- struct bhnd_core_pmu_info *pinfo, u_int rsrc)
-{
- /* HW does not support per-core external resources */
- return (ENODEV);
-}
-
-static int
-bhnd_pwrctl_core_en_clocks(device_t dev, struct bhnd_core_pmu_info *pinfo,
- uint32_t clocks)
-{
- /* All supported clocks are already enabled by default (?) */
- clocks &= ~(BHND_CLOCK_DYN |
- BHND_CLOCK_ILP |
- BHND_CLOCK_ALP |
- BHND_CLOCK_HT);
-
- if (clocks != 0) {
- device_printf(dev, "%s requested unknown clocks: %#x\n",
- device_get_nameunit(pinfo->pm_dev), clocks);
- return (ENODEV);
- }
-
- return (0);
-}
-
-static int
-bhnd_pwrctl_core_release(device_t dev, struct bhnd_core_pmu_info *pinfo)
-{
- /* Requesting BHND_CLOCK_DYN releases any outstanding clock
- * reservations */
- return (bhnd_pwrctl_core_req_clock(dev, pinfo, BHND_CLOCK_DYN));
-}
static device_method_t bhnd_pwrctl_methods[] = {
/* Device interface */
- DEVMETHOD(device_probe, bhnd_pwrctl_probe),
- DEVMETHOD(device_attach, bhnd_pwrctl_attach),
- DEVMETHOD(device_detach, bhnd_pwrctl_detach),
- DEVMETHOD(device_suspend, bhnd_pwrctl_suspend),
- DEVMETHOD(device_resume, bhnd_pwrctl_resume),
-
- /* BHND PMU interface */
- DEVMETHOD(bhnd_pmu_core_req_clock, bhnd_pwrctl_core_req_clock),
- DEVMETHOD(bhnd_pmu_core_en_clocks, bhnd_pwrctl_core_en_clocks),
- DEVMETHOD(bhnd_pmu_core_req_ext_rsrc, bhnd_pwrctl_core_req_ext_rsrc),
- DEVMETHOD(bhnd_pmu_core_release_ext_rsrc, bhnd_pwrctl_core_release_ext_rsrc),
- DEVMETHOD(bhnd_pmu_core_release, bhnd_pwrctl_core_release),
+ DEVMETHOD(device_probe, bhnd_pwrctl_probe),
+ DEVMETHOD(device_attach, bhnd_pwrctl_attach),
+ DEVMETHOD(device_detach, bhnd_pwrctl_detach),
+ DEVMETHOD(device_suspend, bhnd_pwrctl_suspend),
+ DEVMETHOD(device_resume, bhnd_pwrctl_resume),
+
+ /* BHND PWRCTL interface */
+ DEVMETHOD(bhnd_pwrctl_request_clock, bhnd_pwrctl_request_clock),
+ DEVMETHOD(bhnd_pwrctl_get_clock_freq, bhnd_pwrctl_get_clock_freq),
+ DEVMETHOD(bhnd_pwrctl_get_clock_latency, bhnd_pwrctl_get_clock_latency),
DEVMETHOD_END
};
-DEFINE_CLASS_0(bhnd_pmu, bhnd_pwrctl_driver, bhnd_pwrctl_methods,
+DEFINE_CLASS_0(bhnd_pwrctl, bhnd_pwrctl_driver, bhnd_pwrctl_methods,
sizeof(struct bhnd_pwrctl_softc));
EARLY_DRIVER_MODULE(bhnd_pwrctl, bhnd_chipc, bhnd_pwrctl_driver,
bhnd_pmu_devclass, NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h
new file mode 100644
index 000000000000..3d05709d5b38
--- /dev/null
+++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2017 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Landon Fuller under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BHND_PWRCTL_BHND_PWRCTL_H_
+#define _BHND_PWRCTL_BHND_PWRCTL_H_
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include "bhnd_pwrctl_if.h"
+
+/**
+ * Request that @p clock (or a faster clock) be enabled on behalf of
+ * @p child.
+ *
+ * @param dev PWRCTL device.
+ * @param child The requesting bhnd(4) device.
+ * @param clock Clock requested.
+ *
+ * @retval 0 success
+ * @retval ENODEV If an unsupported clock was requested.
+ */
+static inline int
+bhnd_pwrctl_request_clock(device_t dev, device_t child, bhnd_clock clock)
+{
+ return (BHND_PWRCTL_REQUEST_CLOCK(dev, child, clock));
+}
+
+/**
+ * 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.
+ *
+ * @param dev PWRCTL 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_pwrctl_get_clock_latency(device_t dev, bhnd_clock clock, u_int *latency)
+{
+ return (BHND_PWRCTL_GET_CLOCK_LATENCY(dev, clock, latency));
+}
+
+/**
+ * Return the frequency for @p clock in Hz, if known.
+ *
+ * @param dev PWRCTL device.
+ * @param clock The clock to be queried.
+ * @param[out] freq On success, the frequency of @p clock in Hz.
+ *
+ * @retval 0 success
+ * @retval ENODEV If the frequency for @p clock is not available.
+ */
+static inline int
+bhnd_pwrctl_get_clock_freq(device_t dev, bhnd_clock clock, u_int *freq)
+{
+ return (BHND_PWRCTL_GET_CLOCK_FREQ(dev, clock, freq));
+}
+
+#endif /* _BHND_PWRCTL_BHND_PWRCTL_H_ */
diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_hostb_if.m b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_hostb_if.m
new file mode 100644
index 000000000000..117cb6c4f93c
--- /dev/null
+++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_hostb_if.m
@@ -0,0 +1,129 @@
+#-
+# Copyright (c) 2016 Landon Fuller <landon@landonf.org>
+# Copyright (c) 2017 The FreeBSD Foundation
+# All rights reserved.
+#
+# Portions of this software were developed by Landon Fuller
+# under sponsorship from the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# $FreeBSD$
+
+#include <sys/types.h>
+#include <sys/bus.h>
+
+#include <dev/bhnd/bhnd.h>
+
+INTERFACE bhnd_pwrctl_hostb;
+
+#
+# bhnd(4) PWRCTL host bridge interface.
+#
+# Provides a common interface to the clock hardware managed by a parent host
+# bridge (e.g. bhndb_pci(4)).
+#
+# Early PWRCTL chipsets[1] expose clock management via their host bridge
+# interface, requiring that a host bridge driver (e.g. bhndb(4)) work in
+# tandem with the ChipCommon-attached PWRCTL driver.
+#
+# [1] Currently, this is known to include PCI (not PCIe) devices, with
+# ChipCommon core revisions 0-9.
+#
+
+HEADER {
+ #include <dev/bhnd/bhnd.h>
+};
+
+CODE {
+ static bhnd_clksrc
+ bhnd_pwrctl_hostb_get_clksrc(device_t dev, device_t child,
+ bhnd_clock clock)
+ {
+ return (BHND_CLKSRC_UNKNOWN);
+ }
+
+ static int
+ bhnd_pwrctl_hostb_gate_clock(device_t dev, device_t child,
+ bhnd_clock clock)
+ {
+ return (ENODEV);
+ }
+
+ static int
+ bhnd_pwrctl_hostb_ungate_clock(device_t dev, device_t child,
+ bhnd_clock clock)
+ {
+ return (ENODEV);
+ }
+
+};
+
+/**
+ * If supported by the chipset, return the clock source for the given clock.
+ *
+ * @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.
+ *
+ * @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.
+ */
+METHOD bhnd_clksrc get_clksrc {
+ device_t dev;
+ device_t child;
+ bhnd_clock clock;
+} DEFAULT bhnd_pwrctl_hostb_get_clksrc;
+
+/**
+ * If supported by the chipset, gate the clock source for @p clock.
+ *
+ * @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.
+ */
+METHOD int gate_clock {
+ device_t dev;
+ device_t child;
+ bhnd_clock clock;
+} DEFAULT bhnd_pwrctl_hostb_gate_clock;
+
+/**
+ * If supported by the chipset, ungate the clock source for @p clock.
+ *
+ * @param dev The parent of @p child.
+ * @param child The bhnd device requesting clock gating.
+ * @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.
+ */
+METHOD int ungate_clock {
+ device_t dev;
+ device_t child;
+ bhnd_clock clock;
+} DEFAULT bhnd_pwrctl_hostb_ungate_clock; \ No newline at end of file
diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_if.m b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_if.m
new file mode 100644
index 000000000000..3305269632ec
--- /dev/null
+++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_if.m
@@ -0,0 +1,98 @@
+#-
+# Copyright (c) 2016 Landon Fuller <landon@landonf.org>
+# Copyright (c) 2017 The FreeBSD Foundation
+# All rights reserved.
+#
+# Portions of this software were developed by Landon Fuller
+# under sponsorship from the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# $FreeBSD$
+
+#include <sys/types.h>
+#include <sys/bus.h>
+
+#include <dev/bhnd/bhnd.h>
+
+INTERFACE bhnd_pwrctl;
+
+#
+# bhnd(4) PWRCTL interface.
+#
+
+HEADER {
+ #include <dev/bhnd/bhnd.h>
+};
+
+/**
+ * Request that @p clock (or a faster clock) be enabled on behalf of
+ * @p child.
+ *
+ * @param dev PWRCTL device.
+ * @param child The requesting bhnd(4) device.
+ * @param clock Clock requested.
+ *
+ * @retval 0 success
+ * @retval ENODEV If an unsupported clock was requested.
+ */
+METHOD int request_clock {
+ device_t dev;
+ device_t child;
+ bhnd_clock clock;
+};
+
+/**
+ * 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.
+ *
+ * @param dev PWRCTL 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 get_clock_latency {
+ device_t dev;
+ bhnd_clock clock;
+ u_int *latency;
+};
+
+/**
+ * Return the frequency for @p clock in Hz, if known.
+ *
+ * @param dev PWRCTL device.
+ * @param clock The clock to be queried.
+ * @param[out] freq On success, the frequency of @p clock in Hz.
+ *
+ * @retval 0 success
+ * @retval ENODEV If the frequency for @p clock is not available.
+ */
+METHOD int get_clock_freq {
+ device_t dev;
+ bhnd_clock clock;
+ u_int *freq;
+};
diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h
index 0e4eb1a284bf..8bf04e7ed65c 100644
--- a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h
+++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h
@@ -1,7 +1,11 @@
/*-
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
+ * Copyright (c) 2017 The FreeBSD Foundation
* All rights reserved.
*
+ * Portions of this software were developed by Landon Fuller
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -32,12 +36,77 @@
#ifndef _BHND_PWRCTL_BHND_PWRCTL_PRIVATE_H_
#define _BHND_PWRCTL_BHND_PWRCTL_PRIVATE_H_
+#include "bhnd_pwrctl_hostb_if.h"
+
#include "bhnd_pwrctlvar.h"
int bhnd_pwrctl_init(struct bhnd_pwrctl_softc *sc);
int bhnd_pwrctl_setclk(struct bhnd_pwrctl_softc *sc,
bhnd_clock clock);
uint32_t bhnd_pwrctl_getclk_speed(struct bhnd_pwrctl_softc *sc);
-uint16_t bhnd_pwrctl_fast_pwrup_delay(struct bhnd_pwrctl_softc *sc);
+u_int bhnd_pwrctl_fast_pwrup_delay(struct bhnd_pwrctl_softc *sc);
+
+/**
+ * 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_hostb_get_clksrc(device_t dev, bhnd_clock clock)
+{
+ return (BHND_PWRCTL_HOSTB_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_hostb_gate_clock(device_t dev, bhnd_clock clock)
+{
+ return (BHND_PWRCTL_HOSTB_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_hostb_ungate_clock(device_t dev, bhnd_clock clock)
+{
+ return (BHND_PWRCTL_HOSTB_UNGATE_CLOCK(device_get_parent(dev), dev,
+ clock));
+}
#endif /* _BHND_PWRCTL_BHND_PWRCTL_PRIVATE_H_ */
diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c
index 9d5052c89c39..4a280632c52e 100644
--- a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c
+++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c
@@ -333,7 +333,8 @@ bhnd_pwrctl_slowclk_src(struct bhnd_pwrctl_softc *sc)
/* Fetch clock source */
if (PWRCTL_QUIRK(sc, PCICLK_CTL)) {
- return (bhnd_pwrctl_get_clksrc(sc->chipc_dev, BHND_CLOCK_ILP));
+ return (bhnd_pwrctl_hostb_get_clksrc(sc->chipc_dev,
+ BHND_CLOCK_ILP));
} else if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
clkreg = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL);
clksrc = clkreg & CHIPC_SCC_SS_MASK;
@@ -460,11 +461,11 @@ bhnd_pwrctl_init(struct bhnd_pwrctl_softc *sc)
/* return the value suitable for writing to the dot11 core
* FAST_PWRUP_DELAY register */
-uint16_t
+u_int
bhnd_pwrctl_fast_pwrup_delay(struct bhnd_pwrctl_softc *sc)
{
- uint32_t pll_on_delay, slowminfreq;
- uint16_t fpdelay;
+ u_int pll_on_delay, slowminfreq;
+ u_int fpdelay;
fpdelay = 0;
@@ -516,7 +517,8 @@ bhnd_pwrctl_setclk(struct bhnd_pwrctl_softc *sc, bhnd_clock clock)
scc |= CHIPC_SCC_IP;
/* force xtal back on before clearing SCC_DYN_XTAL.. */
- bhnd_pwrctl_ungate_clock(sc->chipc_dev, BHND_CLOCK_HT);
+ bhnd_pwrctl_hostb_ungate_clock(sc->chipc_dev,
+ BHND_CLOCK_HT);
} else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
scc |= CHIPC_SYCC_HR;
} else {
@@ -543,7 +545,7 @@ bhnd_pwrctl_setclk(struct bhnd_pwrctl_softc *sc, bhnd_clock clock)
/* for dynamic control, we have to release our xtal_pu
* "force on" */
if (scc & CHIPC_SCC_XC) {
- bhnd_pwrctl_gate_clock(sc->chipc_dev,
+ bhnd_pwrctl_hostb_gate_clock(sc->chipc_dev,
BHND_CLOCK_HT);
}
} else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu.c b/sys/dev/bhnd/cores/pmu/bhnd_pmu.c
index 254fa309dd39..43bdba12c7d7 100644
--- a/sys/dev/bhnd/cores/pmu/bhnd_pmu.c
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu.c
@@ -47,7 +47,8 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/resource.h>
-#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/bhndreg.h>
+#include <dev/bhnd/bhndvar.h>
#include <dev/bhnd/cores/chipc/chipc.h>
#include "bhnd_nvram_map.h"
@@ -84,20 +85,6 @@ static const struct bhnd_pmu_io bhnd_pmu_res_io = {
.rd_chipst = bhnd_pmu_read_chipst
};
-#define BPMU_ASSERT_CLKCTL_AVAIL(_pinfo) \
- KASSERT(!bhnd_is_hw_suspended((_pinfo)->pm_dev), \
- ("reading clkctl on suspended core will trigger system livelock"))
-
-#define BPMU_CLKCTL_READ_4(_pinfo) \
- bhnd_bus_read_4((_pinfo)->pm_res, (_pinfo)->pm_regs)
-
-#define BPMU_CLKCTL_WRITE_4(_pinfo, _val) \
- bhnd_bus_write_4((_pinfo)->pm_res, (_pinfo)->pm_regs, (_val))
-
-#define BPMU_CLKCTL_SET_4(_pinfo, _val, _mask) \
- BPMU_CLKCTL_WRITE_4((_pinfo), \
- ((_val) & (_mask)) | (BPMU_CLKCTL_READ_4(_pinfo) & ~(_mask)))
-
/**
* Default bhnd_pmu driver implementation of DEVICE_PROBE().
*/
@@ -126,7 +113,6 @@ bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
sc = device_get_softc(dev);
sc->dev = dev;
- sc->quirks = 0;
sc->res = res;
/* Fetch capability flags */
@@ -147,6 +133,17 @@ bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
return (ENXIO);
}
+ /* Allocate our own core clkctl state directly; we use this to wait on
+ * PMU state transitions, avoiding a cyclic dependency between bhnd(4)'s
+ * clkctl handling and registration of this device as a PMU */
+ sc->clkctl = bhnd_alloc_core_clkctl(core, dev, sc->res, BHND_CLK_CTL_ST,
+ BHND_PMU_MAX_TRANSITION_DLY);
+ if (sc->clkctl == NULL) {
+ device_printf(sc->dev, "failed to allocate clkctl for %s\n",
+ device_get_nameunit(core));
+ return (ENOMEM);
+ }
+
/* Fetch chip and board info */
sc->cid = *bhnd_get_chipid(core);
@@ -157,7 +154,7 @@ bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
}
/* Locate ChipCommon device */
- sc->chipc_dev = bhnd_bus_find_child(bus, BHND_DEVCLASS_CC, 0);
+ sc->chipc_dev = bhnd_retain_provider(dev, BHND_SERVICE_CHIPC);
if (sc->chipc_dev == NULL) {
device_printf(sc->dev, "chipcommon device not found\n");
return (ENXIO);
@@ -173,17 +170,6 @@ bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
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);
@@ -218,6 +204,9 @@ bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
failed:
BPMU_LOCK_DESTROY(sc);
bhnd_pmu_query_fini(&sc->query);
+ bhnd_free_core_clkctl(sc->clkctl);
+ bhnd_release_provider(sc->dev, sc->chipc_dev, BHND_SERVICE_CHIPC);
+
return (error);
}
@@ -237,7 +226,9 @@ bhnd_pmu_detach(device_t dev)
BPMU_LOCK_DESTROY(sc);
bhnd_pmu_query_fini(&sc->query);
-
+ bhnd_free_core_clkctl(sc->clkctl);
+ bhnd_release_provider(sc->dev, sc->chipc_dev, BHND_SERVICE_CHIPC);
+
return (0);
}
@@ -315,189 +306,270 @@ bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS)
return (sysctl_handle_32(oidp, NULL, freq, req));
}
-static int
-bhnd_pmu_core_req_clock(device_t dev, struct bhnd_core_pmu_info *pinfo,
- bhnd_clock clock)
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_READ_CHIPCTRL().
+ */
+static uint32_t
+bhnd_pmu_read_chipctrl_method(device_t dev, uint32_t reg)
{
- struct bhnd_pmu_softc *sc;
- uint32_t avail;
- uint32_t req;
-
- BPMU_ASSERT_CLKCTL_AVAIL(pinfo);
+ struct bhnd_pmu_softc *sc;
+ uint32_t rval;
sc = device_get_softc(dev);
- avail = 0x0;
- req = 0x0;
+ BPMU_LOCK(sc);
+ rval = BHND_PMU_CCTRL_READ(sc, reg);
+ BPMU_UNLOCK(sc);
- 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(pinfo->pm_dev), clock);
- return (ENODEV);
- }
+ return (rval);
+}
+
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_WRITE_CHIPCTRL().
+ */
+static void
+bhnd_pmu_write_chipctrl_method(device_t dev, uint32_t reg, uint32_t value,
+ uint32_t mask)
+{
+ struct bhnd_pmu_softc *sc = device_get_softc(dev);
BPMU_LOCK(sc);
+ BHND_PMU_CCTRL_WRITE(sc, reg, value, mask);
+ BPMU_UNLOCK(sc);
+}
- /* Issue request */
- BPMU_CLKCTL_SET_4(pinfo, req, BHND_CCS_FORCE_MASK);
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_READ_REGCTRL().
+ */
+static uint32_t
+bhnd_pmu_read_regctrl_method(device_t dev, uint32_t reg)
+{
+ struct bhnd_pmu_softc *sc;
+ uint32_t rval;
- /* Wait for clock availability */
- bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
- avail, avail);
+ sc = device_get_softc(dev);
+ BPMU_LOCK(sc);
+ rval = BHND_PMU_REGCTRL_READ(sc, reg);
BPMU_UNLOCK(sc);
- return (0);
+ return (rval);
}
-static int
-bhnd_pmu_core_en_clocks(device_t dev, struct bhnd_core_pmu_info *pinfo,
- uint32_t clocks)
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_WRITE_REGCTRL().
+ */
+static void
+bhnd_pmu_write_regctrl_method(device_t dev, uint32_t reg, uint32_t value,
+ uint32_t mask)
{
- struct bhnd_pmu_softc *sc;
- uint32_t avail;
- uint32_t req;
+ struct bhnd_pmu_softc *sc = device_get_softc(dev);
+
+ BPMU_LOCK(sc);
+ BHND_PMU_REGCTRL_WRITE(sc, reg, value, mask);
+ BPMU_UNLOCK(sc);
+}
- BPMU_ASSERT_CLKCTL_AVAIL(pinfo);
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_READ_PLLCTRL().
+ */
+static uint32_t
+bhnd_pmu_read_pllctrl_method(device_t dev, uint32_t reg)
+{
+ struct bhnd_pmu_softc *sc;
+ uint32_t rval;
sc = device_get_softc(dev);
- avail = 0x0;
- req = 0x0;
+ BPMU_LOCK(sc);
+ rval = BHND_PMU_PLL_READ(sc, reg);
+ BPMU_UNLOCK(sc);
- /* Build clock request flags */
- if (clocks & BHND_CLOCK_DYN) /* nothing to enable */
- clocks &= ~BHND_CLOCK_DYN;
+ return (rval);
+}
- if (clocks & BHND_CLOCK_ILP) /* nothing to enable */
- clocks &= ~BHND_CLOCK_ILP;
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_WRITE_PLLCTRL().
+ */
+static void
+bhnd_pmu_write_pllctrl_method(device_t dev, uint32_t reg, uint32_t value,
+ uint32_t mask)
+{
+ struct bhnd_pmu_softc *sc = device_get_softc(dev);
- if (clocks & BHND_CLOCK_ALP) {
- req |= BHND_CCS_ALPAREQ;
- avail |= BHND_CCS_ALPAVAIL;
- clocks &= ~BHND_CLOCK_ALP;
- }
+ BPMU_LOCK(sc);
+ BHND_PMU_PLL_WRITE(sc, reg, value, mask);
+ BPMU_UNLOCK(sc);
+}
- if (clocks & BHND_CLOCK_HT) {
- req |= BHND_CCS_HTAREQ;
- avail |= BHND_CCS_HTAVAIL;
- clocks &= ~BHND_CLOCK_HT;
- }
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_SET_VOLTAGE_RAW().
+ */
+static int
+bhnd_pmu_set_voltage_raw_method(device_t dev, bhnd_pmu_regulator regulator,
+ uint32_t value)
+{
+ struct bhnd_pmu_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
- /* Check for unknown clock values */
- if (clocks != 0x0) {
- device_printf(dev, "%s requested unknown clocks: %#x\n",
- device_get_nameunit(pinfo->pm_dev), clocks);
+ switch (regulator) {
+ case BHND_REGULATOR_PAREF_LDO:
+ if (value > UINT8_MAX)
+ return (EINVAL);
+
+ BPMU_LOCK(sc);
+ error = bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_PAREF,
+ value);
+ BPMU_UNLOCK(sc);
+
+ return (error);
+
+ default:
return (ENODEV);
}
+}
- BPMU_LOCK(sc);
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_ENABLE_REGULATOR().
+ */
+static int
+bhnd_pmu_enable_regulator_method(device_t dev, bhnd_pmu_regulator regulator)
+{
+ struct bhnd_pmu_softc *sc;
+ int error;
- /* Issue request */
- BPMU_CLKCTL_SET_4(pinfo, req, BHND_CCS_AREQ_MASK);
+ sc = device_get_softc(dev);
- /* Wait for clock availability */
- bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
- avail, avail);
+ switch (regulator) {
+ case BHND_REGULATOR_PAREF_LDO:
+ BPMU_LOCK(sc);
+ error = bhnd_pmu_paref_ldo_enable(sc, true);
+ BPMU_UNLOCK(sc);
- BPMU_UNLOCK(sc);
+ return (error);
- return (0);
+ default:
+ return (ENODEV);
+ }
}
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_DISABLE_REGULATOR().
+ */
static int
-bhnd_pmu_core_req_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo,
- u_int rsrc)
+bhnd_pmu_disable_regulator_method(device_t dev, bhnd_pmu_regulator regulator)
{
struct bhnd_pmu_softc *sc;
- uint32_t req;
- uint32_t avail;
-
- BPMU_ASSERT_CLKCTL_AVAIL(pinfo);
+ int error;
sc = device_get_softc(dev);
- if (rsrc > BHND_CCS_ERSRC_MAX)
- return (EINVAL);
+ switch (regulator) {
+ case BHND_REGULATOR_PAREF_LDO:
+ BPMU_LOCK(sc);
+ error = bhnd_pmu_paref_ldo_enable(sc, false);
+ BPMU_UNLOCK(sc);
- req = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
- avail = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_STS);
+ return (error);
+
+ default:
+ return (ENODEV);
+ }
+}
- BPMU_LOCK(sc);
- /* Write request */
- BPMU_CLKCTL_SET_4(pinfo, req, req);
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_GET_CLOCK_LATENCY().
+ */
+static int
+bhnd_pmu_get_clock_latency_method(device_t dev, bhnd_clock clock,
+ u_int *latency)
+{
+ struct bhnd_pmu_softc *sc;
+ u_int pwrup_delay;
+ int error;
- /* Wait for resource availability */
- bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
- avail, avail);
+ sc = device_get_softc(dev);
- BPMU_UNLOCK(sc);
+ switch (clock) {
+ case BHND_CLOCK_HT:
+ BPMU_LOCK(sc);
+ error = bhnd_pmu_fast_pwrup_delay(sc, &pwrup_delay);
+ BPMU_UNLOCK(sc);
- return (0);
+ if (error)
+ return (error);
+
+ *latency = pwrup_delay;
+ return (0);
+
+ default:
+ return (ENODEV);
+ }
}
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_GET_CLOCK_FREQ().
+ */
static int
-bhnd_pmu_core_release_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo,
- u_int rsrc)
+bhnd_pmu_get_clock_freq_method(device_t dev, bhnd_clock clock, uint32_t *freq)
{
- struct bhnd_pmu_softc *sc;
- uint32_t mask;
+ struct bhnd_pmu_softc *sc = device_get_softc(dev);
- BPMU_ASSERT_CLKCTL_AVAIL(pinfo);
+ BPMU_LOCK(sc);
+ switch (clock) {
+ case BHND_CLOCK_HT:
+ *freq = bhnd_pmu_si_clock(&sc->query);
+ break;
- sc = device_get_softc(dev);
+ case BHND_CLOCK_ALP:
+ *freq = bhnd_pmu_alp_clock(&sc->query);
+ break;
- if (rsrc > BHND_CCS_ERSRC_MAX)
- return (EINVAL);
+ case BHND_CLOCK_ILP:
+ *freq = bhnd_pmu_ilp_clock(&sc->query);
+ break;
- mask = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
+ case BHND_CLOCK_DYN:
+ default:
+ BPMU_UNLOCK(sc);
+ return (ENODEV);
+ }
- /* Clear request */
- BPMU_LOCK(sc);
- BPMU_CLKCTL_SET_4(pinfo, 0x0, mask);
BPMU_UNLOCK(sc);
-
- return (0);
+ return (0);
}
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_REQUEST_SPURAVOID().
+ */
static int
-bhnd_pmu_core_release(device_t dev, struct bhnd_core_pmu_info *pinfo)
+bhnd_pmu_request_spuravoid_method(device_t dev, bhnd_pmu_spuravoid spuravoid)
{
struct bhnd_pmu_softc *sc;
+ int error;
sc = device_get_softc(dev);
- /* On PMU-equipped hardware, clkctl is cleared on RESET (and
- * attempting to access it will trigger a system livelock). */
- if (bhnd_is_hw_suspended(pinfo->pm_dev))
- return (0);
-
BPMU_LOCK(sc);
-
- /* Clear all FORCE, AREQ, and ERSRC flags */
- BPMU_CLKCTL_SET_4(pinfo, 0x0,
- BHND_CCS_FORCE_MASK | BHND_CCS_AREQ_MASK | BHND_CCS_ERSRC_REQ_MASK);
-
+ error = bhnd_pmu_set_spuravoid(sc, spuravoid);
BPMU_UNLOCK(sc);
- return (0);
+ return (error);
+}
+
+/**
+ * Default bhnd_pmu driver implementation of BHND_PMU_GET_TRANSITION_LATENCY().
+ */
+static u_int
+bhnd_pmu_get_max_transition_latency_method(device_t dev)
+{
+ return (BHND_PMU_MAX_TRANSITION_DLY);
}
+/* bhnd_pmu_query read_4 callback */
static uint32_t
bhnd_pmu_read_4(bus_size_t reg, void *ctx)
{
@@ -505,6 +577,7 @@ bhnd_pmu_read_4(bus_size_t reg, void *ctx)
return (bhnd_bus_read_4(sc->res, reg));
}
+/* bhnd_pmu_query write_4 callback */
static void
bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx)
{
@@ -512,6 +585,7 @@ bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx)
return (bhnd_bus_write_4(sc->res, reg, val));
}
+/* bhnd_pmu_query read_chipst callback */
static uint32_t
bhnd_pmu_read_chipst(void *ctx)
{
@@ -521,18 +595,28 @@ bhnd_pmu_read_chipst(void *ctx)
static device_method_t bhnd_pmu_methods[] = {
/* Device interface */
- DEVMETHOD(device_probe, bhnd_pmu_probe),
- DEVMETHOD(device_detach, bhnd_pmu_detach),
- DEVMETHOD(device_suspend, bhnd_pmu_suspend),
- DEVMETHOD(device_resume, bhnd_pmu_resume),
+ DEVMETHOD(device_probe, bhnd_pmu_probe),
+ DEVMETHOD(device_detach, bhnd_pmu_detach),
+ DEVMETHOD(device_suspend, bhnd_pmu_suspend),
+ DEVMETHOD(device_resume, bhnd_pmu_resume),
/* BHND PMU interface */
- DEVMETHOD(bhnd_pmu_core_req_clock, bhnd_pmu_core_req_clock),
- DEVMETHOD(bhnd_pmu_core_en_clocks, bhnd_pmu_core_en_clocks),
- DEVMETHOD(bhnd_pmu_core_req_ext_rsrc, bhnd_pmu_core_req_ext_rsrc),
- DEVMETHOD(bhnd_pmu_core_release_ext_rsrc, bhnd_pmu_core_release_ext_rsrc),
- DEVMETHOD(bhnd_pmu_core_release, bhnd_pmu_core_release),
-
+ DEVMETHOD(bhnd_pmu_read_chipctrl, bhnd_pmu_read_chipctrl_method),
+ DEVMETHOD(bhnd_pmu_write_chipctrl, bhnd_pmu_write_chipctrl_method),
+ DEVMETHOD(bhnd_pmu_read_regctrl, bhnd_pmu_read_regctrl_method),
+ DEVMETHOD(bhnd_pmu_write_regctrl, bhnd_pmu_write_regctrl_method),
+ DEVMETHOD(bhnd_pmu_read_pllctrl, bhnd_pmu_read_pllctrl_method),
+ DEVMETHOD(bhnd_pmu_write_pllctrl, bhnd_pmu_write_pllctrl_method),
+ DEVMETHOD(bhnd_pmu_set_voltage_raw, bhnd_pmu_set_voltage_raw_method),
+ DEVMETHOD(bhnd_pmu_enable_regulator, bhnd_pmu_enable_regulator_method),
+ DEVMETHOD(bhnd_pmu_disable_regulator, bhnd_pmu_disable_regulator_method),
+
+ DEVMETHOD(bhnd_pmu_get_clock_latency, bhnd_pmu_get_clock_latency_method),
+ DEVMETHOD(bhnd_pmu_get_clock_freq, bhnd_pmu_get_clock_freq_method),
+
+ DEVMETHOD(bhnd_pmu_get_max_transition_latency, bhnd_pmu_get_max_transition_latency_method),
+ DEVMETHOD(bhnd_pmu_request_spuravoid, bhnd_pmu_request_spuravoid_method),
+
DEVMETHOD_END
};
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu.h b/sys/dev/bhnd/cores/pmu/bhnd_pmu.h
index 01c3ea127e67..a83e6d622c02 100644
--- a/sys/dev/bhnd/cores/pmu/bhnd_pmu.h
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu.h
@@ -1,7 +1,11 @@
/*-
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
+ * Copyright (c) 2017 The FreeBSD Foundation
* All rights reserved.
*
+ * Portions of this software were developed by Landon Fuller
+ * under sponsorship from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -37,18 +41,227 @@
#include <dev/bhnd/bhnd.h>
#include "bhnd_pmu_if.h"
+#include "bhnd_pmu_types.h"
+
+
+/**
+ * Return the current value of a PMU chipctrl register.
+ *
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU chipctrl register to be read.
+ *
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_chipc() function.
+ *
+ * @returns The chipctrl register value, or 0 if undefined by this hardware.
+ */
+static inline uint32_t
+bhnd_pmu_read_chipctrl(device_t dev, uint32_t reg)
+{
+ return (BHND_PMU_READ_CHIPCTRL(dev, reg));
+}
+
+/**
+ * Write @p value with @p mask to a PMU chipctrl register.
+ *
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU chipctrl register to be written.
+ * @param value The value to write.
+ * @param mask The mask of bits to be written from @p value.
+ *
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_pmu() function.
+ */
+static inline void
+bhnd_pmu_write_chipctrl(device_t dev, uint32_t reg, uint32_t value,
+ uint32_t mask)
+{
+ return (BHND_PMU_WRITE_CHIPCTRL(dev, reg, value, mask));
+}
+
+/**
+ * Return the current value of a PMU regulator control register.
+ *
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU regctrl register to be read.
+ *
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_chipc() function.
+ *
+ * @returns The regctrl register value, or 0 if undefined by this hardware.
+ */
+static inline uint32_t
+bhnd_pmu_read_regctrl(device_t dev, uint32_t reg)
+{
+ return (BHND_PMU_READ_REGCTRL(dev, reg));
+}
+
+/**
+ * Write @p value with @p mask to a PMU regulator control register.
+ *
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU regctrl register to be written.
+ * @param value The value to write.
+ * @param mask The mask of bits to be written from @p value.
+ *
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_pmu() function.
+ */
+static inline void
+bhnd_pmu_write_regctrl(device_t dev, uint32_t reg, uint32_t value,
+ uint32_t mask)
+{
+ return (BHND_PMU_WRITE_REGCTRL(dev, reg, value, mask));
+}
+
+/**
+ * Return the current value of a PMU PLL control register.
+ *
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU pllctrl register to be read.
+ *
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_chipc() function.
+ *
+ * @returns The pllctrl register value, or 0 if undefined by this hardware.
+ */
+static inline uint32_t
+bhnd_pmu_read_pllctrl(device_t dev, uint32_t reg)
+{
+ return (BHND_PMU_READ_PLLCTRL(dev, reg));
+}
+
+/**
+ * Write @p value with @p mask to a PMU PLL control register.
+ *
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU pllctrl register to be written.
+ * @param value The value to write.
+ * @param mask The mask of bits to be written from @p value.
+ *
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_pmu() function.
+ */
+static inline void
+bhnd_pmu_write_pllctrl(device_t dev, uint32_t reg, uint32_t value,
+ uint32_t mask)
+{
+ return (BHND_PMU_WRITE_PLLCTRL(dev, reg, value, mask));
+}
/**
- * Per-core PMU register information.
+ * Set a hardware-specific output voltage register value for @p regulator.
+ *
+ * @param dev PMU device.
+ * @param regulator Regulator to be configured.
+ * @param value The raw voltage register value.
+ *
+ * @retval 0 success
+ * @retval ENODEV If @p regulator is not supported by this driver.
+ */
+static inline int
+bhnd_pmu_set_voltage_raw(device_t dev, bhnd_pmu_regulator regulator,
+ uint32_t value)
+{
+ return (BHND_PMU_SET_VOLTAGE_RAW(dev, regulator, value));
+}
+
+/**
+ * Enable the given @p regulator.
+ *
+ * @param dev PMU device.
+ * @param regulator Regulator to be enabled.
+ *
+ * @retval 0 success
+ * @retval ENODEV If @p regulator is not supported by this driver.
+ */
+static inline int
+bhnd_pmu_enable_regulator(device_t dev, bhnd_pmu_regulator regulator)
+{
+ return (BHND_PMU_ENABLE_REGULATOR(dev, regulator));
+}
+
+/**
+ * Disable the given @p regulator.
+ *
+ * @param dev PMU device.
+ * @param regulator Regulator to be disabled.
+ *
+ * @retval 0 success
+ * @retval ENODEV If @p regulator is not supported by this driver.
+ */
+static inline int
+bhnd_pmu_disable_regulator(device_t dev, bhnd_pmu_regulator regulator)
+{
+ return (BHND_PMU_DISABLE_REGULATOR(dev, regulator));
+}
+
+/**
+ * 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.
+ *
+ * @param dev PMU 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_pmu_get_clock_latency(device_t dev, bhnd_clock clock, u_int *latency)
+{
+ return (BHND_PMU_GET_CLOCK_LATENCY(dev, clock, latency));
+}
+
+/**
+ * Return the frequency for @p clock in Hz, if known.
+ *
+ * @param dev PMU device.
+ * @param clock The clock to be queried.
+ * @param[out] freq On success, the frequency of @p clock in Hz.
+ *
+ * @retval 0 success
+ * @retval ENODEV If the frequency for @p clock is not available.
+ */
+static inline int
+bhnd_pmu_get_clock_freq(device_t dev, bhnd_clock clock, u_int *freq)
+{
+ return (BHND_PMU_GET_CLOCK_FREQ(dev, clock, freq));
+}
+
+/**
+ * Request that the PMU configure itself for a given hardware-specific
+ * spuravoid mode.
+ *
+ * @param dev PMU device.
+ * @param spuravoid The requested mode.
+ *
+ * @retval 0 success
+ * @retval ENODEV If @p regulator is not supported by this driver.
+ */
+static inline int
+bhnd_pmu_request_spuravoid(device_t dev, bhnd_pmu_spuravoid spuravoid)
+{
+ return (BHND_PMU_REQUEST_SPURAVOID(dev, spuravoid));
+}
+
+
+/**
+ * Return the PMU's maximum state transition latency in microseconds.
+ *
+ * This upper bound may be used to busy-wait on PMU clock and resource state
+ * transitions.
+ *
+ * @param dev PMU device.
*/
-struct bhnd_core_pmu_info {
- device_t pm_dev; /**< core device */
- device_t pm_pmu; /**< PMU device */
- struct bhnd_resource *pm_res; /**< Resource containing PMU
- register block for this
- device (if any). */
- bus_size_t pm_regs; /**< Offset to PMU register
- * block in @p pm_res */
-};
+static inline u_int
+bhnd_pmu_get_max_transition_latency(device_t dev)
+{
+ return (BHND_PMU_GET_MAX_TRANSITION_LATENCY(dev));
+}
#endif /* _BHND_CORES_PMU_BHND_PMU_H_ */
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c b/sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c
index 2c2cf3d485a0..5575f2e29629 100644
--- a/sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c
@@ -94,6 +94,14 @@ bhnd_pmu_core_attach(device_t dev)
return (ENXIO);
}
+ /* Allocate our per-core PMU state */
+ if ((error = bhnd_alloc_pmu(dev))) {
+ device_printf(sc->dev, "failed to allocate PMU state: %d\n",
+ error);
+
+ return (error);
+ }
+
/* Delegate to common driver implementation */
if ((error = bhnd_pmu_attach(dev, res))) {
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, res);
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m b/sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m
index dc27cfd6ceac..bbc9191719c0 100644
--- a/sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m
@@ -1,7 +1,11 @@
#-
# Copyright (c) 2016 Landon Fuller <landon@landonf.org>
+# Copyright (c) 2017 The FreeBSD Foundation
# All rights reserved.
#
+# Portions of this software were developed by Landon Fuller
+# under sponsorship from the FreeBSD Foundation.
+#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
@@ -34,97 +38,307 @@ INTERFACE bhnd_pmu;
#
# bhnd(4) PMU interface.
#
-# Provides a common PMU and clock control interface.
+# Provides an interface to the PMU hardware found on modern bhnd(4) chipsets.
#
HEADER {
+ #include <dev/bhnd/cores/pmu/bhnd_pmu_types.h>
+
struct bhnd_core_pmu_info;
}
-/**
- * Enabling routing of @p clock (or faster) to a requesting core.
+CODE {
+
+ static uint32_t
+ bhnd_pmu_null_read_chipctrl(device_t dev, uint32_t reg)
+ {
+ panic("bhnd_pmu_read_chipctrl unimplemented");
+ }
+
+ static void
+ bhnd_pmu_null_write_chipctrl(device_t dev, uint32_t reg, uint32_t value,
+ uint32_t mask)
+ {
+ panic("bhnd_pmu_write_chipctrl unimplemented");
+ }
+
+ static uint32_t
+ bhnd_pmu_null_read_regctrl(device_t dev, uint32_t reg)
+ {
+ panic("bhnd_pmu_read_regctrl unimplemented");
+ }
+
+ static void
+ bhnd_pmu_null_write_regctrl(device_t dev, uint32_t reg, uint32_t value,
+ uint32_t mask)
+ {
+ panic("bhnd_pmu_write_regctrl unimplemented");
+ }
+
+ static uint32_t
+ bhnd_pmu_null_read_pllctrl(device_t dev, uint32_t reg)
+ {
+ panic("bhnd_pmu_read_pllctrl unimplemented");
+ }
+
+ static void
+ bhnd_pmu_null_write_pllctrl(device_t dev, uint32_t reg, uint32_t value,
+ uint32_t mask)
+ {
+ panic("bhnd_pmu_write_pllctrl unimplemented");
+ }
+
+ static int
+ bhnd_pmu_null_request_spuravoid(device_t dev,
+ bhnd_pmu_spuravoid spuravoid)
+ {
+ panic("bhnd_pmu_request_spuravoid unimplemented");
+ }
+
+ static int
+ bhnd_pmu_null_set_voltage_raw(device_t dev,
+ bhnd_pmu_regulator regulator, uint32_t value)
+ {
+ panic("bhnd_pmu_set_voltage_raw unimplemented");
+ }
+
+ static int
+ bhnd_pmu_null_enable_regulator(device_t dev,
+ bhnd_pmu_regulator regulator)
+ {
+ panic("bhnd_pmu_enable_regulator unimplemented");
+ }
+
+ static int
+ bhnd_pmu_null_disable_regulator(device_t dev,
+ bhnd_pmu_regulator regulator)
+ {
+ panic("bhnd_pmu_disable_regulator unimplemented");
+ }
+
+ static int
+ bhnd_pmu_null_get_clock_latency(device_t dev, bhnd_clock clock,
+ u_int *latency)
+ {
+ panic("bhnd_pmu_get_clock_latency unimplemented");
+ }
+
+ static int
+ bhnd_pmu_null_get_clock_freq(device_t dev, bhnd_clock clock,
+ u_int *freq)
+ {
+ panic("bhnd_pmu_get_clock_freq unimplemented");
+ }
+}
+
+/**
+ * Return the current value of a PMU chipctrl register.
*
- * @param dev PMU device.
- * @param pinfo PMU info for requesting core.
- * @param clock Clock requested.
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU chipctrl register to be read.
*
- * @retval 0 success
- * @retval ENODEV If an unsupported clock was requested.
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_chipc() function.
+ *
+ * @returns The chipctrl register value, or 0 if undefined by this hardware.
*/
-METHOD int core_req_clock {
- device_t dev;
- struct bhnd_core_pmu_info *pinfo;
- bhnd_clock clock;
-};
+METHOD uint32_t read_chipctrl {
+ device_t dev;
+ uint32_t reg;
+} DEFAULT bhnd_pmu_null_read_chipctrl;
+/**
+ * Write @p value with @p mask to a PMU chipctrl register.
+ *
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU chipctrl register to be written.
+ * @param value The value to write.
+ * @param mask The mask of bits to be written from @p value.
+ *
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_pmu() function.
+ */
+METHOD void write_chipctrl {
+ device_t dev;
+ uint32_t reg;
+ uint32_t value;
+ uint32_t mask;
+} DEFAULT bhnd_pmu_null_write_chipctrl;
-/**
- * Request that @p clocks be powered on behalf of a requesting core.
+/**
+ * Return the current value of a PMU regulator control register.
*
- * This will power any clock sources (XTAL, PLL, etc,) required by
- * @p clocks and wait until they are ready, discarding any previous
- * requests from the @p pinfo device.
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU regctrl register to be read.
*
- * Requests from multiple devices are aggregated by the PMU.
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_chipc() function.
*
- * @param dev PMU device.
- * @param pinfo PMU info for requesting core.
- * @param clocks Clocks requested.
+ * @returns The regctrl register value, or 0 if undefined by this hardware.
+ */
+METHOD uint32_t read_regctrl {
+ device_t dev;
+ uint32_t reg;
+} DEFAULT bhnd_pmu_null_read_regctrl;
+
+/**
+ * Write @p value with @p mask to a PMU regulator control register.
+ *
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU regctrl register to be written.
+ * @param value The value to write.
+ * @param mask The mask of bits to be written from @p value.
*
- * @retval 0 success
- * @retval ENODEV If an unsupported clock was requested.
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_pmu() function.
*/
-METHOD int core_en_clocks {
- device_t dev;
- struct bhnd_core_pmu_info *pinfo;
- uint32_t clocks;
-};
+METHOD void write_regctrl {
+ device_t dev;
+ uint32_t reg;
+ uint32_t value;
+ uint32_t mask;
+} DEFAULT bhnd_pmu_null_write_regctrl;
/**
- * Power up a core-specific external resource.
+ * Return the current value of a PMU PLL control register.
+ *
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU pllctrl register to be read.
*
- * @param dev The parent of @p child.
- * @param pinfo PMU info for requesting core.
- * @param rsrc The core-specific external resource identifier.
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_chipc() function.
*
- * @retval 0 success
- * @retval ENODEV If @p rsrc is not supported by this PMU driver.
+ * @returns The pllctrl register value, or 0 if undefined by this hardware.
*/
-METHOD int core_req_ext_rsrc {
- device_t dev;
- struct bhnd_core_pmu_info *pinfo;
- u_int rsrc;
-};
+METHOD uint32_t read_pllctrl {
+ device_t dev;
+ uint32_t reg;
+} DEFAULT bhnd_pmu_null_read_pllctrl;
/**
- * Power down a core-specific external resource.
+ * Write @p value with @p mask to a PMU PLL control register.
*
- * @param dev The parent of @p child.
- * @param pinfo PMU info for requesting core.
- * @param rsrc The core-specific external resource identifier.
+ * @param dev A bhnd(4) PMU device.
+ * @param reg The PMU pllctrl register to be written.
+ * @param value The value to write.
+ * @param mask The mask of bits to be written from @p value.
*
- * @retval 0 success
- * @retval ENODEV If @p rsrc is not supported by this PMU driver.
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_pmu() function.
*/
-METHOD int core_release_ext_rsrc {
- device_t dev;
- struct bhnd_core_pmu_info *pinfo;
- u_int rsrc;
-};
+METHOD void write_pllctrl {
+ device_t dev;
+ uint32_t reg;
+ uint32_t value;
+ uint32_t mask;
+} DEFAULT bhnd_pmu_null_write_pllctrl;
-/**
- * Release all outstanding requests (clocks, resources, etc) associated with
- * @p pinfo.
+/**
+ * Set a hardware-specific output voltage register value for @p regulator.
*
- * @param dev PMU device.
- * @param pinfo PMU info for requesting core.
+ * @param dev PMU device.
+ * @param regulator Regulator to be configured.
+ * @param value The raw voltage register value.
*
* @retval 0 success
- * @retval non-zero If releasing PMU request state fails, a
- * regular unix error code will be returned, and
- * the request state will be left unmodified.
+ * @retval ENODEV If @p regulator is not supported by this driver.
+ */
+METHOD int set_voltage_raw {
+ device_t dev;
+ bhnd_pmu_regulator regulator;
+ uint32_t value;
+} DEFAULT bhnd_pmu_null_set_voltage_raw;
+
+/**
+ * Enable the given @p regulator.
+ *
+ * @param dev PMU device.
+ * @param regulator Regulator to be enabled.
+ *
+ * @retval 0 success
+ * @retval ENODEV If @p regulator is not supported by this driver.
+ */
+METHOD int enable_regulator {
+ device_t dev;
+ bhnd_pmu_regulator regulator;
+} DEFAULT bhnd_pmu_null_enable_regulator;
+
+/**
+ * Disable the given @p regulator.
+ *
+ * @param dev PMU device.
+ * @param regulator Regulator to be disabled.
+ *
+ * @retval 0 success
+ * @retval ENODEV If @p regulator is not supported by this driver.
+ */
+METHOD int disable_regulator {
+ device_t dev;
+ bhnd_pmu_regulator regulator;
+} DEFAULT bhnd_pmu_null_disable_regulator;
+
+/**
+ * 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.
+ *
+ * @param dev PMU 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 get_clock_latency {
+ device_t dev;
+ bhnd_clock clock;
+ u_int *latency;
+} DEFAULT bhnd_pmu_null_get_clock_latency;
+
+/**
+ * Return the frequency for @p clock in Hz, if known.
+ *
+ * @param dev PMU device.
+ * @param clock The clock to be queried.
+ * @param[out] freq On success, the frequency of @p clock in Hz.
+ *
+ * @retval 0 success
+ * @retval ENODEV If the frequency for @p clock is not available.
+ */
+METHOD int get_clock_freq {
+ device_t dev;
+ bhnd_clock clock;
+ u_int *freq;
+} DEFAULT bhnd_pmu_null_get_clock_freq;
+
+/**
+ * Request that the PMU configure itself for a given hardware-specific
+ * spuravoid mode.
+ *
+ * @param dev PMU device.
+ * @param spuravoid The requested mode.
+ *
+ * @retval 0 success
+ * @retval ENODEV If @p regulator is not supported by this driver.
+ */
+METHOD int request_spuravoid {
+ device_t dev;
+ bhnd_pmu_spuravoid spuravoid;
+} DEFAULT bhnd_pmu_null_request_spuravoid;
+
+/**
+ * Return the PMU's maximum state transition latency in microseconds.
+ *
+ * This upper bound may be used to busy-wait on PMU clock and resource state
+ * transitions.
+ *
+ * @param dev PMU device.
+ *
+ * @returns maximum PMU transition latency, in microseconds.
*/
-METHOD int core_release {
- device_t dev;
- struct bhnd_core_pmu_info *pinfo;
+METHOD u_int get_max_transition_latency {
+ device_t dev;
};
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h b/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h
index e20f65fe7787..2cc282c9c35c 100644
--- a/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h
@@ -52,11 +52,11 @@
/* Chip Control indirect registers */
#define BHND_PMU_CCTRL_READ(_sc, _reg) \
- BHND_PMU_IND_READ((_sc), CHIPCTL, (_reg))
+ BHND_PMU_IND_READ((_sc), CHIP_CONTROL, (_reg))
#define BHND_PMU_CCTRL_WRITE(_sc, _reg, _val, _mask) \
- BHND_PMU_IND_WRITE((_sc), CHIPCTL, (_reg), (_val), (_mask))
+ BHND_PMU_IND_WRITE((_sc), CHIP_CONTROL, (_reg), (_val), (_mask))
-/* Register Control indirect registers */
+/* Regulator Control indirect registers */
#define BHND_PMU_REGCTRL_READ(_sc, _reg) \
BHND_PMU_IND_READ((_sc), REG_CONTROL, (_reg))
#define BHND_PMU_REGCTRL_WRITE(_sc, _reg, _val, _mask) \
@@ -98,10 +98,6 @@ void bhnd_pmu_ind_write(const struct bhnd_pmu_io *io, void *io_ctx,
bus_size_t addr, bus_size_t data, uint32_t reg,
uint32_t val, uint32_t mask);
-bool bhnd_pmu_wait_clkst(struct bhnd_pmu_softc *sc, device_t dev,
- struct bhnd_resource *r, bus_size_t clkst_reg,
- uint32_t value, uint32_t mask);
-
int bhnd_pmu_init(struct bhnd_pmu_softc *sc);
void bhnd_pmu_pll_init(struct bhnd_pmu_softc *sc, uint32_t xtalfreq);
int bhnd_pmu_res_init(struct bhnd_pmu_softc *sc);
@@ -111,13 +107,13 @@ uint32_t bhnd_pmu_force_ilp(struct bhnd_pmu_softc *sc, bool force);
void bhnd_pmu_set_switcher_voltage(struct bhnd_pmu_softc *sc,
uint8_t bb_voltage, uint8_t rf_voltage);
-void bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc,
+int bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc,
uint8_t ldo, uint8_t voltage);
int bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc,
- uint16_t *pwrup_delay);
+ u_int *pwrup_delay);
void bhnd_pmu_rcal(struct bhnd_pmu_softc *sc);
-void bhnd_pmu_spuravoid(struct bhnd_pmu_softc *sc,
- uint8_t spuravoid);
+int bhnd_pmu_set_spuravoid(struct bhnd_pmu_softc *sc,
+ bhnd_pmu_spuravoid spuravoid);
bool bhnd_pmu_is_otp_powered(struct bhnd_pmu_softc *sc);
uint32_t bhnd_pmu_measure_alpclk(struct bhnd_pmu_softc *sc);
@@ -132,7 +128,7 @@ int bhnd_pmu_otp_power(struct bhnd_pmu_softc *sc, bool on);
void bhnd_pmu_sdiod_drive_strength_init(struct bhnd_pmu_softc *sc,
uint32_t drivestrength);
-void bhnd_pmu_paref_ldo_enable(struct bhnd_pmu_softc *sc,
+int bhnd_pmu_paref_ldo_enable(struct bhnd_pmu_softc *sc,
bool enable);
#endif /* _BHND_CORES_PMU_BHND_PMU_PRIVATE_H_ */
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c b/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
index 7eafd3cc6ff6..c0784448e85e 100644
--- a/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
@@ -25,7 +25,7 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
-#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/bhndvar.h>
#include <dev/bhnd/cores/chipc/chipc.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
@@ -84,16 +84,15 @@ static int bhnd_pmu_res_uptime(struct bhnd_pmu_softc *sc, uint8_t rsrc,
static int bhnd_pmu_res_masks(struct bhnd_pmu_softc *sc, uint32_t *pmin,
uint32_t *pmax);
-static void bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc,
- uint8_t spuravoid);
+static int bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc,
+ bhnd_pmu_spuravoid spuravoid);
static void bhnd_pmu_set_4330_plldivs(struct bhnd_pmu_softc *sc);
#define BHND_PMU_REV(_sc) \
((uint8_t)BHND_PMU_GET_BITS((_sc)->caps, BHND_PMU_CAP_REV))
-#define PMU_WAIT_CLKST(_sc, _val, _mask) \
- bhnd_pmu_wait_clkst((_sc), (_sc)->dev, (_sc)->res, \
- BHND_CLK_CTL_ST, (_val), (_mask))
+#define PMU_WAIT_CLKST(_sc, _val, _mask) \
+ bhnd_core_clkctl_wait((_sc)->clkctl, (_val), (_mask))
#define PMURES_BIT(_bit) \
(1 << (BHND_PMU_ ## _bit))
@@ -181,59 +180,6 @@ bhnd_pmu_ind_write(const struct bhnd_pmu_io *io, void *io_ctx, bus_size_t addr,
io->wr4(data, rval, io_ctx);
}
-/**
- * Wait for up to BHND_PMU_MAX_TRANSITION_DLY microseconds for the per-core
- * clock status to be equal to @p value after applying @p mask.
- *
- * @param sc PMU driver state.
- * @param dev Requesting device.
- * @param r An active resource mapping the clock status register.
- * @param clkst_reg Offset to the CLK_CTL_ST register.
- * @param value Value to wait for.
- * @param mask Mask to apply prior to value comparison.
- */
-bool
-bhnd_pmu_wait_clkst(struct bhnd_pmu_softc *sc, device_t dev,
- struct bhnd_resource *r, bus_size_t clkst_reg, uint32_t value,
- uint32_t mask)
-{
- uint32_t clkst;
-
- /* Bitswapped HTAVAIL/ALPAVAIL work-around */
- if (sc->quirks & BPMU_QUIRK_CLKCTL_CCS0) {
- uint32_t fmask, fval;
-
- fmask = mask & ~(BHND_CCS_HTAVAIL | BHND_CCS_ALPAVAIL);
- fval = value & ~(BHND_CCS_HTAVAIL | BHND_CCS_ALPAVAIL);
-
- if (mask & BHND_CCS_HTAVAIL)
- fmask |= BHND_CCS0_HTAVAIL;
- if (value & BHND_CCS_HTAVAIL)
- fval |= BHND_CCS0_HTAVAIL;
-
- if (mask & BHND_CCS_ALPAVAIL)
- fmask |= BHND_CCS0_ALPAVAIL;
- if (value & BHND_CCS_ALPAVAIL)
- fval |= BHND_CCS0_ALPAVAIL;
-
- mask = fmask;
- value = fval;
- }
-
- for (uint32_t i = 0; i < BHND_PMU_MAX_TRANSITION_DLY; i += 10) {
- clkst = bhnd_bus_read_4(r, clkst_reg);
- if ((clkst & mask) == (value & mask))
- return (true);
-
- DELAY(10);
- }
-
- device_printf(dev, "clkst wait timeout (value=%#x, "
- "mask=%#x)\n", value, mask);
-
- return (false);
-}
-
/* Setup switcher voltage */
void
bhnd_pmu_set_switcher_voltage(struct bhnd_pmu_softc *sc, uint8_t bb_voltage,
@@ -243,7 +189,7 @@ bhnd_pmu_set_switcher_voltage(struct bhnd_pmu_softc *sc, uint8_t bb_voltage,
BHND_PMU_REGCTRL_WRITE(sc, 0x00, (rf_voltage & 0x1f) << 14, ~0);
}
-void
+int
bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc, uint8_t ldo,
uint8_t voltage)
{
@@ -278,7 +224,8 @@ bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc, uint8_t ldo,
mask = 0x3f;
break;
default:
- panic("unknown BCM4328/BCM5354 LDO %hhu\n", ldo);
+ PMU_LOG(sc, "unknown BCM4328/BCM5354 LDO %hhu\n", ldo);
+ return (ENODEV);
}
break;
case BHND_CHIPID_BCM4312:
@@ -289,7 +236,8 @@ bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc, uint8_t ldo,
mask = 0x3f;
break;
default:
- panic("unknown BCM4312 LDO %hhu\n", ldo);
+ PMU_LOG(sc, "unknown BCM4312 LDO %hhu\n", ldo);
+ return (ENODEV);
}
break;
case BHND_CHIPID_BCM4325:
@@ -333,7 +281,8 @@ bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc, uint8_t ldo,
mask = 0x1;
break;
default:
- panic("unknown BCM4325 LDO %hhu\n", ldo);
+ PMU_LOG(sc, "unknown BCM4325 LDO %hhu\n", ldo);
+ return (ENODEV);
}
break;
case BHND_CHIPID_BCM4336:
@@ -354,7 +303,8 @@ bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc, uint8_t ldo,
mask = 0xf;
break;
default:
- panic("unknown BCM4336 LDO %hhu\n", ldo);
+ PMU_LOG(sc, "unknown BCM4336 LDO %hhu\n", ldo);
+ return (ENODEV);
}
break;
case BHND_CHIPID_BCM4330:
@@ -365,7 +315,8 @@ bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc, uint8_t ldo,
mask = 0x1f;
break;
default:
- panic("unknown BCM4330 LDO %hhu\n", ldo);
+ PMU_LOG(sc, "unknown BCM4330 LDO %hhu\n", ldo);
+ return (ENODEV);
}
break;
case BHND_CHIPID_BCM4331:
@@ -376,24 +327,27 @@ bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc, uint8_t ldo,
mask = 0xf;
break;
default:
- panic("unknown BCM4331 LDO %hhu\n", ldo);
+ PMU_LOG(sc, "unknown BCM4331 LDO %hhu\n", ldo);
+ return (ENODEV);
}
break;
default:
- panic("cannot set LDO voltage on unsupported chip %hu\n",
+ PMU_LOG(sc, "cannot set LDO voltage on unsupported chip %hu\n",
sc->cid.chip_id);
- return;
+ return (ENODEV);
}
regctrl = (voltage & mask) << shift;
BHND_PMU_REGCTRL_WRITE(sc, addr, regctrl, mask << shift);
+
+ return (0);
}
/* d11 slow to fast clock transition time in slow clock cycles */
#define D11SCC_SLOW2FAST_TRANSITION 2
int
-bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, uint16_t *pwrup_delay)
+bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, u_int *pwrup_delay)
{
uint32_t ilp;
uint32_t uptime;
@@ -470,7 +424,7 @@ bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, uint16_t *pwrup_delay)
break;
}
- *pwrup_delay = (uint16_t)delay;
+ *pwrup_delay = delay;
return (0);
}
@@ -2005,10 +1959,10 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
switch (xt->fref) {
case XTAL_FREQ_24000MHZ:
- pll_sel = BHND_PMU_CCTL_4319USB_24MHZ_PLL_SEL;
+ pll_sel = BHND_PMU_CCTRL4319USB_24MHZ_PLL_SEL;
break;
case XTAL_FREQ_48000MHZ:
- pll_sel = BHND_PMU_CCTL_4319USB_48MHZ_PLL_SEL;
+ pll_sel = BHND_PMU_CCTRL4319USB_48MHZ_PLL_SEL;
break;
default:
panic("unsupported 4319USB XTAL frequency: %hu\n",
@@ -2016,8 +1970,8 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
}
BHND_PMU_CCTRL_WRITE(sc, BHND_PMU1_PLL0_CHIPCTL2,
- BHND_PMU_SET_BITS(pll_sel, BHND_PMU_CCTL_4319USB_XTAL_SEL),
- BHND_PMU_CCTL_4319USB_XTAL_SEL_MASK);
+ BHND_PMU_SET_BITS(pll_sel, BHND_PMU_CCTRL4319USB_XTAL_SEL),
+ BHND_PMU_CCTRL4319USB_XTAL_SEL_MASK);
}
/* Flush deferred pll control registers writes */
@@ -2926,10 +2880,10 @@ bhnd_pmu_rcal(struct bhnd_pmu_softc *sc)
case BHND_CHIPID_BCM4325:
case BHND_CHIPID_BCM4329:
/* Kick RCal */
- BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 1);
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIP_CONTROL_ADDR, 1);
/* Power Down RCAL Block */
- BHND_PMU_AND_4(sc, BHND_PMU_CHIPCTL_DATA, ~0x04);
+ BHND_PMU_AND_4(sc, BHND_PMU_CHIP_CONTROL_DATA, ~0x04);
if (sc->cid.chip_id == BHND_CHIPID_BCM4325) {
chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
@@ -2938,7 +2892,7 @@ bhnd_pmu_rcal(struct bhnd_pmu_softc *sc)
}
/* Power Up RCAL block */
- BHND_PMU_AND_4(sc, BHND_PMU_CHIPCTL_DATA, 0x04);
+ BHND_PMU_AND_4(sc, BHND_PMU_CHIP_CONTROL_DATA, 0x04);
/* Wait for completion */
for (int i = 0; i < (10 * 1000 * 1000); i++) {
@@ -2975,34 +2929,36 @@ bhnd_pmu_rcal(struct bhnd_pmu_softc *sc)
BHND_PMU_WRITE_4(sc, BHND_PMU_REG_CONTROL_DATA, val);
/* Write RCal code into pmu_chip_ctrl[33:30] */
- BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 0);
- val = BHND_PMU_READ_4(sc, BHND_PMU_CHIPCTL_DATA);
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIP_CONTROL_ADDR, 0);
+ val = BHND_PMU_READ_4(sc, BHND_PMU_CHIP_CONTROL_DATA);
val &= ~((uint32_t) 0x03 << 30);
val |= (uint32_t) (rcal_code & 0x03) << 30;
- BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_DATA, val);
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIP_CONTROL_DATA, val);
- BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 1);
- val = BHND_PMU_READ_4(sc, BHND_PMU_CHIPCTL_DATA);
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIP_CONTROL_ADDR, 1);
+ val = BHND_PMU_READ_4(sc, BHND_PMU_CHIP_CONTROL_DATA);
val &= ~(uint32_t) 0x03;
val |= (uint32_t) ((rcal_code >> 2) & 0x03);
- BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_DATA, val);
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIP_CONTROL_DATA, val);
/* Set override in pmu_chip_ctrl[29] */
- BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 0);
- BHND_PMU_OR_4(sc, BHND_PMU_CHIPCTL_DATA, (0x01 << 29));
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIP_CONTROL_ADDR, 0);
+ BHND_PMU_OR_4(sc, BHND_PMU_CHIP_CONTROL_DATA, (0x01 << 29));
/* Power off RCal block */
- BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 1);
- BHND_PMU_AND_4(sc, BHND_PMU_CHIPCTL_DATA, ~0x04);
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIP_CONTROL_ADDR, 1);
+ BHND_PMU_AND_4(sc, BHND_PMU_CHIP_CONTROL_DATA, ~0x04);
break;
default:
break;
}
}
-void
-bhnd_pmu_spuravoid(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
+int
+bhnd_pmu_set_spuravoid(struct bhnd_pmu_softc *sc, bhnd_pmu_spuravoid spuravoid)
{
+ int error;
+
/* force the HT off */
if (sc->cid.chip_id == BHND_CHIPID_BCM4336) {
BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK,
@@ -3013,25 +2969,24 @@ bhnd_pmu_spuravoid(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
}
/* update the pll changes */
- bhnd_pmu_spuravoid_pllupdate(sc, spuravoid);
+ error = bhnd_pmu_spuravoid_pllupdate(sc, spuravoid);
/* enable HT back on */
if (sc->cid.chip_id == BHND_CHIPID_BCM4336) {
BHND_PMU_OR_4(sc, BHND_PMU_MAX_RES_MASK,
BHND_PMU_RES4336_HT_AVAIL);
}
+
+ return (error);
}
-static void
-bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
+static int
+bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc,
+ bhnd_pmu_spuravoid spuravoid)
{
- uint16_t chip_id;
- uint32_t tmp;
- uint32_t pmuctrl;
- uint8_t phypll_offset;
-
- uint8_t bcm5357_bcm43236_p1div[] = { 0x1, 0x5, 0x5 };
- uint8_t bcm5357_bcm43236_ndiv[] = { 0x30, 0xf6, 0xfc };
+ uint16_t chip_id;
+ uint32_t pmuctrl;
+ uint32_t tmp;
/* 6362a0 has same clks as 4322[4-6] */
chip_id = sc->cid.chip_id;
@@ -3050,12 +3005,26 @@ bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
case BHND_CHIPID_BCM43238:
case BHND_CHIPID_BCM43234:
case BHND_CHIPID_BCM43237:
- case BHND_CHIPID_BCM53572:
- KASSERT(spuravoid < nitems(bcm5357_bcm43236_p1div),
- ("spuravoid %hhu outside p1div table\n", spuravoid));
-
- KASSERT(spuravoid < nitems(bcm5357_bcm43236_ndiv),
- ("spuravoid %hhu outside ndiv table\n", spuravoid));
+ case BHND_CHIPID_BCM53572: {
+ uint8_t p1div, ndiv;
+ uint8_t phypll_offset;
+
+ switch (spuravoid) {
+ case BHND_PMU_SPURAVOID_NONE:
+ p1div = 0x1;
+ ndiv = 0x30;
+ break;
+ case BHND_PMU_SPURAVOID_M1:
+ p1div = 0x5;
+ ndiv = 0xf6;
+ break;
+ case BHND_PMU_SPURAVOID_M2:
+ p1div = 0x5;
+ ndiv = 0xfc;
+ break;
+ default:
+ return (ENODEV);
+ }
/* BCM5357 needs to touch PLL1_PLLCTL[02], so offset
* PLL0_PLLCTL[02] by 6 */
@@ -3064,37 +3033,46 @@ bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
phypll_offset = 6;
/* RMW only the P1 divider */
- tmp = BHND_PMU_SET_BITS(bcm5357_bcm43236_p1div[spuravoid],
- BHND_PMU1_PLL0_PC0_P1DIV);
+ tmp = BHND_PMU_SET_BITS(p1div, BHND_PMU1_PLL0_PC0_P1DIV);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0 + phypll_offset,
tmp, BHND_PMU1_PLL0_PC0_P1DIV_MASK);
/* RMW only the int feedback divider */
- tmp = BHND_PMU_SET_BITS(bcm5357_bcm43236_ndiv[spuravoid],
- BHND_PMU1_PLL0_PC2_NDIV_INT);
+ tmp = BHND_PMU_SET_BITS(ndiv, BHND_PMU1_PLL0_PC2_NDIV_INT);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2 + phypll_offset,
tmp, BHND_PMU1_PLL0_PC0_P1DIV_MASK);
pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
break;
+ }
case BHND_CHIPID_BCM4331:
- if (spuravoid == 2) {
+ switch (spuravoid) {
+ case BHND_PMU_SPURAVOID_NONE:
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
- 0x11500014, ~0);
+ 0x11100014, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
- 0x0FC00a08, ~0);
- } else if (spuravoid == 1) {
+ 0x03000a08, ~0);
+ break;
+
+ case BHND_PMU_SPURAVOID_M1:
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
0x11500014, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
0x0F600a08, ~0);
- } else {
+ break;
+
+ case BHND_PMU_SPURAVOID_M2:
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
- 0x11100014, ~0);
+ 0x11500014, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
- 0x03000a08, ~0);
+ 0x0FC00a08, ~0);
+ break;
+
+ default:
+ return (ENODEV);
}
+
pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
break;
@@ -3102,33 +3080,42 @@ bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
case BHND_CHIPID_BCM43225:
case BHND_CHIPID_BCM43226:
case BHND_CHIPID_BCM43421:
- if (spuravoid == 1) {
+ switch (spuravoid) {
+ case BHND_PMU_SPURAVOID_NONE:
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
- 0x11500010, ~0);
+ 0x11100010, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
- 0x000C0C06, ~0);
+ 0x000c0c06, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
- 0x0F600a08, ~0);
+ 0x03000a08, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
0x00000000, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
- 0x2001E920, ~0);
+ 0x200005c0, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
0x88888815, ~0);
- } else {
+ break;
+
+ case BHND_PMU_SPURAVOID_M1:
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
- 0x11100010, ~0);
+ 0x11500010, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
- 0x000c0c06, ~0);
+ 0x000C0C06, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
- 0x03000a08, ~0);
+ 0x0F600a08, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
0x00000000, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
- 0x200005c0, ~0);
+ 0x2001E920, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
0x88888815, ~0);
+ break;
+
+ case BHND_PMU_SPURAVOID_M2:
+ default:
+ return (ENODEV);
}
+
pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
break;
@@ -3136,32 +3123,40 @@ bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
case BHND_CHIPID_BCM43112:
case BHND_CHIPID_BCM43222:
case BHND_CHIPID_BCM43420:
- if (spuravoid == 1) {
+ switch (spuravoid) {
+ case BHND_PMU_SPURAVOID_NONE:
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
- 0x11500008, ~0);
+ 0x11100008, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
0x0c000c06, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
- 0x0f600a08, ~0);
+ 0x03000a08, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
0x00000000, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
- 0x2001e920, ~0);
+ 0x200005c0, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
- 0x88888815, ~0);
- } else {
+ 0x88888855, ~0);
+ break;
+
+ case BHND_PMU_SPURAVOID_M1:
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
- 0x11100008, ~0);
+ 0x11500008, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
0x0c000c06, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
- 0x03000a08, ~0);
+ 0x0f600a08, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
0x00000000, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
- 0x200005c0, ~0);
+ 0x2001e920, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
- 0x88888855, ~0);
+ 0x88888815, ~0);
+ break;
+
+ case BHND_PMU_SPURAVOID_M2:
+ default:
+ return (ENODEV);
}
pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
@@ -3170,34 +3165,43 @@ bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
case BHND_CHIPID_BCM4716:
case BHND_CHIPID_BCM4748:
case BHND_CHIPID_BCM47162:
- if (spuravoid == 1) {
+ switch (spuravoid) {
+ case BHND_PMU_SPURAVOID_NONE:
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
- 0x11500060, ~0);
+ 0x11100060, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
- 0x080C0C06, ~0);
+ 0x080c0c06, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
- 0x0F600000, ~0);
+ 0x03000000, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
0x00000000, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
- 0x2001E924, ~0);
+ 0x200005c0, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
0x88888815, ~0);
- } else {
+ break;
+
+ case BHND_PMU_SPURAVOID_M1:
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
- 0x11100060, ~0);
+ 0x11500060, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
- 0x080c0c06, ~0);
+ 0x080C0C06, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
- 0x03000000, ~0);
+ 0x0F600000, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
0x00000000, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
- 0x200005c0, ~0);
+ 0x2001E924, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
0x88888815, ~0);
+ break;
+
+ case BHND_PMU_SPURAVOID_M2:
+ default:
+ return (ENODEV);
}
+
pmuctrl = BHND_PMU_CTRL_NOILP_ON_WAIT |
BHND_PMU_CTRL_PLL_PLLCTL_UPD;
break;
@@ -3214,14 +3218,22 @@ bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x1014140a, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888854, ~0);
- if (spuravoid == 1) {
- /* spur_avoid ON, enable 41/82/164Mhz clock mode */
- BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
- 0x05201828, ~0);
- } else {
+ switch (spuravoid) {
+ case BHND_PMU_SPURAVOID_NONE:
/* enable 40/80/160Mhz clock mode */
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
0x05001828, ~0);
+ break;
+
+ case BHND_PMU_SPURAVOID_M1:
+ /* spur_avoid ON, enable 41/82/164Mhz clock mode */
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x05201828, ~0);
+ break;
+
+ case BHND_PMU_SPURAVOID_M2:
+ default:
+ return (ENODEV);
}
pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
@@ -3235,15 +3247,25 @@ bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, 0x202C2820, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888825, ~0);
- if (spuravoid == 1) {
- tmp = 0x00EC4EC4;
- } else {
- tmp = 0x00762762;
+ switch (spuravoid) {
+ case BHND_PMU_SPURAVOID_NONE:
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
+ 0x00762762, ~0);
+ break;
+
+ case BHND_PMU_SPURAVOID_M1:
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
+ 0x00EC4EC4, ~0);
+ break;
+
+ case BHND_PMU_SPURAVOID_M2:
+ default:
+ return (ENODEV);
}
- BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, tmp, ~0);
pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
break;
+
case BHND_CHIPID_BCM43131:
case BHND_CHIPID_BCM43227:
case BHND_CHIPID_BCM43228:
@@ -3251,44 +3273,55 @@ bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
/* LCNXN */
/* PLL Settings for spur avoidance on/off mode, no on2 support
* for 43228A0 */
- if (spuravoid == 1) {
+ switch (spuravoid) {
+ case BHND_PMU_SPURAVOID_NONE:
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
- 0x01100014, ~0);
+ 0x11100014, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
- 0x040C0C06, ~0);
+ 0x040c0c06, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
- 0x03140A08, ~0);
+ 0x03000a08, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
- 0x00333333, ~0);
+ 0x00000000, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
- 0x202C2820, ~0);
+ 0x200005c0, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
0x88888815, ~0);
- } else {
+ break;
+
+ case BHND_PMU_SPURAVOID_M1:
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
- 0x11100014, ~0);
+ 0x01100014, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
- 0x040c0c06, ~0);
+ 0x040C0C06, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
- 0x03000a08, ~0);
+ 0x03140A08, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
- 0x00000000, ~0);
+ 0x00333333, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
- 0x200005c0, ~0);
+ 0x202C2820, ~0);
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
0x88888815, ~0);
+ break;
+
+ case BHND_PMU_SPURAVOID_M2:
+ default:
+ return (ENODEV);
}
+
pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
break;
default:
PMU_LOG(sc, "%s: unknown spuravoidance settings for chip %#hx, "
"not changing PLL", __func__, sc->cid.chip_id);
- pmuctrl = 0;
- break;
+
+ return (ENODEV);
}
if (pmuctrl != 0)
BHND_PMU_OR_4(sc, BHND_PMU_CTRL, pmuctrl);
+
+ return (0);
}
bool
@@ -3333,7 +3366,7 @@ bhnd_pmu_is_otp_powered(struct bhnd_pmu_softc *sc)
return (true);
}
-void
+int
bhnd_pmu_paref_ldo_enable(struct bhnd_pmu_softc *sc, bool enable)
{
uint32_t ldo;
@@ -3349,7 +3382,7 @@ bhnd_pmu_paref_ldo_enable(struct bhnd_pmu_softc *sc, bool enable)
ldo = PMURES_BIT(RES4312_PA_REF_LDO);
break;
default:
- return;
+ return (ENODEV);
}
if (enable) {
@@ -3357,6 +3390,8 @@ bhnd_pmu_paref_ldo_enable(struct bhnd_pmu_softc *sc, bool enable)
} else {
BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~ldo);
}
+
+ return (0);
}
/* initialize PMU switch/regulators */
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu_types.h b/sys/dev/bhnd/cores/pmu/bhnd_pmu_types.h
new file mode 100644
index 000000000000..2f4dc1ea1bd9
--- /dev/null
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu_types.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2017 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Landon Fuller under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BHND_CORES_PMU_BHND_PMU_TYPES_H_
+#define _BHND_CORES_PMU_BHND_PMU_TYPES_H_
+
+#include <sys/types.h>
+
+/**
+ * bhnd_pmu(4) regulators.
+ */
+typedef enum bhnd_pmu_regulator {
+ BHND_REGULATOR_PAREF_LDO = 0, /**< PA reference LDO */
+} bhnd_pmu_regulator;
+
+/**
+ * bhnd_pmu(4) spurious signal avoidance modes.
+ */
+typedef enum bhnd_pmu_spuravoid {
+ BHND_PMU_SPURAVOID_NONE = 0, /**< spur avoidance disabled */
+ BHND_PMU_SPURAVOID_M1 = 1, /**< chipset-specific mode 1 */
+ BHND_PMU_SPURAVOID_M2 = 2, /**< chipset-specific mode 2 */
+} bhnd_pmu_spuravoid;
+
+#endif /* _BHND_CORES_PMU_BHND_PMU_TYPES_H_ */
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmureg.h b/sys/dev/bhnd/cores/pmu/bhnd_pmureg.h
index 9c11ef4194a3..059f59b83e84 100644
--- a/sys/dev/bhnd/cores/pmu/bhnd_pmureg.h
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmureg.h
@@ -148,8 +148,8 @@
#define BHND_PMU_RRQT_ALP_REQ 0x1000
#define BHND_PMU_RRQT_HT_REQ 0x2000
#define BHND_PMU_RES_REQ_MASK 0x648
-#define BHND_PMU_CHIPCTL_ADDR 0x650
-#define BHND_PMU_CHIPCTL_DATA 0x654
+#define BHND_PMU_CHIP_CONTROL_ADDR 0x650
+#define BHND_PMU_CHIP_CONTROL_DATA 0x654
#define BHND_PMU_REG_CONTROL_ADDR 0x658
#define BHND_PMU_REG_CONTROL_DATA 0x65C
#define BHND_PMU_PLL_CONTROL_ADDR 0x660
@@ -434,8 +434,8 @@
/* 5357 chip-specific CHIPCTRL register bits */
-#define BHND_PMU_CCTRL5357_EXTPA (1<<14) /* extPA in CHIPCTL1, bit 14 */
-#define BHND_PMU_CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in CHIPCTL1, bit 15 */
+#define BHND_PMU_CCTRL5357_EXTPA (1<<14) /* extPA in CHIPCTRL1, bit 14 */
+#define BHND_PMU_CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in CHIPCTRL1, bit 15 */
/* 4328 PMU resources */
@@ -553,9 +553,9 @@
/* 43224 chip-specific CHIPCTRL register bits */
-#define BHND_PMU_CCTRL_43224_GPIO_TOGGLE 0x8000
-#define BHND_PMU_CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */
-#define BHND_PMU_CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */
+#define BHND_PMU_CCTRL43224_GPIO_TOGGLE 0x8000
+#define BHND_PMU_CCTRL43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */
+#define BHND_PMU_CCTRL43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */
/* 43236 PMU resources */
@@ -626,10 +626,10 @@
#define BHND_PMU1_PLL0_CHIPCTL0 0
#define BHND_PMU1_PLL0_CHIPCTL1 1
#define BHND_PMU1_PLL0_CHIPCTL2 2
-#define BHND_PMU_CCTL_4319USB_XTAL_SEL_MASK 0x00180000
-#define BHND_PMU_CCTL_4319USB_XTAL_SEL_SHIFT 19
-#define BHND_PMU_CCTL_4319USB_48MHZ_PLL_SEL 1
-#define BHND_PMU_CCTL_4319USB_24MHZ_PLL_SEL 2
+#define BHND_PMU_CCTRL4319USB_XTAL_SEL_MASK 0x00180000
+#define BHND_PMU_CCTRL4319USB_XTAL_SEL_SHIFT 19
+#define BHND_PMU_CCTRL4319USB_48MHZ_PLL_SEL 1
+#define BHND_PMU_CCTRL4319USB_24MHZ_PLL_SEL 2
/* 4336 PMU resources */
#define BHND_PMU_RES4336_CBUCK_LPOM 0
@@ -708,7 +708,7 @@
#define BHND_PMU_RES4313_MACPHY_CLK_AVAIL_RSRC 15
/* 4313 chip-specific CHIPCTRL register bits */
-#define BHND_PMU_CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */
+#define BHND_PMU_CCTRL4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */
/* 43228 resources */
#define BHND_PMU_RES43228_NOT_USED 0
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h b/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h
index 0f6246d405e4..162f25803d31 100644
--- a/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h
@@ -60,20 +60,6 @@ uint32_t bhnd_pmu_mem_clock(struct bhnd_pmu_query *sc);
uint32_t bhnd_pmu_alp_clock(struct bhnd_pmu_query *sc);
uint32_t bhnd_pmu_ilp_clock(struct bhnd_pmu_query *sc);
-/*
- * BHND PMU device quirks / features
- */
-enum {
- /** No quirks */
- BPMU_QUIRK_NONE = 0,
-
- /** On BCM4328-derived chipsets, the CLK_CTL_ST register CCS_HTAVAIL
- * and CCS_ALPAVAIL bits are swapped; the BHND_CCS0_* constants should
- * be used. */
- BPMU_QUIRK_CLKCTL_CCS0 = 1
-};
-
-
/**
* PMU read-only query support.
*
@@ -110,7 +96,6 @@ struct bhnd_pmu_io {
*/
struct bhnd_pmu_softc {
device_t dev;
- uint32_t quirks; /**< device quirk flags */
uint32_t caps; /**< pmu capability flags. */
struct bhnd_chipid cid; /**< chip identification */
@@ -121,6 +106,7 @@ struct bhnd_pmu_softc {
struct bhnd_resource *res; /**< pmu register block. */
int rid; /**< pmu register RID */
+ struct bhnd_core_clkctl *clkctl; /**< pmu clkctl register */
struct mtx mtx; /**< state mutex */
@@ -132,11 +118,10 @@ struct bhnd_pmu_softc {
};
#define BPMU_LOCK_INIT(sc) \
- mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
- "BHND chipc driver lock", MTX_DEF)
-#define BPMU_LOCK(sc) mtx_lock(&(sc)->mtx)
+ mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), NULL, MTX_DEF)
+#define BPMU_LOCK(sc) mtx_lock(&(sc)->mtx)
#define BPMU_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
-#define BPMU_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
-#define BPMU_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
+#define BPMU_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
+#define BPMU_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
#endif /* _BHND_CORES_PMU_BHND_PMUVAR_H_ */
diff --git a/sys/dev/bhnd/siba/siba.c b/sys/dev/bhnd/siba/siba.c
index 2266d9d49e04..000b5aa7c040 100644
--- a/sys/dev/bhnd/siba/siba.c
+++ b/sys/dev/bhnd/siba/siba.c
@@ -39,12 +39,12 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/refcount.h>
#include <sys/systm.h>
#include <machine/bus.h>
-#include <dev/bhnd/cores/chipc/chipcreg.h>
-#include <dev/bhnd/cores/pmu/bhnd_pmu.h>
+#include <dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h>
#include "sibareg.h"
#include "sibavar.h"
@@ -78,9 +78,12 @@ siba_attach(device_t dev)
sc = device_get_softc(dev);
sc->dev = dev;
+ SIBA_LOCK_INIT(sc);
+
/* Enumerate children */
if ((error = siba_add_children(dev))) {
device_delete_children(dev);
+ SIBA_LOCK_DESTROY(sc);
return (error);
}
@@ -90,7 +93,17 @@ siba_attach(device_t dev)
int
siba_detach(device_t dev)
{
- return (bhnd_generic_detach(dev));
+ struct siba_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ if ((error = bhnd_generic_detach(dev)))
+ return (error);
+
+ SIBA_LOCK_DESTROY(sc);
+
+ return (0);
}
int
@@ -108,9 +121,11 @@ siba_suspend(device_t dev)
static int
siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
{
- const struct siba_devinfo *dinfo;
- const struct bhnd_core_info *cfg;
-
+ struct siba_softc *sc;
+ const struct siba_devinfo *dinfo;
+ const struct bhnd_core_info *cfg;
+
+ sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
cfg = &dinfo->core_id.core_info;
@@ -140,8 +155,27 @@ siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
*result = cfg->unit;
return (0);
case BHND_IVAR_PMU_INFO:
- *result = (uintptr_t) dinfo->pmu_info;
- return (0);
+ SIBA_LOCK(sc);
+ switch (dinfo->pmu_state) {
+ case SIBA_PMU_NONE:
+ *result = (uintptr_t)NULL;
+ SIBA_UNLOCK(sc);
+ return (0);
+
+ case SIBA_PMU_BHND:
+ *result = (uintptr_t)dinfo->pmu.bhnd_info;
+ SIBA_UNLOCK(sc);
+ return (0);
+
+ case SIBA_PMU_PWRCTL:
+ panic("bhnd_get_pmu_info() called with "
+ "SIBA_PMU_PWRCTL");
+ return (ENXIO);
+ }
+
+ panic("invalid PMU state: %d", dinfo->pmu_state);
+ return (ENXIO);
+
default:
return (ENOENT);
}
@@ -150,8 +184,10 @@ siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
static int
siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
{
- struct siba_devinfo *dinfo;
+ struct siba_softc *sc;
+ struct siba_devinfo *dinfo;
+ sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
switch (index) {
@@ -165,8 +201,24 @@ siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
case BHND_IVAR_CORE_UNIT:
return (EINVAL);
case BHND_IVAR_PMU_INFO:
- dinfo->pmu_info = (struct bhnd_core_pmu_info *) value;
- return (0);
+ SIBA_LOCK(sc);
+ switch (dinfo->pmu_state) {
+ case SIBA_PMU_NONE:
+ case SIBA_PMU_BHND:
+ dinfo->pmu.bhnd_info = (void *)value;
+ dinfo->pmu_state = SIBA_PMU_BHND;
+ SIBA_UNLOCK(sc);
+ return (0);
+
+ case SIBA_PMU_PWRCTL:
+ panic("bhnd_set_pmu_info() called with "
+ "SIBA_PMU_PWRCTL");
+ return (ENXIO);
+ }
+
+ panic("invalid PMU state: %d", dinfo->pmu_state);
+ return (ENXIO);
+
default:
return (ENOENT);
}
@@ -179,6 +231,332 @@ siba_get_resource_list(device_t dev, device_t child)
return (&dinfo->resources);
}
+/* BHND_BUS_ALLOC_PMU() */
+static int
+siba_alloc_pmu(device_t dev, device_t child)
+{
+ struct siba_softc *sc;
+ struct siba_devinfo *dinfo;
+ device_t pwrctl;
+ int error;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+ pwrctl = bhnd_retain_provider(child, BHND_SERVICE_PWRCTL);
+
+ /* Unless this is a legacy PWRCTL chipset, defer to bhnd(4)'s PMU
+ * implementation */
+ if (pwrctl == NULL) {
+ if ((error = bhnd_generic_alloc_pmu(dev, child)))
+ return (error);
+
+ KASSERT(dinfo->pmu_state == SIBA_PMU_BHND,
+ ("unexpected PMU state: %d", dinfo->pmu_state));
+
+ return (0);
+ }
+
+ /* This is a legacy PWRCTL chipset; we need to map all bhnd(4) bus PMU
+ * to PWRCTL operations ourselves.*/
+ SIBA_LOCK(sc);
+
+ /* Per-core PMU state already allocated? */
+ if (dinfo->pmu_state != SIBA_PMU_NONE) {
+ panic("duplicate PMU allocation for %s",
+ device_get_nameunit(child));
+ }
+
+ /* Update the child's PMU allocation state, and transfer ownership of
+ * the PWRCTL provider reference */
+ dinfo->pmu_state = SIBA_PMU_PWRCTL;
+ dinfo->pmu.pwrctl = pwrctl;
+
+ SIBA_UNLOCK(sc);
+
+ return (0);
+}
+
+/* BHND_BUS_RELEASE_PMU() */
+static int
+siba_release_pmu(device_t dev, device_t child)
+{
+ struct siba_softc *sc;
+ struct siba_devinfo *dinfo;
+ device_t pwrctl;
+ int error;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ SIBA_LOCK(sc);
+ switch(dinfo->pmu_state) {
+ case SIBA_PMU_NONE:
+ panic("pmu over-release for %s", device_get_nameunit(child));
+ SIBA_UNLOCK(sc);
+ return (ENXIO);
+
+ case SIBA_PMU_BHND:
+ SIBA_UNLOCK(sc);
+ return (bhnd_generic_release_pmu(dev, child));
+
+ case SIBA_PMU_PWRCTL:
+ /* Requesting BHND_CLOCK_DYN releases any outstanding clock
+ * reservations */
+ pwrctl = dinfo->pmu.pwrctl;
+ error = bhnd_pwrctl_request_clock(pwrctl, child,
+ BHND_CLOCK_DYN);
+ if (error) {
+ SIBA_UNLOCK(sc);
+ return (error);
+ }
+
+ /* Clean up the child's PMU state */
+ dinfo->pmu_state = SIBA_PMU_NONE;
+ dinfo->pmu.pwrctl = NULL;
+ SIBA_UNLOCK(sc);
+
+ /* Release the provider reference */
+ bhnd_release_provider(child, pwrctl, BHND_SERVICE_PWRCTL);
+ return (0);
+ }
+
+ panic("invalid PMU state: %d", dinfo->pmu_state);
+}
+
+/* BHND_BUS_GET_CLOCK_LATENCY() */
+static int
+siba_get_clock_latency(device_t dev, device_t child, bhnd_clock clock,
+ u_int *latency)
+{
+ struct siba_softc *sc;
+ struct siba_devinfo *dinfo;
+ int error;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ SIBA_LOCK(sc);
+ switch(dinfo->pmu_state) {
+ case SIBA_PMU_NONE:
+ panic("no active PMU request state");
+
+ SIBA_UNLOCK(sc);
+ return (ENXIO);
+
+ case SIBA_PMU_BHND:
+ SIBA_UNLOCK(sc);
+ return (bhnd_generic_get_clock_latency(dev, child, clock,
+ latency));
+
+ case SIBA_PMU_PWRCTL:
+ error = bhnd_pwrctl_get_clock_latency(dinfo->pmu.pwrctl, clock,
+ latency);
+ SIBA_UNLOCK(sc);
+
+ return (error);
+ }
+
+ panic("invalid PMU state: %d", dinfo->pmu_state);
+}
+
+/* BHND_BUS_GET_CLOCK_FREQ() */
+static int
+siba_get_clock_freq(device_t dev, device_t child, bhnd_clock clock,
+ u_int *freq)
+{
+ struct siba_softc *sc;
+ struct siba_devinfo *dinfo;
+ int error;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ SIBA_LOCK(sc);
+ switch(dinfo->pmu_state) {
+ case SIBA_PMU_NONE:
+ panic("no active PMU request state");
+
+ SIBA_UNLOCK(sc);
+ return (ENXIO);
+
+ case SIBA_PMU_BHND:
+ SIBA_UNLOCK(sc);
+ return (bhnd_generic_get_clock_freq(dev, child, clock, freq));
+
+ case SIBA_PMU_PWRCTL:
+ error = bhnd_pwrctl_get_clock_freq(dinfo->pmu.pwrctl, clock,
+ freq);
+ SIBA_UNLOCK(sc);
+
+ return (error);
+ }
+
+ panic("invalid PMU state: %d", dinfo->pmu_state);
+}
+
+/* BHND_BUS_REQUEST_EXT_RSRC() */
+static int
+siba_request_ext_rsrc(device_t dev, device_t child, u_int rsrc)
+{
+ struct siba_softc *sc;
+ struct siba_devinfo *dinfo;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ SIBA_LOCK(sc);
+ switch(dinfo->pmu_state) {
+ case SIBA_PMU_NONE:
+ panic("no active PMU request state");
+
+ SIBA_UNLOCK(sc);
+ return (ENXIO);
+
+ case SIBA_PMU_BHND:
+ SIBA_UNLOCK(sc);
+ return (bhnd_generic_request_ext_rsrc(dev, child, rsrc));
+
+ case SIBA_PMU_PWRCTL:
+ /* HW does not support per-core external resources */
+ SIBA_UNLOCK(sc);
+ return (ENODEV);
+ }
+
+ panic("invalid PMU state: %d", dinfo->pmu_state);
+}
+
+/* BHND_BUS_RELEASE_EXT_RSRC() */
+static int
+siba_release_ext_rsrc(device_t dev, device_t child, u_int rsrc)
+{
+ struct siba_softc *sc;
+ struct siba_devinfo *dinfo;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ SIBA_LOCK(sc);
+ switch(dinfo->pmu_state) {
+ case SIBA_PMU_NONE:
+ panic("no active PMU request state");
+
+ SIBA_UNLOCK(sc);
+ return (ENXIO);
+
+ case SIBA_PMU_BHND:
+ SIBA_UNLOCK(sc);
+ return (bhnd_generic_release_ext_rsrc(dev, child, rsrc));
+
+ case SIBA_PMU_PWRCTL:
+ /* HW does not support per-core external resources */
+ SIBA_UNLOCK(sc);
+ return (ENODEV);
+ }
+
+ panic("invalid PMU state: %d", dinfo->pmu_state);
+}
+
+/* BHND_BUS_REQUEST_CLOCK() */
+static int
+siba_request_clock(device_t dev, device_t child, bhnd_clock clock)
+{
+ struct siba_softc *sc;
+ struct siba_devinfo *dinfo;
+ int error;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ SIBA_LOCK(sc);
+ switch(dinfo->pmu_state) {
+ case SIBA_PMU_NONE:
+ panic("no active PMU request state");
+
+ SIBA_UNLOCK(sc);
+ return (ENXIO);
+
+ case SIBA_PMU_BHND:
+ SIBA_UNLOCK(sc);
+ return (bhnd_generic_request_clock(dev, child, clock));
+
+ case SIBA_PMU_PWRCTL:
+ error = bhnd_pwrctl_request_clock(dinfo->pmu.pwrctl, child,
+ clock);
+ SIBA_UNLOCK(sc);
+
+ return (error);
+ }
+
+ panic("invalid PMU state: %d", dinfo->pmu_state);
+}
+
+/* BHND_BUS_ENABLE_CLOCKS() */
+static int
+siba_enable_clocks(device_t dev, device_t child, uint32_t clocks)
+{
+ struct siba_softc *sc;
+ struct siba_devinfo *dinfo;
+
+ if (device_get_parent(child) != dev)
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ SIBA_LOCK(sc);
+ switch(dinfo->pmu_state) {
+ case SIBA_PMU_NONE:
+ panic("no active PMU request state");
+
+ SIBA_UNLOCK(sc);
+ return (ENXIO);
+
+ case SIBA_PMU_BHND:
+ SIBA_UNLOCK(sc);
+ return (bhnd_generic_enable_clocks(dev, child, clocks));
+
+ case SIBA_PMU_PWRCTL:
+ SIBA_UNLOCK(sc);
+
+ /* All (supported) clocks are already enabled by default */
+ clocks &= ~(BHND_CLOCK_DYN |
+ BHND_CLOCK_ILP |
+ BHND_CLOCK_ALP |
+ BHND_CLOCK_HT);
+
+ if (clocks != 0) {
+ device_printf(dev, "%s requested unknown clocks: %#x\n",
+ device_get_nameunit(child), clocks);
+ return (ENODEV);
+ }
+
+ return (0);
+ }
+
+ panic("invalid PMU state: %d", dinfo->pmu_state);
+}
+
static int
siba_read_iost(device_t dev, device_t child, uint16_t *iost)
{
@@ -328,8 +706,8 @@ siba_reset_hw(device_t dev, device_t child, uint16_t ioctl)
static int
siba_suspend_hw(device_t dev, device_t child)
{
+ struct siba_softc *sc;
struct siba_devinfo *dinfo;
- struct bhnd_core_pmu_info *pm;
struct bhnd_resource *r;
uint32_t idl, ts_low;
uint16_t ioctl;
@@ -338,8 +716,8 @@ siba_suspend_hw(device_t dev, device_t child)
if (device_get_parent(child) != dev)
return (EINVAL);
+ sc = device_get_softc(dev);
dinfo = device_get_ivars(child);
- pm = dinfo->pmu_info;
/* Can't suspend the core without access to the CFG0 registers */
if ((r = dinfo->cfg_res[0]) == NULL)
@@ -412,16 +790,30 @@ siba_suspend_hw(device_t dev, device_t child)
return (error);
}
- /* Core is now in RESET, with clocks disabled and REJ not asserted.
- *
- * We lastly need to inform the PMU, releasing any outstanding per-core
- * PMU requests */
- if (pm != NULL) {
- if ((error = BHND_PMU_CORE_RELEASE(pm->pm_pmu, pm)))
+ /*
+ * Core is now in RESET, with clocks disabled and REJ not asserted.
+ *
+ * If the core holds any PWRCTL clock reservations, we need to release
+ * those now. This emulates the standard bhnd(4) PMU behavior of RESET
+ * automatically clearing clkctl
+ */
+ SIBA_LOCK(sc);
+ if (dinfo->pmu_state == SIBA_PMU_PWRCTL) {
+ error = bhnd_pwrctl_request_clock(dinfo->pmu.pwrctl, child,
+ BHND_CLOCK_DYN);
+ SIBA_UNLOCK(sc);
+
+ if (error) {
+ device_printf(child, "failed to release clock request: "
+ "%d", error);
return (error);
- }
+ }
- return (0);
+ return (0);
+ } else {
+ SIBA_UNLOCK(sc);
+ return (0);
+ }
}
static int
@@ -1061,6 +1453,14 @@ static device_method_t siba_methods[] = {
/* BHND interface */
DEVMETHOD(bhnd_bus_get_erom_class, siba_get_erom_class),
+ DEVMETHOD(bhnd_bus_alloc_pmu, siba_alloc_pmu),
+ DEVMETHOD(bhnd_bus_release_pmu, siba_release_pmu),
+ DEVMETHOD(bhnd_bus_request_clock, siba_request_clock),
+ DEVMETHOD(bhnd_bus_enable_clocks, siba_enable_clocks),
+ DEVMETHOD(bhnd_bus_request_ext_rsrc, siba_request_ext_rsrc),
+ DEVMETHOD(bhnd_bus_release_ext_rsrc, siba_release_ext_rsrc),
+ DEVMETHOD(bhnd_bus_get_clock_freq, siba_get_clock_freq),
+ DEVMETHOD(bhnd_bus_get_clock_latency, siba_get_clock_latency),
DEVMETHOD(bhnd_bus_read_ioctl, siba_read_ioctl),
DEVMETHOD(bhnd_bus_write_ioctl, siba_write_ioctl),
DEVMETHOD(bhnd_bus_read_iost, siba_read_iost),
diff --git a/sys/dev/bhnd/siba/siba_bhndb.c b/sys/dev/bhnd/siba/siba_bhndb.c
index 452fec94b7b1..c3099ea4d367 100644
--- a/sys/dev/bhnd/siba/siba_bhndb.c
+++ b/sys/dev/bhnd/siba/siba_bhndb.c
@@ -121,7 +121,7 @@ siba_bhndb_attach(device_t dev)
/* Perform initial attach and enumerate our children. */
if ((error = siba_attach(dev)))
- goto failed;
+ return (error);
/* Fetch bus-level quirks required by the host bridge core */
if ((hostb = bhnd_bus_find_hostb_device(dev)) != NULL) {
@@ -140,7 +140,7 @@ siba_bhndb_attach(device_t dev)
return (0);
failed:
- device_delete_children(dev);
+ siba_detach(dev);
return (error);
}
diff --git a/sys/dev/bhnd/siba/siba_subr.c b/sys/dev/bhnd/siba/siba_subr.c
index bd69fc7dcb71..37c3a335efef 100644
--- a/sys/dev/bhnd/siba/siba_subr.c
+++ b/sys/dev/bhnd/siba/siba_subr.c
@@ -137,6 +137,7 @@ siba_alloc_dinfo(device_t bus)
resource_list_init(&dinfo->resources);
+ dinfo->pmu_state = SIBA_PMU_NONE;
dinfo->intr_en = false;
return dinfo;
diff --git a/sys/dev/bhnd/siba/sibavar.h b/sys/dev/bhnd/siba/sibavar.h
index 35a5d6ffa1d7..0e952abb1696 100644
--- a/sys/dev/bhnd/siba/sibavar.h
+++ b/sys/dev/bhnd/siba/sibavar.h
@@ -39,6 +39,8 @@
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <machine/bus.h>
#include <sys/rman.h>
@@ -53,6 +55,7 @@ struct siba_addrspace;
struct siba_cfg_block;
struct siba_devinfo;
struct siba_core_id;
+struct siba_softc;
int siba_probe(device_t dev);
int siba_attach(device_t dev);
@@ -184,26 +187,47 @@ struct siba_core_id {
};
/**
+ * siba(4) per-core PMU allocation state.
+ */
+typedef enum {
+ SIBA_PMU_NONE, /**< If the core has not yet allocated PMU state */
+ SIBA_PMU_BHND, /**< If standard bhnd(4) PMU support should be used */
+ SIBA_PMU_PWRCTL, /**< If legacy PWRCTL PMU support should be used */
+} siba_pmu_state;
+
+/**
* siba(4) per-device info
*/
struct siba_devinfo {
- struct resource_list resources; /**< per-core memory regions. */
- struct siba_core_id core_id; /**< core identification info */
- struct siba_addrspace addrspace[SIBA_MAX_ADDRSPACE]; /**< memory map descriptors */
- struct siba_cfg_block cfg[SIBA_MAX_CFG]; /**< config block descriptors */
- struct siba_intr intr; /**< interrupt flag descriptor, if any */
- bool intr_en; /**< if true, core has an assigned interrupt flag */
-
- struct bhnd_resource *cfg_res[SIBA_MAX_CFG]; /**< bus-mapped config block registers */
- int cfg_rid[SIBA_MAX_CFG]; /**< bus-mapped config block resource IDs */
- struct bhnd_core_pmu_info *pmu_info; /**< Bus-managed PMU state, or NULL */
+ struct resource_list resources; /**< per-core memory regions. */
+ struct siba_core_id core_id; /**< core identification info */
+ struct siba_addrspace addrspace[SIBA_MAX_ADDRSPACE]; /**< memory map descriptors */
+ struct siba_cfg_block cfg[SIBA_MAX_CFG]; /**< config block descriptors */
+ struct siba_intr intr; /**< interrupt flag descriptor, if any */
+ bool intr_en; /**< if true, core has an assigned interrupt flag */
+
+ struct bhnd_resource *cfg_res[SIBA_MAX_CFG]; /**< bus-mapped config block registers */
+ int cfg_rid[SIBA_MAX_CFG]; /**< bus-mapped config block resource IDs */
+ siba_pmu_state pmu_state; /**< per-core PMU state */
+ union {
+ void *bhnd_info; /**< if SIBA_PMU_BHND, bhnd(4)-managed per-core PMU info. */
+ device_t pwrctl; /**< if SIBA_PMU_PWRCTL, legacy PWRCTL provider. */
+ } pmu;
};
-
/** siba(4) per-instance state */
struct siba_softc {
- struct bhnd_softc bhnd_sc; /**< bhnd state */
- device_t dev; /**< siba device */
+ struct bhnd_softc bhnd_sc; /**< bhnd state */
+ device_t dev; /**< siba device */
+ struct mtx mtx; /**< state mutex */
};
+
+#define SIBA_LOCK_INIT(sc) \
+ mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), NULL, MTX_DEF)
+#define SIBA_LOCK(sc) mtx_lock(&(sc)->mtx)
+#define SIBA_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
+#define SIBA_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
+#define SIBA_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
+
#endif /* _SIBA_SIBAVAR_H_ */