aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-ux500/prcmu-fw.c
diff options
context:
space:
mode:
authorSundar R Iyer <sundar.iyer@stericsson.com>2010-04-19 11:53:12 +0530
committerJohn Rigby <john.rigby@linaro.org>2010-09-02 22:45:25 -0600
commit5d3f6b387faafb9690a891f99d5ea050963eb3d7 (patch)
tree9b972a3b26814e8fc1018dc753a066aaa93271c9 /arch/arm/mach-ux500/prcmu-fw.c
parentc82a2e5b581f3adf7539aaacea8bf9ccc854f69d (diff)
ux500-pm: "ApDeepSleep" low power state support
This patch adds the "ApDeepSleep" low power state for the U8500 platform. The ApDeepSleep is the lowest power state, both the core/ape turned off. This low power mode can now be entered/exited through the standard linux PM framework echo mem > /sys/power/state will put the core into the deep sleep state. The system can be woken up from USB insertion, console, RTC events back to the execute mode. This patch - cleans existing non-working deepsleep code from PRCMU f/w file - cleans redundant code for cpu hotplug - re-orgs the platform pm.c file for supporting uart2/gic/icn/prcc peripheral contexts - fixes FIDO_IR_ER: 258539, make UART2 console as a wakeup event - incorporates review comments from gerrit The "ApSleep" power state can now be entered through the echo standby > /sys/power/state command. FIDO_IR_ER: 258539, add deep sleep support FIDO_IR_ER: 258539, make UART2 console as a wakeup event Signed-off-by: Sundar R Iyer <sundar.iyer@stericsson.com> Acked-By: Biju C Das <biju.das@stericsson.com> Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> Change-Id: I1ebb7fc193ec7dcea765c300277042464868493c Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/2355 Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'arch/arm/mach-ux500/prcmu-fw.c')
-rwxr-xr-xarch/arm/mach-ux500/prcmu-fw.c448
1 files changed, 9 insertions, 439 deletions
diff --git a/arch/arm/mach-ux500/prcmu-fw.c b/arch/arm/mach-ux500/prcmu-fw.c
index ef39dceb4f7..bdce3c9c6af 100755
--- a/arch/arm/mach-ux500/prcmu-fw.c
+++ b/arch/arm/mach-ux500/prcmu-fw.c
@@ -29,8 +29,6 @@
(printk(KERN_ALERT NAME ": " format , ## arg)) : \
({do {} while (0); })
-void __iomem *rtc_register_base ;
-
struct hw_usage{
char b2r2:1;
char mcde:1;
@@ -747,222 +745,6 @@ int prcmu_set_irq_wakeup(uint32_t irq)
}
EXPORT_SYMBOL(prcmu_set_irq_wakeup);
-/* FIXME : Make these generic enough to pass backup
- * addresses for re-using the same functions
- * for sleep/deep sleep modes
- */
-/* Context Backups for ApSleep */
-unsigned int PRCC_backup[15];
-
-#define _PRCC_CLK_RST1_BASE IO_ADDRESS(U8500_PER1_BASE + 0xF000)
-#define _PRCC_CLK_RST2_BASE IO_ADDRESS(U8500_PER2_BASE + 0xF000)
-#define _PRCC_CLK_RST3_BASE IO_ADDRESS(U8500_PER3_BASE + 0xF000)
-#define _PRCC_CLK_RST5_BASE IO_ADDRESS(U8500_PER5_BASE + 0x1F000)
-#define _PRCC_CLK_RST6_BASE IO_ADDRESS(U8500_PER6_BASE + 0xF000)
-
-void pm_save_config_PRCC(void)
-{
- uint8_t i = 0;
-
- PRCC_backup[i++] = readl(_PRCC_CLK_RST1_BASE + 0x10);
- PRCC_backup[i++] = readl(_PRCC_CLK_RST1_BASE + 0x14);
- PRCC_backup[i++] = readl(_PRCC_CLK_RST2_BASE + 0x10);
- PRCC_backup[i++] = readl(_PRCC_CLK_RST2_BASE + 0x14);
- PRCC_backup[i++] = readl(_PRCC_CLK_RST3_BASE + 0x10);
- PRCC_backup[i++] = readl(_PRCC_CLK_RST3_BASE + 0x14);
- PRCC_backup[i++] = readl(_PRCC_CLK_RST5_BASE + 0x10);
- PRCC_backup[i++] = readl(_PRCC_CLK_RST5_BASE + 0x14);
- PRCC_backup[i++] = readl(_PRCC_CLK_RST6_BASE + 0x10);
- PRCC_backup[i++] = readl(_PRCC_CLK_RST6_BASE + 0x14);
-}
-
-void pm_restore_config_PRCC(void)
-{
- uint8_t i = 0;
-
- writel(PRCC_backup[i++], _PRCC_CLK_RST1_BASE + 0x0);
- writel(PRCC_backup[i++], _PRCC_CLK_RST1_BASE + 0x8);
- writel(PRCC_backup[i++], _PRCC_CLK_RST2_BASE + 0x0);
- writel(PRCC_backup[i++], _PRCC_CLK_RST2_BASE + 0x8);
- writel(PRCC_backup[i++], _PRCC_CLK_RST3_BASE + 0x0);
- writel(PRCC_backup[i++], _PRCC_CLK_RST3_BASE + 0x8);
- writel(PRCC_backup[i++], _PRCC_CLK_RST5_BASE + 0x0);
- writel(PRCC_backup[i++], _PRCC_CLK_RST5_BASE + 0x8);
- writel(PRCC_backup[i++], _PRCC_CLK_RST6_BASE + 0x0);
- writel(PRCC_backup[i++], _PRCC_CLK_RST6_BASE + 0x8);
-}
-
-void __iomem *uart_backup_base, *uart_register_base;
-
-/* TODO : return success value to let decide to proceed
- * for low power request or not
- */
-void pm_save_config_UART(void)
-{
- uart_register_base = ioremap(U8500_UART2_BASE, SZ_4K);
- if (!uart_register_base) {
- printk(KERN_WARNING
- "u8500-prcm : cannot allocate uart register base\n");
- }
-
- uart_backup_base = kzalloc(SZ_4K, GFP_KERNEL);
- if (!uart_backup_base) {
- printk(KERN_WARNING
- "u8500-prcm : cannot allocate uart register backup base\n");
- }
-
- /* Copy UART config */
- memcpy(uart_backup_base, uart_register_base, SZ_4K);
-}
-
-void __iomem *ab8500_backup_base, *ab8500_register_base;
-
-void pm_restore_config_UART(void)
-{
- memcpy(uart_register_base, uart_backup_base, SZ_4K);
-}
-
-/* Deep Sleep context save */
-
-/* public context backup */
-/* TODO : remove hard coded backup RAM addresses */
-void a9ss_save_public_config(void)
-{
- int val;
-
- /* this happens for CPU0 only as of now */
- /* CP15 SCTLR */
- __asm__ __volatile__(
- "mrc p15, 0, %0, c1, c1, 2"
- : "=r" (val)
- :
- : "cc");
- writel(val, IO_ADDRESS(0x80151F80));
-
- /* CP15 TTBR0 */
- __asm__ __volatile__(
- "mrc p15, 0, %0, c2, c0, 0"
- : "=r" (val)
- :
- : "cc");
- writel(val, IO_ADDRESS(0x80151F84));
-
- /* CP15 TTBR1 */
- __asm__ __volatile__(
- "mrc p15, 0, %0, c2, c0, 1"
- : "=r" (val)
- :
- : "cc");
- writel(val, IO_ADDRESS(0x80151F88));
-
- /* CP15 TTBCR */
- __asm__ __volatile__(
- "mrc p15, 0, %0, c2, c0, 2"
- : "=r" (val)
- :
- : "cc");
- writel(val, IO_ADDRESS(0x80151F8C));
-
- /* CP15 DACR */
- __asm__ __volatile__(
- "mrc p15, 0, %0, c3, c0, 0"
- : "=r" (val)
- :
- : "cc");
- writel(val, IO_ADDRESS(0x80151F90));
-
- /* CPSR */
- __asm__ __volatile__(
- "mrs %0, cpsr"
- : "=r" (val)
- :
- : "cc");
- writel(val, IO_ADDRESS(0x80151F98));
-
- return;
-}
-
-void a9ss_restore_public_config(void)
-{
- int val;
-
- /* CPSR */
- val = readl(IO_ADDRESS(0x80151F98));
- __asm__ __volatile__(
- "msr cpsr, %0"
- :
- : "r" (val));
-
- /* CP15 DACR */
- val = readl(IO_ADDRESS(0x80151F90));
- __asm__ __volatile__(
- "mcr p15, 0, %0, c3, c0, 0"
- :
- : "r" (val));
-
- /* CP15 TTBCR */
- val = readl(IO_ADDRESS(0x80151F8C));
- __asm__ __volatile__(
- "mcr p15, 0, %0, c2, c0, 2"
- :
- : "r" (val));
-
- /* CP15 TTBR1 */
- val = readl(IO_ADDRESS(0x80151F88));
- __asm__ __volatile__(
- "mcr p15, 0, %0, c2, c0, 1"
- :
- : "r" (val));
-
- /* CP15 TTBR0 */
- val = readl(IO_ADDRESS(0x80151F84));
- __asm__ __volatile__(
- "mcr p15, 0, %0, c2, c0, 0"
- :
- : "r" (val));
-
- /* CP15 SCTLR */
- val = readl(IO_ADDRESS(0x80151F80));
- __asm__ __volatile__(
- "mrc p15, 0, %0, c1, c1, 2"
- :
- : "r" (val));
-
- return;
-}
-
-/* ARM SCU backup */
-#include <mach/scu.h>
-unsigned int scu_backup_config[5];
-
-void a9ss_save_scu_config(void)
-{
- scu_backup_config[0] = __raw_readl(IO_ADDRESS(U8500_SCU_BASE)
- + SCU_CTRL);
- scu_backup_config[1] = __raw_readl(IO_ADDRESS(U8500_SCU_BASE)
- + SCU_CONFIG);
- scu_backup_config[2] = __raw_readl(IO_ADDRESS(U8500_SCU_BASE)
- + SCU_CPU_STATUS);
- scu_backup_config[3] = __raw_readl(IO_ADDRESS(U8500_SCU_BASE)
- + SCU_INVALIDATE);
-
- return;
-}
-
-void a9ss_restore_scu_config(void)
-{
- __raw_writel(scu_backup_config[0], IO_ADDRESS(U8500_SCU_BASE)
- + SCU_CTRL);
- __raw_writel(scu_backup_config[1], IO_ADDRESS(U8500_SCU_BASE)
- + SCU_CONFIG);
- __raw_writel(scu_backup_config[2], IO_ADDRESS(U8500_SCU_BASE)
- + SCU_CPU_STATUS);
- __raw_writel(scu_backup_config[3], IO_ADDRESS(U8500_SCU_BASE)
- + SCU_INVALIDATE);
-
- return;
-}
-
/* FIXME : get these from platform/header files instead */
/* GIC BAse Address */
#define GIC_BASE_ADDR IO_ADDRESS(0xA0411000)
@@ -975,9 +757,6 @@ void a9ss_restore_scu_config(void)
#define DIST_ENABLE_CLEAR (GIC_BASE_ADDR + 0x180)
#define DIST_ACTIVE_BIT (GIC_BASE_ADDR + 0x304)
-#define PRCM_DEBUG_NOPWRDOWN_VAL IO_ADDRESS(0x80157194)
-#define PRCM_POWER_STATE_VAL IO_ADDRESS(0x8015725C)
-
/**
* prcmu_apply_ap_state_transition - PRCMU State Transition function
* @transition: Transition to be requested to move to new AP power mode
@@ -997,6 +776,7 @@ void a9ss_restore_scu_config(void)
* not support it. This also assumes that the non-boot cpu's are in wfi
* and not wfe.
*/
+
int prcmu_apply_ap_state_transition(enum ap_pwrst_trans_t transition,
enum ddr_pwrst_t ddr_state_req,
int _4500_fifo_wakeup)
@@ -1038,118 +818,6 @@ int prcmu_apply_ap_state_transition(enum ap_pwrst_trans_t transition,
}
switch (transition) {
- case APEXECUTE_TO_APSLEEP:
-
- /* PROGRAM THE ITMASK* registers for a Sleep */
- writel(0x00000000, PRCM_ARMITMSK31TO0);
- writel(0x00000100, PRCM_ARMITMSK63TO32);
- writel(0x00000000, PRCM_ARMITMSK95TO64);
- writel(0x00000000, PRCM_ARMITMSK127TO96);
-
- /* probe the GIC if its already frozen */
- tmp = readl(PRCM_A9_MASK_ACK);
- if (tmp & 0x00000001)
- printk(KERN_WARNING "GIC is already frozen\n");
-
- /* write to GIC freeze */
- tmp = readl(PRCM_A9_MASK_REQ);
- tmp |= 0x01;
- writel(tmp, PRCM_A9_MASK_REQ);
-
- /* we wait for a random timeout. as of now the
- * the GIC freeze isnt ACKed; so wait
- */
- timeout = 100;
- while (timeout--)
- cpu_relax();
-
- prcmu_configure_wakeup_events(0xFFFFFFFF, 0x0,
- LOW_POWER_WAKEUP);
-
- spin_lock(&req_mb0_lock);
-
- /* CREATE MAILBOX FOR EXECUTE TO IDLE POWER TRANSITION */
- /* Write PwrStTrH=0 header to request a Power state xsition */
- writeb(0x0, PRCM_MBOX_HEADER_REQ_MB0);
-
- /* write request to the MBOX0 */
- writeb(APEXECUTE_TO_APSLEEP, PRCM_REQ_MB0_PWRSTTRH_APPWRST);
- writeb(OFF, PRCM_REQ_MB0_PWRSTTRH_APPLLST);
- writeb(ON, PRCM_REQ_MB0_PWRSTTRH_ULPCLKST);
- writeb(0x56, PRCM_REQ_MB0_PWRSTTRH_BYTEFILL);
-
- /* As per the sync logic, we are supposed to be the final CPU.
- * If the other CPU isnt in wfi, better exit by putting
- * ourselves in wfi
- */
- if (smp_processor_id()) {
- if (!(readl(PRCM_ARM_WFI_STANDBY) & 0x8)) {
- spin_unlock(&req_mb0_lock);
- __asm__ __volatile__(
- "dsb\n\t" "wfi\n\t" : : : "memory");
- return 0;
- }
- } else /* running on CPU0, check for CPU1 WFI standby */ {
- if (!(readl(PRCM_ARM_WFI_STANDBY) & 0x10)) {
- spin_unlock(&req_mb0_lock);
- __asm__ __volatile__(
- "dsb\n\t" "wfi\n\t" : : : "memory");
- return 0;
- }
- }
-
- /* Enable RTC-INT in the GIC */
- if (!(readl(PRCM_ARMITMSK31TO0) & 0x40000))
- writel((readl(PRCM_ARMITMSK31TO0) | 0x40000),
- PRCM_ARMITMSK31TO0);
-
-
- /* FIXME : later on, the ARM should not request a Idle if one
- * of the ITSTATUS0/5 are still alive!!!
- */
- if (readl(PRCM_ITSTATUS0) == 0x80) {
- printk(KERN_WARNING "PRCM_ITSTATUS0 Not cleared\n");
- spin_unlock(&req_mb0_lock);
- __asm__ __volatile__(
- "dsb\n\t" "wfi\n\t" : : : "memory");
- return -EBUSY;
- }
-
- /*
- *
- * REQUEST POWER XSITION
- *
- */
-
- /* clear ACK MB0 */
- writeb(0x0, PRCM_ACK_MB0);
-
- _wait_for_req_complete(REQ_MB0);
-
- spin_unlock(&req_mb0_lock);
-
- printk(KERN_INFO "u8500-prcm : To ApSleep\n");
-
- /* Context Saving beings */
-
- pm_save_config_PRCC();
-
- pm_save_config_UART();
-
- /* here comes the wfi */
- __asm__ __volatile__(
- "dsb\n\t" "wfi\n\t" : : : "memory");
-
- /* Restore PRCC Configs */
- pm_restore_config_PRCC();
-
- /* Restore UART Configs */
- pm_restore_config_UART();
-
- if (readb(PRCM_ACK_MB0_AP_PWRST_STATUS) == 0xF3)
- printk(KERN_INFO "u8500-prcm : Woken from Sleep OK\n");
-
- break;
case APEXECUTE_TO_APIDLE:
/* Copy the current GIC set enable config as wakeup */
for (val = 0; val < 4; val++) {
@@ -1159,20 +827,6 @@ int prcmu_apply_ap_state_transition(enum ap_pwrst_trans_t transition,
prcmu_configure_wakeup_events(((1 << 17) | (1 << 5)),
0x0, EXE_WAKEUP);
-#if 0
- /* SIGNAL MAILBOX */
- /* set the MBOX_CPU_SET bit to set an IT to xP70 */
- writel(1 << 0, PRCM_MBOX_CPU_SET);
-
- /* wait for corresponding MB0X_CPU_VAL bit to be cleared */
- while ((readl(PRCM_MBOX_CPU_VAL) & (1 << 0)) && timeout--)
- cpu_relax();
- if (!timeout) {
- printk(KERN_INFO
- "Timeout in prcmu_configure_wakeup_events!!\n");
- return -EBUSY;
- }
-#endif
spin_lock(&req_mb0_lock);
/* CREATE MAILBOX FOR EXECUTE TO IDLE POWER TRANSITION */
@@ -1247,111 +901,27 @@ int prcmu_apply_ap_state_transition(enum ap_pwrst_trans_t transition,
prcmu_configure_wakeup_events((1 << 5), 0x0, EXE_WAKEUP);
break;
- case APEXECUTE_TO_APDEEPSLEEP:
- /* PROGRAM THE ITMASK* registers for deep sleep */
- writel(0x00000000, PRCM_ARMITMSK31TO0);
- writel(0x00000100, PRCM_ARMITMSK63TO32);
- writel(0x00000000, PRCM_ARMITMSK95TO64);
- writel(0x00000000, PRCM_ARMITMSK127TO96);
-
- /* we skip the GIC freeze due to the FIQ being
- * not handled by the ARM later on
- */
- prcmu_configure_wakeup_events(((1 << 17) | (1 << 5)),
- 0x0, LOW_POWER_WAKEUP);
- spin_lock(&req_mb0_lock);
-
- /* CREATE MAILBOX FOR EXECUTE TO IDLE POWER TRANSITION */
+ case APEXECUTE_TO_APSLEEP:
+ case APEXECUTE_TO_APDEEPSLEEP:
/* Write PwrStTrH=0 header to request a Power state xsition */
writeb(0x0, PRCM_MBOX_HEADER_REQ_MB0);
/* write request to the MBOX0 */
- writeb(APEXECUTE_TO_APDEEPSLEEP, PRCM_REQ_MB0_PWRSTTRH_APPWRST);
- writeb(OFF, PRCM_REQ_MB0_PWRSTTRH_APPLLST);
- writeb(ON, PRCM_REQ_MB0_PWRSTTRH_ULPCLKST);
- writeb(0x56, PRCM_REQ_MB0_PWRSTTRH_BYTEFILL);
-
- /* As per the sync logic, we are supposed to be the final CPU.
- * If the other CPU isnt in wfi, better exit by putting
- * ourselves in wfi
- */
- if (smp_processor_id()) {
- if (!(readl(PRCM_ARM_WFI_STANDBY) & 0x8)) {
- spin_unlock(&req_mb0_lock);
- __asm__ __volatile__(
- "dsb\n\t" "wfi\n\t" : : : "memory");
- return 0;
- }
- } else /* running on CPU0, check for CPU1 WFI standby */ {
- if (!(readl(PRCM_ARM_WFI_STANDBY) & 0x10)) {
- spin_unlock(&req_mb0_lock);
- __asm__ __volatile__(
- "dsb\n\t" "wfi\n\t" : : : "memory");
- return 0;
- }
- }
-
- /* Enable RTC-INT in the GIC */
- if (!(readl(PRCM_ARMITMSK31TO0) & 0x40000))
- writel((readl(PRCM_ARMITMSK31TO0) | 0x40000),
- PRCM_ARMITMSK31TO0);
-
-
- /* FIXME : later on, the ARM should not request a Idle if one
- * of the ITSTATUS0/5 are still alive!!!
- */
- if (readl(PRCM_ITSTATUS0) == 0x80) {
- printk(KERN_WARNING "PRCM_ITSTATUS0 Not cleared\n");
- spin_unlock(&req_mb0_lock);
- __asm__ __volatile__(
- "dsb\n\t" "wfi\n\t" : : : "memory");
- return -EBUSY;
- }
-
- /*
- *
- * REQUEST POWER XSITION
- *
- */
-
- /* clear ACK MB0 */
- writeb(0x0, PRCM_ACK_MB0);
-
- _wait_for_req_complete(REQ_MB0);
- spin_unlock(&req_mb0_lock);
-
- printk(KERN_INFO "u8500-prcm : To Sleep\n");
+ writeb(transition, PRCM_REQ_MB0_PWRSTTRH_APPWRST);
+ writeb(0x1, PRCM_REQ_MB0_PWRSTTRH_APPLLST);
+ writeb(0x1, PRCM_REQ_MB0_PWRSTTRH_ULPCLKST);
- /* Restore PRCC configs */
- pm_save_config_PRCC();
-
- pm_save_config_UART();
-
- a9ss_save_public_config();
-
- /* here comes the wfi */
- __asm__ __volatile__(
- "dsb\n\t" "wfi\n\t" : : : "memory");
-
- /* Restore PRCC Configs */
- pm_restore_config_PRCC();
-
- /* Restore UART Configs */
- pm_restore_config_UART();
-
- if (readb(PRCM_ACK_MB0_AP_PWRST_STATUS) == 0xF3)
- printk(KERN_INFO "u8500-prcm : Woken from Sleep OK\n");
+ /* Execute PRCMU command */
+ writel(1, PRCM_MBOX_CPU_SET);
- break;
- case APBOOT_TO_APEXECUTE:
+ __asm__ __volatile__("dsb\n\t" "wfi\n\t" : : : "memory");
break;
default:
ret = -EINVAL;
}
return ret;
-
}
EXPORT_SYMBOL(prcmu_apply_ap_state_transition);