From 9a8f39950d276bc77d3eb22bfc798c4612ee3c29 Mon Sep 17 00:00:00 2001 From: Amit Daniel Kachhap Date: Fri, 9 May 2014 06:43:26 +0900 Subject: ARM: EXYNOS: Move arm core power down clock to exynos5250 common clock Now with common clock support added for exynos5250 it is necessary to move this code to exynos5250 common clock driver as clock registers should be handled there. This change is tested in exynos5250 based arndale platform. Cc: Abhilash Kesavan Cc: Thomas Abraham Acked-by: Kukjin Kim Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Amit Daniel Kachhap [t.figa: Rebased onto current kernel sources.] Signed-off-by: Tomasz Figa Signed-off-by: Daniel Lezcano Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 54 ------------------------------------------ 1 file changed, 54 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index c57cae0e8779..8125a1534093 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -41,25 +41,6 @@ #define S5P_CHECK_AFTR 0xFCBA0D10 -#define EXYNOS5_PWR_CTRL1 (S5P_VA_CMU + 0x01020) -#define EXYNOS5_PWR_CTRL2 (S5P_VA_CMU + 0x01024) - -#define PWR_CTRL1_CORE2_DOWN_RATIO (7 << 28) -#define PWR_CTRL1_CORE1_DOWN_RATIO (7 << 16) -#define PWR_CTRL1_DIV2_DOWN_EN (1 << 9) -#define PWR_CTRL1_DIV1_DOWN_EN (1 << 8) -#define PWR_CTRL1_USE_CORE1_WFE (1 << 5) -#define PWR_CTRL1_USE_CORE0_WFE (1 << 4) -#define PWR_CTRL1_USE_CORE1_WFI (1 << 1) -#define PWR_CTRL1_USE_CORE0_WFI (1 << 0) - -#define PWR_CTRL2_DIV2_UP_EN (1 << 25) -#define PWR_CTRL2_DIV1_UP_EN (1 << 24) -#define PWR_CTRL2_DUR_STANDBY2_VAL (1 << 16) -#define PWR_CTRL2_DUR_STANDBY1_VAL (1 << 8) -#define PWR_CTRL2_CORE2_UP_RATIO (1 << 4) -#define PWR_CTRL2_CORE1_UP_RATIO (1 << 0) - static int exynos4_enter_lowpower(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index); @@ -182,46 +163,11 @@ static int exynos4_enter_lowpower(struct cpuidle_device *dev, return exynos4_enter_core0_aftr(dev, drv, new_index); } -static void __init exynos5_core_down_clk(void) -{ - unsigned int tmp; - - /* - * Enable arm clock down (in idle) and set arm divider - * ratios in WFI/WFE state. - */ - tmp = PWR_CTRL1_CORE2_DOWN_RATIO | \ - PWR_CTRL1_CORE1_DOWN_RATIO | \ - PWR_CTRL1_DIV2_DOWN_EN | \ - PWR_CTRL1_DIV1_DOWN_EN | \ - PWR_CTRL1_USE_CORE1_WFE | \ - PWR_CTRL1_USE_CORE0_WFE | \ - PWR_CTRL1_USE_CORE1_WFI | \ - PWR_CTRL1_USE_CORE0_WFI; - __raw_writel(tmp, EXYNOS5_PWR_CTRL1); - - /* - * Enable arm clock up (on exiting idle). Set arm divider - * ratios when not in idle along with the standby duration - * ratios. - */ - tmp = PWR_CTRL2_DIV2_UP_EN | \ - PWR_CTRL2_DIV1_UP_EN | \ - PWR_CTRL2_DUR_STANDBY2_VAL | \ - PWR_CTRL2_DUR_STANDBY1_VAL | \ - PWR_CTRL2_CORE2_UP_RATIO | \ - PWR_CTRL2_CORE1_UP_RATIO; - __raw_writel(tmp, EXYNOS5_PWR_CTRL2); -} - static int exynos_cpuidle_probe(struct platform_device *pdev) { int cpu_id, ret; struct cpuidle_device *device; - if (soc_is_exynos5250()) - exynos5_core_down_clk(); - if (soc_is_exynos5440()) exynos4_idle_driver.state_count = 1; -- cgit v1.2.3 From 53af16a1a8d6776b19747291b39f0d4cbda42d92 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:43:26 +0900 Subject: ARM: EXYNOS: Prevent forward declaration for cpuidle Move the structure below the 'exynos4_enter_lowpower' function so no more need of forward declaration. Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 8125a1534093..56780c64a620 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -41,30 +41,8 @@ #define S5P_CHECK_AFTR 0xFCBA0D10 -static int exynos4_enter_lowpower(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index); - static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device); -static struct cpuidle_driver exynos4_idle_driver = { - .name = "exynos4_idle", - .owner = THIS_MODULE, - .states = { - [0] = ARM_CPUIDLE_WFI_STATE, - [1] = { - .enter = exynos4_enter_lowpower, - .exit_latency = 300, - .target_residency = 100000, - .flags = CPUIDLE_FLAG_TIME_VALID, - .name = "C1", - .desc = "ARM power down", - }, - }, - .state_count = 2, - .safe_state_index = 0, -}; - /* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ static void exynos4_set_wakeupmask(void) { @@ -163,6 +141,24 @@ static int exynos4_enter_lowpower(struct cpuidle_device *dev, return exynos4_enter_core0_aftr(dev, drv, new_index); } +static struct cpuidle_driver exynos4_idle_driver = { + .name = "exynos4_idle", + .owner = THIS_MODULE, + .states = { + [0] = ARM_CPUIDLE_WFI_STATE, + [1] = { + .enter = exynos4_enter_lowpower, + .exit_latency = 300, + .target_residency = 100000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "C1", + .desc = "ARM power down", + }, + }, + .state_count = 2, + .safe_state_index = 0, +}; + static int exynos_cpuidle_probe(struct platform_device *pdev) { int cpu_id, ret; -- cgit v1.2.3 From 043c86b6f2d54cfee8ec67e1f7f49156a68b2bd2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:43:26 +0900 Subject: ARM: EXYNOS: Use cpuidle_register Use the cpuidle generic function 'cpuidle_register'. That saves us from some extra lines of code and unneeded variables. A side effect of this change is a bug fix where before the cpuidle driver was registered for each_online_cpu and now it is for each_possible_cpu. Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 56780c64a620..0093d369f099 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -41,8 +41,6 @@ #define S5P_CHECK_AFTR 0xFCBA0D10 -static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device); - /* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ static void exynos4_set_wakeupmask(void) { @@ -161,29 +159,17 @@ static struct cpuidle_driver exynos4_idle_driver = { static int exynos_cpuidle_probe(struct platform_device *pdev) { - int cpu_id, ret; - struct cpuidle_device *device; + int ret; if (soc_is_exynos5440()) exynos4_idle_driver.state_count = 1; - ret = cpuidle_register_driver(&exynos4_idle_driver); + ret = cpuidle_register(&exynos4_idle_driver, NULL); if (ret) { dev_err(&pdev->dev, "failed to register cpuidle driver\n"); return ret; } - for_each_online_cpu(cpu_id) { - device = &per_cpu(exynos4_cpuidle_device, cpu_id); - device->cpu = cpu_id; - - ret = cpuidle_register_device(device); - if (ret) { - dev_err(&pdev->dev, "failed to register cpuidle device\n"); - return ret; - } - } - return 0; } -- cgit v1.2.3 From 7880e45ed0f898fa2c45415a9cb5e9cb3860d1a3 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:43:26 +0900 Subject: ARM: EXYNOS: Change function name prefix for cpuidle The driver was initially written for exynos4 but the driver is used also for exynos5. Change the function prefix name exynos4 -> exynos Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 0093d369f099..15b9bda1ab6e 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -1,4 +1,4 @@ -/* linux/arch/arm/mach-exynos4/cpuidle.c +/* linux/arch/arm/mach-exynos/cpuidle.c * * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com @@ -42,7 +42,7 @@ #define S5P_CHECK_AFTR 0xFCBA0D10 /* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ -static void exynos4_set_wakeupmask(void) +static void exynos_set_wakeupmask(void) { __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK); } @@ -73,13 +73,13 @@ static int idle_finisher(unsigned long flags) return 1; } -static int exynos4_enter_core0_aftr(struct cpuidle_device *dev, +static int exynos_enter_core0_aftr(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { unsigned long tmp; - exynos4_set_wakeupmask(); + exynos_set_wakeupmask(); /* Set value of power down register for aftr mode */ exynos_sys_powerdown_conf(SYS_AFTR); @@ -123,7 +123,7 @@ static int exynos4_enter_core0_aftr(struct cpuidle_device *dev, return index; } -static int exynos4_enter_lowpower(struct cpuidle_device *dev, +static int exynos_enter_lowpower(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { @@ -136,16 +136,16 @@ static int exynos4_enter_lowpower(struct cpuidle_device *dev, if (new_index == 0) return arm_cpuidle_simple_enter(dev, drv, new_index); else - return exynos4_enter_core0_aftr(dev, drv, new_index); + return exynos_enter_core0_aftr(dev, drv, new_index); } -static struct cpuidle_driver exynos4_idle_driver = { - .name = "exynos4_idle", +static struct cpuidle_driver exynos_idle_driver = { + .name = "exynos_idle", .owner = THIS_MODULE, .states = { [0] = ARM_CPUIDLE_WFI_STATE, [1] = { - .enter = exynos4_enter_lowpower, + .enter = exynos_enter_lowpower, .exit_latency = 300, .target_residency = 100000, .flags = CPUIDLE_FLAG_TIME_VALID, @@ -162,9 +162,9 @@ static int exynos_cpuidle_probe(struct platform_device *pdev) int ret; if (soc_is_exynos5440()) - exynos4_idle_driver.state_count = 1; + exynos_idle_driver.state_count = 1; - ret = cpuidle_register(&exynos4_idle_driver, NULL); + ret = cpuidle_register(&exynos_idle_driver, NULL); if (ret) { dev_err(&pdev->dev, "failed to register cpuidle driver\n"); return ret; -- cgit v1.2.3 From 309e08c4ca5446ab9f3e8c17581e5515855d339d Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:43:27 +0900 Subject: ARM: EXYNOS: Encapsulate register access inside a function for pm That makes the code cleaner and encapsulted. The function will be reused in the next patch. Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pm.c | 65 ++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 24 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 3f2ae864582e..86a46607969f 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -169,6 +169,42 @@ int exynos_cluster_power_state(int cluster) /* For Cortex-A9 Diagnostic and Power control register */ static unsigned int save_arm_register[2]; +static void exynos_cpu_save_register(void) +{ + unsigned long tmp; + + /* Save Power control register */ + asm ("mrc p15, 0, %0, c15, c0, 0" + : "=r" (tmp) : : "cc"); + + save_arm_register[0] = tmp; + + /* Save Diagnostic register */ + asm ("mrc p15, 0, %0, c15, c0, 1" + : "=r" (tmp) : : "cc"); + + save_arm_register[1] = tmp; +} + +static void exynos_cpu_restore_register(void) +{ + unsigned long tmp; + + /* Restore Power control register */ + tmp = save_arm_register[0]; + + asm volatile ("mcr p15, 0, %0, c15, c0, 0" + : : "r" (tmp) + : "cc"); + + /* Restore Diagnostic register */ + tmp = save_arm_register[1]; + + asm volatile ("mcr p15, 0, %0, c15, c0, 1" + : : "r" (tmp) + : "cc"); +} + static int exynos_cpu_suspend(unsigned long arg) { #ifdef CONFIG_CACHE_L2X0 @@ -228,17 +264,8 @@ static int exynos_pm_suspend(void) tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0); __raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); - if (!soc_is_exynos5250()) { - /* Save Power control register */ - asm ("mrc p15, 0, %0, c15, c0, 0" - : "=r" (tmp) : : "cc"); - save_arm_register[0] = tmp; - - /* Save Diagnostic register */ - asm ("mrc p15, 0, %0, c15, c0, 1" - : "=r" (tmp) : : "cc"); - save_arm_register[1] = tmp; - } + if (!soc_is_exynos5250()) + exynos_cpu_save_register(); return 0; } @@ -262,19 +289,9 @@ static void exynos_pm_resume(void) /* No need to perform below restore code */ goto early_wakeup; } - if (!soc_is_exynos5250()) { - /* Restore Power control register */ - tmp = save_arm_register[0]; - asm volatile ("mcr p15, 0, %0, c15, c0, 0" - : : "r" (tmp) - : "cc"); - - /* Restore Diagnostic register */ - tmp = save_arm_register[1]; - asm volatile ("mcr p15, 0, %0, c15, c0, 1" - : : "r" (tmp) - : "cc"); - } + + if (!soc_is_exynos5250()) + exynos_cpu_restore_register(); /* For release retention */ -- cgit v1.2.3 From 20115fa874ce948f309b49d7b641d2cf55e09ad4 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:43:27 +0900 Subject: ARM: EXYNOS: Move some code inside the idle_finisher for cpuidle Move the code around to differentiate different section of code and prepare it to be factored out in the next patches. The call order changed but hat doesn't have a side effect because they are independent. The important call is cpu_do_idle() which must be done the last. Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 15b9bda1ab6e..144ff1e7bbf8 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -69,7 +69,16 @@ static void restore_cpu_arch_register(void) static int idle_finisher(unsigned long flags) { + exynos_set_wakeupmask(); + + __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR); + __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG); + + /* Set value of power down register for aftr mode */ + exynos_sys_powerdown_conf(SYS_AFTR); + cpu_do_idle(); + return 1; } @@ -79,14 +88,6 @@ static int exynos_enter_core0_aftr(struct cpuidle_device *dev, { unsigned long tmp; - exynos_set_wakeupmask(); - - /* Set value of power down register for aftr mode */ - exynos_sys_powerdown_conf(SYS_AFTR); - - __raw_writel(virt_to_phys(exynos_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 */ -- cgit v1.2.3 From 9bd5544af89618f2f5bee31a7ef24d987f2b3f1d Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:43:27 +0900 Subject: ARM: EXYNOS: Fix S5P_WAKEUP_STAT call for cpuidle This function should be called only when the powerdown sequence fails. Even if the current code does not hurt, by moving this line, we have the same code than the one in pm.c. Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 144ff1e7bbf8..87f9f129883d 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -116,11 +116,10 @@ static int exynos_enter_core0_aftr(struct cpuidle_device *dev, 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); } - /* Clear wakeup state register */ - __raw_writel(0x0, S5P_WAKEUP_STAT); - return index; } -- cgit v1.2.3 From 85f9f90808b4437bbdff1dff2c80663dae57ab51 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:43:27 +0900 Subject: ARM: EXYNOS: Use the cpu_pm notifier for pm Use the cpu_pm_enter/exit notifier to group some pm code inside the pm file. The save and restore code is duplicated across pm.c and cpuidle.c. By using the cpu_pm notifier, we can factor out the routine. Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 24 ------------------------ arch/arm/mach-exynos/pm.c | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 24 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 87f9f129883d..7a2d01bbef6b 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -47,26 +47,6 @@ static void exynos_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) { exynos_set_wakeupmask(); @@ -88,8 +68,6 @@ static int exynos_enter_core0_aftr(struct cpuidle_device *dev, { unsigned long tmp; - save_cpu_arch_register(); - /* Setting Central Sequence Register for power down mode */ tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); tmp &= ~S5P_CENTRAL_LOWPWR_CFG; @@ -104,8 +82,6 @@ static int exynos_enter_core0_aftr(struct cpuidle_device *dev, #endif 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(). diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 86a46607969f..3eb80cd4607d 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -387,10 +388,36 @@ static const struct platform_suspend_ops exynos_suspend_ops = { .valid = suspend_valid_only_mem, }; +static int exynos_cpu_pm_notifier(struct notifier_block *self, + unsigned long cmd, void *v) +{ + int cpu = smp_processor_id(); + + switch (cmd) { + case CPU_PM_ENTER: + if (cpu == 0) + exynos_cpu_save_register(); + break; + + case CPU_PM_EXIT: + if (cpu == 0) + exynos_cpu_restore_register(); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block exynos_cpu_pm_notifier_block = { + .notifier_call = exynos_cpu_pm_notifier, +}; + void __init exynos_pm_init(void) { u32 tmp; + cpu_pm_register_notifier(&exynos_cpu_pm_notifier_block); + /* Platform-specific GIC callback */ gic_arch_extn.irq_set_wake = exynos_irq_set_wake; -- cgit v1.2.3 From 795537daae8a14dd05923ee78b687a821460d4f1 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:50:16 +0900 Subject: ARM: EXYNOS: Move scu_enable in the cpu_pm notifier We make the cpuidle code less arch dependent. Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 6 ------ arch/arm/mach-exynos/pm.c | 7 ++++++- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 7a2d01bbef6b..bf1bf87af00e 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -75,11 +74,6 @@ static int exynos_enter_core0_aftr(struct cpuidle_device *dev, cpu_pm_enter(); cpu_suspend(0, idle_finisher); - -#ifdef CONFIG_SMP - if (!soc_is_exynos5250()) - scu_enable(S5P_VA_SCU); -#endif cpu_pm_exit(); /* diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 3eb80cd4607d..fb1d9160991a 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -400,8 +400,13 @@ static int exynos_cpu_pm_notifier(struct notifier_block *self, break; case CPU_PM_EXIT: - if (cpu == 0) + if (cpu == 0) { +#ifdef CONFIG_SMP + if (!soc_is_exynos5250()) + scu_enable(S5P_VA_SCU); +#endif exynos_cpu_restore_register(); + } break; } -- cgit v1.2.3 From 58afbc61a33928a764460bfa4ea85c9dbe9d0a77 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:53:26 +0900 Subject: ARM: EXYNOS: Remove ifdef for scu_enable in pm The scu_enable function is already a noop in the scu's header file is CONFIG_SMP=n, so no need to use these macros in the code. Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index fb1d9160991a..24c638d2afd4 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -310,7 +310,7 @@ static void exynos_pm_resume(void) s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); - if (IS_ENABLED(CONFIG_SMP) && !soc_is_exynos5250()) + if (!soc_is_exynos5250()) scu_enable(S5P_VA_SCU); early_wakeup: @@ -401,10 +401,8 @@ static int exynos_cpu_pm_notifier(struct notifier_block *self, case CPU_PM_EXIT: if (cpu == 0) { -#ifdef CONFIG_SMP if (!soc_is_exynos5250()) scu_enable(S5P_VA_SCU); -#endif exynos_cpu_restore_register(); } break; -- cgit v1.2.3 From 623f22665c790f82a571653c01e949834490a55a Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:52:59 +0900 Subject: ARM: EXYNOS: Pass wakeup mask parameter to function for cpuidle Pass the wakeup mask to 'exynos_set_wakeupmask' as this function could be used for different idle states with different mask. Signed-off-by: Daniel Lezcano Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index bf1bf87af00e..717dbf28ede7 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -41,14 +41,14 @@ #define S5P_CHECK_AFTR 0xFCBA0D10 /* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ -static void exynos_set_wakeupmask(void) +static void exynos_set_wakeupmask(long mask) { - __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK); + __raw_writel(mask, S5P_WAKEUP_MASK); } static int idle_finisher(unsigned long flags) { - exynos_set_wakeupmask(); + exynos_set_wakeupmask(0x0000ff3e); __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR); __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG); -- cgit v1.2.3 From dcef663d49e3beb09bc3cb436c997ce40aaf80fa Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:52:59 +0900 Subject: ARM: EXYNOS: Encapsulate boot vector code into a function for cpuidle Signed-off-by: Daniel Lezcano Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 717dbf28ede7..4e46a12b4056 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -46,13 +46,16 @@ static void exynos_set_wakeupmask(long mask) __raw_writel(mask, S5P_WAKEUP_MASK); } +static void exynos_cpu_set_boot_vector(long flags) +{ + __raw_writel(virt_to_phys(exynos_cpu_resume), REG_DIRECTGO_ADDR); + __raw_writel(flags, REG_DIRECTGO_FLAG); +} + static int idle_finisher(unsigned long flags) { exynos_set_wakeupmask(0x0000ff3e); - - __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR); - __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG); - + exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); /* Set value of power down register for aftr mode */ exynos_sys_powerdown_conf(SYS_AFTR); -- cgit v1.2.3 From 70ecb842ba19d205a1e5d6c3de5656e1cb986284 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:52:59 +0900 Subject: ARM: EXYNOS: Disable cpuidle for exynos5440 There is no point to register the cpuidle driver for the 5440 as it has only one WFI state which is the default idle function when the cpuidle driver is disabled. By disabling cpuidle we prevent to enter to the governor computation for nothing, thus saving a lot of processing time. The only drawback is the statistic via sysfs on this state which is lost but it is meaningless and it could be retrieved from the ftrace easily. Signed-off-by: Daniel Lezcano Reviewed-by: Tomasz Figa Acked-by: Amit Kucheria Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 3 --- arch/arm/mach-exynos/exynos.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 4e46a12b4056..862d6beae4af 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -134,9 +134,6 @@ static int exynos_cpuidle_probe(struct platform_device *pdev) { int ret; - if (soc_is_exynos5440()) - exynos_idle_driver.state_count = 1; - ret = cpuidle_register(&exynos_idle_driver, NULL); if (ret) { dev_err(&pdev->dev, "failed to register cpuidle driver\n"); diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index e973ff5de7b3..89872405cccd 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -177,6 +177,9 @@ static struct platform_device exynos_cpuidle = { void __init exynos_cpuidle_init(void) { + if (soc_is_exynos5440()) + return; + platform_device_register(&exynos_cpuidle); } -- cgit v1.2.3 From 712bb69e89c575b793954eb641958f992f4b5f78 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:52:59 +0900 Subject: ARM: EXYNOS: Encapsulate the AFTR code into a function Let's encapsulate the AFTR state specific call into a single function. Signed-off-by: Daniel Lezcano Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 862d6beae4af..d8b80c053e42 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -52,13 +52,17 @@ static void exynos_cpu_set_boot_vector(long flags) __raw_writel(flags, REG_DIRECTGO_FLAG); } -static int idle_finisher(unsigned long flags) +static void exynos_enter_aftr(void) { exynos_set_wakeupmask(0x0000ff3e); exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); /* Set value of power down register for aftr mode */ exynos_sys_powerdown_conf(SYS_AFTR); +} +static int idle_finisher(unsigned long flags) +{ + exynos_enter_aftr(); cpu_do_idle(); return 1; -- cgit v1.2.3 From 3681bafeb1e4781bdeaecd19aa8c9f6d0db90f6f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:53:00 +0900 Subject: ARM: EXYNOS: Move the AFTR state function into pm.c In order to remove depedency on pm code, let's move the 'exynos_enter_aftr' function into the pm.c file as well as the other helper functions. Signed-off-by: Daniel Lezcano Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/common.h | 1 + arch/arm/mach-exynos/cpuidle.c | 29 ----------------------------- arch/arm/mach-exynos/pm.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 29 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 7876ed04b7a5..27c9abdeb79e 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -69,5 +69,6 @@ extern int exynos_cpu_power_state(int cpu); extern void exynos_cluster_power_down(int cluster); extern void exynos_cluster_power_up(int cluster); extern int exynos_cluster_power_state(int cluster); +extern void exynos_enter_aftr(void); #endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */ diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index d8b80c053e42..eea3eb9cecef 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -31,35 +31,6 @@ #include "common.h" #include "regs-pmu.h" -#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 0xFCBA0D10 - -/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ -static void exynos_set_wakeupmask(long mask) -{ - __raw_writel(mask, S5P_WAKEUP_MASK); -} - -static void exynos_cpu_set_boot_vector(long flags) -{ - __raw_writel(virt_to_phys(exynos_cpu_resume), REG_DIRECTGO_ADDR); - __raw_writel(flags, REG_DIRECTGO_FLAG); -} - -static void exynos_enter_aftr(void) -{ - exynos_set_wakeupmask(0x0000ff3e); - exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); - /* Set value of power down register for aftr mode */ - exynos_sys_powerdown_conf(SYS_AFTR); -} - static int idle_finisher(unsigned long flags) { exynos_enter_aftr(); diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 24c638d2afd4..179f7e09e20d 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -167,6 +167,35 @@ int exynos_cluster_power_state(int cluster) S5P_CORE_LOCAL_PWR_EN); } +#define EXYNOS_BOOT_VECTOR_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ + S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ + (S5P_VA_SYSRAM + 0x24) : S5P_INFORM0)) +#define EXYNOS_BOOT_VECTOR_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 0xFCBA0D10 + +/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ +static void exynos_set_wakeupmask(long mask) +{ + __raw_writel(mask, S5P_WAKEUP_MASK); +} + +static void exynos_cpu_set_boot_vector(long flags) +{ + __raw_writel(virt_to_phys(exynos_cpu_resume), EXYNOS_BOOT_VECTOR_ADDR); + __raw_writel(flags, EXYNOS_BOOT_VECTOR_FLAG); +} + +void exynos_enter_aftr(void) +{ + exynos_set_wakeupmask(0x0000ff3e); + exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); + /* Set value of power down register for aftr mode */ + exynos_sys_powerdown_conf(SYS_AFTR); +} + /* For Cortex-A9 Diagnostic and Power control register */ static unsigned int save_arm_register[2]; -- cgit v1.2.3 From 0ebc13e2a2353f76ecdca11cf4d49da0b4e77f09 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:55:12 +0900 Subject: ARM: EXYNOS: Move the power sequence call in the cpu_pm notifier The code to initiate and exit the powerdown sequence is the same in pm.c and cpuidle.c. Let's split the common part in the pm.c and reuse it from the cpu_pm notifier. That is one more step forward to make the cpuidle driver arch indenpendant. Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 22 ---------------------- arch/arm/mach-exynos/pm.c | 27 ++++++++++++++++++++++----- 2 files changed, 22 insertions(+), 27 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index eea3eb9cecef..cac51d852605 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -29,7 +29,6 @@ #include #include "common.h" -#include "regs-pmu.h" static int idle_finisher(unsigned long flags) { @@ -43,31 +42,10 @@ static int exynos_enter_core0_aftr(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - unsigned long tmp; - - /* 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); cpu_pm_exit(); - /* - * 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); - } - return index; } diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 179f7e09e20d..8b268b5b42fa 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -279,15 +279,21 @@ static void exynos_pm_prepare(void) __raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); } -static int exynos_pm_suspend(void) +static void exynos_pm_central_suspend(void) { unsigned long tmp; /* 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); +} + +static int exynos_pm_suspend(void) +{ + unsigned long tmp; + + exynos_pm_central_suspend(); /* Setting SEQ_OPTION register */ @@ -300,7 +306,7 @@ static int exynos_pm_suspend(void) return 0; } -static void exynos_pm_resume(void) +static int exynos_pm_central_resume(void) { unsigned long tmp; @@ -317,9 +323,17 @@ static void exynos_pm_resume(void) /* clear the wakeup state register */ __raw_writel(0x0, S5P_WAKEUP_STAT); /* No need to perform below restore code */ - goto early_wakeup; + return -1; } + return 0; +} + +static void exynos_pm_resume(void) +{ + if (exynos_pm_central_resume()) + goto early_wakeup; + if (!soc_is_exynos5250()) exynos_cpu_restore_register(); @@ -424,8 +438,10 @@ static int exynos_cpu_pm_notifier(struct notifier_block *self, switch (cmd) { case CPU_PM_ENTER: - if (cpu == 0) + if (cpu == 0) { + exynos_pm_central_suspend(); exynos_cpu_save_register(); + } break; case CPU_PM_EXIT: @@ -433,6 +449,7 @@ static int exynos_cpu_pm_notifier(struct notifier_block *self, if (!soc_is_exynos5250()) scu_enable(S5P_VA_SCU); exynos_cpu_restore_register(); + exynos_pm_central_resume(); } break; } -- cgit v1.2.3 From e30b154bd2df3be95deda85ce5bc5a05a18896ef Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:56:24 +0900 Subject: ARM: EXYNOS: Move S5P_CHECK_SLEEP into pm.c This macro is only used there. Signed-off-by: Daniel Lezcano Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pm.c | 3 ++- arch/arm/mach-exynos/regs-pmu.h | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 8b268b5b42fa..f7b0b77582f6 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -174,7 +174,8 @@ int exynos_cluster_power_state(int cluster) S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ (S5P_VA_SYSRAM + 0x20) : S5P_INFORM1)) -#define S5P_CHECK_AFTR 0xFCBA0D10 +#define S5P_CHECK_AFTR 0xFCBA0D10 +#define S5P_CHECK_SLEEP 0x00000BAD /* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ static void exynos_set_wakeupmask(long mask) diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h index 4179f6a6d595..1d13b08708f0 100644 --- a/arch/arm/mach-exynos/regs-pmu.h +++ b/arch/arm/mach-exynos/regs-pmu.h @@ -129,8 +129,6 @@ #define S5P_CORE_LOCAL_PWR_EN 0x3 #define S5P_INT_LOCAL_PWR_EN 0x7 -#define S5P_CHECK_SLEEP 0x00000BAD - /* Only for EXYNOS4210 */ #define S5P_CMU_CLKSTOP_LCD1_LOWPWR S5P_PMUREG(0x1154) #define S5P_CMU_RESET_LCD1_LOWPWR S5P_PMUREG(0x1174) -- cgit v1.2.3 From 277f50464d8b2e68a05cfcac765a0e54fd382d1f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:56:29 +0900 Subject: ARM: EXYNOS: Pass the AFTR callback to the platform_data No more dependency on the arch code. The platform_data field is used to set the PM callback as the other cpuidle drivers. Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 4 +++- arch/arm/mach-exynos/exynos.c | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index cac51d852605..05cb00c79406 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -28,7 +28,7 @@ #include -#include "common.h" +static void (*exynos_enter_aftr)(void); static int idle_finisher(unsigned long flags) { @@ -87,6 +87,8 @@ static int exynos_cpuidle_probe(struct platform_device *pdev) { int ret; + exynos_enter_aftr = (void *)(pdev->dev.platform_data); + ret = cpuidle_register(&exynos_idle_driver, NULL); if (ret) { dev_err(&pdev->dev, "failed to register cpuidle driver\n"); diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 89872405cccd..7d9d8762b56e 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -171,8 +171,9 @@ void exynos_restart(enum reboot_mode mode, const char *cmd) } static struct platform_device exynos_cpuidle = { - .name = "exynos_cpuidle", - .id = -1, + .name = "exynos_cpuidle", + .dev.platform_data = exynos_enter_aftr, + .id = -1, }; void __init exynos_cpuidle_init(void) -- cgit v1.2.3 From ce4305d2a5ad76d80c8edfd2f847ae34bcda32ab Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:57:30 +0900 Subject: ARM: EXYNOS: Cleanup all unneeded headers from cpuidle.c Signed-off-by: Daniel Lezcano Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index 05cb00c79406..7c0151263828 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -8,26 +8,16 @@ * published by the Free Software Foundation. */ -#include -#include #include #include -#include #include #include -#include #include #include #include -#include #include -#include -#include - -#include - static void (*exynos_enter_aftr)(void); static int idle_finisher(unsigned long flags) -- cgit v1.2.3 From ff6a9c039dc7da12fcfc70c28ccc9893d85f8e1f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 9 May 2014 06:57:35 +0900 Subject: ARM: EXYNOS: Move the driver to drivers/cpuidle directory Signed-off-by: Daniel Lezcano Reviewed-by: Viresh Kumar Reviewed-by: Bartlomiej Zolnierkiewicz Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/Makefile | 1 - arch/arm/mach-exynos/cpuidle.c | 99 ---------------------------------------- drivers/cpuidle/Kconfig.arm | 6 +++ drivers/cpuidle/Makefile | 1 + drivers/cpuidle/cpuidle-exynos.c | 99 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 100 deletions(-) delete mode 100644 arch/arm/mach-exynos/cpuidle.c create mode 100644 drivers/cpuidle/cpuidle-exynos.c (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 01bc9b94a032..3705048f744a 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos.o obj-$(CONFIG_PM_SLEEP) += pm.o sleep.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o -obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_ARCH_EXYNOS) += pmu.o diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c deleted file mode 100644 index 7c0151263828..000000000000 --- a/arch/arm/mach-exynos/cpuidle.c +++ /dev/null @@ -1,99 +0,0 @@ -/* linux/arch/arm/mach-exynos/cpuidle.c - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * 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 -#include -#include -#include -#include - -#include -#include -#include - -static void (*exynos_enter_aftr)(void); - -static int idle_finisher(unsigned long flags) -{ - exynos_enter_aftr(); - cpu_do_idle(); - - return 1; -} - -static int exynos_enter_core0_aftr(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) -{ - cpu_pm_enter(); - cpu_suspend(0, idle_finisher); - cpu_pm_exit(); - - return index; -} - -static int exynos_enter_lowpower(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) -{ - int new_index = index; - - /* AFTR can only be entered when cores other than CPU0 are offline */ - if (num_online_cpus() > 1 || dev->cpu != 0) - new_index = drv->safe_state_index; - - if (new_index == 0) - return arm_cpuidle_simple_enter(dev, drv, new_index); - else - return exynos_enter_core0_aftr(dev, drv, new_index); -} - -static struct cpuidle_driver exynos_idle_driver = { - .name = "exynos_idle", - .owner = THIS_MODULE, - .states = { - [0] = ARM_CPUIDLE_WFI_STATE, - [1] = { - .enter = exynos_enter_lowpower, - .exit_latency = 300, - .target_residency = 100000, - .flags = CPUIDLE_FLAG_TIME_VALID, - .name = "C1", - .desc = "ARM power down", - }, - }, - .state_count = 2, - .safe_state_index = 0, -}; - -static int exynos_cpuidle_probe(struct platform_device *pdev) -{ - int ret; - - exynos_enter_aftr = (void *)(pdev->dev.platform_data); - - ret = cpuidle_register(&exynos_idle_driver, NULL); - if (ret) { - dev_err(&pdev->dev, "failed to register cpuidle driver\n"); - return ret; - } - - return 0; -} - -static struct platform_driver exynos_cpuidle_driver = { - .probe = exynos_cpuidle_probe, - .driver = { - .name = "exynos_cpuidle", - .owner = THIS_MODULE, - }, -}; - -module_platform_driver(exynos_cpuidle_driver); diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index 97ccc31dbdd8..695507ae345a 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -44,3 +44,9 @@ config ARM_AT91_CPUIDLE depends on ARCH_AT91 help Select this to enable cpuidle for AT91 processors + +config ARM_EXYNOS_CPUIDLE + bool "Cpu Idle Driver for the Exynos processors" + depends on ARCH_EXYNOS + help + Select this to enable cpuidle for Exynos processors diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile index f71ae1b373c5..0d1540adaf78 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE) += cpuidle-kirkwood.o obj-$(CONFIG_ARM_ZYNQ_CPUIDLE) += cpuidle-zynq.o obj-$(CONFIG_ARM_U8500_CPUIDLE) += cpuidle-ux500.o obj-$(CONFIG_ARM_AT91_CPUIDLE) += cpuidle-at91.o +obj-$(CONFIG_ARM_EXYNOS_CPUIDLE) += cpuidle-exynos.o ############################################################################### # POWERPC drivers diff --git a/drivers/cpuidle/cpuidle-exynos.c b/drivers/cpuidle/cpuidle-exynos.c new file mode 100644 index 000000000000..7c0151263828 --- /dev/null +++ b/drivers/cpuidle/cpuidle-exynos.c @@ -0,0 +1,99 @@ +/* linux/arch/arm/mach-exynos/cpuidle.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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 +#include +#include +#include +#include + +#include +#include +#include + +static void (*exynos_enter_aftr)(void); + +static int idle_finisher(unsigned long flags) +{ + exynos_enter_aftr(); + cpu_do_idle(); + + return 1; +} + +static int exynos_enter_core0_aftr(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + cpu_pm_enter(); + cpu_suspend(0, idle_finisher); + cpu_pm_exit(); + + return index; +} + +static int exynos_enter_lowpower(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + int new_index = index; + + /* AFTR can only be entered when cores other than CPU0 are offline */ + if (num_online_cpus() > 1 || dev->cpu != 0) + new_index = drv->safe_state_index; + + if (new_index == 0) + return arm_cpuidle_simple_enter(dev, drv, new_index); + else + return exynos_enter_core0_aftr(dev, drv, new_index); +} + +static struct cpuidle_driver exynos_idle_driver = { + .name = "exynos_idle", + .owner = THIS_MODULE, + .states = { + [0] = ARM_CPUIDLE_WFI_STATE, + [1] = { + .enter = exynos_enter_lowpower, + .exit_latency = 300, + .target_residency = 100000, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "C1", + .desc = "ARM power down", + }, + }, + .state_count = 2, + .safe_state_index = 0, +}; + +static int exynos_cpuidle_probe(struct platform_device *pdev) +{ + int ret; + + exynos_enter_aftr = (void *)(pdev->dev.platform_data); + + ret = cpuidle_register(&exynos_idle_driver, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to register cpuidle driver\n"); + return ret; + } + + return 0; +} + +static struct platform_driver exynos_cpuidle_driver = { + .probe = exynos_cpuidle_probe, + .driver = { + .name = "exynos_cpuidle", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(exynos_cpuidle_driver); -- cgit v1.2.3 From cd245f59aae5d6ef265f46aa6cea78354d61b629 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 26 May 2014 04:50:34 +0900 Subject: ARM: EXYNOS: Fix kernel panic when unplugging CPU1 on exynos A look at the code reveals use of S5P_VA_SYSRAM macro, in case of certain SoC revisions, which is not valid any longer, after SYSRAM started to be mapped dynamically. The new dynamic mapping is stored in sysram_base_addr variable, which is declared static in platsmp.c This fix makes sysram_base_addr non-static, declared it in common.h and used in pm.c instead of S5P_VA_SYSRAM. Suggested-by: Tomasz Figa Signed-off-by: Daniel Lezcano Reviewed-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/common.h | 1 + arch/arm/mach-exynos/platsmp.c | 2 +- arch/arm/mach-exynos/pm.c | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-exynos') diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 27c9abdeb79e..5848d3cc29e9 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -19,6 +19,7 @@ void mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1); struct map_desc; extern void __iomem *sysram_ns_base_addr; +extern void __iomem *sysram_base_addr; void exynos_init_io(void); void exynos_restart(enum reboot_mode mode, const char *cmd); void exynos_cpuidle_init(void); diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 78002c7344b3..9e5e230575dd 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -34,7 +34,7 @@ extern void exynos4_secondary_startup(void); -static void __iomem *sysram_base_addr; +void __iomem *sysram_base_addr; void __iomem *sysram_ns_base_addr; static void __init exynos_smp_prepare_sysram(void) diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index f7b0b77582f6..0d1a46e7b021 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -169,10 +169,10 @@ int exynos_cluster_power_state(int cluster) #define EXYNOS_BOOT_VECTOR_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (S5P_VA_SYSRAM + 0x24) : S5P_INFORM0)) + (sysram_base_addr + 0x24) : S5P_INFORM0)) #define EXYNOS_BOOT_VECTOR_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (S5P_VA_SYSRAM + 0x20) : S5P_INFORM1)) + (sysram_base_addr + 0x20) : S5P_INFORM1)) #define S5P_CHECK_AFTR 0xFCBA0D10 #define S5P_CHECK_SLEEP 0x00000BAD -- cgit v1.2.3