On Tue, Jan 25, 2011 at 12:16:56PM +0000, Russell King - ARM Linux wrote:
> On Tue, Jan 25, 2011 at 05:32:57PM +0530, Santosh Shilimkar wrote:
> > I have similar patch implemented but what it does is just
> > prepares the value to be programmed and stores it to a scratchpad.
> > I see your point but below patch may now work well. The reason is the SCU
> > register needs to accessed at the lowest level. May be even when
> > stack is not available. Also this register needs to be cleared in cases
> > where the attempted power state is failed for some reason.
> 
> >From the documentation I have, the power control register has no effect
> until the CPU enters WFI mode - which means that provided we can
> guarantee no one issues a WFI instruction between setting the power mode,
> and executing that instruction, being woken up (or failing) and resetting
> the power mode back... that shouldn't require the power mode to be
> programmed from assembly code.
> 
> In any case, we actually need the help of spinlocks to deal with
> concurrent access to the SCU power control register - something you
> can't do in assembly code.
> 
> On the way down to a WFI low power mode, we can call scu_power_mode(),
> do the rest of the cleanup (which must not schedule) and issue WFI.  On
> the way back up, do whatever needs to be done and call scu_power_mode()
> to reset back to 'normal' mode.
> 
> > Also note that this register can be blocked using trust-zone which
> > again makes it platform dependent because direct write won't be
> > allowed in that case.
> 
> Yes, I did notice.  What's the OMAP SMC interface for that?
> 
> > I would prefer the header export if there is no major
> > objection since there is already a possibility of custom
> > implementation with trust zone.
> > 
> > On OMAP4, on ES1.0 we need to use a secure API to achieve
> > this where as on ES2.0, it can be directly accessed.
> 
> As I say, I'd rather not have each SoC implementing access to this as
> someone's bound to forget the spinlock if they're dealing with more than
> one CPU, which'll make stuff unreliable (just like I did on my initial
> version.)
> 
> We could have a callback to SoC code which does the appropriate SMC call,
> but first I'll need to know what's required for the SMC call.

I did mean to include the updated patch:

 arch/arm/include/asm/smp_scu.h |    5 +++++
 arch/arm/kernel/smp_scu.c      |   23 +++++++++++++++++++++++
 2 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/arch/arm/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h
index 2376835..108f31d 100644
--- a/arch/arm/include/asm/smp_scu.h
+++ b/arch/arm/include/asm/smp_scu.h
@@ -1,7 +1,12 @@
 #ifndef __ASMARM_ARCH_SCU_H
 #define __ASMARM_ARCH_SCU_H
 
+#define SCU_PM_NORMAL  0
+#define SCU_PM_DORMANT 2
+#define SCU_PM_POWEROFF        3
+
 unsigned int scu_get_core_count(void __iomem *);
 void scu_enable(void __iomem *);
+int scu_power_mode(unsigned int);
 
 #endif
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index 9ab4149..4c4c90d 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -10,6 +10,7 @@
  */
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
 
 #include <asm/smp_scu.h>
 #include <asm/cacheflush.h>
@@ -20,6 +21,8 @@
 #define SCU_INVALIDATE         0x0c
 #define SCU_FPGA_REVISION      0x10
 
+static DEFINE_SPINLOCK(scu_power_lock);
+
 /*
  * Get the number of CPU cores from the SCU configuration
  */
@@ -50,3 +53,23 @@ void __init scu_enable(void __iomem *scu_base)
         */
        flush_cache_all();
 }
+
+int scu_power_mode(unsigned int mode)
+{
+       int cpu = smp_processor_id();
+       int shift;
+       u32 val;
+
+       if (mode > 3 || mode == 1 || cpu > 3)
+               return -EINVAL;
+
+       shift = cpu * 8;
+
+       spin_lock(&scu_power_lock);
+       val = raw_readl(scu_base + SCU_CPU_STATUS) & ~(0x03 << shift);
+       val |= mode << shift;
+       __raw_writel(val, scu_base + SCU_CPU_STATUS);
+       spin_unlock(&scu_power_lock);
+
+       return 0;
+}

If we need a SMC call, that should happen within the spinlock'd region via
a function pointer which the platform can set.  I can't code that into this
patch until I know what the SMC call requires as arguments (cpu number,
power state, or new register value, or mask and bits to set?)
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to