clear wakeup enable bit upon resuming from suspend

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
This commit is contained in:
Achin Gupta 2013-11-12 16:40:00 +00:00 committed by Dan Handley
parent 4a826ddad8
commit b127cdb879
4 changed files with 21 additions and 3 deletions

View File

@ -45,6 +45,9 @@ Detailed changes since last release
instructions for how to contribute and update copyright text in all files to instructions for how to contribute and update copyright text in all files to
acknowledge contributors. 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 ARM Trusted Firmware - version 0.2
================================== ==================================

View File

@ -77,7 +77,7 @@ void fvp_pwrc_write_ppoffr(unsigned long mpidr)
bakery_lock_release(mpidr, &pwrc_lock); 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); bakery_lock_get(mpidr, &pwrc_lock);
mmio_write_32(PWRC_BASE + PWKUPR_OFF, 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); 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) void fvp_pwrc_write_pcoffr(unsigned long mpidr)
{ {
bakery_lock_get(mpidr, &pwrc_lock); bakery_lock_get(mpidr, &pwrc_lock);

View File

@ -67,7 +67,8 @@ extern int fvp_pwrc_setup(void);
extern void fvp_pwrc_write_pcoffr(unsigned long); extern void fvp_pwrc_write_pcoffr(unsigned long);
extern void fvp_pwrc_write_ppoffr(unsigned long); extern void fvp_pwrc_write_ppoffr(unsigned long);
extern void fvp_pwrc_write_pponr(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_read_psysr(unsigned long);
extern unsigned int fvp_pwrc_get_cpu_wkr(unsigned long); extern unsigned int fvp_pwrc_get_cpu_wkr(unsigned long);

View File

@ -251,7 +251,7 @@ int fvp_affinst_suspend(unsigned long mpidr,
* Program the power controller to power this * Program the power controller to power this
* cpu off and enable wakeup interrupts. * cpu off and enable wakeup interrupts.
*/ */
fvp_pwrc_write_pwkupr(mpidr); fvp_pwrc_set_wen(mpidr);
fvp_pwrc_write_ppoffr(mpidr); fvp_pwrc_write_ppoffr(mpidr);
} }
break; break;
@ -309,6 +309,12 @@ int fvp_affinst_on_finish(unsigned long mpidr,
write_cpuectlr(ectlr); 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 */ /* Zero the jump address in the mailbox for this cpu */
fvp_mboxes = (mailbox *) (TZDRAM_BASE + MBOX_OFF); fvp_mboxes = (mailbox *) (TZDRAM_BASE + MBOX_OFF);
linear_id = platform_get_core_pos(mpidr); linear_id = platform_get_core_pos(mpidr);