Hi,
This patch series adds support for AFTR idle mode on boards with secure firmware enabled and allows EXYNOS cpuidle driver usage on Exynos4x12 SoCs.
It has been tested on Trats2 board (using Exynos4412 SoC with secure firmware enabled) on which AFTR mode reduces power consumption by ~12% when EXYNOS cpuidle driver is enabled (in both cases the default exynos_defconfig config is used and CPU1-3 are offlined).
Currently Exynos4412 SoC support is limited to Trats2 board.
Depends on: - for-next branch of linux-samsung.git kernel tree - [PATCH v3 0/5] Firmware-assisted suspend/resume of Exynos SoCs (https://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg35921.html)
Changes since v6: - rebased on top of for-next branch of linux-samsung.git kernel tree + [PATCH v3 0/5] Firmware-assisted suspend/resume of Exynos SoCs (https://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg35921.html) - fixed build on Tegra - updated patch #2 summary line
Changes since v5: - rebased on top of next-20140904 + "irqchip: Properly fetch the per cpu offset" patch (https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg716674.html) [PATCH v3 0/5] Firmware-assisted suspend/resume of Exynos SoCs (https://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg35921.html) - limit Exynos4412 SoC support to Trats2 board for now
Changes since v4: - rebased on top of next-20140804 + [PATCH v5][next-20140804] ARM: EXYNOS: Fix suspend/resume sequences (http://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg35262.html) [PATCH v2 0/2] Firmware-assisted suspend/resume of Exynos SoCs (http://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg34282.html) - call exynos_save_cp15() only on A9 type core (this is needed for the future Exynos3250 SoC support)
Changes since v3: - rebased on top of next-20140804 + [PATCH v4][next-20140804] ARM: EXYNOS: Fix suspend/resume sequences (http://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg35192.html) [PATCH v2 0/2] Firmware-assisted suspend/resume of Exynos SoCs (http://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg34282.html) - (re-)added patch fixing S5P_CENTRAL_SEQ_OPTION register setup
Changes since v2: - rebased on top of next-20140708 + [PATCH 5/6] ARM: EXYNOS: Fix suspend/resume sequencies (http://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg32809.html) [with rejects fixed] [PATCH 6/6] ARM: EXYNOS: Register cpuidle device only on Exynos4210 and 5250 (http://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg32808.html) [PATCH 0/2] Firmware-assisted suspend/resume of Exynos SoCs (http://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg32991.html) [with rejects fixed in patch #2] - addressed review comments from Tomasz Figa and Daniel Lezcano
Changes since v1: - synced against next-20140602 - added missing Acked-by-s
Best regards, -- Bartlomiej Zolnierkiewicz Samsung R&D Institute Poland Samsung Electronics
Bartlomiej Zolnierkiewicz (5): ARM: EXYNOS: PM: replace EXYNOS_BOOT_VECTOR_* macros by static inlines ARM: add AFTR mode support to firmware do_idle method ARM: EXYNOS: cpuidle: add secure firmware support to AFTR mode code ARM: EXYNOS: PM: fix register setup for AFTR mode code ARM: EXYNOS: cpuidle: allow driver usage on Exynos4x12 SoCs
arch/arm/include/asm/firmware.h | 2 +- arch/arm/mach-exynos/common.h | 5 +++ arch/arm/mach-exynos/exynos.c | 5 ++- arch/arm/mach-exynos/firmware.c | 34 ++++++++++++++----- arch/arm/mach-exynos/pm.c | 60 ++++++++++++++++++++-------------- arch/arm/mach-tegra/cpuidle-tegra114.c | 2 +- 6 files changed, 72 insertions(+), 36 deletions(-)
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: Kyungmin Park kyungmin.park@samsung.com Acked-by: Daniel Lezcano daniel.lezcano@linaro.org --- v7: - no changes
arch/arm/mach-exynos/pm.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 047ac30..3407fc1 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -128,16 +128,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 ? \ - pmu_base_addr + S5P_INFORM7 : \ - (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (sysram_base_addr + 0x24) : \ - pmu_base_addr + S5P_INFORM0)) -#define EXYNOS_BOOT_VECTOR_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ - pmu_base_addr + S5P_INFORM6 : \ - (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (sysram_base_addr + 0x20) : \ - pmu_base_addr + S5P_INFORM1)) +static inline void __iomem *exynos_boot_vector_addr(void) +{ + if (samsung_rev() == EXYNOS4210_REV_1_1) + return pmu_base_addr + S5P_INFORM7; + else if (samsung_rev() == EXYNOS4210_REV_1_0) + return sysram_base_addr + 0x24; + return pmu_base_addr + S5P_INFORM0; +} + +static inline void __iomem *exynos_boot_vector_flag(void) +{ + if (samsung_rev() == EXYNOS4210_REV_1_1) + return pmu_base_addr + S5P_INFORM6; + else if (samsung_rev() == EXYNOS4210_REV_1_0) + return sysram_base_addr + 0x20; + return pmu_base_addr + S5P_INFORM1; +}
#define S5P_CHECK_AFTR 0xFCBA0D10 #define S5P_CHECK_SLEEP 0x00000BAD @@ -222,8 +229,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()); }
static int exynos_aftr_finisher(unsigned long flags)
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.
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com Acked-by: Kyungmin Park kyungmin.park@samsung.com --- v7: - fixed build on Tegra - updated summary line
arch/arm/include/asm/firmware.h | 2 +- arch/arm/mach-exynos/common.h | 5 +++++ arch/arm/mach-exynos/firmware.c | 10 ++++++++-- arch/arm/mach-tegra/cpuidle-tegra114.c | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 5904f59..89aefe1 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)(unsigned long mode); /* * Sets boot address of specified physical CPU */ diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index c218200..2d830df 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -119,6 +119,11 @@ extern void __iomem *sysram_base_addr; extern void __iomem *pmu_base_addr; void exynos_sysram_init(void);
+enum { + FW_DO_IDLE_SLEEP, + FW_DO_IDLE_AFTR, +}; + void exynos_firmware_init(void);
extern u32 exynos_get_eint_wake_mask(void); diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index f5e626d..e57b7c3 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -28,9 +28,15 @@ #define EXYNOS_BOOT_ADDR 0x8 #define EXYNOS_BOOT_FLAG 0xc
-static int exynos_do_idle(void) +static int exynos_do_idle(unsigned long 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_SLEEP: + exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + } return 0; }
diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index e3ebdce..425b6c8 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -49,7 +49,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, call_firmware_op(prepare_idle);
/* Do suspend by ourselves if the firmware does not implement it */ - if (call_firmware_op(do_idle) == -ENOSYS) + if (call_firmware_op(do_idle, 0) == -ENOSYS) cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
On 09/24/14 21:24, Bartlomiej Zolnierkiewicz wrote:
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.
Signed-off-by: Bartlomiej Zolnierkiewiczb.zolnierkie@samsung.com Acked-by: Kyungmin Parkkyungmin.park@samsung.com
v7:
fixed build on Tegra
updated summary line
arch/arm/include/asm/firmware.h | 2 +- arch/arm/mach-exynos/common.h | 5 +++++ arch/arm/mach-exynos/firmware.c | 10 ++++++++-- arch/arm/mach-tegra/cpuidle-tegra114.c | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 5904f59..89aefe1 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)(unsigned long mode); /*
*/
- Sets boot address of specified physical CPU
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index c218200..2d830df 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -119,6 +119,11 @@ extern void __iomem *sysram_base_addr; extern void __iomem *pmu_base_addr; void exynos_sysram_init(void);
+enum {
- FW_DO_IDLE_SLEEP,
- FW_DO_IDLE_AFTR,
+};
void exynos_firmware_init(void);
extern u32 exynos_get_eint_wake_mask(void);
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index f5e626d..e57b7c3 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -28,9 +28,15 @@ #define EXYNOS_BOOT_ADDR 0x8 #define EXYNOS_BOOT_FLAG 0xc
-static int exynos_do_idle(void) +static int exynos_do_idle(unsigned long 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_SLEEP:
exynos_smc(SMC_CMD_SLEEP, 0, 0, 0);
- } return 0; }
diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index e3ebdce..425b6c8 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -49,7 +49,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, call_firmware_op(prepare_idle);
/* Do suspend by ourselves if the firmware does not implement it */
- if (call_firmware_op(do_idle) == -ENOSYS)
if (call_firmware_op(do_idle, 0) == -ENOSYS) cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT,&dev->cpu);
+ Thierry(using nvidia.com e-mail address)
Hi Thierry,
For supporting AFTR mode in call_firmware_op(do_idle), need to modify tegra stuff as you can see. The functionality will be same with before. Is it OK to you? If you have no objection, I'd like to take this series into samsung tree.
Thanks, Kukjin
On Thu, Sep 25, 2014 at 05:23:32PM +0900, Kukjin Kim wrote:
On 09/24/14 21:24, Bartlomiej Zolnierkiewicz wrote:
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.
Signed-off-by: Bartlomiej Zolnierkiewiczb.zolnierkie@samsung.com Acked-by: Kyungmin Parkkyungmin.park@samsung.com
v7:
- fixed build on Tegra
- updated summary line
arch/arm/include/asm/firmware.h | 2 +- arch/arm/mach-exynos/common.h | 5 +++++ arch/arm/mach-exynos/firmware.c | 10 ++++++++-- arch/arm/mach-tegra/cpuidle-tegra114.c | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 5904f59..89aefe1 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)(unsigned long mode); /*
*/
- Sets boot address of specified physical CPU
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index c218200..2d830df 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -119,6 +119,11 @@ extern void __iomem *sysram_base_addr; extern void __iomem *pmu_base_addr; void exynos_sysram_init(void);
+enum {
- FW_DO_IDLE_SLEEP,
- FW_DO_IDLE_AFTR,
+};
void exynos_firmware_init(void);
extern u32 exynos_get_eint_wake_mask(void); diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index f5e626d..e57b7c3 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -28,9 +28,15 @@ #define EXYNOS_BOOT_ADDR 0x8 #define EXYNOS_BOOT_FLAG 0xc
-static int exynos_do_idle(void) +static int exynos_do_idle(unsigned long 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_SLEEP:
exynos_smc(SMC_CMD_SLEEP, 0, 0, 0);
- } return 0;
}
diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index e3ebdce..425b6c8 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -49,7 +49,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, call_firmware_op(prepare_idle);
/* Do suspend by ourselves if the firmware does not implement it */
- if (call_firmware_op(do_idle) == -ENOSYS)
if (call_firmware_op(do_idle, 0) == -ENOSYS) cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT,&dev->cpu);
- Thierry(using nvidia.com e-mail address)
Hi Thierry,
For supporting AFTR mode in call_firmware_op(do_idle), need to modify tegra stuff as you can see. The functionality will be same with before. Is it OK to you? If you have no objection, I'd like to take this series into samsung tree.
I'm only aware of any devices using TrustedFirmware on Tegra, which is what the above code handles. The implementation for TrustedFirmware does not implement do_idle() (yet?) so I don't think this patch would cause any damage.
Acked-by: Thierry Reding treding@nvidia.com
On 09/25/14 18:03, Thierry Reding wrote:
On Thu, Sep 25, 2014 at 05:23:32PM +0900, Kukjin Kim wrote:
On 09/24/14 21:24, Bartlomiej Zolnierkiewicz wrote:
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.
Signed-off-by: Bartlomiej Zolnierkiewiczb.zolnierkie@samsung.com Acked-by: Kyungmin Parkkyungmin.park@samsung.com
v7:
fixed build on Tegra
updated summary line
arch/arm/include/asm/firmware.h | 2 +- arch/arm/mach-exynos/common.h | 5 +++++ arch/arm/mach-exynos/firmware.c | 10 ++++++++-- arch/arm/mach-tegra/cpuidle-tegra114.c | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 5904f59..89aefe1 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)(unsigned long mode); /*
*/
- Sets boot address of specified physical CPU
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index c218200..2d830df 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -119,6 +119,11 @@ extern void __iomem *sysram_base_addr; extern void __iomem *pmu_base_addr; void exynos_sysram_init(void);
+enum {
- FW_DO_IDLE_SLEEP,
- FW_DO_IDLE_AFTR,
+};
void exynos_firmware_init(void);
extern u32 exynos_get_eint_wake_mask(void);
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index f5e626d..e57b7c3 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -28,9 +28,15 @@ #define EXYNOS_BOOT_ADDR 0x8 #define EXYNOS_BOOT_FLAG 0xc
-static int exynos_do_idle(void) +static int exynos_do_idle(unsigned long 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_SLEEP:
exynos_smc(SMC_CMD_SLEEP, 0, 0, 0);
- } return 0; }
diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index e3ebdce..425b6c8 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -49,7 +49,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, call_firmware_op(prepare_idle);
/* Do suspend by ourselves if the firmware does not implement it */
- if (call_firmware_op(do_idle) == -ENOSYS)
if (call_firmware_op(do_idle, 0) == -ENOSYS) cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT,&dev->cpu);
- Thierry(using nvidia.com e-mail address)
Hi Thierry,
For supporting AFTR mode in call_firmware_op(do_idle), need to modify tegra stuff as you can see. The functionality will be same with before. Is it OK to you? If you have no objection, I'd like to take this series into samsung tree.
I'm only aware of any devices using TrustedFirmware on Tegra, which is what the above code handles. The implementation for TrustedFirmware does not implement do_idle() (yet?) so I don't think this patch would cause any damage.
Acked-by: Thierry Redingtreding@nvidia.com
Thanks, I've applied this whole series.
- Kukjin
* Move cp15 registers saving to exynos_save_cp15() helper and add additional helper usage to do_idle firmware method.
* Use resume firmware method instead of exynos_cpu_restore_register() and skip exynos_cpu_save_register() on boards with secure firmware enabled.
* Use sysram_ns_base_addr + 0x24/0x20 addresses instead of the default ones used by exynos_cpu_set_boot_vector() on boards with secure firmware enabled.
* Use do_idle firmware method instead of cpu_do_idle() on boards with secure firmware enabled.
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com Acked-by: Kyungmin Park kyungmin.park@samsung.com --- v7: - no changes
arch/arm/mach-exynos/firmware.c | 24 +++++++++++++++++------- arch/arm/mach-exynos/pm.c | 17 ++++++++++++----- 2 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index e57b7c3..2c5bc6b 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -25,13 +25,28 @@ #include "smc.h"
#define EXYNOS_SLEEP_MAGIC 0x00000bad +#define EXYNOS_AFTR_MAGIC 0xfcba0d10 #define EXYNOS_BOOT_ADDR 0x8 #define EXYNOS_BOOT_FLAG 0xc
+static void exynos_save_cp15(void) +{ + /* Save Power control and Diagnostic registers */ + asm ("mrc p15, 0, %0, c15, c0, 0\n" + "mrc p15, 0, %1, c15, c0, 1\n" + : "=r" (cp15_save_power), "=r" (cp15_save_diag) + : : "cc"); +} + static int exynos_do_idle(unsigned long mode) { switch (mode) { case FW_DO_IDLE_AFTR: + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_save_cp15(); + __raw_writel(virt_to_phys(exynos_cpu_resume_ns), + sysram_ns_base_addr + 0x24); + __raw_writel(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20); exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0); break; case FW_DO_IDLE_SLEEP: @@ -96,13 +111,8 @@ static int exynos_cpu_suspend(unsigned long arg)
static int exynos_suspend(void) { - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { - /* Save Power control and Diagnostic registers */ - asm ("mrc p15, 0, %0, c15, c0, 0\n" - "mrc p15, 0, %1, c15, c0, 1\n" - : "=r" (cp15_save_power), "=r" (cp15_save_diag) - : : "cc"); - } + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_save_cp15();
writel(EXYNOS_SLEEP_MAGIC, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); writel(virt_to_phys(exynos_cpu_resume_ns), diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 3407fc1..6796fce 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -236,11 +236,19 @@ static void exynos_cpu_set_boot_vector(long flags)
static int exynos_aftr_finisher(unsigned long flags) { + int ret; + 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); - cpu_do_idle(); + + ret = call_firmware_op(do_idle, FW_DO_IDLE_AFTR); + if (ret == -ENOSYS) { + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_cpu_save_register(); + exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); + cpu_do_idle(); + }
return 1; } @@ -250,14 +258,13 @@ void exynos_enter_aftr(void) cpu_pm_enter();
exynos_pm_central_suspend(); - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - exynos_cpu_save_register();
cpu_suspend(0, exynos_aftr_finisher);
if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { scu_enable(S5P_VA_SCU); - exynos_cpu_restore_register(); + if (call_firmware_op(resume) == -ENOSYS) + exynos_cpu_restore_register(); }
exynos_pm_central_resume();
Add S5P_CENTRAL_SEQ_OPTION register setup to cpuidle AFTR mode code by moving the relevant code from exynos_pm_suspend() (used only by suspend) to exynos_pm_central_suspend() (used by both suspend and AFTR). Without this setup AFTR mode doesn't show any benefit over WFI one (at least on Exynos4412 SoC). 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 Acked-by: Kyungmin Park kyungmin.park@samsung.com --- v7: - no changes
arch/arm/mach-exynos/pm.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 6796fce..16c5c32 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -196,6 +196,10 @@ static void exynos_pm_central_suspend(void) tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); tmp &= ~S5P_CENTRAL_LOWPWR_CFG; pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); + + /* Setting SEQ_OPTION register */ + pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0, + S5P_CENTRAL_SEQ_OPTION); }
static int exynos_pm_central_resume(void) @@ -321,15 +325,8 @@ static void exynos_pm_prepare(void)
static int exynos_pm_suspend(void) { - unsigned long tmp; - exynos_pm_central_suspend();
- /* Setting SEQ_OPTION register */ - - tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0); - pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) exynos_cpu_save_register();
Register cpuidle platform device on Exynos4x12 SoCs allowing EXYNOS cpuidle driver usage on these SoCs.
AFTR mode reduces power consumption on Trats2 board (Exynos4412 SoC with secure firmware enabled) by ~12% when EXYNOS cpuidle driver is enabled (in both cases the default exynos_defconfig config is used and CPU1-3 are offlined).
Currently Exynos4412 SoC support is limited to Trats2 board.
Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com Acked-by: Kyungmin Park kyungmin.park@samsung.com --- v7: - no changes
arch/arm/mach-exynos/exynos.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index d57f136..2f2f7b2 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -319,7 +319,10 @@ static void __init exynos_dt_machine_init(void) exynos_sysram_init();
if (of_machine_is_compatible("samsung,exynos4210") || - of_machine_is_compatible("samsung,exynos5250")) + of_machine_is_compatible("samsung,exynos4212") || + (of_machine_is_compatible("samsung,exynos4412") && + of_machine_is_compatible("samsung,trats2")) || + of_machine_is_compatible("samsung,exynos5250")) platform_device_register(&exynos_cpuidle);
platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
linaro-kernel@lists.linaro.org