Commit d5f13093 authored by Juan Castillo's avatar Juan Castillo Committed by Dan Handley
Browse files

Add support for PSCI SYSTEM_OFF and SYSTEM_RESET APIs

This patch adds support for SYSTEM_OFF and SYSTEM_RESET PSCI
operations. A platform should export handlers to complete the
requested operation. The FVP port exports fvp_system_off() and
fvp_system_reset() as an example.

If the SPD provides a power management hook for system off and
system reset, then the SPD is notified about the corresponding
operation so it can do some bookkeeping. The TSPD exports
tspd_system_off() and tspd_system_reset() for that purpose.

Versatile Express shutdown and reset methods have been removed
from the FDT as new PSCI sys_poweroff and sys_reset services
have been added. For those kernels that do not support yet these
PSCI services (i.e. GICv3 kernel), the original dtsi files have
been renamed to *-no_psci.dtsi.

Fixes ARM-software/tf-issues#218

Change-Id: Ic8a3bf801db979099ab7029162af041c4e8330c8
parent a1d80440
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <assert.h> #include <assert.h>
#include <bakery_lock.h> #include <bakery_lock.h>
#include <cci400.h> #include <cci400.h>
#include <debug.h>
#include <mmio.h> #include <mmio.h>
#include <platform.h> #include <platform.h>
#include <plat_config.h> #include <plat_config.h>
...@@ -364,17 +365,41 @@ int fvp_affinst_suspend_finish(unsigned long mpidr, ...@@ -364,17 +365,41 @@ int fvp_affinst_suspend_finish(unsigned long mpidr,
return fvp_affinst_on_finish(mpidr, afflvl, state); return fvp_affinst_on_finish(mpidr, afflvl, state);
} }
/*******************************************************************************
* FVP handlers to shutdown/reboot the system
******************************************************************************/
static void __dead2 fvp_system_off(void)
{
/* Write the System Configuration Control Register */
mmio_write_32(VE_SYSREGS_BASE + V2M_SYS_CFGCTRL,
CFGCTRL_START | CFGCTRL_RW | CFGCTRL_FUNC(FUNC_SHUTDOWN));
wfi();
ERROR("FVP System Off: operation not handled.\n");
panic();
}
static void __dead2 fvp_system_reset(void)
{
/* Write the System Configuration Control Register */
mmio_write_32(VE_SYSREGS_BASE + V2M_SYS_CFGCTRL,
CFGCTRL_START | CFGCTRL_RW | CFGCTRL_FUNC(FUNC_REBOOT));
wfi();
ERROR("FVP System Reset: operation not handled.\n");
panic();
}
/******************************************************************************* /*******************************************************************************
* Export the platform handlers to enable psci to invoke them * Export the platform handlers to enable psci to invoke them
******************************************************************************/ ******************************************************************************/
static const plat_pm_ops_t fvp_plat_pm_ops = { static const plat_pm_ops_t fvp_plat_pm_ops = {
fvp_affinst_standby, .affinst_standby = fvp_affinst_standby,
fvp_affinst_on, .affinst_on = fvp_affinst_on,
fvp_affinst_off, .affinst_off = fvp_affinst_off,
fvp_affinst_suspend, .affinst_suspend = fvp_affinst_suspend,
fvp_affinst_on_finish, .affinst_on_finish = fvp_affinst_on_finish,
fvp_affinst_suspend_finish, .affinst_suspend_finish = fvp_affinst_suspend_finish,
.system_off = fvp_system_off,
.system_reset = fvp_system_reset
}; };
/******************************************************************************* /*******************************************************************************
......
...@@ -437,6 +437,8 @@ uint64_t tspd_smc_handler(uint32_t smc_fid, ...@@ -437,6 +437,8 @@ uint64_t tspd_smc_handler(uint32_t smc_fid,
*/ */
case TSP_OFF_DONE: case TSP_OFF_DONE:
case TSP_SUSPEND_DONE: case TSP_SUSPEND_DONE:
case TSP_SYSTEM_OFF_DONE:
case TSP_SYSTEM_RESET_DONE:
if (ns) if (ns)
SMC_RET1(handle, SMC_UNK); SMC_RET1(handle, SMC_UNK);
......
...@@ -192,17 +192,60 @@ static int32_t tspd_cpu_migrate_info(uint64_t *resident_cpu) ...@@ -192,17 +192,60 @@ static int32_t tspd_cpu_migrate_info(uint64_t *resident_cpu)
return TSP_MIGRATE_INFO; return TSP_MIGRATE_INFO;
} }
/*******************************************************************************
* System is about to be switched off. Allow the TSPD/TSP to perform
* any actions needed.
******************************************************************************/
static void tspd_system_off(void)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
assert(tsp_vectors);
assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
/* Program the entry point */
cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_off_entry);
/* Enter the TSP. We do not care about the return value because we
* must continue the shutdown anyway */
tspd_synchronous_sp_entry(tsp_ctx);
}
/*******************************************************************************
* System is about to be reset. Allow the TSPD/TSP to perform
* any actions needed.
******************************************************************************/
static void tspd_system_reset(void)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
assert(tsp_vectors);
assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
/* Program the entry point */
cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_reset_entry);
/* Enter the TSP. We do not care about the return value because we
* must continue the reset anyway */
tspd_synchronous_sp_entry(tsp_ctx);
}
/******************************************************************************* /*******************************************************************************
* Structure populated by the TSP Dispatcher to be given a chance to perform any * Structure populated by the TSP Dispatcher to be given a chance to perform any
* TSP bookkeeping before PSCI executes a power mgmt. operation. * TSP bookkeeping before PSCI executes a power mgmt. operation.
******************************************************************************/ ******************************************************************************/
const spd_pm_ops_t tspd_pm = { const spd_pm_ops_t tspd_pm = {
tspd_cpu_on_handler, .svc_on = tspd_cpu_on_handler,
tspd_cpu_off_handler, .svc_off = tspd_cpu_off_handler,
tspd_cpu_suspend_handler, .svc_suspend = tspd_cpu_suspend_handler,
tspd_cpu_on_finish_handler, .svc_on_finish = tspd_cpu_on_finish_handler,
tspd_cpu_suspend_finish_handler, .svc_suspend_finish = tspd_cpu_suspend_finish_handler,
NULL, .svc_migrate = NULL,
tspd_cpu_migrate_info .svc_migrate_info = tspd_cpu_migrate_info,
.svc_system_off = tspd_system_off,
.svc_system_reset = tspd_system_reset
}; };
...@@ -446,3 +446,33 @@ void psci_register_spd_pm_hook(const spd_pm_ops_t *pm) ...@@ -446,3 +446,33 @@ void psci_register_spd_pm_hook(const spd_pm_ops_t *pm)
{ {
psci_spd_pm = pm; psci_spd_pm = pm;
} }
/*******************************************************************************
* This function prints the state of all affinity instances present in the
* system
******************************************************************************/
void psci_print_affinity_map(void)
{
#if LOG_LEVEL >= LOG_LEVEL_INFO
aff_map_node_t *node;
unsigned int idx;
/* This array maps to the PSCI_STATE_X definitions in psci.h */
static const char *psci_state_str[] = {
"ON",
"OFF",
"ON_PENDING",
"SUSPEND"
};
INFO("PSCI Affinity Map:\n");
for (idx = 0; idx < PSCI_NUM_AFFS ; idx++) {
node = &psci_aff_map[idx];
if (!(node->state & PSCI_AFF_PRESENT)) {
continue;
}
INFO(" AffInst: Level %u, MPID 0x%lx, State %s\n",
node->level, node->mpidr,
psci_state_str[psci_get_state(node)]);
}
#endif
}
...@@ -250,6 +250,14 @@ uint64_t psci_smc_handler(uint32_t smc_fid, ...@@ -250,6 +250,14 @@ uint64_t psci_smc_handler(uint32_t smc_fid,
case PSCI_MIG_INFO_UP_CPU_AARCH32: case PSCI_MIG_INFO_UP_CPU_AARCH32:
SMC_RET1(handle, psci_migrate_info_up_cpu()); SMC_RET1(handle, psci_migrate_info_up_cpu());
case PSCI_SYSTEM_OFF:
psci_system_off();
/* We should never return from psci_system_off() */
case PSCI_SYSTEM_RESET:
psci_system_reset();
/* We should never return from psci_system_reset() */
default: default:
break; break;
} }
......
...@@ -99,6 +99,7 @@ void psci_acquire_afflvl_locks(int start_afflvl, ...@@ -99,6 +99,7 @@ void psci_acquire_afflvl_locks(int start_afflvl,
void psci_release_afflvl_locks(int start_afflvl, void psci_release_afflvl_locks(int start_afflvl,
int end_afflvl, int end_afflvl,
mpidr_aff_map_nodes_t mpidr_nodes); mpidr_aff_map_nodes_t mpidr_nodes);
void psci_print_affinity_map(void);
/* Private exported functions from psci_setup.c */ /* Private exported functions from psci_setup.c */
int psci_get_aff_map_nodes(unsigned long mpidr, int psci_get_aff_map_nodes(unsigned long mpidr,
...@@ -132,4 +133,8 @@ unsigned int psci_afflvl_suspend_finish(int, int); ...@@ -132,4 +133,8 @@ unsigned int psci_afflvl_suspend_finish(int, int);
void psci_do_pwrdown_cache_maintenance(uint32_t affinity_level); void psci_do_pwrdown_cache_maintenance(uint32_t affinity_level);
void psci_do_pwrup_cache_maintenance(void); void psci_do_pwrup_cache_maintenance(void);
/* Private exported functions from psci_system_off.c */
void __dead2 psci_system_off(void);
void __dead2 psci_system_reset(void);
#endif /* __PSCI_PRIVATE_H__ */ #endif /* __PSCI_PRIVATE_H__ */
/*
* Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
#include <arch_helpers.h>
#include <debug.h>
#include <platform.h>
#include "psci_private.h"
void psci_system_off(void)
{
/* Check platform support */
if (!psci_plat_pm_ops->system_off) {
ERROR("Platform has not exported a PSCI System Off hook.\n");
panic();
}
psci_print_affinity_map();
/* Notify the Secure Payload Dispatcher */
if (psci_spd_pm && psci_spd_pm->svc_system_off) {
psci_spd_pm->svc_system_off();
}
/* Call the platform specific hook */
psci_plat_pm_ops->system_off();
/* This function does not return. We should never get here */
}
void psci_system_reset(void)
{
/* Check platform support */
if (!psci_plat_pm_ops->system_reset) {
ERROR("Platform has not exported a PSCI System Reset hook.\n");
panic();
}
psci_print_affinity_map();
/* Notify the Secure Payload Dispatcher */
if (psci_spd_pm && psci_spd_pm->svc_system_reset) {
psci_spd_pm->svc_system_reset();
}
/* Call the platform specific hook */
psci_plat_pm_ops->system_reset();
/* This function does not return. We should never get here */
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment