clear wakeup enable bit upon resuming from suspend
authorAchin Gupta <achin.gupta@arm.com>
Tue, 12 Nov 2013 16:40:00 +0000 (16:40 +0000)
committerDan Handley <dan.handley@arm.com>
Thu, 5 Dec 2013 12:28:50 +0000 (12:28 +0000)
The FVP specific code that gets called after a cpu has been physically
powered on after having been turned off or suspended earlier does not
clear the PWRC.PWKUPR.WEN bit. Not doing so causes problems if: a cpu
is suspended, woken from suspend, powered down through a cpu_off call
& receives a spurious interrupt. Since the WEN bit is not cleared
after the cpu woke up from suspend, the spurious wakeup will power the
cpu on. Since the cpu_off call clears the jump address in the mailbox
this spurious wakeup will cause the cpu to crash.

This patch fixes this issue by clearing the WEN bit whenever a cpu is
powered up.

Change-Id: Ic91f5dffe1ed01d76bc7fc807acf0ecd3e38ce5b

docs/change-log.md
drivers/power/fvp_pwrc.c
drivers/power/fvp_pwrc.h
plat/fvp/fvp_pm.c

index 841def96ad5241d5a2e3bfbc63e376ca381b0f0b..3ae5fabe953a929744d08f548f9de2999ee9e3bb 100644 (file)
@@ -45,6 +45,9 @@ Detailed changes since last release
     instructions for how to contribute and update copyright text in all files to
     acknowledge contributors.
 
+*   The wake up enable bit in the FVP power controller is cleared when a cpu is
+    physically powered up to prevent a spurious wake up from a subsequent cpu
+    off state.
 
 ARM Trusted Firmware - version 0.2
 ==================================
index 2b98b054d2f6dcad730462900f344117e3b74e50..cbaaa3d4a5164f384a6582f55759ac12b2f22d7a 100644 (file)
@@ -77,7 +77,7 @@ void fvp_pwrc_write_ppoffr(unsigned long mpidr)
        bakery_lock_release(mpidr, &pwrc_lock);
 }
 
-void fvp_pwrc_write_pwkupr(unsigned long mpidr)
+void fvp_pwrc_set_wen(unsigned long mpidr)
 {
        bakery_lock_get(mpidr, &pwrc_lock);
        mmio_write_32(PWRC_BASE + PWKUPR_OFF,
@@ -85,6 +85,14 @@ void fvp_pwrc_write_pwkupr(unsigned long mpidr)
        bakery_lock_release(mpidr, &pwrc_lock);
 }
 
+void fvp_pwrc_clr_wen(unsigned long mpidr)
+{
+       bakery_lock_get(mpidr, &pwrc_lock);
+       mmio_write_32(PWRC_BASE + PWKUPR_OFF,
+                     (unsigned int) mpidr);
+       bakery_lock_release(mpidr, &pwrc_lock);
+}
+
 void fvp_pwrc_write_pcoffr(unsigned long mpidr)
 {
        bakery_lock_get(mpidr, &pwrc_lock);
index 050c33b64ba60b4a5d2d1d1005de62abb6bd771d..73d36df7a027855738d3dfc9cb4e2f5555e3ce23 100644 (file)
@@ -67,7 +67,8 @@ extern int fvp_pwrc_setup(void);
 extern void fvp_pwrc_write_pcoffr(unsigned long);
 extern void fvp_pwrc_write_ppoffr(unsigned long);
 extern void fvp_pwrc_write_pponr(unsigned long);
-extern void fvp_pwrc_write_pwkupr(unsigned long);
+extern void fvp_pwrc_set_wen(unsigned long);
+extern void fvp_pwrc_clr_wen(unsigned long);
 extern unsigned int fvp_pwrc_read_psysr(unsigned long);
 extern unsigned int fvp_pwrc_get_cpu_wkr(unsigned long);
 
index fd92526d5bc7562922450057794f157b4626fdfd..658a28594110ec9c30c2a3ef7086004b01b6f887 100644 (file)
@@ -251,7 +251,7 @@ int fvp_affinst_suspend(unsigned long mpidr,
                         * Program the power controller to power this
                         * cpu off and enable wakeup interrupts.
                         */
-                       fvp_pwrc_write_pwkupr(mpidr);
+                       fvp_pwrc_set_wen(mpidr);
                        fvp_pwrc_write_ppoffr(mpidr);
                }
                break;
@@ -309,6 +309,12 @@ int fvp_affinst_on_finish(unsigned long mpidr,
                        write_cpuectlr(ectlr);
                }
 
+               /*
+                * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
+                * with a cpu power down unless the bit is set again
+                */
+               fvp_pwrc_clr_wen(mpidr);
+
                /* Zero the jump address in the mailbox for this cpu */
                fvp_mboxes = (mailbox *) (TZDRAM_BASE + MBOX_OFF);
                linear_id = platform_get_core_pos(mpidr);