@@ -786,6 +786,7 @@ config ARCH_EXYNOS4
select CLKDEV_LOOKUP
select ARCH_HAS_CPUFREQ
select GENERIC_CLOCKEVENTS
+ select ARCH_USES_CPU_PM
select HAVE_S3C_RTC if RTC_CLASS
select HAVE_S3C2410_I2C if I2C
select HAVE_S3C2410_WATCHDOG if WATCHDOG
@@ -16,7 +16,7 @@ obj-$(CONFIG_CPU_EXYNOS4210) += cpu.o init.o clock.o irq-combiner.o
obj-$(CONFIG_CPU_EXYNOS4210) += setup-i2c0.o irq-eint.o dma.o pmu.o
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
-obj-$(CONFIG_CPU_IDLE) += cpuidle.o idle.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
@@ -13,16 +13,23 @@
#include <linux/cpuidle.h>
#include <linux/io.h>
#include <linux/suspend.h>
-
+#include <linux/slab.h>
+#include <linux/err.h>
#include <asm/proc-fns.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/cacheflush.h>
-
+#include <asm/unified.h>
+#include <asm/sr_platform_api.h>
#include <mach/regs-pmu.h>
#include <mach/pmu.h>
-#define REG_DIRECTGO_ADDR (S5P_VA_SYSRAM + 0x24)
-#define REG_DIRECTGO_FLAG (S5P_VA_SYSRAM + 0x20)
+#include <plat/exynos4.h>
+
+#define REG_DIRECTGO_ADDR (exynos4_subrev() == 0 ?\
+ (S5P_VA_SYSRAM + 0x24) : S5P_INFORM7)
+#define REG_DIRECTGO_FLAG (exynos4_subrev() == 0 ?\
+ (S5P_VA_SYSRAM + 0x20) : S5P_INFORM6)
+
static int exynos4_enter_idle(struct cpuidle_device *dev,
struct cpuidle_state *state);
@@ -56,29 +63,30 @@ static struct cpuidle_driver exynos4_idle_driver = {
.owner = THIS_MODULE,
};
-void exynos4_cpu_lp(void *stack_addr)
+/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
+static void exynos4_set_wakeupmask(void)
{
- /*
- * Refer to v7 cpu_suspend function.
- * From saveblk to stack_addr + (4 * 3) + (4 * 9)
- * 4byte * (v:p offset, virt sp, phy resume fn)
- * cpu_suspend_size = 4 * 9 (from proc-v7.S)
- * Min L2 cache clean size = 36 + 12 + 36 = 84
- */
-
- outer_clean_range(virt_to_phys(stack_addr), 84);
-
- /* To clean sleep_save_sp area */
+ __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK);
+}
- outer_clean_range(virt_to_phys(cpu_resume), 64);
+unsigned int g_pwr_ctrl, g_diag_reg;
- cpu_do_idle();
+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;
}
-/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
-static void exynos4_set_wakeupmask(void)
+static void restore_cpu_arch_register(void)
{
- __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK);
+ /*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 exynos4_enter_core0_aftr(struct cpuidle_device *dev,
@@ -93,18 +101,24 @@ static int exynos4_enter_core0_aftr(struct cpuidle_device *dev,
exynos4_set_wakeupmask();
- __raw_writel(virt_to_phys(exynos4_idle_resume), REG_DIRECTGO_ADDR);
+ __raw_writel(BSYM(virt_to_phys(arch_reset_handler())),
+ REG_DIRECTGO_ADDR);
__raw_writel(0xfcba0d10, REG_DIRECTGO_FLAG);
/* Set value of power down register for aftr mode */
exynos4_sys_powerdown_conf(SYS_AFTR);
+ 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);
- exynos4_enter_lp(0, PLAT_PHYS_OFFSET - PAGE_OFFSET);
+ /*cstate=SHUTDOWN, cluster=RETENTION, save=ALL*/
+ cpu_enter_idle(3, 2, SR_SAVE_ALL);
+
+ restore_cpu_arch_register();
/*
* If PMU failed while entering sleep mode, WFI will be
@@ -117,7 +131,6 @@ static int exynos4_enter_core0_aftr(struct cpuidle_device *dev,
tmp |= S5P_CENTRAL_LOWPWR_CFG;
__raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
}
- cpu_init();
/* Clear wakeup state register */
__raw_writel(0x0, S5P_WAKEUP_STAT);
@@ -139,7 +152,8 @@ static int exynos4_enter_idle(struct cpuidle_device *dev,
local_irq_disable();
do_gettimeofday(&before);
- cpu_do_idle();
+ /*cstate=STANDBY, cluster=RUN, save=no flags*/
+ cpu_enter_idle(1, 0, 0);
do_gettimeofday(&after);
local_irq_enable();
@@ -169,6 +183,17 @@ static int exynos4_enter_lowpower(struct cpuidle_device *dev,
return exynos4_enter_idle(dev, new_state);
}
+void *platform_context_pointer(unsigned int size)
+{
+ void *memory;
+ memory = kmalloc(size, GFP_KERNEL);
+ if (memory == NULL) {
+ printk(KERN_ERR "Memory size = %u not available", size);
+ return ERR_PTR(-ENOMEM);
+ }
+ return virt_to_phys(memory);
+}
+
static int __init exynos4_init_cpuidle(void)
{
int i, max_cpuidle_state, cpu_id;
@@ -200,16 +225,6 @@ static int __init exynos4_init_cpuidle(void)
return -EIO;
}
}
-
- l2cc_save[0] = __raw_readl(S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
- l2cc_save[1] = __raw_readl(S5P_VA_L2CC + L2X0_POWER_CTRL);
- l2cc_save[2] = __raw_readl(S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
- l2cc_save[3] = __raw_readl(S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
- l2cc_save[4] = __raw_readl(S5P_VA_L2CC + L2X0_AUX_CTRL);
-
- clean_dcache_area(&l2cc_save[0], 5 * sizeof(unsigned long));
- outer_clean_range(virt_to_phys(&l2cc_save[0]),
- virt_to_phys(&l2cc_save[4] + sizeof(unsigned long)));
return 0;
}
device_initcall(exynos4_init_cpuidle);
deleted file mode 100644
@@ -1,165 +0,0 @@
-/* linux/arch/arm/mach-exynos4/idle.S
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * EXYNOS4210 AFTR/LPA idle support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/linkage.h>
-
-#include <asm/assembler.h>
-#include <asm/memory.h>
-#include <asm/hardware/cache-l2x0.h>
-
-#include <mach/map.h>
-
- .text
-
- /*
- * exynos4_enter_lp
- *
- * entry:
- * r1 = v:p offset
- */
-
-ENTRY(exynos4_enter_lp)
- stmfd sp!, { r3 - r12, lr }
-
- adr r0, sleep_save_misc
-
- mrc p15, 0, r2, c15, c0, 0 @ read power control register
- str r2, [r0], #4
-
- mrc p15, 0, r2, c15, c0, 1 @ read diagnostic register
- str r2, [r0], #4
-
- ldr r3, =resume_with_mmu
- bl cpu_suspend
-
- mov r0, sp
- bl exynos4_cpu_lp
-
- /* Restore original sp */
- mov r0, sp
- add r0, r0, #4
- ldr sp, [r0]
-
- mov r0, #0
- b early_wakeup
-
-resume_with_mmu:
-
- adr r0, sleep_save_misc
-
- ldr r1, [r0], #4
- mcr p15, 0, r1, c15, c0, 0 @ write power control register
-
- ldr r1, [r0], #4
- mcr p15, 0, r1, c15, c0, 1 @ write diagnostic register
-
- mov r0, #1
-early_wakeup:
-
- ldmfd sp!, { r3 - r12, pc }
-
- .ltorg
-
- /*
- * sleep magic, to allow the bootloader to check for an valid
- * image to resume to. Must be the first word before the
- * s3c_cpu_resume entry.
- */
-
- .word 0x2bedf00d
-
-sleep_save_misc:
- .long 0
- .long 0
-
- /*
- * exynos4_idle_resume
- *
- * resume code entry for IROM to call
- *
- * we must put this code here in the data segment as we have no
- * other way of restoring the stack pointer after sleep, and we
- * must not write to the code segment (code is read-only)
- */
- .data
- .align
-ENTRY(exynos4_idle_resume)
- ldr r0, scu_pa_addr @ load physica address of SCU
- ldr r1, [r0]
- orr r1, r1, #1
- orr r1, r1, #(1 << 5)
- str r1, [r0] @ enable SCU
-
- ldr r0, l2cc_pa_addr @ load physical address of L2CC
-
- ldr r1, l2cc_tag_latency_ctrl @ tag latency register offset
- add r1, r0, r1
- ldr r2, l2cc_tag_data @ load saved tag latency register
- str r2, [r1] @ store saved value to register
-
- ldr r1, l2cc_data_latency_ctrl @ data latency register offset
- add r1, r0, r1
- ldr r2, l2cc_data_data @ load saved data latency register
- str r2, [r1] @ store saved value to register
-
- ldr r1, l2cc_prefetch_ctrl @ prefetch control register offset
- add r1, r0, r1
- ldr r2, l2cc_prefetch_data @ load saved prefetch control register
- str r2, [r1] @ store saved value to register
-
- ldr r1, l2cc_pwr_ctrl @ power control register offset
- add r1, r0, r1
- ldr r2, l2cc_pwr_data @ load saved power control register
- str r2, [r1] @ store saved value to register
-
- ldr r1, l2cc_aux_ctrl @ aux control register offset
- add r1, r0, r1
- ldr r2, l2cc_aux_data @ load saved aux control register
- str r2, [r1] @ store saved value to register
-
- ldr r1, l2cc_ctrl @ control register offset
- add r1, r0, r1
- mov r2, #1 @ enable L2CC
- str r2, [r1]
-
- b cpu_resume
-ENDPROC(exynos4_idle_resume)
-
- .global l2cc_save
-
-scu_pa_addr:
- .word EXYNOS4_PA_COREPERI
-l2cc_pa_addr:
- .word EXYNOS4_PA_L2CC
-l2cc_prefetch_ctrl:
- .word L2X0_PREFETCH_CTRL
-l2cc_pwr_ctrl:
- .word L2X0_POWER_CTRL
-l2cc_tag_latency_ctrl:
- .word L2X0_TAG_LATENCY_CTRL
-l2cc_data_latency_ctrl:
- .word L2X0_DATA_LATENCY_CTRL
-l2cc_aux_ctrl:
- .word L2X0_AUX_CTRL
-l2cc_ctrl:
- .word L2X0_CTRL
-l2cc_save:
-l2cc_prefetch_data:
- .long 0
-l2cc_pwr_data:
- .long 0
-l2cc_tag_data:
- .long 0
-l2cc_data_data:
- .long 0
-l2cc_aux_data:
- .long 0
@@ -21,8 +21,4 @@ enum sys_powerdown {
};
extern void exynos4_sys_powerdown_conf(enum sys_powerdown mode);
-extern void exynos4_idle_resume(void);
-extern void exynos4_enter_lp(unsigned long arg, long offset);
-/* Keep following save sequence prefetch, power, tag, data, aux */
-extern unsigned long l2cc_save[5];
#endif /* __ASM_ARCH_PMU_H */
The L2 retention cpuidle state is modified to use the interfaces exposed by the lorenzo's cpuidle consolidation code. As can be seen lot of code is reduced in the machine directory. Signed-off-by: Amit Daniel Kachhap <amit.kachhap@linaro.org> --- arch/arm/Kconfig | 1 + arch/arm/mach-exynos4/Makefile | 2 +- arch/arm/mach-exynos4/cpuidle.c | 85 +++++++++------- arch/arm/mach-exynos4/idle.S | 165 ------------------------------ arch/arm/mach-exynos4/include/mach/pmu.h | 4 - 5 files changed, 52 insertions(+), 205 deletions(-) delete mode 100644 arch/arm/mach-exynos4/idle.S