[PATCH V6 1/5] ARM: exynos: Add support AFTR mode on EXYNOS4210

Amit Kachhap amit.kachhap at linaro.org
Thu Feb 23 06:49:41 EST 2012


On 23 February 2012 11:54, Rob Lee <rob.lee at linaro.org> wrote:
>>  static struct cpuidle_state exynos4_cpuidle_set[] = {
>>        [0] = {
>> @@ -27,9 +47,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",
>> +       },
>>  };
>
> It looks like you could make this __initdata because your are copying
> this state data over to the cpuidle_driver object during
> initialization.
Hi Rob,

This is a good suggestion. I tested it and this works fine.

Hi Mr kim,

Can this change be accommodated in the current patch series as below
or should i send a new patchset?

--- a/arch/arm/mach-exynos/cpuidle.c
+++ b/arch/arm/mach-exynos/cpuidle.c
@@ -41,7 +41,7 @@ static int exynos4_enter_lowpower(struct cpuidle_device *dev,
                                struct cpuidle_driver *drv,
                                int index);

-static struct cpuidle_state exynos4_cpuidle_set[] = {
+static struct cpuidle_state exynos4_cpuidle_set[] __initdata = {
        [0] = {
                .enter                  = exynos4_enter_idle,
                .exit_latency           = 1,


Thanks,
Amit Daniel


>
>>
>>  static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
>> @@ -39,9 +67,100 @@ 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);
>> +
>> +       __raw_writel(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();
>> +       cpu_suspend(0, idle_finisher);
>> +
>> +       scu_enable(S5P_VA_SCU);
>> +       cpu_pm_exit();
>> +
>> +       restore_cpu_arch_register();
>> +
>> +       /*
>> +        * If PMU failed while entering sleep mode, WFI will be
>> +        * ignored by PMU and then exiting cpu_do_idle().
>> +        * S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically
>> +        * in this situation.
>> +        */
>> +       tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
>> +       if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) {
>> +               tmp |= S5P_CENTRAL_LOWPWR_CFG;
>> +               __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
>> +       }
>> +
>> +       /* Clear wakeup state register */
>> +       __raw_writel(0x0, S5P_WAKEUP_STAT);
>> +
>> +       do_gettimeofday(&after);
>> +
>> +       local_irq_enable();
>> +       idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
>> +                   (after.tv_usec - before.tv_usec);
>> +
>> +       dev->last_residency = idle_time;
>> +       return index;
>> +}
>> +
>>  static int exynos4_enter_idle(struct cpuidle_device *dev,
>>                                struct cpuidle_driver *drv,
>> -                             int index)
>> +                               int index)
>>  {
>>        struct timeval before, after;
>>        int idle_time;
>> @@ -60,6 +179,22 @@ static int exynos4_enter_idle(struct cpuidle_device *dev,
>>        return index;
>>  }
>>
>> +static int exynos4_enter_lowpower(struct cpuidle_device *dev,
>> +                               struct cpuidle_driver *drv,
>> +                               int index)
>> +{
>> +       int new_index = index;
>> +
>> +       /* This mode only can be entered when other core's are offline */
>> +       if (num_online_cpus() > 1)
>> +               new_index = drv->safe_state_index;
>> +
>> +       if (new_index == 0)
>> +               return exynos4_enter_idle(dev, drv, new_index);
>> +       else
>> +               return exynos4_enter_core0_aftr(dev, drv, new_index);
>> +}
>> +
>>  static int __init exynos4_init_cpuidle(void)
>>  {
>>        int i, max_cpuidle_state, cpu_id;
>> @@ -74,19 +209,25 @@ static int __init exynos4_init_cpuidle(void)
>>                memcpy(&drv->states[i], &exynos4_cpuidle_set[i],
>>                                sizeof(struct cpuidle_state));
>>        }
>> +       drv->safe_state_index = 0;
>>        cpuidle_register_driver(&exynos4_idle_driver);
>>
>>        for_each_cpu(cpu_id, cpu_online_mask) {
>>                device = &per_cpu(exynos4_cpuidle_device, cpu_id);
>>                device->cpu = cpu_id;
>>
>> -               device->state_count = drv->state_count;
>> +               if (cpu_id == 0)
>> +                       device->state_count = (sizeof(exynos4_cpuidle_set) /
>> +                                              sizeof(struct cpuidle_state));
>> +               else
>> +                       device->state_count = 1;        /* Support IDLE only */
>>
>>                if (cpuidle_register_device(device)) {
>>                        printk(KERN_ERR "CPUidle register device failed\n,");
>>                        return -EIO;
>>                }
>>        }
>> +
>>        return 0;
>>  }
>>  device_initcall(exynos4_init_cpuidle);
>> diff --git a/arch/arm/mach-exynos/include/mach/pmu.h b/arch/arm/mach-exynos/include/mach/pmu.h
>> index 632dd56..e76b7fa 100644
>> --- a/arch/arm/mach-exynos/include/mach/pmu.h
>> +++ b/arch/arm/mach-exynos/include/mach/pmu.h
>> @@ -22,11 +22,13 @@ enum sys_powerdown {
>>        NUM_SYS_POWERDOWN,
>>  };
>>
>> +extern unsigned long l2x0_regs_phys;
>>  struct exynos4_pmu_conf {
>>        void __iomem *reg;
>>        unsigned int val[NUM_SYS_POWERDOWN];
>>  };
>>
>>  extern void exynos4_sys_powerdown_conf(enum sys_powerdown mode);
>> +extern void s3c_cpu_resume(void);
>>
>>  #endif /* __ASM_ARCH_PMU_H */
>> --
>> 1.7.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



More information about the linux-arm-kernel mailing list