[PATCH V2 1/5] ARM: exynos4: Add support for AFTR mode cpuidle state
Amit Kachhap
amit.kachhap at linaro.org
Fri Nov 11 06:12:31 EST 2011
On 11 November 2011 15:47, Lorenzo Pieralisi <lorenzo.pieralisi at arm.com> wrote:
> Hi Amit,
>
> On Fri, Nov 11, 2011 at 06:29:33AM +0000, Amit Daniel Kachhap wrote:
>> This patch adds support for AFTR(ARM OFF TOP RUNNING) mode in
>> cpuidle driver for EXYNOS4210. L2 cache keeps their data in this mode.
>> This patch adds the code to the latest interfaces to
>> save/restore CPU state inclusive of CPU PM notifiers, l2
>> resume and cpu_suspend/resume.
>>
>> Signed-off-by: Jaecheol Lee <jc.lee at samsung.com>
>> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi at arm.com>
>> Signed-off-by: Amit Daniel Kachhap <amit.kachhap at linaro.org>
>> ---
>> arch/arm/mach-exynos/cpuidle.c | 148 ++++++++++++++++++++++++++++++-
>> arch/arm/mach-exynos/include/mach/pmu.h | 2 +
>> 2 files changed, 146 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c
>> index c6485d3..857ccc6 100644
>> --- a/arch/arm/mach-exynos/cpuidle.c
>> +++ b/arch/arm/mach-exynos/cpuidle.c
>> @@ -12,13 +12,31 @@
>> #include <linux/module.h>
>> #include <linux/init.h>
>> #include <linux/cpuidle.h>
>> +#include <linux/cpu_pm.h>
>
> Included but not used, why ? Is GIC state kept in AFTR ? Even if it
> is, VFP state is certainly gone, so you must call the notifiers anyway.
>
>> #include <linux/io.h>
>> -
>> +#include <linux/suspend.h>
>> +#include <linux/err.h>
>> #include <asm/proc-fns.h>
>> +#include <asm/smp_scu.h>
>> +#include <asm/suspend.h>
>> +#include <asm/unified.h>
>> +#include <mach/regs-pmu.h>
>> +#include <mach/pmu.h>
>> +
>> +#include <plat/exynos4.h>
>> +#include <plat/cpu.h>
>> +
>> +#define REG_DIRECTGO_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \
>> + S5P_INFORM7 : (S5P_VA_SYSRAM + 0x24))
>> +#define REG_DIRECTGO_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \
>> + S5P_INFORM6 : (S5P_VA_SYSRAM + 0x20))
>>
>> static int exynos4_enter_idle(struct cpuidle_device *dev,
>> struct cpuidle_driver *drv,
>> int index);
>> +static int exynos4_enter_lowpower(struct cpuidle_device *dev,
>> + struct cpuidle_driver *drv,
>> + int index);
>>
>> static struct cpuidle_state exynos4_cpuidle_set[] = {
>> [0] = {
>> @@ -26,9 +44,17 @@ static struct cpuidle_state exynos4_cpuidle_set[] = {
>> .exit_latency = 1,
>> .target_residency = 100000,
>> .flags = CPUIDLE_FLAG_TIME_VALID,
>> - .name = "IDLE",
>> + .name = "C0",
>> .desc = "ARM clock gating(WFI)",
>> },
>> + [1] = {
>> + .enter = exynos4_enter_lowpower,
>> + .exit_latency = 300,
>> + .target_residency = 100000,
>> + .flags = CPUIDLE_FLAG_TIME_VALID,
>> + .name = "C1",
>> + .desc = "ARM power down",
>> + },
>> };
>>
>> static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
>> @@ -38,9 +64,95 @@ static struct cpuidle_driver exynos4_idle_driver = {
>> .owner = THIS_MODULE,
>> };
>>
>> +/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
>> +static void exynos4_set_wakeupmask(void)
>> +{
>> + __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK);
>> +}
>> +
>> +static unsigned int g_pwr_ctrl, g_diag_reg;
>> +
>> +static void save_cpu_arch_register(void)
>> +{
>> + /*read power control register*/
>> + asm("mrc p15, 0, %0, c15, c0, 0" : "=r"(g_pwr_ctrl) : : "cc");
>> + /*read diagnostic register*/
>> + asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
>> + return;
>> +}
>> +
>> +static void restore_cpu_arch_register(void)
>> +{
>> + /*write power control register*/
>> + asm("mcr p15, 0, %0, c15, c0, 0" : : "r"(g_pwr_ctrl) : "cc");
>> + /*write diagnostic register*/
>> + asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
>> + return;
>> +}
>> +
>> +static int idle_finisher(unsigned long flags)
>> +{
>> + cpu_do_idle();
>> + return 1;
>> +}
>> +
>> +static int exynos4_enter_core0_aftr(struct cpuidle_device *dev,
>> + struct cpuidle_driver *drv,
>> + int index)
>> +{
>> + struct timeval before, after;
>> + int idle_time;
>> + unsigned long tmp;
>> +
>> + local_irq_disable();
>> + do_gettimeofday(&before);
>> +
>> + exynos4_set_wakeupmask();
>> +
>> + /* Set value of power down register for aftr mode */
>> + exynos4_sys_powerdown_conf(SYS_AFTR);
>> +
>> + save_cpu_arch_register();
>> +
>
> You must call the notifiers here, at least cpu_pm_enter();
Yes lorenzo, cpu_pm_enter may be needed although it does GIC_CPU
save/restore which may not be needed.
Thanks for the review.
>
>> + /* Setting Central Sequence Register for power down mode */
>> + tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
>> + tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
>> + __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
>> +
>> + cpu_suspend(0, idle_finisher);
>> +
>> + scu_enable(S5P_VA_SCU);
>> +
>
> Again, you need to resume (VFP, if GIC is kept) through notifiers here,
> I do not understand why that code has been removed.
>
> Lorenzo
>
>
More information about the linux-arm-kernel
mailing list