svn commit: r326102 - in head/sys: conf dev/bhnd dev/bhnd/bcma dev/bhnd/bhndb dev/bhnd/cores/chipc dev/bhnd/cores/chipc/pwrctl dev/bhnd/cores/pmu dev/bhnd/siba mips/broadcom modules/bhnd modules/bh...

Landon J. Fuller landonf at FreeBSD.org
Wed Nov 22 20:27:48 UTC 2017


Author: landonf
Date: Wed Nov 22 20:27:46 2017
New Revision: 326102
URL: https://svnweb.freebsd.org/changeset/base/326102

Log:
  bhnd(4): extend the PMU APIs to support bwn(4)
  
  The bwn(4) driver requires a number of extensions to the bhnd(4) PMU
  interface to support external configuration of PLLs, LDOs, and other
  parameters that require chipset or PHY-specific workarounds.
  
  These changes add support for:
  
  - Writing raw voltage register values to PHY-specific LDO regulator
    registers (required by LP-PHY).
  - Enabling/disabling PHY-specific LDOs (required by LP-PHY)
  - Writing to arbitrary PMU chipctrl registers (required for common PHY PLL
    reset support).
  - Requesting chipset/PLL-specific spurious signal avoidance modes.
  - Querying clock frequency and latency.
  
  Additionally, rather than updating legacy PWRCTL support to conform to the
  new PMU interface:
  
  - PWRCTL API is now provided by a bhnd_pwrctl_if.m interface.
  - Since PWRCTL is only found in older SSB-based chipsets, translation from
    bhnd(4) bus APIs to corresponding PWRCTL operations is now handled
    entirely within the siba(4) driver.
  - The PWRCTL-specific host bridge clock gating APIs in bhnd_bus_if.m have
    been lifted out into a standalone bhnd_pwrctl_hostb_if.m interface.
  
  Approved by:	adrian (mentor, implicit)
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D12664

Added:
  head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h   (contents, props changed)
  head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_hostb_if.m   (contents, props changed)
  head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_if.m   (contents, props changed)
  head/sys/dev/bhnd/cores/pmu/bhnd_pmu_types.h   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/dev/bhnd/bcma/bcma.c
  head/sys/dev/bhnd/bcma/bcmavar.h
  head/sys/dev/bhnd/bhnd.c
  head/sys/dev/bhnd/bhnd.h
  head/sys/dev/bhnd/bhnd_bus_if.m
  head/sys/dev/bhnd/bhnd_private.h
  head/sys/dev/bhnd/bhnd_subr.c
  head/sys/dev/bhnd/bhnd_types.h
  head/sys/dev/bhnd/bhndb/bhnd_bhndb.c
  head/sys/dev/bhnd/bhndb/bhndb_pci.c
  head/sys/dev/bhnd/bhndreg.h
  head/sys/dev/bhnd/bhndvar.h
  head/sys/dev/bhnd/cores/chipc/chipc.c
  head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c
  head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_private.h
  head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c
  head/sys/dev/bhnd/cores/pmu/bhnd_pmu.c
  head/sys/dev/bhnd/cores/pmu/bhnd_pmu.h
  head/sys/dev/bhnd/cores/pmu/bhnd_pmu_core.c
  head/sys/dev/bhnd/cores/pmu/bhnd_pmu_if.m
  head/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h
  head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
  head/sys/dev/bhnd/cores/pmu/bhnd_pmureg.h
  head/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h
  head/sys/dev/bhnd/siba/siba.c
  head/sys/dev/bhnd/siba/siba_bhndb.c
  head/sys/dev/bhnd/siba/siba_subr.c
  head/sys/dev/bhnd/siba/sibavar.h
  head/sys/mips/broadcom/siba_nexus.c
  head/sys/modules/bhnd/Makefile
  head/sys/modules/bhnd/bhndb/Makefile
  head/sys/modules/bhnd/bhndb_pci/Makefile
  head/sys/modules/bhnd/siba/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Wed Nov 22 19:58:29 2017	(r326101)
+++ head/sys/conf/files	Wed Nov 22 20:27:46 2017	(r326102)
@@ -1250,6 +1250,8 @@ dev/bhnd/cores/chipc/chipc_slicer.c	optional bhnd cfi 
 dev/bhnd/cores/chipc/chipc_spi.c	optional bhnd spibus
 dev/bhnd/cores/chipc/chipc_subr.c	optional bhnd
 dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.c	optional bhnd
+dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_if.m	optional bhnd
+dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_hostb_if.m	optional bhnd
 dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c	optional bhnd
 dev/bhnd/cores/pci/bhnd_pci.c		optional bhnd pci
 dev/bhnd/cores/pci/bhnd_pci_hostb.c	optional bhndb bhnd pci

Modified: head/sys/dev/bhnd/bcma/bcma.c
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma.c	Wed Nov 22 19:58:29 2017	(r326101)
+++ head/sys/dev/bhnd/bcma/bcma.c	Wed Nov 22 20:27:46 2017	(r326102)
@@ -193,7 +193,7 @@ bcma_write_ivar(device_t dev, device_t child, int inde
 	case BHND_IVAR_CORE_UNIT:
 		return (EINVAL);
 	case BHND_IVAR_PMU_INFO:
-		dinfo->pmu_info = (struct bhnd_core_pmu_info *) value;
+		dinfo->pmu_info = (void *)value;
 		return (0);
 	default:
 		return (ENOENT);
@@ -349,17 +349,15 @@ bcma_reset_hw(device_t dev, device_t child, uint16_t i
 static int
 bcma_suspend_hw(device_t dev, device_t child)
 {
-	struct bcma_devinfo		*dinfo;
-	struct bhnd_core_pmu_info	*pm;
-	struct bhnd_resource		*r;
-	uint32_t			 rst;
-	int				 error;
+	struct bcma_devinfo	*dinfo;
+	struct bhnd_resource	*r;
+	uint32_t		 rst;
+	int			 error;
 
 	if (device_get_parent(child) != dev)
 		return (EINVAL);
 
 	dinfo = device_get_ivars(child);
-	pm = dinfo->pmu_info;
 
 	/* Can't suspend the core without access to the agent registers */
 	if ((r = dinfo->res_agent) == NULL)
@@ -381,12 +379,6 @@ bcma_suspend_hw(device_t dev, device_t child)
 	/* Clear core flags */
 	if ((error = bhnd_write_ioctl(child, 0x0, UINT16_MAX)))
 		return (error);
-
-	/* Inform PMU that all outstanding request state should be discarded */
-	if (pm != NULL) {
-		if ((error = BHND_PMU_CORE_RELEASE(pm->pm_pmu, pm)))
-			return (error);
-	}
 
 	return (0);
 }

Modified: head/sys/dev/bhnd/bcma/bcmavar.h
==============================================================================
--- head/sys/dev/bhnd/bcma/bcmavar.h	Wed Nov 22 19:58:29 2017	(r326101)
+++ head/sys/dev/bhnd/bcma/bcmavar.h	Wed Nov 22 20:27:46 2017	(r326102)
@@ -175,17 +175,17 @@ struct bcma_corecfg {
  * BCMA per-device info
  */
 struct bcma_devinfo {
-	struct resource_list		 resources;	/**< Slave port memory regions. */
-	struct bcma_corecfg		*corecfg;	/**< IP core/block config */
+	struct resource_list	 resources;	/**< Slave port memory regions. */
+	struct bcma_corecfg	*corecfg;	/**< IP core/block config */
 
-	struct bhnd_resource		*res_agent;	/**< Agent (wrapper) resource, or NULL. Not
-							  *  all bcma(4) cores have or require an agent. */
-	int				 rid_agent;	/**< Agent resource ID, or -1 */
+	struct bhnd_resource	*res_agent;	/**< Agent (wrapper) resource, or NULL. Not
+						  *  all bcma(4) cores have or require an agent. */
+	int			 rid_agent;	/**< Agent resource ID, or -1 */
 
-	u_int				 num_intrs;	/**< number of interrupt descriptors. */
-	struct bcma_intr_list		 intrs;		/**< interrupt descriptors */
+	u_int			 num_intrs;	/**< number of interrupt descriptors. */
+	struct bcma_intr_list	 intrs;		/**< interrupt descriptors */
 
-	struct bhnd_core_pmu_info	*pmu_info;	/**< Bus-managed PMU state, or NULL */
+	void			*pmu_info;	/**< Bus-managed PMU state, or NULL */
 };
 
 

Modified: head/sys/dev/bhnd/bhnd.c
==============================================================================
--- head/sys/dev/bhnd/bhnd.c	Wed Nov 22 19:58:29 2017	(r326101)
+++ head/sys/dev/bhnd/bhnd.c	Wed Nov 22 20:27:46 2017	(r326102)
@@ -62,15 +62,13 @@ __FBSDID("$FreeBSD$");
 #include <sys/rman.h>
 #include <machine/resource.h>
 
-#include <dev/bhnd/cores/chipc/chipcvar.h>
-
 #include <dev/bhnd/cores/pmu/bhnd_pmu.h>
-#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
 
 #include "bhnd_chipc_if.h"
 #include "bhnd_nvram_if.h"
 
 #include "bhnd.h"
+#include "bhndreg.h"
 #include "bhndvar.h"
 
 #include "bhnd_private.h"
@@ -363,24 +361,28 @@ int
 bhnd_generic_alloc_pmu(device_t dev, device_t child)
 {
 	struct bhnd_softc		*sc;
-	struct bhnd_resource		*br;
-	struct bhnd_core_pmu_info	*pm;
+	struct bhnd_resource		*r;
+	struct bhnd_core_clkctl		*clkctl;
 	struct resource_list		*rl;
 	struct resource_list_entry	*rle;
 	device_t			 pmu_dev;
 	bhnd_addr_t			 r_addr;
 	bhnd_size_t			 r_size;
 	bus_size_t			 pmu_regs;
+	u_int				 max_latency;
 	int				 error;
 
 	GIANT_REQUIRED;	/* for newbus */
-	
+
+	if (device_get_parent(child) != dev)
+		return (EINVAL);
+
 	sc = device_get_softc(dev);
-	pm = bhnd_get_pmu_info(child);
+	clkctl = bhnd_get_pmu_info(child);
 	pmu_regs = BHND_CLK_CTL_ST;
 
 	/* already allocated? */
-	if (pm != NULL) {
+	if (clkctl != NULL) {
 		panic("duplicate PMU allocation for %s",
 		    device_get_nameunit(child));
 	}
@@ -440,36 +442,38 @@ bhnd_generic_alloc_pmu(device_t dev, device_t child)
 	else
 		pmu_regs -= r_addr - rman_get_start(rle->res);
 
-	/* Retain PMU reference on behalf of our caller */
+	/* Retain a PMU reference for the clkctl instance state */
 	pmu_dev = bhnd_retain_provider(child, BHND_SERVICE_PMU);
 	if (pmu_dev == NULL) {
-		device_printf(sc->dev, 
-		    "pmu unavailable; cannot allocate request state\n");
+		device_printf(sc->dev, "PMU not found\n");
 		return (ENXIO);
 	}
 
-	/* Allocate and initialize PMU info */
-	br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
-	if (br == NULL) {
+	/* Fetch the maximum transition latency from our PMU */
+	max_latency = bhnd_pmu_get_max_transition_latency(pmu_dev);
+
+	/* Allocate a new bhnd_resource wrapping the standard resource we
+	 * fetched from the resource list; we'll free this in
+	 * bhnd_generic_release_pmu() */
+	r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
+	if (r == NULL) {
 		bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU);
 		return (ENOMEM);
 	}
 
-	br->res = rle->res;
-	br->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0);
+	r->res = rle->res;
+	r->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0);
 
-	pm = malloc(sizeof(*pm), M_BHND, M_NOWAIT);
-	if (pm == NULL) {
+	/* Allocate the clkctl instance */
+	clkctl = bhnd_alloc_core_clkctl(child, pmu_dev, r, pmu_regs,
+	    max_latency);
+	if (clkctl == NULL) {
+		free(r, M_BHND);
 		bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU);
-		free(br, M_BHND);
 		return (ENOMEM);
 	}
-	pm->pm_dev = child;
-	pm->pm_res = br;
-	pm->pm_regs = pmu_regs;
-	pm->pm_pmu = pmu_dev;
 
-	bhnd_set_pmu_info(child, pm);
+	bhnd_set_pmu_info(child, clkctl);
 	return (0);
 }
 
@@ -479,48 +483,148 @@ bhnd_generic_alloc_pmu(device_t dev, device_t child)
 int
 bhnd_generic_release_pmu(device_t dev, device_t child)
 {
-	struct bhnd_softc		*sc;
-	struct bhnd_core_pmu_info	*pm;
-	int				 error;
+	struct bhnd_softc	*sc;
+	struct bhnd_core_clkctl	*clkctl;
+	struct bhnd_resource	*r;
+	device_t		 pmu_dev;
 
 	GIANT_REQUIRED;	/* for newbus */
 	
 	sc = device_get_softc(dev);
 
-	/* dispatch release request */
-	pm = bhnd_get_pmu_info(child);
-	if (pm == NULL)
+	if (device_get_parent(child) != dev)
+		return (EINVAL);
+
+	clkctl = bhnd_get_pmu_info(child);
+	if (clkctl == NULL)
 		panic("pmu over-release for %s", device_get_nameunit(child));
 
-	if ((error = BHND_PMU_CORE_RELEASE(pm->pm_pmu, pm)))
-		return (error);
+	/* Clear all FORCE, AREQ, and ERSRC flags, unless we're already in
+	 * RESET. Suspending a core clears clkctl automatically (and attempting
+	 * to access the PMU registers in a suspended core will trigger a
+	 * system livelock). */
+	if (!bhnd_is_hw_suspended(clkctl->cc_dev)) {
+		BHND_CLKCTL_LOCK(clkctl);
 
-	/* free PMU info */
+		/* Clear all FORCE, AREQ, and ERSRC flags */
+		BHND_CLKCTL_SET_4(clkctl, 0x0, BHND_CCS_FORCE_MASK |
+		    BHND_CCS_AREQ_MASK | BHND_CCS_ERSRC_REQ_MASK);
+
+		BHND_CLKCTL_UNLOCK(clkctl);
+	}
+
+	/* Clear child's PMU info reference */
 	bhnd_set_pmu_info(child, NULL);
 
-	bhnd_release_provider(pm->pm_dev, pm->pm_pmu, BHND_SERVICE_PMU);
-	free(pm->pm_res, M_BHND);
-	free(pm, M_BHND);
+	/* Before freeing the clkctl instance, save a pointer to resources we
+	 * need to clean up manually */
+	r = clkctl->cc_res;
+	pmu_dev = clkctl->cc_pmu_dev;
 
+	/* Free the clkctl instance */
+	bhnd_free_core_clkctl(clkctl);
+
+	/* Free the child's bhnd resource wrapper */
+	free(r, M_BHND);
+
+	/* Release the child's PMU provider reference */
+	bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU);
+
 	return (0);
 }
 
 /**
+ * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_LATENCY().
+ */
+int
+bhnd_generic_get_clock_latency(device_t dev, device_t child, bhnd_clock clock,
+    u_int *latency)
+{
+	struct bhnd_core_clkctl *clkctl;
+
+	if (device_get_parent(child) != dev)
+		return (EINVAL);
+
+	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
+		panic("no active PMU allocation");
+
+	return (bhnd_pmu_get_clock_latency(clkctl->cc_pmu_dev, clock, latency));
+}
+
+/**
+ * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_FREQ().
+ */
+int
+bhnd_generic_get_clock_freq(device_t dev, device_t child, bhnd_clock clock,
+    u_int *freq)
+{
+	struct bhnd_core_clkctl *clkctl;
+
+	if (device_get_parent(child) != dev)
+		return (EINVAL);
+
+	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
+		panic("no active PMU allocation");
+
+	return (bhnd_pmu_get_clock_freq(clkctl->cc_pmu_dev, clock, freq));
+}
+
+/**
  * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_CLOCK().
  */
 int
 bhnd_generic_request_clock(device_t dev, device_t child, bhnd_clock clock)
 {
-	struct bhnd_softc		*sc;
-	struct bhnd_core_pmu_info	*pm;
+	struct bhnd_softc	*sc;
+	struct bhnd_core_clkctl	*clkctl;
+	uint32_t		 avail;
+	uint32_t		 req;
+	int			 error;
 
 	sc = device_get_softc(dev);
 
-	if ((pm = bhnd_get_pmu_info(child)) == NULL)
-		panic("no active PMU request state");
+	if (device_get_parent(child) != dev)
+		return (EINVAL);
 
-	/* dispatch request to PMU */
-	return (BHND_PMU_CORE_REQ_CLOCK(pm->pm_pmu, pm, clock));
+	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
+		panic("no active PMU allocation");
+
+	BHND_ASSERT_CLKCTL_AVAIL(clkctl);
+
+	avail = 0x0;
+	req = 0x0;
+
+	switch (clock) {
+	case BHND_CLOCK_DYN:
+		break;
+	case BHND_CLOCK_ILP:
+		req |= BHND_CCS_FORCEILP;
+		break;
+	case BHND_CLOCK_ALP:
+		req |= BHND_CCS_FORCEALP;
+		avail |= BHND_CCS_ALPAVAIL;
+		break;
+	case BHND_CLOCK_HT:
+		req |= BHND_CCS_FORCEHT;
+		avail |= BHND_CCS_HTAVAIL;
+		break;
+	default:
+		device_printf(dev, "%s requested unknown clock: %#x\n",
+		    device_get_nameunit(clkctl->cc_dev), clock);
+		return (ENODEV);
+	}
+
+	BHND_CLKCTL_LOCK(clkctl);
+
+	/* Issue request */
+	BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_FORCE_MASK);
+
+	/* Wait for clock availability */
+	error = bhnd_core_clkctl_wait(clkctl, avail, avail);
+
+	BHND_CLKCTL_UNLOCK(clkctl);
+
+	return (error);
 }
 
 /**
@@ -529,16 +633,64 @@ bhnd_generic_request_clock(device_t dev, device_t chil
 int
 bhnd_generic_enable_clocks(device_t dev, device_t child, uint32_t clocks)
 {
-	struct bhnd_softc		*sc;
-	struct bhnd_core_pmu_info	*pm;
+	struct bhnd_softc	*sc;
+	struct bhnd_core_clkctl	*clkctl;
+	uint32_t		 avail;
+	uint32_t		 req;
+	int			 error;
 
 	sc = device_get_softc(dev);
 
-	if ((pm = bhnd_get_pmu_info(child)) == NULL)
-		panic("no active PMU request state");
+	if (device_get_parent(child) != dev)
+		return (EINVAL);
 
-	/* dispatch request to PMU */
-	return (BHND_PMU_CORE_EN_CLOCKS(pm->pm_pmu, pm, clocks));
+	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
+		panic("no active PMU allocation");
+
+	BHND_ASSERT_CLKCTL_AVAIL(clkctl);
+
+	sc = device_get_softc(dev);
+
+	avail = 0x0;
+	req = 0x0;
+
+	/* Build clock request flags */
+	if (clocks & BHND_CLOCK_DYN)		/* nothing to enable */
+		clocks &= ~BHND_CLOCK_DYN;
+
+	if (clocks & BHND_CLOCK_ILP)		/* nothing to enable */
+		clocks &= ~BHND_CLOCK_ILP;
+
+	if (clocks & BHND_CLOCK_ALP) {
+		req |= BHND_CCS_ALPAREQ;
+		avail |= BHND_CCS_ALPAVAIL;
+		clocks &= ~BHND_CLOCK_ALP;
+	}
+
+	if (clocks & BHND_CLOCK_HT) {
+		req |= BHND_CCS_HTAREQ;
+		avail |= BHND_CCS_HTAVAIL;
+		clocks &= ~BHND_CLOCK_HT;
+	}
+
+	/* Check for unknown clock values */
+	if (clocks != 0x0) {
+		device_printf(dev, "%s requested unknown clocks: %#x\n",
+		    device_get_nameunit(clkctl->cc_dev), clocks);
+		return (ENODEV);
+	}
+
+	BHND_CLKCTL_LOCK(clkctl);
+
+	/* Issue request */
+	BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_AREQ_MASK);
+
+	/* Wait for clock availability */
+	error = bhnd_core_clkctl_wait(clkctl, avail, avail);
+
+	BHND_CLKCTL_UNLOCK(clkctl);
+
+	return (error);
 }
 
 /**
@@ -547,16 +699,41 @@ bhnd_generic_enable_clocks(device_t dev, device_t chil
 int
 bhnd_generic_request_ext_rsrc(device_t dev, device_t child, u_int rsrc)
 {
-	struct bhnd_softc		*sc;
-	struct bhnd_core_pmu_info	*pm;
+	struct bhnd_softc	*sc;
+	struct bhnd_core_clkctl	*clkctl;
+	uint32_t		 req;
+	uint32_t		 avail;
+	int			 error;
 
 	sc = device_get_softc(dev);
 
-	if ((pm = bhnd_get_pmu_info(child)) == NULL)
-		panic("no active PMU request state");
+	if (device_get_parent(child) != dev)
+		return (EINVAL);
 
-	/* dispatch request to PMU */
-	return (BHND_PMU_CORE_REQ_EXT_RSRC(pm->pm_pmu, pm, rsrc));
+	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
+		panic("no active PMU allocation");
+
+	BHND_ASSERT_CLKCTL_AVAIL(clkctl);
+
+	sc = device_get_softc(dev);
+
+	if (rsrc > BHND_CCS_ERSRC_MAX)
+		return (EINVAL);
+
+	req = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
+	avail = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_STS);
+
+	BHND_CLKCTL_LOCK(clkctl);
+
+	/* Write request */
+	BHND_CLKCTL_SET_4(clkctl, req, req);
+
+	/* Wait for resource availability */
+	error = bhnd_core_clkctl_wait(clkctl, avail, avail);
+
+	BHND_CLKCTL_UNLOCK(clkctl);
+
+	return (error);
 }
 
 /**
@@ -565,19 +742,36 @@ bhnd_generic_request_ext_rsrc(device_t dev, device_t c
 int
 bhnd_generic_release_ext_rsrc(device_t dev, device_t child, u_int rsrc)
 {
-	struct bhnd_softc		*sc;
-	struct bhnd_core_pmu_info	*pm;
+	struct bhnd_softc	*sc;
+	struct bhnd_core_clkctl	*clkctl;
+	uint32_t		 mask;
 
 	sc = device_get_softc(dev);
 
-	if ((pm = bhnd_get_pmu_info(child)) == NULL)
-		panic("no active PMU request state");
+	if (device_get_parent(child) != dev)
+		return (EINVAL);
 
-	/* dispatch request to PMU */
-	return (BHND_PMU_CORE_RELEASE_EXT_RSRC(pm->pm_pmu, pm, rsrc));
-}
+	if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
+		panic("no active PMU allocation");
 
 
+	BHND_ASSERT_CLKCTL_AVAIL(clkctl);
+
+	sc = device_get_softc(dev);
+
+	if (rsrc > BHND_CCS_ERSRC_MAX)
+		return (EINVAL);
+
+	mask = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
+
+	/* Clear request */
+	BHND_CLKCTL_LOCK(clkctl);
+	BHND_CLKCTL_SET_4(clkctl, 0x0, mask);
+	BHND_CLKCTL_UNLOCK(clkctl);
+
+	return (0);
+}
+
 /**
  * Default bhnd(4) bus driver implementation of BHND_BUS_IS_REGION_VALID().
  * 
@@ -954,6 +1148,8 @@ static device_method_t bhnd_methods[] = {
 	DEVMETHOD(bhnd_bus_enable_clocks,	bhnd_generic_enable_clocks),
 	DEVMETHOD(bhnd_bus_request_ext_rsrc,	bhnd_generic_request_ext_rsrc),
 	DEVMETHOD(bhnd_bus_release_ext_rsrc,	bhnd_generic_release_ext_rsrc),
+	DEVMETHOD(bhnd_bus_get_clock_latency,	bhnd_generic_get_clock_latency),
+	DEVMETHOD(bhnd_bus_get_clock_freq,	bhnd_generic_get_clock_freq),
 
 	DEVMETHOD(bhnd_bus_is_region_valid,	bhnd_generic_is_region_valid),
 	DEVMETHOD(bhnd_bus_get_nvram_var,	bhnd_generic_get_nvram_var),

Modified: head/sys/dev/bhnd/bhnd.h
==============================================================================
--- head/sys/dev/bhnd/bhnd.h	Wed Nov 22 19:58:29 2017	(r326101)
+++ head/sys/dev/bhnd/bhnd.h	Wed Nov 22 20:27:46 2017	(r326102)
@@ -52,8 +52,6 @@
 
 #include "nvram/bhnd_nvram.h"
 
-struct bhnd_core_pmu_info;
-
 extern devclass_t bhnd_devclass;
 extern devclass_t bhnd_hostb_devclass;
 extern devclass_t bhnd_nvram_devclass;
@@ -155,7 +153,7 @@ BHND_ACCESSOR(vendor_name,	VENDOR_NAME,	const char *);
 BHND_ACCESSOR(device_name,	DEVICE_NAME,	const char *);
 BHND_ACCESSOR(core_index,	CORE_INDEX,	u_int);
 BHND_ACCESSOR(core_unit,	CORE_UNIT,	int);
-BHND_ACCESSOR(pmu_info,		PMU_INFO,	struct bhnd_core_pmu_info *);
+BHND_ACCESSOR(pmu_info,		PMU_INFO,	void *);
 
 #undef	BHND_ACCESSOR
 
@@ -859,67 +857,6 @@ bhnd_suspend_hw(device_t dev)
 }
 
 /**
- * If supported by the chipset, return the clock source for the given clock.
- *
- * This function is only supported on early PWRCTL-equipped chipsets
- * that expose clock management via their host bridge interface. Currently,
- * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
- *
- * @param dev A bhnd bus child device.
- * @param clock The clock for which a clock source will be returned.
- *
- * @retval	bhnd_clksrc		The clock source for @p clock.
- * @retval	BHND_CLKSRC_UNKNOWN	If @p clock is unsupported, or its
- *					clock source is not known to the bus.
- */
-static inline bhnd_clksrc
-bhnd_pwrctl_get_clksrc(device_t dev, bhnd_clock clock)
-{
-	return (BHND_BUS_PWRCTL_GET_CLKSRC(device_get_parent(dev), dev, clock));
-}
-
-/**
- * If supported by the chipset, gate @p clock
- *
- * This function is only supported on early PWRCTL-equipped chipsets
- * that expose clock management via their host bridge interface. Currently,
- * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
- *
- * @param dev A bhnd bus child device.
- * @param clock The clock to be disabled.
- *
- * @retval 0 success
- * @retval ENODEV If bus-level clock source management is not supported.
- * @retval ENXIO If bus-level management of @p clock is not supported.
- */
-static inline int
-bhnd_pwrctl_gate_clock(device_t dev, bhnd_clock clock)
-{
-	return (BHND_BUS_PWRCTL_GATE_CLOCK(device_get_parent(dev), dev, clock));
-}
-
-/**
- * If supported by the chipset, ungate @p clock
- *
- * This function is only supported on early PWRCTL-equipped chipsets
- * that expose clock management via their host bridge interface. Currently,
- * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
- *
- * @param dev A bhnd bus child device.
- * @param clock The clock to be enabled.
- *
- * @retval 0 success
- * @retval ENODEV If bus-level clock source management is not supported.
- * @retval ENXIO If bus-level management of @p clock is not supported.
- */
-static inline int
-bhnd_pwrctl_ungate_clock(device_t dev, bhnd_clock clock)
-{
-	return (BHND_BUS_PWRCTL_UNGATE_CLOCK(device_get_parent(dev), dev,
-	    clock));
-}
-
-/**
  * Return the BHND attachment type of the parent bhnd bus.
  *
  * @param dev A bhnd bus child device.
@@ -1066,8 +1003,7 @@ bhnd_unmap_intr(device_t dev, rman_res_t irq)
  * calling bhnd_alloc_pmu(), and must not be released until after
  * calling bhnd_release_pmu().
  *
- * @param dev The parent of @p child.
- * @param child The requesting bhnd device.
+ * @param dev The requesting bhnd device.
  * 
  * @retval 0           success
  * @retval non-zero    If allocating PMU request state otherwise fails, a
@@ -1083,8 +1019,7 @@ bhnd_alloc_pmu(device_t dev)
  * Release any per-core PMU resources allocated for @p child. Any outstanding
  * PMU requests are are discarded.
  *
- * @param dev The parent of @p child.
- * @param child The requesting bhnd device.
+ * @param dev The requesting bhnd device.
  * 
  * @retval 0           success
  * @retval non-zero    If releasing PMU request state otherwise fails, a
@@ -1095,6 +1030,51 @@ static inline int
 bhnd_release_pmu(device_t dev)
 {
 	return (BHND_BUS_RELEASE_PMU(device_get_parent(dev), dev));
+}
+
+/**
+ * Return the transition latency required for @p clock in microseconds, if
+ * known.
+ *
+ * The BHND_CLOCK_HT latency value is suitable for use as the D11 core's
+ * 'fastpwrup_dly' value. 
+ *
+ * @note A driver must ask the bhnd bus to allocate PMU request state
+ * via BHND_BUS_ALLOC_PMU() before querying PMU clocks.
+ *
+ * @param dev The requesting bhnd device.
+ * @param clock	The clock to be queried for transition latency.
+ * @param[out] latency On success, the transition latency of @p clock in
+ * microseconds.
+ * 
+ * @retval 0		success
+ * @retval ENODEV	If the transition latency for @p clock is not available.
+ */
+static inline int
+bhnd_get_clock_latency(device_t dev, bhnd_clock clock, u_int *latency)
+{
+	return (BHND_BUS_GET_CLOCK_LATENCY(device_get_parent(dev), dev, clock,
+	    latency));
+}
+
+/**
+ * Return the frequency for @p clock in Hz, if known.
+ *
+ * @param dev The requesting bhnd device.
+ * @param clock The clock to be queried.
+ * @param[out] freq On success, the frequency of @p clock in Hz.
+ *
+ * @note A driver must ask the bhnd bus to allocate PMU request state
+ * via BHND_BUS_ALLOC_PMU() before querying PMU clocks.
+ * 
+ * @retval 0		success
+ * @retval ENODEV	If the frequency for @p clock is not available.
+ */
+static inline int
+bhnd_get_clock_freq(device_t dev, bhnd_clock clock, u_int *freq)
+{
+	return (BHND_BUS_GET_CLOCK_FREQ(device_get_parent(dev), dev, clock,
+	    freq));
 }
 
 /** 

Modified: head/sys/dev/bhnd/bhnd_bus_if.m
==============================================================================
--- head/sys/dev/bhnd/bhnd_bus_if.m	Wed Nov 22 19:58:29 2017	(r326101)
+++ head/sys/dev/bhnd/bhnd_bus_if.m	Wed Nov 22 20:27:46 2017	(r326102)
@@ -114,28 +114,7 @@ CODE {
 		panic("bhnd_bus_get_attach_type unimplemented");
 	}
 
-	static bhnd_clksrc
-	bhnd_bus_null_pwrctl_get_clksrc(device_t dev, device_t child,
-	    bhnd_clock clock)
-	{
-		return (BHND_CLKSRC_UNKNOWN);
-	}
-
 	static int
-	bhnd_bus_null_pwrctl_gate_clock(device_t dev, device_t child,
-	    bhnd_clock clock)
-	{
-		return (ENODEV);
-	}
-
-	static int
-	bhnd_bus_null_pwrctl_ungate_clock(device_t dev, device_t child,
-	    bhnd_clock clock)
-	{
-		return (ENODEV);
-	}
-
-	static int
 	bhnd_bus_null_read_board_info(device_t dev, device_t child,
 	    struct bhnd_board_info *info)
 	{
@@ -160,6 +139,20 @@ CODE {
 	}
 
 	static int
+	bhnd_bus_null_get_clock_latency(device_t dev, device_t child,
+	    bhnd_clock clock, u_int *latency)
+	{
+		panic("bhnd_pmu_get_clock_latency unimplemented");
+	}
+
+	static int
+	bhnd_bus_null_get_clock_freq(device_t dev, device_t child,
+	    bhnd_clock clock, u_int *freq)
+	{
+		panic("bhnd_pmu_get_clock_freq unimplemented");
+	}
+
+	static int
 	bhnd_bus_null_request_clock(device_t dev, device_t child,
 	    bhnd_clock clock)
 	{
@@ -671,95 +664,83 @@ METHOD int suspend_hw {
 } DEFAULT bhnd_bus_null_suspend_hw;
 
 /**
- * If supported by the chipset, return the clock source for the given clock.
+ * Allocate per-core PMU resources and enable PMU request handling for @p child.
  *
- * This function is only supported on early PWRCTL-equipped chipsets
- * that expose clock management via their host bridge interface. Currently,
- * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
+ * The region containing the core's PMU register block (if any) must be
+ * allocated via bus_alloc_resource(9) (or bhnd_alloc_resource) before
+ * calling BHND_BUS_ALLOC_PMU(), and must not be released until after
+ * calling BHND_BUS_RELEASE_PMU().
  *
  * @param dev The parent of @p child.
- * @param child The bhnd device requesting a clock source.
- * @param clock The clock for which a clock source will be returned.
+ * @param child The requesting bhnd device.
  *
- * @retval	bhnd_clksrc		The clock source for @p clock.
- * @retval	BHND_CLKSRC_UNKNOWN	If @p clock is unsupported, or its
- *					clock source is not known to the bus.
+ * @retval 0		success
+ * @retval non-zero	if enabling per-core PMU request handling fails, a
+ *			regular unix error code will be returned.
  */
-METHOD bhnd_clksrc pwrctl_get_clksrc {
+METHOD int alloc_pmu {
 	device_t dev;
 	device_t child;
-	bhnd_clock clock;
-} DEFAULT bhnd_bus_null_pwrctl_get_clksrc;
+} DEFAULT bhnd_bus_null_alloc_pmu;
 
 /**
- * If supported by the chipset, gate the clock source for @p clock
+ * Release per-core PMU resources allocated for @p child. Any
+ * outstanding PMU requests are discarded.
  *
- * This function is only supported on early PWRCTL-equipped chipsets
- * that expose clock management via their host bridge interface. Currently,
- * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
- *
  * @param dev The parent of @p child.
- * @param child The bhnd device requesting clock gating.
- * @param clock The clock to be disabled.
- *
- * @retval 0 success
- * @retval ENODEV If bus-level clock source management is not supported.
- * @retval ENXIO If bus-level management of @p clock is not supported.
+ * @param child The requesting bhnd device.
  */
-METHOD int pwrctl_gate_clock {
+METHOD int release_pmu {
 	device_t dev;
 	device_t child;
-	bhnd_clock clock;
-} DEFAULT bhnd_bus_null_pwrctl_gate_clock;
+} DEFAULT bhnd_bus_null_release_pmu;
 
 /**
- * If supported by the chipset, ungate the clock source for @p clock
+ * Return the transition latency required for @p clock in microseconds, if
+ * known.
  *
- * This function is only supported on early PWRCTL-equipped chipsets
- * that expose clock management via their host bridge interface. Currently,
- * this includes PCI (not PCIe) devices, with ChipCommon core revisions 0-9.
+ * The BHND_CLOCK_HT latency value is suitable for use as the D11 core's
+ * 'fastpwrup_dly' value. 
  *
- * @param dev The parent of @p child.
- * @param child The bhnd device requesting clock gating.
- * @param clock The clock to be enabled.
+ * @note A driver must ask the bhnd bus to allocate PMU request state
+ * via BHND_BUS_ALLOC_PMU() before querying PMU clocks.
  *
- * @retval 0 success
- * @retval ENODEV If bus-level clock source management is not supported.
- * @retval ENXIO If bus-level management of @p clock is not supported.
- */
-METHOD int pwrctl_ungate_clock {
-	device_t dev;
-	device_t child;
-	bhnd_clock clock;
-} DEFAULT bhnd_bus_null_pwrctl_ungate_clock;
-
-/**
- * Allocate and enable per-core PMU request handling for @p child.
- *
- * The region containing the core's PMU register block (if any) must be
- * allocated via bus_alloc_resource(9) (or bhnd_alloc_resource) before
- * calling BHND_BUS_ALLOC_PMU(), and must not be released until after
- * calling BHND_BUS_RELEASE_PMU().
- *
  * @param dev The parent of @p child.
  * @param child The requesting bhnd device.
+ * @param clock	The clock to be queried for transition latency.
+ * @param[out] latency On success, the transition latency of @p clock in
+ * microseconds.
+ * 
+ * @retval 0		success
+ * @retval ENODEV	If the transition latency for @p clock is not available.
  */
-METHOD int alloc_pmu {
+METHOD int get_clock_latency {
 	device_t dev;
 	device_t child;
-} DEFAULT bhnd_bus_null_alloc_pmu;
+	bhnd_clock clock;
+	u_int *latency;
+} DEFAULT bhnd_bus_null_get_clock_latency;
 
 /**
- * Release per-core PMU resources allocated for @p child. Any
- * outstanding PMU requests are discarded.
+ * Return the frequency for @p clock in Hz, if known.
  *
  * @param dev The parent of @p child.
  * @param child The requesting bhnd device.
+ * @param clock The clock to be queried.
+ * @param[out] freq On success, the frequency of @p clock in Hz.
+ *
+ * @note A driver must ask the bhnd bus to allocate PMU request state
+ * via BHND_BUS_ALLOC_PMU() before querying PMU clocks.
+ * 
+ * @retval 0		success
+ * @retval ENODEV	If the frequency for @p clock is not available.
  */
-METHOD int release_pmu {
+METHOD int get_clock_freq {
 	device_t dev;
 	device_t child;
-} DEFAULT bhnd_bus_null_release_pmu;
+	bhnd_clock clock;
+	u_int *freq;
+} DEFAULT bhnd_bus_null_get_clock_freq;
 
 /** 
  * Request that @p clock (or faster) be routed to @p child.
@@ -772,11 +753,13 @@ METHOD int release_pmu {
  *
  * @param dev The parent of @p child.
  * @param child The bhnd device requesting @p clock.
- * @param clock The requested clock source. 
+ * @param clock The requested clock source.
  *
- * @retval 0 success
- * @retval ENODEV If an unsupported clock was requested.
- * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
+ * @retval 0		success
+ * @retval ENODEV	If an unsupported clock was requested.
+ * @retval ETIMEDOUT	If the clock request succeeds, but the clock is not
+ *			detected as ready within the PMU's maximum transition
+ *			delay. This should not occur in normal operation.
  */
 METHOD int request_clock {
 	device_t dev;
@@ -801,9 +784,11 @@ METHOD int request_clock {
  * @param child The bhnd device requesting @p clock.
  * @param clock The requested clock source.
  *
- * @retval 0 success
- * @retval ENODEV If an unsupported clock was requested.
- * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
+ * @retval 0		success
+ * @retval ENODEV	If an unsupported clock was requested.
+ * @retval ETIMEDOUT	If the clock request succeeds, but the clock is not
+ *			detected as ready within the PMU's maximum transition
+ *			delay. This should not occur in normal operation.
  */
 METHOD int enable_clocks {
 	device_t dev;
@@ -824,9 +809,11 @@ METHOD int enable_clocks {
  * @param child The bhnd device requesting @p rsrc.
  * @param rsrc The core-specific external resource identifier.
  *
- * @retval 0 success
- * @retval ENODEV If the PMU does not support @p rsrc.
- * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
+ * @retval 0		success
+ * @retval ENODEV	If the PMU does not support @p rsrc.
+ * @retval ETIMEDOUT	If the clock request succeeds, but the clock is not
+ *			detected as ready within the PMU's maximum transition
+ *			delay. This should not occur in normal operation.
  */
 METHOD int request_ext_rsrc {
 	device_t dev;
@@ -844,9 +831,11 @@ METHOD int request_ext_rsrc {
  * @param child The bhnd device requesting @p rsrc.
  * @param rsrc The core-specific external resource number.
  *
- * @retval 0 success
- * @retval ENODEV If the PMU does not support @p rsrc.
- * @retval ENXIO If the PMU has not been initialized or is otherwise unvailable.
+ * @retval 0		success
+ * @retval ENODEV	If the PMU does not support @p rsrc.
+ * @retval ETIMEDOUT	If the clock request succeeds, but the clock is not
+ *			detected as ready within the PMU's maximum transition
+ *			delay. This should not occur in normal operation.
  */
 METHOD int release_ext_rsrc {
 	device_t dev;

Modified: head/sys/dev/bhnd/bhnd_private.h
==============================================================================
--- head/sys/dev/bhnd/bhnd_private.h	Wed Nov 22 19:58:29 2017	(r326101)
+++ head/sys/dev/bhnd/bhnd_private.h	Wed Nov 22 20:27:46 2017	(r326102)
@@ -54,4 +54,49 @@ struct bhnd_service_entry {
 	STAILQ_ENTRY(bhnd_service_entry) link;
 };
 
+/**
+ * bhnd(4) per-core PMU clkctl quirks.
+ */
+enum {
+	/** On BCM4328-derived chipsets, the CLK_CTL_ST register CCS_HTAVAIL
+	 *  and CCS_ALPAVAIL bits are swapped in the ChipCommon and PCMCIA
+	 *  cores; the BHND_CCS0_* constants should be used. */
+	BHND_CLKCTL_QUIRK_CCS0	= 1
+};
+
+/**
+ * Per-core bhnd(4) PMU clkctl registers.
+ */
+struct bhnd_core_clkctl {
+	device_t		 cc_dev;		/**< core device */
+	device_t		 cc_pmu_dev;		/**< pmu device */
+	uint32_t		 cc_quirks;		/**< core-specific clkctl quirks */
+	struct bhnd_resource	*cc_res;		/**< resource mapping core's clkctl register */
+	bus_size_t		 cc_res_offset;		/**< offset to clkctl register */
+	u_int			 cc_max_latency;	/**< maximum PMU transition latency, in microseconds */
+	struct mtx		 cc_mtx;		/**< register read/modify/write lock */
+};
+
+#define	BHND_ASSERT_CLKCTL_AVAIL(_clkctl)			\
+	KASSERT(!bhnd_is_hw_suspended((_clkctl)->cc_dev),	\
+	    ("reading clkctl on suspended core will trigger system livelock"))
+
+#define	BHND_CLKCTL_LOCK_INIT(_clkctl)		mtx_init(&(_clkctl)->cc_mtx, \
+    device_get_nameunit((_clkctl)->cc_dev), NULL, MTX_DEF)
+#define	BHND_CLKCTL_LOCK(_clkctl)		mtx_lock(&(_clkctl)->cc_mtx)
+#define	BHND_CLKCTL_UNLOCK(_clkctl)		mtx_unlock(&(_clkctl)->cc_mtx)
+#define	BHND_CLKCTL_LOCK_ASSERT(_clkctl, what)	\
+    mtx_assert(&(_clkctl)->cc_mtx, what)
+#define	BHND_CLKCTL_LOCK_DESTROY(_clkctl)	mtx_destroy(&(_clkctl->cc_mtx))
+
+#define	BHND_CLKCTL_READ_4(_clkctl)		\
+	bhnd_bus_read_4((_clkctl)->cc_res, (_clkctl)->cc_res_offset)
+
+#define	BHND_CLKCTL_WRITE_4(_clkctl, _val)	\
+	bhnd_bus_write_4((_clkctl)->cc_res, (_clkctl)->cc_res_offset, (_val))
+	
+#define	BHND_CLKCTL_SET_4(_clkctl, _val, _mask)	\
+	BHND_CLKCTL_WRITE_4((_clkctl),		\
+	    ((_val) & (_mask)) | (BHND_CLKCTL_READ_4(_clkctl) & ~(_mask)))
+
 #endif /* _BHND_BHND_PRIVATE_H_ */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list