Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152449312
D12664.id33966.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
146 KB
Referenced Files
None
Subscribers
None
D12664.id33966.diff
View Options
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -1250,6 +1250,8 @@
dev/bhnd/cores/chipc/chipc_spi.c optional bhnd spibus
dev/bhnd/cores/chipc/chipc_subr.c optional bhnd
dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c optional bhnd
+dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_if.m optional bhnd
+dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_hostb_if.m optional bhnd
dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c optional bhnd
dev/bhnd/cores/pci/bhnd_pci.c optional bhnd pci
dev/bhnd/cores/pci/bhnd_pci_hostb.c optional bhndb bhnd pci
Index: sys/dev/bhnd/bcma/bcma.c
===================================================================
--- sys/dev/bhnd/bcma/bcma.c
+++ sys/dev/bhnd/bcma/bcma.c
@@ -193,7 +193,7 @@
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 @@
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 @@
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);
}
Index: sys/dev/bhnd/bcma/bcmavar.h
===================================================================
--- sys/dev/bhnd/bcma/bcmavar.h
+++ sys/dev/bhnd/bcma/bcmavar.h
@@ -175,17 +175,17 @@
* 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 */
};
Index: sys/dev/bhnd/bhnd.h
===================================================================
--- sys/dev/bhnd/bhnd.h
+++ 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(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
@@ -858,67 +856,6 @@
return (BHND_BUS_SUSPEND_HW(device_get_parent(dev), 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.
*
@@ -1066,8 +1003,7 @@
* 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 @@
* 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 @@
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.
*
Index: sys/dev/bhnd/bhnd.c
===================================================================
--- sys/dev/bhnd/bhnd.c
+++ sys/dev/bhnd/bhnd.c
@@ -62,15 +62,13 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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().
*
Index: sys/dev/bhnd/bhnd_bus_if.m
===================================================================
--- sys/dev/bhnd/bhnd_bus_if.m
+++ sys/dev/bhnd/bhnd_bus_if.m
@@ -114,27 +114,6 @@
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)
@@ -159,6 +138,20 @@
panic("bhnd_bus_release_pmu unimplemented");
}
+ 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 @@
} 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 @@
*
* @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 @@
* @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 @@
* @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 @@
* @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;
Index: sys/dev/bhnd/bhnd_private.h
===================================================================
--- sys/dev/bhnd/bhnd_private.h
+++ sys/dev/bhnd/bhnd_private.h
@@ -54,4 +54,49 @@
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_ */
Index: sys/dev/bhnd/bhnd_subr.c
===================================================================
--- sys/dev/bhnd/bhnd_subr.c
+++ sys/dev/bhnd/bhnd_subr.c
@@ -171,6 +171,34 @@
{ 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.
*
@@ -1180,6 +1208,119 @@
return (error);
}
+/**
+ * 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.
*
@@ -2351,4 +2492,4 @@
bhnd_bus_generic_get_intr_domain(device_t dev, device_t child, bool self)
{
return ((uintptr_t)dev);
-}
\ No newline at end of file
+}
Index: sys/dev/bhnd/bhnd_types.h
===================================================================
--- sys/dev/bhnd/bhnd_types.h
+++ sys/dev/bhnd/bhnd_types.h
@@ -72,6 +72,7 @@
/** 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 */
Index: sys/dev/bhnd/bhndb/bhnd_bhndb.c
===================================================================
--- sys/dev/bhnd/bhndb/bhnd_bhndb.c
+++ sys/dev/bhnd/bhndb/bhnd_bhndb.c
@@ -42,6 +42,8 @@
#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_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_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_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 @@
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
};
Index: sys/dev/bhnd/bhndb/bhndb_pci.c
===================================================================
--- sys/dev/bhnd/bhndb/bhndb_pci.c
+++ sys/dev/bhnd/bhndb/bhndb_pci.c
@@ -68,6 +68,8 @@
#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 @@
/* 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 @@
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
};
Index: sys/dev/bhnd/bhndreg.h
===================================================================
--- sys/dev/bhnd/bhndreg.h
+++ 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_ */
Index: sys/dev/bhnd/bhndvar.h
===================================================================
--- sys/dev/bhnd/bhndvar.h
+++ 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 @@
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,
@@ -102,7 +116,7 @@
* softc structures.
*/
struct bhnd_softc {
- device_t dev; /**< bus device */
+ device_t dev; /**< bus device */
};
#endif /* _BHND_BHNDVAR_H_ */
Index: sys/dev/bhnd/cores/chipc/chipc.c
===================================================================
--- sys/dev/bhnd/cores/chipc/chipc.c
+++ 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 @@
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 @@
* 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 */
Index: sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h
===================================================================
--- /dev/null
+++ 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_ */
Index: sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c
===================================================================
--- sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c
+++ 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 @@
#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 {
@@ -184,10 +186,10 @@
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 +270,61 @@
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 +398,9 @@
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 +411,7 @@
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 +450,12 @@
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 +471,24 @@
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);
Index: sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_hostb_if.m
===================================================================
--- /dev/null
+++ 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
Index: sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_if.m
===================================================================
--- /dev/null
+++ 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;
+};
Index: sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h
===================================================================
--- sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h
+++ 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_ */
Index: sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c
===================================================================
--- sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c
+++ sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c
@@ -333,7 +333,8 @@
/* 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 @@
/* 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 @@
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 @@
/* 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)) {
Index: sys/dev/bhnd/cores/pmu/bhnd_pmu.h
===================================================================
--- sys/dev/bhnd/cores/pmu/bhnd_pmu.h
+++ 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_ */
Index: sys/dev/bhnd/cores/pmu/bhnd_pmu.c
===================================================================
--- sys/dev/bhnd/cores/pmu/bhnd_pmu.c
+++ sys/dev/bhnd/cores/pmu/bhnd_pmu.c
@@ -47,7 +47,8 @@
#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 @@
.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 @@
sc = device_get_softc(dev);
sc->dev = dev;
- sc->quirks = 0;
sc->res = res;
/* Fetch capability flags */
@@ -147,6 +133,17 @@
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 @@
}
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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
};
Index: sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c
===================================================================
--- sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c
+++ sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c
@@ -94,6 +94,14 @@
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);
Index: sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m
===================================================================
--- sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m
+++ 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 @@
#
# 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;
};
Index: sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h
===================================================================
--- sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h
+++ 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 @@
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 @@
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 @@
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_ */
Index: sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
===================================================================
--- sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
+++ sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
@@ -25,7 +25,7 @@
#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_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 @@
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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
break;
}
- *pwrup_delay = (uint16_t)delay;
+ *pwrup_delay = delay;
return (0);
}
@@ -2005,10 +1959,10 @@
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_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 @@
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 @@
}
/* 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_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 @@
}
/* 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 @@
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 @@
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,6 +3080,19 @@
case BHND_CHIPID_BCM43225:
case BHND_CHIPID_BCM43226:
case BHND_CHIPID_BCM43421:
+ switch (spuravoid) {
+ case BHND_PMU_SPURAVOID_NONE:
+
+ break;
+ case BHND_PMU_SPURAVOID_M1:
+
+ break;
+ case BHND_PMU_SPURAVOID_M2:
+
+ break;
+ default:
+ return (ENODEV);
+ }
if (spuravoid == 1) {
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
0x11500010, ~0);
@@ -3136,6 +3127,19 @@
case BHND_CHIPID_BCM43112:
case BHND_CHIPID_BCM43222:
case BHND_CHIPID_BCM43420:
+ switch (spuravoid) {
+ case BHND_PMU_SPURAVOID_NONE:
+
+ break;
+ case BHND_PMU_SPURAVOID_M1:
+
+ break;
+ case BHND_PMU_SPURAVOID_M2:
+
+ break;
+ default:
+ return (ENODEV);
+ }
if (spuravoid == 1) {
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
0x11500008, ~0);
@@ -3170,34 +3174,44 @@
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 +3228,21 @@
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 +3256,24 @@
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 +3281,53 @@
/* 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 +3372,7 @@
return (true);
}
-void
+int
bhnd_pmu_paref_ldo_enable(struct bhnd_pmu_softc *sc, bool enable)
{
uint32_t ldo;
@@ -3349,7 +3388,7 @@
ldo = PMURES_BIT(RES4312_PA_REF_LDO);
break;
default:
- return;
+ return (ENODEV);
}
if (enable) {
@@ -3357,6 +3396,8 @@
} else {
BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~ldo);
}
+
+ return (0);
}
/* initialize PMU switch/regulators */
Index: sys/dev/bhnd/cores/pmu/bhnd_pmu_types.h
===================================================================
--- sys/dev/bhnd/cores/pmu/bhnd_pmu_types.h
+++ sys/dev/bhnd/cores/pmu/bhnd_pmu_types.h
@@ -29,29 +29,25 @@
* $FreeBSD$
*/
-#ifndef _BHND_BHND_PRIVATE_H_
-#define _BHND_BHND_PRIVATE_H_
+#ifndef _BHND_CORES_PMU_BHND_PMU_TYPES_H_
+#define _BHND_CORES_PMU_BHND_PMU_TYPES_H_
-#include <sys/param.h>
-#include <sys/queue.h>
+#include <sys/types.h>
-#include "bhnd_types.h"
-
-/*
- * Private bhnd(4) driver definitions.
- */
+/**
+ * bhnd_pmu(4) regulators.
+ */
+typedef enum bhnd_pmu_regulator {
+ BHND_REGULATOR_PAREF_LDO = 0, /**< PA reference LDO */
+} bhnd_pmu_regulator;
/**
- * A bhnd(4) service registry entry.
+ * bhnd_pmu(4) spurious signal avoidance modes.
*/
-struct bhnd_service_entry {
- device_t provider; /**< service provider */
- bhnd_service_t service; /**< service implemented */
- uint32_t flags; /**< entry flags (see BHND_SPF_*) */
- volatile u_int refs; /**< reference count; updated atomically
- with only a shared lock held */
-
- STAILQ_ENTRY(bhnd_service_entry) link;
-};
+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_BHND_PRIVATE_H_ */
+#endif /* _BHND_CORES_PMU_BHND_PMU_TYPES_H_ */
Index: sys/dev/bhnd/cores/pmu/bhnd_pmureg.h
===================================================================
--- sys/dev/bhnd/cores/pmu/bhnd_pmureg.h
+++ 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
Index: sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h
===================================================================
--- sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h
+++ sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h
@@ -60,20 +60,6 @@
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_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_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 @@
};
#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_ */
Index: sys/dev/bhnd/siba/siba.c
===================================================================
--- sys/dev/bhnd/siba/siba.c
+++ sys/dev/bhnd/siba/siba.c
@@ -39,12 +39,12 @@
#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 @@
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 @@
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 @@
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 @@
*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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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),
Index: sys/dev/bhnd/siba/siba_bhndb.c
===================================================================
--- sys/dev/bhnd/siba/siba_bhndb.c
+++ sys/dev/bhnd/siba/siba_bhndb.c
@@ -121,7 +121,7 @@
/* 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 @@
return (0);
failed:
- device_delete_children(dev);
+ siba_detach(dev);
return (error);
}
Index: sys/dev/bhnd/siba/siba_subr.c
===================================================================
--- sys/dev/bhnd/siba/siba_subr.c
+++ sys/dev/bhnd/siba/siba_subr.c
@@ -137,6 +137,7 @@
resource_list_init(&dinfo->resources);
+ dinfo->pmu_state = SIBA_PMU_NONE;
dinfo->intr_en = false;
return dinfo;
Index: sys/dev/bhnd/siba/sibavar.h
===================================================================
--- sys/dev/bhnd/siba/sibavar.h
+++ 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_cfg_block;
struct siba_devinfo;
struct siba_core_id;
+struct siba_softc;
int siba_probe(device_t dev);
int siba_attach(device_t dev);
@@ -183,27 +186,48 @@
space */
};
+/**
+ * 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_ */
Index: sys/mips/broadcom/siba_nexus.c
===================================================================
--- sys/mips/broadcom/siba_nexus.c
+++ sys/mips/broadcom/siba_nexus.c
@@ -80,7 +80,7 @@
/* Perform initial attach and enumerate our children. */
if ((error = siba_attach(dev)))
- goto failed;
+ return (error);
/* Delegate remainder to standard bhnd method implementation */
if ((error = bhnd_generic_attach(dev)))
@@ -89,7 +89,7 @@
return (0);
failed:
- device_delete_children(dev);
+ siba_detach(dev);
return (error);
}
Index: sys/modules/bhnd/Makefile
===================================================================
--- sys/modules/bhnd/Makefile
+++ sys/modules/bhnd/Makefile
@@ -16,8 +16,10 @@
# ChipCommon
SRCS+= chipc.c chipc_subr.c
SRCS+= bhnd_sprom_chipc.c \
- bhnd_pmu_chipc.c \
- bhnd_pwrctl.c bhnd_pwrctl_subr.c
+ bhnd_pmu_chipc.c
+SRCS+= bhnd_pwrctl.c bhnd_pwrctl_subr.c \
+ bhnd_pwrctl_if.c bhnd_pwrctl_if.h \
+ bhnd_pwrctl_hostb_if.c bhnd_pwrctl_hostb_if.h
SRCS+= bhnd_chipc_if.c bhnd_chipc_if.h
# PMU
Index: sys/modules/bhnd/bhndb_pci/Makefile
===================================================================
--- sys/modules/bhnd/bhndb_pci/Makefile
+++ sys/modules/bhnd/bhndb_pci/Makefile
@@ -8,6 +8,7 @@
SRCS+= bhnd_bus_if.h bhndb_bus_if.h bhndb_if.h
SRCS+= bhnd_erom_if.h
SRCS+= bhnd_nvram_if.h
+SRCS+= bhnd_pwrctl_hostb_if.h
SRCS+= device_if.h bus_if.h pci_if.h
Index: sys/modules/bhnd/siba/Makefile
===================================================================
--- sys/modules/bhnd/siba/Makefile
+++ sys/modules/bhnd/siba/Makefile
@@ -7,6 +7,7 @@
siba_erom.c
SRCS+= device_if.h bus_if.h
-SRCS+= bhnd_bus_if.h bhnd_erom_if.h bhnd_pmu_if.h
+SRCS+= bhnd_bus_if.h bhnd_erom_if.h \
+ bhnd_pmu_if.h bhnd_pwrctl_if.h
.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 16, 1:10 AM (8 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31567099
Default Alt Text
D12664.id33966.diff (146 KB)
Attached To
Mode
D12664: bhnd(4): extend the PMU APIs to support bwn(4)
Attached
Detach File
Event Timeline
Log In to Comment