svn commit: r304870 - in head/sys: conf dev/bhnd dev/bhnd/bcma dev/bhnd/bhndb dev/bhnd/cores/chipc dev/bhnd/cores/chipc/pwrctl dev/bhnd/cores/pmu dev/bhnd/nvram dev/bhnd/pmu dev/bhnd/siba mips/broa...
Landon J. Fuller
landonf at FreeBSD.org
Sat Aug 27 00:03:04 UTC 2016
Author: landonf
Date: Sat Aug 27 00:03:02 2016
New Revision: 304870
URL: https://svnweb.freebsd.org/changeset/base/304870
Log:
bhnd(4): Initial PMU/PWRCTL power and clock management support.
- Added bhnd_pmu driver implementations for PMU and PWRCTL chipsets,
derived from Broadcom's ISC-licensed HND code.
- Added bhnd bus-level support for routing per-core clock and resource
power requests to the PMU device.
- Lift ChipCommon support out into the bhnd module, dropping
bhnd_chipc.
Reviewed by: mizhka
Approved by: adrian (mentor)
Differential Revision: https://reviews.freebsd.org/D7492
Added:
head/sys/dev/bhnd/cores/chipc/bhnd_pmu_chipc.c (contents, props changed)
head/sys/dev/bhnd/cores/chipc/pwrctl/
head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c (contents, props changed)
head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h (contents, props changed)
head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c (contents, props changed)
head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h (contents, props changed)
head/sys/dev/bhnd/cores/pmu/
head/sys/dev/bhnd/cores/pmu/bhnd_pmu.c (contents, props changed)
head/sys/dev/bhnd/cores/pmu/bhnd_pmu.h (contents, props changed)
head/sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c (contents, props changed)
head/sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m (contents, props changed)
head/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h (contents, props changed)
head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c (contents, props changed)
head/sys/dev/bhnd/cores/pmu/bhnd_pmureg.h (contents, props changed)
head/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h (contents, props changed)
head/sys/dev/bhnd/pmu/
Deleted:
head/sys/modules/bhnd/cores/bhnd_chipc/
Modified:
head/sys/conf/files
head/sys/dev/bhnd/bcma/bcma.c
head/sys/dev/bhnd/bcma/bcma_dmp.h
head/sys/dev/bhnd/bhnd.c
head/sys/dev/bhnd/bhnd.h
head/sys/dev/bhnd/bhnd_bus_if.m
head/sys/dev/bhnd/bhnd_core.h
head/sys/dev/bhnd/bhnd_ids.h
head/sys/dev/bhnd/bhnd_subr.c
head/sys/dev/bhnd/bhnd_types.h
head/sys/dev/bhnd/bhndb/bhnd_bhndb.c
head/sys/dev/bhnd/bhndb/bhndb.c
head/sys/dev/bhnd/bhndb/bhndb_pci.c
head/sys/dev/bhnd/bhndvar.h
head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c
head/sys/dev/bhnd/cores/chipc/chipc.c
head/sys/dev/bhnd/cores/chipc/chipc.h
head/sys/dev/bhnd/cores/chipc/chipc_subr.c
head/sys/dev/bhnd/cores/chipc/chipcreg.h
head/sys/dev/bhnd/cores/chipc/chipcvar.h
head/sys/dev/bhnd/nvram/nvram_map
head/sys/dev/bhnd/siba/siba.c
head/sys/mips/broadcom/bcm_machdep.c
head/sys/modules/bhnd/Makefile
head/sys/modules/bhnd/cores/Makefile
Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Fri Aug 26 23:50:44 2016 (r304869)
+++ head/sys/conf/files Sat Aug 27 00:03:02 2016 (r304870)
@@ -1157,19 +1157,26 @@ dev/bhnd/bcma/bcma_bhndb.c optional bcm
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 | \
Modified: head/sys/dev/bhnd/bcma/bcma.c
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma.c Fri Aug 26 23:50:44 2016 (r304869)
+++ head/sys/dev/bhnd/bcma/bcma.c Sat Aug 27 00:03:02 2016 (r304870)
@@ -259,6 +259,78 @@ bcma_suspend_core(device_t dev, device_t
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 r
* 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),
Modified: head/sys/dev/bhnd/bcma/bcma_dmp.h
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma_dmp.h Fri Aug 26 23:50:44 2016 (r304869)
+++ head/sys/dev/bhnd/bcma/bcma_dmp.h Sat Aug 27 00:03:02 2016 (r304870)
@@ -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) */
Modified: head/sys/dev/bhnd/bhnd.c
==============================================================================
--- head/sys/dev/bhnd/bhnd.c Fri Aug 26 23:50:44 2016 (r304869)
+++ head/sys/dev/bhnd/bhnd.c Sat Aug 27 00:03:02 2016 (r304870)
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon at landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landonf at 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 de
}
/**
+ * 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_i
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,
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) */
Modified: head/sys/dev/bhnd/bhnd.h
==============================================================================
--- head/sys/dev/bhnd/bhnd.h Fri Aug 26 23:50:44 2016 (r304869)
+++ head/sys/dev/bhnd/bhnd.h Sat Aug 27 00:03:02 2016 (r304870)
@@ -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, struc
}
/**
+ * 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.
Modified: head/sys/dev/bhnd/bhnd_bus_if.m
==============================================================================
--- head/sys/dev/bhnd/bhnd_bus_if.m Fri Aug 26 23:50:44 2016 (r304869)
+++ head/sys/dev/bhnd/bhnd_bus_if.m Sat Aug 27 00:03:02 2016 (r304870)
@@ -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.
+ *
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-head
mailing list