PSCI: Add pwr_domain_pwr_down_wfi() hook in plat_psci_ops

This patch adds a new optional platform hook `pwr_domain_pwr_down_wfi()` in
the plat_psci_ops structure. This hook allows the platform to perform platform
specific actions including the wfi invocation to enter powerdown. This hook
is invoked by both psci_do_cpu_off() and psci_cpu_suspend_start() functions.
The porting-guide.md is also updated for the same.

This patch also modifies the `psci_power_down_wfi()` function to invoke
`plat_panic_handler` incase of panic instead of the busy while loop.

Fixes ARM-Software/tf-issues#375

Change-Id: Iba104469a1445ee8d59fb3a6fdd0a98e7f24dfa3
This commit is contained in:
Soby Mathew 2016-04-27 14:46:28 +01:00
parent e141aa0357
commit ac1cc8eb76
5 changed files with 36 additions and 9 deletions

View file

@ -1715,6 +1715,22 @@ latter case, the power domain is expected to save enough state so that it can
resume execution by restoring this state when its powered on (see
`pwr_domain_suspend_finish()`).
#### plat_psci_ops.pwr_domain_pwr_down_wfi()
This is an optional function and, if implemented, is expected to perform
platform specific actions including the `wfi` invocation which allows the
CPU to powerdown. Since this function is invoked outside the PSCI locks,
the actions performed in this hook must be local to the CPU or the platform
must ensure that races between multiple CPUs cannot occur.
The `target_state` has a similar meaning as described in the `pwr_domain_off()`
operation and it encodes the platform coordinated target local power states for
the CPU power domain and its parent power domain levels. This function must
not return back to the caller.
If this function is not implemented by the platform, PSCI generic
implementation invokes `psci_power_down_wfi()` for power down.
#### plat_psci_ops.pwr_domain_on_finish()
This function is called by the PSCI implementation after the calling CPU is

View file

@ -265,6 +265,8 @@ typedef struct plat_psci_ops {
void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);
void (*pwr_domain_suspend_finish)(
const psci_power_state_t *target_state);
void (*pwr_domain_pwr_down_wfi)(
const psci_power_state_t *target_state) __dead2;
void (*system_off)(void) __dead2;
void (*system_reset)(void) __dead2;
int (*validate_power_state)(unsigned int power_state,

View file

@ -106,7 +106,6 @@ endfunc psci_entrypoint
func psci_power_down_wfi
dsb sy // ensure write buffer empty
wfi
wfi_spill:
b wfi_spill
bl plat_panic_handler
endfunc psci_power_down_wfi

View file

@ -138,11 +138,16 @@ exit:
dsbish();
inv_cpu_data(psci_svc_cpu_data.aff_info_state);
/*
* Enter a wfi loop which will allow the power controller to
* physically power down this cpu.
*/
psci_power_down_wfi();
if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi) {
/* This function must not return */
psci_plat_pm_ops->pwr_domain_pwr_down_wfi(&state_info);
} else {
/*
* Enter a wfi loop which will allow the power
* controller to physically power down this cpu.
*/
psci_power_down_wfi();
}
}
return rc;

View file

@ -189,8 +189,13 @@ exit:
if (skip_wfi)
return;
if (is_power_down_state)
psci_power_down_wfi();
if (is_power_down_state) {
/* The function calls below must not return */
if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi)
psci_plat_pm_ops->pwr_domain_pwr_down_wfi(state_info);
else
psci_power_down_wfi();
}
/*
* We will reach here if only retention/standby states have been