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 ***
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to