Hi,
This patch series fixes support for AFTR idle mode on boards with secure firmware enabled (it also includes fix for register setup on EXYNOS4x12 SoCs). It has been tested on Trats2 target but should also work on (EXYNOS4412 based) Insignal Origen board.
This patchset depends on "[PATCH V5 00/20] ARM: exynos: cpuidle: Move the driver to drivers/cpuidle" patch series from Daniel Lezcano ("http://www.spinics.net/lists/linux-samsung-soc/msg28494.html").
Best regards, -- Bartlomiej Zolnierkiewicz Samsung R&D Institute Poland Samsung Electronics
Bartlomiej Zolnierkiewicz (5): ARM: EXYNOS: add AFTR mode support to firmware do_idle method ARM: EXYNOS: PM: replace EXYNOS_BOOT_VECTOR_* macros by static inlines ARM: EXYNOS: PM: use c15resume firmware method if secure firmware is enabled ARM: EXYNOS: PM: fix register setup on EXYNOS4x12 for AFTR mode code ARM: EXYNOS: cpuidle: add secure firmware support to AFTR mode code
Kyungmin Park (1): arm: firmware: Check firmware is running or not
Tomasz Figa (1): ARM: EXYNOS: add support for firmware-assisted c15resume
arch/arm/common/firmware.c | 5 +++++ arch/arm/include/asm/firmware.h | 14 +++++++++++++- arch/arm/mach-exynos/firmware.c | 18 ++++++++++++++++-- arch/arm/mach-exynos/pm.c | 40 ++++++++++++++++++++++++++++++++-------- drivers/cpuidle/cpuidle-exynos.c | 7 ++++++- 5 files changed, 72 insertions(+), 12 deletions(-)
From: Kyungmin Park kyungmin.park@samsung.com
To support multi-platform, it needs to know it's running under secure OS or not. Sometimes it needs to access physical address by SMC calls.
e.g., if (firmware_run()) { addr = physical address; } else { addr = virtual address; }
call_firmware_ops(read_address, addr, &value);
Signed-off-by: Kyungmin Park kyungmin.park@samsung.com Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com --- arch/arm/common/firmware.c | 5 +++++ arch/arm/include/asm/firmware.h | 3 +++ 2 files changed, 8 insertions(+)
diff --git a/arch/arm/common/firmware.c b/arch/arm/common/firmware.c index 27ddccb..e9d9ee5 100644 --- a/arch/arm/common/firmware.c +++ b/arch/arm/common/firmware.c @@ -16,3 +16,8 @@ static const struct firmware_ops default_firmware_ops;
const struct firmware_ops *firmware_ops = &default_firmware_ops; + +int firmware_run(void) +{ + return firmware_ops != &default_firmware_ops; +} diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 2c9f10d..c72ec47 100644 --- a/arch/arm/include/asm/firmware.h +++ b/arch/arm/include/asm/firmware.h @@ -46,6 +46,9 @@ struct firmware_ops { /* Global pointer for current firmware_ops structure, can't be NULL. */ extern const struct firmware_ops *firmware_ops;
+/* Check firmware is running */ +extern int firmware_run(void); + /* * call_firmware_op(op, ...) *
From: Tomasz Figa t.figa@samsung.com
This change is a preparation for adding secure firmware support to EXYNOS cpuidle driver.
This patch shouldn't cause any functionality changes.
Signed-off-by: Tomasz Figa t.figa@samsung.com [bzolnier: splitted out from bigger patch] Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com --- arch/arm/include/asm/firmware.h | 4 ++++ arch/arm/mach-exynos/firmware.c | 8 ++++++++ 2 files changed, 12 insertions(+)
diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index c72ec47..70883c7 100644 --- a/arch/arm/include/asm/firmware.h +++ b/arch/arm/include/asm/firmware.h @@ -41,6 +41,10 @@ struct firmware_ops { * Initializes L2 cache */ int (*l2x0_init)(void); + /* + * Restores coprocessor 15 registers + */ + int (*c15resume)(u32 *regs); };
/* Global pointer for current firmware_ops structure, can't be NULL. */ diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index 932129e..581c7bf 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -40,10 +40,18 @@ static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr) return 0; }
+static int exynos_c15resume(u32 *regs) +{ + exynos_smc(SMC_CMD_C15RESUME, regs[0], regs[1], 0); + + return 0; +} + static const struct firmware_ops exynos_firmware_ops = { .do_idle = exynos_do_idle, .set_cpu_boot_addr = exynos_set_cpu_boot_addr, .cpu_boot = exynos_cpu_boot, + .c15resume = exynos_c15resume, };
void __init exynos_firmware_init(void)
On some platforms (i.e. EXYNOS ones) more than one idle mode is available and we need to distinguish them in firmware do_idle method.
Add mode parameter to do_idle firmware method and AFTR mode support to EXYNOS do_idle implementation.
This change is a preparation for adding secure firmware support to EXYNOS cpuidle driver.
This patch shouldn't cause any functionality changes (please note that do_idle firmware method is unused currently).
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com --- arch/arm/include/asm/firmware.h | 7 ++++++- arch/arm/mach-exynos/firmware.c | 10 ++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 70883c7..63989c3 100644 --- a/arch/arm/include/asm/firmware.h +++ b/arch/arm/include/asm/firmware.h @@ -28,7 +28,7 @@ struct firmware_ops { /* * Enters CPU idle mode */ - int (*do_idle)(void); + int (*do_idle)(int mode); /* * Sets boot address of specified physical CPU */ @@ -47,6 +47,11 @@ struct firmware_ops { int (*c15resume)(u32 *regs); };
+enum { + FW_DO_IDLE_NORMAL, + FW_DO_IDLE_AFTR, +}; + /* Global pointer for current firmware_ops structure, can't be NULL. */ extern const struct firmware_ops *firmware_ops;
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index 581c7bf..71fe169 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -20,9 +20,15 @@
#include "smc.h"
-static int exynos_do_idle(void) +static int exynos_do_idle(int mode) { - exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + switch (mode) { + case FW_DO_IDLE_AFTR: + exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0); + break; + case FW_DO_IDLE_NORMAL: + exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + } return 0; }
Replace EXYNOS_BOOT_VECTOR_ADDR and EXYNOS_BOOT_VECTOR_FLAG macros by exynos_boot_vector_addr() and exynos_boot_vector_flag() static inlines.
This patch shouldn't cause any functionality changes.
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com --- arch/arm/mach-exynos/pm.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index b380d48..1679c51 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -101,12 +101,23 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) return -ENOENT; }
-#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)) +static inline void __iomem *exynos_boot_vector_addr(void) +{ + if (samsung_rev() == EXYNOS4210_REV_1_1) + return S5P_INFORM7; + else if (samsung_rev() == EXYNOS4210_REV_1_0) + return S5P_VA_SYSRAM + 0x24; + return S5P_INFORM0; +} + +static inline void __iomem *exynos_boot_vector_flag(void) +{ + if (samsung_rev() == EXYNOS4210_REV_1_1) + return S5P_INFORM6; + else if (samsung_rev() == EXYNOS4210_REV_1_0) + return S5P_VA_SYSRAM + 0x20; + return S5P_INFORM1; +}
#define S5P_CHECK_AFTR 0xFCBA0D10 #define S5P_CHECK_SLEEP 0x00000BAD @@ -119,8 +130,9 @@ static void exynos_set_wakeupmask(long 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); + __raw_writel(virt_to_phys(exynos_cpu_resume), + exynos_boot_vector_addr()); + __raw_writel(flags, exynos_boot_vector_flag()); }
void exynos_enter_aftr(void)
On 05/05/2014 12:57 PM, Bartlomiej Zolnierkiewicz wrote:
Replace EXYNOS_BOOT_VECTOR_ADDR and EXYNOS_BOOT_VECTOR_FLAG macros by exynos_boot_vector_addr() and exynos_boot_vector_flag() static inlines.
This patch shouldn't cause any functionality changes.
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com
Acked-by: Daniel Lezcano daniel.lezcano@linaro.org
Use c15resume firmware method instead of accessing the registers directly in exynos_cpu_restore_register() if secure firmware is enabled. This affects both PM resume method and cpuidle AFTR mode.
This patch shouldn't cause any functionality changes on boards that don't use secure firmware.
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com --- arch/arm/mach-exynos/pm.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 1679c51..18f6bf8 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -26,6 +26,7 @@ #include <asm/hardware/cache-l2x0.h> #include <asm/smp_scu.h> #include <asm/suspend.h> +#include <asm/firmware.h>
#include <plat/cpu.h> #include <plat/pm-common.h> @@ -167,6 +168,9 @@ static void exynos_cpu_restore_register(void) { unsigned long tmp;
+ if (call_firmware_op(c15resume, save_arm_register) == 0) + return; + /* Restore Power control register */ tmp = save_arm_register[0];
Add S5P_CENTRAL_SEQ_OPTION register setup for EXYNOS4x12 to AFTR mode code. Without this setup AFTR mode doesn't show any benefit over WFI one. When this setup is applied AFTR mode reduces power consumption by ~12% (as measured on Trats2 board).
This change is a preparation for adding secure firmware support to EXYNOS cpuidle driver.
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com --- arch/arm/mach-exynos/pm.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 18f6bf8..3922968 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -391,6 +391,10 @@ static int exynos_cpu_pm_notifier(struct notifier_block *self, case CPU_PM_ENTER: if (cpu == 0) { exynos_pm_central_suspend(); + if (soc_is_exynos4212() || soc_is_exynos4412()) + __raw_writel(S5P_USE_STANDBY_WFI0 | + S5P_USE_STANDBY_WFE0, + S5P_CENTRAL_SEQ_OPTION); exynos_cpu_save_register(); } break;
On 05/05/2014 12:57 PM, Bartlomiej Zolnierkiewicz wrote:
Add S5P_CENTRAL_SEQ_OPTION register setup for EXYNOS4x12 to AFTR mode code. Without this setup AFTR mode doesn't show any benefit over WFI one. When this setup is applied AFTR mode reduces power consumption by ~12% (as measured on Trats2 board).
This change is a preparation for adding secure firmware support to EXYNOS cpuidle driver.
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com
arch/arm/mach-exynos/pm.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 18f6bf8..3922968 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -391,6 +391,10 @@ static int exynos_cpu_pm_notifier(struct notifier_block *self, case CPU_PM_ENTER: if (cpu == 0) { exynos_pm_central_suspend();
if (soc_is_exynos4212() || soc_is_exynos4412())
__raw_writel(S5P_USE_STANDBY_WFI0 |
S5P_USE_STANDBY_WFE0,
S5P_CENTRAL_SEQ_OPTION);
Why not put this code in the exynos_enter_aftr() ?
exynos_cpu_save_register(); } break;
Hi,
On Friday, May 16, 2014 11:03:11 AM Daniel Lezcano wrote:
On 05/05/2014 12:57 PM, Bartlomiej Zolnierkiewicz wrote:
Add S5P_CENTRAL_SEQ_OPTION register setup for EXYNOS4x12 to AFTR mode code. Without this setup AFTR mode doesn't show any benefit over WFI one. When this setup is applied AFTR mode reduces power consumption by ~12% (as measured on Trats2 board).
This change is a preparation for adding secure firmware support to EXYNOS cpuidle driver.
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com
arch/arm/mach-exynos/pm.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 18f6bf8..3922968 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -391,6 +391,10 @@ static int exynos_cpu_pm_notifier(struct notifier_block *self, case CPU_PM_ENTER: if (cpu == 0) { exynos_pm_central_suspend();
if (soc_is_exynos4212() || soc_is_exynos4412())
__raw_writel(S5P_USE_STANDBY_WFI0 |
S5P_USE_STANDBY_WFE0,
S5P_CENTRAL_SEQ_OPTION);
Why not put this code in the exynos_enter_aftr() ?
I would prefer to keep this code close to exynos_pm_central_suspend() because exynos_pm_suspend() (which calls exynos_pm_central_suspend() too) also contains S5P_USE_STANDBY_WF[I,E]0 setting code (done for all SoCs). If possible I would like to make this code common for AFTR & suspend in the future (once it is tested on Exynos4210 and Exynos5250) by moving S5P_USE_STANDBY_WF[I,E]0 setting to exynos_pm_central_suspend() and doing it for all SoCs. Are you okay with this?
exynos_cpu_save_register(); } break;
Best regards, -- Bartlomiej Zolnierkiewicz Samsung R&D Institute Poland Samsung Electronics
On 06/02/2014 02:08 PM, Bartlomiej Zolnierkiewicz wrote:
Hi,
On Friday, May 16, 2014 11:03:11 AM Daniel Lezcano wrote:
On 05/05/2014 12:57 PM, Bartlomiej Zolnierkiewicz wrote:
Add S5P_CENTRAL_SEQ_OPTION register setup for EXYNOS4x12 to AFTR mode code. Without this setup AFTR mode doesn't show any benefit over WFI one. When this setup is applied AFTR mode reduces power consumption by ~12% (as measured on Trats2 board).
This change is a preparation for adding secure firmware support to EXYNOS cpuidle driver.
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com
arch/arm/mach-exynos/pm.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 18f6bf8..3922968 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -391,6 +391,10 @@ static int exynos_cpu_pm_notifier(struct notifier_block *self, case CPU_PM_ENTER: if (cpu == 0) { exynos_pm_central_suspend();
if (soc_is_exynos4212() || soc_is_exynos4412())
__raw_writel(S5P_USE_STANDBY_WFI0 |
S5P_USE_STANDBY_WFE0,
S5P_CENTRAL_SEQ_OPTION);
Why not put this code in the exynos_enter_aftr() ?
I would prefer to keep this code close to exynos_pm_central_suspend() because exynos_pm_suspend() (which calls exynos_pm_central_suspend() too) also contains S5P_USE_STANDBY_WF[I,E]0 setting code (done for all SoCs). If possible I would like to make this code common for AFTR & suspend in the future (once it is tested on Exynos4210 and Exynos5250) by moving S5P_USE_STANDBY_WF[I,E]0 setting to exynos_pm_central_suspend() and doing it for all SoCs. Are you okay with this?
Yeah, no problem.
exynos_cpu_save_register(); } break;
Best regards,
Bartlomiej Zolnierkiewicz Samsung R&D Institute Poland Samsung Electronics
* Use do_idle firmware method instead of cpu_do_idle() on boards with secure firmware enabled.
* Use S5P_VA_SYSRAM_NS + 0x24 address for exynos_boot_vector_addr() and S5P_VA_SYSRAM_NS + 0x20 one for exynos_boot_vector_flag() on boards with secure firmware enabled.
This patch fixes hang on an attempt to enter AFTR mode for TRATS2 board (which uses EXYNOS4412 SoC with secure firmware enabled).
This patch shouldn't cause any functionality changes on boards that don't use secure firmware.
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com --- arch/arm/mach-exynos/pm.c | 8 ++++++-- drivers/cpuidle/cpuidle-exynos.c | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 3922968..ba4cd05 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -104,7 +104,9 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
static inline void __iomem *exynos_boot_vector_addr(void) { - if (samsung_rev() == EXYNOS4210_REV_1_1) + if (firmware_run()) + return S5P_VA_SYSRAM_NS + 0x24; + else if (samsung_rev() == EXYNOS4210_REV_1_1) return S5P_INFORM7; else if (samsung_rev() == EXYNOS4210_REV_1_0) return S5P_VA_SYSRAM + 0x24; @@ -113,7 +115,9 @@ static inline void __iomem *exynos_boot_vector_addr(void)
static inline void __iomem *exynos_boot_vector_flag(void) { - if (samsung_rev() == EXYNOS4210_REV_1_1) + if (firmware_run()) + return S5P_VA_SYSRAM_NS + 0x20; + else if (samsung_rev() == EXYNOS4210_REV_1_1) return S5P_INFORM6; else if (samsung_rev() == EXYNOS4210_REV_1_0) return S5P_VA_SYSRAM + 0x20; diff --git a/drivers/cpuidle/cpuidle-exynos.c b/drivers/cpuidle/cpuidle-exynos.c index 7c01512..f90a4a0 100644 --- a/drivers/cpuidle/cpuidle-exynos.c +++ b/drivers/cpuidle/cpuidle-exynos.c @@ -17,13 +17,18 @@ #include <asm/proc-fns.h> #include <asm/suspend.h> #include <asm/cpuidle.h> +#include <asm/firmware.h>
static void (*exynos_enter_aftr)(void);
static int idle_finisher(unsigned long flags) { exynos_enter_aftr(); - cpu_do_idle(); + if (firmware_run()) + /* no need to check the return value on EXYNOS SoCs */ + call_firmware_op(do_idle, FW_DO_IDLE_AFTR); + else + cpu_do_idle();
return 1; }
linaro-kernel@lists.linaro.org