aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/conf/files11
-rw-r--r--sys/dev/bhnd/bcma/bcma.c77
-rw-r--r--sys/dev/bhnd/bcma/bcma_dmp.h13
-rw-r--r--sys/dev/bhnd/bhnd.c295
-rw-r--r--sys/dev/bhnd/bhnd.h226
-rw-r--r--sys/dev/bhnd/bhnd_bus_if.m304
-rw-r--r--sys/dev/bhnd/bhnd_core.h36
-rw-r--r--sys/dev/bhnd/bhnd_ids.h6
-rw-r--r--sys/dev/bhnd/bhnd_subr.c4
-rw-r--r--sys/dev/bhnd/bhnd_types.h60
-rw-r--r--sys/dev/bhnd/bhndb/bhnd_bhndb.c31
-rw-r--r--sys/dev/bhnd/bhndb/bhndb.c1
-rw-r--r--sys/dev/bhnd/bhndb/bhndb_pci.c64
-rw-r--r--sys/dev/bhnd/bhndvar.h62
-rw-r--r--sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m16
-rw-r--r--sys/dev/bhnd/cores/chipc/bhnd_pmu_chipc.c126
-rw-r--r--sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c5
-rw-r--r--sys/dev/bhnd/cores/chipc/chipc.c228
-rw-r--r--sys/dev/bhnd/cores/chipc/chipc.h56
-rw-r--r--sys/dev/bhnd/cores/chipc/chipc_subr.c4
-rw-r--r--sys/dev/bhnd/cores/chipc/chipcreg.h691
-rw-r--r--sys/dev/bhnd/cores/chipc/chipcvar.h58
-rw-r--r--sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c479
-rw-r--r--sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h43
-rw-r--r--sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c463
-rw-r--r--sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h120
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu.c466
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu.h52
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c138
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m130
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h147
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c3446
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmureg.h712
-rw-r--r--sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h92
-rw-r--r--sys/dev/bhnd/nvram/nvram_map15
-rw-r--r--sys/dev/bhnd/siba/siba.c19
-rw-r--r--sys/mips/broadcom/bcm_machdep.c3
-rw-r--r--sys/modules/bhnd/Makefile26
-rw-r--r--sys/modules/bhnd/cores/Makefile3
-rw-r--r--sys/modules/bhnd/cores/bhnd_chipc/Makefile11
40 files changed, 7834 insertions, 905 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 487613a40450..c630868299a9 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1157,19 +1157,26 @@ dev/bhnd/bcma/bcma_bhndb.c optional bcma bhnd bhndb
dev/bhnd/bcma/bcma_erom.c optional bcma bhnd
dev/bhnd/bcma/bcma_nexus.c optional bcma_nexus bcma bhnd
dev/bhnd/bcma/bcma_subr.c optional bcma bhnd
+dev/bhnd/cores/chipc/bhnd_chipc_if.m optional bhnd
+dev/bhnd/cores/chipc/bhnd_sprom_chipc.c optional bhnd
+dev/bhnd/cores/chipc/bhnd_pmu_chipc.c optional bhnd
dev/bhnd/cores/chipc/chipc.c optional bhnd
dev/bhnd/cores/chipc/chipc_cfi.c optional bhnd cfi
dev/bhnd/cores/chipc/chipc_slicer.c optional bhnd cfi | bhnd spibus
dev/bhnd/cores/chipc/chipc_spi.c optional bhnd spibus
dev/bhnd/cores/chipc/chipc_subr.c optional bhnd
-dev/bhnd/cores/chipc/bhnd_chipc_if.m optional bhnd
-dev/bhnd/cores/chipc/bhnd_sprom_chipc.c optional bhnd
+dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c 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
dev/bhnd/cores/pci/bhnd_pcib.c optional bhnd_pcib bhnd pci
dev/bhnd/cores/pcie2/bhnd_pcie2.c optional bhnd pci
dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c optional bhndb bhnd pci
dev/bhnd/cores/pcie2/bhnd_pcie2b.c optional bhnd_pcie2b bhnd pci
+dev/bhnd/cores/pmu/bhnd_pmu.c optional bhnd
+dev/bhnd/cores/pmu/bhnd_pmu_core.c optional bhnd
+dev/bhnd/cores/pmu/bhnd_pmu_if.m optional bhnd
+dev/bhnd/cores/pmu/bhnd_pmu_subr.c optional bhnd
dev/bhnd/nvram/bhnd_nvram.c optional bhnd
dev/bhnd/nvram/bhnd_nvram_common.c optional bhnd
dev/bhnd/nvram/bhnd_nvram_cfe.c optional bhnd siba_nexus cfe | \
diff --git a/sys/dev/bhnd/bcma/bcma.c b/sys/dev/bhnd/bcma/bcma.c
index a3bebcc4515b..4533d3df17ae 100644
--- a/sys/dev/bhnd/bcma/bcma.c
+++ b/sys/dev/bhnd/bcma/bcma.c
@@ -259,6 +259,78 @@ bcma_suspend_core(device_t dev, device_t child)
return (ENXIO);
}
+static uint32_t
+bcma_read_config(device_t dev, device_t child, bus_size_t offset, u_int width)
+{
+ struct bcma_devinfo *dinfo;
+ struct bhnd_resource *r;
+
+ /* Must be a directly attached child core */
+ if (device_get_parent(child) != dev)
+ return (UINT32_MAX);
+
+ /* Fetch the agent registers */
+ dinfo = device_get_ivars(child);
+ if ((r = dinfo->res_agent) == NULL)
+ return (UINT32_MAX);
+
+ /* Verify bounds */
+ if (offset > rman_get_size(r->res))
+ return (UINT32_MAX);
+
+ if (rman_get_size(r->res) - offset < width)
+ return (UINT32_MAX);
+
+ switch (width) {
+ case 1:
+ return (bhnd_bus_read_1(r, offset));
+ case 2:
+ return (bhnd_bus_read_2(r, offset));
+ case 4:
+ return (bhnd_bus_read_4(r, offset));
+ default:
+ return (UINT32_MAX);
+ }
+}
+
+static void
+bcma_write_config(device_t dev, device_t child, bus_size_t offset, uint32_t val,
+ u_int width)
+{
+ struct bcma_devinfo *dinfo;
+ struct bhnd_resource *r;
+
+ /* Must be a directly attached child core */
+ if (device_get_parent(child) != dev)
+ return;
+
+ /* Fetch the agent registers */
+ dinfo = device_get_ivars(child);
+ if ((r = dinfo->res_agent) == NULL)
+ return;
+
+ /* Verify bounds */
+ if (offset > rman_get_size(r->res))
+ return;
+
+ if (rman_get_size(r->res) - offset < width)
+ return;
+
+ switch (width) {
+ case 1:
+ bhnd_bus_write_1(r, offset, val);
+ break;
+ case 2:
+ bhnd_bus_write_2(r, offset, val);
+ break;
+ case 4:
+ bhnd_bus_write_4(r, offset, val);
+ break;
+ default:
+ break;
+ }
+}
+
static u_int
bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type)
{
@@ -473,6 +545,9 @@ bcma_add_children(device_t bus, struct resource *erom_res, bus_size_t erom_offse
* unpopulated, the device shouldn't be used. */
if (bhnd_is_hw_disabled(child))
device_disable(child);
+
+ /* Issue bus callback for fully initialized child. */
+ BHND_BUS_CHILD_ADDED(bus, child);
}
/* Hit EOF parsing cores? */
@@ -504,6 +579,8 @@ static device_method_t bcma_methods[] = {
DEVMETHOD(bhnd_bus_free_devinfo, bcma_free_bhnd_dinfo),
DEVMETHOD(bhnd_bus_reset_core, bcma_reset_core),
DEVMETHOD(bhnd_bus_suspend_core, bcma_suspend_core),
+ DEVMETHOD(bhnd_bus_read_config, bcma_read_config),
+ DEVMETHOD(bhnd_bus_write_config, bcma_write_config),
DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count),
DEVMETHOD(bhnd_bus_get_region_count, bcma_get_region_count),
DEVMETHOD(bhnd_bus_get_port_rid, bcma_get_port_rid),
diff --git a/sys/dev/bhnd/bcma/bcma_dmp.h b/sys/dev/bhnd/bcma/bcma_dmp.h
index 4be5a8ebe8b4..b65e90e19c3b 100644
--- a/sys/dev/bhnd/bcma/bcma_dmp.h
+++ b/sys/dev/bhnd/bcma/bcma_dmp.h
@@ -109,6 +109,19 @@
#define BCMA_DMP_OOBDINWIDTH 0x364
#define BCMA_DMP_OOBDOUTWIDTH 0x368
+/* The exact interpretation of these bits is unverified; these
+ * are our best guesses as to their use */
+#define BCMA_DMP_OOBSEL_MASK 0xFF /**< OOBSEL config mask */
+#define BCMA_DMP_OOBSEL_0_MASK BCMA_DMP_OOBSEL_MASK
+#define BCMA_DMP_OOBSEL_1_MASK BCMA_DMP_OOBSEL_MASK
+#define BCMA_DMP_OOBSEL_2_MASK BCMA_DMP_OOBSEL_MASK
+#define BCMA_DMP_OOBSEL_3_MASK BCMA_DMP_OOBSEL_MASK
+#define BCMA_DMP_OOBSEL_0_SHIFT 0 /**< first OOBSEL config */
+#define BCMA_DMP_OOBSEL_1_SHIFT 8 /**< second OOBSEL config */
+#define BCMA_DMP_OOBSEL_2_SHIFT 16 /**< third OOBSEL config */
+#define BCMA_DMP_OOBSEL_3_SHIFT 24 /**< fouth OOBSEL config */
+#define BCMA_DMP_OOBSEL_EN (1 << 7) /**< enable bit */
+
// This was inherited from Broadcom's aidmp.h header
// Is it required for any of our use-cases?
#if 0 /* defined(IL_BIGENDIAN) && defined(BCMHND74K) */
diff --git a/sys/dev/bhnd/bhnd.c b/sys/dev/bhnd/bhnd.c
index d86c53488ec9..c4232a1cbf3e 100644
--- a/sys/dev/bhnd/bhnd.c
+++ b/sys/dev/bhnd/bhnd.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -60,6 +60,9 @@ __FBSDID("$FreeBSD$");
#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"
@@ -342,7 +345,7 @@ bhnd_finish_attach(struct bhnd_softc *sc)
{
struct chipc_caps *ccaps;
- GIANT_REQUIRED; /* newbus */
+ GIANT_REQUIRED; /* for newbus */
KASSERT(bus_current_pass >= BHND_FINISH_ATTACH_PASS,
("bhnd_finish_attach() called in pass %d", bus_current_pass));
@@ -367,10 +370,11 @@ bhnd_finish_attach(struct bhnd_softc *sc)
}
/* Look for a PMU */
- if (ccaps->pmu) {
+ if (ccaps->pmu || ccaps->pwr_ctrl) {
if ((sc->pmu_dev = bhnd_find_pmu(sc)) == NULL) {
device_printf(sc->dev,
- "warning: PMU device not found\n");
+ "attach failed: supported PMU not found\n");
+ return (ENXIO);
}
}
@@ -478,8 +482,6 @@ found:
static device_t
bhnd_find_pmu(struct bhnd_softc *sc)
{
- struct chipc_caps *ccaps;
-
/* Make sure we're holding Giant for newbus */
GIANT_REQUIRED;
@@ -494,11 +496,6 @@ bhnd_find_pmu(struct bhnd_softc *sc)
return (sc->pmu_dev);
}
- if ((ccaps = bhnd_find_chipc_caps(sc)) == NULL)
- return (NULL);
-
- if (!ccaps->pmu)
- return (NULL);
return (bhnd_find_platform_dev(sc, "bhnd_pmu"));
}
@@ -626,6 +623,244 @@ bhnd_generic_get_probe_order(device_t dev, device_t child)
}
/**
+ * Default bhnd(4) bus driver implementation of BHND_BUS_ALLOC_PMU().
+ */
+int
+bhnd_generic_alloc_pmu(device_t dev, device_t child)
+{
+ struct bhnd_softc *sc;
+ struct bhnd_resource *br;
+ struct chipc_caps *ccaps;
+ struct bhnd_devinfo *dinfo;
+ struct bhnd_core_pmu_info *pm;
+ 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;
+ int error;
+
+ GIANT_REQUIRED; /* for newbus */
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+ pmu_regs = BHND_CLK_CTL_ST;
+
+ if ((ccaps = bhnd_find_chipc_caps(sc)) == NULL) {
+ device_printf(sc->dev, "alloc_pmu failed: chipc "
+ "capabilities unavailable\n");
+ return (ENXIO);
+ }
+
+ if ((pmu_dev = bhnd_find_pmu(sc)) == NULL) {
+ device_printf(sc->dev,
+ "pmu unavailable; cannot allocate request state\n");
+ return (ENXIO);
+ }
+
+ /* already allocated? */
+ if (dinfo->pmu_info != NULL) {
+ panic("duplicate PMU allocation for %s",
+ device_get_nameunit(child));
+ }
+
+ /* Determine address+size of the core's PMU register block */
+ error = bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &r_addr,
+ &r_size);
+ if (error) {
+ device_printf(sc->dev, "error fetching register block info for "
+ "%s: %d\n", device_get_nameunit(child), error);
+ return (error);
+ }
+
+ if (r_size < (pmu_regs + sizeof(uint32_t))) {
+ device_printf(sc->dev, "pmu offset %#jx would overrun %s "
+ "register block\n", (uintmax_t)pmu_regs,
+ device_get_nameunit(child));
+ return (ENODEV);
+ }
+
+ /* Locate actual resource containing the core's register block */
+ if ((rl = BUS_GET_RESOURCE_LIST(dev, child)) == NULL) {
+ device_printf(dev, "NULL resource list returned for %s\n",
+ device_get_nameunit(child));
+ return (ENXIO);
+ }
+
+ if ((rle = resource_list_find(rl, SYS_RES_MEMORY, 0)) == NULL) {
+ device_printf(dev, "cannot locate core register resource "
+ "for %s\n", device_get_nameunit(child));
+ return (ENXIO);
+ }
+
+ if (rle->res == NULL) {
+ device_printf(dev, "core register resource unallocated for "
+ "%s\n", device_get_nameunit(child));
+ return (ENXIO);
+ }
+
+ if (r_addr+pmu_regs < rman_get_start(rle->res) ||
+ r_addr+pmu_regs >= rman_get_end(rle->res))
+ {
+ device_printf(dev, "core register resource does not map PMU "
+ "registers at %#jx\n for %s\n", r_addr+pmu_regs,
+ device_get_nameunit(child));
+ return (ENXIO);
+ }
+
+ /* Adjust PMU register offset relative to the actual start address
+ * of the core's register block allocation.
+ *
+ * XXX: The saved offset will be invalid if bus_adjust_resource is
+ * used to modify the resource's start address.
+ */
+ if (rman_get_start(rle->res) > r_addr)
+ pmu_regs -= rman_get_start(rle->res) - r_addr;
+ else
+ pmu_regs -= r_addr - rman_get_start(rle->res);
+
+ /* Allocate and initialize PMU info */
+ br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
+ if (br == NULL)
+ return (ENOMEM);
+
+ br->res = rle->res;
+ br->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0);
+
+ pm = malloc(sizeof(*dinfo->pmu_info), M_BHND, M_NOWAIT);
+ if (pm == NULL) {
+ free(br, M_BHND);
+ return (ENOMEM);
+ }
+ pm->pm_dev = child;
+ pm->pm_pmu = pmu_dev;
+ pm->pm_res = br;
+ pm->pm_regs = pmu_regs;
+
+ dinfo->pmu_info = pm;
+ return (0);
+}
+
+/**
+ * Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_PMU().
+ */
+int
+bhnd_generic_release_pmu(device_t dev, device_t child)
+{
+ struct bhnd_softc *sc;
+ struct bhnd_devinfo *dinfo;
+ device_t pmu;
+ int error;
+
+ GIANT_REQUIRED; /* for newbus */
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ if ((pmu = bhnd_find_pmu(sc)) == NULL) {
+ device_printf(sc->dev,
+ "pmu unavailable; cannot release request state\n");
+ return (ENXIO);
+ }
+
+ /* dispatch release request */
+ if (dinfo->pmu_info == NULL)
+ panic("pmu over-release for %s", device_get_nameunit(child));
+
+ if ((error = BHND_PMU_CORE_RELEASE(pmu, dinfo->pmu_info)))
+ return (error);
+
+ /* free PMU info */
+ free(dinfo->pmu_info->pm_res, M_BHND);
+ free(dinfo->pmu_info, M_BHND);
+ dinfo->pmu_info = NULL;
+
+ return (0);
+}
+
+/**
+ * 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_devinfo *dinfo;
+ struct bhnd_core_pmu_info *pm;
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ if ((pm = dinfo->pmu_info) == NULL)
+ panic("no active PMU request state");
+
+ /* dispatch request to PMU */
+ return (BHND_PMU_CORE_REQ_CLOCK(pm->pm_pmu, pm, clock));
+}
+
+/**
+ * Default bhnd(4) bus driver implementation of BHND_BUS_ENABLE_CLOCKS().
+ */
+int
+bhnd_generic_enable_clocks(device_t dev, device_t child, uint32_t clocks)
+{
+ struct bhnd_softc *sc;
+ struct bhnd_devinfo *dinfo;
+ struct bhnd_core_pmu_info *pm;
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ if ((pm = dinfo->pmu_info) == NULL)
+ panic("no active PMU request state");
+
+ /* dispatch request to PMU */
+ return (BHND_PMU_CORE_EN_CLOCKS(pm->pm_pmu, pm, clocks));
+}
+
+/**
+ * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_EXT_RSRC().
+ */
+int
+bhnd_generic_request_ext_rsrc(device_t dev, device_t child, u_int rsrc)
+{
+ struct bhnd_softc *sc;
+ struct bhnd_devinfo *dinfo;
+ struct bhnd_core_pmu_info *pm;
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ if ((pm = dinfo->pmu_info) == NULL)
+ panic("no active PMU request state");
+
+ /* dispatch request to PMU */
+ return (BHND_PMU_CORE_REQ_EXT_RSRC(pm->pm_pmu, pm, rsrc));
+}
+
+/**
+ * Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_EXT_RSRC().
+ */
+int
+bhnd_generic_release_ext_rsrc(device_t dev, device_t child, u_int rsrc)
+{
+ struct bhnd_softc *sc;
+ struct bhnd_devinfo *dinfo;
+ struct bhnd_core_pmu_info *pm;
+
+ sc = device_get_softc(dev);
+ dinfo = device_get_ivars(child);
+
+ if ((pm = dinfo->pmu_info) == NULL)
+ panic("no active PMU request state");
+
+ /* dispatch request to PMU */
+ return (BHND_PMU_CORE_RELEASE_EXT_RSRC(pm->pm_pmu, pm, rsrc));
+}
+
+
+/**
* Default bhnd(4) bus driver implementation of BHND_BUS_IS_REGION_VALID().
*
* This implementation assumes that port and region numbers are 0-indexed and
@@ -815,13 +1050,21 @@ bhnd_generic_add_child(device_t dev, u_int order, const char *name, int unit)
device_set_ivars(child, dinfo);
- /* Inform concrete bus driver. */
- BHND_BUS_CHILD_ADDED(dev, child);
-
return (child);
}
/**
+ * Default bhnd(4) bus driver implementation of BHND_BUS_CHILD_ADDED().
+ *
+ * This implementation manages internal bhnd(4) state, and must be called
+ * by subclassing drivers.
+ */
+void
+bhnd_generic_child_added(device_t dev, device_t child)
+{
+}
+
+/**
* Default bhnd(4) bus driver implementation of BUS_CHILD_DELETED().
*
* This implementation manages internal bhnd(4) state, and must be called
@@ -836,8 +1079,17 @@ bhnd_generic_child_deleted(device_t dev, device_t child)
sc = device_get_softc(dev);
/* Free device info */
- if ((dinfo = device_get_ivars(child)) != NULL)
+ if ((dinfo = device_get_ivars(child)) != NULL) {
+ if (dinfo->pmu_info != NULL) {
+ /* Releasing PMU requests automatically would be nice,
+ * but we can't reference per-core PMU register
+ * resource after driver detach */
+ panic("%s leaked device pmu state\n",
+ device_get_nameunit(child));
+ }
+
BHND_BUS_FREE_DEVINFO(dev, dinfo);
+ }
/* Clean up platform device references */
if (sc->chipc_dev == child) {
@@ -998,9 +1250,20 @@ static device_method_t bhnd_methods[] = {
/* BHND interface */
DEVMETHOD(bhnd_bus_get_chipid, bhnd_bus_generic_get_chipid),
+ DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled),
+ DEVMETHOD(bhnd_bus_read_board_info, bhnd_bus_generic_read_board_info),
+
DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order),
+
+ DEVMETHOD(bhnd_bus_alloc_pmu, bhnd_generic_alloc_pmu),
+ DEVMETHOD(bhnd_bus_release_pmu, bhnd_generic_release_pmu),
+ DEVMETHOD(bhnd_bus_request_clock, bhnd_generic_request_clock),
+ DEVMETHOD(bhnd_bus_enable_clocks, bhnd_generic_enable_clocks),
+ DEVMETHOD(bhnd_bus_request_ext_rsrc, bhnd_generic_request_ext_rsrc),
+ DEVMETHOD(bhnd_bus_release_ext_rsrc, bhnd_generic_release_ext_rsrc),
+
+ DEVMETHOD(bhnd_bus_child_added, bhnd_generic_child_added),
DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid),
- DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled),
DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_generic_get_nvram_var),
/* BHND interface (bus I/O) */
diff --git a/sys/dev/bhnd/bhnd.h b/sys/dev/bhnd/bhnd.h
index e4eb40ecc16c..1a4d8d8c544b 100644
--- a/sys/dev/bhnd/bhnd.h
+++ b/sys/dev/bhnd/bhnd.h
@@ -417,6 +417,67 @@ bhnd_get_chipid(device_t dev) {
};
/**
+ * If supported by the chipset, return the clock source for the given clock.
+ *
+ * This function is only supported on early PWRCTL-equipped chipsets
+ * that expose clock management via their host bridge interface. Currently,
+ * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
+ *
+ * @param dev A bhnd bus child device.
+ * @param clock The clock for which a clock source will be returned.
+ *
+ * @retval bhnd_clksrc The clock source for @p clock.
+ * @retval BHND_CLKSRC_UNKNOWN If @p clock is unsupported, or its
+ * clock source is not known to the bus.
+ */
+static inline bhnd_clksrc
+bhnd_pwrctl_get_clksrc(device_t dev, bhnd_clock clock)
+{
+ return (BHND_BUS_PWRCTL_GET_CLKSRC(device_get_parent(dev), dev, clock));
+}
+
+/**
+ * If supported by the chipset, gate @p clock
+ *
+ * This function is only supported on early PWRCTL-equipped chipsets
+ * that expose clock management via their host bridge interface. Currently,
+ * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
+ *
+ * @param dev A bhnd bus child device.
+ * @param clock The clock to be disabled.
+ *
+ * @retval 0 success
+ * @retval ENODEV If bus-level clock source management is not supported.
+ * @retval ENXIO If bus-level management of @p clock is not supported.
+ */
+static inline int
+bhnd_pwrctl_gate_clock(device_t dev, bhnd_clock clock)
+{
+ return (BHND_BUS_PWRCTL_GATE_CLOCK(device_get_parent(dev), dev, clock));
+}
+
+/**
+ * If supported by the chipset, ungate @p clock
+ *
+ * This function is only supported on early PWRCTL-equipped chipsets
+ * that expose clock management via their host bridge interface. Currently,
+ * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
+ *
+ * @param dev A bhnd bus child device.
+ * @param clock The clock to be enabled.
+ *
+ * @retval 0 success
+ * @retval ENODEV If bus-level clock source management is not supported.
+ * @retval ENXIO If bus-level management of @p clock is not supported.
+ */
+static inline int
+bhnd_pwrctl_ungate_clock(device_t dev, bhnd_clock clock)
+{
+ return (BHND_BUS_PWRCTL_UNGATE_CLOCK(device_get_parent(dev), dev,
+ clock));
+}
+
+/**
* Return the BHND attachment type of the parent bhnd bus.
*
* @param dev A bhnd bus child device.
@@ -454,6 +515,171 @@ bhnd_read_board_info(device_t dev, struct bhnd_board_info *info)
}
/**
+ * Allocate and enable per-core PMU request handling for @p child.
+ *
+ * The region containing the core's PMU register block (if any) must be
+ * allocated via bus_alloc_resource(9) (or bhnd_alloc_resource) before
+ * calling bhnd_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.
+ *
+ * @retval 0 success
+ * @retval non-zero If allocating PMU request state otherwise fails, a
+ * regular unix error code will be returned.
+ */
+static inline int
+bhnd_alloc_pmu(device_t dev)
+{
+ return (BHND_BUS_ALLOC_PMU(device_get_parent(dev), dev));
+}
+
+/**
+ * Release any per-core PMU resources allocated for @p child. Any outstanding
+ * PMU requests are are discarded.
+ *
+ * @param dev The parent of @p child.
+ * @param child The requesting bhnd device.
+ *
+ * @retval 0 success
+ * @retval non-zero If releasing PMU request state otherwise fails, a
+ * regular unix error code will be returned, and
+ * the core state will be left unmodified.
+ */
+static inline int
+bhnd_release_pmu(device_t dev)
+{
+ return (BHND_BUS_RELEASE_PMU(device_get_parent(dev), dev));
+}
+
+/**
+ * Request that @p clock (or faster) be routed to @p dev.
+ *
+ * A driver must ask the bhnd bus to allocate clock request state
+ * via bhnd_alloc_pmu() before it can request clock resources.
+ *
+ * Request multiplexing is managed by the bus.
+ *
+ * @param dev The bhnd(4) device to which @p clock should be routed.
+ * @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.
+ */
+static inline int
+bhnd_request_clock(device_t dev, bhnd_clock clock)
+{
+ return (BHND_BUS_REQUEST_CLOCK(device_get_parent(dev), dev, clock));
+}
+
+/**
+ * Request that @p clocks be powered on behalf of @p dev.
+ *
+ * This will power any clock sources (e.g. XTAL, PLL, etc) required for
+ * @p clocks and wait until they are ready, discarding any previous
+ * requests by @p dev.
+ *
+ * Request multiplexing is managed by the bus.
+ *
+ * A driver must ask the bhnd bus to allocate clock request state
+ * via bhnd_alloc_pmu() before it can request clock resources.
+ *
+ * @param dev The requesting bhnd(4) device.
+ * @param clocks The clock(s) to be enabled.
+ *
+ * @retval 0 success
+ * @retval ENODEV If an unsupported clock was requested.
+ * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
+ */
+static inline int
+bhnd_enable_clocks(device_t dev, uint32_t clocks)
+{
+ return (BHND_BUS_ENABLE_CLOCKS(device_get_parent(dev), dev, clocks));
+}
+
+/**
+ * Power up an external PMU-managed resource assigned to @p dev.
+ *
+ * A driver must ask the bhnd bus to allocate PMU request state
+ * via bhnd_alloc_pmu() before it can request PMU resources.
+ *
+ * @param dev The requesting bhnd(4) device.
+ * @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.
+ */
+static inline int
+bhnd_request_ext_rsrc(device_t dev, u_int rsrc)
+{
+ return (BHND_BUS_REQUEST_EXT_RSRC(device_get_parent(dev), dev, rsrc));
+}
+
+/**
+ * Power down an external PMU-managed resource assigned to @p dev.
+ *
+ * A driver must ask the bhnd bus to allocate PMU request state
+ * via bhnd_alloc_pmu() before it can request PMU resources.
+ *
+ * @param dev The requesting bhnd(4) device.
+ * @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.
+ */
+static inline int
+bhnd_release_ext_rsrc(device_t dev, u_int rsrc)
+{
+ return (BHND_BUS_RELEASE_EXT_RSRC(device_get_parent(dev), dev, rsrc));
+}
+
+
+/**
+ * Read @p width bytes at @p offset from the bus-specific agent/config
+ * space of @p dev.
+ *
+ * @param dev The bhnd device for which @p offset should be read.
+ * @param offset The offset to be read.
+ * @param width The size of the access. Must be 1, 2 or 4 bytes.
+ *
+ * The exact behavior of this method is bus-specific. In the case of
+ * bcma(4), this method provides access to the first agent port of @p child.
+ *
+ * @note Device drivers should only use this API for functionality
+ * that is not available via another bhnd(4) function.
+ */
+static inline uint32_t
+bhnd_read_config(device_t dev, bus_size_t offset, u_int width)
+{
+ return (BHND_BUS_READ_CONFIG(device_get_parent(dev), dev, offset,
+ width));
+}
+
+/**
+ * Read @p width bytes at @p offset from the bus-specific agent/config
+ * space of @p dev.
+ *
+ * @param dev The bhnd device for which @p offset should be read.
+ * @param offset The offset to be written.
+ * @param width The size of the access. Must be 1, 2 or 4 bytes.
+ *
+ * The exact behavior of this method is bus-specific. In the case of
+ * bcma(4), this method provides access to the first agent port of @p child.
+ *
+ * @note Device drivers should only use this API for functionality
+ * that is not available via another bhnd(4) function.
+ */
+static inline void
+bhnd_write_config(device_t dev, bus_size_t offset, uint32_t val, u_int width)
+{
+ BHND_BUS_WRITE_CONFIG(device_get_parent(dev), dev, offset, val, width);
+}
+
+/**
* Read an NVRAM variable, coerced to the requested @p type.
*
* @param dev A bhnd bus child device.
diff --git a/sys/dev/bhnd/bhnd_bus_if.m b/sys/dev/bhnd/bhnd_bus_if.m
index bf69af7b206b..0499e685af5d 100644
--- a/sys/dev/bhnd/bhnd_bus_if.m
+++ b/sys/dev/bhnd/bhnd_bus_if.m
@@ -61,6 +61,27 @@ CODE {
{
panic("bhnd_bus_get_attach_type unimplemented");
}
+
+ static bhnd_clksrc
+ bhnd_bus_null_pwrctl_get_clksrc(device_t dev, device_t child,
+ bhnd_clock clock)
+ {
+ return (BHND_CLKSRC_UNKNOWN);
+ }
+
+ static int
+ bhnd_bus_null_pwrctl_gate_clock(device_t dev, device_t child,
+ bhnd_clock clock)
+ {
+ return (ENODEV);
+ }
+
+ static int
+ bhnd_bus_null_pwrctl_ungate_clock(device_t dev, device_t child,
+ bhnd_clock clock)
+ {
+ return (ENODEV);
+ }
static int
bhnd_bus_null_read_board_info(device_t dev, device_t child,
@@ -74,6 +95,60 @@ CODE {
{
}
+ static int
+ bhnd_bus_null_alloc_pmu(device_t dev, device_t child)
+ {
+ panic("bhnd_bus_alloc_pmu unimplemented");
+ }
+
+ static int
+ bhnd_bus_null_release_pmu(device_t dev, device_t child)
+ {
+ panic("bhnd_bus_release_pmu unimplemented");
+ }
+
+ static int
+ bhnd_bus_null_request_clock(device_t dev, device_t child,
+ bhnd_clock clock)
+ {
+ panic("bhnd_bus_request_clock unimplemented");
+ }
+
+ static int
+ bhnd_bus_null_enable_clocks(device_t dev, device_t child,
+ uint32_t clocks)
+ {
+ panic("bhnd_bus_enable_clocks unimplemented");
+ }
+
+ static int
+ bhnd_bus_null_request_ext_rsrc(device_t dev, device_t child,
+ u_int rsrc)
+ {
+ panic("bhnd_bus_request_ext_rsrc unimplemented");
+ }
+
+ static int
+ bhnd_bus_null_release_ext_rsrc(device_t dev, device_t child,
+ u_int rsrc)
+ {
+ panic("bhnd_bus_release_ext_rsrc unimplemented");
+ }
+
+ static uint32_t
+ bhnd_bus_null_read_config(device_t dev, device_t child,
+ bus_size_t offset, u_int width)
+ {
+ panic("bhnd_bus_null_read_config unimplemented");
+ }
+
+ static void
+ bhnd_bus_null_write_config(device_t dev, device_t child,
+ bus_size_t offset, uint32_t val, u_int width)
+ {
+ panic("bhnd_bus_null_write_config unimplemented");
+ }
+
static device_t
bhnd_bus_null_find_hostb_device(device_t dev)
{
@@ -261,9 +336,8 @@ METHOD void free_devinfo {
/**
* Notify a bhnd bus that a child was added.
*
- * Called at the end of BUS_ADD_CHILD() to allow the concrete bhnd(4)
- * driver instance to initialize any additional driver-specific state for the
- * child.
+ * This method must be called by concrete bhnd(4) driver impementations
+ * after @p child's bus state is fully initialized.
*
* @param dev The bhnd bus whose child is being added.
* @param child The child added to @p dev.
@@ -304,6 +378,230 @@ METHOD int suspend_core {
}
/**
+ * 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 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 pwrctl_get_clksrc {
+ device_t dev;
+ device_t child;
+ bhnd_clock clock;
+} DEFAULT bhnd_bus_null_pwrctl_get_clksrc;
+
+/**
+ * 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.
+ *
+ * @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 pwrctl_gate_clock {
+ device_t dev;
+ device_t child;
+ bhnd_clock clock;
+} DEFAULT bhnd_bus_null_pwrctl_gate_clock;
+
+/**
+ * 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.
+ *
+ * @retval 0 success
+ * @retval ENODEV If bus-level clock source management is not supported.
+ * @retval ENXIO If bus-level management of @p clock is not supported.
+ */
+METHOD int pwrctl_ungate_clock {
+ device_t dev;
+ device_t child;
+ bhnd_clock clock;
+} DEFAULT bhnd_bus_null_pwrctl_ungate_clock;
+
+/**
+ * Allocate and enable per-core PMU request handling for @p child.
+ *
+ * The region containing the core's PMU register block (if any) must be
+ * allocated via bus_alloc_resource(9) (or bhnd_alloc_resource) before
+ * calling BHND_BUS_ALLOC_PMU(), and must not be released until after
+ * calling BHND_BUS_RELEASE_PMU().
+ *
+ * @param dev The parent of @p child.
+ * @param child The requesting bhnd device.
+ */
+METHOD int alloc_pmu {
+ device_t dev;
+ device_t child;
+} DEFAULT bhnd_bus_null_alloc_pmu;
+
+/**
+ * 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 requesting bhnd device.
+ */
+METHOD int release_pmu {
+ device_t dev;
+ device_t child;
+} DEFAULT bhnd_bus_null_release_pmu;
+
+/**
+ * Request that @p clock (or faster) be routed to @p child.
+ *
+ * A driver must ask the bhnd bus to allocate PMU request state
+ * via BHND_BUS_ALLOC_PMU() before it can request clock resources.
+ *
+ * Request multiplexing is managed by the bus.
+ *
+ * @param dev The parent of @p child.
+ * @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.
+ */
+METHOD int request_clock {
+ device_t dev;
+ device_t child;
+ bhnd_clock clock;
+} DEFAULT bhnd_bus_null_request_clock;
+
+/**
+ * Request that @p clocks be powered on behalf of @p child.
+ *
+ * This will power on clock sources (e.g. XTAL, PLL, etc) required for
+ * @p clocks and wait until they are ready, discarding any previous
+ * requests by @p child.
+ *
+ * Request multiplexing is managed by the bus.
+ *
+ * A driver must ask the bhnd bus to allocate PMU request state
+ * via BHND_BUS_ALLOC_PMU() before it can request clock resources.
+ *
+ * @param dev The parent of @p child.
+ * @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.
+ */
+METHOD int enable_clocks {
+ device_t dev;
+ device_t child;
+ uint32_t clocks;
+} DEFAULT bhnd_bus_null_enable_clocks;
+
+/**
+ * Power up an external PMU-managed resource assigned to @p child.
+ *
+ * A driver must ask the bhnd bus to allocate PMU request state
+ * via BHND_BUS_ALLOC_PMU() before it can request PMU resources.
+ *
+ * @param dev The parent of @p child.
+ * @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.
+ */
+METHOD int request_ext_rsrc {
+ device_t dev;
+ device_t child;
+ u_int rsrc;
+} DEFAULT bhnd_bus_null_request_ext_rsrc;
+
+/**
+ * Power down an external PMU-managed resource assigned to @p child.
+ *
+ * A driver must ask the bhnd bus to allocate PMU request state
+ * via BHND_BUS_ALLOC_PMU() before it can request PMU resources.
+ *
+ * @param dev The parent of @p child.
+ * @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.
+ */
+METHOD int release_ext_rsrc {
+ device_t dev;
+ device_t child;
+ u_int rsrc;
+} DEFAULT bhnd_bus_null_release_ext_rsrc;
+
+/**
+ * Read @p width bytes at @p offset from the bus-specific agent/config
+ * space of @p child.
+ *
+ * @param dev The parent of @p child.
+ * @param child The bhnd device for which @p offset should be read.
+ * @param offset The offset to be read.
+ * @param width The size of the access. Must be 1, 2 or 4 bytes.
+ *
+ * The exact behavior of this method is bus-specific. In the case of
+ * bcma(4), this method provides access to the first agent port of @p child.
+ *
+ * @note Device drivers should only use this API for functionality
+ * that is not available via another bhnd(4) function.
+ */
+METHOD uint32_t read_config {
+ device_t dev;
+ device_t child;
+ bus_size_t offset;
+ u_int width;
+} DEFAULT bhnd_bus_null_read_config;
+
+/**
+ * Read @p width bytes at @p offset from the bus-specific agent/config
+ * space of @p child.
+ *
+ * @param dev The parent of @p child.
+ * @param child The bhnd device for which @p offset should be read.
+ * @param offset The offset to be written.
+ * @param width The size of the access. Must be 1, 2 or 4 bytes.
+ *
+ * The exact behavior of this method is bus-specific. In the case of
+ * bcma(4), this method provides access to the first agent port of @p child.
+ *
+ * @note Device drivers should only use this API for functionality
+ * that is not available via another bhnd(4) function.
+ */
+METHOD void write_config {
+ device_t dev;
+ device_t child;
+ bus_size_t offset;
+ uint32_t val;
+ u_int width;
+} DEFAULT bhnd_bus_null_write_config;
+
+/**
* Allocate a bhnd resource.
*
* This method's semantics are functionally identical to the bus API of the same
diff --git a/sys/dev/bhnd/bhnd_core.h b/sys/dev/bhnd/bhnd_core.h
index f635a642b5d6..26506969429a 100644
--- a/sys/dev/bhnd/bhnd_core.h
+++ b/sys/dev/bhnd/bhnd_core.h
@@ -46,40 +46,4 @@
#define BHND_RESET_SF 0x0804
-/*
- * A register that is common to all cores to
- * communicate w/PMU regarding clock control.
- *
- * TODO: Determine when this register first appeared.
- */
-#define BHND_CLK_CTL_ST 0x1e0 /**< clock control and status */
-
-/*
- * BHND_CLK_CTL_ST register
- *
- * 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_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_ALPAREQ 0x00000008 /**< ALP Avail Request */
-#define BHND_CCS_HTAREQ 0x00000010 /**< HT Avail Request */
-#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_ALPAVAIL 0x00010000 /**< ALP is available */
-#define BHND_CCS_HTAVAIL 0x00020000 /**< HT is available */
-#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 */
-
#endif /* _BHND_BHND_CORE_H_ */
diff --git a/sys/dev/bhnd/bhnd_ids.h b/sys/dev/bhnd/bhnd_ids.h
index 6945c7650cb5..ac5cba9a8117 100644
--- a/sys/dev/bhnd/bhnd_ids.h
+++ b/sys/dev/bhnd/bhnd_ids.h
@@ -698,12 +698,6 @@
#define BHND_GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */
#define BHND_GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */
-/* Power Control Defines */
-#define BHND_CHIPC_PLL_DELAY 150 /* us pll on delay */
-#define BHND_CHIPC_FREF_DELAY 200 /* us fref change delay */
-#define BHND_CHIPC_MIN_SLOW_CLK 32 /* us Slow clock period */
-#define BHND_CHIPC_XTAL_ON_DELAY 1000 /* us crystal power-on delay */
-
/* Board Types */
#define BHND_BOARD_BU4710 0x0400
#define BHND_BOARD_VSIM4710 0x0401
diff --git a/sys/dev/bhnd/bhnd_subr.c b/sys/dev/bhnd/bhnd_subr.c
index 03d1b5a625ce..abea9128d5ca 100644
--- a/sys/dev/bhnd/bhnd_subr.c
+++ b/sys/dev/bhnd/bhnd_subr.c
@@ -1311,7 +1311,9 @@ bhnd_bus_generic_read_board_info(device_t dev, device_t child,
OPT_BHND_GV(info->board_vendor, BOARDVENDOR, 0);
OPT_BHND_GV(info->board_type, BOARDTYPE, 0); /* srom >= 2 */
REQ_BHND_GV(info->board_rev, BOARDREV);
- REQ_BHND_GV(info->board_srom_rev,SROMREV);
+ OPT_BHND_GV(info->board_srom_rev,SROMREV, 0); /* missing in
+ some SoC
+ NVRAM */
REQ_BHND_GV(info->board_flags, BOARDFLAGS);
OPT_BHND_GV(info->board_flags2, BOARDFLAGS2, 0); /* srom >= 4 */
OPT_BHND_GV(info->board_flags3, BOARDFLAGS3, 0); /* srom >= 11 */
diff --git a/sys/dev/bhnd/bhnd_types.h b/sys/dev/bhnd/bhnd_types.h
index 352e1039a182..49387080703c 100644
--- a/sys/dev/bhnd/bhnd_types.h
+++ b/sys/dev/bhnd/bhnd_types.h
@@ -85,6 +85,66 @@ typedef enum {
* SoC */
} bhnd_attach_type;
+/**
+ * bhnd(4) clock types.
+ */
+typedef enum {
+ /**
+ * Dynamically select an appropriate clock source based on all
+ * outstanding clock requests.
+ */
+ BHND_CLOCK_DYN = (1 << 0),
+
+ /**
+ * Idle Low-Power (ILP).
+ *
+ * No register access is required, or long request latency is
+ * acceptable.
+ */
+ BHND_CLOCK_ILP = (1 << 1),
+
+ /**
+ * Active Low-Power (ALP).
+ *
+ * Low-latency register access and low-rate DMA.
+ */
+ BHND_CLOCK_ALP = (1 << 2),
+
+ /**
+ * High Throughput (HT).
+ *
+ * High bus throughput and lowest-latency register access.
+ */
+ BHND_CLOCK_HT = (1 << 3)
+} bhnd_clock;
+
+/**
+ * Given two clock types, return the type with the highest precedence.
+ */
+static inline bhnd_clock
+bhnd_clock_max(bhnd_clock a, bhnd_clock b) {
+ return (a > b ? a : b);
+}
+
+/**
+ * bhnd(4) clock sources.
+ */
+typedef enum {
+ /**
+ * Clock is provided by the PCI bus clock
+ */
+ BHND_CLKSRC_PCI = 0,
+
+ /** Clock is provided by a crystal. */
+ BHND_CLKSRC_XTAL = 1,
+
+ /** Clock is provided by a low power oscillator. */
+ BHND_CLKSRC_LPO = 2,
+
+ /** Clock source is unknown */
+ BHND_CLKSRC_UNKNOWN = 3
+} bhnd_clksrc;
+
/** Evaluates to true if @p cls is a device class that can be configured
* as a host bridge device. */
#define BHND_DEVCLASS_SUPPORTS_HOSTB(cls) \
diff --git a/sys/dev/bhnd/bhndb/bhnd_bhndb.c b/sys/dev/bhnd/bhndb/bhnd_bhndb.c
index c561b4dc82b3..c70bbbf89309 100644
--- a/sys/dev/bhnd/bhndb/bhnd_bhndb.c
+++ b/sys/dev/bhnd/bhndb/bhnd_bhndb.c
@@ -66,11 +66,42 @@ bhnd_bhndb_get_attach_type(device_t dev, device_t child)
return (BHND_ATTACH_ADAPTER);
}
+static bhnd_clksrc
+bhnd_bhndb_pwrctl_get_clksrc(device_t dev, device_t child,
+ bhnd_clock clock)
+{
+ /* Delegate to parent bridge */
+ return (BHND_BUS_PWRCTL_GET_CLKSRC(device_get_parent(dev), child,
+ clock));
+}
+
+static int
+bhnd_bhndb_pwrctl_gate_clock(device_t dev, device_t child,
+ bhnd_clock clock)
+{
+ /* Delegate to parent bridge */
+ return (BHND_BUS_PWRCTL_GATE_CLOCK(device_get_parent(dev), child,
+ clock));
+}
+
+static int
+bhnd_bhndb_pwrctl_ungate_clock(device_t dev, device_t child,
+ bhnd_clock clock)
+{
+ /* Delegate to parent bridge */
+ return (BHND_BUS_PWRCTL_UNGATE_CLOCK(device_get_parent(dev), child,
+ clock));
+}
+
static device_method_t bhnd_bhndb_methods[] = {
/* BHND interface */
DEVMETHOD(bhnd_bus_get_attach_type, bhnd_bhndb_get_attach_type),
DEVMETHOD(bhnd_bus_read_board_info, bhnd_bhndb_read_board_info),
+ 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_END
};
diff --git a/sys/dev/bhnd/bhndb/bhndb.c b/sys/dev/bhnd/bhndb/bhndb.c
index d7bc121a8862..f12c5434c811 100644
--- a/sys/dev/bhnd/bhndb/bhndb.c
+++ b/sys/dev/bhnd/bhndb/bhndb.c
@@ -2028,4 +2028,3 @@ DEFINE_CLASS_0(bhndb, bhndb_driver, bhndb_methods, sizeof(struct bhndb_softc));
MODULE_VERSION(bhndb, 1);
MODULE_DEPEND(bhndb, bhnd, 1, 1, 1);
-MODULE_DEPEND(bhndb, bhnd_chipc, 1, 1, 1);
diff --git a/sys/dev/bhnd/bhndb/bhndb_pci.c b/sys/dev/bhnd/bhndb/bhndb_pci.c
index 3cadb142b5ee..5d834724f1dd 100644
--- a/sys/dev/bhnd/bhndb/bhndb_pci.c
+++ b/sys/dev/bhnd/bhndb/bhndb_pci.c
@@ -606,6 +606,64 @@ bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc)
return (0);
}
+static bhnd_clksrc
+bhndb_pci_pwrctl_get_clksrc(device_t dev, device_t child,
+ bhnd_clock clock)
+{
+ struct bhndb_pci_softc *sc;
+ uint32_t gpio_out;
+
+ sc = device_get_softc(dev);
+
+ /* Only supported on PCI devices */
+ if (sc->pci_devclass != BHND_DEVCLASS_PCI)
+ return (ENODEV);
+
+ /* Only ILP is supported */
+ if (clock != BHND_CLOCK_ILP)
+ return (ENXIO);
+
+ gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4);
+ if (gpio_out & BHNDB_PCI_GPIO_SCS)
+ return (BHND_CLKSRC_PCI);
+ else
+ return (BHND_CLKSRC_XTAL);
+}
+
+static int
+bhndb_pci_pwrctl_gate_clock(device_t dev, device_t child,
+ bhnd_clock clock)
+{
+ struct bhndb_pci_softc *sc = device_get_softc(dev);
+
+ /* Only supported on PCI devices */
+ if (sc->pci_devclass != BHND_DEVCLASS_PCI)
+ return (ENODEV);
+
+ /* Only HT is supported */
+ if (clock != BHND_CLOCK_HT)
+ return (ENXIO);
+
+ return (bhndb_disable_pci_clocks(sc));
+}
+
+static int
+bhndb_pci_pwrctl_ungate_clock(device_t dev, device_t child,
+ bhnd_clock clock)
+{
+ struct bhndb_pci_softc *sc = device_get_softc(dev);
+
+ /* Only supported on PCI devices */
+ if (sc->pci_devclass != BHND_DEVCLASS_PCI)
+ return (ENODEV);
+
+ /* Only HT is supported */
+ if (clock != BHND_CLOCK_HT)
+ return (ENXIO);
+
+ return (bhndb_enable_pci_clocks(sc));
+}
+
static device_method_t bhndb_pci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bhndb_pci_probe),
@@ -614,6 +672,11 @@ static device_method_t bhndb_pci_methods[] = {
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),
+
/* BHNDB interface */
DEVMETHOD(bhndb_init_full_config, bhndb_pci_init_full_config),
DEVMETHOD(bhndb_set_window_addr, bhndb_pci_set_window_addr),
@@ -627,7 +690,6 @@ DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods,
MODULE_VERSION(bhndb_pci, 1);
MODULE_DEPEND(bhndb_pci, bhnd_pci_hostb, 1, 1, 1);
-MODULE_DEPEND(bhndb_pci, bhnd_pcie2_hostb, 1, 1, 1);
MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1);
MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1);
MODULE_DEPEND(bhndb_pci, bhnd, 1, 1, 1);
diff --git a/sys/dev/bhnd/bhndvar.h b/sys/dev/bhnd/bhndvar.h
index eccf55c234e0..c5317a04b5b9 100644
--- a/sys/dev/bhnd/bhndvar.h
+++ b/sys/dev/bhnd/bhndvar.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,27 +45,7 @@
MALLOC_DECLARE(M_BHND);
DECLARE_CLASS(bhnd_driver);
-/**
- * bhnd per-device info. Must be first member of all subclass
- * devinfo structures.
- */
-struct bhnd_devinfo {
-};
-
-/**
- * bhnd driver instance state. Must be first member of all subclass
- * softc structures.
- */
-struct bhnd_softc {
- device_t dev; /**< bus device */
-
- bool attach_done; /**< true if initialization of all
- * platform devices has been
- * completed */
- device_t chipc_dev; /**< bhnd_chipc device */
- device_t nvram_dev; /**< bhnd_nvram device, if any */
- device_t pmu_dev; /**< bhnd_pmu device, if any */
-};
+struct bhnd_core_pmu_info;
int bhnd_generic_attach(device_t dev);
int bhnd_generic_detach(device_t dev);
@@ -76,6 +56,19 @@ int bhnd_generic_suspend(device_t dev);
int bhnd_generic_get_probe_order(device_t dev,
device_t child);
+int bhnd_generic_alloc_pmu(device_t dev,
+ device_t child);
+int bhnd_generic_release_pmu(device_t dev,
+ device_t child);
+int bhnd_generic_request_clock(device_t dev,
+ device_t child, bhnd_clock clock);
+int bhnd_generic_enable_clocks(device_t dev,
+ device_t child, uint32_t clocks);
+int bhnd_generic_request_ext_rsrc(device_t dev,
+ device_t child, u_int rsrc);
+int bhnd_generic_release_ext_rsrc(device_t dev,
+ device_t child, u_int rsrc);
+
int bhnd_generic_print_child(device_t dev,
device_t child);
void bhnd_generic_probe_nomatch(device_t dev,
@@ -83,6 +76,7 @@ void bhnd_generic_probe_nomatch(device_t dev,
device_t bhnd_generic_add_child(device_t dev, u_int order,
const char *name, int unit);
+void bhnd_generic_child_added(device_t dev, device_t child);
void bhnd_generic_child_deleted(device_t dev,
device_t child);
int bhnd_generic_suspend_child(device_t dev,
@@ -94,4 +88,28 @@ int bhnd_generic_get_nvram_var(device_t dev,
device_t child, const char *name, void *buf,
size_t *size, bhnd_nvram_type type);
+
+/**
+ * bhnd per-device info. Must be first member of all subclass
+ * devinfo structures.
+ */
+struct bhnd_devinfo {
+ struct bhnd_core_pmu_info *pmu_info; /**< PMU info, or NULL */
+};
+
+/**
+ * bhnd driver instance state. Must be first member of all subclass
+ * softc structures.
+ */
+struct bhnd_softc {
+ device_t dev; /**< bus device */
+
+ bool attach_done; /**< true if initialization of
+ * all platform devices has
+ * been completed */
+ device_t chipc_dev; /**< bhnd_chipc device */
+ device_t nvram_dev; /**< bhnd_nvram device, if any */
+ device_t pmu_dev; /**< bhnd_pmu device, if any */
+};
+
#endif /* _BHND_BHNDVAR_H_ */
diff --git a/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m b/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
index 5773d39a2b35..0cfcc3975973 100644
--- a/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
+++ b/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
@@ -48,6 +48,22 @@ CODE {
}
}
+
+/**
+ * Return the current value of the chipstatus register.
+ *
+ * @param dev A bhnd(4) ChipCommon device.
+ *
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_chipc() function.
+ *
+ * @returns The chipstatus register value, or 0 if undefined by this
+ * hardware (e.g. if @p dev is an EXTIF core).
+ */
+METHOD uint32_t read_chipst {
+ device_t dev;
+}
+
/**
* Write @p value with @p mask directly to the chipctrl register.
*
diff --git a/sys/dev/bhnd/cores/chipc/bhnd_pmu_chipc.c b/sys/dev/bhnd/cores/chipc/bhnd_pmu_chipc.c
new file mode 100644
index 000000000000..25b1abb6f0b6
--- /dev/null
+++ b/sys/dev/bhnd/cores/chipc/bhnd_pmu_chipc.c
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 2016 Landon Fuller <landon@landonf.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * ChipCommon attachment support for the bhnd(4) PMU driver.
+ *
+ * Supports non-AOB ("Always-on Bus") devices that map the PMU register blocks
+ * via the ChipCommon core, rather than vending a distinct PMU core on the
+ * bhnd bus.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+
+#include <dev/bhnd/bhnd.h>
+
+#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
+#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
+
+#include "bhnd_chipc_if.h"
+#include "bhnd_pmu_if.h"
+
+#include "chipcvar.h"
+
+static int
+bhnd_pmu_chipc_probe(device_t dev)
+{
+ struct bhnd_pmu_softc *sc;
+ struct chipc_caps *ccaps;
+ struct chipc_softc *chipc_sc;
+ device_t chipc;
+ char desc[34];
+ int error;
+ uint32_t pcaps;
+ uint8_t rev;
+
+ sc = device_get_softc(dev);
+
+ /* Look for chipc parent */
+ chipc = device_get_parent(dev);
+ if (device_get_devclass(chipc) != devclass_find("bhnd_chipc"))
+ return (ENXIO);
+
+ /* Check the chipc PMU capability flag. */
+ ccaps = BHND_CHIPC_GET_CAPS(chipc);
+ if (!ccaps->pmu)
+ return (ENXIO);
+
+ /* Delegate to common driver implementation */
+ if ((error = bhnd_pmu_probe(dev)) > 0)
+ return (error);
+
+ /* Fetch PMU capability flags */
+ chipc_sc = device_get_softc(chipc);
+ pcaps = bhnd_bus_read_4(chipc_sc->core, BHND_PMU_CAP);
+
+ /* Set description */
+ rev = BHND_PMU_GET_BITS(pcaps, BHND_PMU_CAP_REV);
+ snprintf(desc, sizeof(desc), "Broadcom ChipCommon PMU, rev %hhu", rev);
+ device_set_desc_copy(dev, desc);
+
+ return (BUS_PROBE_NOWILDCARD);
+}
+
+static int
+bhnd_pmu_chipc_attach(device_t dev)
+{
+ struct chipc_softc *chipc_sc;
+ struct bhnd_resource *r;
+
+ /* Fetch core registers from ChipCommon parent */
+ chipc_sc = device_get_softc(device_get_parent(dev));
+ r = chipc_sc->core;
+
+ return (bhnd_pmu_attach(dev, r));
+}
+
+static device_method_t bhnd_pmu_chipc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, bhnd_pmu_chipc_probe),
+ DEVMETHOD(device_attach, bhnd_pmu_chipc_attach),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(bhnd_pmu, bhnd_pmu_chipc_driver, bhnd_pmu_chipc_methods,
+ sizeof(struct bhnd_pmu_softc), bhnd_pmu_driver);
+EARLY_DRIVER_MODULE(bhnd_pmu_chipc, bhnd_chipc, bhnd_pmu_chipc_driver,
+ bhnd_pmu_devclass, NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
+
+MODULE_DEPEND(bhnd_pmu_chipc, bhnd, 1, 1, 1);
+MODULE_VERSION(bhnd_pmu_chipc, 1);
diff --git a/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c b/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c
index 520842cd2ce0..c3299f51de95 100644
--- a/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c
+++ b/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c
@@ -46,10 +46,9 @@ __FBSDID("$FreeBSD$");
#include <dev/bhnd/nvram/bhnd_nvram.h>
#include <dev/bhnd/nvram/bhnd_spromvar.h>
-#include "bhnd_nvram_if.h"
+#include <dev/bhnd/cores/chipc/chipc.h>
-#include "chipcvar.h"
-#include "chipc_private.h"
+#include "bhnd_nvram_if.h"
#define CHIPC_VALID_SPROM_SRC(_src) \
((_src) == BHND_NVRAM_SRC_SPROM || (_src) == BHND_NVRAM_SRC_OTP)
diff --git a/sys/dev/bhnd/cores/chipc/chipc.c b/sys/dev/bhnd/cores/chipc/chipc.c
index d2e9f22bc790..b57ceb4d6779 100644
--- a/sys/dev/bhnd/cores/chipc/chipc.c
+++ b/sys/dev/bhnd/cores/chipc/chipc.c
@@ -110,25 +110,27 @@ static struct bhnd_device_quirk chipc_quirks[] = {
// FIXME: IRQ shouldn't be hard-coded
#define CHIPC_MIPS_IRQ 2
-static int chipc_add_children(struct chipc_softc *sc);
+static int chipc_add_children(struct chipc_softc *sc);
-static bhnd_nvram_src chipc_find_nvram_src(struct chipc_softc *sc,
- struct chipc_caps *caps);
-static int chipc_read_caps(struct chipc_softc *sc,
- struct chipc_caps *caps);
+static bhnd_nvram_src chipc_find_nvram_src(struct chipc_softc *sc,
+ struct chipc_caps *caps);
+static int chipc_read_caps(struct chipc_softc *sc,
+ struct chipc_caps *caps);
-static bool chipc_should_enable_sprom(
- struct chipc_softc *sc);
+static bool chipc_should_enable_muxed_sprom(
+ struct chipc_softc *sc);
+static int chipc_enable_otp_power(struct chipc_softc *sc);
+static void chipc_disable_otp_power(struct chipc_softc *sc);
+static int chipc_enable_sprom_pins(struct chipc_softc *sc);
+static void chipc_disable_sprom_pins(struct chipc_softc *sc);
-static int chipc_try_activate_resource(
- struct chipc_softc *sc, device_t child,
- int type, int rid, struct resource *r,
- bool req_direct);
+static int chipc_try_activate_resource(struct chipc_softc *sc,
+ device_t child, int type, int rid,
+ struct resource *r, bool req_direct);
-static int chipc_init_rman(struct chipc_softc *sc);
-static void chipc_free_rman(struct chipc_softc *sc);
-static struct rman *chipc_get_rman(struct chipc_softc *sc,
- int type);
+static int chipc_init_rman(struct chipc_softc *sc);
+static void chipc_free_rman(struct chipc_softc *sc);
+static struct rman *chipc_get_rman(struct chipc_softc *sc, int type);
/* quirk and capability flag convenience macros */
#define CHIPC_QUIRK(_sc, _name) \
@@ -266,40 +268,19 @@ chipc_add_children(struct chipc_softc *sc)
return (error);
}
-#ifdef notyet
/*
- * PMU/SLOWCLK/INSTACLK
+ * PMU/PWR_CTRL
*
- * On AOB ("Always on Bus") devices, a PMU core (if it exists) is
- * enumerated directly by the bhnd(4) bus -- not chipc.
- *
- * Otherwise, we always add a PMU child device, and let the
- * chipc bhnd_pmu drivers probe for it. If the core supports an
- * earlier non-PMU clock/power register interface, one of the instaclk,
- * powerctl, or null bhnd_pmu drivers will claim the device.
+ * 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.aob || (sc->caps.aob && !sc->caps.pmu)) {
+ if (sc->caps.pwr_ctrl || (sc->caps.pmu && !sc->caps.aob)) {
child = BUS_ADD_CHILD(sc->dev, 0, "bhnd_pmu", -1);
if (child == NULL) {
device_printf(sc->dev, "failed to add pmu\n");
return (ENXIO);
}
-
- /* Associate the applicable register block */
- error = 0;
- if (sc->caps.pmu) {
- error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0,
- CHIPC_PMU, CHIPC_PMU_SIZE, 0, 0);
- } else if (sc->caps.power_control) {
- error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0,
- CHIPC_PWRCTL, CHIPC_PWRCTL_SIZE, 0, 0);
- }
-
- if (error)
- return (error);
-
}
-#endif /* notyet */
/* All remaining devices are SoC-only */
if (bhnd_get_attach_type(sc->dev) != BHND_ATTACH_NATIVE)
@@ -422,7 +403,7 @@ chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps)
caps->uart_clock = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_UCLKSEL);
caps->extbus_type = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_EXTBUS);
- caps->power_control = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PWR_CTL);
+ caps->pwr_ctrl = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PWR_CTL);
caps->jtag_master = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_JTAGP);
caps->pll_type = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_PLL);
@@ -1089,7 +1070,7 @@ chipc_deactivate_resource(device_t dev, device_t child, int type,
* @param sc chipc driver state.
*/
static bool
-chipc_should_enable_sprom(struct chipc_softc *sc)
+chipc_should_enable_muxed_sprom(struct chipc_softc *sc)
{
device_t *devs;
device_t hostb;
@@ -1098,17 +1079,19 @@ chipc_should_enable_sprom(struct chipc_softc *sc)
int error;
bool result;
- mtx_assert(&Giant, MA_OWNED); /* for newbus */
-
/* Nothing to do? */
if (!CHIPC_QUIRK(sc, MUX_SPROM))
return (true);
+ mtx_lock(&Giant); /* for newbus */
+
parent = device_get_parent(sc->dev);
hostb = bhnd_find_hostb_device(parent);
- if ((error = device_get_children(parent, &devs, &devcount)))
+ if ((error = device_get_children(parent, &devs, &devcount))) {
+ mtx_unlock(&Giant);
return (false);
+ }
/* Reject any active devices other than ChipCommon, or the
* host bridge (if any). */
@@ -1129,42 +1112,112 @@ chipc_should_enable_sprom(struct chipc_softc *sc)
}
free(devs, M_TEMP);
+ mtx_unlock(&Giant);
return (result);
}
+static int
+chipc_enable_sprom(device_t dev)
+{
+ struct chipc_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ CHIPC_LOCK(sc);
+
+ /* Already enabled? */
+ if (sc->sprom_refcnt >= 1) {
+ sc->sprom_refcnt++;
+ CHIPC_UNLOCK(sc);
+
+ return (0);
+ }
+
+ switch (sc->caps.nvram_src) {
+ case BHND_NVRAM_SRC_SPROM:
+ error = chipc_enable_sprom_pins(sc);
+ break;
+ case BHND_NVRAM_SRC_OTP:
+ error = chipc_enable_otp_power(sc);
+ break;
+ default:
+ error = 0;
+ break;
+ }
+
+ /* Bump the reference count */
+ if (error == 0)
+ sc->sprom_refcnt++;
+
+ CHIPC_UNLOCK(sc);
+ return (error);
+}
+
+static void
+chipc_disable_sprom(device_t dev)
+{
+ struct chipc_softc *sc;
+
+ sc = device_get_softc(dev);
+ CHIPC_LOCK(sc);
+
+ /* Check reference count, skip disable if in-use. */
+ KASSERT(sc->sprom_refcnt > 0, ("sprom refcnt overrelease"));
+ sc->sprom_refcnt--;
+ if (sc->sprom_refcnt > 0) {
+ CHIPC_UNLOCK(sc);
+ return;
+ }
+
+ switch (sc->caps.nvram_src) {
+ case BHND_NVRAM_SRC_SPROM:
+ chipc_disable_sprom_pins(sc);
+ break;
+ case BHND_NVRAM_SRC_OTP:
+ chipc_disable_otp_power(sc);
+ break;
+ default:
+ break;
+ }
+
+
+ CHIPC_UNLOCK(sc);
+}
+
+static int
+chipc_enable_otp_power(struct chipc_softc *sc)
+{
+ // TODO: Enable OTP resource via PMU, and wait up to 100 usec for
+ // OTPS_READY to be set in `optstatus`.
+ return (0);
+}
+
+static void
+chipc_disable_otp_power(struct chipc_softc *sc)
+{
+ // TODO: Disable OTP resource via PMU
+}
+
/**
* If required by this device, enable access to the SPROM.
*
* @param sc chipc driver state.
*/
static int
-chipc_enable_sprom_pins(device_t dev)
+chipc_enable_sprom_pins(struct chipc_softc *sc)
{
- struct chipc_softc *sc;
uint32_t cctrl;
- int error;
- sc = device_get_softc(dev);
+ CHIPC_LOCK_ASSERT(sc, MA_OWNED);
+ KASSERT(sc->sprom_refcnt == 0, ("sprom pins already enabled"));
/* Nothing to do? */
if (!CHIPC_QUIRK(sc, MUX_SPROM))
return (0);
- /* Make sure we're holding Giant for newbus */
- mtx_lock(&Giant);
- CHIPC_LOCK(sc);
-
- /* Already enabled? */
- if (sc->sprom_refcnt >= 1) {
- error = 0;
- goto finished;
- }
-
/* Check whether bus is busy */
- if (!chipc_should_enable_sprom(sc)) {
- error = EBUSY;
- goto finished;
- }
+ if (!chipc_should_enable_muxed_sprom(sc))
+ return (EBUSY);
cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
@@ -1179,8 +1232,7 @@ chipc_enable_sprom_pins(device_t dev)
cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN2;
bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
- error = 0;
- goto finished;
+ return (0);
}
/* 4360 devices */
@@ -1190,17 +1242,7 @@ chipc_enable_sprom_pins(device_t dev)
/* Refuse to proceed on unsupported devices with muxed SPROM pins */
device_printf(sc->dev, "muxed sprom lines on unrecognized device\n");
- error = ENXIO;
-
-finished:
- /* Bump the reference count */
- if (error == 0)
- sc->sprom_refcnt++;
-
- CHIPC_UNLOCK(sc);
- mtx_unlock(&Giant);
-
- return (error);
+ return (ENXIO);
}
/**
@@ -1210,24 +1252,17 @@ finished:
* @param sc chipc driver state.
*/
static void
-chipc_disable_sprom_pins(device_t dev)
+chipc_disable_sprom_pins(struct chipc_softc *sc)
{
- struct chipc_softc *sc;
uint32_t cctrl;
- sc = device_get_softc(dev);
-
/* Nothing to do? */
if (!CHIPC_QUIRK(sc, MUX_SPROM))
return;
- CHIPC_LOCK(sc);
-
- /* Check reference count, skip disable if in-use. */
- KASSERT(sc->sprom_refcnt > 0, ("sprom refcnt overrelease"));
- sc->sprom_refcnt--;
- if (sc->sprom_refcnt > 0)
- goto finished;
+ CHIPC_LOCK_ASSERT(sc, MA_OWNED);
+ KASSERT(sc->sprom_refcnt != 0, ("sprom pins already disabled"));
+ KASSERT(sc->sprom_refcnt == 1, ("sprom pins in use"));
cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
@@ -1242,16 +1277,20 @@ chipc_disable_sprom_pins(device_t dev)
cctrl |= CHIPC_CCTRL4331_EXTPA_EN2;
bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
- goto finished;
+ return;
}
/* 4360 devices */
if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) {
/* Unimplemented */
}
+}
-finished:
- CHIPC_UNLOCK(sc);
+static uint32_t
+chipc_read_chipst(device_t dev)
+{
+ struct chipc_softc *sc = device_get_softc(dev);
+ return (bhnd_bus_read_4(sc->core, CHIPC_CHIPST));
}
static void
@@ -1317,16 +1356,17 @@ static device_method_t chipc_methods[] = {
DEVMETHOD(bhnd_bus_activate_resource, chipc_activate_bhnd_resource),
/* ChipCommon interface */
+ DEVMETHOD(bhnd_chipc_read_chipst, chipc_read_chipst),
DEVMETHOD(bhnd_chipc_write_chipctrl, chipc_write_chipctrl),
- DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom_pins),
- DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom_pins),
+ DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom),
+ DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom),
DEVMETHOD(bhnd_chipc_get_caps, chipc_get_caps),
DEVMETHOD_END
};
-DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc));
-EARLY_DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0,
+DEFINE_CLASS_0(bhnd_chipc, bhnd_chipc_driver, chipc_methods, sizeof(struct chipc_softc));
+EARLY_DRIVER_MODULE(bhnd_chipc, bhnd, bhnd_chipc_driver, bhnd_chipc_devclass, 0, 0,
BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
MODULE_DEPEND(bhnd_chipc, bhnd, 1, 1, 1);
MODULE_VERSION(bhnd_chipc, 1);
diff --git a/sys/dev/bhnd/cores/chipc/chipc.h b/sys/dev/bhnd/cores/chipc/chipc.h
index 1036e67bf3ea..d42d4892f633 100644
--- a/sys/dev/bhnd/cores/chipc/chipc.h
+++ b/sys/dev/bhnd/cores/chipc/chipc.h
@@ -37,4 +37,60 @@
#include "bhnd_chipc_if.h"
+/**
+ * Supported ChipCommon flash types.
+ */
+typedef enum {
+ CHIPC_FLASH_NONE = 0, /**< No flash, or a type unrecognized
+ by the ChipCommon driver */
+ CHIPC_PFLASH_CFI = 1, /**< CFI-compatible parallel flash */
+ CHIPC_SFLASH_ST = 2, /**< ST serial flash */
+ CHIPC_SFLASH_AT = 3, /**< Atmel serial flash */
+ CHIPC_QSFLASH_ST = 4, /**< ST quad-SPI flash */
+ CHIPC_QSFLASH_AT = 5, /**< Atmel quad-SPI flash */
+ CHIPC_NFLASH = 6, /**< NAND flash */
+ CHIPC_NFLASH_4706 = 7 /**< BCM4706 NAND flash */
+} chipc_flash;
+
+/**
+ * ChipCommon capability flags;
+ */
+struct chipc_caps {
+ uint8_t num_uarts; /**< Number of attached UARTS (1-3) */
+ bool mipseb; /**< MIPS is big-endian */
+ uint8_t uart_clock; /**< UART clock source (see CHIPC_CAP_UCLKSEL_*) */
+ uint8_t uart_gpio; /**< UARTs own GPIO pins 12-15 */
+
+ uint8_t extbus_type; /**< ExtBus type (CHIPC_CAP_EXTBUS_*) */
+
+ chipc_flash flash_type; /**< flash type */
+ uint8_t cfi_width; /**< CFI bus width, 0 if unknown or CFI
+ not present */
+
+ bhnd_nvram_src nvram_src; /**< identified NVRAM source */
+ bus_size_t sprom_offset; /**< Offset to SPROM data within
+ SPROM/OTP, 0 if unknown or not
+ present */
+ uint8_t otp_size; /**< OTP (row?) size, 0 if not present */
+
+ uint8_t pll_type; /**< PLL type */
+ bool pwr_ctrl; /**< Power/clock control available */
+ bool jtag_master; /**< JTAG Master present */
+ bool boot_rom; /**< Internal boot ROM is active */
+ uint8_t backplane_64; /**< Backplane supports 64-bit addressing.
+ Note that this does not gaurantee
+ the CPU itself supports 64-bit
+ addressing. */
+ bool pmu; /**< PMU is present. */
+ bool eci; /**< ECI (enhanced coexistence inteface) is present. */
+ bool seci; /**< SECI (serial ECI) is present */
+ bool sprom; /**< SPROM is present */
+ bool gsio; /**< GSIO (SPI/I2C) present */
+ bool aob; /**< AOB (always on bus) present.
+ If set, PMU and GCI registers are
+ not accessible via ChipCommon,
+ and are instead accessible via
+ dedicated cores on the bhnd bus */
+};
+
#endif /* _BHND_CORES_CHIPC_CHIPC_H_ */
diff --git a/sys/dev/bhnd/cores/chipc/chipc_subr.c b/sys/dev/bhnd/cores/chipc/chipc_subr.c
index 9b27ba3890a1..e7a8b0df504e 100644
--- a/sys/dev/bhnd/cores/chipc/chipc_subr.c
+++ b/sys/dev/bhnd/cores/chipc/chipc_subr.c
@@ -248,8 +248,8 @@ chipc_print_caps(device_t dev, struct chipc_caps *caps)
CC_TFS(sprom), CC_TFS(otp_size));
device_printf(dev, "CFIsz: 0x%02x | OTPsz: 0x%02x\n",
caps->cfi_width, caps->otp_size);
- device_printf(dev, "ExtBus: 0x%02x | PwCtl: %s\n",
- caps->extbus_type, CC_TFS(power_control));
+ device_printf(dev, "ExtBus: 0x%02x | PwrCtrl: %s\n",
+ caps->extbus_type, CC_TFS(pwr_ctrl));
device_printf(dev, "PLL: 0x%02x | JTAGM: %s\n",
caps->pll_type, CC_TFS(jtag_master));
device_printf(dev, "PMU: %-3s | ECI: %s\n",
diff --git a/sys/dev/bhnd/cores/chipc/chipcreg.h b/sys/dev/bhnd/cores/chipc/chipcreg.h
index ee7dff2276a1..ccbc97e05081 100644
--- a/sys/dev/bhnd/cores/chipc/chipcreg.h
+++ b/sys/dev/bhnd/cores/chipc/chipcreg.h
@@ -100,24 +100,25 @@
#define CHIPC_GPIOTIMERVAL 0x88 /**< gpio-based LED duty cycle (rev >= 16) */
#define CHIPC_GPIOTIMEROUTMASK 0x8C
-/* clock control block */
+/* clock control registers (non-PMU devices) */
#define CHIPC_CLKC_N 0x90
#define CHIPC_CLKC_SB 0x94 /* m0 (backplane) */
#define CHIPC_CLKC_PCI 0x98 /* m1 */
#define CHIPC_CLKC_M2 0x9C /* mii/uart/mipsref */
#define CHIPC_CLKC_M3 0xA0 /* cpu */
#define CHIPC_CLKDIV 0xA4 /* rev >= 3 */
+
#define CHIPC_GPIODEBUGSEL 0xA8 /* rev >= 28 */
#define CHIPC_CAPABILITIES_EXT 0xAC
-/* pll delay (registers rev >= 4) */
-#define CHIPC_PLL_ON_DELAY 0xB0
-#define CHIPC_PLL_FREFSEL_DELAY 0xB4
-#define CHIPC_PLL_SLOWCLK_CTL 0xB8 /* revs 6-9 */
-
-/* "instaclock" registers */
-#define CHIPC_SYS_CLK_CTL 0xC0 /* rev >= 10 */
-#define CHIPC_SYS_CLKSTATESTRETCH 0xC4 /* rev >= 10 */
+/* pll/slowclk clock control registers (rev >= 4) */
+#define CHIPC_PLL_ON_DELAY 0xB0 /* rev >= 4 */
+#define CHIPC_PLL_FREFSEL_DELAY 0xB4 /* rev >= 4 */
+#define CHIPC_PLL_SLOWCLK_CTL 0xB8 /* "slowclock" (rev 6-9) */
+
+ /* "instaclock" clock control registers */
+#define CHIPC_SYS_CLK_CTL 0xC0 /* "instaclock" (rev >= 10) */
+#define CHIPC_SYS_CLK_ST_STRETCH 0xC4 /* state strech (?) rev >= 10 */
/* indirect backplane access (rev >= 10) */
#define CHIPC_BP_ADDRLOW 0xD0
@@ -135,7 +136,7 @@
#define CHIPC_EROMPTR 0xFC /**< 32-bit EROM base address
* on BCMA devices */
-
+
/* ExtBus control registers (rev >= 3) */
#define CHIPC_PCMCIA_CFG 0x100
#define CHIPC_PCMCIA_MEMWAIT 0x104
@@ -188,38 +189,10 @@
#define CHIPC_UART_MAX 3 /**< max UART blocks */
#define CHIPC_UART(_n) (CHIPC_UART_BASE + (CHIPC_UART_SIZE*_n))
-/* PMU registers (rev >= 20) */
+/* PMU register block (rev >= 20) */
#define CHIPC_PMU_BASE 0x600
#define CHIPC_PMU_SIZE 0x70
-#define CHIPC_PMU_CTRL 0x600
-#define CHIPC_PMU_CAP 0x604
-#define CHIPC_PMU_ST 0x608
-#define CHIPC_PMU_RES_STATE 0x60c
-#define CHIPC_PMU_RES_PENDING 0x610
-#define CHIPC_PMU_TIMER 0x614
-#define CHIPC_PMU_MIN_RES_MASK 0x618
-#define CHIPC_PMU_MAX_RES_MASK 0x61c
-#define CHIPC_PMU_RES_TABLE_SEL 0x620
-#define CHIPC_PMU_RES_DEP_MASK 0x624
-#define CHIPC_PMU_RES_UPDN_TIMER 0x628
-#define CHIPC_PMU_RES_TIMER 0x62C
-#define CHIPC_PMU_CLKSTRETCH 0x630
-#define CHIPC_PMU_WATCHDOG 0x634
-#define CHIPC_PMU_GPIOSEL 0x638 /* pmu rev >= 1 ? */
-#define CHIPC_PMU_GPIOEN 0x63C /* pmu rev >= 1 ? */
-#define CHIPC_PMU_RES_REQ_TIMER_SEL 0x640
-#define CHIPC_PMU_RES_REQ_TIMER 0x644
-#define CHIPC_PMU_RES_REQ_MASK 0x648
-#define CHIPC_CHIPCTL_ADDR 0x650
-#define CHIPC_CHIPCTL_DATA 0x654
-#define CHIPC_PMU_REG_CONTROL_ADDR 0x658
-#define CHIPC_PMU_REG_CONTROL_DATA 0x65C
-#define CHIPC_PMU_PLL_CONTROL_ADDR 0x660
-#define CHIPC_PMU_PLL_CONTROL_DATA 0x664
-#define CHIPC_PMU_STRAPOPT 0x668 /* chipc rev >= 28 */
-#define CHIPC_PMU_XTALFREQ 0x66C /* pmu rev >= 10 */
-
#define CHIPC_SPROM_OTP 0x800 /* SPROM/OTP address space */
#define CHIPC_SPROM_OTP_SIZE 0x400
@@ -257,7 +230,7 @@
#define CHIPC_CAP_PFLASH 0x7 /* Parallel flash */
#define CHIPC_CAP_PLL_MASK 0x00038000 /* Type of PLL */
#define CHIPC_CAP_PLL_SHIFT 15
-#define CHIPC_CAP_PWR_CTL 0x00040000 /* Power control */
+#define CHIPC_CAP_PWR_CTL 0x00040000 /* Power/clock control */
#define CHIPC_CAP_OTP_SIZE_MASK 0x00380000 /* OTP Size (0 = none) */
#define CHIPC_CAP_OTP_SIZE_SHIFT 19 /* OTP Size shift */
#define CHIPC_CAP_OTP_SIZE_BASE 5 /* OTP Size base */
@@ -305,23 +278,31 @@ enum {
#define CHIPC_CST_SPROM_OTP_SEL_R23_SHIFT 6
/* PLL type */
-#define CHIPC_PLL_NONE 0x00000000
-#define CHIPC_PLL_TYPE1 0x00010000 /* 48MHz base, 3 dividers */
-#define CHIPC_PLL_TYPE2 0x00020000 /* 48MHz, 4 dividers */
-#define CHIPC_PLL_TYPE3 0x00030000 /* 25MHz, 2 dividers */
-#define CHIPC_PLL_TYPE4 0x00008000 /* 48MHz, 4 dividers */
-#define CHIPC_PLL_TYPE5 0x00018000 /* 25MHz, 4 dividers */
-#define CHIPC_PLL_TYPE6 0x00028000 /* 100/200 or 120/240 only */
-#define CHIPC_PLL_TYPE7 0x00038000 /* 25MHz, 4 dividers */
-
-/* ILP clock */
-#define CHIPC_ILP_CLOCK 32000
-
-/* ALP clock on pre-PMU chips */
-#define CHIPC_ALP_CLOCK 20000000
-
-/* HT clock */
-#define CHIPC_HT_CLOCK 80000000
+#define CHIPC_PLL_NONE 0x00
+#define CHIPC_PLL_TYPE1 0x10 /* 48MHz base, 3 dividers */
+#define CHIPC_PLL_TYPE2 0x20 /* 48MHz, 4 dividers */
+#define CHIPC_PLL_TYPE3 0x30 /* 25MHz, 2 dividers */
+#define CHIPC_PLL_TYPE4 0x08 /* 48MHz, 4 dividers */
+#define CHIPC_PLL_TYPE5 0x18 /* 25MHz, 4 dividers */
+#define CHIPC_PLL_TYPE6 0x28 /* 100/200 or 120/240 only */
+#define CHIPC_PLL_TYPE7 0x38 /* 25MHz, 4 dividers */
+
+/* dynamic clock control defines */
+#define CHIPC_LPOMINFREQ 25000 /* low power oscillator min */
+#define CHIPC_LPOMAXFREQ 43000 /* low power oscillator max */
+#define CHIPC_XTALMINFREQ 19800000 /* 20 MHz - 1% */
+#define CHIPC_XTALMAXFREQ 20200000 /* 20 MHz + 1% */
+#define CHIPC_PCIMINFREQ 25000000 /* 25 MHz */
+#define CHIPC_PCIMAXFREQ 34000000 /* 33 MHz + fudge */
+
+#define CHIPC_ILP_DIV_5MHZ 0 /* ILP = 5 MHz */
+#define CHIPC_ILP_DIV_1MHZ 4 /* ILP = 1 MHz */
+
+/* Power Control Defines */
+#define CHIPC_PLL_DELAY 150 /* us pll on delay */
+#define CHIPC_FREF_DELAY 200 /* us fref change delay */
+#define CHIPC_MIN_SLOW_CLK 32 /* us Slow clock period */
+#define CHIPC_XTAL_ON_DELAY 1000 /* us crystal power-on delay */
/* corecontrol */
#define CHIPC_UARTCLKO 0x00000001 /* Drive UART with internal clock */
@@ -577,27 +558,12 @@ enum {
#define CHIPC_SRC_SIZE_SHIFT 1
#define CHIPC_SRC_PRESENT 0x00000001
-/* Fields in pmucontrol */
-#define CHIPC_PCTL_ILP_DIV_MASK 0xffff0000
-#define CHIPC_PCTL_ILP_DIV_SHIFT 16
-#define CHIPC_PCTL_PLL_PLLCTL_UPD 0x00000400 /* rev 2 */
-#define CHIPC_PCTL_NOILP_ON_WAIT 0x00000200 /* rev 1 */
-#define CHIPC_PCTL_HT_REQ_EN 0x00000100
-#define CHIPC_PCTL_ALP_REQ_EN 0x00000080
-#define CHIPC_PCTL_XTALFREQ_MASK 0x0000007c
-#define CHIPC_PCTL_XTALFREQ_SHIFT 2
-#define CHIPC_PCTL_ILP_DIV_EN 0x00000002
-#define CHIPC_PCTL_LPO_SEL 0x00000001
-
-/* Fields in clkstretch */
-#define CHIPC_CSTRETCH_HT 0xffff0000
-#define CHIPC_CSTRETCH_ALP 0x0000ffff
-
/* gpiotimerval */
#define CHIPC_GPIO_ONTIME_SHIFT 16
/* clockcontrol_n */
#define CHIPC_CN_N1_MASK 0x3f /* n1 control */
+#define CHIPC_CN_N1_SHIFT 0
#define CHIPC_CN_N2_MASK 0x3f00 /* n2 control */
#define CHIPC_CN_N2_SHIFT 8
#define CHIPC_CN_PLLC_MASK 0xf0000 /* pll control */
@@ -605,6 +571,7 @@ enum {
/* clockcontrol_sb/pci/uart */
#define CHIPC_M1_MASK 0x3f /* m1 control */
+#define CHIPC_M1_SHIFT 0
#define CHIPC_M2_MASK 0x3f00 /* m2 control */
#define CHIPC_M2_SHIFT 8
#define CHIPC_M3_MASK 0x3f0000 /* m3 control */
@@ -788,345 +755,6 @@ enum {
#define CHIPC_UART_IER_ETBEI 2 /* enable transmitter holding register empty interrupt */
#define CHIPC_UART_IER_ERBFI 1 /* enable data available interrupt */
-/* pmustatus */
-#define CHIPC_PST_EXTLPOAVAIL 0x0100
-#define CHIPC_PST_WDRESET 0x0080
-#define CHIPC_PST_INTPEND 0x0040
-#define CHIPC_PST_SBCLKST 0x0030
-#define CHIPC_PST_SBCLKST_ILP 0x0010
-#define CHIPC_PST_SBCLKST_ALP 0x0020
-#define CHIPC_PST_SBCLKST_HT 0x0030
-#define CHIPC_PST_ALPAVAIL 0x0008
-#define CHIPC_PST_HTAVAIL 0x0004
-#define CHIPC_PST_RESINIT 0x0003
-
-/* pmucapabilities */
-#define CHIPC_PCAP_REV_MASK 0x000000ff
-#define CHIPC_PCAP_RC_MASK 0x00001f00
-#define CHIPC_PCAP_RC_SHIFT 8
-#define CHIPC_PCAP_TC_MASK 0x0001e000
-#define CHIPC_PCAP_TC_SHIFT 13
-#define CHIPC_PCAP_PC_MASK 0x001e0000
-#define CHIPC_PCAP_PC_SHIFT 17
-#define CHIPC_PCAP_VC_MASK 0x01e00000
-#define CHIPC_PCAP_VC_SHIFT 21
-#define CHIPC_PCAP_CC_MASK 0x1e000000
-#define CHIPC_PCAP_CC_SHIFT 25
-#define CHIPC_PCAP5_PC_MASK 0x003e0000 /* PMU corerev >= 5 */
-#define CHIPC_PCAP5_PC_SHIFT 17
-#define CHIPC_PCAP5_VC_MASK 0x07c00000
-#define CHIPC_PCAP5_VC_SHIFT 22
-#define CHIPC_PCAP5_CC_MASK 0xf8000000
-#define CHIPC_PCAP5_CC_SHIFT 27
-
-/* PMU Resource Request Timer registers */
-/* This is based on PmuRev0 */
-#define CHIPC_PRRT_TIME_MASK 0x03ff
-#define CHIPC_PRRT_INTEN 0x0400
-#define CHIPC_PRRT_REQ_ACTIVE 0x0800
-#define CHIPC_PRRT_ALP_REQ 0x1000
-#define CHIPC_PRRT_HT_REQ 0x2000
-
-/* PMU resource bit position */
-#define CHIPC_PMURES_BIT(bit) (1 << (bit))
-
-/* PMU resource number limit */
-#define CHIPC_PMURES_MAX_RESNUM 30
-
-/* PMU chip control0 register */
-#define CHIPC_PMU_CHIPCTL0 0
-
-/* PMU chip control1 register */
-#define CHIPC_PMU_CHIPCTL1 1
-#define CHIPC_PMU_CC1_RXC_DLL_BYPASS 0x00010000
-
-#define CHIPC_PMU_CC1_IF_TYPE_MASK 0x00000030
-#define CHIPC_PMU_CC1_IF_TYPE_RMII 0x00000000
-#define CHIPC_PMU_CC1_IF_TYPE_MII 0x00000010
-#define CHIPC_PMU_CC1_IF_TYPE_RGMII 0x00000020
-
-#define CHIPC_PMU_CC1_SW_TYPE_MASK 0x000000c0
-#define CHIPC_PMU_CC1_SW_TYPE_EPHY 0x00000000
-#define CHIPC_PMU_CC1_SW_TYPE_EPHYMII 0x00000040
-#define CHIPC_PMU_CC1_SW_TYPE_EPHYRMII 0x00000080
-#define CHIPC_PMU_CC1_SW_TYPE_RGMII 0x000000c0
-
-/* PMU corerev and chip specific PLL controls.
- * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary number
- * to differentiate different PLLs controlled by the same PMU rev.
- */
-/* pllcontrol registers */
-/* PDIV, div_phy, div_arm, div_adc, dith_sel, ioff, kpd_scale, lsb_sel, mash_sel, lf_c & lf_r */
-#define CHIPC_PMU0_PLL0_PLLCTL0 0
-#define CHIPC_PMU0_PLL0_PC0_PDIV_MASK 1
-#define CHIPC_PMU0_PLL0_PC0_PDIV_FREQ 25000
-#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038
-#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_SHIFT 3
-#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_BASE 8
-
-/* PC0_DIV_ARM for PLLOUT_ARM */
-#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_110MHZ 0
-#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1
-#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_88MHZ 2
-#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 /* Default */
-#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4
-#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5
-#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6
-#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7
-
-/* Wildcard base, stop_mod, en_lf_tp, en_cal & lf_r2 */
-#define CHIPC_PMU0_PLL0_PLLCTL1 1
-#define CHIPC_PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000
-#define CHIPC_PMU0_PLL0_PC1_WILD_INT_SHIFT 28
-#define CHIPC_PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00
-#define CHIPC_PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8
-#define CHIPC_PMU0_PLL0_PC1_STOP_MOD 0x00000040
-
-/* Wildcard base, vco_calvar, vco_swc, vco_var_selref, vso_ical & vco_sel_avdd */
-#define CHIPC_PMU0_PLL0_PLLCTL2 2
-#define CHIPC_PMU0_PLL0_PC2_WILD_INT_MASK 0xf
-#define CHIPC_PMU0_PLL0_PC2_WILD_INT_SHIFT 4
-
-/* pllcontrol registers */
-/* ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>, p1div, p2div, _bypass_sdmod */
-#define CHIPC_PMU1_PLL0_PLLCTL0 0
-#define CHIPC_PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000
-#define CHIPC_PMU1_PLL0_PC0_P1DIV_SHIFT 20
-#define CHIPC_PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000
-#define CHIPC_PMU1_PLL0_PC0_P2DIV_SHIFT 24
-
-/* m<x>div */
-#define CHIPC_PMU1_PLL0_PLLCTL1 1
-#define CHIPC_PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff
-#define CHIPC_PMU1_PLL0_PC1_M1DIV_SHIFT 0
-#define CHIPC_PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00
-#define CHIPC_PMU1_PLL0_PC1_M2DIV_SHIFT 8
-#define CHIPC_PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000
-#define CHIPC_PMU1_PLL0_PC1_M3DIV_SHIFT 16
-#define CHIPC_PMU1_PLL0_PC1_M4DIV_MASK 0xff000000
-#define CHIPC_PMU1_PLL0_PC1_M4DIV_SHIFT 24
-
-#define CHIPC_DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8
-#define CHIPC_DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT)
-#define CHIPC_DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT)
-
-/* m<x>div, ndiv_dither_mfb, ndiv_mode, ndiv_int */
-#define CHIPC_PMU1_PLL0_PLLCTL2 2
-#define CHIPC_PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff
-#define CHIPC_PMU1_PLL0_PC2_M5DIV_SHIFT 0
-#define CHIPC_PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00
-#define CHIPC_PMU1_PLL0_PC2_M6DIV_SHIFT 8
-#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000
-#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17
-#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_MASH 1
-#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_MFB 2 /* recommended for 4319 */
-#define CHIPC_PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000
-#define CHIPC_PMU1_PLL0_PC2_NDIV_INT_SHIFT 20
-
-/* ndiv_frac */
-#define CHIPC_PMU1_PLL0_PLLCTL3 3
-#define CHIPC_PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff
-#define CHIPC_PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0
-
-/* pll_ctrl */
-#define CHIPC_PMU1_PLL0_PLLCTL4 4
-
-/* pll_ctrl, vco_rng, clkdrive_ch<x> */
-#define CHIPC_PMU1_PLL0_PLLCTL5 5
-#define CHIPC_PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00
-#define CHIPC_PMU1_PLL0_PC5_CLK_DRV_SHIFT 8
-
-/* PMU rev 2 control words */
-#define CHIPC_PMU2_PHY_PLL_PLLCTL 4
-#define CHIPC_PMU2_SI_PLL_PLLCTL 10
-
-/* PMU rev 2 */
-/* pllcontrol registers */
-/* ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>, p1div, p2div, _bypass_sdmod */
-#define CHIPC_PMU2_PLL_PLLCTL0 0
-#define CHIPC_PMU2_PLL_PC0_P1DIV_MASK 0x00f00000
-#define CHIPC_PMU2_PLL_PC0_P1DIV_SHIFT 20
-#define CHIPC_PMU2_PLL_PC0_P2DIV_MASK 0x0f000000
-#define CHIPC_PMU2_PLL_PC0_P2DIV_SHIFT 24
-
-/* m<x>div */
-#define CHIPC_PMU2_PLL_PLLCTL1 1
-#define CHIPC_PMU2_PLL_PC1_M1DIV_MASK 0x000000ff
-#define CHIPC_PMU2_PLL_PC1_M1DIV_SHIFT 0
-#define CHIPC_PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00
-#define CHIPC_PMU2_PLL_PC1_M2DIV_SHIFT 8
-#define CHIPC_PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000
-#define CHIPC_PMU2_PLL_PC1_M3DIV_SHIFT 16
-#define CHIPC_PMU2_PLL_PC1_M4DIV_MASK 0xff000000
-#define CHIPC_PMU2_PLL_PC1_M4DIV_SHIFT 24
-
-/* m<x>div, ndiv_dither_mfb, ndiv_mode, ndiv_int */
-#define CHIPC_PMU2_PLL_PLLCTL2 2
-#define CHIPC_PMU2_PLL_PC2_M5DIV_MASK 0x000000ff
-#define CHIPC_PMU2_PLL_PC2_M5DIV_SHIFT 0
-#define CHIPC_PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00
-#define CHIPC_PMU2_PLL_PC2_M6DIV_SHIFT 8
-#define CHIPC_PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000
-#define CHIPC_PMU2_PLL_PC2_NDIV_MODE_SHIFT 17
-#define CHIPC_PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000
-#define CHIPC_PMU2_PLL_PC2_NDIV_INT_SHIFT 20
-
-/* ndiv_frac */
-#define CHIPC_PMU2_PLL_PLLCTL3 3
-#define CHIPC_PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff
-#define CHIPC_PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0
-
-/* pll_ctrl */
-#define CHIPC_PMU2_PLL_PLLCTL4 4
-
-/* pll_ctrl, vco_rng, clkdrive_ch<x> */
-#define CHIPC_PMU2_PLL_PLLCTL5 5
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000
-#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28
-
-/* PMU rev 5 (& 6) */
-#define CHIPC_PMU5_PLL_P1P2_OFF 0
-#define CHIPC_PMU5_PLL_P1_MASK 0x0f000000
-#define CHIPC_PMU5_PLL_P1_SHIFT 24
-#define CHIPC_PMU5_PLL_P2_MASK 0x00f00000
-#define CHIPC_PMU5_PLL_P2_SHIFT 20
-#define CHIPC_PMU5_PLL_M14_OFF 1
-#define CHIPC_PMU5_PLL_MDIV_MASK 0x000000ff
-#define CHIPC_PMU5_PLL_MDIV_WIDTH 8
-#define CHIPC_PMU5_PLL_NM5_OFF 2
-#define CHIPC_PMU5_PLL_NDIV_MASK 0xfff00000
-#define CHIPC_PMU5_PLL_NDIV_SHIFT 20
-#define CHIPC_PMU5_PLL_NDIV_MODE_MASK 0x000e0000
-#define CHIPC_PMU5_PLL_NDIV_MODE_SHIFT 17
-#define CHIPC_PMU5_PLL_FMAB_OFF 3
-#define CHIPC_PMU5_PLL_MRAT_MASK 0xf0000000
-#define CHIPC_PMU5_PLL_MRAT_SHIFT 28
-#define CHIPC_PMU5_PLL_ABRAT_MASK 0x08000000
-#define CHIPC_PMU5_PLL_ABRAT_SHIFT 27
-#define CHIPC_PMU5_PLL_FDIV_MASK 0x07ffffff
-#define CHIPC_PMU5_PLL_PLLCTL_OFF 4
-#define CHIPC_PMU5_PLL_PCHI_OFF 5
-#define CHIPC_PMU5_PLL_PCHI_MASK 0x0000003f
-
-/* pmu XtalFreqRatio */
-#define CHIPC_PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF
-#define CHIPC_PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000
-#define CHIPC_PMU_XTALFREQ_REG_MEASURE_SHIFT 31
-
-/* Divider allocation in 4716/47162/5356/5357 */
-#define CHIPC_PMU5_MAINPLL_CPU 1
-#define CHIPC_PMU5_MAINPLL_MEM 2
-#define CHIPC_PMU5_MAINPLL_SI 3
-
-#define CHIPC_PMU7_PLL_PLLCTL7 7
-#define CHIPC_PMU7_PLL_PLLCTL8 8
-#define CHIPC_PMU7_PLL_PLLCTL11 11
-
-/* PLL usage in 4716/47162 */
-#define CHIPC_PMU4716_MAINPLL_PLL0 12
-
-/* PLL usage in 5356/5357 */
-#define CHIPC_PMU5356_MAINPLL_PLL0 0
-#define CHIPC_PMU5357_MAINPLL_PLL0 0
-
-/* 4716/47162 resources */
-#define CHIPC_RES4716_PROC_PLL_ON 0x00000040
-#define CHIPC_RES4716_PROC_HT_AVAIL 0x00000080
-
-/* 4716/4717/4718 Chip specific ChipControl register bits */
-#define CHIPC_CCTRL471X_I2S_PINS_ENABLE 0x0080 /* I2S pins off by default, shared with pflash */
-
-/* 5354 resources */
-#define CHIPC_RES5354_EXT_SWITCHER_PWM 0 /* 0x00001 */
-#define CHIPC_RES5354_BB_SWITCHER_PWM 1 /* 0x00002 */
-#define CHIPC_RES5354_BB_SWITCHER_BURST 2 /* 0x00004 */
-#define CHIPC_RES5354_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */
-#define CHIPC_RES5354_ILP_REQUEST 4 /* 0x00010 */
-#define CHIPC_RES5354_RADIO_SWITCHER_PWM 5 /* 0x00020 */
-#define CHIPC_RES5354_RADIO_SWITCHER_BURST 6 /* 0x00040 */
-#define CHIPC_RES5354_ROM_SWITCH 7 /* 0x00080 */
-#define CHIPC_RES5354_PA_REF_LDO 8 /* 0x00100 */
-#define CHIPC_RES5354_RADIO_LDO 9 /* 0x00200 */
-#define CHIPC_RES5354_AFE_LDO 10 /* 0x00400 */
-#define CHIPC_RES5354_PLL_LDO 11 /* 0x00800 */
-#define CHIPC_RES5354_BG_FILTBYP 12 /* 0x01000 */
-#define CHIPC_RES5354_TX_FILTBYP 13 /* 0x02000 */
-#define CHIPC_RES5354_RX_FILTBYP 14 /* 0x04000 */
-#define CHIPC_RES5354_XTAL_PU 15 /* 0x08000 */
-#define CHIPC_RES5354_XTAL_EN 16 /* 0x10000 */
-#define CHIPC_RES5354_BB_PLL_FILTBYP 17 /* 0x20000 */
-#define CHIPC_RES5354_RF_PLL_FILTBYP 18 /* 0x40000 */
-#define CHIPC_RES5354_BB_PLL_PU 19 /* 0x80000 */
-
-/* 5357 Chip specific ChipControl register bits */
-#define CHIPC_CCTRL5357_EXTPA (1<<14) /* extPA in ChipControl 1, bit 14 */
-#define CHIPC_CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in ChipControl 1, bit 15 */
-
-/* 4328 resources */
-#define CHIPC_RES4328_EXT_SWITCHER_PWM 0 /* 0x00001 */
-#define CHIPC_RES4328_BB_SWITCHER_PWM 1 /* 0x00002 */
-#define CHIPC_RES4328_BB_SWITCHER_BURST 2 /* 0x00004 */
-#define CHIPC_RES4328_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */
-#define CHIPC_RES4328_ILP_REQUEST 4 /* 0x00010 */
-#define CHIPC_RES4328_RADIO_SWITCHER_PWM 5 /* 0x00020 */
-#define CHIPC_RES4328_RADIO_SWITCHER_BURST 6 /* 0x00040 */
-#define CHIPC_RES4328_ROM_SWITCH 7 /* 0x00080 */
-#define CHIPC_RES4328_PA_REF_LDO 8 /* 0x00100 */
-#define CHIPC_RES4328_RADIO_LDO 9 /* 0x00200 */
-#define CHIPC_RES4328_AFE_LDO 10 /* 0x00400 */
-#define CHIPC_RES4328_PLL_LDO 11 /* 0x00800 */
-#define CHIPC_RES4328_BG_FILTBYP 12 /* 0x01000 */
-#define CHIPC_RES4328_TX_FILTBYP 13 /* 0x02000 */
-#define CHIPC_RES4328_RX_FILTBYP 14 /* 0x04000 */
-#define CHIPC_RES4328_XTAL_PU 15 /* 0x08000 */
-#define CHIPC_RES4328_XTAL_EN 16 /* 0x10000 */
-#define CHIPC_RES4328_BB_PLL_FILTBYP 17 /* 0x20000 */
-#define CHIPC_RES4328_RF_PLL_FILTBYP 18 /* 0x40000 */
-#define CHIPC_RES4328_BB_PLL_PU 19 /* 0x80000 */
-
-/* 4325 A0/A1 resources */
-#define CHIPC_RES4325_BUCK_BOOST_BURST 0 /* 0x00000001 */
-#define CHIPC_RES4325_CBUCK_BURST 1 /* 0x00000002 */
-#define CHIPC_RES4325_CBUCK_PWM 2 /* 0x00000004 */
-#define CHIPC_RES4325_CLDO_CBUCK_BURST 3 /* 0x00000008 */
-#define CHIPC_RES4325_CLDO_CBUCK_PWM 4 /* 0x00000010 */
-#define CHIPC_RES4325_BUCK_BOOST_PWM 5 /* 0x00000020 */
-#define CHIPC_RES4325_ILP_REQUEST 6 /* 0x00000040 */
-#define CHIPC_RES4325_ABUCK_BURST 7 /* 0x00000080 */
-#define CHIPC_RES4325_ABUCK_PWM 8 /* 0x00000100 */
-#define CHIPC_RES4325_LNLDO1_PU 9 /* 0x00000200 */
-#define CHIPC_RES4325_OTP_PU 10 /* 0x00000400 */
-#define CHIPC_RES4325_LNLDO3_PU 11 /* 0x00000800 */
-#define CHIPC_RES4325_LNLDO4_PU 12 /* 0x00001000 */
-#define CHIPC_RES4325_XTAL_PU 13 /* 0x00002000 */
-#define CHIPC_RES4325_ALP_AVAIL 14 /* 0x00004000 */
-#define CHIPC_RES4325_RX_PWRSW_PU 15 /* 0x00008000 */
-#define CHIPC_RES4325_TX_PWRSW_PU 16 /* 0x00010000 */
-#define CHIPC_RES4325_RFPLL_PWRSW_PU 17 /* 0x00020000 */
-#define CHIPC_RES4325_LOGEN_PWRSW_PU 18 /* 0x00040000 */
-#define CHIPC_RES4325_AFE_PWRSW_PU 19 /* 0x00080000 */
-#define CHIPC_RES4325_BBPLL_PWRSW_PU 20 /* 0x00100000 */
-#define CHIPC_RES4325_HT_AVAIL 21 /* 0x00200000 */
-
-/* 4325 B0/C0 resources */
-#define CHIPC_RES4325B0_CBUCK_LPOM 1 /* 0x00000002 */
-#define CHIPC_RES4325B0_CBUCK_BURST 2 /* 0x00000004 */
-#define CHIPC_RES4325B0_CBUCK_PWM 3 /* 0x00000008 */
-#define CHIPC_RES4325B0_CLDO_PU 4 /* 0x00000010 */
-
-/* 4325 C1 resources */
-#define CHIPC_RES4325C1_LNLDO2_PU 12 /* 0x00001000 */
-
/* 4325 chip-specific ChipStatus register bits */
#define CHIPC_CST4325_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK
#define CHIPC_CST4325_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT
@@ -1139,29 +767,6 @@ enum {
#define CHIPC_CST4325_PMUTOP_2B_MASK 0x00000200 /* 1 for 2b, 0 for to 2a */
#define CHIPC_CST4325_PMUTOP_2B_SHIFT 9
-#define CHIPC_RES4329_RESERVED0 0 /* 0x00000001 */
-#define CHIPC_RES4329_CBUCK_LPOM 1 /* 0x00000002 */
-#define CHIPC_RES4329_CBUCK_BURST 2 /* 0x00000004 */
-#define CHIPC_RES4329_CBUCK_PWM 3 /* 0x00000008 */
-#define CHIPC_RES4329_CLDO_PU 4 /* 0x00000010 */
-#define CHIPC_RES4329_PALDO_PU 5 /* 0x00000020 */
-#define CHIPC_RES4329_ILP_REQUEST 6 /* 0x00000040 */
-#define CHIPC_RES4329_RESERVED7 7 /* 0x00000080 */
-#define CHIPC_RES4329_RESERVED8 8 /* 0x00000100 */
-#define CHIPC_RES4329_LNLDO1_PU 9 /* 0x00000200 */
-#define CHIPC_RES4329_OTP_PU 10 /* 0x00000400 */
-#define CHIPC_RES4329_RESERVED11 11 /* 0x00000800 */
-#define CHIPC_RES4329_LNLDO2_PU 12 /* 0x00001000 */
-#define CHIPC_RES4329_XTAL_PU 13 /* 0x00002000 */
-#define CHIPC_RES4329_ALP_AVAIL 14 /* 0x00004000 */
-#define CHIPC_RES4329_RX_PWRSW_PU 15 /* 0x00008000 */
-#define CHIPC_RES4329_TX_PWRSW_PU 16 /* 0x00010000 */
-#define CHIPC_RES4329_RFPLL_PWRSW_PU 17 /* 0x00020000 */
-#define CHIPC_RES4329_LOGEN_PWRSW_PU 18 /* 0x00040000 */
-#define CHIPC_RES4329_AFE_PWRSW_PU 19 /* 0x00080000 */
-#define CHIPC_RES4329_BBPLL_PWRSW_PU 20 /* 0x00100000 */
-#define CHIPC_RES4329_HT_AVAIL 21 /* 0x00200000 */
-
/* 4329 chip-specific ChipStatus register bits */
#define CHIPC_CST4329_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK
#define CHIPC_CST4329_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT
@@ -1172,33 +777,6 @@ enum {
#define CHIPC_CST4312_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK
#define CHIPC_CST4312_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT
-/* 4312 resources (all PMU chips with little memory constraint) */
-#define CHIPC_RES4312_SWITCHER_BURST 0 /* 0x00000001 */
-#define CHIPC_RES4312_SWITCHER_PWM 1 /* 0x00000002 */
-#define CHIPC_RES4312_PA_REF_LDO 2 /* 0x00000004 */
-#define CHIPC_RES4312_CORE_LDO_BURST 3 /* 0x00000008 */
-#define CHIPC_RES4312_CORE_LDO_PWM 4 /* 0x00000010 */
-#define CHIPC_RES4312_RADIO_LDO 5 /* 0x00000020 */
-#define CHIPC_RES4312_ILP_REQUEST 6 /* 0x00000040 */
-#define CHIPC_RES4312_BG_FILTBYP 7 /* 0x00000080 */
-#define CHIPC_RES4312_TX_FILTBYP 8 /* 0x00000100 */
-#define CHIPC_RES4312_RX_FILTBYP 9 /* 0x00000200 */
-#define CHIPC_RES4312_XTAL_PU 10 /* 0x00000400 */
-#define CHIPC_RES4312_ALP_AVAIL 11 /* 0x00000800 */
-#define CHIPC_RES4312_BB_PLL_FILTBYP 12 /* 0x00001000 */
-#define CHIPC_RES4312_RF_PLL_FILTBYP 13 /* 0x00002000 */
-#define CHIPC_RES4312_HT_AVAIL 14 /* 0x00004000 */
-
-/* 4322 resources */
-#define CHIPC_RES4322_RF_LDO 0
-#define CHIPC_RES4322_ILP_REQUEST 1
-#define CHIPC_RES4322_XTAL_PU 2
-#define CHIPC_RES4322_ALP_AVAIL 3
-#define CHIPC_RES4322_SI_PLL_ON 4
-#define CHIPC_RES4322_HT_SI_AVAIL 5
-#define CHIPC_RES4322_PHY_PLL_ON 6
-#define CHIPC_RES4322_HT_PHY_AVAIL 7
-#define CHIPC_RES4322_OTP_PU 8
/* 4322 chip-specific ChipStatus register bits */
#define CHIPC_CST4322_XTAL_FREQ_20_40MHZ 0x00000020
@@ -1227,26 +805,6 @@ enum {
#define CHIPC_CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000
#define CHIPC_CST4322_PCI_CARDBUS_MODE 0x00040000
-/* 43224 chip-specific ChipControl register bits */
-#define CHIPC_CCTRL43224_GPIO_TOGGLE 0x8000
-#define CHIPC_CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */
-#define CHIPC_CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */
-
-/* 43236 resources */
-#define CHIPC_RES43236_REGULATOR 0
-#define CHIPC_RES43236_ILP_REQUEST 1
-#define CHIPC_RES43236_XTAL_PU 2
-#define CHIPC_RES43236_ALP_AVAIL 3
-#define CHIPC_RES43236_SI_PLL_ON 4
-#define CHIPC_RES43236_HT_SI_AVAIL 5
-
-/* 43236 chip-specific ChipControl register bits */
-#define CHIPC_CCTRL43236_BT_COEXIST (1<<0) /* 0 disable */
-#define CHIPC_CCTRL43236_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */
-#define CHIPC_CCTRL43236_EXT_LNA (1<<2) /* 0 disable */
-#define CHIPC_CCTRL43236_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */
-#define CHIPC_CCTRL43236_GSIO (1<<4) /* 0 disable */
-
/* 43236 Chip specific ChipStatus register bits */
#define CHIPC_CST43236_SFLASH_MASK 0x00000040
#define CHIPC_CST43236_OTP_SEL_MASK 0x00000080
@@ -1260,15 +818,17 @@ enum {
#define CHIPC_CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */
#define CHIPC_CST43236_BOOT_FROM_INVALID 3
-/* 4331 resources */
-#define CHIPC_RES4331_REGULATOR 0
-#define CHIPC_RES4331_ILP_REQUEST 1
-#define CHIPC_RES4331_XTAL_PU 2
-#define CHIPC_RES4331_ALP_AVAIL 3
-#define CHIPC_RES4331_SI_PLL_ON 4
-#define CHIPC_RES4331_HT_SI_AVAIL 5
+/* 43237 Chip specific ChipStatus register bits */
+#define CHIPC_CST43237_BP_CLK 0x00000200 /* 96/80Mbps */
+
+/* 4331 Chip specific ChipStatus register bits */
+#define CHIPC_CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */
+#define CHIPC_CST4331_SPROM_PRESENT 0x00000002
+#define CHIPC_CST4331_OTP_PRESENT 0x00000004
+#define CHIPC_CST4331_LDO_RF 0x00000008
+#define CHIPC_CST4331_LDO_PAR 0x00000010
-/* 4331 chip-specific ChipControl register bits */
+/* 4331 chip-specific CHIPCTRL register bits */
#define CHIPC_CCTRL4331_BT_COEXIST (1<<0) /* 0 disable */
#define CHIPC_CCTRL4331_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */
#define CHIPC_CCTRL4331_EXT_LNA (1<<2) /* 0 disable */
@@ -1285,33 +845,6 @@ enum {
#define CHIPC_CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) /* enable bt_shd0 at gpio4 */
#define CHIPC_CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) /* enable bt_shd1 at gpio5 */
-/* 4331 Chip specific ChipStatus register bits */
-#define CHIPC_CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */
-#define CHIPC_CST4331_SPROM_PRESENT 0x00000002
-#define CHIPC_CST4331_OTP_PRESENT 0x00000004
-#define CHIPC_CST4331_LDO_RF 0x00000008
-#define CHIPC_CST4331_LDO_PAR 0x00000010
-
-/* 4315 resources */
-#define CHIPC_RES4315_CBUCK_LPOM 1 /* 0x00000002 */
-#define CHIPC_RES4315_CBUCK_BURST 2 /* 0x00000004 */
-#define CHIPC_RES4315_CBUCK_PWM 3 /* 0x00000008 */
-#define CHIPC_RES4315_CLDO_PU 4 /* 0x00000010 */
-#define CHIPC_RES4315_PALDO_PU 5 /* 0x00000020 */
-#define CHIPC_RES4315_ILP_REQUEST 6 /* 0x00000040 */
-#define CHIPC_RES4315_LNLDO1_PU 9 /* 0x00000200 */
-#define CHIPC_RES4315_OTP_PU 10 /* 0x00000400 */
-#define CHIPC_RES4315_LNLDO2_PU 12 /* 0x00001000 */
-#define CHIPC_RES4315_XTAL_PU 13 /* 0x00002000 */
-#define CHIPC_RES4315_ALP_AVAIL 14 /* 0x00004000 */
-#define CHIPC_RES4315_RX_PWRSW_PU 15 /* 0x00008000 */
-#define CHIPC_RES4315_TX_PWRSW_PU 16 /* 0x00010000 */
-#define CHIPC_RES4315_RFPLL_PWRSW_PU 17 /* 0x00020000 */
-#define CHIPC_RES4315_LOGEN_PWRSW_PU 18 /* 0x00040000 */
-#define CHIPC_RES4315_AFE_PWRSW_PU 19 /* 0x00080000 */
-#define CHIPC_RES4315_BBPLL_PWRSW_PU 20 /* 0x00100000 */
-#define CHIPC_RES4315_HT_AVAIL 21 /* 0x00200000 */
-
/* 4315 chip-specific ChipStatus register bits */
#define CHIPC_CST4315_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK
#define CHIPC_CST4315_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT
@@ -1324,26 +857,6 @@ enum {
#define CHIPC_CST4315_CBUCK_MODE_BURST 0x00000400
#define CHIPC_CST4315_CBUCK_MODE_LPBURST 0x00000c00
-/* 4319 resources */
-#define CHIPC_RES4319_CBUCK_LPOM 1 /* 0x00000002 */
-#define CHIPC_RES4319_CBUCK_BURST 2 /* 0x00000004 */
-#define CHIPC_RES4319_CBUCK_PWM 3 /* 0x00000008 */
-#define CHIPC_RES4319_CLDO_PU 4 /* 0x00000010 */
-#define CHIPC_RES4319_PALDO_PU 5 /* 0x00000020 */
-#define CHIPC_RES4319_ILP_REQUEST 6 /* 0x00000040 */
-#define CHIPC_RES4319_LNLDO1_PU 9 /* 0x00000200 */
-#define CHIPC_RES4319_OTP_PU 10 /* 0x00000400 */
-#define CHIPC_RES4319_LNLDO2_PU 12 /* 0x00001000 */
-#define CHIPC_RES4319_XTAL_PU 13 /* 0x00002000 */
-#define CHIPC_RES4319_ALP_AVAIL 14 /* 0x00004000 */
-#define CHIPC_RES4319_RX_PWRSW_PU 15 /* 0x00008000 */
-#define CHIPC_RES4319_TX_PWRSW_PU 16 /* 0x00010000 */
-#define CHIPC_RES4319_RFPLL_PWRSW_PU 17 /* 0x00020000 */
-#define CHIPC_RES4319_LOGEN_PWRSW_PU 18 /* 0x00040000 */
-#define CHIPC_RES4319_AFE_PWRSW_PU 19 /* 0x00080000 */
-#define CHIPC_RES4319_BBPLL_PWRSW_PU 20 /* 0x00100000 */
-#define CHIPC_RES4319_HT_AVAIL 21 /* 0x00200000 */
-
/* 4319 chip-specific ChipStatus register bits */
#define CHIPC_CST4319_SPI_CPULESSUSB 0x00000001
#define CHIPC_CST4319_SPI_CLK_POL 0x00000002
@@ -1364,42 +877,6 @@ enum {
#define CHIPC_CST4319_RCAL_VALUE_MASK 0x3e000000
#define CHIPC_CST4319_RCAL_VALUE_SHIFT 25
-#define CHIPC_PMU1_PLL0_CHIPCTL0 0
-#define CHIPC_PMU1_PLL0_CHIPCTL1 1
-#define CHIPC_PMU1_PLL0_CHIPCTL2 2
-#define CHIPC_CCTL_4319USB_XTAL_SEL_MASK 0x00180000
-#define CHIPC_CCTL_4319USB_XTAL_SEL_SHIFT 19
-#define CHIPC_CCTL_4319USB_48MHZ_PLL_SEL 1
-#define CHIPC_CCTL_4319USB_24MHZ_PLL_SEL 2
-
-/* PMU resources for 4336 */
-#define CHIPC_RES4336_CBUCK_LPOM 0
-#define CHIPC_RES4336_CBUCK_BURST 1
-#define CHIPC_RES4336_CBUCK_LP_PWM 2
-#define CHIPC_RES4336_CBUCK_PWM 3
-#define CHIPC_RES4336_CLDO_PU 4
-#define CHIPC_RES4336_DIS_INT_RESET_PD 5
-#define CHIPC_RES4336_ILP_REQUEST 6
-#define CHIPC_RES4336_LNLDO_PU 7
-#define CHIPC_RES4336_LDO3P3_PU 8
-#define CHIPC_RES4336_OTP_PU 9
-#define CHIPC_RES4336_XTAL_PU 10
-#define CHIPC_RES4336_ALP_AVAIL 11
-#define CHIPC_RES4336_RADIO_PU 12
-#define CHIPC_RES4336_BG_PU 13
-#define CHIPC_RES4336_VREG1p4_PU_PU 14
-#define CHIPC_RES4336_AFE_PWRSW_PU 15
-#define CHIPC_RES4336_RX_PWRSW_PU 16
-#define CHIPC_RES4336_TX_PWRSW_PU 17
-#define CHIPC_RES4336_BB_PWRSW_PU 18
-#define CHIPC_RES4336_SYNTH_PWRSW_PU 19
-#define CHIPC_RES4336_MISC_PWRSW_PU 20
-#define CHIPC_RES4336_LOGEN_PWRSW_PU 21
-#define CHIPC_RES4336_BBPLL_PWRSW_PU 22
-#define CHIPC_RES4336_MACPHY_CLKAVAIL 23
-#define CHIPC_RES4336_HT_AVAIL 24
-#define CHIPC_RES4336_RSVD 25
-
/* 4336 chip-specific ChipStatus register bits */
#define CHIPC_CST4336_SPI_MODE_MASK 0x00000001
#define CHIPC_CST4336_SPROM_PRESENT 0x00000002
@@ -1416,36 +893,6 @@ enum {
#define CHIPC_CST4336_CBUCK_MODE_MASK 0x00000600
#define CHIPC_CST4336_CBUCK_MODE_SHIFT 9
-/* 4330 resources */
-#define CHIPC_RES4330_CBUCK_LPOM 0
-#define CHIPC_RES4330_CBUCK_BURST 1
-#define CHIPC_RES4330_CBUCK_LP_PWM 2
-#define CHIPC_RES4330_CBUCK_PWM 3
-#define CHIPC_RES4330_CLDO_PU 4
-#define CHIPC_RES4330_DIS_INT_RESET_PD 5
-#define CHIPC_RES4330_ILP_REQUEST 6
-#define CHIPC_RES4330_LNLDO_PU 7
-#define CHIPC_RES4330_LDO3P3_PU 8
-#define CHIPC_RES4330_OTP_PU 9
-#define CHIPC_RES4330_XTAL_PU 10
-#define CHIPC_RES4330_ALP_AVAIL 11
-#define CHIPC_RES4330_RADIO_PU 12
-#define CHIPC_RES4330_BG_PU 13
-#define CHIPC_RES4330_VREG1p4_PU_PU 14
-#define CHIPC_RES4330_AFE_PWRSW_PU 15
-#define CHIPC_RES4330_RX_PWRSW_PU 16
-#define CHIPC_RES4330_TX_PWRSW_PU 17
-#define CHIPC_RES4330_BB_PWRSW_PU 18
-#define CHIPC_RES4330_SYNTH_PWRSW_PU 19
-#define CHIPC_RES4330_MISC_PWRSW_PU 20
-#define CHIPC_RES4330_LOGEN_PWRSW_PU 21
-#define CHIPC_RES4330_BBPLL_PWRSW_PU 22
-#define CHIPC_RES4330_MACPHY_CLKAVAIL 23
-#define CHIPC_RES4330_HT_AVAIL 24
-#define CHIPC_RES4330_5gRX_PWRSW_PU 25
-#define CHIPC_RES4330_5gTX_PWRSW_PU 26
-#define CHIPC_RES4330_5g_LOGEN_PWRSW_PU 27
-
/* 4330 chip-specific ChipStatus register bits */
#define CHIPC_CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) /* SDIO || gSPI */
#define CHIPC_CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) /* USB || USBDA */
@@ -1468,41 +915,12 @@ enum {
#define CHIPC_SOCDEVRAM_4330_BP_ADDR 0x1E000000
#define CHIPC_SOCDEVRAM_4330_ARM_ADDR 0x00800000
-/* 4313 resources */
-#define CHIPC_RES4313_BB_PU_RSRC 0
-#define CHIPC_RES4313_ILP_REQ_RSRC 1
-#define CHIPC_RES4313_XTAL_PU_RSRC 2
-#define CHIPC_RES4313_ALP_AVAIL_RSRC 3
-#define CHIPC_RES4313_RADIO_PU_RSRC 4
-#define CHIPC_RES4313_BG_PU_RSRC 5
-#define CHIPC_RES4313_VREG1P4_PU_RSRC 6
-#define CHIPC_RES4313_AFE_PWRSW_RSRC 7
-#define CHIPC_RES4313_RX_PWRSW_RSRC 8
-#define CHIPC_RES4313_TX_PWRSW_RSRC 9
-#define CHIPC_RES4313_BB_PWRSW_RSRC 10
-#define CHIPC_RES4313_SYNTH_PWRSW_RSRC 11
-#define CHIPC_RES4313_MISC_PWRSW_RSRC 12
-#define CHIPC_RES4313_BB_PLL_PWRSW_RSRC 13
-#define CHIPC_RES4313_HT_AVAIL_RSRC 14
-#define CHIPC_RES4313_MACPHY_CLK_AVAIL_RSRC 15
-
/* 4313 chip-specific ChipStatus register bits */
#define CHIPC_CST4313_SPROM_PRESENT 1
#define CHIPC_CST4313_OTP_PRESENT 2
#define CHIPC_CST4313_SPROM_OTP_SEL_MASK 0x00000002
#define CHIPC_CST4313_SPROM_OTP_SEL_SHIFT 0
-/* 4313 Chip specific ChipControl register bits */
-#define CHIPC_CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */
-
-/* 43228 resources */
-#define CHIPC_RES43228_NOT_USED 0
-#define CHIPC_RES43228_ILP_REQUEST 1
-#define CHIPC_RES43228_XTAL_PU 2
-#define CHIPC_RES43228_ALP_AVAIL 3
-#define CHIPC_RES43228_PLL_EN 4
-#define CHIPC_RES43228_HT_PHY_AVAIL 5
-
/* 43228 chipstatus reg bits */
#define CHIPC_CST43228_ILP_DIV_EN 0x1
#define CHIPC_CST43228_OTP_PRESENT 0x2
@@ -1513,15 +931,6 @@ enum {
#define CHIPC_CST43228_SDIO_RESET 0x20
/*
-* Maximum delay for the PMU state transition in us.
-* This is an upper bound intended for spinwaits etc.
-*/
-#define CHIPC_PMU_MAX_TRANSITION_DLY 15000
-
-/* PMU resource up transition time in ILP cycles */
-#define CHIPC_PMURES_UP_TRANSITION 2
-
-/*
* Register eci_inputlo bitfield values.
* - BT packet type information bits [7:0]
*/
diff --git a/sys/dev/bhnd/cores/chipc/chipcvar.h b/sys/dev/bhnd/cores/chipc/chipcvar.h
index af35a39e1c2d..b5f2a3700651 100644
--- a/sys/dev/bhnd/cores/chipc/chipcvar.h
+++ b/sys/dev/bhnd/cores/chipc/chipcvar.h
@@ -39,71 +39,15 @@
#include "chipc.h"
-DECLARE_CLASS(bhnd_chipc);
+DECLARE_CLASS(bhnd_chipc_driver);
extern devclass_t bhnd_chipc_devclass;
struct chipc_region;
-/**
- * Supported ChipCommon flash types.
- */
-typedef enum {
- CHIPC_FLASH_NONE = 0, /**< No flash, or a type unrecognized
- by the ChipCommon driver */
- CHIPC_PFLASH_CFI = 1, /**< CFI-compatible parallel flash */
- CHIPC_SFLASH_ST = 2, /**< ST serial flash */
- CHIPC_SFLASH_AT = 3, /**< Atmel serial flash */
- CHIPC_QSFLASH_ST = 4, /**< ST quad-SPI flash */
- CHIPC_QSFLASH_AT = 5, /**< Atmel quad-SPI flash */
- CHIPC_NFLASH = 6, /**< NAND flash */
- CHIPC_NFLASH_4706 = 7 /**< BCM4706 NAND flash */
-} chipc_flash;
-
const char *chipc_flash_name(chipc_flash type);
const char *chipc_flash_bus_name(chipc_flash type);
const char *chipc_sflash_device_name(chipc_flash type);
-/**
- * ChipCommon capability flags;
- */
-struct chipc_caps {
- uint8_t num_uarts; /**< Number of attached UARTS (1-3) */
- bool mipseb; /**< MIPS is big-endian */
- uint8_t uart_clock; /**< UART clock source (see CHIPC_CAP_UCLKSEL_*) */
- uint8_t uart_gpio; /**< UARTs own GPIO pins 12-15 */
-
- uint8_t extbus_type; /**< ExtBus type (CHIPC_CAP_EXTBUS_*) */
-
- chipc_flash flash_type; /**< flash type */
- uint8_t cfi_width; /**< CFI bus width, 0 if unknown or CFI
- not present */
-
- bhnd_nvram_src nvram_src; /**< identified NVRAM source */
- bus_size_t sprom_offset; /**< Offset to SPROM data within
- SPROM/OTP, 0 if unknown or not
- present */
- uint8_t otp_size; /**< OTP (row?) size, 0 if not present */
-
- uint8_t pll_type; /**< PLL type */
- bool power_control; /**< Power control available */
- bool jtag_master; /**< JTAG Master present */
- bool boot_rom; /**< Internal boot ROM is active */
- uint8_t backplane_64; /**< Backplane supports 64-bit addressing.
- Note that this does not gaurantee
- the CPU itself supports 64-bit
- addressing. */
- bool pmu; /**< PMU is present. */
- bool eci; /**< ECI (enhanced coexistence inteface) is present. */
- bool seci; /**< SECI (serial ECI) is present */
- bool sprom; /**< SPROM is present */
- bool gsio; /**< GSIO (SPI/I2C) present */
- bool aob; /**< AOB (always on bus) present.
- If set, PMU and GCI registers are
- not accessible via ChipCommon,
- and are instead accessible via
- dedicated cores on the bhnd bus */
-};
-
/*
* ChipCommon device quirks / features
*/
diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c
new file mode 100644
index 000000000000..d2bf54c8ce35
--- /dev/null
+++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c
@@ -0,0 +1,479 @@
+/*-
+ * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
+ * Copyright (c) 2010, Broadcom Corporation.
+ * All rights reserved.
+ *
+ * This file is 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
+ * 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.
+ *
+ * $Id: siutils.c,v 1.821.2.48 2011-02-11 20:59:28 Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+
+#include <dev/bhnd/bhnd.h>
+
+#include <dev/bhnd/cores/chipc/chipcreg.h>
+#include <dev/bhnd/cores/chipc/chipcvar.h>
+
+#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
+#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
+
+#include "bhnd_chipc_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.
+ */
+
+typedef enum {
+ BHND_PWRCTL_WAR_UP, /**< apply attach/resume workarounds */
+ BHND_PWRCTL_WAR_RUN, /**< apply running workarounds */
+ BHND_PWRCTL_WAR_DOWN, /**< apply detach/suspend workarounds */
+} bhnd_pwrctl_wars;
+
+static int bhnd_pwrctl_updateclk(struct bhnd_pwrctl_softc *sc,
+ bhnd_pwrctl_wars wars);
+
+static struct bhnd_device_quirk pwrctl_quirks[];
+
+
+/* Supported parent core device identifiers */
+static const struct bhnd_device pwrctl_devices[] = {
+ BHND_DEVICE(BCM, CC, "ChipCommon Power Control", pwrctl_quirks),
+ BHND_DEVICE_END
+};
+
+/* Device quirks table */
+static struct bhnd_device_quirk pwrctl_quirks[] = {
+ BHND_CORE_QUIRK (HWREV_LTE(5), PWRCTL_QUIRK_PCICLK_CTL),
+ BHND_CORE_QUIRK (HWREV_RANGE(6, 9), PWRCTL_QUIRK_SLOWCLK_CTL),
+ BHND_CORE_QUIRK (HWREV_RANGE(10, 19), PWRCTL_QUIRK_INSTACLK_CTL),
+
+ BHND_DEVICE_QUIRK_END
+};
+
+static int
+bhnd_pwrctl_probe(device_t dev)
+{
+ const struct bhnd_device *id;
+ struct chipc_caps *ccaps;
+ device_t chipc;
+
+ /* Look for compatible chipc parent */
+ chipc = device_get_parent(dev);
+ if (device_get_devclass(chipc) != devclass_find("bhnd_chipc"))
+ return (ENXIO);
+
+ if (device_get_driver(chipc) != &bhnd_chipc_driver)
+ return (ENXIO);
+
+ /* Verify chipc capability flags */
+ ccaps = BHND_CHIPC_GET_CAPS(chipc);
+ if (ccaps->pmu || !ccaps->pwr_ctrl)
+ return (ENXIO);
+
+ /* Check for chipc device match */
+ id = bhnd_device_lookup(chipc, pwrctl_devices,
+ sizeof(pwrctl_devices[0]));
+ if (id == NULL)
+ return (ENXIO);
+
+ device_set_desc(dev, id->desc);
+ return (BUS_PROBE_NOWILDCARD);
+}
+
+static int
+bhnd_pwrctl_attach(device_t dev)
+{
+ struct bhnd_pwrctl_softc *sc;
+ const struct bhnd_chipid *cid;
+ struct chipc_softc *chipc_sc;
+ bhnd_devclass_t hostb_class;
+ device_t hostb_dev;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ /* TODO: Need further testing on actual PWRCTL hardware */
+ device_printf(dev, "WARNING: Using untested PWRCTL support\n");
+
+ sc->dev = dev;
+ sc->chipc_dev = device_get_parent(dev);
+ sc->quirks = bhnd_device_quirks(sc->chipc_dev, pwrctl_devices,
+ sizeof(pwrctl_devices[0]));
+
+ /* On devices that lack a slow clock source, HT must always be
+ * enabled. */
+ hostb_class = BHND_DEVCLASS_INVALID;
+ hostb_dev = bhnd_find_hostb_device(device_get_parent(sc->chipc_dev));
+ if (hostb_dev != NULL)
+ hostb_class = bhnd_get_class(hostb_dev);
+
+ cid = bhnd_get_chipid(sc->chipc_dev);
+ switch (cid->chip_id) {
+ case BHND_CHIPID_BCM4311:
+ if (cid->chip_rev <= 1 && hostb_class == BHND_DEVCLASS_PCI)
+ sc->quirks |= PWRCTL_QUIRK_FORCE_HT;
+ break;
+
+ case BHND_CHIPID_BCM4321:
+ if (hostb_class == BHND_DEVCLASS_PCIE ||
+ hostb_class == BHND_DEVCLASS_PCI)
+ sc->quirks |= PWRCTL_QUIRK_FORCE_HT;
+ break;
+
+ case BHND_CHIPID_BCM4716:
+ if (hostb_class == BHND_DEVCLASS_PCIE)
+ sc->quirks |= PWRCTL_QUIRK_FORCE_HT;
+ break;
+ }
+
+ /* Fetch core register block from ChipCommon parent */
+ chipc_sc = device_get_softc(sc->chipc_dev);
+ sc->res = chipc_sc->core;
+
+ PWRCTL_LOCK_INIT(sc);
+ STAILQ_INIT(&sc->clkres_list);
+
+ /* Initialize power control */
+ PWRCTL_LOCK(sc);
+
+ if ((error = bhnd_pwrctl_init(sc))) {
+ PWRCTL_UNLOCK(sc);
+ goto cleanup;
+ }
+
+ /* Apply default clock transitions */
+ if ((error = bhnd_pwrctl_updateclk(sc, BHND_PWRCTL_WAR_UP))) {
+ PWRCTL_UNLOCK(sc);
+ goto cleanup;
+ }
+
+ PWRCTL_UNLOCK(sc);
+
+ return (0);
+
+cleanup:
+ PWRCTL_LOCK_DESTROY(sc);
+ return (error);
+}
+
+static int
+bhnd_pwrctl_detach(device_t dev)
+{
+ struct bhnd_pwrctl_softc *sc;
+ struct bhnd_pwrctl_clkres *clkres, *crnext;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ if ((error = bhnd_pwrctl_setclk(sc, BHND_CLOCK_DYN)))
+ return (error);
+
+ STAILQ_FOREACH_SAFE(clkres, &sc->clkres_list, cr_link, crnext)
+ free(clkres, M_DEVBUF);
+
+ PWRCTL_LOCK_DESTROY(sc);
+ return (0);
+}
+
+static int
+bhnd_pwrctl_suspend(device_t dev)
+{
+ struct bhnd_pwrctl_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ /* Update clock state */
+ PWRCTL_LOCK(sc);
+ error = bhnd_pwrctl_updateclk(sc, BHND_PWRCTL_WAR_DOWN);
+ PWRCTL_UNLOCK(sc);
+
+ return (error);
+}
+
+static int
+bhnd_pwrctl_resume(device_t dev)
+{
+ struct bhnd_pwrctl_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ PWRCTL_LOCK(sc);
+
+ /* Re-initialize power control registers */
+ if ((error = bhnd_pwrctl_init(sc))) {
+ device_printf(sc->dev, "PWRCTL init failed: %d\n", error);
+ goto cleanup;
+ }
+
+ /* Restore clock state */
+ if ((error = bhnd_pwrctl_updateclk(sc, BHND_PWRCTL_WAR_UP))) {
+ device_printf(sc->dev, "clock state restore failed: %d\n",
+ error);
+ goto cleanup;
+ }
+
+cleanup:
+ PWRCTL_UNLOCK(sc);
+ return (error);
+}
+
+/**
+ * Find the clock reservation associated with @p pinfo, if any.
+ *
+ * @param sc Driver instance state.
+ * @param pinfo PMU info for device.
+ */
+static struct bhnd_pwrctl_clkres *
+bhnd_pwrctl_find_res(struct bhnd_pwrctl_softc *sc,
+ struct bhnd_core_pmu_info *pinfo)
+{
+ 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)
+ return (clkres);
+ }
+
+ /* not found */
+ return (NULL);
+}
+
+/**
+ * Enumerate all active clock requests, compute the minimum required clock,
+ * and issue any required clock transition.
+ *
+ * @param sc Driver instance state.
+ * @param wars Work-around state.
+ */
+static int
+bhnd_pwrctl_updateclk(struct bhnd_pwrctl_softc *sc, bhnd_pwrctl_wars wars)
+{
+ struct bhnd_pwrctl_clkres *clkres;
+ bhnd_clock clock;
+
+ PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
+
+ /* Default clock target */
+ clock = BHND_CLOCK_DYN;
+
+ /* Apply quirk-specific overrides to the clock target */
+ switch (wars) {
+ case BHND_PWRCTL_WAR_UP:
+ /* Force HT clock */
+ if (PWRCTL_QUIRK(sc, FORCE_HT))
+ clock = BHND_CLOCK_HT;
+ break;
+
+ case BHND_PWRCTL_WAR_RUN:
+ /* Cannot transition clock if FORCE_HT */
+ if (PWRCTL_QUIRK(sc, FORCE_HT))
+ return (0);
+ break;
+
+ case BHND_PWRCTL_WAR_DOWN:
+ /* Leave default clock unmodified to permit
+ * transition back to BHND_CLOCK_DYN on FORCE_HT devices. */
+ break;
+ }
+
+ /* Determine required clock */
+ STAILQ_FOREACH(clkres, &sc->clkres_list, cr_link)
+ clock = bhnd_clock_max(clock, clkres->clock);
+
+ /* Map to supported clock setting */
+ switch (clock) {
+ case BHND_CLOCK_DYN:
+ case BHND_CLOCK_ILP:
+ clock = BHND_CLOCK_DYN;
+ break;
+ case BHND_CLOCK_ALP:
+ /* In theory FORCE_ALP is supported by the hardware, but
+ * there are currently no known use-cases for it; mapping
+ * to HT is still valid, and allows us to punt on determing
+ * where FORCE_ALP is supported and functional */
+ clock = BHND_CLOCK_HT;
+ break;
+ case BHND_CLOCK_HT:
+ break;
+ default:
+ device_printf(sc->dev, "unknown clock: %#x\n", clock);
+ return (ENODEV);
+ }
+
+ /* Issue transition */
+ return (bhnd_pwrctl_setclk(sc, clock));
+}
+
+static int
+bhnd_pwrctl_core_req_clock(device_t dev, struct bhnd_core_pmu_info *pinfo,
+ bhnd_clock clock)
+{
+ struct bhnd_pwrctl_softc *sc;
+ struct bhnd_pwrctl_clkres *clkres;
+ int error;
+
+ sc = device_get_softc(dev);
+ error = 0;
+
+ PWRCTL_LOCK(sc);
+
+ clkres = bhnd_pwrctl_find_res(sc, pinfo);
+
+ /* BHND_CLOCK_DYN discards the clock reservation entirely */
+ if (clock == BHND_CLOCK_DYN) {
+ /* nothing to clean up? */
+ if (clkres == NULL) {
+ PWRCTL_UNLOCK(sc);
+ return (0);
+ }
+
+ /* drop reservation and apply clock transition */
+ STAILQ_REMOVE(&sc->clkres_list, clkres,
+ bhnd_pwrctl_clkres, cr_link);
+
+ if ((error = bhnd_pwrctl_updateclk(sc, BHND_PWRCTL_WAR_RUN))) {
+ device_printf(dev, "clock transition failed: %d\n",
+ error);
+
+ /* restore reservation */
+ STAILQ_INSERT_TAIL(&sc->clkres_list, clkres, cr_link);
+
+ PWRCTL_UNLOCK(sc);
+ return (error);
+ }
+
+ /* deallocate orphaned reservation */
+ free(clkres, M_DEVBUF);
+
+ PWRCTL_UNLOCK(sc);
+ return (0);
+ }
+
+ /* create (or update) reservation */
+ if (clkres == NULL) {
+ clkres = malloc(sizeof(struct bhnd_pwrctl_clkres), M_DEVBUF,
+ M_NOWAIT);
+ if (clkres == NULL)
+ return (ENOMEM);
+
+ clkres->owner = pinfo->pm_dev;
+ clkres->clock = clock;
+
+ STAILQ_INSERT_TAIL(&sc->clkres_list, clkres, cr_link);
+ } else {
+ KASSERT(clkres->owner == pinfo->pm_dev, ("invalid owner"));
+ clkres->clock = clock;
+ }
+
+ /* apply clock transition */
+ error = bhnd_pwrctl_updateclk(sc, BHND_PWRCTL_WAR_RUN);
+ if (error) {
+ STAILQ_REMOVE(&sc->clkres_list, clkres, bhnd_pwrctl_clkres,
+ cr_link);
+ free(clkres, M_DEVBUF);
+ }
+
+ PWRCTL_UNLOCK(sc);
+ 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_END
+};
+
+DEFINE_CLASS_0(bhnd_pmu, 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);
+
+MODULE_DEPEND(bhnd_pwrctl, bhnd, 1, 1, 1);
+MODULE_VERSION(bhnd_pwrctl, 1);
diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h
new file mode 100644
index 000000000000..0e4eb1a284bf
--- /dev/null
+++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BHND_PWRCTL_BHND_PWRCTL_PRIVATE_H_
+#define _BHND_PWRCTL_BHND_PWRCTL_PRIVATE_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);
+
+#endif /* _BHND_PWRCTL_BHND_PWRCTL_PRIVATE_H_ */
diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c
new file mode 100644
index 000000000000..9f6f400390ff
--- /dev/null
+++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c
@@ -0,0 +1,463 @@
+/*-
+ * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
+ * Copyright (c) 2010, Broadcom Corporation.
+ * All rights reserved.
+ *
+ * This file is 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
+ * 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.
+ *
+ * $Id: siutils.c,v 1.821.2.48 2011-02-11 20:59:28 Exp $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+
+#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/bhndb/bhndb_pcireg.h>
+
+#include <dev/bhnd/cores/chipc/chipc.h>
+#include <dev/bhnd/cores/chipc/chipcreg.h>
+
+#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
+#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
+
+#include "bhnd_chipc_if.h"
+
+#include "bhnd_pwrctl_private.h"
+
+static uint32_t bhnd_pwrctl_factor6(uint32_t x);
+static uint32_t bhnd_pwrctl_clock_rate(uint32_t pll_type, uint32_t n,
+ uint32_t m);
+
+/**
+ * Return the factor value corresponding to a given N3M clock control magic
+ * field value (CHIPC_F6_*).
+ */
+static uint32_t
+bhnd_pwrctl_factor6(uint32_t x)
+{
+ switch (x) {
+ case CHIPC_F6_2:
+ return (2);
+ case CHIPC_F6_3:
+ return (3);
+ case CHIPC_F6_4:
+ return (4);
+ case CHIPC_F6_5:
+ return (5);
+ case CHIPC_F6_6:
+ return (6);
+ case CHIPC_F6_7:
+ return (7);
+ default:
+ return (0);
+ }
+}
+
+/**
+ * Calculate the clock speed (in Hz) for a given a set of clockcontrol
+ * values.
+ *
+ * @param pll_type PLL type (CHIPC_PLL_TYPE*)
+ * @param n clock control N register value.
+ * @param m clock control N register value.
+ */
+static uint32_t
+bhnd_pwrctl_clock_rate(uint32_t pll_type, uint32_t n, uint32_t m)
+{
+ uint32_t clk_base;
+ uint32_t n1, n2, clock, m1, m2, m3, mc;
+
+ n1 = CHIPC_GET_BITS(n, CHIPC_CN_N1);
+ n2 = CHIPC_GET_BITS(n, CHIPC_CN_N2);
+
+ switch (pll_type) {
+ case CHIPC_PLL_TYPE1:
+ case CHIPC_PLL_TYPE3:
+ case CHIPC_PLL_TYPE4:
+ case CHIPC_PLL_TYPE7:
+ n1 = bhnd_pwrctl_factor6(n1);
+ n2 += CHIPC_F5_BIAS;
+ break;
+
+ case CHIPC_PLL_TYPE2:
+ n1 += CHIPC_T2_BIAS;
+ n2 += CHIPC_T2_BIAS;
+ KASSERT(n1 >= 2 && n1 <= 7, ("invalid n1 value"));
+ KASSERT(n2 >= 5 && n2 <= 23, ("invalid n2 value"));
+ break;
+
+ case CHIPC_PLL_TYPE5:
+ return (100000000);
+
+ case CHIPC_PLL_TYPE6:
+ if (m & CHIPC_T6_MMASK)
+ return (CHIPC_T6_M1);
+ else
+ return (CHIPC_T6_M0);
+
+ default:
+ printf("unsupported PLL type %u\n", pll_type);
+ return (0);
+ }
+
+ /* PLL types 3 and 7 use BASE2 (25Mhz) */
+ if (pll_type == CHIPC_PLL_TYPE3 || pll_type == CHIPC_PLL_TYPE7) {
+ clk_base = CHIPC_CLOCK_BASE2;
+ } else {
+ clk_base = CHIPC_CLOCK_BASE1;
+ }
+
+ clock = clk_base * n1 * n2;
+
+ if (clock == 0)
+ return (0);
+
+ m1 = CHIPC_GET_BITS(m, CHIPC_M1);
+ m2 = CHIPC_GET_BITS(m, CHIPC_M2);
+ m3 = CHIPC_GET_BITS(m, CHIPC_M3);
+ mc = CHIPC_GET_BITS(m, CHIPC_MC);
+
+ switch (pll_type) {
+ case CHIPC_PLL_TYPE1:
+ case CHIPC_PLL_TYPE3:
+ case CHIPC_PLL_TYPE4:
+ case CHIPC_PLL_TYPE7:
+ m1 = bhnd_pwrctl_factor6(m1);
+ if (pll_type == CHIPC_PLL_TYPE1 || pll_type == CHIPC_PLL_TYPE3)
+ m2 += CHIPC_F5_BIAS;
+ else
+ m2 = bhnd_pwrctl_factor6(m2);
+
+ m3 = bhnd_pwrctl_factor6(m3);
+
+ switch (mc) {
+ case CHIPC_MC_BYPASS:
+ return (clock);
+ case CHIPC_MC_M1:
+ return (clock / m1);
+ case CHIPC_MC_M1M2:
+ return (clock / (m1 * m2));
+ case CHIPC_MC_M1M2M3:
+ return (clock / (m1 * m2 * m3));
+ case CHIPC_MC_M1M3:
+ return (clock / (m1 * m3));
+ default:
+ printf("unsupported pwrctl mc %#x\n", mc);
+ return (0);
+ }
+ case CHIPC_PLL_TYPE2:
+ m1 += CHIPC_T2_BIAS;
+ m2 += CHIPC_T2M2_BIAS;
+ m3 += CHIPC_T2_BIAS;
+ KASSERT(m1 >= 2 && m1 <= 7, ("invalid m1 value"));
+ KASSERT(m2 >= 3 && m2 <= 10, ("invalid m2 value"));
+ KASSERT(m3 >= 2 && m3 <= 7, ("invalid m3 value"));
+
+ if ((mc & CHIPC_T2MC_M1BYP) == 0)
+ clock /= m1;
+ if ((mc & CHIPC_T2MC_M2BYP) == 0)
+ clock /= m2;
+ if ((mc & CHIPC_T2MC_M3BYP) == 0)
+ clock /= m3;
+
+ return (clock);
+ default:
+ panic("unhandled PLL type %u\n", pll_type);
+ }
+}
+
+/**
+ * Return the backplane clock speed in Hz.
+ *
+ * @param sc driver instance state.
+ */
+uint32_t
+bhnd_pwrctl_getclk_speed(struct bhnd_pwrctl_softc *sc)
+{
+ struct chipc_caps *ccaps;
+ bus_size_t creg;
+ uint32_t n, m;
+ uint32_t rate;
+
+ PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
+
+ ccaps = BHND_CHIPC_GET_CAPS(sc->chipc_dev);
+
+ n = bhnd_bus_read_4(sc->res, CHIPC_CLKC_N);
+
+ switch (ccaps->pll_type) {
+ case CHIPC_PLL_TYPE6:
+ creg = CHIPC_CLKC_M3; /* non-extif regster */
+ break;
+ case CHIPC_PLL_TYPE3:
+ creg = CHIPC_CLKC_M2;
+ break;
+ default:
+ creg = CHIPC_CLKC_SB;
+ break;
+ }
+
+ m = bhnd_bus_read_4(sc->res, creg);
+
+ /* calculate rate */
+ rate = bhnd_pwrctl_clock_rate(ccaps->pll_type, n, m);
+
+ if (ccaps->pll_type == CHIPC_PLL_TYPE3)
+ rate /= 2;
+
+ return (rate);
+}
+
+/* return the slow clock source */
+static bhnd_clksrc
+bhnd_pwrctl_slowclk_src(struct bhnd_pwrctl_softc *sc)
+{
+ uint32_t clkreg;
+ uint32_t clksrc;
+
+ /* Fetch clock source */
+ if (PWRCTL_QUIRK(sc, PCICLK_CTL)) {
+ return (bhnd_pwrctl_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;
+ } else {
+ /* Instaclock */
+ clksrc = CHIPC_SCC_SS_XTAL;
+ }
+
+ /* Map to bhnd_clksrc */
+ switch (clksrc) {
+ case CHIPC_SCC_SS_PCI:
+ return (BHND_CLKSRC_PCI);
+ case CHIPC_SCC_SS_LPO:
+ return (BHND_CLKSRC_LPO);
+ case CHIPC_SCC_SS_XTAL:
+ return (BHND_CLKSRC_XTAL);
+ default:
+ return (BHND_CLKSRC_UNKNOWN);
+ }
+}
+
+/* return the ILP (slowclock) min or max frequency */
+static uint32_t
+bhnd_pwrctl_slowclk_freq(struct bhnd_pwrctl_softc *sc, bool max_freq)
+{
+ bhnd_clksrc slowclk;
+ uint32_t div;
+ uint32_t hz;
+
+ slowclk = bhnd_pwrctl_slowclk_src(sc);
+
+ /* Determine clock divisor */
+ if (PWRCTL_QUIRK(sc, PCICLK_CTL)) {
+ if (slowclk == BHND_CLKSRC_PCI)
+ div = 64;
+ else
+ div = 32;
+ } else if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
+ div = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL);
+ div = CHIPC_GET_BITS(div, CHIPC_SCC_CD);
+ div *= 4;
+ } else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
+ if (max_freq) {
+ div = 1;
+ } else {
+ div = bhnd_bus_read_4(sc->res, CHIPC_SYS_CLK_CTL);
+ div = CHIPC_GET_BITS(div, CHIPC_SYCC_CD);
+ div = 4 * (div + 1);
+ }
+ } else {
+ device_printf(sc->dev, "unknown device type\n");
+ return (0);
+ }
+
+ /* Determine clock frequency */
+ switch (slowclk) {
+ case BHND_CLKSRC_LPO:
+ hz = max_freq ? CHIPC_LPOMAXFREQ : CHIPC_LPOMINFREQ;
+ break;
+ case BHND_CLKSRC_XTAL:
+ hz = max_freq ? CHIPC_XTALMAXFREQ : CHIPC_XTALMINFREQ;
+ break;
+ case BHND_CLKSRC_PCI:
+ hz = max_freq ? CHIPC_PCIMAXFREQ : CHIPC_PCIMINFREQ;
+ break;
+ default:
+ device_printf(sc->dev, "unknown slowclk source %#x\n", slowclk);
+ return (0);
+ }
+
+ return (hz / div);
+}
+
+/**
+ * Initialize power control registers.
+ */
+int
+bhnd_pwrctl_init(struct bhnd_pwrctl_softc *sc)
+{
+ uint32_t clkctl;
+ uint32_t pll_delay, slowclk, slowmaxfreq;
+ uint32_t pll_on_delay, fref_sel_delay;
+ int error;
+
+ pll_delay = CHIPC_PLL_DELAY;
+
+ /* set all Instaclk chip ILP to 1 MHz */
+ if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
+ clkctl = (CHIPC_ILP_DIV_1MHZ << CHIPC_SYCC_CD_SHIFT);
+ clkctl &= CHIPC_SYCC_CD_MASK;
+ bhnd_bus_write_4(sc->res, CHIPC_SYS_CLK_CTL, clkctl);
+ }
+
+ /*
+ * Initialize PLL/FREF delays.
+ *
+ * If the slow clock is not sourced by the xtal, include the
+ * delay required to bring it up.
+ */
+ slowclk = bhnd_pwrctl_slowclk_src(sc);
+ if (slowclk != CHIPC_SCC_SS_XTAL)
+ pll_delay += CHIPC_XTAL_ON_DELAY;
+
+ /* Starting with 4318 it is ILP that is used for the delays */
+ if (PWRCTL_QUIRK(sc, INSTACLK_CTL))
+ slowmaxfreq = bhnd_pwrctl_slowclk_freq(sc, false);
+ else
+ slowmaxfreq = bhnd_pwrctl_slowclk_freq(sc, true);
+
+ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
+ fref_sel_delay = ((slowmaxfreq * CHIPC_FREF_DELAY) + 999999) / 1000000;
+
+ bhnd_bus_write_4(sc->res, CHIPC_PLL_ON_DELAY, pll_on_delay);
+ bhnd_bus_write_4(sc->res, CHIPC_PLL_FREFSEL_DELAY, fref_sel_delay);
+
+ /* If required, force HT */
+ if (PWRCTL_QUIRK(sc, FORCE_HT)) {
+ if ((error = bhnd_pwrctl_setclk(sc, BHND_CLOCK_HT)))
+ return (error);
+ }
+
+ return (0);
+}
+
+/* return the value suitable for writing to the dot11 core
+ * FAST_PWRUP_DELAY register */
+uint16_t
+bhnd_pwrctl_fast_pwrup_delay(struct bhnd_pwrctl_softc *sc)
+{
+ uint32_t pll_on_delay, slowminfreq;
+ uint16_t fpdelay;
+
+ fpdelay = 0;
+
+ slowminfreq = bhnd_pwrctl_slowclk_freq(sc, false);
+
+ pll_on_delay = bhnd_bus_read_4(sc->res, CHIPC_PLL_ON_DELAY) + 2;
+ pll_on_delay *= 1000000;
+ pll_on_delay += (slowminfreq - 1);
+ fpdelay = pll_on_delay / slowminfreq;
+
+ return (fpdelay);
+}
+
+/**
+ * Distribute @p clock on backplane.
+ *
+ * @param sc Driver instance state.
+ * @param clock Clock to enable.
+ *
+ * @retval 0 success
+ * @retval ENODEV If @p clock is unsupported, or if the device does not
+ * support dynamic clock control.
+ */
+int
+bhnd_pwrctl_setclk(struct bhnd_pwrctl_softc *sc, bhnd_clock clock)
+{
+ uint32_t scc;
+
+ PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
+
+ /* Is dynamic clock control supported? */
+ if (PWRCTL_QUIRK(sc, FIXED_CLK))
+ return (ENODEV);
+
+ /* Chips with ccrev 10 are EOL and they don't have SYCC_HR used below */
+ if (bhnd_get_hwrev(sc->chipc_dev) == 10)
+ return (ENODEV);
+
+ scc = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL);
+
+ switch (clock) {
+ case BHND_CLOCK_HT:
+ /* fast (pll) clock */
+ if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
+ scc &= ~(CHIPC_SCC_XC | CHIPC_SCC_FS | CHIPC_SCC_IP);
+ scc |= CHIPC_SCC_IP;
+
+ /* force xtal back on before clearing SCC_DYN_XTAL.. */
+ bhnd_pwrctl_ungate_clock(sc->chipc_dev, BHND_CLOCK_HT);
+ } else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
+ scc |= CHIPC_SYCC_HR;
+ } else {
+ return (ENODEV);
+ }
+
+ bhnd_bus_write_4(sc->res, CHIPC_PLL_SLOWCLK_CTL, scc);
+ DELAY(CHIPC_PLL_DELAY);
+
+ break;
+
+ case BHND_CLOCK_DYN:
+ /* enable dynamic clock control */
+ if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
+ scc &= ~(CHIPC_SCC_FS | CHIPC_SCC_IP | CHIPC_SCC_XC);
+ if ((scc & CHIPC_SCC_SS_MASK) != CHIPC_SCC_SS_XTAL)
+ scc |= CHIPC_SCC_XC;
+
+ bhnd_bus_write_4(sc->res, CHIPC_PLL_SLOWCLK_CTL, scc);
+
+ /* 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_CLOCK_HT);
+ }
+ } else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
+ /* Instaclock */
+ scc &= ~CHIPC_SYCC_HR;
+ bhnd_bus_write_4(sc->res, CHIPC_SYS_CLK_CTL, scc);
+ } else {
+ return (ENODEV);
+ }
+
+ break;
+
+ default:
+ return (ENODEV);
+ }
+
+ return (0);
+}
diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h
new file mode 100644
index 000000000000..67b5015d03c4
--- /dev/null
+++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BHND_PWRCTL_BHND_PWRCTLVAR_H_
+#define _BHND_PWRCTL_BHND_PWRCTLVAR_H_
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/queue.h>
+
+/**
+ * bhnd pwrctl device quirks.
+ */
+enum {
+ /** No quirks */
+ PWRCTL_QUIRK_NONE = 0,
+
+ /**
+ * Early ChipCommon revisions do not support dynamic clock control
+ */
+ PWRCTL_QUIRK_FIXED_CLK = (1 << 0),
+
+ /**
+ * On PCI (not PCIe) devices, early ChipCommon revisions
+ * (rev <= 5) vend xtal/pll and clock config registers via the PCI
+ * config space.
+ *
+ * Dynamic clock control is not supported on these devices.
+ */
+ PWRCTL_QUIRK_PCICLK_CTL = (1 << 1) | PWRCTL_QUIRK_FIXED_CLK,
+
+
+ /**
+ * On earliy BCM4311, BCM4321, and BCM4716 PCI(e) devices, no ALP
+ * clock is available, and the HT clock must be enabled.
+ */
+ PWRCTL_QUIRK_FORCE_HT = (1 << 2),
+
+ /**
+ * ChipCommon revisions 6-9 use the slowclk register layout.
+ */
+ PWRCTL_QUIRK_SLOWCLK_CTL = (1 << 3),
+
+ /**
+ * ChipCommon revisions 10-19 support the instaclk register layout.
+ */
+ PWRCTL_QUIRK_INSTACLK_CTL = (1 << 4),
+
+};
+
+/**
+ * device clock reservation.
+ */
+struct bhnd_pwrctl_clkres {
+ device_t owner; /**< bhnd(4) device holding this reservation */
+ bhnd_clock clock; /**< requested clock */
+ STAILQ_ENTRY(bhnd_pwrctl_clkres) cr_link;
+};
+
+
+/**
+ * bhnd pwrctl driver instance state.
+ */
+struct bhnd_pwrctl_softc {
+ device_t dev;
+ uint32_t quirks;
+
+ device_t chipc_dev; /**< core device */
+ struct bhnd_resource *res; /**< core register block. */
+
+ struct mtx mtx; /**< state mutex */
+
+ /** active clock reservations */
+ STAILQ_HEAD(, bhnd_pwrctl_clkres) clkres_list;
+};
+
+#define PWRCTL_LOCK_INIT(sc) \
+ mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
+ "bhnd pwrctl driver lock", MTX_DEF)
+#define PWRCTL_LOCK(sc) mtx_lock(&(sc)->mtx)
+#define PWRCTL_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
+#define PWRCTL_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
+#define PWRCTL_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
+
+/* quirk convenience macro */
+#define PWRCTL_QUIRK(_sc, _name) \
+ ((_sc)->quirks & PWRCTL_QUIRK_ ## _name)
+
+#define PWRCTL_ASSERT_QUIRK(_sc, name) \
+ KASSERT(PWRCTL_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set"))
+
+#endif /* _BHND_PWRCTL_BHND_PWRCTLVAR_H_ */
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu.c b/sys/dev/bhnd/cores/pmu/bhnd_pmu.c
new file mode 100644
index 000000000000..6cc657f0e6ac
--- /dev/null
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu.c
@@ -0,0 +1,466 @@
+/*-
+ * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/bhnd/bhnd.h>
+
+#include "bhnd_nvram_map.h"
+
+#include "bhnd_pmureg.h"
+#include "bhnd_pmuvar.h"
+
+#include "bhnd_pmu_private.h"
+
+/*
+ * Broadcom PMU driver.
+ *
+ * On modern BHND chipsets, the PMU, GCI, and SRENG (Save/Restore Engine?)
+ * register blocks are found within a dedicated PMU core (attached via
+ * the AHB 'always on bus').
+ *
+ * On earlier chipsets, these register blocks are found at the same
+ * offsets within the ChipCommon core.
+ */
+
+devclass_t bhnd_pmu_devclass; /**< bhnd(4) PMU device class */
+
+static int bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS);
+static int bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS);
+static int bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS);
+
+#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().
+ */
+int
+bhnd_pmu_probe(device_t dev)
+{
+ return (BUS_PROBE_DEFAULT);
+}
+
+/**
+ * Default bhnd_pmu driver implementation of DEVICE_ATTACH().
+ *
+ * @param dev PMU device.
+ * @param res The PMU device registers. The driver will maintain a borrowed
+ * reference to this resource for the lifetime of the device.
+ */
+int
+bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
+{
+ struct bhnd_pmu_softc *sc;
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid *tree;
+ devclass_t bhnd_class;
+ device_t core, bus;
+ int error;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->quirks = 0;
+ sc->res = res;
+
+ /* Fetch capability flags */
+ sc->caps = bhnd_bus_read_4(sc->res, BHND_PMU_CAP);
+
+ /* Find the bus-attached core */
+ bhnd_class = devclass_find("bhnd");
+ core = sc->dev;
+ while ((bus = device_get_parent(core)) != NULL) {
+ if (device_get_devclass(bus) == bhnd_class)
+ break;
+
+ core = bus;
+ }
+
+ if (core == NULL) {
+ device_printf(sc->dev, "bhnd bus not found\n");
+ return (ENXIO);
+ }
+
+ /* Fetch chip and board info */
+ sc->cid = *bhnd_get_chipid(core);
+
+ if ((error = bhnd_read_board_info(core, &sc->board))) {
+ device_printf(sc->dev, "error fetching board info: %d\n",
+ error);
+ return (ENXIO);
+ }
+
+ /* Locate ChipCommon device */
+ sc->chipc_dev = bhnd_find_child(bus, BHND_DEVCLASS_CC, 0);
+ if (sc->chipc_dev == NULL) {
+ device_printf(sc->dev, "chipcommon device not found\n");
+ return (ENXIO);
+ }
+
+ BPMU_LOCK_INIT(sc);
+
+ /* Set quirk flags */
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4328:
+ case BHND_CHIPID_BCM5354:
+ /* HTAVAIL/ALPAVAIL are bitswapped in CLKCTL */
+ sc->quirks |= BPMU_QUIRK_CLKCTL_CCS0;
+ break;
+ default:
+ break;
+ }
+
+ /* Initialize PMU */
+ if ((error = bhnd_pmu_init(sc))) {
+ device_printf(sc->dev, "PMU init failed: %d\n", error);
+ goto failed;
+ }
+
+ /* Set up sysctl nodes */
+ ctx = device_get_sysctl_ctx(dev);
+ tree = device_get_sysctl_tree(dev);
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "bus_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0,
+ bhnd_pmu_sysctl_bus_freq, "IU", "Bus clock frequency");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "cpu_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0,
+ bhnd_pmu_sysctl_cpu_freq, "IU", "CPU clock frequency");
+
+ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "mem_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0,
+ bhnd_pmu_sysctl_mem_freq, "IU", "Memory clock frequency");
+
+ return (0);
+
+failed:
+ BPMU_LOCK_DESTROY(sc);
+ return (error);
+}
+
+/**
+ * Default bhnd_pmu driver implementation of DEVICE_DETACH().
+ */
+int
+bhnd_pmu_detach(device_t dev)
+{
+ struct bhnd_pmu_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ BPMU_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+/**
+ * Default bhnd_pmu driver implementation of DEVICE_SUSPEND().
+ */
+int
+bhnd_pmu_suspend(device_t dev)
+{
+ return (0);
+}
+
+/**
+ * Default bhnd_pmu driver implementation of DEVICE_RESUME().
+ */
+int
+bhnd_pmu_resume(device_t dev)
+{
+ struct bhnd_pmu_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ /* Re-initialize PMU */
+ if ((error = bhnd_pmu_init(sc))) {
+ device_printf(sc->dev, "PMU init failed: %d\n", error);
+ return (error);
+ }
+
+ return (0);
+}
+
+static int
+bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS)
+{
+ struct bhnd_pmu_softc *sc;
+ uint32_t freq;
+
+ sc = arg1;
+
+ BPMU_LOCK(sc);
+ freq = bhnd_pmu_si_clock(sc);
+ BPMU_UNLOCK(sc);
+
+ return (sysctl_handle_32(oidp, NULL, freq, req));
+}
+
+static int
+bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS)
+{
+ struct bhnd_pmu_softc *sc;
+ uint32_t freq;
+
+ sc = arg1;
+
+ BPMU_LOCK(sc);
+ freq = bhnd_pmu_cpu_clock(sc);
+ BPMU_UNLOCK(sc);
+
+ return (sysctl_handle_32(oidp, NULL, freq, req));
+}
+
+static int
+bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS)
+{
+ struct bhnd_pmu_softc *sc;
+ uint32_t freq;
+
+ sc = arg1;
+
+ BPMU_LOCK(sc);
+ freq = bhnd_pmu_mem_clock(sc);
+ BPMU_UNLOCK(sc);
+
+ 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)
+{
+ struct bhnd_pmu_softc *sc;
+ uint32_t avail;
+ uint32_t req;
+
+ sc = device_get_softc(dev);
+
+ 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(pinfo->pm_dev), clock);
+ return (ENODEV);
+ }
+
+ BPMU_LOCK(sc);
+
+ /* Issue request */
+ BPMU_CLKCTL_SET_4(pinfo, req, BHND_CCS_FORCE_MASK);
+
+ /* Wait for clock availability */
+ bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
+ avail, avail);
+
+ BPMU_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+bhnd_pmu_core_en_clocks(device_t dev, struct bhnd_core_pmu_info *pinfo,
+ uint32_t clocks)
+{
+ struct bhnd_pmu_softc *sc;
+ uint32_t avail;
+ uint32_t req;
+
+ sc = device_get_softc(dev);
+
+ avail = 0x0;
+ req = 0x0;
+
+ /* Build clock request flags */
+ if (clocks & BHND_CLOCK_DYN) /* nothing to enable */
+ clocks &= ~BHND_CLOCK_DYN;
+
+ if (clocks & BHND_CLOCK_ILP) /* nothing to enable */
+ clocks &= ~BHND_CLOCK_ILP;
+
+ if (clocks & BHND_CLOCK_ALP) {
+ req |= BHND_CCS_ALPAREQ;
+ avail |= BHND_CCS_ALPAVAIL;
+ clocks &= ~BHND_CLOCK_ALP;
+ }
+
+ if (clocks & BHND_CLOCK_HT) {
+ req |= BHND_CCS_HTAREQ;
+ avail |= BHND_CCS_HTAVAIL;
+ clocks &= ~BHND_CLOCK_HT;
+ }
+
+ /* Check for unknown clock values */
+ if (clocks != 0x0) {
+ device_printf(dev, "%s requested unknown clocks: %#x\n",
+ device_get_nameunit(pinfo->pm_dev), clocks);
+ return (ENODEV);
+ }
+
+ BPMU_LOCK(sc);
+
+ /* Issue request */
+ BPMU_CLKCTL_SET_4(pinfo, req, BHND_CCS_AREQ_MASK);
+
+ /* Wait for clock availability */
+ bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
+ avail, avail);
+
+ BPMU_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+bhnd_pmu_core_req_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo,
+ u_int rsrc)
+{
+ struct bhnd_pmu_softc *sc;
+ uint32_t req;
+ uint32_t avail;
+
+ sc = device_get_softc(dev);
+
+ if (rsrc > BHND_CCS_ERSRC_MAX)
+ return (EINVAL);
+
+ req = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
+ avail = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_STS);
+
+ BPMU_LOCK(sc);
+
+ /* Write request */
+ BPMU_CLKCTL_SET_4(pinfo, req, req);
+
+ /* Wait for resource availability */
+ bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs,
+ avail, avail);
+
+ BPMU_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+bhnd_pmu_core_release_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo,
+ u_int rsrc)
+{
+ struct bhnd_pmu_softc *sc;
+ uint32_t mask;
+
+ sc = device_get_softc(dev);
+
+ if (rsrc > BHND_CCS_ERSRC_MAX)
+ return (EINVAL);
+
+ mask = BHND_PMU_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
+
+ /* Clear request */
+ BPMU_LOCK(sc);
+ BPMU_CLKCTL_SET_4(pinfo, 0x0, mask);
+ BPMU_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+bhnd_pmu_core_release(device_t dev, struct bhnd_core_pmu_info *pinfo)
+{
+ struct bhnd_pmu_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ 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);
+
+ BPMU_UNLOCK(sc);
+
+ return (0);
+}
+
+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),
+
+ /* 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_END
+};
+
+DEFINE_CLASS_0(bhnd_pmu, bhnd_pmu_driver, bhnd_pmu_methods, sizeof(struct bhnd_pmu_softc));
+MODULE_VERSION(bhnd_pmu, 1);
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu.h b/sys/dev/bhnd/cores/pmu/bhnd_pmu.h
new file mode 100644
index 000000000000..64f4c8e5c645
--- /dev/null
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BHND_CORES_PMU_BHND_PMU_H_
+#define _BHND_CORES_PMU_BHND_PMU_H_
+
+#include <sys/types.h>
+
+#include "bhnd_pmu_if.h"
+
+/**
+ * Per-core PMU register information.
+ */
+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 */
+};
+
+#endif /* _BHND_CORES_PMU_BHND_PMU_H_ */
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c b/sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c
new file mode 100644
index 000000000000..2c2cf3d485a0
--- /dev/null
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c
@@ -0,0 +1,138 @@
+/*-
+ * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/bhnd/bhnd.h>
+
+#include "bhnd_pmureg.h"
+#include "bhnd_pmuvar.h"
+
+/*
+ * PMU core driver.
+ */
+
+/* Supported device identifiers */
+static const struct bhnd_device bhnd_pmucore_devices[] = {
+ BHND_DEVICE(BCM, PMU, NULL, NULL),
+
+ BHND_DEVICE_END
+};
+
+static int
+bhnd_pmu_core_probe(device_t dev)
+{
+ const struct bhnd_device *id;
+ int error;
+
+ id = bhnd_device_lookup(dev, bhnd_pmucore_devices,
+ sizeof(bhnd_pmucore_devices[0]));
+ if (id == NULL)
+ return (ENXIO);
+
+ /* Delegate to common driver implementation */
+ if ((error = bhnd_pmu_probe(dev)) > 0)
+ return (error);
+
+ bhnd_set_default_core_desc(dev);
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+bhnd_pmu_core_attach(device_t dev)
+{
+ struct bhnd_pmu_softc *sc;
+ struct bhnd_resource *res;
+ int error;
+ int rid;
+
+ sc = device_get_softc(dev);
+
+ /* Allocate register block */
+ rid = 0;
+ res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (res == NULL) {
+ device_printf(dev, "failed to allocate resources\n");
+ return (ENXIO);
+ }
+
+ /* Delegate to common driver implementation */
+ if ((error = bhnd_pmu_attach(dev, res))) {
+ bhnd_release_resource(dev, SYS_RES_MEMORY, rid, res);
+ return (error);
+ }
+
+ sc->rid = rid;
+ return (0);
+}
+
+static int
+bhnd_pmu_core_detach(device_t dev)
+{
+ struct bhnd_pmu_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ /* Delegate to common driver implementation */
+ if ((error = bhnd_pmu_detach(dev)))
+ return (error);
+
+ bhnd_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
+ return (0);
+}
+
+static device_method_t bhnd_pmucore_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, bhnd_pmu_core_probe),
+ DEVMETHOD(device_attach, bhnd_pmu_core_attach),
+ DEVMETHOD(device_detach, bhnd_pmu_core_detach),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(bhnd_pmu, bhnd_pmucore_driver, bhnd_pmucore_methods,
+ sizeof(struct bhnd_pmu_softc), bhnd_pmu_driver);
+EARLY_DRIVER_MODULE(bhnd_pmu, bhnd, bhnd_pmucore_driver, bhnd_pmu_devclass,
+ NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
+
+MODULE_DEPEND(bhnd_pmu_core, bhnd_pmu, 1, 1, 1);
+MODULE_VERSION(bhnd_pmu_core, 1);
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m b/sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m
new file mode 100644
index 000000000000..dc27cfd6ceac
--- /dev/null
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m
@@ -0,0 +1,130 @@
+#-
+# Copyright (c) 2016 Landon Fuller <landon@landonf.org>
+# 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.
+# 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_pmu;
+
+#
+# bhnd(4) PMU interface.
+#
+# Provides a common PMU and clock control interface.
+#
+
+HEADER {
+ struct bhnd_core_pmu_info;
+}
+
+/**
+ * Enabling routing of @p clock (or faster) to a requesting core.
+ *
+ * @param dev PMU device.
+ * @param pinfo PMU info for requesting core.
+ * @param clock Clock requested.
+ *
+ * @retval 0 success
+ * @retval ENODEV If an unsupported clock was requested.
+ */
+METHOD int core_req_clock {
+ device_t dev;
+ struct bhnd_core_pmu_info *pinfo;
+ bhnd_clock clock;
+};
+
+
+/**
+ * Request that @p clocks be powered on behalf of a requesting core.
+ *
+ * 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.
+ *
+ * Requests from multiple devices are aggregated by the PMU.
+ *
+ * @param dev PMU device.
+ * @param pinfo PMU info for requesting core.
+ * @param clocks Clocks requested.
+ *
+ * @retval 0 success
+ * @retval ENODEV If an unsupported clock was requested.
+ */
+METHOD int core_en_clocks {
+ device_t dev;
+ struct bhnd_core_pmu_info *pinfo;
+ uint32_t clocks;
+};
+
+/**
+ * Power up a core-specific external resource.
+ *
+ * @param dev The parent of @p child.
+ * @param pinfo PMU info for requesting core.
+ * @param rsrc The core-specific external resource identifier.
+ *
+ * @retval 0 success
+ * @retval ENODEV If @p rsrc is not supported by this PMU driver.
+ */
+METHOD int core_req_ext_rsrc {
+ device_t dev;
+ struct bhnd_core_pmu_info *pinfo;
+ u_int rsrc;
+};
+
+/**
+ * Power down a core-specific external resource.
+ *
+ * @param dev The parent of @p child.
+ * @param pinfo PMU info for requesting core.
+ * @param rsrc The core-specific external resource identifier.
+ *
+ * @retval 0 success
+ * @retval ENODEV If @p rsrc is not supported by this PMU driver.
+ */
+METHOD int core_release_ext_rsrc {
+ device_t dev;
+ struct bhnd_core_pmu_info *pinfo;
+ u_int rsrc;
+};
+
+/**
+ * Release all outstanding requests (clocks, resources, etc) associated with
+ * @p pinfo.
+ *
+ * @param dev PMU device.
+ * @param pinfo PMU info for requesting core.
+ *
+ * @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.
+ */
+METHOD int core_release {
+ device_t dev;
+ struct bhnd_core_pmu_info *pinfo;
+};
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h b/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h
new file mode 100644
index 000000000000..ee705eac880c
--- /dev/null
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
+ * Copyright (C) 2010, Broadcom Corporation.
+ * All rights reserved.
+ *
+ * This file is derived from the hndpmu.h header contributed by Broadcom
+ * to to the Linux staging repository, as well as later revisions of hndpmu.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$
+ */
+
+#ifndef _BHND_CORES_PMU_BHND_PMU_PRIVATE_H_
+#define _BHND_CORES_PMU_BHND_PMU_PRIVATE_H_
+
+#include <sys/types.h>
+
+#include "bhnd_pmuvar.h"
+
+/* Register I/O */
+#define BHND_PMU_READ_1(_sc, _reg) bhnd_bus_read_1((_sc)->res, (_reg))
+#define BHND_PMU_READ_2(_sc, _reg) bhnd_bus_read_2((_sc)->res, (_reg))
+#define BHND_PMU_READ_4(_sc, _reg) bhnd_bus_read_4((_sc)->res, (_reg))
+#define BHND_PMU_WRITE_1(_sc, _reg, _val) \
+ bhnd_bus_write_1((_sc)->res, (_reg), (_val))
+#define BHND_PMU_WRITE_2(_sc, _reg, _val) \
+ bhnd_bus_write_2((_sc)->res, (_reg), (_val))
+#define BHND_PMU_WRITE_4(_sc, _reg, _val) \
+ bhnd_bus_write_4((_sc)->res, (_reg), (_val))
+
+#define BHND_PMU_AND_4(_sc, _reg, _val) \
+ BHND_PMU_WRITE_4((_sc), (_reg), \
+ BHND_PMU_READ_4((_sc), (_reg)) & (_val))
+#define BHND_PMU_OR_4(_sc, _reg, _val) \
+ BHND_PMU_WRITE_4((_sc), (_reg), \
+ BHND_PMU_READ_4((_sc), (_reg)) | (_val))
+
+/* Indirect register support */
+#define BHND_PMU_IND_READ(_sc, _src, _reg) \
+ bhnd_pmu_ind_read((_sc), BHND_PMU_ ## _src ## _ADDR, \
+ BHND_PMU_ ## _src ## _DATA, (_reg))
+#define BHND_PMU_IND_WRITE(_sc, _src, _reg, _val, _mask) \
+ bhnd_pmu_ind_write(sc, BHND_PMU_ ## _src ## _ADDR, \
+ BHND_PMU_ ## _src ## _DATA, (_reg), (_val), (_mask))
+
+/* Chip Control indirect registers */
+#define BHND_PMU_CCTRL_READ(_sc, _reg) \
+ BHND_PMU_IND_READ((_sc), CHIPCTL, (_reg))
+#define BHND_PMU_CCTRL_WRITE(_sc, _reg, _val, _mask) \
+ BHND_PMU_IND_WRITE((_sc), CHIPCTL, (_reg), (_val), (_mask))
+
+/* Register 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) \
+ BHND_PMU_IND_WRITE((_sc), REG_CONTROL, (_reg), (_val), (_mask))
+
+/* PLL Control indirect registers */
+#define BHND_PMU_PLL_READ(_sc, _reg) \
+ BHND_PMU_IND_READ((_sc), PLL_CONTROL, (_reg))
+#define BHND_PMU_PLL_WRITE(_sc, _reg, _val, _mask) \
+ BHND_PMU_IND_WRITE((_sc), PLL_CONTROL, (_reg), (_val), (_mask))
+
+
+/** FVCO frequencies, in Hz */
+enum {
+ FVCO_880 = 880 * 1000, /**< 880MHz */
+ FVCO_1760 = 1760 * 1000, /**< 1760MHz */
+ FVCO_1440 = 1440 * 1000, /**< 1440MHz */
+ FVCO_960 = 960 * 1000, /**< 960MHz */
+};
+
+/** LDO voltage tunables */
+enum {
+ SET_LDO_VOLTAGE_LDO1 = 1,
+ SET_LDO_VOLTAGE_LDO2 = 2,
+ SET_LDO_VOLTAGE_LDO3 = 3,
+ SET_LDO_VOLTAGE_PAREF = 4,
+ SET_LDO_VOLTAGE_CLDO_PWM = 5,
+ SET_LDO_VOLTAGE_CLDO_BURST = 6,
+ SET_LDO_VOLTAGE_CBUCK_PWM = 7,
+ SET_LDO_VOLTAGE_CBUCK_BURST = 8,
+ SET_LDO_VOLTAGE_LNLDO1 = 9,
+ SET_LDO_VOLTAGE_LNLDO2_SEL = 10,
+};
+
+uint32_t bhnd_pmu_ind_read(struct bhnd_pmu_softc *sc, bus_size_t addr,
+ bus_size_t data, uint32_t reg);
+void bhnd_pmu_ind_write(struct bhnd_pmu_softc *sc, 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);
+void bhnd_pmu_swreg_init(struct bhnd_pmu_softc *sc);
+
+uint32_t bhnd_pmu_force_ilp(struct bhnd_pmu_softc *sc, bool force);
+
+uint32_t bhnd_pmu_si_clock(struct bhnd_pmu_softc *sc);
+uint32_t bhnd_pmu_cpu_clock(struct bhnd_pmu_softc *sc);
+uint32_t bhnd_pmu_mem_clock(struct bhnd_pmu_softc *sc);
+uint32_t bhnd_pmu_alp_clock(struct bhnd_pmu_softc *sc);
+uint32_t bhnd_pmu_ilp_clock(struct bhnd_pmu_softc *sc);
+
+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,
+ uint8_t ldo, uint8_t voltage);
+int bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc,
+ uint16_t *pwrup_delay);
+void bhnd_pmu_rcal(struct bhnd_pmu_softc *sc);
+void bhnd_pmu_spuravoid(struct bhnd_pmu_softc *sc,
+ uint8_t spuravoid);
+
+bool bhnd_pmu_is_otp_powered(struct bhnd_pmu_softc *sc);
+uint32_t bhnd_pmu_measure_alpclk(struct bhnd_pmu_softc *sc);
+
+void bhnd_pmu_radio_enable(struct bhnd_pmu_softc *sc,
+ device_t d11core, bool enable);
+
+uint32_t bhnd_pmu_waitforclk_on_backplane(struct bhnd_pmu_softc *sc,
+ uint32_t clk, uint32_t delay);
+
+int bhnd_pmu_otp_power(struct bhnd_pmu_softc *sc, bool on);
+void bhnd_pmu_sdiod_drive_strength_init(struct bhnd_pmu_softc *sc,
+ uint32_t drivestrength);
+
+void bhnd_pmu_paref_ldo_enable(struct bhnd_pmu_softc *sc,
+ bool enable);
+
+#endif /* _BHND_CORES_PMU_BHND_PMU_PRIVATE_H_ */
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c b/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
new file mode 100644
index 000000000000..682baf17ce8e
--- /dev/null
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
@@ -0,0 +1,3446 @@
+/*-
+ * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
+ * Copyright (C) 2010, Broadcom Corporation.
+ * All rights reserved.
+ *
+ * This file is derived from the hndpmu.c source contributed by Broadcom
+ * to to the Linux staging repository, as well as later revisions of hndpmu.c
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/cores/chipc/chipc.h>
+#include <dev/bhnd/cores/chipc/chipcreg.h>
+
+#include <dev/bhnd/bcma/bcma_dmp.h>
+
+#include "bhnd_nvram_map.h"
+
+#include "bhnd_pmureg.h"
+#include "bhnd_pmuvar.h"
+
+#include "bhnd_pmu_private.h"
+
+#ifdef BCMDBG
+#define PMU_MSG(args) printf args
+#define PMU_ERROR(args) do { \
+ panic args; \
+} while (0)
+#else
+#define PMU_MSG(args)
+#define PMU_ERROR(args) printf args
+#endif
+
+typedef struct pmu0_xtaltab0 pmu0_xtaltab0_t;
+typedef struct pmu1_xtaltab0 pmu1_xtaltab0_t;
+
+/* PLL controls/clocks */
+static const pmu1_xtaltab0_t *bhnd_pmu1_xtaltab0(struct bhnd_pmu_softc *sc);
+static const pmu1_xtaltab0_t *bhnd_pmu1_xtaldef0(struct bhnd_pmu_softc *sc);
+
+static void bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal);
+static uint32_t bhnd_pmu0_cpuclk0(struct bhnd_pmu_softc *sc);
+static uint32_t bhnd_pmu0_alpclk0(struct bhnd_pmu_softc *sc);
+
+static void bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal);
+static uint32_t bhnd_pmu1_pllfvco0(struct bhnd_pmu_softc *sc);
+static uint32_t bhnd_pmu1_cpuclk0(struct bhnd_pmu_softc *sc);
+static uint32_t bhnd_pmu1_alpclk0(struct bhnd_pmu_softc *sc);
+
+static uint32_t bhnd_pmu5_clock(struct bhnd_pmu_softc *sc, u_int pll0, u_int m);
+
+/* PMU resources */
+static bool bhnd_pmu_res_depfltr_bb(struct bhnd_pmu_softc *sc);
+static bool bhnd_pmu_res_depfltr_ncb(struct bhnd_pmu_softc *sc);
+static bool bhnd_pmu_res_depfltr_paldo(struct bhnd_pmu_softc *sc);
+static bool bhnd_pmu_res_depfltr_npaldo(struct bhnd_pmu_softc *sc);
+static uint32_t bhnd_pmu_res_deps(struct bhnd_pmu_softc *sc, uint32_t rsrcs,
+ bool all);
+static int bhnd_pmu_res_uptime(struct bhnd_pmu_softc *sc, uint8_t rsrc,
+ uint32_t *uptime);
+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 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 PMURES_BIT(_bit) \
+ (1 << (BHND_PMU_ ## _bit))
+
+#define PMU_CST4330_SDIOD_CHIPMODE(_sc) \
+ CHIPC_CST4330_CHIPMODE_SDIOD(BHND_CHIPC_READ_CHIPST((_sc)->chipc_dev))
+
+/**
+ * Perform an indirect register read.
+ *
+ * @param addr Offset of the address register.
+ * @param data Offset of the data register.
+ * @param reg Indirect register to be read.
+ */
+uint32_t
+bhnd_pmu_ind_read(struct bhnd_pmu_softc *sc, bus_size_t addr, bus_size_t data,
+ uint32_t reg)
+{
+ BHND_PMU_WRITE_4(sc, addr, reg);
+ return (BHND_PMU_READ_4(sc, data));
+}
+
+/**
+ * Perform an indirect register write.
+ *
+ * @param addr Offset of the address register.
+ * @param data Offset of the data register.
+ * @param reg Indirect register to be written.
+ * @param val Value to be written to @p reg.
+ * @param mask Only the bits defined by @p mask will be updated from @p val.
+ */
+void
+bhnd_pmu_ind_write(struct bhnd_pmu_softc *sc, bus_size_t addr,
+ bus_size_t data, uint32_t reg, uint32_t val, uint32_t mask)
+{
+ uint32_t rval;
+
+ BHND_PMU_WRITE_4(sc, addr, reg);
+
+ if (mask != UINT32_MAX) {
+ rval = BHND_PMU_READ_4(sc, data);
+ rval &= ~mask | (val & mask);
+ } else {
+ rval = val;
+ }
+
+ BHND_PMU_WRITE_4(sc, data, rval);
+}
+
+/**
+ * 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,
+ uint8_t rf_voltage)
+{
+ BHND_PMU_REGCTRL_WRITE(sc, 0x01, (bb_voltage & 0x1f) << 22, ~0);
+ BHND_PMU_REGCTRL_WRITE(sc, 0x00, (rf_voltage & 0x1f) << 14, ~0);
+}
+
+void
+bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc, uint8_t ldo,
+ uint8_t voltage)
+{
+ uint32_t chipst;
+ uint32_t regctrl;
+ uint8_t shift;
+ uint8_t mask;
+ uint8_t addr;
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4328:
+ case BHND_CHIPID_BCM5354:
+ switch (ldo) {
+ case SET_LDO_VOLTAGE_LDO1:
+ addr = 2;
+ shift = 17 + 8;
+ mask = 0xf;
+ break;
+ case SET_LDO_VOLTAGE_LDO2:
+ addr = 3;
+ shift = 1;
+ mask = 0xf;
+ break;
+ case SET_LDO_VOLTAGE_LDO3:
+ addr = 3;
+ shift = 9;
+ mask = 0xf;
+ break;
+ case SET_LDO_VOLTAGE_PAREF:
+ addr = 3;
+ shift = 17;
+ mask = 0x3f;
+ break;
+ default:
+ panic("unknown BCM4328/BCM5354 LDO %hhu\n", ldo);
+ }
+ break;
+ case BHND_CHIPID_BCM4312:
+ switch (ldo) {
+ case SET_LDO_VOLTAGE_PAREF:
+ addr = 0;
+ shift = 21;
+ mask = 0x3f;
+ break;
+ default:
+ panic("unknown BCM4312 LDO %hhu\n", ldo);
+ }
+ break;
+ case BHND_CHIPID_BCM4325:
+ switch (ldo) {
+ case SET_LDO_VOLTAGE_CLDO_PWM:
+ addr = 5;
+ shift = 9;
+ mask = 0xf;
+ break;
+ case SET_LDO_VOLTAGE_CLDO_BURST:
+ addr = 5;
+ shift = 13;
+ mask = 0xf;
+ break;
+ case SET_LDO_VOLTAGE_CBUCK_PWM:
+ addr = 3;
+ shift = 20;
+ mask = 0x1f;
+ /* Bit 116 & 119 are inverted in CLB for opt 2b */
+ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
+ if (BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_PMUTOP_2B))
+ voltage ^= 0x9;
+ break;
+ case SET_LDO_VOLTAGE_CBUCK_BURST:
+ addr = 3;
+ shift = 25;
+ mask = 0x1f;
+ /* Bit 121 & 124 are inverted in CLB for opt 2b */
+ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
+ if (BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_PMUTOP_2B))
+ voltage ^= 0x9;
+ break;
+ case SET_LDO_VOLTAGE_LNLDO1:
+ addr = 5;
+ shift = 17;
+ mask = 0x1f;
+ break;
+ case SET_LDO_VOLTAGE_LNLDO2_SEL:
+ addr = 6;
+ shift = 0;
+ mask = 0x1;
+ break;
+ default:
+ panic("unknown BCM4325 LDO %hhu\n", ldo);
+ }
+ break;
+ case BHND_CHIPID_BCM4336:
+ switch (ldo) {
+ case SET_LDO_VOLTAGE_CLDO_PWM:
+ addr = 4;
+ shift = 1;
+ mask = 0xf;
+ break;
+ case SET_LDO_VOLTAGE_CLDO_BURST:
+ addr = 4;
+ shift = 5;
+ mask = 0xf;
+ break;
+ case SET_LDO_VOLTAGE_LNLDO1:
+ addr = 4;
+ shift = 17;
+ mask = 0xf;
+ break;
+ default:
+ panic("unknown BCM4336 LDO %hhu\n", ldo);
+ }
+ break;
+ case BHND_CHIPID_BCM4330:
+ switch (ldo) {
+ case SET_LDO_VOLTAGE_CBUCK_PWM:
+ addr = 3;
+ shift = 0;
+ mask = 0x1f;
+ break;
+ default:
+ panic("unknown BCM4330 LDO %hhu\n", ldo);
+ }
+ break;
+ case BHND_CHIPID_BCM4331:
+ switch (ldo) {
+ case SET_LDO_VOLTAGE_PAREF:
+ addr = 1;
+ shift = 0;
+ mask = 0xf;
+ break;
+ default:
+ panic("unknown BCM4331 LDO %hhu\n", ldo);
+ }
+ break;
+ default:
+ panic("cannot set LDO voltage on unsupported chip %hu\n",
+ sc->cid.chip_id);
+ return;
+ }
+
+ regctrl = (voltage & mask) << shift;
+ BHND_PMU_REGCTRL_WRITE(sc, addr, regctrl, mask << shift);
+}
+
+/* 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)
+{
+ uint32_t ilp;
+ uint32_t uptime;
+ u_int delay;
+ int error;
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM43224:
+ case BHND_CHIPID_BCM43225:
+ case BHND_CHIPID_BCM43421:
+ case BHND_CHIPID_BCM43235:
+ case BHND_CHIPID_BCM43236:
+ case BHND_CHIPID_BCM43238:
+ case BHND_CHIPID_BCM4331:
+ case BHND_CHIPID_BCM6362:
+ case BHND_CHIPID_BCM4313:
+ delay = 3700;
+ break;
+
+ case BHND_CHIPID_BCM4325:
+ error = bhnd_pmu_res_uptime(sc, BHND_PMU_RES4325_HT_AVAIL,
+ &uptime);
+ if (error)
+ return (error);
+
+ ilp = bhnd_pmu_ilp_clock(sc);
+ delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
+ ((1000000 + ilp - 1) / ilp);
+ delay = (11 * delay) / 10;
+ break;
+
+ case BHND_CHIPID_BCM4329:
+ error = bhnd_pmu_res_uptime(sc, BHND_PMU_RES4329_HT_AVAIL,
+ &uptime);
+ if (error)
+ return (error);
+
+ ilp = bhnd_pmu_ilp_clock(sc);
+ delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
+ ((1000000 + ilp - 1) / ilp);
+ delay = (11 * delay) / 10;
+ break;
+
+ case BHND_CHIPID_BCM4319:
+ delay = 3700;
+ break;
+
+ case BHND_CHIPID_BCM4336:
+ error = bhnd_pmu_res_uptime(sc, BHND_PMU_RES4336_HT_AVAIL,
+ &uptime);
+ if (error)
+ return (error);
+
+ ilp = bhnd_pmu_ilp_clock(sc);
+ delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
+ ((1000000 + ilp - 1) / ilp);
+ delay = (11 * delay) / 10;
+ break;
+
+ case BHND_CHIPID_BCM4330:
+ error = bhnd_pmu_res_uptime(sc, BHND_PMU_RES4330_HT_AVAIL,
+ &uptime);
+ if (error)
+ return (error);
+
+ ilp = bhnd_pmu_ilp_clock(sc);
+ delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
+ ((1000000 + ilp - 1) / ilp);
+ delay = (11 * delay) / 10;
+ break;
+
+ default:
+ delay = BHND_PMU_MAX_TRANSITION_DLY;
+ break;
+ }
+
+ *pwrup_delay = (uint16_t)delay;
+ return (0);
+}
+
+uint32_t
+bhnd_pmu_force_ilp(struct bhnd_pmu_softc *sc, bool force)
+{
+ uint32_t orig;
+ uint32_t pctrl;
+
+ pctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
+ orig = pctrl;
+
+ if (force)
+ pctrl &= ~(BHND_PMU_CTRL_HT_REQ_EN | BHND_PMU_CTRL_ALP_REQ_EN);
+ else
+ pctrl |= (BHND_PMU_CTRL_HT_REQ_EN | BHND_PMU_CTRL_ALP_REQ_EN);
+
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CTRL, pctrl);
+
+ return (orig);
+}
+
+/* Setup resource up/down timers */
+typedef struct {
+ uint8_t resnum;
+ uint16_t updown;
+} pmu_res_updown_t;
+
+typedef bool (*pmu_res_filter) (struct bhnd_pmu_softc *sc);
+
+/* Change resource dependencies masks */
+typedef struct {
+ uint32_t res_mask; /* resources (chip specific) */
+ int8_t action; /* action */
+ uint32_t depend_mask; /* changes to the dependencies mask */
+ pmu_res_filter filter; /* action is taken when filter is NULL or returns true */
+} pmu_res_depend_t;
+
+/* Resource dependencies mask change action */
+#define RES_DEPEND_SET 0 /* Override the dependencies mask */
+#define RES_DEPEND_ADD 1 /* Add to the dependencies mask */
+#define RES_DEPEND_REMOVE -1 /* Remove from the dependencies mask */
+
+static const pmu_res_updown_t bcm4328a0_res_updown[] = {
+ {
+ BHND_PMU_RES4328_EXT_SWITCHER_PWM, 0x0101}, {
+ BHND_PMU_RES4328_BB_SWITCHER_PWM, 0x1f01}, {
+ BHND_PMU_RES4328_BB_SWITCHER_BURST, 0x010f}, {
+ BHND_PMU_RES4328_BB_EXT_SWITCHER_BURST, 0x0101}, {
+ BHND_PMU_RES4328_ILP_REQUEST, 0x0202}, {
+ BHND_PMU_RES4328_RADIO_SWITCHER_PWM, 0x0f01}, {
+ BHND_PMU_RES4328_RADIO_SWITCHER_BURST, 0x0f01}, {
+ BHND_PMU_RES4328_ROM_SWITCH, 0x0101}, {
+ BHND_PMU_RES4328_PA_REF_LDO, 0x0f01}, {
+ BHND_PMU_RES4328_RADIO_LDO, 0x0f01}, {
+ BHND_PMU_RES4328_AFE_LDO, 0x0f01}, {
+ BHND_PMU_RES4328_PLL_LDO, 0x0f01}, {
+ BHND_PMU_RES4328_BG_FILTBYP, 0x0101}, {
+ BHND_PMU_RES4328_TX_FILTBYP, 0x0101}, {
+ BHND_PMU_RES4328_RX_FILTBYP, 0x0101}, {
+ BHND_PMU_RES4328_XTAL_PU, 0x0101}, {
+ BHND_PMU_RES4328_XTAL_EN, 0xa001}, {
+ BHND_PMU_RES4328_BB_PLL_FILTBYP, 0x0101}, {
+ BHND_PMU_RES4328_RF_PLL_FILTBYP, 0x0101}, {
+ BHND_PMU_RES4328_BB_PLL_PU, 0x0701}
+};
+
+static const pmu_res_depend_t bcm4328a0_res_depend[] = {
+ /* Adjust ILP request resource not to force ext/BB switchers into burst mode */
+ {
+ PMURES_BIT(RES4328_ILP_REQUEST),
+ RES_DEPEND_SET,
+ PMURES_BIT(RES4328_EXT_SWITCHER_PWM) |
+ PMURES_BIT(RES4328_BB_SWITCHER_PWM), NULL}
+};
+
+static const pmu_res_updown_t bcm4325a0_res_updown[] = {
+ {
+ BHND_PMU_RES4325_XTAL_PU, 0x1501}
+};
+
+static const pmu_res_depend_t bcm4325a0_res_depend[] = {
+ /* Adjust OTP PU resource dependencies - remove BB BURST */
+ {
+ PMURES_BIT(RES4325_OTP_PU),
+ RES_DEPEND_REMOVE,
+ PMURES_BIT(RES4325_BUCK_BOOST_BURST), NULL},
+ /* Adjust ALP/HT Avail resource dependencies - bring up BB along if it is used. */
+ {
+ PMURES_BIT(RES4325_ALP_AVAIL) | PMURES_BIT(RES4325_HT_AVAIL),
+ RES_DEPEND_ADD,
+ PMURES_BIT(RES4325_BUCK_BOOST_BURST) |
+ PMURES_BIT(RES4325_BUCK_BOOST_PWM), bhnd_pmu_res_depfltr_bb},
+ /* Adjust HT Avail resource dependencies - bring up RF switches along with HT. */
+ {
+ PMURES_BIT(RES4325_HT_AVAIL),
+ RES_DEPEND_ADD,
+ PMURES_BIT(RES4325_RX_PWRSW_PU) |
+ PMURES_BIT(RES4325_TX_PWRSW_PU) |
+ PMURES_BIT(RES4325_LOGEN_PWRSW_PU) |
+ PMURES_BIT(RES4325_AFE_PWRSW_PU), NULL},
+ /* Adjust ALL resource dependencies - remove CBUCK dependencies if it is not used. */
+ {
+ PMURES_BIT(RES4325_ILP_REQUEST) |
+ PMURES_BIT(RES4325_ABUCK_BURST) |
+ PMURES_BIT(RES4325_ABUCK_PWM) |
+ PMURES_BIT(RES4325_LNLDO1_PU) |
+ PMURES_BIT(RES4325C1_LNLDO2_PU) |
+ PMURES_BIT(RES4325_XTAL_PU) |
+ PMURES_BIT(RES4325_ALP_AVAIL) |
+ PMURES_BIT(RES4325_RX_PWRSW_PU) |
+ PMURES_BIT(RES4325_TX_PWRSW_PU) |
+ PMURES_BIT(RES4325_RFPLL_PWRSW_PU) |
+ PMURES_BIT(RES4325_LOGEN_PWRSW_PU) |
+ PMURES_BIT(RES4325_AFE_PWRSW_PU) |
+ PMURES_BIT(RES4325_BBPLL_PWRSW_PU) |
+ PMURES_BIT(RES4325_HT_AVAIL), RES_DEPEND_REMOVE,
+ PMURES_BIT(RES4325B0_CBUCK_LPOM) |
+ PMURES_BIT(RES4325B0_CBUCK_BURST) |
+ PMURES_BIT(RES4325B0_CBUCK_PWM), bhnd_pmu_res_depfltr_ncb}
+};
+
+static const pmu_res_updown_t bcm4315a0_res_updown[] = {
+ {
+ BHND_PMU_RES4315_XTAL_PU, 0x2501}
+};
+
+static const pmu_res_depend_t bcm4315a0_res_depend[] = {
+ /* Adjust OTP PU resource dependencies - not need PALDO unless write */
+ {
+ PMURES_BIT(RES4315_OTP_PU),
+ RES_DEPEND_REMOVE,
+ PMURES_BIT(RES4315_PALDO_PU), bhnd_pmu_res_depfltr_npaldo},
+ /* Adjust ALP/HT Avail resource dependencies - bring up PALDO along if it is used. */
+ {
+ PMURES_BIT(RES4315_ALP_AVAIL) | PMURES_BIT(RES4315_HT_AVAIL),
+ RES_DEPEND_ADD,
+ PMURES_BIT(RES4315_PALDO_PU), bhnd_pmu_res_depfltr_paldo},
+ /* Adjust HT Avail resource dependencies - bring up RF switches along with HT. */
+ {
+ PMURES_BIT(RES4315_HT_AVAIL),
+ RES_DEPEND_ADD,
+ PMURES_BIT(RES4315_RX_PWRSW_PU) |
+ PMURES_BIT(RES4315_TX_PWRSW_PU) |
+ PMURES_BIT(RES4315_LOGEN_PWRSW_PU) |
+ PMURES_BIT(RES4315_AFE_PWRSW_PU), NULL},
+ /* Adjust ALL resource dependencies - remove CBUCK dependencies if it is not used. */
+ {
+ PMURES_BIT(RES4315_CLDO_PU) | PMURES_BIT(RES4315_ILP_REQUEST) |
+ PMURES_BIT(RES4315_LNLDO1_PU) |
+ PMURES_BIT(RES4315_OTP_PU) |
+ PMURES_BIT(RES4315_LNLDO2_PU) |
+ PMURES_BIT(RES4315_XTAL_PU) |
+ PMURES_BIT(RES4315_ALP_AVAIL) |
+ PMURES_BIT(RES4315_RX_PWRSW_PU) |
+ PMURES_BIT(RES4315_TX_PWRSW_PU) |
+ PMURES_BIT(RES4315_RFPLL_PWRSW_PU) |
+ PMURES_BIT(RES4315_LOGEN_PWRSW_PU) |
+ PMURES_BIT(RES4315_AFE_PWRSW_PU) |
+ PMURES_BIT(RES4315_BBPLL_PWRSW_PU) |
+ PMURES_BIT(RES4315_HT_AVAIL), RES_DEPEND_REMOVE,
+ PMURES_BIT(RES4315_CBUCK_LPOM) |
+ PMURES_BIT(RES4315_CBUCK_BURST) |
+ PMURES_BIT(RES4315_CBUCK_PWM), bhnd_pmu_res_depfltr_ncb}
+};
+
+/* 4329 specific. needs to come back this issue later */
+static const pmu_res_updown_t bcm4329_res_updown[] = {
+ {
+ BHND_PMU_RES4329_XTAL_PU, 0x1501}
+};
+
+static const pmu_res_depend_t bcm4329_res_depend[] = {
+ /* Adjust HT Avail resource dependencies */
+ {
+ PMURES_BIT(RES4329_HT_AVAIL),
+ RES_DEPEND_ADD,
+ PMURES_BIT(RES4329_CBUCK_LPOM) |
+ PMURES_BIT(RES4329_CBUCK_BURST) |
+ PMURES_BIT(RES4329_CBUCK_PWM) |
+ PMURES_BIT(RES4329_CLDO_PU) |
+ PMURES_BIT(RES4329_PALDO_PU) |
+ PMURES_BIT(RES4329_LNLDO1_PU) |
+ PMURES_BIT(RES4329_XTAL_PU) |
+ PMURES_BIT(RES4329_ALP_AVAIL) |
+ PMURES_BIT(RES4329_RX_PWRSW_PU) |
+ PMURES_BIT(RES4329_TX_PWRSW_PU) |
+ PMURES_BIT(RES4329_RFPLL_PWRSW_PU) |
+ PMURES_BIT(RES4329_LOGEN_PWRSW_PU) |
+ PMURES_BIT(RES4329_AFE_PWRSW_PU) |
+ PMURES_BIT(RES4329_BBPLL_PWRSW_PU), NULL}
+};
+
+static const pmu_res_updown_t bcm4319a0_res_updown[] = {
+ {
+ BHND_PMU_RES4319_XTAL_PU, 0x3f01}
+};
+
+static const pmu_res_depend_t bcm4319a0_res_depend[] = {
+ /* Adjust OTP PU resource dependencies - not need PALDO unless write */
+ {
+ PMURES_BIT(RES4319_OTP_PU),
+ RES_DEPEND_REMOVE,
+ PMURES_BIT(RES4319_PALDO_PU), bhnd_pmu_res_depfltr_npaldo},
+ /* Adjust HT Avail resource dependencies - bring up PALDO along if it is used. */
+ {
+ PMURES_BIT(RES4319_HT_AVAIL),
+ RES_DEPEND_ADD,
+ PMURES_BIT(RES4319_PALDO_PU), bhnd_pmu_res_depfltr_paldo},
+ /* Adjust HT Avail resource dependencies - bring up RF switches along with HT. */
+ {
+ PMURES_BIT(RES4319_HT_AVAIL),
+ RES_DEPEND_ADD,
+ PMURES_BIT(RES4319_RX_PWRSW_PU) |
+ PMURES_BIT(RES4319_TX_PWRSW_PU) |
+ PMURES_BIT(RES4319_RFPLL_PWRSW_PU) |
+ PMURES_BIT(RES4319_LOGEN_PWRSW_PU) |
+ PMURES_BIT(RES4319_AFE_PWRSW_PU), NULL}
+};
+
+static const pmu_res_updown_t bcm4336a0_res_updown[] = {
+ {
+ BHND_PMU_RES4336_HT_AVAIL, 0x0D01}
+};
+
+static const pmu_res_depend_t bcm4336a0_res_depend[] = {
+ /* Just a dummy entry for now */
+ {
+ PMURES_BIT(RES4336_RSVD), RES_DEPEND_ADD, 0, NULL}
+};
+
+static const pmu_res_updown_t bcm4330a0_res_updown[] = {
+ {
+ BHND_PMU_RES4330_HT_AVAIL, 0x0e02}
+};
+
+static const pmu_res_depend_t bcm4330a0_res_depend[] = {
+ /* Just a dummy entry for now */
+ {
+ PMURES_BIT(RES4330_HT_AVAIL), RES_DEPEND_ADD, 0, NULL}
+};
+
+/* true if the power topology uses the buck boost to provide 3.3V to VDDIO_RF
+ * and WLAN PA */
+static bool
+bhnd_pmu_res_depfltr_bb(struct bhnd_pmu_softc *sc)
+{
+ return (BHND_PMU_GET_FLAG(sc->board.board_flags, BHND_BFL_BUCKBOOST));
+}
+
+/* true if the power topology doesn't use the cbuck. Key on chiprev also if
+ * the chip is BCM4325. */
+static bool
+bhnd_pmu_res_depfltr_ncb(struct bhnd_pmu_softc *sc)
+{
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4325 && sc->cid.chip_rev <= 1)
+ return (false);
+
+ return (BHND_PMU_GET_FLAG(sc->board.board_flags, BHND_BFL_NOCBUCK));
+}
+
+/* true if the power topology uses the PALDO */
+static bool
+bhnd_pmu_res_depfltr_paldo(struct bhnd_pmu_softc *sc)
+{
+ return (BHND_PMU_GET_FLAG(sc->board.board_flags, BHND_BFL_PALDO));
+}
+
+/* true if the power topology doesn't use the PALDO */
+static bool
+bhnd_pmu_res_depfltr_npaldo(struct bhnd_pmu_softc *sc)
+{
+ return (!BHND_PMU_GET_FLAG(sc->board.board_flags, BHND_BFL_PALDO));
+}
+
+/* Determine min/max rsrc masks. Value 0 leaves hardware at default. */
+static int
+bhnd_pmu_res_masks(struct bhnd_pmu_softc *sc, uint32_t *pmin, uint32_t *pmax)
+{
+ uint32_t max_mask, min_mask;
+ uint32_t chipst, otpsel;
+ uint32_t nval;
+ uint8_t rsrcs;
+ int error;
+
+ max_mask = 0;
+ min_mask = 0;
+
+ /* # resources */
+ rsrcs = BHND_PMU_GET_BITS(sc->caps, BHND_PMU_CAP_RC);
+
+ /* determine min/max rsrc masks */
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4325:
+ /* If used by this device, enable the CBUCK */
+ if (!bhnd_pmu_res_depfltr_ncb(sc))
+ min_mask |= PMURES_BIT(RES4325B0_CBUCK_LPOM);
+
+ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
+ if (BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_PMUTOP_2B))
+ min_mask |= PMURES_BIT(RES4325B0_CLDO_PU);
+
+ /* Is OTP required? */
+ otpsel = BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_SPROM_OTP_SEL);
+ if (otpsel != CHIPC_CST_OTP_PWRDN)
+ min_mask |= PMURES_BIT(RES4325_OTP_PU);
+
+ /* Leave buck boost on in burst mode for certain boards */
+ if (sc->board.board_flags & BHND_BFL_BUCKBOOST) {
+ switch (sc->board.board_type) {
+ case BHND_BOARD_BCM94325DEVBU:
+ case BHND_BOARD_BCM94325BGABU:
+ min_mask |= PMURES_BIT(
+ RES4325_BUCK_BOOST_BURST);
+ break;
+ }
+ }
+
+ /* Allow all resources to be turned on upon requests */
+ max_mask = ~(~0 << rsrcs);
+ break;
+
+ case BHND_CHIPID_BCM4312:
+ /* default min_mask = 0x80000cbb is wrong */
+ min_mask = 0xcbb;
+ /*
+ * max_mask = 0x7fff;
+ * pmu_res_updown_table_sz = 0;
+ * pmu_res_depend_table_sz = 0;
+ */
+ break;
+
+ case BHND_CHIPID_BCM4322:
+ case BHND_CHIPID_BCM43221:
+ case BHND_CHIPID_BCM43231:
+ case BHND_CHIPID_BCM4342:
+ if (sc->cid.chip_rev >= 2)
+ break;
+
+ /* request ALP(can skip for A1) */
+ min_mask = PMURES_BIT(RES4322_RF_LDO) |
+ PMURES_BIT(RES4322_XTAL_PU) |
+ PMURES_BIT(RES4322_ALP_AVAIL);
+
+ if (bhnd_get_attach_type(sc->chipc_dev) == BHND_ATTACH_NATIVE) {
+ min_mask |=
+ PMURES_BIT(RES4322_SI_PLL_ON) |
+ PMURES_BIT(RES4322_HT_SI_AVAIL) |
+ PMURES_BIT(RES4322_PHY_PLL_ON) |
+ PMURES_BIT(RES4322_OTP_PU) |
+ PMURES_BIT(RES4322_HT_PHY_AVAIL);
+ max_mask = 0x1ff;
+ }
+ break;
+
+ case BHND_CHIPID_BCM43222:
+ case BHND_CHIPID_BCM43111:
+ case BHND_CHIPID_BCM43112:
+ case BHND_CHIPID_BCM43224:
+ case BHND_CHIPID_BCM43225:
+ case BHND_CHIPID_BCM43421:
+ case BHND_CHIPID_BCM43226:
+ case BHND_CHIPID_BCM43420:
+ case BHND_CHIPID_BCM43235:
+ case BHND_CHIPID_BCM43236:
+ case BHND_CHIPID_BCM43238:
+ case BHND_CHIPID_BCM43234:
+ case BHND_CHIPID_BCM43237:
+ case BHND_CHIPID_BCM4331:
+ case BHND_CHIPID_BCM43431:
+ case BHND_CHIPID_BCM6362:
+ /* use chip default */
+ break;
+
+ case BHND_CHIPID_BCM4328:
+ min_mask =
+ PMURES_BIT(RES4328_BB_SWITCHER_PWM) |
+ PMURES_BIT(RES4328_EXT_SWITCHER_PWM) |
+ PMURES_BIT(RES4328_XTAL_EN);
+ max_mask = 0xfffffff;
+ break;
+
+ case BHND_CHIPID_BCM5354:
+ /* Allow (but don't require) PLL to turn on */
+ max_mask = 0xfffffff;
+ break;
+
+ case BHND_CHIPID_BCM4329:
+ /* Down to save the power. */
+ if (sc->cid.chip_rev >= 0x2) {
+ min_mask =
+ PMURES_BIT(RES4329_CBUCK_LPOM) |
+ PMURES_BIT(RES4329_LNLDO1_PU) |
+ PMURES_BIT(RES4329_CLDO_PU);
+ } else {
+ min_mask =
+ PMURES_BIT(RES4329_CBUCK_LPOM) |
+ PMURES_BIT(RES4329_CLDO_PU);
+ }
+
+ /* Is OTP required? */
+ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
+ otpsel = BHND_PMU_GET_BITS(chipst, CHIPC_CST4329_SPROM_OTP_SEL);
+ if (otpsel != CHIPC_CST_OTP_PWRDN)
+ min_mask |= PMURES_BIT(RES4329_OTP_PU);
+
+ /* Allow (but don't require) PLL to turn on */
+ max_mask = 0x3ff63e;
+ break;
+
+ case BHND_CHIPID_BCM4319:
+ /* We only need a few resources to be kept on all the time */
+ min_mask = PMURES_BIT(RES4319_CBUCK_LPOM) |
+ PMURES_BIT(RES4319_CLDO_PU);
+
+ /* Allow everything else to be turned on upon requests */
+ max_mask = ~(~0 << rsrcs);
+ break;
+
+ case BHND_CHIPID_BCM4336:
+ /* Down to save the power. */
+ min_mask =
+ PMURES_BIT(RES4336_CBUCK_LPOM) |
+ PMURES_BIT(RES4336_CLDO_PU) |
+ PMURES_BIT(RES4336_LDO3P3_PU) |
+ PMURES_BIT(RES4336_OTP_PU) |
+ PMURES_BIT(RES4336_DIS_INT_RESET_PD);
+ /* Allow (but don't require) PLL to turn on */
+ max_mask = 0x1ffffff;
+ break;
+
+ case BHND_CHIPID_BCM4330:
+ /* Down to save the power. */
+ min_mask =
+ PMURES_BIT(RES4330_CBUCK_LPOM) | PMURES_BIT(RES4330_CLDO_PU)
+ | PMURES_BIT(RES4330_DIS_INT_RESET_PD) |
+ PMURES_BIT(RES4330_LDO3P3_PU) | PMURES_BIT(RES4330_OTP_PU);
+ /* Allow (but don't require) PLL to turn on */
+ max_mask = 0xfffffff;
+ break;
+
+ case BHND_CHIPID_BCM4313:
+ min_mask = PMURES_BIT(RES4313_BB_PU_RSRC) |
+ PMURES_BIT(RES4313_XTAL_PU_RSRC) |
+ PMURES_BIT(RES4313_ALP_AVAIL_RSRC) |
+ PMURES_BIT(RES4313_BB_PLL_PWRSW_RSRC);
+ max_mask = 0xffff;
+ break;
+ default:
+ break;
+ }
+
+ /* Apply nvram override to min mask */
+ error = bhnd_nvram_getvar_uint32(sc->chipc_dev, BHND_NVAR_RMIN, &nval);
+ if (error && error != ENOENT) {
+ device_printf(sc->dev, "NVRAM error reading %s: %d\n",
+ BHND_NVAR_RMIN, error);
+ return (error);
+ } else if (!error) {
+ PMU_MSG(("Applying rmin=%#x to min_mask\n", nval));
+ min_mask = nval;
+ }
+
+ /* Apply nvram override to max mask */
+ error = bhnd_nvram_getvar_uint32(sc->chipc_dev, BHND_NVAR_RMAX, &nval);
+ if (error && error != ENOENT) {
+ device_printf(sc->dev, "NVRAM error reading %s: %d\n",
+ BHND_NVAR_RMAX, error);
+ return (error);
+ } else if (!error) {
+ PMU_MSG(("Applying rmax=%#x to max_mask\n", nval));
+ min_mask = nval;
+ }
+
+ if (pmin != NULL)
+ *pmin = min_mask;
+
+ if (pmax != NULL)
+ *pmax = max_mask;
+
+ return (0);
+}
+
+/* initialize PMU resources */
+int
+bhnd_pmu_res_init(struct bhnd_pmu_softc *sc)
+{
+ const pmu_res_updown_t *pmu_res_updown_table;
+ const pmu_res_depend_t *pmu_res_depend_table;
+ size_t pmu_res_updown_table_sz;
+ size_t pmu_res_depend_table_sz;
+ uint32_t max_mask, min_mask;
+ uint8_t rsrcs;
+ int error;
+
+ pmu_res_depend_table = NULL;
+ pmu_res_depend_table_sz = 0;
+
+ pmu_res_updown_table = NULL;
+ pmu_res_updown_table_sz = 0;
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4315:
+ /* Optimize resources up/down timers */
+ pmu_res_updown_table = bcm4315a0_res_updown;
+ pmu_res_updown_table_sz = nitems(bcm4315a0_res_updown);
+
+ /* Optimize resources dependencies */
+ pmu_res_depend_table = bcm4315a0_res_depend;
+ pmu_res_depend_table_sz = nitems(bcm4315a0_res_depend);
+ break;
+
+ case BHND_CHIPID_BCM4325:
+ /* Optimize resources up/down timers */
+ pmu_res_updown_table = bcm4325a0_res_updown;
+ pmu_res_updown_table_sz = nitems(bcm4325a0_res_updown);
+
+ /* Optimize resources dependencies */
+ pmu_res_depend_table = bcm4325a0_res_depend;
+ pmu_res_depend_table_sz = nitems(bcm4325a0_res_depend);
+ break;
+
+ case BHND_CHIPID_BCM4328:
+ /* Optimize resources up/down timers */
+ pmu_res_updown_table = bcm4328a0_res_updown;
+ pmu_res_updown_table_sz = nitems(bcm4328a0_res_updown);
+
+ /* Optimize resources dependencies */
+ pmu_res_depend_table = bcm4328a0_res_depend;
+ pmu_res_depend_table_sz = nitems(bcm4328a0_res_depend);
+ break;
+
+ case BHND_CHIPID_BCM4329:
+ /* Optimize resources up/down timers */
+ pmu_res_updown_table = bcm4329_res_updown;
+ pmu_res_updown_table_sz = nitems(bcm4329_res_updown);
+
+ /* Optimize resources dependencies */
+ pmu_res_depend_table = bcm4329_res_depend;
+ pmu_res_depend_table_sz = nitems(bcm4329_res_depend);
+ break;
+
+ case BHND_CHIPID_BCM4319:
+ /* Optimize resources up/down timers */
+ pmu_res_updown_table = bcm4319a0_res_updown;
+ pmu_res_updown_table_sz = nitems(bcm4319a0_res_updown);
+
+ /* Optimize resources dependencies masks */
+ pmu_res_depend_table = bcm4319a0_res_depend;
+ pmu_res_depend_table_sz = nitems(bcm4319a0_res_depend);
+ break;
+
+ case BHND_CHIPID_BCM4336:
+ /* Optimize resources up/down timers */
+ pmu_res_updown_table = bcm4336a0_res_updown;
+ pmu_res_updown_table_sz = nitems(bcm4336a0_res_updown);
+
+ /* Optimize resources dependencies masks */
+ pmu_res_depend_table = bcm4336a0_res_depend;
+ pmu_res_depend_table_sz = nitems(bcm4336a0_res_depend);
+ break;
+
+ case BHND_CHIPID_BCM4330:
+ /* Optimize resources up/down timers */
+ pmu_res_updown_table = bcm4330a0_res_updown;
+ pmu_res_updown_table_sz = nitems(bcm4330a0_res_updown);
+
+ /* Optimize resources dependencies masks */
+ pmu_res_depend_table = bcm4330a0_res_depend;
+ pmu_res_depend_table_sz = nitems(bcm4330a0_res_depend);
+ break;
+ default:
+ break;
+ }
+
+ /* # resources */
+ rsrcs = BHND_PMU_GET_BITS(sc->caps, BHND_PMU_CAP_RC);
+
+ /* Program up/down timers */
+ for (size_t i = 0; i < pmu_res_updown_table_sz; i++) {
+ const pmu_res_updown_t *updt;
+
+ KASSERT(pmu_res_updown_table != NULL, ("no updown tables"));
+
+ updt = &pmu_res_updown_table[pmu_res_updown_table_sz - i - 1];
+
+ PMU_MSG(("Changing rsrc %d res_updn_timer to %#x\n",
+ updt->resnum, updt->updown));
+
+ BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, updt->resnum);
+ BHND_PMU_WRITE_4(sc, BHND_PMU_RES_UPDN_TIMER, updt->updown);
+ }
+
+ /* Apply nvram overrides to up/down timers */
+ for (uint8_t i = 0; i < rsrcs; i++) {
+ char name[6];
+ uint32_t val;
+
+ snprintf(name, sizeof(name), "r%dt", i);
+ error = bhnd_nvram_getvar_uint32(sc->chipc_dev, name, &val);
+
+ if (error == ENOENT) {
+ continue;
+ } else if (error) {
+ device_printf(sc->dev, "NVRAM error reading %s: %d\n",
+ name, error);
+ return (error);
+ }
+
+ PMU_MSG(("Applying %s=%s to rsrc %d res_updn_timer\n", name,
+ val, i));
+
+ BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i);
+ BHND_PMU_WRITE_4(sc, BHND_PMU_RES_UPDN_TIMER, val);
+ }
+
+ /* Program resource dependencies table */
+ for (size_t i = 0; i < pmu_res_depend_table_sz; i++) {
+ const pmu_res_depend_t *rdep;
+ pmu_res_filter filter;
+ uint32_t depend_mask;
+
+ KASSERT(pmu_res_depend_table != NULL, ("no depend tables"));
+
+ rdep = &pmu_res_depend_table[pmu_res_depend_table_sz - i - 1];
+ filter = rdep->filter;
+
+ if (filter != NULL && !filter(sc))
+ continue;
+
+ for (uint8_t i = 0; i < rsrcs; i++) {
+ if ((rdep->res_mask & BHND_PMURES_BIT(i)) == 0)
+ continue;
+
+ BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i);
+ depend_mask = BHND_PMU_READ_4(sc,
+ BHND_PMU_RES_DEP_MASK);
+ switch (rdep->action) {
+ case RES_DEPEND_SET:
+ PMU_MSG(("Changing rsrc %hhu res_dep_mask to "
+ "%#x\n", i, table->depend_mask));
+ depend_mask = rdep->depend_mask;
+ break;
+
+ case RES_DEPEND_ADD:
+ PMU_MSG(("Adding %#x to rsrc %hhu "
+ "res_dep_mask\n", table->depend_mask, i));
+
+ depend_mask |= rdep->depend_mask;
+ break;
+
+ case RES_DEPEND_REMOVE:
+ PMU_MSG(("Removing %#x from rsrc %hhu "
+ "res_dep_mask\n", table->depend_mask, i));
+
+ depend_mask &= ~(rdep->depend_mask);
+ break;
+
+ default:
+ panic("unknown RES_DEPEND action: %d\n",
+ rdep->action);
+ break;
+ }
+
+
+ }
+ }
+
+ /* Apply nvram overrides to dependencies masks */
+ for (uint8_t i = 0; i < rsrcs; i++) {
+ char name[6];
+ uint32_t val;
+
+ snprintf(name, sizeof(name), "r%dd", i);
+ error = bhnd_nvram_getvar_uint32(sc->chipc_dev, name, &val);
+
+ if (error == ENOENT) {
+ continue;
+ } else if (error) {
+ device_printf(sc->dev, "NVRAM error reading %s: %d\n",
+ name, error);
+ return (error);
+ }
+
+ PMU_MSG(("Applying %s=%s to rsrc %d res_dep_mask\n", name, val,
+ i));
+
+ BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i);
+ BHND_PMU_WRITE_4(sc, BHND_PMU_RES_DEP_MASK, val);
+ }
+
+ /* Determine min/max rsrc masks */
+ if ((error = bhnd_pmu_res_masks(sc, &min_mask, &max_mask)))
+ return (error);
+
+ /* It is required to program max_mask first and then min_mask */
+
+ /* Program max resource mask */
+ if (max_mask != 0) {
+ PMU_MSG(("Changing max_res_mask to 0x%x\n", max_mask));
+ BHND_PMU_WRITE_4(sc, BHND_PMU_MAX_RES_MASK, max_mask);
+ }
+
+ /* Program min resource mask */
+
+ if (min_mask != 0) {
+ PMU_MSG(("Changing min_res_mask to 0x%x\n", min_mask));
+ BHND_PMU_WRITE_4(sc, BHND_PMU_MIN_RES_MASK, min_mask);
+ }
+
+ /* Add some delay; allow resources to come up and settle. */
+ DELAY(2000);
+
+ return (0);
+}
+
+/* setup pll and query clock speed */
+struct pmu0_xtaltab0 {
+ uint16_t freq;
+ uint8_t xf;
+ uint8_t wbint;
+ uint32_t wbfrac;
+};
+
+/* the following table is based on 880Mhz fvco */
+static const pmu0_xtaltab0_t pmu0_xtaltab0[] = {
+ {
+ 12000, 1, 73, 349525}, {
+ 13000, 2, 67, 725937}, {
+ 14400, 3, 61, 116508}, {
+ 15360, 4, 57, 305834}, {
+ 16200, 5, 54, 336579}, {
+ 16800, 6, 52, 399457}, {
+ 19200, 7, 45, 873813}, {
+ 19800, 8, 44, 466033}, {
+ 20000, 9, 44, 0}, {
+ 25000, 10, 70, 419430}, {
+ 26000, 11, 67, 725937}, {
+ 30000, 12, 58, 699050}, {
+ 38400, 13, 45, 873813}, {
+ 40000, 14, 45, 0}, {
+ 0, 0, 0, 0}
+};
+
+#define PMU0_XTAL0_DEFAULT 8
+
+/* setup pll and query clock speed */
+struct pmu1_xtaltab0 {
+ uint16_t fref;
+ uint8_t xf;
+ uint8_t p1div;
+ uint8_t p2div;
+ uint8_t ndiv_int;
+ uint32_t ndiv_frac;
+};
+
+static const pmu1_xtaltab0_t pmu1_xtaltab0_880_4329[] = {
+ {
+ 12000, 1, 3, 22, 0x9, 0xFFFFEF}, {
+ 13000, 2, 1, 6, 0xb, 0x483483}, {
+ 14400, 3, 1, 10, 0xa, 0x1C71C7}, {
+ 15360, 4, 1, 5, 0xb, 0x755555}, {
+ 16200, 5, 1, 10, 0x5, 0x6E9E06}, {
+ 16800, 6, 1, 10, 0x5, 0x3Cf3Cf}, {
+ 19200, 7, 1, 4, 0xb, 0x755555}, {
+ 19800, 8, 1, 11, 0x4, 0xA57EB}, {
+ 20000, 9, 1, 11, 0x4, 0x0}, {
+ 24000, 10, 3, 11, 0xa, 0x0}, {
+ 25000, 11, 5, 16, 0xb, 0x0}, {
+ 26000, 12, 1, 1, 0x21, 0xD89D89}, {
+ 30000, 13, 3, 8, 0xb, 0x0}, {
+ 37400, 14, 3, 1, 0x46, 0x969696}, {
+ 38400, 15, 1, 1, 0x16, 0xEAAAAA}, {
+ 40000, 16, 1, 2, 0xb, 0}, {
+ 0, 0, 0, 0, 0, 0}
+};
+
+/* the following table is based on 880Mhz fvco */
+static const pmu1_xtaltab0_t pmu1_xtaltab0_880[] = {
+ {
+ 12000, 1, 3, 22, 0x9, 0xFFFFEF}, {
+ 13000, 2, 1, 6, 0xb, 0x483483}, {
+ 14400, 3, 1, 10, 0xa, 0x1C71C7}, {
+ 15360, 4, 1, 5, 0xb, 0x755555}, {
+ 16200, 5, 1, 10, 0x5, 0x6E9E06}, {
+ 16800, 6, 1, 10, 0x5, 0x3Cf3Cf}, {
+ 19200, 7, 1, 4, 0xb, 0x755555}, {
+ 19800, 8, 1, 11, 0x4, 0xA57EB}, {
+ 20000, 9, 1, 11, 0x4, 0x0}, {
+ 24000, 10, 3, 11, 0xa, 0x0}, {
+ 25000, 11, 5, 16, 0xb, 0x0}, {
+ 26000, 12, 1, 2, 0x10, 0xEC4EC4}, {
+ 30000, 13, 3, 8, 0xb, 0x0}, {
+ 33600, 14, 1, 2, 0xd, 0x186186}, {
+ 38400, 15, 1, 2, 0xb, 0x755555}, {
+ 40000, 16, 1, 2, 0xb, 0}, {
+ 0, 0, 0, 0, 0, 0}
+};
+
+#define PMU1_XTALTAB0_880_12000K 0
+#define PMU1_XTALTAB0_880_13000K 1
+#define PMU1_XTALTAB0_880_14400K 2
+#define PMU1_XTALTAB0_880_15360K 3
+#define PMU1_XTALTAB0_880_16200K 4
+#define PMU1_XTALTAB0_880_16800K 5
+#define PMU1_XTALTAB0_880_19200K 6
+#define PMU1_XTALTAB0_880_19800K 7
+#define PMU1_XTALTAB0_880_20000K 8
+#define PMU1_XTALTAB0_880_24000K 9
+#define PMU1_XTALTAB0_880_25000K 10
+#define PMU1_XTALTAB0_880_26000K 11
+#define PMU1_XTALTAB0_880_30000K 12
+#define PMU1_XTALTAB0_880_37400K 13
+#define PMU1_XTALTAB0_880_38400K 14
+#define PMU1_XTALTAB0_880_40000K 15
+
+/* the following table is based on 1760Mhz fvco */
+static const pmu1_xtaltab0_t pmu1_xtaltab0_1760[] = {
+ {
+ 12000, 1, 3, 44, 0x9, 0xFFFFEF}, {
+ 13000, 2, 1, 12, 0xb, 0x483483}, {
+ 14400, 3, 1, 20, 0xa, 0x1C71C7}, {
+ 15360, 4, 1, 10, 0xb, 0x755555}, {
+ 16200, 5, 1, 20, 0x5, 0x6E9E06}, {
+ 16800, 6, 1, 20, 0x5, 0x3Cf3Cf}, {
+ 19200, 7, 1, 18, 0x5, 0x17B425}, {
+ 19800, 8, 1, 22, 0x4, 0xA57EB}, {
+ 20000, 9, 1, 22, 0x4, 0x0}, {
+ 24000, 10, 3, 22, 0xa, 0x0}, {
+ 25000, 11, 5, 32, 0xb, 0x0}, {
+ 26000, 12, 1, 4, 0x10, 0xEC4EC4}, {
+ 30000, 13, 3, 16, 0xb, 0x0}, {
+ 38400, 14, 1, 10, 0x4, 0x955555}, {
+ 40000, 15, 1, 4, 0xb, 0}, {
+ 0, 0, 0, 0, 0, 0}
+};
+
+/* table index */
+#define PMU1_XTALTAB0_1760_12000K 0
+#define PMU1_XTALTAB0_1760_13000K 1
+#define PMU1_XTALTAB0_1760_14400K 2
+#define PMU1_XTALTAB0_1760_15360K 3
+#define PMU1_XTALTAB0_1760_16200K 4
+#define PMU1_XTALTAB0_1760_16800K 5
+#define PMU1_XTALTAB0_1760_19200K 6
+#define PMU1_XTALTAB0_1760_19800K 7
+#define PMU1_XTALTAB0_1760_20000K 8
+#define PMU1_XTALTAB0_1760_24000K 9
+#define PMU1_XTALTAB0_1760_25000K 10
+#define PMU1_XTALTAB0_1760_26000K 11
+#define PMU1_XTALTAB0_1760_30000K 12
+#define PMU1_XTALTAB0_1760_38400K 13
+#define PMU1_XTALTAB0_1760_40000K 14
+
+/* the following table is based on 1440Mhz fvco */
+static const pmu1_xtaltab0_t pmu1_xtaltab0_1440[] = {
+ {
+ 12000, 1, 1, 1, 0x78, 0x0}, {
+ 13000, 2, 1, 1, 0x6E, 0xC4EC4E}, {
+ 14400, 3, 1, 1, 0x64, 0x0}, {
+ 15360, 4, 1, 1, 0x5D, 0xC00000}, {
+ 16200, 5, 1, 1, 0x58, 0xE38E38}, {
+ 16800, 6, 1, 1, 0x55, 0xB6DB6D}, {
+ 19200, 7, 1, 1, 0x4B, 0}, {
+ 19800, 8, 1, 1, 0x48, 0xBA2E8B}, {
+ 20000, 9, 1, 1, 0x48, 0x0}, {
+ 25000, 10, 1, 1, 0x39, 0x999999}, {
+ 26000, 11, 1, 1, 0x37, 0x627627}, {
+ 30000, 12, 1, 1, 0x30, 0x0}, {
+ 37400, 13, 2, 1, 0x4D, 0x15E76}, {
+ 38400, 13, 2, 1, 0x4B, 0x0}, {
+ 40000, 14, 2, 1, 0x48, 0x0}, {
+ 48000, 15, 2, 1, 0x3c, 0x0}, {
+ 0, 0, 0, 0, 0, 0}
+};
+
+/* table index */
+#define PMU1_XTALTAB0_1440_12000K 0
+#define PMU1_XTALTAB0_1440_13000K 1
+#define PMU1_XTALTAB0_1440_14400K 2
+#define PMU1_XTALTAB0_1440_15360K 3
+#define PMU1_XTALTAB0_1440_16200K 4
+#define PMU1_XTALTAB0_1440_16800K 5
+#define PMU1_XTALTAB0_1440_19200K 6
+#define PMU1_XTALTAB0_1440_19800K 7
+#define PMU1_XTALTAB0_1440_20000K 8
+#define PMU1_XTALTAB0_1440_25000K 9
+#define PMU1_XTALTAB0_1440_26000K 10
+#define PMU1_XTALTAB0_1440_30000K 11
+#define PMU1_XTALTAB0_1440_37400K 12
+#define PMU1_XTALTAB0_1440_38400K 13
+#define PMU1_XTALTAB0_1440_40000K 14
+#define PMU1_XTALTAB0_1440_48000K 15
+
+#define XTAL_FREQ_24000MHZ 24000
+#define XTAL_FREQ_30000MHZ 30000
+#define XTAL_FREQ_37400MHZ 37400
+#define XTAL_FREQ_48000MHZ 48000
+
+static const pmu1_xtaltab0_t pmu1_xtaltab0_960[] = {
+ {
+ 12000, 1, 1, 1, 0x50, 0x0}, {
+ 13000, 2, 1, 1, 0x49, 0xD89D89}, {
+ 14400, 3, 1, 1, 0x42, 0xAAAAAA}, {
+ 15360, 4, 1, 1, 0x3E, 0x800000}, {
+ 16200, 5, 1, 1, 0x39, 0x425ED0}, {
+ 16800, 6, 1, 1, 0x39, 0x249249}, {
+ 19200, 7, 1, 1, 0x32, 0x0}, {
+ 19800, 8, 1, 1, 0x30, 0x7C1F07}, {
+ 20000, 9, 1, 1, 0x30, 0x0}, {
+ 25000, 10, 1, 1, 0x26, 0x666666}, {
+ 26000, 11, 1, 1, 0x24, 0xEC4EC4}, {
+ 30000, 12, 1, 1, 0x20, 0x0}, {
+ 37400, 13, 2, 1, 0x33, 0x563EF9}, {
+ 38400, 14, 2, 1, 0x32, 0x0}, {
+ 40000, 15, 2, 1, 0x30, 0x0}, {
+ 48000, 16, 2, 1, 0x28, 0x0}, {
+ 0, 0, 0, 0, 0, 0}
+};
+
+/* table index */
+#define PMU1_XTALTAB0_960_12000K 0
+#define PMU1_XTALTAB0_960_13000K 1
+#define PMU1_XTALTAB0_960_14400K 2
+#define PMU1_XTALTAB0_960_15360K 3
+#define PMU1_XTALTAB0_960_16200K 4
+#define PMU1_XTALTAB0_960_16800K 5
+#define PMU1_XTALTAB0_960_19200K 6
+#define PMU1_XTALTAB0_960_19800K 7
+#define PMU1_XTALTAB0_960_20000K 8
+#define PMU1_XTALTAB0_960_25000K 9
+#define PMU1_XTALTAB0_960_26000K 10
+#define PMU1_XTALTAB0_960_30000K 11
+#define PMU1_XTALTAB0_960_37400K 12
+#define PMU1_XTALTAB0_960_38400K 13
+#define PMU1_XTALTAB0_960_40000K 14
+#define PMU1_XTALTAB0_960_48000K 15
+
+/* select xtal table for each chip */
+static const pmu1_xtaltab0_t *
+bhnd_pmu1_xtaltab0(struct bhnd_pmu_softc *sc)
+{
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4315:
+ return (pmu1_xtaltab0_1760);
+ case BHND_CHIPID_BCM4319:
+ return (pmu1_xtaltab0_1440);
+ case BHND_CHIPID_BCM4325:
+ return (pmu1_xtaltab0_880);
+ case BHND_CHIPID_BCM4329:
+ return (pmu1_xtaltab0_880_4329);
+ case BHND_CHIPID_BCM4336:
+ return (pmu1_xtaltab0_960);
+ case BHND_CHIPID_BCM4330:
+ if (PMU_CST4330_SDIOD_CHIPMODE(sc))
+ return (pmu1_xtaltab0_960);
+ else
+ return (pmu1_xtaltab0_1440);
+ default:
+ PMU_MSG(("bhnd_pmu1_xtaltab0: Unknown chipid %#hx\n",
+ sc->cid.chip_id));
+ return (NULL);
+ }
+}
+
+/* select default xtal frequency for each chip */
+static const pmu1_xtaltab0_t *
+bhnd_pmu1_xtaldef0(struct bhnd_pmu_softc *sc)
+{
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4315:
+ /* Default to 26000Khz */
+ return (&pmu1_xtaltab0_1760[PMU1_XTALTAB0_1760_26000K]);
+ case BHND_CHIPID_BCM4319:
+ /* Default to 30000Khz */
+ return (&pmu1_xtaltab0_1440[PMU1_XTALTAB0_1440_30000K]);
+ case BHND_CHIPID_BCM4325:
+ /* Default to 26000Khz */
+ return (&pmu1_xtaltab0_880[PMU1_XTALTAB0_880_26000K]);
+ case BHND_CHIPID_BCM4329:
+ /* Default to 38400Khz */
+ return (&pmu1_xtaltab0_880_4329[PMU1_XTALTAB0_880_38400K]);
+ case BHND_CHIPID_BCM4336:
+ /* Default to 26000Khz */
+ return (&pmu1_xtaltab0_960[PMU1_XTALTAB0_960_26000K]);
+ case BHND_CHIPID_BCM4330:
+ /* Default to 37400Khz */
+ if (PMU_CST4330_SDIOD_CHIPMODE(sc))
+ return (&pmu1_xtaltab0_960[PMU1_XTALTAB0_960_37400K]);
+ else
+ return (&pmu1_xtaltab0_1440[PMU1_XTALTAB0_1440_37400K]);
+ default:
+ PMU_MSG(("bhnd_pmu1_xtaldef0: Unknown chipid %#hx\n",
+ sc->cid.chip_id));
+ return (NULL);
+ }
+}
+
+/* select default pll fvco for each chip */
+static uint32_t
+bhnd_pmu1_pllfvco0(struct bhnd_pmu_softc *sc)
+{
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4329:
+ return (FVCO_880);
+ case BHND_CHIPID_BCM4319:
+ return (FVCO_1440);
+ case BHND_CHIPID_BCM4336:
+ return (FVCO_960);
+ case BHND_CHIPID_BCM4330:
+ if (PMU_CST4330_SDIOD_CHIPMODE(sc))
+ return (FVCO_960);
+ else
+ return (FVCO_1440);
+ default:
+ PMU_MSG(("bhnd_pmu1_pllfvco0: Unknown chipid %#hx\n",
+ sc->cid.chip_id));
+ return (0);
+ }
+}
+
+/* query alp/xtal clock frequency */
+static uint32_t
+bhnd_pmu1_alpclk0(struct bhnd_pmu_softc *sc)
+{
+ const pmu1_xtaltab0_t *xt;
+ uint32_t xf;
+
+ /* Find the frequency in the table */
+ xf = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
+ xf = BHND_PMU_GET_BITS(xf, BHND_PMU_CTRL_XTALFREQ);
+
+ for (xt = bhnd_pmu1_xtaltab0(sc); xt != NULL && xt->fref != 0; xt++) {
+ if (xt->xf == xf)
+ break;
+ }
+
+ /* Could not find it so assign a default value */
+ if (xt == NULL || xt->fref == 0)
+ xt = bhnd_pmu1_xtaldef0(sc);
+
+ if (xt == NULL || xt->fref == 0) {
+ device_printf(sc->dev,
+ "no matching ALP/XTAL frequency found\n");
+ return (0);
+ }
+
+ return (xt->fref * 1000);
+}
+
+/* Set up PLL registers in the PMU as per the crystal speed. */
+static void
+bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
+{
+ const pmu0_xtaltab0_t *xt;
+ uint32_t pll_data, pll_mask;
+ uint32_t pll_res;
+ uint32_t pmu_ctrl;
+ uint32_t xf;
+
+ /* Use h/w default PLL config */
+ if (xtal == 0) {
+ PMU_MSG(("Unspecified xtal frequency, skipping PLL "
+ "configuration\n"));
+ return;
+ }
+
+ /* Find the frequency in the table */
+ for (xt = pmu0_xtaltab0; xt->freq; xt ++) {
+ if (xt->freq == xtal)
+ break;
+ }
+
+ if (xt->freq == 0)
+ xt = &pmu0_xtaltab0[PMU0_XTAL0_DEFAULT];
+
+ PMU_MSG(("XTAL %d.%d MHz (%d)\n", xtal / 1000, xtal % 1000, xt->xf));
+
+ /* Check current PLL state */
+ pmu_ctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
+ xf = BHND_PMU_GET_BITS(pmu_ctrl, BHND_PMU_CTRL_XTALFREQ);
+ if (xf == xt->xf) {
+#ifdef BCMUSBDEV
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4328) {
+ bhnd_pmu0_sbclk4328(sc,
+ BHND_PMU0_PLL0_PC0_DIV_ARM_88MHZ);
+ return;
+ }
+#endif /* BCMUSBDEV */
+
+ PMU_MSG(("PLL already programmed for %d.%d MHz\n",
+ xt->freq / 1000, xt->freq % 1000));
+ return;
+ }
+
+ if (xf != 0) {
+ PMU_MSG(("Reprogramming PLL for %d.%d MHz (was %d.%dMHz)\n",
+ xt->freq / 1000, xt->freq % 1000,
+ pmu0_xtaltab0[tmp-1].freq / 1000,
+ pmu0_xtaltab0[tmp-1].freq % 1000));
+ } else {
+ PMU_MSG(("Programming PLL for %d.%d MHz\n",
+ xt->freq / 1000, xt->freq % 1000));
+ }
+
+ /* Make sure the PLL is off */
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4328:
+ pll_res = PMURES_BIT(RES4328_BB_PLL_PU);
+ break;
+ case BHND_CHIPID_BCM5354:
+ pll_res = PMURES_BIT(RES5354_BB_PLL_PU);
+ break;
+ default:
+ panic("unsupported chipid %#hx\n", sc->cid.chip_id);
+ }
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~pll_res);
+ BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~pll_res);
+
+ /* Wait for HT clock to shutdown. */
+ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL);
+
+ PMU_MSG(("Done masking\n"));
+
+ /* Write PDIV in pllcontrol[0] */
+ if (xt->freq >= BHND_PMU0_PLL0_PC0_PDIV_FREQ) {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU0_PLL0_PLLCTL0,
+ BHND_PMU0_PLL0_PC0_PDIV_MASK, BHND_PMU0_PLL0_PC0_PDIV_MASK);
+ } else {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU0_PLL0_PLLCTL0, 0,
+ BHND_PMU0_PLL0_PC0_PDIV_MASK);
+ }
+
+ /* Write WILD in pllcontrol[1] */
+ pll_data =
+ BHND_PMU_SET_BITS(xt->wbint, BHND_PMU0_PLL0_PC1_WILD_INT) |
+ BHND_PMU_SET_BITS(xt->wbfrac, BHND_PMU0_PLL0_PC1_WILD_FRAC);
+
+ if (xt->wbfrac == 0) {
+ pll_data |= BHND_PMU0_PLL0_PC1_STOP_MOD;
+ } else {
+ pll_data &= ~BHND_PMU0_PLL0_PC1_STOP_MOD;
+ }
+
+ pll_mask =
+ BHND_PMU0_PLL0_PC1_WILD_INT_MASK |
+ BHND_PMU0_PLL0_PC1_WILD_FRAC_MASK;
+
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU0_PLL0_PLLCTL1, pll_data, pll_mask);
+
+ /* Write WILD in pllcontrol[2] */
+ pll_data = BHND_PMU_SET_BITS(xt->wbint, BHND_PMU0_PLL0_PC2_WILD_INT);
+ pll_mask = BHND_PMU0_PLL0_PC2_WILD_INT_MASK;
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU0_PLL0_PLLCTL2, pll_data, pll_mask);
+
+ PMU_MSG(("Done pll\n"));
+
+ /* Write XtalFreq. Set the divisor also. */
+ pmu_ctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
+ pmu_ctrl &= ~(BHND_PMU_CTRL_ILP_DIV_MASK|BHND_PMU_CTRL_XTALFREQ_MASK);
+
+ pmu_ctrl |= BHND_PMU_SET_BITS(((xt->freq + 127) / 128) - 1,
+ BHND_PMU_CTRL_ILP_DIV);
+ pmu_ctrl |= BHND_PMU_SET_BITS(xt->xf, BHND_PMU_CTRL_XTALFREQ);
+
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CTRL, pmu_ctrl);
+}
+
+/* query alp/xtal clock frequency */
+static uint32_t
+bhnd_pmu0_alpclk0(struct bhnd_pmu_softc *sc)
+{
+ const pmu0_xtaltab0_t *xt;
+ uint32_t xf;
+
+ /* Find the frequency in the table */
+ xf = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
+ xf = BHND_PMU_GET_BITS(xf, BHND_PMU_CTRL_XTALFREQ);
+ for (xt = pmu0_xtaltab0; xt->freq; xt++)
+ if (xt->xf == xf)
+ break;
+
+ /* PLL must be configured before */
+ if (xt == NULL || xt->freq == 0)
+ panic("unsupported frequency: %u", xf);
+
+ return (xt->freq * 1000);
+}
+
+/* query CPU clock frequency */
+static uint32_t
+bhnd_pmu0_cpuclk0(struct bhnd_pmu_softc *sc)
+{
+ uint32_t tmp, divarm;
+ uint32_t FVCO;
+#ifdef BCMDBG
+ uint32_t pdiv, wbint, wbfrac, fvco;
+ uint32_t freq;
+#endif
+
+ FVCO = FVCO_880;
+
+ /* Read divarm from pllcontrol[0] */
+ tmp = BHND_PMU_PLL_READ(sc, BHND_PMU0_PLL0_PLLCTL0);
+ divarm = BHND_PMU_GET_BITS(tmp, BHND_PMU0_PLL0_PC0_DIV_ARM);
+
+#ifdef BCMDBG
+ /* Calculate fvco based on xtal freq, pdiv, and wild */
+ pdiv = tmp & BHND_PMU0_PLL0_PC0_PDIV_MASK;
+
+ tmp = BHND_PMU_PLL_READ(sc, BHND_PMU0_PLL0_PLLCTL1);
+ wbfrac = BHND_PMU_GET_BITS(tmp, BHND_PMU0_PLL0_PC1_WILD_FRAC);
+ wbint = BHND_PMU_GET_BITS(tmp, PMU0_PLL0_PC1_WILD_INT);
+
+ tmp = BHND_PMU_PLL_READ(sc, BHND_PMU0_PLL0_PLLCTL2);
+ wbint += BHND_PMU_GET_BITS(tmp, BHND_PMU0_PLL0_PC2_WILD_INT);
+
+ freq = bhnd_pmu0_alpclk0(sih, osh, cc) / 1000;
+
+ fvco = (freq * wbint) << 8;
+ fvco += (freq * (wbfrac >> 10)) >> 2;
+ fvco += (freq * (wbfrac & 0x3ff)) >> 10;
+ fvco >>= 8;
+ fvco >>= pdiv;
+ fvco /= 1000;
+ fvco *= 1000;
+
+ PMU_MSG(("bhnd_pmu0_cpuclk0: wbint %u wbfrac %u fvco %u\n",
+ wbint, wbfrac, fvco));
+
+ FVCO = fvco;
+#endif /* BCMDBG */
+
+ /* Return ARM/SB clock */
+ return FVCO / (divarm + BHND_PMU0_PLL0_PC0_DIV_ARM_BASE) * 1000;
+}
+
+
+
+/* Set up PLL registers in the PMU as per the crystal speed. */
+static void
+bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
+{
+ const pmu1_xtaltab0_t *xt;
+ uint32_t buf_strength;
+ uint32_t plladdr, plldata, pllmask;
+ uint32_t pmuctrl;
+ uint32_t FVCO;
+ uint8_t ndiv_mode;
+
+ FVCO = bhnd_pmu1_pllfvco0(sc) / 1000;
+ buf_strength = 0;
+ ndiv_mode = 1;
+
+ /* Use h/w default PLL config */
+ if (xtal == 0) {
+ PMU_MSG(("Unspecified xtal frequency, skipping PLL "
+ "configuration\n"));
+ return;
+ }
+
+ /* Find the frequency in the table */
+ for (xt = bhnd_pmu1_xtaltab0(sc); xt != NULL && xt->fref != 0; xt++) {
+ if (xt->fref == xtal)
+ break;
+ }
+
+ /* Check current PLL state, bail out if it has been programmed or
+ * we don't know how to program it.
+ */
+ if (xt == NULL || xt->fref == 0) {
+ device_printf(sc->dev, "Unsupported XTAL frequency %d.%dMHz, "
+ "skipping PLL configuration\n", xtal / 1000, xtal % 1000);
+ return;
+ }
+
+ /* For 4319 bootloader already programs the PLL but bootloader does not
+ * program the PLL4 and PLL5. So Skip this check for 4319. */
+ pmuctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
+ if (BHND_PMU_GET_BITS(pmuctrl, BHND_PMU_CTRL_XTALFREQ) == xt->xf &&
+ sc->cid.chip_id != BHND_CHIPID_BCM4319 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM4330)
+ {
+ PMU_MSG(("PLL already programmed for %d.%dMHz\n",
+ xt->fref / 1000, xt->fref % 1000));
+ return;
+ }
+
+ PMU_MSG(("XTAL %d.%dMHz (%d)\n", xtal / 1000, xtal % 1000, xt->xf));
+ PMU_MSG(("Programming PLL for %d.%dMHz\n", xt->fref / 1000,
+ xt->fref % 1000));
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4325:
+ /* Change the BBPLL drive strength to 2 for all channels */
+ buf_strength = 0x222222;
+
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK,
+ ~(PMURES_BIT(RES4325_BBPLL_PWRSW_PU) |
+ PMURES_BIT(RES4325_HT_AVAIL)));
+ BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK,
+ ~(PMURES_BIT(RES4325_BBPLL_PWRSW_PU) |
+ PMURES_BIT(RES4325_HT_AVAIL)));
+
+ /* Wait for HT clock to shutdown. */
+ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL);
+ break;
+
+ case BHND_CHIPID_BCM4329:
+ /* Change the BBPLL drive strength to 8 for all channels */
+ buf_strength = 0x888888;
+
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK,
+ ~(PMURES_BIT(RES4329_BBPLL_PWRSW_PU) |
+ PMURES_BIT(RES4329_HT_AVAIL)));
+ BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK,
+ ~(PMURES_BIT(RES4329_BBPLL_PWRSW_PU) |
+ PMURES_BIT(RES4329_HT_AVAIL)));
+
+ /* Wait for HT clock to shutdown. */
+ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL);
+
+ /* Initialize PLL4 */
+ plladdr = BHND_PMU1_PLL0_PLLCTL4;
+ if (xt->fref == 38400)
+ plldata = 0x200024C0;
+ else if (xt->fref == 37400)
+ plldata = 0x20004500;
+ else if (xt->fref == 26000)
+ plldata = 0x200024C0;
+ else
+ plldata = 0x200005C0; /* Chip Dflt Settings */
+
+ BHND_PMU_PLL_WRITE(sc, plladdr, plldata, ~0);
+
+ /* Initialize PLL5 */
+ plladdr = BHND_PMU1_PLL0_PLLCTL5;
+
+ plldata = BHND_PMU_PLL_READ(sc, plladdr);
+ plldata &= BHND_PMU1_PLL0_PC5_CLK_DRV_MASK;
+
+ if (xt->fref == 38400 ||
+ xt->fref == 37400 ||
+ xt->fref == 26000) {
+ plldata |= 0x15;
+ } else {
+ plldata |= 0x25; /* Chip Dflt Settings */
+ }
+
+ BHND_PMU_PLL_WRITE(sc, plladdr, plldata, ~0);
+ break;
+
+ case BHND_CHIPID_BCM4319:
+ /* Change the BBPLL drive strength to 2 for all channels */
+ buf_strength = 0x222222;
+
+ /* Make sure the PLL is off */
+ /* WAR65104: Disable the HT_AVAIL resource first and then
+ * after a delay (more than downtime for HT_AVAIL) remove the
+ * BBPLL resource; backplane clock moves to ALP from HT.
+ */
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK,
+ ~(PMURES_BIT(RES4319_HT_AVAIL)));
+ BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK,
+ ~(PMURES_BIT(RES4319_HT_AVAIL)));
+
+ DELAY(100);
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK,
+ ~(PMURES_BIT(RES4319_BBPLL_PWRSW_PU)));
+ BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK,
+ ~(PMURES_BIT(RES4319_BBPLL_PWRSW_PU)));
+
+ DELAY(100);
+
+ /* Wait for HT clock to shutdown. */
+ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL);
+
+ plldata = 0x200005c0;
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, plldata, ~0);
+ break;
+
+ case BHND_CHIPID_BCM4336:
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK,
+ ~(PMURES_BIT(RES4336_HT_AVAIL) |
+ PMURES_BIT(RES4336_MACPHY_CLKAVAIL)));
+ BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK,
+ ~(PMURES_BIT(RES4336_HT_AVAIL) |
+ PMURES_BIT(RES4336_MACPHY_CLKAVAIL)));
+ DELAY(100);
+
+ /* Wait for HT clock to shutdown. */
+ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL);
+
+ break;
+
+ case BHND_CHIPID_BCM4330:
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK,
+ ~(PMURES_BIT(RES4330_HT_AVAIL) |
+ PMURES_BIT(RES4330_MACPHY_CLKAVAIL)));
+ BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK,
+ ~(PMURES_BIT(RES4330_HT_AVAIL) |
+ PMURES_BIT(RES4330_MACPHY_CLKAVAIL)));
+ DELAY(100);
+
+ /* Wait for HT clock to shutdown. */
+ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL);
+
+ break;
+
+ default:
+ panic("unsupported chipid %#hx\n", sc->cid.chip_id);
+ }
+
+ PMU_MSG(("Done masking\n"));
+
+ /* Write p1div and p2div to pllcontrol[0] */
+ plldata =
+ BHND_PMU_SET_BITS(xt->p1div, BHND_PMU1_PLL0_PC0_P1DIV) |
+ BHND_PMU_SET_BITS(xt->p2div, BHND_PMU1_PLL0_PC0_P2DIV);
+ pllmask = BHND_PMU1_PLL0_PC0_P1DIV_MASK|BHND_PMU1_PLL0_PC0_P2DIV_MASK;
+
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4319) {
+ plldata &= ~(BHND_PMU1_PLL0_PC0_BYPASS_SDMOD_MASK);
+ pllmask |= BHND_PMU1_PLL0_PC0_BYPASS_SDMOD_MASK;
+ if (!xt->ndiv_frac) {
+ plldata |= BHND_PMU_SET_BITS(1,
+ BHND_PMU1_PLL0_PC0_BYPASS_SDMOD);
+ }
+ }
+
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, plldata, pllmask);
+
+
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4330)
+ bhnd_pmu_set_4330_plldivs(sc);
+
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4329 && sc->cid.chip_rev == 0) {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
+ BHND_PMU_DOT11MAC_880MHZ_CLK_DIVISOR_VAL,
+ BHND_PMU_DOT11MAC_880MHZ_CLK_DIVISOR_MASK);
+ }
+
+ /* Write ndiv_int and ndiv_mode to pllcontrol[2] */
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4336 ||
+ sc->cid.chip_id == BHND_CHIPID_BCM4330)
+ {
+ ndiv_mode = BHND_PMU1_PLL0_PC2_NDIV_MODE_MFB;
+ } else if (sc->cid.chip_id == BHND_CHIPID_BCM4319) {
+ if (!(xt->ndiv_frac))
+ ndiv_mode = BHND_PMU1_PLL0_PC2_NDIV_MODE_INT;
+ else
+ ndiv_mode = BHND_PMU1_PLL0_PC2_NDIV_MODE_MFB;
+ } else {
+ ndiv_mode = BHND_PMU1_PLL0_PC2_NDIV_MODE_MASH;
+ }
+
+
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ BHND_PMU_SET_BITS(xt->ndiv_int, BHND_PMU1_PLL0_PC2_NDIV_INT) |
+ BHND_PMU_SET_BITS(ndiv_mode, BHND_PMU1_PLL0_PC2_NDIV_MODE),
+ BHND_PMU1_PLL0_PC2_NDIV_INT_MASK |
+ BHND_PMU1_PLL0_PC2_NDIV_MODE_MASK);
+
+ /* Write ndiv_frac to pllcontrol[3] */
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
+ BHND_PMU_SET_BITS(xt->ndiv_frac, BHND_PMU1_PLL0_PC3_NDIV_FRAC),
+ BHND_PMU1_PLL0_PC3_NDIV_FRAC_MASK);
+
+ /* Writing to pllcontrol[4] */
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4319) {
+ uint8_t xs;
+
+ if (!xt->ndiv_frac)
+ plldata = 0x200005c0;
+ else
+ plldata = 0x202C2820;
+
+ if (FVCO < 1600)
+ xs = 4;
+ else
+ xs = 7;
+
+ plldata &= ~(BHND_PMU1_PLL0_PC4_KVCO_XS_MASK);
+ plldata |= BHND_PMU_SET_BITS(xs, BHND_PMU1_PLL0_PC4_KVCO_XS);
+ BHND_PMU_WRITE_4(sc, BHND_PMU1_PLL0_PLLCTL4, plldata);
+ }
+
+ /* Write clock driving strength to pllcontrol[5] */
+ if (buf_strength) {
+ PMU_MSG(("Adjusting PLL buffer drive strength: %x\n",
+ buf_strength));
+
+ plldata = BHND_PMU_SET_BITS(buf_strength,
+ BHND_PMU1_PLL0_PC5_CLK_DRV);
+ pllmask = BHND_PMU1_PLL0_PC5_CLK_DRV_MASK;
+
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4319) {
+ pllmask |=
+ BHND_PMU1_PLL0_PC5_VCO_RNG_MASK |
+ BHND_PMU1_PLL0_PC5_PLL_CTRL_37_32_MASK;
+
+ if (!xt->ndiv_frac) {
+ plldata |= BHND_PMU_SET_BITS(0x25,
+ BHND_PMU1_PLL0_PC5_PLL_CTRL_37_32);
+ } else {
+ plldata |= BHND_PMU_SET_BITS(0x15,
+ BHND_PMU1_PLL0_PC5_PLL_CTRL_37_32);
+ }
+
+ if (FVCO >= 1600) {
+ plldata |= BHND_PMU_SET_BITS(0x1,
+ BHND_PMU1_PLL0_PC5_VCO_RNG);
+ }
+ }
+
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, plldata,
+ pllmask);
+ }
+
+ PMU_MSG(("Done pll\n"));
+
+ /* to operate the 4319 usb in 24MHz/48MHz; chipcontrol[2][84:83] needs
+ * to be updated.
+ */
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4319 &&
+ xt->fref != XTAL_FREQ_30000MHZ)
+ {
+ uint32_t pll_sel;
+
+ switch (xt->fref) {
+ case XTAL_FREQ_24000MHZ:
+ pll_sel = BHND_PMU_CCTL_4319USB_24MHZ_PLL_SEL;
+ break;
+ case XTAL_FREQ_48000MHZ:
+ pll_sel = BHND_PMU_CCTL_4319USB_48MHZ_PLL_SEL;
+ break;
+ default:
+ panic("unsupported 4319USB XTAL frequency: %hu\n",
+ xt->fref);
+ }
+
+ 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);
+ }
+
+ /* Flush deferred pll control registers writes */
+ if (BHND_PMU_REV(sc) >= 2)
+ BHND_PMU_OR_4(sc, BHND_PMU_CTRL, BHND_PMU_CTRL_PLL_PLLCTL_UPD);
+
+ /* Write XtalFreq. Set the divisor also. */
+ pmuctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
+ pmuctrl = ~(BHND_PMU_CTRL_ILP_DIV_MASK | BHND_PMU_CTRL_XTALFREQ_MASK);
+ pmuctrl |= BHND_PMU_SET_BITS(((xt->fref + 127) / 128) - 1,
+ BHND_PMU_CTRL_ILP_DIV);
+ pmuctrl |= BHND_PMU_SET_BITS(xt->xf, BHND_PMU_CTRL_XTALFREQ);
+
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4329 && sc->cid.chip_rev == 0) {
+ /* clear the htstretch before clearing HTReqEn */
+ BHND_PMU_AND_4(sc, BHND_PMU_CLKSTRETCH, ~BHND_PMU_CLKSTRETCH);
+ pmuctrl &= ~BHND_PMU_CTRL_HT_REQ_EN;
+ }
+
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CTRL, pmuctrl);
+}
+
+/* query the CPU clock frequency */
+static uint32_t
+bhnd_pmu1_cpuclk0(struct bhnd_pmu_softc *sc)
+{
+ uint32_t tmp, m1div;
+#ifdef BCMDBG
+ uint32_t ndiv_int, ndiv_frac, p2div, p1div, fvco;
+ uint32_t fref;
+#endif
+ uint32_t FVCO = bhnd_pmu1_pllfvco0(sc);
+
+ /* Read m1div from pllcontrol[1] */
+ tmp = BHND_PMU_PLL_READ(sc, BHND_PMU1_PLL0_PLLCTL1);
+ m1div = BHND_PMU_GET_BITS(tmp, BHND_PMU1_PLL0_PC1_M1DIV);
+
+#ifdef BCMDBG
+ /* Read p2div/p1div from pllcontrol[0] */
+ tmp = BHND_PMU_PLL_READ(sc, BHND_PMU1_PLL0_PLLCTL0);
+ p2div = BHND_PMU_GET_BITS(tmp, BHND_PMU1_PLL0_PC0_P2DIV);
+ p1div = BHND_PMU_GET_BITS(tmp, BHND_PMU1_PLL0_PC0_P1DIV);
+
+ /* Calculate fvco based on xtal freq and ndiv and pdiv */
+ tmp = BHND_PMU_PLL_READ(sc, BHND_PMU1_PLL0_PLLCTL2);
+ ndiv_int = BHND_PMU_GET_BITS(tmp, BHND_PMU1_PLL0_PC2_NDIV_INT);
+
+ tmp = BHND_PMU_PLL_READ(sc, BHND_PMU1_PLL0_PLLCTL3);
+ ndiv_frac = BHND_PMU_GET_BITS(tmp, BHND_PMU1_PLL0_PC3_NDIV_FRAC);
+
+ fref = bhnd_pmu1_alpclk0(sc) / 1000;
+
+ fvco = (fref * ndiv_int) << 8;
+ fvco += (fref * (ndiv_frac >> 12)) >> 4;
+ fvco += (fref * (ndiv_frac & 0xfff)) >> 12;
+ fvco >>= 8;
+ fvco *= p2div;
+ fvco /= p1div;
+ fvco /= 1000;
+ fvco *= 1000;
+
+ PMU_MSG(("bhnd_pmu1_cpuclk0: ndiv_int %u ndiv_frac %u p2div %u "
+ "p1div %u fvco %u\n", ndiv_int, ndiv_frac, p2div, p1div, fvco));
+
+ FVCO = fvco;
+#endif /* BCMDBG */
+
+ /* Return ARM/SB clock */
+ return (FVCO / m1div * 1000);
+}
+
+/* initialize PLL */
+void
+bhnd_pmu_pll_init(struct bhnd_pmu_softc *sc, u_int xtalfreq)
+{
+ uint32_t max_mask, min_mask;
+ uint32_t res_ht, res_pll;
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4312:
+ /* assume default works */
+ break;
+ case BHND_CHIPID_BCM4322:
+ case BHND_CHIPID_BCM43221:
+ case BHND_CHIPID_BCM43231:
+ case BHND_CHIPID_BCM4342:
+ if (sc->cid.chip_rev != 0)
+ break;
+
+ min_mask = BHND_PMU_READ_4(sc, BHND_PMU_MIN_RES_MASK);
+ max_mask = BHND_PMU_READ_4(sc, BHND_PMU_MIN_RES_MASK);
+ res_ht = PMURES_BIT(RES4322_HT_SI_AVAIL);
+ res_pll = PMURES_BIT(RES4322_SI_PLL_ON);
+
+ /* Have to remove HT Avail request before powering off PLL */
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~res_ht);
+ BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~res_ht);
+ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL);
+
+ /* Make sure the PLL is off */
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~res_pll);
+ BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~res_pll);
+ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL);
+
+ DELAY(1000);
+
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU2_SI_PLL_PLLCTL, 0x380005c0, ~0);
+ DELAY(100);
+
+ BHND_PMU_WRITE_4(sc, BHND_PMU_MAX_RES_MASK, max_mask);
+ DELAY(100);
+ BHND_PMU_WRITE_4(sc, BHND_PMU_MIN_RES_MASK, min_mask);
+ DELAY(100);
+
+ break;
+ case BHND_CHIPID_BCM4325:
+ bhnd_pmu1_pllinit0(sc, xtalfreq);
+ break;
+ case BHND_CHIPID_BCM4328:
+ bhnd_pmu0_pllinit0(sc, xtalfreq);
+ break;
+ case BHND_CHIPID_BCM5354:
+ if (xtalfreq == 0)
+ xtalfreq = 25000;
+ bhnd_pmu0_pllinit0(sc, xtalfreq);
+ break;
+ case BHND_CHIPID_BCM4329:
+ if (xtalfreq == 0)
+ xtalfreq = 38400;
+ bhnd_pmu1_pllinit0(sc, xtalfreq);
+ break;
+
+ case BHND_CHIPID_BCM4313:
+ case BHND_CHIPID_BCM43222:
+ case BHND_CHIPID_BCM43111:
+ case BHND_CHIPID_BCM43112:
+ case BHND_CHIPID_BCM43224:
+ case BHND_CHIPID_BCM43225:
+ case BHND_CHIPID_BCM43420:
+ case BHND_CHIPID_BCM43421:
+ case BHND_CHIPID_BCM43226:
+ case BHND_CHIPID_BCM43235:
+ case BHND_CHIPID_BCM43236:
+ case BHND_CHIPID_BCM43238:
+ case BHND_CHIPID_BCM43234:
+ case BHND_CHIPID_BCM43237:
+ case BHND_CHIPID_BCM4331:
+ case BHND_CHIPID_BCM43431:
+ case BHND_CHIPID_BCM43131:
+ case BHND_CHIPID_BCM43227:
+ case BHND_CHIPID_BCM43228:
+ case BHND_CHIPID_BCM43428:
+ case BHND_CHIPID_BCM6362:
+ /* assume default works */
+ break;
+
+ case BHND_CHIPID_BCM4315:
+ case BHND_CHIPID_BCM4319:
+ case BHND_CHIPID_BCM4336:
+ case BHND_CHIPID_BCM4330:
+ bhnd_pmu1_pllinit0(sc, xtalfreq);
+ break;
+ default:
+ PMU_MSG(("No PLL init done for chip %#hx rev %d pmurev %d\n",
+ sc->cid.chip_id, sc->cid.chip_rev, BHND_PMU_REV(sc)));
+ break;
+ }
+}
+
+/* query alp/xtal clock frequency */
+uint32_t
+bhnd_pmu_alp_clock(struct bhnd_pmu_softc *sc)
+{
+ uint32_t clock;
+
+ clock = BHND_PMU_ALP_CLOCK;
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4328:
+ case BHND_CHIPID_BCM5354:
+ clock = bhnd_pmu0_alpclk0(sc);
+ break;
+ case BHND_CHIPID_BCM4315:
+ case BHND_CHIPID_BCM4319:
+ case BHND_CHIPID_BCM4325:
+ case BHND_CHIPID_BCM4329:
+ case BHND_CHIPID_BCM4330:
+ case BHND_CHIPID_BCM4336:
+ clock = bhnd_pmu1_alpclk0(sc);
+ break;
+ case BHND_CHIPID_BCM4312:
+ case BHND_CHIPID_BCM4322:
+ case BHND_CHIPID_BCM43221:
+ case BHND_CHIPID_BCM43231:
+ case BHND_CHIPID_BCM43222:
+ case BHND_CHIPID_BCM43111:
+ case BHND_CHIPID_BCM43112:
+ case BHND_CHIPID_BCM43224:
+ case BHND_CHIPID_BCM43225:
+ case BHND_CHIPID_BCM43420:
+ case BHND_CHIPID_BCM43421:
+ case BHND_CHIPID_BCM43226:
+ case BHND_CHIPID_BCM43235:
+ case BHND_CHIPID_BCM43236:
+ case BHND_CHIPID_BCM43238:
+ case BHND_CHIPID_BCM43234:
+ case BHND_CHIPID_BCM43237:
+ case BHND_CHIPID_BCM4331:
+ case BHND_CHIPID_BCM43431:
+ case BHND_CHIPID_BCM43131:
+ case BHND_CHIPID_BCM43227:
+ case BHND_CHIPID_BCM43228:
+ case BHND_CHIPID_BCM43428:
+ case BHND_CHIPID_BCM6362:
+ case BHND_CHIPID_BCM4342:
+ case BHND_CHIPID_BCM4716:
+ case BHND_CHIPID_BCM4748:
+ case BHND_CHIPID_BCM47162:
+ case BHND_CHIPID_BCM4313:
+ case BHND_CHIPID_BCM5357:
+ case BHND_CHIPID_BCM4749:
+ case BHND_CHIPID_BCM53572:
+ /* always 20Mhz */
+ clock = 20000 * 1000;
+ break;
+ case BHND_CHIPID_BCM5356:
+ case BHND_CHIPID_BCM4706:
+ /* always 25Mhz */
+ clock = 25000 * 1000;
+ break;
+ default:
+ PMU_MSG(("No ALP clock specified "
+ "for chip %s rev %d pmurev %d, using default %d Hz\n",
+ bcm_chipname(sih->chip, chn, 8), sih->chiprev,
+ sih->pmurev, clock));
+ break;
+ }
+
+ return (clock);
+}
+
+/* Find the output of the "m" pll divider given pll controls that start with
+ * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
+ */
+static uint32_t
+bhnd_pmu5_clock(struct bhnd_pmu_softc *sc, u_int pll0, u_int m)
+{
+ uint32_t div;
+ uint32_t fc;
+ uint32_t ndiv;
+ uint32_t p1, p2;
+ uint32_t tmp;
+
+ if ((pll0 & 3) || (pll0 > BHND_PMU4716_MAINPLL_PLL0)) {
+ PMU_ERROR(("%s: Bad pll0: %d\n", __func__, pll0));
+ return (0);
+ }
+
+ /* Strictly there is an m5 divider, but I'm not sure we use it */
+ if ((m == 0) || (m > 4)) {
+ PMU_ERROR(("%s: Bad m divider: %d\n", __func__, m));
+ return (0);
+ }
+
+ if (sc->cid.chip_id == BHND_CHIPID_BCM5357 ||
+ sc->cid.chip_id == BHND_CHIPID_BCM4749)
+ {
+ /* Detect failure in clock setting */
+ tmp = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
+ if ((tmp & 0x40000) != 0)
+ return (133 * 1000000);
+ }
+
+
+ /* Fetch p1 and p2 */
+ BHND_PMU_WRITE_4(sc, BHND_PMU_PLL_CONTROL_ADDR,
+ pll0 + BHND_PMU5_PLL_P1P2_OFF);
+ BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_ADDR);
+
+ tmp = BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_DATA);
+ p1 = BHND_PMU_GET_BITS(tmp, BHND_PMU5_PLL_P1);
+ p2 = BHND_PMU_GET_BITS(tmp, BHND_PMU5_PLL_P2);
+
+ /* Fetch div */
+ BHND_PMU_WRITE_4(sc, BHND_PMU_PLL_CONTROL_ADDR,
+ pll0 + BHND_PMU5_PLL_M14_OFF);
+ BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_ADDR);
+
+ tmp = BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_DATA);
+ div = (tmp >> ((m - 1) * BHND_PMU5_PLL_MDIV_WIDTH));
+ div &= BHND_PMU5_PLL_MDIV_MASK;
+
+ /* Fetch ndiv */
+ BHND_PMU_WRITE_4(sc, BHND_PMU_PLL_CONTROL_ADDR,
+ pll0 + BHND_PMU5_PLL_NM5_OFF);
+ BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_ADDR);
+
+ tmp = BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_DATA);
+ ndiv = BHND_PMU_GET_BITS(tmp, BHND_PMU5_PLL_NDIV);
+
+ /* Do calculation in Mhz */
+ fc = bhnd_pmu_alp_clock(sc) / 1000000;
+ fc = (p1 * ndiv * fc) / p2;
+
+ PMU_MSG(("%s: p1=%d, p2=%d, ndiv=%d(0x%x), m%d=%d; fc=%d, clock=%d\n",
+ __func__, p1, p2, ndiv, ndiv, m, div, fc, fc / div));
+
+ /* Return clock in Hertz */
+ return ((fc / div) * 1000000);
+}
+
+/* query backplane clock frequency */
+/* For designs that feed the same clock to both backplane
+ * and CPU just return the CPU clock speed.
+ */
+uint32_t
+bhnd_pmu_si_clock(struct bhnd_pmu_softc *sc)
+{
+ uint32_t chipst;
+ uint32_t clock;
+
+ clock = BHND_PMU_HT_CLOCK;
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4322:
+ case BHND_CHIPID_BCM43221:
+ case BHND_CHIPID_BCM43231:
+ case BHND_CHIPID_BCM43222:
+ case BHND_CHIPID_BCM43111:
+ case BHND_CHIPID_BCM43112:
+ case BHND_CHIPID_BCM43224:
+ case BHND_CHIPID_BCM43420:
+ case BHND_CHIPID_BCM43225:
+ case BHND_CHIPID_BCM43421:
+ case BHND_CHIPID_BCM43226:
+ case BHND_CHIPID_BCM4331:
+ case BHND_CHIPID_BCM43431:
+ case BHND_CHIPID_BCM6362:
+ case BHND_CHIPID_BCM4342:
+ /* 96MHz backplane clock */
+ clock = 96000 * 1000;
+ break;
+
+ case BHND_CHIPID_BCM4716:
+ case BHND_CHIPID_BCM4748:
+ case BHND_CHIPID_BCM47162:
+ clock = bhnd_pmu5_clock(sc, BHND_PMU4716_MAINPLL_PLL0,
+ BHND_PMU5_MAINPLL_SI);
+ break;
+
+ case BHND_CHIPID_BCM4325:
+ clock = bhnd_pmu1_cpuclk0(sc);
+ break;
+
+ case BHND_CHIPID_BCM4328:
+ clock = bhnd_pmu0_cpuclk0(sc);
+ break;
+
+ case BHND_CHIPID_BCM4329:
+ if (sc->cid.chip_rev == 0)
+ clock = 38400 * 1000;
+ else
+ clock = bhnd_pmu1_cpuclk0(sc);
+ break;
+
+ case BHND_CHIPID_BCM4315:
+ case BHND_CHIPID_BCM4319:
+ case BHND_CHIPID_BCM4336:
+ case BHND_CHIPID_BCM4330:
+ clock = bhnd_pmu1_cpuclk0(sc);
+ break;
+
+ case BHND_CHIPID_BCM4313:
+ /* 80MHz backplane clock */
+ clock = 80000 * 1000;
+ break;
+
+ case BHND_CHIPID_BCM43234:
+ case BHND_CHIPID_BCM43235:
+ case BHND_CHIPID_BCM43236:
+ case BHND_CHIPID_BCM43238:
+ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
+ if (chipst & CHIPC_CST43236_BP_CLK)
+ clock = 120000 * 1000;
+ else
+ clock = 96000 * 1000;
+ break;
+ case BHND_CHIPID_BCM43237:
+ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
+ if (chipst & CHIPC_CST43237_BP_CLK)
+ clock = 96000 * 1000;
+ else
+ clock = 80000 * 1000;
+ break;
+ case BHND_CHIPID_BCM5356:
+ clock = bhnd_pmu5_clock(sc, BHND_PMU5356_MAINPLL_PLL0,
+ BHND_PMU5_MAINPLL_SI);
+ break;
+ case BHND_CHIPID_BCM5357:
+ case BHND_CHIPID_BCM4749:
+ clock = bhnd_pmu5_clock(sc, BHND_PMU5357_MAINPLL_PLL0,
+ BHND_PMU5_MAINPLL_SI);
+ break;
+ case BHND_CHIPID_BCM53572:
+ clock = 75000000;
+ break;
+ default:
+ device_printf(sc->dev, "No backplane clock specified for chip "
+ "%#hx rev %hhd pmurev %hhd, using default %dHz\n",
+ sc->cid.chip_id, sc->cid.chip_rev, BHND_PMU_REV(sc), clock);
+ break;
+ }
+
+ return (clock);
+}
+
+/* query CPU clock frequency */
+uint32_t
+bhnd_pmu_cpu_clock(struct bhnd_pmu_softc *sc)
+{
+ uint32_t clock;
+
+ if (sc->cid.chip_id == BHND_CHIPID_BCM5354)
+ return (240 * 1000 * 1000); /* 240MHz */
+
+ /* 5354 chip uses a non programmable PLL of frequency 240MHz */
+ if (sc->cid.chip_id == BHND_CHIPID_BCM5354)
+ return (240000000);
+
+ if (sc->cid.chip_id == BHND_CHIPID_BCM53572)
+ return (300000000);
+
+ if (BHND_PMU_REV(sc) >= 5 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM4329 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM4319 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM43234 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM43235 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM43236 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM43237 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM43238 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM4336 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM4330)
+ {
+ u_int pll;
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM5356:
+ pll = BHND_PMU5356_MAINPLL_PLL0;
+ break;
+ case BHND_CHIPID_BCM5357:
+ case BHND_CHIPID_BCM4749:
+ pll = BHND_PMU5357_MAINPLL_PLL0;
+ break;
+ default:
+ pll = BHND_PMU4716_MAINPLL_PLL0;
+ break;
+ }
+
+ clock = bhnd_pmu5_clock(sc, pll, BHND_PMU5_MAINPLL_CPU);
+ } else {
+ clock = bhnd_pmu_si_clock(sc);
+ }
+
+ return (clock);
+}
+
+/* query memory clock frequency */
+uint32_t
+bhnd_pmu_mem_clock(struct bhnd_pmu_softc *sc)
+{
+ uint32_t clock;
+
+ if (BHND_PMU_REV(sc) >= 5 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM4329 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM4319 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM43234 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM43235 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM43236 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM43237 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM43238 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM4336 &&
+ sc->cid.chip_id != BHND_CHIPID_BCM4330)
+ {
+ u_int pll;
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM5356:
+ pll = BHND_PMU5356_MAINPLL_PLL0;
+ break;
+ case BHND_CHIPID_BCM5357:
+ case BHND_CHIPID_BCM4749:
+ pll = BHND_PMU5357_MAINPLL_PLL0;
+ break;
+ default:
+ pll = BHND_PMU4716_MAINPLL_PLL0;
+ break;
+ }
+
+ clock = bhnd_pmu5_clock(sc, pll, BHND_PMU5_MAINPLL_MEM);
+ } else {
+ clock = bhnd_pmu_si_clock(sc);
+ }
+
+ return (clock);
+}
+
+/* Measure ILP clock frequency */
+#define ILP_CALC_DUR 10 /* ms, make sure 1000 can be divided by it. */
+
+uint32_t
+bhnd_pmu_ilp_clock(struct bhnd_pmu_softc *sc)
+{
+ uint32_t start, end, delta;
+
+ if (sc->ilp_cps == 0) {
+ start = BHND_PMU_READ_4(sc, BHND_PMU_TIMER);
+ DELAY(ILP_CALC_DUR);
+ end = BHND_PMU_READ_4(sc, BHND_PMU_TIMER);
+ delta = end - start;
+ sc->ilp_cps = delta * (1000 / ILP_CALC_DUR);
+ }
+
+ return (sc->ilp_cps);
+}
+
+/* SDIO Pad drive strength to select value mappings */
+typedef struct {
+ uint8_t strength; /* Pad Drive Strength in mA */
+ uint8_t sel; /* Chip-specific select value */
+} sdiod_drive_str_t;
+
+/* SDIO Drive Strength to sel value table for PMU Rev 1 */
+static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = {
+ {
+ 4, 0x2}, {
+ 2, 0x3}, {
+ 1, 0x0}, {
+ 0, 0x0}
+ };
+
+/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
+static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = {
+ {
+ 12, 0x7}, {
+ 10, 0x6}, {
+ 8, 0x5}, {
+ 6, 0x4}, {
+ 4, 0x2}, {
+ 2, 0x1}, {
+ 0, 0x0}
+ };
+
+/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
+static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = {
+ {
+ 32, 0x7}, {
+ 26, 0x6}, {
+ 22, 0x5}, {
+ 16, 0x4}, {
+ 12, 0x3}, {
+ 8, 0x2}, {
+ 4, 0x1}, {
+ 0, 0x0}
+ };
+
+#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
+
+void
+bhnd_pmu_sdiod_drive_strength_init(struct bhnd_pmu_softc *sc,
+ uint32_t drivestrength)
+{
+ const sdiod_drive_str_t *str_tab;
+ uint32_t str_mask;
+ uint32_t str_shift;
+ u_int intr_val;
+
+ str_tab = NULL;
+ str_mask = 0;
+ str_shift = 0;
+ intr_val = 0;
+
+ switch (SDIOD_DRVSTR_KEY(sc->cid.chip_id, BHND_PMU_REV(sc))) {
+ case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4325, 1):
+ str_tab = sdiod_drive_strength_tab1;
+ str_mask = 0x30000000;
+ str_shift = 28;
+ break;
+ case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4325, 2):
+ case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4325, 3):
+ case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4315, 4):
+ case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4319, 7):
+ str_tab = sdiod_drive_strength_tab2;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+ case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4336, 8):
+ str_tab = sdiod_drive_strength_tab3;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+
+ default:
+ device_printf(sc->dev, "No SDIO Drive strength init done for "
+ "chip %#x rev %hhd pmurev %hhd\n", sc->cid.chip_id,
+ sc->cid.chip_rev, BHND_PMU_REV(sc));
+ break;
+ }
+
+ if (str_tab != NULL) {
+ uint32_t drivestrength_sel = 0;
+ uint32_t cc_data_temp;
+
+ for (u_int i = 0; str_tab[i].strength != 0; i++) {
+ if (drivestrength >= str_tab[i].strength) {
+ drivestrength_sel = str_tab[i].sel;
+ break;
+ }
+ }
+
+ cc_data_temp = BHND_PMU_CCTRL_READ(sc, 1);
+ cc_data_temp &= ~str_mask;
+ drivestrength_sel <<= str_shift;
+ cc_data_temp |= drivestrength_sel;
+ BHND_PMU_CCTRL_WRITE(sc, 1, cc_data_temp, ~0);
+
+ PMU_MSG(("SDIO: %dmA drive strength selected, set to 0x%08x\n",
+ drivestrength, cc_data_temp));
+ }
+}
+
+/**
+ * Initialize the PMU.
+ */
+int
+bhnd_pmu_init(struct bhnd_pmu_softc *sc)
+{
+ uint32_t xtalfreq;
+ int error;
+
+ if (BHND_PMU_REV(sc) == 1) {
+ BHND_PMU_AND_4(sc, BHND_PMU_CTRL, ~BHND_PMU_CTRL_NOILP_ON_WAIT);
+ } else if (BHND_PMU_REV(sc) >= 2) {
+ BHND_PMU_OR_4(sc, BHND_PMU_CTRL, BHND_PMU_CTRL_NOILP_ON_WAIT);
+ }
+
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4329 && sc->cid.chip_rev == 2) {
+ /* Fix for 4329b0 bad LPOM state. */
+ BHND_PMU_REGCTRL_WRITE(sc, 2, 0x100, ~0);
+ BHND_PMU_REGCTRL_WRITE(sc, 3, 0x4, ~0);
+ }
+
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4319) {
+ /* Limiting the PALDO spike during init time */
+ BHND_PMU_REGCTRL_WRITE(sc, 2, 0x00000005, 0x00000007);
+ }
+
+
+ /* Fetch target xtalfreq, in KHz */
+ error = bhnd_nvram_getvar_uint32(sc->chipc_dev, BHND_NVAR_XTALFREQ,
+ &xtalfreq);
+
+ /* If not available, log any real errors, and then try to measure it */
+ if (error) {
+ if (error != ENOENT) {
+ device_printf(sc->dev, "error fetching xtalfreq: %d\n",
+ error);
+ }
+
+ xtalfreq = bhnd_pmu_measure_alpclk(sc);
+ }
+
+ /* Perform PLL initialization */
+ bhnd_pmu_pll_init(sc, xtalfreq);
+
+ if ((error = bhnd_pmu_res_init(sc)))
+ return (error);
+
+ bhnd_pmu_swreg_init(sc);
+
+ return (0);
+}
+
+/* Return up time in ILP cycles for the given resource. */
+static int
+bhnd_pmu_res_uptime(struct bhnd_pmu_softc *sc, uint8_t rsrc, uint32_t *uptime)
+{
+ uint32_t deps;
+ uint32_t up, dup, dmax;
+ uint32_t min_mask;
+ int error;
+
+ /* uptime of resource 'rsrc' */
+ BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, rsrc);
+ up = BHND_PMU_READ_4(sc, BHND_PMU_RES_UPDN_TIMER);
+ up = BHND_PMU_GET_BITS(up, BHND_PMU_RES_UPDN_UPTME);
+
+ /* Find direct dependencies of resource 'rsrc' */
+ deps = bhnd_pmu_res_deps(sc, BHND_PMURES_BIT(rsrc), false);
+ for (uint8_t i = 0; i <= BHND_PMU_RESNUM_MAX; i++) {
+ if (!(deps & BHND_PMURES_BIT(i)))
+ continue;
+ deps &= ~bhnd_pmu_res_deps(sc, BHND_PMURES_BIT(i), true);
+ }
+
+ /* Exclude the minimum resource set */
+ if ((error = bhnd_pmu_res_masks(sc, &min_mask, NULL)))
+ return (error);
+
+ deps &= ~min_mask;
+
+ /* max uptime of direct dependencies */
+ dmax = 0;
+ for (uint8_t i = 0; i <= BHND_PMU_RESNUM_MAX; i++) {
+ if (!(deps & BHND_PMURES_BIT(i)))
+ continue;
+
+ if ((error = bhnd_pmu_res_uptime(sc, i, &dup)))
+ return (error);
+
+ if (dmax < dup)
+ dmax = dup;
+ }
+
+ PMU_MSG(("bhnd_pmu_res_uptime: rsrc %hhu uptime %u(deps 0x%08x "
+ "uptime %u)\n", rsrc, up, deps, dmax));
+
+ *uptime = (up + dmax + BHND_PMURES_UP_TRANSITION);
+ return (0);
+}
+
+/* Return dependencies (direct or all/indirect) for the given resources */
+static uint32_t
+bhnd_pmu_res_deps(struct bhnd_pmu_softc *sc, uint32_t rsrcs, bool all)
+{
+ uint32_t deps;
+
+ deps = 0;
+ for (uint8_t i = 0; i <= BHND_PMU_RESNUM_MAX; i++) {
+ if (!(rsrcs & BHND_PMURES_BIT(i)))
+ continue;
+
+ BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i);
+ deps |= BHND_PMU_READ_4(sc, BHND_PMU_RES_DEP_MASK);
+ }
+
+ /* None found? */
+ if (deps == 0)
+ return (0);
+
+ /* Recurse dependencies */
+ if (all)
+ deps |= bhnd_pmu_res_deps(sc, deps, true);
+
+ return (deps);
+}
+
+/* power up/down OTP through PMU resources */
+int
+bhnd_pmu_otp_power(struct bhnd_pmu_softc *sc, bool on)
+{
+ uint32_t deps;
+ uint32_t min_mask;
+ uint32_t rsrcs;
+ int error;
+
+ /* Determine rsrcs to turn on/off OTP power */
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4322:
+ case BHND_CHIPID_BCM43221:
+ case BHND_CHIPID_BCM43231:
+ case BHND_CHIPID_BCM4342:
+ rsrcs = PMURES_BIT(RES4322_OTP_PU);
+ break;
+ case BHND_CHIPID_BCM4315:
+ rsrcs = PMURES_BIT(RES4315_OTP_PU);
+ break;
+ case BHND_CHIPID_BCM4325:
+ rsrcs = PMURES_BIT(RES4325_OTP_PU);
+ break;
+ case BHND_CHIPID_BCM4329:
+ rsrcs = PMURES_BIT(RES4329_OTP_PU);
+ break;
+ case BHND_CHIPID_BCM4319:
+ rsrcs = PMURES_BIT(RES4319_OTP_PU);
+ break;
+ case BHND_CHIPID_BCM4336:
+ rsrcs = PMURES_BIT(RES4336_OTP_PU);
+ break;
+ case BHND_CHIPID_BCM4330:
+ rsrcs = PMURES_BIT(RES4330_OTP_PU);
+ break;
+ default:
+ /* Not required? */
+ return (0);
+ }
+
+ /* Fetch all dependencies */
+ deps = bhnd_pmu_res_deps(sc, rsrcs, true);
+
+ /* Exclude the minimum resource set */
+ if ((error = bhnd_pmu_res_masks(sc, &min_mask, NULL)))
+ return (error);
+
+ deps &= ~min_mask;
+
+ /* Turn on/off the power */
+ if (on) {
+ uint32_t state;
+
+ PMU_MSG(("Adding rsrc 0x%x to min_res_mask\n",
+ rsrcs | deps));
+ BHND_PMU_OR_4(sc, BHND_PMU_MIN_RES_MASK, (rsrcs|deps));
+
+ /* Wait for all resources to become available */
+ for (int i = 0; i < BHND_PMU_MAX_TRANSITION_DLY; i += 10) {
+ state = BHND_PMU_READ_4(sc, BHND_PMU_RES_STATE);
+ if ((state & rsrcs) == rsrcs)
+ break;
+
+ DELAY(10);
+ }
+
+ if ((state & rsrcs) != rsrcs) {
+ device_printf(sc->dev, "timeout waiting for OTP "
+ "resource enable\n");
+ return (ENXIO);
+ }
+ } else {
+ PMU_MSG(("Removing rsrc 0x%x from min_res_mask\n",
+ rsrcs | deps));
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~(rsrcs|deps));
+ }
+
+ return (0);
+}
+
+void
+bhnd_pmu_rcal(struct bhnd_pmu_softc *sc)
+{
+ uint32_t chipst;
+ uint32_t val;
+ uint8_t rcal_code;
+ bool bluetooth_rcal;
+
+
+ bluetooth_rcal = false;
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4325:
+ case BHND_CHIPID_BCM4329:
+ /* Kick RCal */
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 1);
+
+ /* Power Down RCAL Block */
+ BHND_PMU_AND_4(sc, BHND_PMU_CHIPCTL_DATA, ~0x04);
+
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4325) {
+ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
+ if (BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_RCAL_VALID))
+ bluetooth_rcal = true;
+ }
+
+ /* Power Up RCAL block */
+ BHND_PMU_AND_4(sc, BHND_PMU_CHIPCTL_DATA, 0x04);
+
+ /* Wait for completion */
+ for (int i = 0; i < (10 * 1000 * 1000); i++) {
+ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
+
+ if (chipst & 0x08)
+ break;
+
+ DELAY(10);
+ }
+ KASSERT((chipst & 0x08) != 0, ("rcal completion timeout"));
+
+ if (bluetooth_rcal) {
+ rcal_code = 0x6;
+ } else {
+ /* Drop LSB to convert from 5 bit code to 4 bit code */
+ rcal_code = (uint8_t) (chipst >> 5) & 0x0f;
+ }
+
+ PMU_MSG(("RCal completed, status 0x%x, code 0x%x\n",
+ R_REG(&cc->chipstatus), rcal_code));
+
+ /* Write RCal code into pmu_vreg_ctrl[32:29] */
+ BHND_PMU_WRITE_4(sc, BHND_PMU_REG_CONTROL_ADDR, 0);
+ val = BHND_PMU_READ_4(sc, BHND_PMU_REG_CONTROL_DATA);
+ val &= ~((uint32_t) 0x07 << 29);
+ val |= (uint32_t) (rcal_code & 0x07) << 29;
+ BHND_PMU_WRITE_4(sc, BHND_PMU_REG_CONTROL_DATA, val);
+
+ BHND_PMU_WRITE_4(sc, BHND_PMU_REG_CONTROL_ADDR, 1);
+ val = BHND_PMU_READ_4(sc, BHND_PMU_REG_CONTROL_DATA);
+ val &= ~(uint32_t) 0x01;
+ val |= (uint32_t) ((rcal_code >> 3) & 0x01);
+ 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);
+ 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_CHIPCTL_ADDR, 1);
+ val = BHND_PMU_READ_4(sc, BHND_PMU_CHIPCTL_DATA);
+ val &= ~(uint32_t) 0x03;
+ val |= (uint32_t) ((rcal_code >> 2) & 0x03);
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_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));
+
+ /* Power off RCal block */
+ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 1);
+ BHND_PMU_AND_4(sc, BHND_PMU_CHIPCTL_DATA, ~0x04);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+bhnd_pmu_spuravoid(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
+{
+ /* force the HT off */
+ if (sc->cid.chip_id == BHND_CHIPID_BCM4336) {
+ BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK,
+ ~BHND_PMU_RES4336_HT_AVAIL);
+
+ /* wait for the ht to really go away */
+ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL);
+ }
+
+ /* update the pll changes */
+ 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);
+ }
+}
+
+static void
+bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t 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 };
+
+ /* 6362a0 has same clks as 4322[4-6] */
+ chip_id = sc->cid.chip_id;
+ if (chip_id == BHND_CHIPID_BCM6362 && sc->cid.chip_rev == 0) {
+ chip_id = BHND_CHIPID_BCM43224;
+ }
+
+ switch (chip_id) {
+ case BHND_CHIPID_BCM6362:
+ KASSERT(sc->cid.chip_rev != 0, ("invalid clock config"));
+ /* fallthrough */
+ case BHND_CHIPID_BCM5357:
+ case BHND_CHIPID_BCM4749:
+ case BHND_CHIPID_BCM43235:
+ case BHND_CHIPID_BCM43236:
+ 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));
+
+ /* BCM5357 needs to touch PLL1_PLLCTL[02], so offset
+ * PLL0_PLLCTL[02] by 6 */
+ phypll_offset = 0;
+ if (sc->cid.chip_id == BHND_CHIPID_BCM5357)
+ phypll_offset = 6;
+
+ /* RMW only the P1 divider */
+ tmp = BHND_PMU_SET_BITS(bcm5357_bcm43236_p1div[spuravoid],
+ 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);
+ 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) {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
+ 0x11500014, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x0FC00a08, ~0);
+ } else if (spuravoid == 1) {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
+ 0x11500014, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x0F600a08, ~0);
+ } else {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
+ 0x11100014, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x03000a08, ~0);
+ }
+ pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
+ break;
+
+ case BHND_CHIPID_BCM43224:
+ case BHND_CHIPID_BCM43225:
+ case BHND_CHIPID_BCM43226:
+ case BHND_CHIPID_BCM43421:
+ if (spuravoid == 1) {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
+ 0x11500010, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
+ 0x000C0C06, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x0F600a08, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
+ 0x00000000, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
+ 0x2001E920, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
+ 0x88888815, ~0);
+ } else {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
+ 0x11100010, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
+ 0x000c0c06, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x03000a08, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
+ 0x00000000, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
+ 0x200005c0, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
+ 0x88888815, ~0);
+ }
+ pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
+ break;
+
+ case BHND_CHIPID_BCM43111:
+ case BHND_CHIPID_BCM43112:
+ case BHND_CHIPID_BCM43222:
+ case BHND_CHIPID_BCM43420:
+ if (spuravoid == 1) {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
+ 0x11500008, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
+ 0x0c000c06, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x0f600a08, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
+ 0x00000000, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
+ 0x2001e920, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
+ 0x88888815, ~0);
+ } else {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
+ 0x11100008, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
+ 0x0c000c06, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x03000a08, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
+ 0x00000000, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
+ 0x200005c0, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
+ 0x88888855, ~0);
+ }
+
+ pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
+ break;
+
+ case BHND_CHIPID_BCM4716:
+ case BHND_CHIPID_BCM4748:
+ case BHND_CHIPID_BCM47162:
+ if (spuravoid == 1) {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
+ 0x11500060, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
+ 0x080C0C06, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x0F600000, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
+ 0x00000000, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
+ 0x2001E924, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
+ 0x88888815, ~0);
+ } else {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
+ 0x11100060, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
+ 0x080c0c06, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x03000000, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
+ 0x00000000, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
+ 0x200005c0, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
+ 0x88888815, ~0);
+ }
+
+ pmuctrl = BHND_PMU_CTRL_NOILP_ON_WAIT |
+ BHND_PMU_CTRL_PLL_PLLCTL_UPD;
+ break;
+
+ case BHND_CHIPID_BCM4319:
+ break;
+
+ case BHND_CHIPID_BCM4322:
+ case BHND_CHIPID_BCM43221:
+ case BHND_CHIPID_BCM43231:
+ case BHND_CHIPID_BCM4342:
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11100070, ~0);
+ 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 {
+ /* enable 40/80/160Mhz clock mode */
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x05001828, ~0);
+ }
+
+ pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
+ break;
+
+ case BHND_CHIPID_BCM4336:
+ /* Looks like these are only for default xtal freq 26MHz */
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x02100020, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x0C0C0C0C, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x01240C0C, ~0);
+ 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;
+ }
+ 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:
+ case BHND_CHIPID_BCM43428:
+ /* LCNXN */
+ /* PLL Settings for spur avoidance on/off mode, no on2 support
+ * for 43228A0 */
+ if (spuravoid == 1) {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
+ 0x01100014, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
+ 0x040C0C06, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x03140A08, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
+ 0x00333333, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
+ 0x202C2820, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
+ 0x88888815, ~0);
+ } else {
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0,
+ 0x11100014, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1,
+ 0x040c0c06, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2,
+ 0x03000a08, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3,
+ 0x00000000, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4,
+ 0x200005c0, ~0);
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5,
+ 0x88888815, ~0);
+ }
+ pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
+ break;
+ default:
+ PMU_ERROR(("%s: unknown spuravoidance settings for chip %#hx, "
+ "not changing PLL\n", __func__, sc->cid.chip_id));
+ break;
+ }
+
+ BHND_PMU_OR_4(sc, BHND_PMU_CTRL, pmuctrl);
+}
+
+bool
+bhnd_pmu_is_otp_powered(struct bhnd_pmu_softc *sc)
+{
+ uint32_t otp_res;
+
+ /* Determine per-chip OTP resource */
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4329:
+ otp_res = PMURES_BIT(RES4329_OTP_PU);
+ break;
+ case BHND_CHIPID_BCM4319:
+ otp_res = PMURES_BIT(RES4319_OTP_PU);
+ break;
+ case BHND_CHIPID_BCM4336:
+ otp_res = PMURES_BIT(RES4336_OTP_PU);
+ break;
+ case BHND_CHIPID_BCM4330:
+ otp_res = PMURES_BIT(RES4330_OTP_PU);
+ break;
+
+ /* These chips don't use PMU bit to power up/down OTP. OTP always on.
+ * Use OTP_INIT command to reset/refresh state.
+ */
+ case BHND_CHIPID_BCM43224:
+ case BHND_CHIPID_BCM43225:
+ case BHND_CHIPID_BCM43421:
+ case BHND_CHIPID_BCM43236:
+ case BHND_CHIPID_BCM43235:
+ case BHND_CHIPID_BCM43238:
+ return (true);
+
+ default:
+ return (true);
+ }
+
+ /* Check resource state */
+ if ((BHND_PMU_READ_4(sc, BHND_PMU_RES_STATE) & otp_res) == 0)
+ return (false);
+
+ return (true);
+}
+
+void
+bhnd_pmu_paref_ldo_enable(struct bhnd_pmu_softc *sc, bool enable)
+{
+ uint32_t ldo;
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4328:
+ ldo = PMURES_BIT(RES4328_PA_REF_LDO);
+ break;
+ case BHND_CHIPID_BCM5354:
+ ldo = PMURES_BIT(RES5354_PA_REF_LDO);
+ break;
+ case BHND_CHIPID_BCM4312:
+ ldo = PMURES_BIT(RES4312_PA_REF_LDO);
+ break;
+ default:
+ return;
+ }
+
+ if (enable) {
+ BHND_PMU_OR_4(sc, BHND_PMU_MIN_RES_MASK, ldo);
+ } else {
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~ldo);
+ }
+}
+
+/* initialize PMU switch/regulators */
+void
+bhnd_pmu_swreg_init(struct bhnd_pmu_softc *sc)
+{
+ uint32_t chipst;
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4325:
+ if (sc->cid.chip_rev <= 2)
+ break;
+
+ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
+ if (BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_PMUTOP_2B)) {
+ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CLDO_PWM,
+ 0xf);
+ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CLDO_BURST,
+ 0xf);
+ }
+
+ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CBUCK_PWM, 0xb);
+ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CBUCK_BURST, 0xb);
+
+ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_LNLDO1, 0x1);
+ if (sc->board.board_flags & BHND_BFL_LNLDO2_2P5) {
+ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_LNLDO2_SEL,
+ 0x1);
+ }
+
+ break;
+ case BHND_CHIPID_BCM4336:
+ /* Reduce CLDO PWM output voltage to 1.2V */
+ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CLDO_PWM, 0xe);
+ /* Reduce CLDO BURST output voltage to 1.2V */
+ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CLDO_BURST, 0xe);
+ /* Reduce LNLDO1 output voltage to 1.2V */
+ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_LNLDO1, 0xe);
+ if (sc->cid.chip_rev == 0)
+ BHND_PMU_REGCTRL_WRITE(sc, 2, 0x400000, 0x400000);
+ break;
+
+ case BHND_CHIPID_BCM4330:
+ /* CBUCK Voltage is 1.8 by default and set that to 1.5 */
+ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CBUCK_PWM, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+bhnd_pmu_radio_enable(struct bhnd_pmu_softc *sc, device_t d11core, bool enable)
+{
+ uint32_t oobsel;
+ uint32_t rsrcs;
+
+ if (bhnd_get_device(d11core) != BHND_COREID_D11)
+ panic("bhnd_pmu_radio_enable() called on non-D11 core");
+
+ switch (sc->cid.chip_id) {
+ case BHND_CHIPID_BCM4325:
+ if (sc->board.board_flags & BHND_BFL_FASTPWR)
+ break;
+
+ if ((sc->board.board_flags & BHND_BFL_BUCKBOOST) == 0)
+ break;
+
+ rsrcs = PMURES_BIT(RES4325_BUCK_BOOST_BURST);
+
+ if (enable) {
+ BHND_PMU_OR_4(sc, BHND_PMU_MIN_RES_MASK, rsrcs);
+ DELAY(100 * 1000); /* 100ms */
+ } else {
+ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~rsrcs);
+ }
+
+ break;
+ case BHND_CHIPID_BCM4319:
+ oobsel = bhnd_read_config(d11core, BCMA_DMP_OOBSELOUTB74, 4);
+
+ if (enable) {
+ oobsel |= BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
+ BCMA_DMP_OOBSEL_1);
+ oobsel |= BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
+ BCMA_DMP_OOBSEL_2);
+ } else {
+ oobsel &= ~BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
+ BCMA_DMP_OOBSEL_1);
+ oobsel &= ~BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
+ BCMA_DMP_OOBSEL_2);
+ }
+
+ bhnd_write_config(d11core, BCMA_DMP_OOBSELOUTB74, oobsel, 4);
+ break;
+ }
+}
+
+/* Wait for a particular clock level to be on the backplane */
+uint32_t
+bhnd_pmu_waitforclk_on_backplane(struct bhnd_pmu_softc *sc, uint32_t clk,
+ uint32_t delay)
+{
+ uint32_t pmu_st;
+
+ for (uint32_t i = 0; i < delay; i += 10) {
+ pmu_st = BHND_PMU_READ_4(sc, BHND_PMU_ST);
+ if ((pmu_st & clk) == clk)
+ return (clk);
+
+ DELAY(10);
+ }
+
+ pmu_st = BHND_PMU_READ_4(sc, BHND_PMU_ST);
+ return (pmu_st & clk);
+}
+
+/*
+ * Measures the ALP clock frequency in KHz. Returns 0 if not possible.
+ * Possible only if PMU rev >= 10 and there is an external LPO 32768Hz crystal.
+ */
+
+#define EXT_ILP_HZ 32768
+
+uint32_t
+bhnd_pmu_measure_alpclk(struct bhnd_pmu_softc *sc)
+{
+ uint32_t alp_khz;
+ uint32_t pmu_st;
+
+ if (BHND_PMU_REV(sc) < 10)
+ return (0);
+
+ pmu_st = BHND_PMU_READ_4(sc, BHND_PMU_ST);
+ if (pmu_st & BHND_PMU_ST_EXTLPOAVAIL) {
+ uint32_t alp_hz, ilp_ctr;
+
+ /* Enable frequency measurement */
+ BHND_PMU_WRITE_4(sc, BHND_PMU_XTALFREQ, 1U <<
+ BHND_PMU_XTALFREQ_REG_MEASURE_SHIFT);
+
+ /* Delay for well over 4 ILP clocks */
+ DELAY(1000);
+
+ /* Read the latched number of ALP ticks per 4 ILP ticks */
+ ilp_ctr = BHND_PMU_READ_4(sc, BHND_PMU_XTALFREQ);
+ ilp_ctr = BHND_PMU_GET_BITS(ilp_ctr,
+ BHND_PMU_XTALFREQ_REG_ILPCTR);
+
+ /* Turn off PMU_XTALFREQ_REG_MEASURE to save power */
+ BHND_PMU_WRITE_4(sc, BHND_PMU_XTALFREQ, 0);
+
+ /* Calculate ALP frequency */
+ alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4;
+
+ /* Round to nearest 100KHz and convert to KHz */
+ alp_khz = (alp_hz + 50000) / 100000 * 100;
+ } else {
+ alp_khz = 0;
+ }
+
+ return (alp_khz);
+}
+
+static void
+bhnd_pmu_set_4330_plldivs(struct bhnd_pmu_softc *sc)
+{
+ uint32_t FVCO = bhnd_pmu1_pllfvco0(sc) / 1000;
+ uint32_t m1div, m2div, m3div, m4div, m5div, m6div;
+ uint32_t pllc1, pllc2;
+
+ m2div = m3div = m4div = m6div = FVCO / 80;
+ m5div = FVCO / 160;
+
+ if (PMU_CST4330_SDIOD_CHIPMODE(sc))
+ m1div = FVCO / 80;
+ else
+ m1div = FVCO / 90;
+
+ pllc1 = 0;
+ pllc1 |= BHND_PMU_SET_BITS(m1div, BHND_PMU1_PLL0_PC1_M1DIV);
+ pllc1 |= BHND_PMU_SET_BITS(m2div, BHND_PMU1_PLL0_PC1_M2DIV);
+ pllc1 |= BHND_PMU_SET_BITS(m3div, BHND_PMU1_PLL0_PC1_M3DIV);
+ pllc1 |= BHND_PMU_SET_BITS(m4div, BHND_PMU1_PLL0_PC1_M4DIV);
+
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, pllc1, ~0);
+
+ pllc2 = 0;
+ pllc2 |= BHND_PMU_SET_BITS(m5div, BHND_PMU1_PLL0_PC2_M5DIV);
+ pllc2 |= BHND_PMU_SET_BITS(m6div, BHND_PMU1_PLL0_PC2_M6DIV);
+
+ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, pllc2,
+ BHND_PMU1_PLL0_PC2_M5DIV_MASK | BHND_PMU1_PLL0_PC2_M6DIV_MASK);
+}
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmureg.h b/sys/dev/bhnd/cores/pmu/bhnd_pmureg.h
new file mode 100644
index 000000000000..44ededfb15d4
--- /dev/null
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmureg.h
@@ -0,0 +1,712 @@
+/*-
+ * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2010 Broadcom Corporation
+ * All rights reserved.
+ *
+ * This file is 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$
+ */
+
+#ifndef _BHND_CORES_PMU_BHND_PMUREG_H_
+#define _BHND_CORES_PMU_BHND_PMUREG_H_
+
+#define BHND_PMU_GET_FLAG(_value, _flag) \
+ (((_value) & _flag) != 0)
+#define BHND_PMU_GET_BITS(_value, _field) \
+ (((_value) & _field ## _MASK) >> _field ## _SHIFT)
+#define BHND_PMU_SET_BITS(_value, _field) \
+ (((_value) & _field ## _MASK) >> _field ## _SHIFT)
+
+#define BHND_PMU_ILP_CLOCK 32000 /**< default ILP freq */
+#define BHND_PMU_ALP_CLOCK 20000000 /**< default ALP freq */
+#define BHND_PMU_HT_CLOCK 80000000 /**< default HT freq */
+
+/**
+ * Common per-core clock control/status register available on PMU-equipped
+ * devices.
+ */
+#define BHND_CLK_CTL_ST 0x1e0 /**< clock control and status */
+
+/*
+ * BHND_CLK_CTL_ST register
+ *
+ * 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_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 */
+
+/* PMU registers */
+#define BHND_PMU_CTRL 0x600
+#define BHND_PMU_CTRL_ILP_DIV_MASK 0xffff0000
+#define BHND_PMU_CTRL_ILP_DIV_SHIFT 16
+#define BHND_PMU_CTRL_PLL_PLLCTL_UPD 0x00000400 /* rev 2 */
+#define BHND_PMU_CTRL_NOILP_ON_WAIT 0x00000200 /* rev 1 */
+#define BHND_PMU_CTRL_HT_REQ_EN 0x00000100
+#define BHND_PMU_CTRL_ALP_REQ_EN 0x00000080
+#define BHND_PMU_CTRL_XTALFREQ_MASK 0x0000007c
+#define BHND_PMU_CTRL_XTALFREQ_SHIFT 2
+#define BHND_PMU_CTRL_ILP_DIV_EN 0x00000002
+#define BHND_PMU_CTRL_LPO_SEL 0x00000001
+#define BHND_PMU_CAP 0x604
+#define BHND_PMU_CAP_REV_MASK 0x000000ff
+#define BHND_PMU_CAP_REV_SHIFT 0
+#define BHND_PMU_CAP_RC_MASK 0x00001f00
+#define BHND_PMU_CAP_RC_SHIFT 8
+#define BHND_PMU_CAP_RC_MAX \
+ (BHND_PMU_CAP_RC_MASK >> BHND_PMU_CAP_RC_SHIFT)
+#define BHND_PMU_CAP_TC_MASK 0x0001e000
+#define BHND_PMU_CAP_TC_SHIFT 13
+#define BHND_PMU_CAP_PC_MASK 0x001e0000
+#define BHND_PMU_CAP_PC_SHIFT 17
+#define BHND_PMU_CAP_VC_MASK 0x01e00000
+#define BHND_PMU_CAP_VC_SHIFT 21
+#define BHND_PMU_CAP_CC_MASK 0x1e000000
+#define BHND_PMU_CAP_CC_SHIFT 25
+#define BHND_PMU_CAP5_PC_MASK 0x003e0000 /* PMU corerev >= 5 */
+#define BHND_PMU_CAP5_PC_SHIFT 17
+#define BHND_PMU_CAP5_VC_MASK 0x07c00000
+#define BHND_PMU_CAP5_VC_SHIFT 22
+#define BHND_PMU_CAP5_CC_MASK 0xf8000000
+#define BHND_PMU_CAP5_CC_SHIFT 27
+#define BHND_PMU_ST 0x608
+#define BHND_PMU_ST_EXTLPOAVAIL 0x0100
+#define BHND_PMU_ST_WDRESET 0x0080
+#define BHND_PMU_ST_INTPEND 0x0040
+#define BHND_PMU_ST_SBCLKST 0x0030
+#define BHND_PMU_ST_SBCLKST_ILP 0x0010
+#define BHND_PMU_ST_SBCLKST_ALP 0x0020
+#define BHND_PMU_ST_SBCLKST_HT 0x0030
+#define BHND_PMU_ST_ALPAVAIL 0x0008
+#define BHND_PMU_ST_HTAVAIL 0x0004
+#define BHND_PMU_ST_RESINIT 0x0003
+#define BHND_PMU_RES_STATE 0x60c
+#define BHND_PMU_RES_PENDING 0x610
+#define BHND_PMU_TIMER 0x614
+#define BHND_PMU_MIN_RES_MASK 0x618
+#define BHND_PMU_MAX_RES_MASK 0x61c
+#define BHND_PMU_RES_TABLE_SEL 0x620
+#define BHND_PMU_RES_DEP_MASK 0x624
+#define BHND_PMU_RES_UPDN_TIMER 0x628
+#define BHND_PMU_RES_UPDN_UPTME_MASK 0xFF
+#define BHND_PMU_RES_UPDN_UPTME_SHIFT 8
+#define BHND_PMU_RES_TIMER 0x62C
+#define BHND_PMU_CLKSTRETCH 0x630
+#define BHND_PMU_CSTRETCH_HT 0xffff0000
+#define BHND_PMU_CSTRETCH_ALP 0x0000ffff
+#define BHND_PMU_WATCHDOG 0x634
+#define BHND_PMU_GPIOSEL 0x638 /* pmu rev >= 1 ? */
+#define BHND_PMU_GPIOEN 0x63C /* pmu rev >= 1 ? */
+#define BHND_PMU_RES_REQ_TIMER_SEL 0x640
+#define BHND_PMU_RES_REQ_TIMER 0x644
+#define BHND_PMU_RRQT_TIME_MASK 0x03ff
+#define BHND_PMU_RRQT_INTEN 0x0400
+#define BHND_PMU_RRQT_REQ_ACTIVE 0x0800
+#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_REG_CONTROL_ADDR 0x658
+#define BHND_PMU_REG_CONTROL_DATA 0x65C
+#define BHND_PMU_PLL_CONTROL_ADDR 0x660
+#define BHND_PMU_PLL_CONTROL_DATA 0x664
+#define BHND_PMU_STRAPOPT 0x668 /* chipc rev >= 28 */
+#define BHND_PMU_XTALFREQ 0x66C /* pmu rev >= 10 */
+
+/* PMU resource bit position */
+#define BHND_PMURES_BIT(bit) (1 << (bit))
+
+/* PMU resource number limit */
+#define BHND_PMU_RESNUM_MAX 30
+
+/* PMU chip control0 register */
+#define BHND_PMU_CHIPCTL0 0
+
+/* PMU chip control1 register */
+#define BHND_PMU_CHIPCTL1 1
+#define BHND_PMU_CC1_RXC_DLL_BYPASS 0x00010000
+
+#define BHND_PMU_CC1_IF_TYPE_MASK 0x00000030
+#define BHND_PMU_CC1_IF_TYPE_RMII 0x00000000
+#define BHND_PMU_CC1_IF_TYPE_MII 0x00000010
+#define BHND_PMU_CC1_IF_TYPE_RGMII 0x00000020
+
+#define BHND_PMU_CC1_SW_TYPE_MASK 0x000000c0
+#define BHND_PMU_CC1_SW_TYPE_EPHY 0x00000000
+#define BHND_PMU_CC1_SW_TYPE_EPHYMII 0x00000040
+#define BHND_PMU_CC1_SW_TYPE_EPHYRMII 0x00000080
+#define BHND_PMU_CC1_SW_TYPE_RGMII 0x000000c0
+
+/* PMU corerev and chip specific PLL controls.
+ * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary number
+ * to differentiate different PLLs controlled by the same PMU rev.
+ */
+
+/* pllcontrol registers */
+/* PDIV, div_phy, div_arm, div_adc, dith_sel, ioff, kpd_scale, lsb_sel, mash_sel, lf_c & lf_r */
+#define BHND_PMU0_PLL0_PLLCTL0 0
+#define BHND_PMU0_PLL0_PC0_PDIV_MASK 1
+#define BHND_PMU0_PLL0_PC0_PDIV_FREQ 25000
+#define BHND_PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038
+#define BHND_PMU0_PLL0_PC0_DIV_ARM_SHIFT 3
+#define BHND_PMU0_PLL0_PC0_DIV_ARM_BASE 8
+
+/* PC0_DIV_ARM for PLLOUT_ARM */
+#define BHND_PMU0_PLL0_PC0_DIV_ARM_110MHZ 0
+#define BHND_PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1
+#define BHND_PMU0_PLL0_PC0_DIV_ARM_88MHZ 2
+#define BHND_PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 /* Default */
+#define BHND_PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4
+#define BHND_PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5
+#define BHND_PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6
+#define BHND_PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7
+
+/* Wildcard base, stop_mod, en_lf_tp, en_cal & lf_r2 */
+#define BHND_PMU0_PLL0_PLLCTL1 1
+#define BHND_PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000
+#define BHND_PMU0_PLL0_PC1_WILD_INT_SHIFT 28
+#define BHND_PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00
+#define BHND_PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8
+#define BHND_PMU0_PLL0_PC1_STOP_MOD 0x00000040
+
+/* Wildcard base, vco_calvar, vco_swc, vco_var_selref, vso_ical & vco_sel_avdd */
+#define BHND_PMU0_PLL0_PLLCTL2 2
+#define BHND_PMU0_PLL0_PC2_WILD_INT_MASK 0xf
+#define BHND_PMU0_PLL0_PC2_WILD_INT_SHIFT 4
+
+/* pllcontrol registers */
+/* ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>, p1div, p2div, _bypass_sdmod */
+#define BHND_PMU1_PLL0_PLLCTL0 0
+#define BHND_PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000
+#define BHND_PMU1_PLL0_PC0_P1DIV_SHIFT 20
+#define BHND_PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000
+#define BHND_PMU1_PLL0_PC0_P2DIV_SHIFT 24
+#define BHND_PMU1_PLL0_PC0_BYPASS_SDMOD_MASK 0x10000000
+#define BHND_PMU1_PLL0_PC0_BYPASS_SDMOD_SHIFT 28
+
+/* m<x>div */
+#define BHND_PMU1_PLL0_PLLCTL1 1
+#define BHND_PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff
+#define BHND_PMU1_PLL0_PC1_M1DIV_SHIFT 0
+#define BHND_PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00
+#define BHND_PMU1_PLL0_PC1_M2DIV_SHIFT 8
+#define BHND_PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000
+#define BHND_PMU1_PLL0_PC1_M3DIV_SHIFT 16
+#define BHND_PMU1_PLL0_PC1_M4DIV_MASK 0xff000000
+#define BHND_PMU1_PLL0_PC1_M4DIV_SHIFT 24
+
+#define BHND_PMU_DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8
+#define BHND_PMU_DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << BHND_PMU_DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT)
+#define BHND_PMU_DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << BHND_PMU_DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT)
+
+/* m<x>div, ndiv_dither_mfb, ndiv_mode, ndiv_int */
+#define BHND_PMU1_PLL0_PLLCTL2 2
+#define BHND_PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff
+#define BHND_PMU1_PLL0_PC2_M5DIV_SHIFT 0
+#define BHND_PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00
+#define BHND_PMU1_PLL0_PC2_M6DIV_SHIFT 8
+#define BHND_PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000
+#define BHND_PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17
+#define BHND_PMU1_PLL0_PC2_NDIV_MODE_INT 0
+#define BHND_PMU1_PLL0_PC2_NDIV_MODE_MASH 1
+#define BHND_PMU1_PLL0_PC2_NDIV_MODE_MFB 2 /* recommended for 4319 */
+#define BHND_PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000
+#define BHND_PMU1_PLL0_PC2_NDIV_INT_SHIFT 20
+
+/* ndiv_frac */
+#define BHND_PMU1_PLL0_PLLCTL3 3
+#define BHND_PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff
+#define BHND_PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0
+
+/* pll_ctrl */
+#define BHND_PMU1_PLL0_PLLCTL4 4
+#define BHND_PMU1_PLL0_PC4_KVCO_XS_MASK 0x38000000
+#define BHND_PMU1_PLL0_PC4_KVCO_XS_SHIFT 27
+
+/* pll_ctrl, vco_rng, clkdrive_ch<x> */
+#define BHND_PMU1_PLL0_PLLCTL5 5
+#define BHND_PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00
+#define BHND_PMU1_PLL0_PC5_CLK_DRV_SHIFT 8
+#define BHND_PMU1_PLL0_PC5_PLL_CTRL_37_32_MASK 0x0000003f
+#define BHND_PMU1_PLL0_PC5_PLL_CTRL_37_32_SHIFT 0
+#define BHND_PMU1_PLL0_PC5_VCO_RNG_MASK 0x000000C0
+#define BHND_PMU1_PLL0_PC5_VCO_RNG_SHIFT 6
+
+/* PMU rev 2 control words */
+#define BHND_PMU2_PHY_PLL_PLLCTL 4
+#define BHND_PMU2_SI_PLL_PLLCTL 10
+
+/* PMU rev 2 */
+/* pllcontrol registers */
+/* ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>, p1div, p2div, _bypass_sdmod */
+#define BHND_PMU2_PLL_PLLCTL0 0
+#define BHND_PMU2_PLL_PC0_P1DIV_MASK 0x00f00000
+#define BHND_PMU2_PLL_PC0_P1DIV_SHIFT 20
+#define BHND_PMU2_PLL_PC0_P2DIV_MASK 0x0f000000
+#define BHND_PMU2_PLL_PC0_P2DIV_SHIFT 24
+
+/* m<x>div */
+#define BHND_PMU2_PLL_PLLCTL1 1
+#define BHND_PMU2_PLL_PC1_M1DIV_MASK 0x000000ff
+#define BHND_PMU2_PLL_PC1_M1DIV_SHIFT 0
+#define BHND_PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00
+#define BHND_PMU2_PLL_PC1_M2DIV_SHIFT 8
+#define BHND_PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000
+#define BHND_PMU2_PLL_PC1_M3DIV_SHIFT 16
+#define BHND_PMU2_PLL_PC1_M4DIV_MASK 0xff000000
+#define BHND_PMU2_PLL_PC1_M4DIV_SHIFT 24
+
+/* m<x>div, ndiv_dither_mfb, ndiv_mode, ndiv_int */
+#define BHND_PMU2_PLL_PLLCTL2 2
+#define BHND_PMU2_PLL_PC2_M5DIV_MASK 0x000000ff
+#define BHND_PMU2_PLL_PC2_M5DIV_SHIFT 0
+#define BHND_PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00
+#define BHND_PMU2_PLL_PC2_M6DIV_SHIFT 8
+#define BHND_PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000
+#define BHND_PMU2_PLL_PC2_NDIV_MODE_SHIFT 17
+#define BHND_PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000
+#define BHND_PMU2_PLL_PC2_NDIV_INT_SHIFT 20
+
+/* ndiv_frac */
+#define BHND_PMU2_PLL_PLLCTL3 3
+#define BHND_PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff
+#define BHND_PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0
+
+/* pll_ctrl */
+#define BHND_PMU2_PLL_PLLCTL4 4
+
+/* pll_ctrl, vco_rng, clkdrive_ch<x> */
+#define BHND_PMU2_PLL_PLLCTL5 5
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000
+#define BHND_PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28
+
+/* PMU rev 5 (& 6) */
+#define BHND_PMU5_PLL_P1P2_OFF 0
+#define BHND_PMU5_PLL_P1_MASK 0x0f000000
+#define BHND_PMU5_PLL_P1_SHIFT 24
+#define BHND_PMU5_PLL_P2_MASK 0x00f00000
+#define BHND_PMU5_PLL_P2_SHIFT 20
+#define BHND_PMU5_PLL_M14_OFF 1
+#define BHND_PMU5_PLL_MDIV_MASK 0x000000ff
+#define BHND_PMU5_PLL_MDIV_WIDTH 8
+#define BHND_PMU5_PLL_NM5_OFF 2
+#define BHND_PMU5_PLL_NDIV_MASK 0xfff00000
+#define BHND_PMU5_PLL_NDIV_SHIFT 20
+#define BHND_PMU5_PLL_NDIV_MODE_MASK 0x000e0000
+#define BHND_PMU5_PLL_NDIV_MODE_SHIFT 17
+#define BHND_PMU5_PLL_FMAB_OFF 3
+#define BHND_PMU5_PLL_MRAT_MASK 0xf0000000
+#define BHND_PMU5_PLL_MRAT_SHIFT 28
+#define BHND_PMU5_PLL_ABRAT_MASK 0x08000000
+#define BHND_PMU5_PLL_ABRAT_SHIFT 27
+#define BHND_PMU5_PLL_FDIV_MASK 0x07ffffff
+#define BHND_PMU5_PLL_PLLCTL_OFF 4
+#define BHND_PMU5_PLL_PCHI_OFF 5
+#define BHND_PMU5_PLL_PCHI_MASK 0x0000003f
+
+/* pmu XtalFreqRatio */
+#define BHND_PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF
+#define BHND_PMU_XTALFREQ_REG_ILPCTR_SHIFT 0
+#define BHND_PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000
+#define BHND_PMU_XTALFREQ_REG_MEASURE_SHIFT 31
+
+
+/* Divider allocation in 4716/47162/5356/5357 */
+#define BHND_PMU5_MAINPLL_CPU 1
+#define BHND_PMU5_MAINPLL_MEM 2
+#define BHND_PMU5_MAINPLL_SI 3
+
+#define BHND_PMU7_PLL_PLLCTL7 7
+#define BHND_PMU7_PLL_PLLCTL8 8
+#define BHND_PMU7_PLL_PLLCTL11 11
+
+
+/* PLL usage in 4716/47162 */
+#define BHND_PMU4716_MAINPLL_PLL0 12
+
+
+/* PLL usage in 5356/5357 */
+#define BHND_PMU5356_MAINPLL_PLL0 0
+#define BHND_PMU5357_MAINPLL_PLL0 0
+
+
+/* 4716/47162 PMU resources */
+#define BHND_PMU_RES4716_PROC_PLL_ON 0x00000040
+#define BHND_PMU_RES4716_PROC_HT_AVAIL 0x00000080
+
+/* 4716/4717/4718 chip-specific CHIPCTRL PMU register bits */
+#define BHND_PMU_CCTRL471X_I2S_PINS_ENABLE 0x0080 /* I2S pins off by default, shared with pflash */
+
+
+/* 5354 PMU resources */
+#define BHND_PMU_RES5354_EXT_SWITCHER_PWM 0 /* 0x00001 */
+#define BHND_PMU_RES5354_BB_SWITCHER_PWM 1 /* 0x00002 */
+#define BHND_PMU_RES5354_BB_SWITCHER_BURST 2 /* 0x00004 */
+#define BHND_PMU_RES5354_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */
+#define BHND_PMU_RES5354_ILP_REQUEST 4 /* 0x00010 */
+#define BHND_PMU_RES5354_RADIO_SWITCHER_PWM 5 /* 0x00020 */
+#define BHND_PMU_RES5354_RADIO_SWITCHER_BURST 6 /* 0x00040 */
+#define BHND_PMU_RES5354_ROM_SWITCH 7 /* 0x00080 */
+#define BHND_PMU_RES5354_PA_REF_LDO 8 /* 0x00100 */
+#define BHND_PMU_RES5354_RADIO_LDO 9 /* 0x00200 */
+#define BHND_PMU_RES5354_AFE_LDO 10 /* 0x00400 */
+#define BHND_PMU_RES5354_PLL_LDO 11 /* 0x00800 */
+#define BHND_PMU_RES5354_BG_FILTBYP 12 /* 0x01000 */
+#define BHND_PMU_RES5354_TX_FILTBYP 13 /* 0x02000 */
+#define BHND_PMU_RES5354_RX_FILTBYP 14 /* 0x04000 */
+#define BHND_PMU_RES5354_XTAL_PU 15 /* 0x08000 */
+#define BHND_PMU_RES5354_XTAL_EN 16 /* 0x10000 */
+#define BHND_PMU_RES5354_BB_PLL_FILTBYP 17 /* 0x20000 */
+#define BHND_PMU_RES5354_RF_PLL_FILTBYP 18 /* 0x40000 */
+#define BHND_PMU_RES5354_BB_PLL_PU 19 /* 0x80000 */
+
+
+/* 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 */
+
+
+/* 4328 PMU resources */
+#define BHND_PMU_RES4328_EXT_SWITCHER_PWM 0 /* 0x00001 */
+#define BHND_PMU_RES4328_BB_SWITCHER_PWM 1 /* 0x00002 */
+#define BHND_PMU_RES4328_BB_SWITCHER_BURST 2 /* 0x00004 */
+#define BHND_PMU_RES4328_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */
+#define BHND_PMU_RES4328_ILP_REQUEST 4 /* 0x00010 */
+#define BHND_PMU_RES4328_RADIO_SWITCHER_PWM 5 /* 0x00020 */
+#define BHND_PMU_RES4328_RADIO_SWITCHER_BURST 6 /* 0x00040 */
+#define BHND_PMU_RES4328_ROM_SWITCH 7 /* 0x00080 */
+#define BHND_PMU_RES4328_PA_REF_LDO 8 /* 0x00100 */
+#define BHND_PMU_RES4328_RADIO_LDO 9 /* 0x00200 */
+#define BHND_PMU_RES4328_AFE_LDO 10 /* 0x00400 */
+#define BHND_PMU_RES4328_PLL_LDO 11 /* 0x00800 */
+#define BHND_PMU_RES4328_BG_FILTBYP 12 /* 0x01000 */
+#define BHND_PMU_RES4328_TX_FILTBYP 13 /* 0x02000 */
+#define BHND_PMU_RES4328_RX_FILTBYP 14 /* 0x04000 */
+#define BHND_PMU_RES4328_XTAL_PU 15 /* 0x08000 */
+#define BHND_PMU_RES4328_XTAL_EN 16 /* 0x10000 */
+#define BHND_PMU_RES4328_BB_PLL_FILTBYP 17 /* 0x20000 */
+#define BHND_PMU_RES4328_RF_PLL_FILTBYP 18 /* 0x40000 */
+#define BHND_PMU_RES4328_BB_PLL_PU 19 /* 0x80000 */
+
+
+/* 4325 A0/A1 PMU resources */
+#define BHND_PMU_RES4325_BUCK_BOOST_BURST 0 /* 0x00000001 */
+#define BHND_PMU_RES4325_CBUCK_BURST 1 /* 0x00000002 */
+#define BHND_PMU_RES4325_CBUCK_PWM 2 /* 0x00000004 */
+#define BHND_PMU_RES4325_CLDO_CBUCK_BURST 3 /* 0x00000008 */
+#define BHND_PMU_RES4325_CLDO_CBUCK_PWM 4 /* 0x00000010 */
+#define BHND_PMU_RES4325_BUCK_BOOST_PWM 5 /* 0x00000020 */
+#define BHND_PMU_RES4325_ILP_REQUEST 6 /* 0x00000040 */
+#define BHND_PMU_RES4325_ABUCK_BURST 7 /* 0x00000080 */
+#define BHND_PMU_RES4325_ABUCK_PWM 8 /* 0x00000100 */
+#define BHND_PMU_RES4325_LNLDO1_PU 9 /* 0x00000200 */
+#define BHND_PMU_RES4325_OTP_PU 10 /* 0x00000400 */
+#define BHND_PMU_RES4325_LNLDO3_PU 11 /* 0x00000800 */
+#define BHND_PMU_RES4325_LNLDO4_PU 12 /* 0x00001000 */
+#define BHND_PMU_RES4325_XTAL_PU 13 /* 0x00002000 */
+#define BHND_PMU_RES4325_ALP_AVAIL 14 /* 0x00004000 */
+#define BHND_PMU_RES4325_RX_PWRSW_PU 15 /* 0x00008000 */
+#define BHND_PMU_RES4325_TX_PWRSW_PU 16 /* 0x00010000 */
+#define BHND_PMU_RES4325_RFPLL_PWRSW_PU 17 /* 0x00020000 */
+#define BHND_PMU_RES4325_LOGEN_PWRSW_PU 18 /* 0x00040000 */
+#define BHND_PMU_RES4325_AFE_PWRSW_PU 19 /* 0x00080000 */
+#define BHND_PMU_RES4325_BBPLL_PWRSW_PU 20 /* 0x00100000 */
+#define BHND_PMU_RES4325_HT_AVAIL 21 /* 0x00200000 */
+
+
+/* 4325 B0/C0 PMU resources */
+#define BHND_PMU_RES4325B0_CBUCK_LPOM 1 /* 0x00000002 */
+#define BHND_PMU_RES4325B0_CBUCK_BURST 2 /* 0x00000004 */
+#define BHND_PMU_RES4325B0_CBUCK_PWM 3 /* 0x00000008 */
+#define BHND_PMU_RES4325B0_CLDO_PU 4 /* 0x00000010 */
+
+
+/* 4325 C1 PMU resources */
+#define BHND_PMU_RES4325C1_LNLDO2_PU 12 /* 0x00001000 */
+
+
+/* 4325 PMU resources */
+#define BHND_PMU_RES4329_RESERVED0 0 /* 0x00000001 */
+#define BHND_PMU_RES4329_CBUCK_LPOM 1 /* 0x00000002 */
+#define BHND_PMU_RES4329_CBUCK_BURST 2 /* 0x00000004 */
+#define BHND_PMU_RES4329_CBUCK_PWM 3 /* 0x00000008 */
+#define BHND_PMU_RES4329_CLDO_PU 4 /* 0x00000010 */
+#define BHND_PMU_RES4329_PALDO_PU 5 /* 0x00000020 */
+#define BHND_PMU_RES4329_ILP_REQUEST 6 /* 0x00000040 */
+#define BHND_PMU_RES4329_RESERVED7 7 /* 0x00000080 */
+#define BHND_PMU_RES4329_RESERVED8 8 /* 0x00000100 */
+#define BHND_PMU_RES4329_LNLDO1_PU 9 /* 0x00000200 */
+#define BHND_PMU_RES4329_OTP_PU 10 /* 0x00000400 */
+#define BHND_PMU_RES4329_RESERVED11 11 /* 0x00000800 */
+#define BHND_PMU_RES4329_LNLDO2_PU 12 /* 0x00001000 */
+#define BHND_PMU_RES4329_XTAL_PU 13 /* 0x00002000 */
+#define BHND_PMU_RES4329_ALP_AVAIL 14 /* 0x00004000 */
+#define BHND_PMU_RES4329_RX_PWRSW_PU 15 /* 0x00008000 */
+#define BHND_PMU_RES4329_TX_PWRSW_PU 16 /* 0x00010000 */
+#define BHND_PMU_RES4329_RFPLL_PWRSW_PU 17 /* 0x00020000 */
+#define BHND_PMU_RES4329_LOGEN_PWRSW_PU 18 /* 0x00040000 */
+#define BHND_PMU_RES4329_AFE_PWRSW_PU 19 /* 0x00080000 */
+#define BHND_PMU_RES4329_BBPLL_PWRSW_PU 20 /* 0x00100000 */
+#define BHND_PMU_RES4329_HT_AVAIL 21 /* 0x00200000 */
+
+
+/* 4312 PMU resources (all PMU chips with little memory constraint) */
+#define BHND_PMU_RES4312_SWITCHER_BURST 0 /* 0x00000001 */
+#define BHND_PMU_RES4312_SWITCHER_PWM 1 /* 0x00000002 */
+#define BHND_PMU_RES4312_PA_REF_LDO 2 /* 0x00000004 */
+#define BHND_PMU_RES4312_CORE_LDO_BURST 3 /* 0x00000008 */
+#define BHND_PMU_RES4312_CORE_LDO_PWM 4 /* 0x00000010 */
+#define BHND_PMU_RES4312_RADIO_LDO 5 /* 0x00000020 */
+#define BHND_PMU_RES4312_ILP_REQUEST 6 /* 0x00000040 */
+#define BHND_PMU_RES4312_BG_FILTBYP 7 /* 0x00000080 */
+#define BHND_PMU_RES4312_TX_FILTBYP 8 /* 0x00000100 */
+#define BHND_PMU_RES4312_RX_FILTBYP 9 /* 0x00000200 */
+#define BHND_PMU_RES4312_XTAL_PU 10 /* 0x00000400 */
+#define BHND_PMU_RES4312_ALP_AVAIL 11 /* 0x00000800 */
+#define BHND_PMU_RES4312_BB_PLL_FILTBYP 12 /* 0x00001000 */
+#define BHND_PMU_RES4312_RF_PLL_FILTBYP 13 /* 0x00002000 */
+#define BHND_PMU_RES4312_HT_AVAIL 14 /* 0x00004000 */
+
+
+/* 4322 PMU resources */
+#define BHND_PMU_RES4322_RF_LDO 0
+#define BHND_PMU_RES4322_ILP_REQUEST 1
+#define BHND_PMU_RES4322_XTAL_PU 2
+#define BHND_PMU_RES4322_ALP_AVAIL 3
+#define BHND_PMU_RES4322_SI_PLL_ON 4
+#define BHND_PMU_RES4322_HT_SI_AVAIL 5
+#define BHND_PMU_RES4322_PHY_PLL_ON 6
+#define BHND_PMU_RES4322_HT_PHY_AVAIL 7
+#define BHND_PMU_RES4322_OTP_PU 8
+
+
+/* 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 */
+
+
+/* 43236 PMU resources */
+#define BHND_PMU_RES43236_REGULATOR 0
+#define BHND_PMU_RES43236_ILP_REQUEST 1
+#define BHND_PMU_RES43236_XTAL_PU 2
+#define BHND_PMU_RES43236_ALP_AVAIL 3
+#define BHND_PMU_RES43236_SI_PLL_ON 4
+#define BHND_PMU_RES43236_HT_SI_AVAIL 5
+
+/* 43236 chip-specific CHIPCTRL register bits */
+#define BHND_PMU_CCTRL43236_BT_COEXIST (1<<0) /* 0 disable */
+#define BHND_PMU_CCTRL43236_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */
+#define BHND_PMU_CCTRL43236_EXT_LNA (1<<2) /* 0 disable */
+#define BHND_PMU_CCTRL43236_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */
+#define BHND_PMU_CCTRL43236_GSIO (1<<4) /* 0 disable */
+
+
+/* 4331 PMU resources */
+#define BHND_PMU_RES4331_REGULATOR 0
+#define BHND_PMU_RES4331_ILP_REQUEST 1
+#define BHND_PMU_RES4331_XTAL_PU 2
+#define BHND_PMU_RES4331_ALP_AVAIL 3
+#define BHND_PMU_RES4331_SI_PLL_ON 4
+#define BHND_PMU_RES4331_HT_SI_AVAIL 5
+
+/* 4315 PMU resources */
+#define BHND_PMU_RES4315_CBUCK_LPOM 1 /* 0x00000002 */
+#define BHND_PMU_RES4315_CBUCK_BURST 2 /* 0x00000004 */
+#define BHND_PMU_RES4315_CBUCK_PWM 3 /* 0x00000008 */
+#define BHND_PMU_RES4315_CLDO_PU 4 /* 0x00000010 */
+#define BHND_PMU_RES4315_PALDO_PU 5 /* 0x00000020 */
+#define BHND_PMU_RES4315_ILP_REQUEST 6 /* 0x00000040 */
+#define BHND_PMU_RES4315_LNLDO1_PU 9 /* 0x00000200 */
+#define BHND_PMU_RES4315_OTP_PU 10 /* 0x00000400 */
+#define BHND_PMU_RES4315_LNLDO2_PU 12 /* 0x00001000 */
+#define BHND_PMU_RES4315_XTAL_PU 13 /* 0x00002000 */
+#define BHND_PMU_RES4315_ALP_AVAIL 14 /* 0x00004000 */
+#define BHND_PMU_RES4315_RX_PWRSW_PU 15 /* 0x00008000 */
+#define BHND_PMU_RES4315_TX_PWRSW_PU 16 /* 0x00010000 */
+#define BHND_PMU_RES4315_RFPLL_PWRSW_PU 17 /* 0x00020000 */
+#define BHND_PMU_RES4315_LOGEN_PWRSW_PU 18 /* 0x00040000 */
+#define BHND_PMU_RES4315_AFE_PWRSW_PU 19 /* 0x00080000 */
+#define BHND_PMU_RES4315_BBPLL_PWRSW_PU 20 /* 0x00100000 */
+#define BHND_PMU_RES4315_HT_AVAIL 21 /* 0x00200000 */
+
+/* 4319 PMU resources */
+#define BHND_PMU_RES4319_CBUCK_LPOM 1 /* 0x00000002 */
+#define BHND_PMU_RES4319_CBUCK_BURST 2 /* 0x00000004 */
+#define BHND_PMU_RES4319_CBUCK_PWM 3 /* 0x00000008 */
+#define BHND_PMU_RES4319_CLDO_PU 4 /* 0x00000010 */
+#define BHND_PMU_RES4319_PALDO_PU 5 /* 0x00000020 */
+#define BHND_PMU_RES4319_ILP_REQUEST 6 /* 0x00000040 */
+#define BHND_PMU_RES4319_LNLDO1_PU 9 /* 0x00000200 */
+#define BHND_PMU_RES4319_OTP_PU 10 /* 0x00000400 */
+#define BHND_PMU_RES4319_LNLDO2_PU 12 /* 0x00001000 */
+#define BHND_PMU_RES4319_XTAL_PU 13 /* 0x00002000 */
+#define BHND_PMU_RES4319_ALP_AVAIL 14 /* 0x00004000 */
+#define BHND_PMU_RES4319_RX_PWRSW_PU 15 /* 0x00008000 */
+#define BHND_PMU_RES4319_TX_PWRSW_PU 16 /* 0x00010000 */
+#define BHND_PMU_RES4319_RFPLL_PWRSW_PU 17 /* 0x00020000 */
+#define BHND_PMU_RES4319_LOGEN_PWRSW_PU 18 /* 0x00040000 */
+#define BHND_PMU_RES4319_AFE_PWRSW_PU 19 /* 0x00080000 */
+#define BHND_PMU_RES4319_BBPLL_PWRSW_PU 20 /* 0x00100000 */
+#define BHND_PMU_RES4319_HT_AVAIL 21 /* 0x00200000 */
+
+/* 4319 chip-specific CHIPCTL register bits */
+#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
+
+/* 4336 PMU resources */
+#define BHND_PMU_RES4336_CBUCK_LPOM 0
+#define BHND_PMU_RES4336_CBUCK_BURST 1
+#define BHND_PMU_RES4336_CBUCK_LP_PWM 2
+#define BHND_PMU_RES4336_CBUCK_PWM 3
+#define BHND_PMU_RES4336_CLDO_PU 4
+#define BHND_PMU_RES4336_DIS_INT_RESET_PD 5
+#define BHND_PMU_RES4336_ILP_REQUEST 6
+#define BHND_PMU_RES4336_LNLDO_PU 7
+#define BHND_PMU_RES4336_LDO3P3_PU 8
+#define BHND_PMU_RES4336_OTP_PU 9
+#define BHND_PMU_RES4336_XTAL_PU 10
+#define BHND_PMU_RES4336_ALP_AVAIL 11
+#define BHND_PMU_RES4336_RADIO_PU 12
+#define BHND_PMU_RES4336_BG_PU 13
+#define BHND_PMU_RES4336_VREG1p4_PU_PU 14
+#define BHND_PMU_RES4336_AFE_PWRSW_PU 15
+#define BHND_PMU_RES4336_RX_PWRSW_PU 16
+#define BHND_PMU_RES4336_TX_PWRSW_PU 17
+#define BHND_PMU_RES4336_BB_PWRSW_PU 18
+#define BHND_PMU_RES4336_SYNTH_PWRSW_PU 19
+#define BHND_PMU_RES4336_MISC_PWRSW_PU 20
+#define BHND_PMU_RES4336_LOGEN_PWRSW_PU 21
+#define BHND_PMU_RES4336_BBPLL_PWRSW_PU 22
+#define BHND_PMU_RES4336_MACPHY_CLKAVAIL 23
+#define BHND_PMU_RES4336_HT_AVAIL 24
+#define BHND_PMU_RES4336_RSVD 25
+
+/* 4330 resources */
+#define BHND_PMU_RES4330_CBUCK_LPOM 0
+#define BHND_PMU_RES4330_CBUCK_BURST 1
+#define BHND_PMU_RES4330_CBUCK_LP_PWM 2
+#define BHND_PMU_RES4330_CBUCK_PWM 3
+#define BHND_PMU_RES4330_CLDO_PU 4
+#define BHND_PMU_RES4330_DIS_INT_RESET_PD 5
+#define BHND_PMU_RES4330_ILP_REQUEST 6
+#define BHND_PMU_RES4330_LNLDO_PU 7
+#define BHND_PMU_RES4330_LDO3P3_PU 8
+#define BHND_PMU_RES4330_OTP_PU 9
+#define BHND_PMU_RES4330_XTAL_PU 10
+#define BHND_PMU_RES4330_ALP_AVAIL 11
+#define BHND_PMU_RES4330_RADIO_PU 12
+#define BHND_PMU_RES4330_BG_PU 13
+#define BHND_PMU_RES4330_VREG1p4_PU_PU 14
+#define BHND_PMU_RES4330_AFE_PWRSW_PU 15
+#define BHND_PMU_RES4330_RX_PWRSW_PU 16
+#define BHND_PMU_RES4330_TX_PWRSW_PU 17
+#define BHND_PMU_RES4330_BB_PWRSW_PU 18
+#define BHND_PMU_RES4330_SYNTH_PWRSW_PU 19
+#define BHND_PMU_RES4330_MISC_PWRSW_PU 20
+#define BHND_PMU_RES4330_LOGEN_PWRSW_PU 21
+#define BHND_PMU_RES4330_BBPLL_PWRSW_PU 22
+#define BHND_PMU_RES4330_MACPHY_CLKAVAIL 23
+#define BHND_PMU_RES4330_HT_AVAIL 24
+#define BHND_PMU_RES4330_5gRX_PWRSW_PU 25
+#define BHND_PMU_RES4330_5gTX_PWRSW_PU 26
+#define BHND_PMU_RES4330_5g_LOGEN_PWRSW_PU 27
+
+/* 4313 resources */
+#define BHND_PMU_RES4313_BB_PU_RSRC 0
+#define BHND_PMU_RES4313_ILP_REQ_RSRC 1
+#define BHND_PMU_RES4313_XTAL_PU_RSRC 2
+#define BHND_PMU_RES4313_ALP_AVAIL_RSRC 3
+#define BHND_PMU_RES4313_RADIO_PU_RSRC 4
+#define BHND_PMU_RES4313_BG_PU_RSRC 5
+#define BHND_PMU_RES4313_VREG1P4_PU_RSRC 6
+#define BHND_PMU_RES4313_AFE_PWRSW_RSRC 7
+#define BHND_PMU_RES4313_RX_PWRSW_RSRC 8
+#define BHND_PMU_RES4313_TX_PWRSW_RSRC 9
+#define BHND_PMU_RES4313_BB_PWRSW_RSRC 10
+#define BHND_PMU_RES4313_SYNTH_PWRSW_RSRC 11
+#define BHND_PMU_RES4313_MISC_PWRSW_RSRC 12
+#define BHND_PMU_RES4313_BB_PLL_PWRSW_RSRC 13
+#define BHND_PMU_RES4313_HT_AVAIL_RSRC 14
+#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 */
+
+/* 43228 resources */
+#define BHND_PMU_RES43228_NOT_USED 0
+#define BHND_PMU_RES43228_ILP_REQUEST 1
+#define BHND_PMU_RES43228_XTAL_PU 2
+#define BHND_PMU_RES43228_ALP_AVAIL 3
+#define BHND_PMU_RES43228_PLL_EN 4
+#define BHND_PMU_RES43228_HT_PHY_AVAIL 5
+
+/*
+* Maximum delay for the PMU state transition in us.
+* This is an upper bound intended for spinwaits etc.
+*/
+#define BHND_PMU_MAX_TRANSITION_DLY 15000
+
+/* PMU resource up transition time in ILP cycles */
+#define BHND_PMURES_UP_TRANSITION 2
+
+#endif /* _BHND_CORES_PMU_BHND_PMUREG_H_ */
diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h b/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h
new file mode 100644
index 000000000000..14c26dbcb1e7
--- /dev/null
+++ b/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _BHND_CORES_PMU_BHND_PMUVAR_H_
+#define _BHND_CORES_PMU_BHND_PMUVAR_H_
+
+#include <sys/types.h>
+#include <sys/rman.h>
+
+#include "bhnd_pmu.h"
+
+DECLARE_CLASS(bhnd_pmu_driver);
+extern devclass_t bhnd_pmu_devclass;
+
+int bhnd_pmu_probe(device_t dev);
+
+int bhnd_pmu_attach(device_t dev, struct bhnd_resource *res);
+int bhnd_pmu_detach(device_t dev);
+int bhnd_pmu_suspend(device_t dev);
+int bhnd_pmu_resume(device_t dev);
+
+/*
+ * 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
+};
+
+/**
+ * bhnd_pmu driver instance state.
+ */
+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 */
+ struct bhnd_board_info board; /**< board identification */
+ device_t chipc_dev; /**< chipcommon device */
+
+ struct bhnd_resource *res; /**< pmu register block. */
+ int rid; /**< pmu register RID */
+
+ struct mtx mtx; /**< state mutex */
+
+ uint32_t ilp_cps; /**< measured ILP cycles per
+ second, or 0 */
+};
+
+#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)
+#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)
+
+#endif /* _BHND_CORES_PMU_BHND_PMUVAR_H_ */
diff --git a/sys/dev/bhnd/nvram/nvram_map b/sys/dev/bhnd/nvram/nvram_map
index 09230eefa2d7..f38573500ab7 100644
--- a/sys/dev/bhnd/nvram/nvram_map
+++ b/sys/dev/bhnd/nvram/nvram_map
@@ -84,6 +84,21 @@ u8 sromrev {
srom 11 0x1D2
}
+
+# PMU Info
+#
+
+# PMU min resource mask (embedded-only).
+u32 rmin {
+ sfmt decimal
+}
+
+# PMU min resource max (embedded-only).
+u32 rmax {
+ sfmt decimal
+}
+
+
# Antennas available
u8 aa2g {
srom 1-3 0x5C (&0x30, >>4)
diff --git a/sys/dev/bhnd/siba/siba.c b/sys/dev/bhnd/siba/siba.c
index ac37ae381d9d..9e3679a1260e 100644
--- a/sys/dev/bhnd/siba/siba.c
+++ b/sys/dev/bhnd/siba/siba.c
@@ -260,6 +260,20 @@ siba_suspend_core(device_t dev, device_t child)
return (ENXIO);
}
+static uint32_t
+siba_read_config(device_t dev, device_t child, bus_size_t offset, u_int width)
+{
+ /* Unsuported */
+ return (UINT32_MAX);
+}
+
+static void
+siba_write_config(device_t dev, device_t child, bus_size_t offset, uint32_t val,
+ u_int width)
+{
+ /* Unsuported */
+ return;
+}
static u_int
siba_get_port_count(device_t dev, device_t child, bhnd_port_type type)
@@ -603,6 +617,9 @@ siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
/* Release our resource */
bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
r = NULL;
+
+ /* Issue bus callback for fully initialized child. */
+ BHND_BUS_CHILD_ADDED(dev, child);
}
cleanup:
@@ -634,6 +651,8 @@ static device_method_t siba_methods[] = {
DEVMETHOD(bhnd_bus_free_devinfo, siba_free_bhnd_dinfo),
DEVMETHOD(bhnd_bus_reset_core, siba_reset_core),
DEVMETHOD(bhnd_bus_suspend_core, siba_suspend_core),
+ DEVMETHOD(bhnd_bus_read_config, siba_read_config),
+ DEVMETHOD(bhnd_bus_write_config, siba_write_config),
DEVMETHOD(bhnd_bus_get_port_count, siba_get_port_count),
DEVMETHOD(bhnd_bus_get_region_count, siba_get_region_count),
DEVMETHOD(bhnd_bus_get_port_rid, siba_get_port_rid),
diff --git a/sys/mips/broadcom/bcm_machdep.c b/sys/mips/broadcom/bcm_machdep.c
index f03c72b6cebf..2d288a15ecd8 100644
--- a/sys/mips/broadcom/bcm_machdep.c
+++ b/sys/mips/broadcom/bcm_machdep.c
@@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$");
#include <dev/bhnd/siba/sibavar.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
+#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
#include "bcm_machdep.h"
#include "bcm_mips_exts.h"
@@ -342,7 +343,7 @@ platform_reset(void)
/* Set watchdog (PMU or ChipCommon) */
if (bcm_get_platform()->pmu_addr != 0x0) {
- BCM_CHIPC_WRITE_4(CHIPC_PMU_WATCHDOG, 1);
+ BCM_CHIPC_WRITE_4(BHND_PMU_WATCHDOG, 1);
} else
BCM_CHIPC_WRITE_4(CHIPC_WATCHDOG, 1);
diff --git a/sys/modules/bhnd/Makefile b/sys/modules/bhnd/Makefile
index 19d239ec3e3d..955565934734 100644
--- a/sys/modules/bhnd/Makefile
+++ b/sys/modules/bhnd/Makefile
@@ -1,22 +1,36 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../dev/bhnd
+.PATH: ${.CURDIR}/../../dev/bhnd/cores/chipc
+.PATH: ${.CURDIR}/../../dev/bhnd/cores/chipc/pwrctl
+.PATH: ${.CURDIR}/../../dev/bhnd/cores/pmu
.PATH: ${.CURDIR}/../../dev/bhnd/nvram
KMOD= bhnd
-SRCS= bhnd.c \
- bhnd_subr.c
+SRCS= bhnd.c bhnd_subr.c
+SRCS+= bhnd_bus_if.c bhnd_bus_if.h
+# ChipCommon
+SRCS+= chipc.c chipc_subr.c
+SRCS+= bhnd_sprom_chipc.c \
+ bhnd_pmu_chipc.c \
+ bhnd_pwrctl.c bhnd_pwrctl_subr.c
+SRCS+= bhnd_chipc_if.c bhnd_chipc_if.h
+
+# PMU
+SRCS+= bhnd_pmu.c \
+ bhnd_pmu_core.c \
+ bhnd_pmu_subr.c
+SRCS+= bhnd_pmu_if.c bhnd_pmu_if.h
+
+# NVRAM/SPROM
SRCS+= bhnd_nvram.c \
bhnd_nvram_parser.c \
bhnd_sprom.c \
bhnd_sprom_parser.c
SRCS+= bhnd_nvram_common.c
SRCS+= bhnd_nvram_map.h bhnd_nvram_map_data.h
-
-SRCS+= bhnd_bus_if.c bhnd_bus_if.h \
- bhnd_chipc_if.c bhnd_chipc_if.h \
- bhnd_nvram_if.c bhnd_nvram_if.h
+SRCS+= bhnd_nvram_if.c bhnd_nvram_if.h
SRCS+= device_if.h bus_if.h
diff --git a/sys/modules/bhnd/cores/Makefile b/sys/modules/bhnd/cores/Makefile
index cc45dfbe168f..3c7398e38582 100644
--- a/sys/modules/bhnd/cores/Makefile
+++ b/sys/modules/bhnd/cores/Makefile
@@ -1,7 +1,6 @@
# $FreeBSD$
-SUBDIR= bhnd_chipc \
- bhnd_pci \
+SUBDIR= bhnd_pci \
bhnd_pci_hostb \
bhnd_pcib
diff --git a/sys/modules/bhnd/cores/bhnd_chipc/Makefile b/sys/modules/bhnd/cores/bhnd_chipc/Makefile
deleted file mode 100644
index b4ca2a64bd57..000000000000
--- a/sys/modules/bhnd/cores/bhnd_chipc/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR}/../../../../dev/bhnd/cores/chipc
-
-KMOD= bhnd_chipc
-SRCS= chipc.c chipc_subr.c \
- bhnd_sprom_chipc.c
-SRCS+= device_if.h bus_if.h bhnd_bus_if.h \
- bhnd_chipc_if.h bhnd_nvram_if.h
-
-.include <bsd.kmod.mk>