Re: [PATCH V3 1/6] ARM: exynos: Add AFTR mode cpuidle state on EXYNOS4210
On Thu, Nov 24, 2011 at 9:37 AM, Inderpal Singh wrote: > Hi Amit, > > On 22 November 2011 15:05, Amit Daniel Kachhap > wrote: >> >> This patch adds support AFTR(ARM OFF TOP RUNNING) mode in >> cpuidle driver. L2 cache keeps their data in this mode. >> This patch ports 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 >> Signed-off-by: Lorenzo Pieralisi >> Signed-off-by: Amit Daniel Kachhap >> --- >> arch/arm/mach-exynos/cpuidle.c | 152 >> ++- >> arch/arm/mach-exynos/include/mach/pmu.h | 2 + >> 2 files changed, 151 insertions(+), 3 deletions(-) >> >> diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c >> index 21403c8..89afa93 100644 >> --- a/arch/arm/mach-exynos/cpuidle.c >> +++ b/arch/arm/mach-exynos/cpuidle.c >> @@ -12,15 +12,37 @@ >> #include >> #include >> #include >> +#include >> #include >> #include >> #include >> >> #include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include >> + >> +#define REG_DIRECTGO_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ >> + S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? >> \ >> + (S5P_VA_SYSRAM + 0x24) : S5P_INFORM0)) >> +#define REG_DIRECTGO_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ >> + S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? >> \ >> + (S5P_VA_SYSRAM + 0x20) : S5P_INFORM1)) >> + >> +#define S5P_CHECK_AFTR (samsung_rev() == EXYNOS4210_REV_1_0 ? \ >> + 0xBAD0 : 0xFCBA0D10) >> >> 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] = { >> @@ -28,9 +50,17 @@ static struct cpuidle_state exynos4_cpuidle_set[] = { >> .exit_latency = 1, >> .target_residency = 10, >> .flags = CPUIDLE_FLAG_TIME_VALID, >> - .name = "IDLE", >> + .name = "C0", >> .desc = "ARM clock gating(WFI)", >> }, >> + [1] = { >> + .enter = exynos4_enter_lowpower, >> + .exit_latency = 300, >> + .target_residency = 10, >> + .flags = CPUIDLE_FLAG_TIME_VALID, >> + .name = "C1", >> + .desc = "ARM power down", >> + }, >> }; >> >> static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device); >> @@ -40,9 +70,101 @@ 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(0xff3e, 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); >> + >> + __raw_writel(BSYM(virt_to_phys(s3c_cpu_resume)), >> + REG_DIRECTGO_ADDR); >> + __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG); >> + >> + save_cpu_arch_register(); >> + >> + /* Setting Central Sequence Register for power down mod
Re: [PATCH V3 1/6] ARM: exynos: Add AFTR mode cpuidle state on EXYNOS4210
Hi Amit, On 22 November 2011 15:05, Amit Daniel Kachhap wrote: > > This patch adds support AFTR(ARM OFF TOP RUNNING) mode in > cpuidle driver. L2 cache keeps their data in this mode. > This patch ports 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 > Signed-off-by: Lorenzo Pieralisi > Signed-off-by: Amit Daniel Kachhap > --- > arch/arm/mach-exynos/cpuidle.c | 152 > ++- > arch/arm/mach-exynos/include/mach/pmu.h | 2 + > 2 files changed, 151 insertions(+), 3 deletions(-) > > diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c > index 21403c8..89afa93 100644 > --- a/arch/arm/mach-exynos/cpuidle.c > +++ b/arch/arm/mach-exynos/cpuidle.c > @@ -12,15 +12,37 @@ > #include > #include > #include > +#include > #include > #include > #include > > #include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > + > +#define REG_DIRECTGO_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ > + S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ > + (S5P_VA_SYSRAM + 0x24) : S5P_INFORM0)) > +#define REG_DIRECTGO_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ > + S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ > + (S5P_VA_SYSRAM + 0x20) : S5P_INFORM1)) > + > +#define S5P_CHECK_AFTR (samsung_rev() == EXYNOS4210_REV_1_0 ? \ > + 0xBAD0 : 0xFCBA0D10) > > 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] = { > @@ -28,9 +50,17 @@ static struct cpuidle_state exynos4_cpuidle_set[] = { > .exit_latency = 1, > .target_residency = 10, > .flags = CPUIDLE_FLAG_TIME_VALID, > - .name = "IDLE", > + .name = "C0", > .desc = "ARM clock gating(WFI)", > }, > + [1] = { > + .enter = exynos4_enter_lowpower, > + .exit_latency = 300, > + .target_residency = 10, > + .flags = CPUIDLE_FLAG_TIME_VALID, > + .name = "C1", > + .desc = "ARM power down", > + }, > }; > > static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device); > @@ -40,9 +70,101 @@ 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(0xff3e, 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); > + > + __raw_writel(BSYM(virt_to_phys(s3c_cpu_resume)), > + REG_DIRECTGO_ADDR); > + __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG); > + > + save_cpu_arch_register(); > + > + /* 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_pm_enter(); > + c