Re: [PATCHv6 6/9] OMAP: Powerdomains: Add support for checking if pwrdm/clkdm can idle

2010-03-01 Thread Kevin Hilman
Tero Kristo tero.kri...@nokia.com writes:

 From: Tero Kristo tero.kri...@nokia.com

 pwrdm_can_idle(pwrdm) will check if the specified powerdomain can enter
 idle. This is done by checking all clockdomains under the powerdomain
 if they can idle also.

 omap2_clkdm_can_idle(clkdm) will check if the specified clockdomain can
 enter idle. This checks the functional clocks and idle status bits of the
 domain according to following rules:
 1) functional clock check
   * get FCLK register content
   * ignore all clocks defined in idle_def.fclk_ignore
   * if any active functional clocks remain, domain can't idle
 2) idle status check
   * get IDLEST register content
   * inverse it (any non-idle blocks are now as 1)
   * mask against idle_def.idlest_mask
   * if any bits remain high, domain can't idle

 These calls can be used e.g. inside cpuidle to decide which power states
 core and mpu should enter during idle, as there are certain dependencies
 between wakeup capabilities and reset logic.

 Signed-off-by: Tero Kristo tero.kri...@nokia.com

I'm OK with this version.  

Paul?

Kevin


 ---
  arch/arm/mach-omap2/clockdomain.c |   32 
  arch/arm/mach-omap2/clockdomains.h|  106 
 +
  arch/arm/mach-omap2/powerdomain.c |   20 +
  arch/arm/plat-omap/include/plat/clockdomain.h |   17 
  arch/arm/plat-omap/include/plat/powerdomain.h |1 +
  5 files changed, 176 insertions(+), 0 deletions(-)

 diff --git a/arch/arm/mach-omap2/clockdomain.c 
 b/arch/arm/mach-omap2/clockdomain.c
 index a38a615..9ebff51 100644
 --- a/arch/arm/mach-omap2/clockdomain.c
 +++ b/arch/arm/mach-omap2/clockdomain.c
 @@ -867,6 +867,38 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm)
   return 0;
  }
  
 +
 +/**
 + * omap2_clkdm_can_idle - check if clockdomain has any active clocks or not
 + * @clkdm: struct clockdomain *
 + *
 + * Checks if the clockdomain has any active clock or not, i.e. whether it
 + * can enter idle. Returns -EINVAL if clkdm is NULL; 0 if unable to idle;
 + * 1 if can idle.
 + */
 +int omap2_clkdm_can_idle(struct clockdomain *clkdm)
 +{
 + int i;
 +
 + if (!clkdm)
 + return -EINVAL;
 +
 + for (i = 0; i  clkdm-clk_reg_num; i++) {
 + u32 idlest, fclk;
 +
 + fclk = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs,
 + CM_FCLKEN + 4 * i);
 + if (fclk  ~clkdm-idle_def[i].fclk_ignore)
 + return 0;
 +
 + idlest = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs,
 + CM_IDLEST + 4 * i);
 + if (~idlest  clkdm-idle_def[i].idlest_mask)
 + return 0;
 + }
 + return 1;
 +}
 +
  /**
   * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm
   * @clkdm: struct clockdomain *
 diff --git a/arch/arm/mach-omap2/clockdomains.h 
 b/arch/arm/mach-omap2/clockdomains.h
 index 8fc19ff..5e29de8 100644
 --- a/arch/arm/mach-omap2/clockdomains.h
 +++ b/arch/arm/mach-omap2/clockdomains.h
 @@ -663,6 +663,12 @@ static struct clockdomain iva2_clkdm = {
   .wkdep_srcs = iva2_wkdeps,
   .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK,
   .omap_chip  = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 + .clk_reg_num= 1,
 + .idle_def   = {
 + [0] = {
 + .idlest_mask = OMAP3430_ST_IVA2,
 + },
 + },
  };
  
  static struct clockdomain gfx_3430es1_clkdm = {
 @@ -686,6 +692,12 @@ static struct clockdomain sgx_clkdm = {
   .sleepdep_srcs  = gfx_sgx_sleepdeps,
   .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK,
   .omap_chip  = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
 + .clk_reg_num= 1,
 + .idle_def   = {
 + [0] = {
 + .idlest_mask = OMAP3430ES2_ST_SGX_SHIFT,
 + },
 + },
  };
  
  /*
 @@ -717,6 +729,57 @@ static struct clockdomain core_l3_3xxx_clkdm = {
   .dep_bit= OMAP3430_EN_CORE_SHIFT,
   .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK,
   .omap_chip  = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 + .clk_reg_num= 3,
 + .idle_def   = {
 + [0] = {
 + /* UARTs are controlled by idle loop so ignore */
 + .fclk_ignore = OMAP3430_EN_UART2 |
 + OMAP3430_EN_UART1,
 + /*
 +  * Reason for IDLEST ignores:
 +  * - SDRC and OMAPCTRL controlled by HW
 +  * - HSOTGUSB_IDLE bit is autoidled by HW
 +  * - MAILBOX is controlled by HW
 +  */
 + .idlest_mask =
 + OMAP3430ES2_ST_MMC3_MASK |
 + OMAP3430_ST_ICR_MASK |
 + OMAP3430_ST_AES2_MASK |
 + OMAP3430_ST_SHA12_MASK |
 + OMAP3430_ST_DES2_MASK 

[PATCHv6 6/9] OMAP: Powerdomains: Add support for checking if pwrdm/clkdm can idle

2010-02-12 Thread Tero Kristo
From: Tero Kristo tero.kri...@nokia.com

pwrdm_can_idle(pwrdm) will check if the specified powerdomain can enter
idle. This is done by checking all clockdomains under the powerdomain
if they can idle also.

omap2_clkdm_can_idle(clkdm) will check if the specified clockdomain can
enter idle. This checks the functional clocks and idle status bits of the
domain according to following rules:
1) functional clock check
  * get FCLK register content
  * ignore all clocks defined in idle_def.fclk_ignore
  * if any active functional clocks remain, domain can't idle
2) idle status check
  * get IDLEST register content
  * inverse it (any non-idle blocks are now as 1)
  * mask against idle_def.idlest_mask
  * if any bits remain high, domain can't idle

These calls can be used e.g. inside cpuidle to decide which power states
core and mpu should enter during idle, as there are certain dependencies
between wakeup capabilities and reset logic.

Signed-off-by: Tero Kristo tero.kri...@nokia.com
---
 arch/arm/mach-omap2/clockdomain.c |   32 
 arch/arm/mach-omap2/clockdomains.h|  106 +
 arch/arm/mach-omap2/powerdomain.c |   20 +
 arch/arm/plat-omap/include/plat/clockdomain.h |   17 
 arch/arm/plat-omap/include/plat/powerdomain.h |1 +
 5 files changed, 176 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/clockdomain.c 
b/arch/arm/mach-omap2/clockdomain.c
index a38a615..9ebff51 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -867,6 +867,38 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm)
return 0;
 }
 
+
+/**
+ * omap2_clkdm_can_idle - check if clockdomain has any active clocks or not
+ * @clkdm: struct clockdomain *
+ *
+ * Checks if the clockdomain has any active clock or not, i.e. whether it
+ * can enter idle. Returns -EINVAL if clkdm is NULL; 0 if unable to idle;
+ * 1 if can idle.
+ */
+int omap2_clkdm_can_idle(struct clockdomain *clkdm)
+{
+   int i;
+
+   if (!clkdm)
+   return -EINVAL;
+
+   for (i = 0; i  clkdm-clk_reg_num; i++) {
+   u32 idlest, fclk;
+
+   fclk = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs,
+   CM_FCLKEN + 4 * i);
+   if (fclk  ~clkdm-idle_def[i].fclk_ignore)
+   return 0;
+
+   idlest = cm_read_mod_reg(clkdm-pwrdm.ptr-prcm_offs,
+   CM_IDLEST + 4 * i);
+   if (~idlest  clkdm-idle_def[i].idlest_mask)
+   return 0;
+   }
+   return 1;
+}
+
 /**
  * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm
  * @clkdm: struct clockdomain *
diff --git a/arch/arm/mach-omap2/clockdomains.h 
b/arch/arm/mach-omap2/clockdomains.h
index 8fc19ff..5e29de8 100644
--- a/arch/arm/mach-omap2/clockdomains.h
+++ b/arch/arm/mach-omap2/clockdomains.h
@@ -663,6 +663,12 @@ static struct clockdomain iva2_clkdm = {
.wkdep_srcs = iva2_wkdeps,
.clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK,
.omap_chip  = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+   .clk_reg_num= 1,
+   .idle_def   = {
+   [0] = {
+   .idlest_mask = OMAP3430_ST_IVA2,
+   },
+   },
 };
 
 static struct clockdomain gfx_3430es1_clkdm = {
@@ -686,6 +692,12 @@ static struct clockdomain sgx_clkdm = {
.sleepdep_srcs  = gfx_sgx_sleepdeps,
.clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK,
.omap_chip  = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
+   .clk_reg_num= 1,
+   .idle_def   = {
+   [0] = {
+   .idlest_mask = OMAP3430ES2_ST_SGX_SHIFT,
+   },
+   },
 };
 
 /*
@@ -717,6 +729,57 @@ static struct clockdomain core_l3_3xxx_clkdm = {
.dep_bit= OMAP3430_EN_CORE_SHIFT,
.clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK,
.omap_chip  = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+   .clk_reg_num= 3,
+   .idle_def   = {
+   [0] = {
+   /* UARTs are controlled by idle loop so ignore */
+   .fclk_ignore = OMAP3430_EN_UART2 |
+   OMAP3430_EN_UART1,
+   /*
+* Reason for IDLEST ignores:
+* - SDRC and OMAPCTRL controlled by HW
+* - HSOTGUSB_IDLE bit is autoidled by HW
+* - MAILBOX is controlled by HW
+*/
+   .idlest_mask =
+   OMAP3430ES2_ST_MMC3_MASK |
+   OMAP3430_ST_ICR_MASK |
+   OMAP3430_ST_AES2_MASK |
+   OMAP3430_ST_SHA12_MASK |
+   OMAP3430_ST_DES2_MASK |
+   OMAP3430_ST_MMC2_MASK |
+