Commit 432b9905 authored by Achin Gupta's avatar Achin Gupta
Browse files

Merge pull request #361 from achingupta/for_sm/psci_proto_v5

For sm/psci proto v5
parents 9caf7e36 9d070b99
......@@ -66,6 +66,9 @@ ARM_CCI_PRODUCT_ID := 400
ASM_ASSERTION := ${DEBUG}
# Build option to choose whether Trusted firmware uses Coherent memory or not.
USE_COHERENT_MEM := 1
# Flag used to choose the power state format viz Extended State-ID or the Original
# format.
PSCI_EXTENDED_STATE_ID := 0
# Default FIP file name
FIP_NAME := fip.bin
# By default, use the -pedantic option in the gcc command line
......@@ -79,6 +82,8 @@ TRUSTED_BOARD_BOOT := 0
# By default, consider that the platform's reset address is not programmable.
# The platform Makefile is free to override this value.
PROGRAMMABLE_RESET_ADDRESS := 0
# Build flag to warn about usage of deprecated platform and framework APIs
WARN_DEPRECATED := 0
# Checkpatch ignores
CHECK_IGNORE = --ignore COMPLEX_MACRO \
......@@ -166,6 +171,16 @@ msg_start:
include ${PLAT_MAKEFILE_FULL}
# If the platform has not defined ENABLE_PLAT_COMPAT, then enable it by default
ifndef ENABLE_PLAT_COMPAT
ENABLE_PLAT_COMPAT := 1
endif
# Include the platform compatibility helpers for PSCI
ifneq (${ENABLE_PLAT_COMPAT}, 0)
include plat/compat/plat_compat.mk
endif
# Include the CPU specific operations makefile. By default all CPU errata
# workarounds and CPU specifc optimisations are disabled. This can be
# overridden by the platform.
......@@ -268,6 +283,10 @@ $(eval $(call add_define,LOG_LEVEL))
$(eval $(call assert_boolean,USE_COHERENT_MEM))
$(eval $(call add_define,USE_COHERENT_MEM))
# Process PSCI_EXTENDED_STATE_ID flag
$(eval $(call assert_boolean,PSCI_EXTENDED_STATE_ID))
$(eval $(call add_define,PSCI_EXTENDED_STATE_ID))
# Process Generate CoT flags
$(eval $(call assert_boolean,GENERATE_COT))
$(eval $(call assert_boolean,CREATE_KEYS))
......@@ -281,6 +300,14 @@ $(eval $(call add_define,TRUSTED_BOARD_BOOT))
$(eval $(call assert_boolean,PROGRAMMABLE_RESET_ADDRESS))
$(eval $(call add_define,PROGRAMMABLE_RESET_ADDRESS))
# Process ENABLE_PLAT_COMPAT flag
$(eval $(call assert_boolean,ENABLE_PLAT_COMPAT))
$(eval $(call add_define,ENABLE_PLAT_COMPAT))
# Process WARN_DEPRECATED flag
$(eval $(call assert_boolean,WARN_DEPRECATED))
$(eval $(call add_define,WARN_DEPRECATED))
ASFLAGS += -nostdinc -ffreestanding -Wa,--fatal-warnings \
-Werror -Wmissing-include-dirs \
-mgeneral-regs-only -D__ASSEMBLY__ \
......
/*
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2015, 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:
......@@ -105,8 +105,7 @@ func bl2_entrypoint
* primary cpu is running at the moment.
* --------------------------------------------
*/
mrs x0, mpidr_el1
bl platform_set_stack
bl plat_set_my_stack
/* ---------------------------------------------
* Perform early platform setup & platform
......
/*
* Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2014-2015, 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:
......@@ -32,7 +32,6 @@
#include <cpu_data.h>
.globl init_cpu_data_ptr
.globl _cpu_data_by_mpidr
.globl _cpu_data_by_index
/* -----------------------------------------------------------------
......@@ -41,37 +40,19 @@
* Initialise the TPIDR_EL3 register to refer to the cpu_data_t
* for the calling CPU. This must be called before cm_get_cpu_data()
*
* This can be called without a valid stack.
* clobbers: x0, x1, x9, x10
* This can be called without a valid stack. It assumes that
* plat_my_core_pos() does not clobber register x10.
* clobbers: x0, x1, x10
* -----------------------------------------------------------------
*/
func init_cpu_data_ptr
mov x10, x30
mrs x0, mpidr_el1
bl _cpu_data_by_mpidr
bl plat_my_core_pos
bl _cpu_data_by_index
msr tpidr_el3, x0
ret x10
endfunc init_cpu_data_ptr
/* -----------------------------------------------------------------
* cpu_data_t *_cpu_data_by_mpidr(uint64_t mpidr)
*
* Return the cpu_data structure for the CPU with given MPIDR
*
* This can be called without a valid stack. It assumes that
* platform_get_core_pos() does not clobber register x9.
* clobbers: x0, x1, x9
* -----------------------------------------------------------------
*/
func _cpu_data_by_mpidr
mov x9, x30
bl platform_get_core_pos
mov x30, x9
b _cpu_data_by_index
endfunc _cpu_data_by_mpidr
/* -----------------------------------------------------------------
* cpu_data_t *_cpu_data_by_index(uint32_t cpu_index)
*
......
#
# Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2013-2015, 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:
......@@ -42,9 +42,9 @@ BL31_SOURCES += bl31/bl31_main.c \
lib/cpus/aarch64/cpu_helpers.S \
lib/locks/exclusive/spinlock.S \
services/std_svc/std_svc_setup.c \
services/std_svc/psci/psci_afflvl_off.c \
services/std_svc/psci/psci_afflvl_on.c \
services/std_svc/psci/psci_afflvl_suspend.c \
services/std_svc/psci/psci_off.c \
services/std_svc/psci/psci_on.c \
services/std_svc/psci/psci_suspend.c \
services/std_svc/psci/psci_common.c \
services/std_svc/psci/psci_entry.S \
services/std_svc/psci/psci_helpers.S \
......
/*
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2015, 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:
......@@ -155,7 +155,7 @@ void bl31_prepare_next_image_entry(void)
INFO("BL3-1: Next image address = 0x%llx\n",
(unsigned long long) next_image_info->pc);
INFO("BL3-1: Next image spsr = 0x%x\n", next_image_info->spsr);
cm_init_context(read_mpidr_el1(), next_image_info);
cm_init_my_context(next_image_info);
cm_prepare_el3_exit(image_type);
}
......
/*
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2015, 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:
......@@ -64,6 +64,32 @@ void cm_init(void)
*/
}
/*******************************************************************************
* This function returns a pointer to the most recent 'cpu_context' structure
* for the CPU identified by `cpu_idx` that was set as the context for the
* specified security state. NULL is returned if no such structure has been
* specified.
******************************************************************************/
void *cm_get_context_by_index(unsigned int cpu_idx,
unsigned int security_state)
{
assert(sec_state_is_valid(security_state));
return get_cpu_data_by_index(cpu_idx, cpu_context[security_state]);
}
/*******************************************************************************
* This function sets the pointer to the current 'cpu_context' structure for the
* specified security state for the CPU identified by CPU index.
******************************************************************************/
void cm_set_context_by_index(unsigned int cpu_idx, void *context,
unsigned int security_state)
{
assert(sec_state_is_valid(security_state));
set_cpu_data_by_index(cpu_idx, cpu_context[security_state], context);
}
/*******************************************************************************
* This function returns a pointer to the most recent 'cpu_context' structure
* for the CPU identified by MPIDR that was set as the context for the specified
......@@ -73,7 +99,7 @@ void *cm_get_context_by_mpidr(uint64_t mpidr, uint32_t security_state)
{
assert(sec_state_is_valid(security_state));
return get_cpu_data_by_mpidr(mpidr, cpu_context[security_state]);
return cm_get_context_by_index(platform_get_core_pos(mpidr), security_state);
}
/*******************************************************************************
......@@ -84,7 +110,8 @@ void cm_set_context_by_mpidr(uint64_t mpidr, void *context, uint32_t security_st
{
assert(sec_state_is_valid(security_state));
set_cpu_data_by_mpidr(mpidr, cpu_context[security_state], context);
cm_set_context_by_index(platform_get_core_pos(mpidr),
context, security_state);
}
/*******************************************************************************
......@@ -114,7 +141,7 @@ static inline void cm_set_next_context(void *context)
}
/*******************************************************************************
* The following function initializes a cpu_context for the current CPU for
* The following function initializes the cpu_context 'ctx' for
* first use, and sets the initial entrypoint state as specified by the
* entry_point_info structure.
*
......@@ -123,25 +150,24 @@ static inline void cm_set_next_context(void *context)
* context and sets this as the next context to return to.
*
* The EE and ST attributes are used to configure the endianess and secure
* timer availability for the new excution context.
* timer availability for the new execution context.
*
* To prepare the register state for entry call cm_prepare_el3_exit() and
* el3_exit(). For Secure-EL1 cm_prepare_el3_exit() is equivalent to
* cm_e1_sysreg_context_restore().
******************************************************************************/
void cm_init_context(uint64_t mpidr, const entry_point_info_t *ep)
static void cm_init_context_common(cpu_context_t *ctx, const entry_point_info_t *ep)
{
uint32_t security_state;
cpu_context_t *ctx;
unsigned int security_state;
uint32_t scr_el3;
el3_state_t *state;
gp_regs_t *gp_regs;
unsigned long sctlr_elx;
security_state = GET_SECURITY_STATE(ep->h.attr);
ctx = cm_get_context_by_mpidr(mpidr, security_state);
assert(ctx);
security_state = GET_SECURITY_STATE(ep->h.attr);
/* Clear any residual register values from the context */
memset(ctx, 0, sizeof(*ctx));
......@@ -209,6 +235,45 @@ void cm_init_context(uint64_t mpidr, const entry_point_info_t *ep)
memcpy(gp_regs, (void *)&ep->args, sizeof(aapcs64_params_t));
}
/*******************************************************************************
* The following function initializes the cpu_context for a CPU specified by
* its `cpu_idx` for first use, and sets the initial entrypoint state as
* specified by the entry_point_info structure.
******************************************************************************/
void cm_init_context_by_index(unsigned int cpu_idx,
const entry_point_info_t *ep)
{
cpu_context_t *ctx;
ctx = cm_get_context_by_index(cpu_idx, GET_SECURITY_STATE(ep->h.attr));
cm_init_context_common(ctx, ep);
}
/*******************************************************************************
* The following function initializes the cpu_context for the current CPU
* for first use, and sets the initial entrypoint state as specified by the
* entry_point_info structure.
******************************************************************************/
void cm_init_my_context(const entry_point_info_t *ep)
{
cpu_context_t *ctx;
ctx = cm_get_context(GET_SECURITY_STATE(ep->h.attr));
cm_init_context_common(ctx, ep);
}
/*******************************************************************************
* The following function provides a compatibility function for SPDs using the
* existing cm library routines. This function is expected to be invoked for
* initializing the cpu_context for the CPU specified by MPIDR for first use.
******************************************************************************/
void cm_init_context(unsigned long mpidr, const entry_point_info_t *ep)
{
if ((mpidr & MPIDR_AFFINITY_MASK) ==
(read_mpidr_el1() & MPIDR_AFFINITY_MASK))
cm_init_my_context(ep);
else
cm_init_context_by_index(platform_get_core_pos(mpidr), ep);
}
/*******************************************************************************
* Prepare the CPU system registers for first entry into secure or normal world
*
......
/*
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2015, 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:
......@@ -122,8 +122,7 @@ func tsp_entrypoint
* primary cpu is running at the moment.
* --------------------------------------------
*/
mrs x0, mpidr_el1
bl platform_set_stack
bl plat_set_my_stack
/* ---------------------------------------------
* Perform early platform setup & platform
......@@ -248,8 +247,7 @@ func tsp_cpu_on_entry
* enabled.
* --------------------------------------------
*/
mrs x0, mpidr_el1
bl platform_set_stack
bl plat_set_my_stack
/* --------------------------------------------
* Enable the MMU with the DCache disabled. It
......
......@@ -49,8 +49,7 @@
******************************************************************************/
void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
uint32_t linear_id = plat_my_core_pos();
tsp_stats[linear_id].sync_fiq_count++;
if (type == TSP_HANDLE_FIQ_AND_RETURN)
......@@ -59,9 +58,9 @@ void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3)
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
spin_lock(&console_lock);
VERBOSE("TSP: cpu 0x%lx sync fiq request from 0x%lx\n",
mpidr, elr_el3);
read_mpidr(), elr_el3);
VERBOSE("TSP: cpu 0x%lx: %d sync fiq requests, %d sync fiq returns\n",
mpidr,
read_mpidr(),
tsp_stats[linear_id].sync_fiq_count,
tsp_stats[linear_id].sync_fiq_ret_count);
spin_unlock(&console_lock);
......@@ -77,8 +76,7 @@ void tsp_update_sync_fiq_stats(uint32_t type, uint64_t elr_el3)
******************************************************************************/
int32_t tsp_fiq_handler(void)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr), id;
uint32_t linear_id = plat_my_core_pos(), id;
/*
* Get the highest priority pending interrupt id and see if it is the
......@@ -105,9 +103,9 @@ int32_t tsp_fiq_handler(void)
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
spin_lock(&console_lock);
VERBOSE("TSP: cpu 0x%lx handled fiq %d\n",
mpidr, id);
read_mpidr(), id);
VERBOSE("TSP: cpu 0x%lx: %d fiq requests\n",
mpidr, tsp_stats[linear_id].fiq_count);
read_mpidr(), tsp_stats[linear_id].fiq_count);
spin_unlock(&console_lock);
#endif
return 0;
......@@ -115,15 +113,14 @@ int32_t tsp_fiq_handler(void)
int32_t tsp_irq_received(void)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
uint32_t linear_id = plat_my_core_pos();
tsp_stats[linear_id].irq_count++;
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
spin_lock(&console_lock);
VERBOSE("TSP: cpu 0x%lx received irq\n", mpidr);
VERBOSE("TSP: cpu 0x%lx received irq\n", read_mpidr());
VERBOSE("TSP: cpu 0x%lx: %d irq requests\n",
mpidr, tsp_stats[linear_id].irq_count);
read_mpidr(), tsp_stats[linear_id].irq_count);
spin_unlock(&console_lock);
#endif
return TSP_PREEMPTED;
......
/*
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2015, 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:
......@@ -72,7 +72,6 @@ static tsp_args_t *set_smc_args(uint64_t arg0,
uint64_t arg6,
uint64_t arg7)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id;
tsp_args_t *pcpu_smc_args;
......@@ -80,7 +79,7 @@ static tsp_args_t *set_smc_args(uint64_t arg0,
* Return to Secure Monitor by raising an SMC. The results of the
* service are passed as an arguments to the SMC
*/
linear_id = platform_get_core_pos(mpidr);
linear_id = plat_my_core_pos();
pcpu_smc_args = &tsp_smc_args[linear_id];
write_sp_arg(pcpu_smc_args, TSP_ARG0, arg0);
write_sp_arg(pcpu_smc_args, TSP_ARG1, arg1);
......@@ -107,8 +106,7 @@ uint64_t tsp_main(void)
INFO("TSP: Total memory size : 0x%lx bytes\n",
BL32_TOTAL_LIMIT - BL32_TOTAL_BASE);
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
uint32_t linear_id = plat_my_core_pos();
/* Initialize the platform */
tsp_platform_setup();
......@@ -123,7 +121,8 @@ uint64_t tsp_main(void)
#if LOG_LEVEL >= LOG_LEVEL_INFO
spin_lock(&console_lock);
INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n", mpidr,
INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n",
read_mpidr(),
tsp_stats[linear_id].smc_count,
tsp_stats[linear_id].eret_count,
tsp_stats[linear_id].cpu_on_count);
......@@ -139,8 +138,7 @@ uint64_t tsp_main(void)
******************************************************************************/
tsp_args_t *tsp_cpu_on_main(void)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
uint32_t linear_id = plat_my_core_pos();
/* Initialize secure/applications state here */
tsp_generic_timer_start();
......@@ -152,8 +150,9 @@ tsp_args_t *tsp_cpu_on_main(void)
#if LOG_LEVEL >= LOG_LEVEL_INFO
spin_lock(&console_lock);
INFO("TSP: cpu 0x%lx turned on\n", mpidr);
INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n", mpidr,
INFO("TSP: cpu 0x%lx turned on\n", read_mpidr());
INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n",
read_mpidr(),
tsp_stats[linear_id].smc_count,
tsp_stats[linear_id].eret_count,
tsp_stats[linear_id].cpu_on_count);
......@@ -176,8 +175,7 @@ tsp_args_t *tsp_cpu_off_main(uint64_t arg0,
uint64_t arg6,
uint64_t arg7)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
uint32_t linear_id = plat_my_core_pos();
/*
* This cpu is being turned off, so disable the timer to prevent the
......@@ -193,8 +191,9 @@ tsp_args_t *tsp_cpu_off_main(uint64_t arg0,
#if LOG_LEVEL >= LOG_LEVEL_INFO
spin_lock(&console_lock);
INFO("TSP: cpu 0x%lx off request\n", mpidr);
INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu off requests\n", mpidr,
INFO("TSP: cpu 0x%lx off request\n", read_mpidr());
INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu off requests\n",
read_mpidr(),
tsp_stats[linear_id].smc_count,
tsp_stats[linear_id].eret_count,
tsp_stats[linear_id].cpu_off_count);
......@@ -219,8 +218,7 @@ tsp_args_t *tsp_cpu_suspend_main(uint64_t arg0,
uint64_t arg6,
uint64_t arg7)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
uint32_t linear_id = plat_my_core_pos();
/*
* Save the time context and disable it to prevent the secure timer
......@@ -237,7 +235,7 @@ tsp_args_t *tsp_cpu_suspend_main(uint64_t arg0,
#if LOG_LEVEL >= LOG_LEVEL_INFO
spin_lock(&console_lock);
INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n",
mpidr,
read_mpidr(),
tsp_stats[linear_id].smc_count,
tsp_stats[linear_id].eret_count,
tsp_stats[linear_id].cpu_suspend_count);
......@@ -262,8 +260,7 @@ tsp_args_t *tsp_cpu_resume_main(uint64_t suspend_level,
uint64_t arg6,
uint64_t arg7)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
uint32_t linear_id = plat_my_core_pos();
/* Restore the generic timer context */
tsp_generic_timer_restore();
......@@ -276,9 +273,9 @@ tsp_args_t *tsp_cpu_resume_main(uint64_t suspend_level,
#if LOG_LEVEL >= LOG_LEVEL_INFO
spin_lock(&console_lock);
INFO("TSP: cpu 0x%lx resumed. suspend level %ld\n",
mpidr, suspend_level);
read_mpidr(), suspend_level);
INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n",
mpidr,
read_mpidr(),
tsp_stats[linear_id].smc_count,
tsp_stats[linear_id].eret_count,
tsp_stats[linear_id].cpu_suspend_count);
......@@ -301,8 +298,7 @@ tsp_args_t *tsp_system_off_main(uint64_t arg0,
uint64_t arg6,
uint64_t arg7)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
uint32_t linear_id = plat_my_core_pos();
/* Update this cpu's statistics */
tsp_stats[linear_id].smc_count++;
......@@ -310,8 +306,8 @@ tsp_args_t *tsp_system_off_main(uint64_t arg0,
#if LOG_LEVEL >= LOG_LEVEL_INFO
spin_lock(&console_lock);
INFO("TSP: cpu 0x%lx SYSTEM_OFF request\n", mpidr);
INFO("TSP: cpu 0x%lx: %d smcs, %d erets requests\n", mpidr,
INFO("TSP: cpu 0x%lx SYSTEM_OFF request\n", read_mpidr());
INFO("TSP: cpu 0x%lx: %d smcs, %d erets requests\n", read_mpidr(),
tsp_stats[linear_id].smc_count,
tsp_stats[linear_id].eret_count);
spin_unlock(&console_lock);
......@@ -334,8 +330,7 @@ tsp_args_t *tsp_system_reset_main(uint64_t arg0,
uint64_t arg6,
uint64_t arg7)
{
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
uint32_t linear_id = plat_my_core_pos();
/* Update this cpu's statistics */
tsp_stats[linear_id].smc_count++;
......@@ -343,8 +338,8 @@ tsp_args_t *tsp_system_reset_main(uint64_t arg0,
#if LOG_LEVEL >= LOG_LEVEL_INFO
spin_lock(&console_lock);
INFO("TSP: cpu 0x%lx SYSTEM_RESET request\n", mpidr);
INFO("TSP: cpu 0x%lx: %d smcs, %d erets requests\n", mpidr,
INFO("TSP: cpu 0x%lx SYSTEM_RESET request\n", read_mpidr());
INFO("TSP: cpu 0x%lx: %d smcs, %d erets requests\n", read_mpidr(),
tsp_stats[linear_id].smc_count,
tsp_stats[linear_id].eret_count);
spin_unlock(&console_lock);
......@@ -371,17 +366,16 @@ tsp_args_t *tsp_smc_handler(uint64_t func,
{
uint64_t results[2];
uint64_t service_args[2];
uint64_t mpidr = read_mpidr();
uint32_t linear_id = platform_get_core_pos(mpidr);
uint32_t linear_id = plat_my_core_pos();
/* Update this cpu's statistics */
tsp_stats[linear_id].smc_count++;
tsp_stats[linear_id].eret_count++;
INFO("TSP: cpu 0x%lx received %s smc 0x%lx\n", mpidr,
INFO("TSP: cpu 0x%lx received %s smc 0x%lx\n", read_mpidr(),
((func >> 31) & 1) == 1 ? "fast" : "standard",
func);
INFO("TSP: cpu 0x%lx: %d smcs, %d erets\n", mpidr,
INFO("TSP: cpu 0x%lx: %d smcs, %d erets\n", read_mpidr(),
tsp_stats[linear_id].smc_count,
tsp_stats[linear_id].eret_count);
......
/*
* Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2014-2015, 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:
......@@ -92,7 +92,7 @@ void tsp_generic_timer_stop(void)
******************************************************************************/
void tsp_generic_timer_save(void)
{
uint32_t linear_id = platform_get_core_pos(read_mpidr());
uint32_t linear_id = plat_my_core_pos();
pcpu_timer_context[linear_id].cval = read_cntps_cval_el1();
pcpu_timer_context[linear_id].ctl = read_cntps_ctl_el1();
......@@ -105,7 +105,7 @@ void tsp_generic_timer_save(void)
******************************************************************************/
void tsp_generic_timer_restore(void)
{
uint32_t linear_id = platform_get_core_pos(read_mpidr());
uint32_t linear_id = plat_my_core_pos();
write_cntps_cval_el1(pcpu_timer_context[linear_id].cval);
write_cntps_ctl_el1(pcpu_timer_context[linear_id].ctl);
......
This diff is collapsed.
This diff is collapsed.
------------
Requirements
------------
1. A platform must export the `plat_get_aff_count()` and
`plat_get_aff_state()` APIs to enable the generic PSCI code to
populate a tree that describes the hierarchy of power domains in the
system. This approach is inflexible because a change to the topology
requires a change in the code.
It would be much simpler for the platform to describe its power domain tree
in a data structure.
2. The generic PSCI code generates MPIDRs in order to populate the power domain
tree. It also uses an MPIDR to find a node in the tree. The assumption that
a platform will use exactly the same MPIDRs as generated by the generic PSCI
code is not scalable. The use of an MPIDR also restricts the number of
levels in the power domain tree to four.
Therefore, there is a need to decouple allocation of MPIDRs from the
mechanism used to populate the power domain topology tree.
3. The current arrangement of the power domain tree requires a binary search
over the sibling nodes at a particular level to find a specified power
domain node. During a power management operation, the tree is traversed from
a 'start' to an 'end' power level. The binary search is required to find the
node at each level. The natural way to perform this traversal is to
start from a leaf node and follow the parent node pointer to reach the end
level.
Therefore, there is a need to define data structures that implement the tree in
a way which facilitates such a traversal.
4. The attributes of a core power domain differ from the attributes of power
domains at higher levels. For example, only a core power domain can be identified
using an MPIDR. There is no requirement to perform state coordination while
performing a power management operation on the core power domain.
Therefore, there is a need to implement the tree in a way which facilitates this
distinction between a leaf and non-leaf node and any associated
optimizations.
------
Design
------
### Describing a power domain tree
To fulfill requirement 1., the existing platform APIs
`plat_get_aff_count()` and `plat_get_aff_state()` have been
removed. A platform must define an array of unsigned chars such that:
1. The first entry in the array specifies the number of power domains at the
highest power level implemented in the platform. This caters for platforms
where the power domain tree does not have a single root node, for example,
the FVP has two cluster power domains at the highest level (1).
2. Each subsequent entry corresponds to a power domain and contains the number
of power domains that are its direct children.
3. The size of the array minus the first entry will be equal to the number of
non-leaf power domains.
4. The value in each entry in the array is used to find the number of entries
to consider at the next level. The sum of the values (number of children) of
all the entries at a level specifies the number of entries in the array for
the next level.
The following example power domain topology tree will be used to describe the
above text further. The leaf and non-leaf nodes in this tree have been numbered
separately.
```
+-+
|0|
+-+
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
+-+ +-+
|1| |2|
+-+ +-+
/ \ / \
/ \ / \
/ \ / \
/ \ / \
+-+ +-+ +-+ +-+
|3| |4| |5| |6|
+-+ +-+ +-+ +-+
+---+-----+ +----+----| +----+----+ +----+-----+-----+
| | | | | | | | | | | | |
| | | | | | | | | | | | |
v v v v v v v v v v v v v
+-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+ +--+ +--+
|0| |1| |2| |3| |4| |5| |6| |7| |8| |9| |10| |11| |12|
+-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+ +--+ +--+
```
This tree is defined by the platform as the array described above as follows:
```
#define PLAT_NUM_POWER_DOMAINS 20
#define PLATFORM_CORE_COUNT 13
#define PSCI_NUM_NON_CPU_PWR_DOMAINS \
(PLAT_NUM_POWER_DOMAINS - PLATFORM_CORE_COUNT)
unsigned char plat_power_domain_tree_desc[] = { 1, 2, 2, 2, 3, 3, 3, 4};
```
### Removing assumptions about MPIDRs used in a platform
To fulfill requirement 2., it is assumed that the platform assigns a
unique number (core index) between `0` and `PLAT_CORE_COUNT - 1` to each core
power domain. MPIDRs could be allocated in any manner and will not be used to
populate the tree.
`plat_core_pos_by_mpidr(mpidr)` will return the core index for the core
corresponding to the MPIDR. It will return an error (-1) if an MPIDR is passed
which is not allocated or corresponds to an absent core. The semantics of this
platform API have changed since it is required to validate the passed MPIDR. It
has been made a mandatory API as a result.
Another mandatory API, `plat_my_core_pos()` has been added to return the core
index for the calling core. This API provides a more lightweight mechanism to get
the index since there is no need to validate the MPIDR of the calling core.
The platform should assign the core indices (as illustrated in the diagram above)
such that, if the core nodes are numbered from left to right, then the index
for a core domain will be the same as the index returned by
`plat_core_pos_by_mpidr()` or `plat_my_core_pos()` for that core. This
relationship allows the core nodes to be allocated in a separate array
(requirement 4.) during `psci_setup()` in such an order that the index of the
core in the array is the same as the return value from these APIs.
#### Dealing with holes in MPIDR allocation
For platforms where the number of allocated MPIDRs is equal to the number of
core power domains, for example, Juno and FVPs, the logic to convert an MPIDR to
a core index should remain unchanged. Both Juno and FVP use a simple collision
proof hash function to do this.
It is possible that on some platforms, the allocation of MPIDRs is not
contiguous or certain cores have been disabled. This essentially means that the
MPIDRs have been sparsely allocated, that is, the size of the range of MPIDRs
used by the platform is not equal to the number of core power domains.
The platform could adopt one of the following approaches to deal with this
scenario:
1. Implement more complex logic to convert a valid MPIDR to a core index while
maintaining the relationship described earlier. This means that the power
domain tree descriptor will not describe any core power domains which are
disabled or absent. Entries will not be allocated in the tree for these
domains.
2. Treat unallocated MPIDRs and disabled cores as absent but still describe them
in the power domain descriptor, that is, the number of core nodes described
is equal to the size of the range of MPIDRs allocated. This approach will
lead to memory wastage since entries will be allocated in the tree but will
allow use of a simpler logic to convert an MPIDR to a core index.
### Traversing through and distinguishing between core and non-core power domains
To fulfill requirement 3 and 4, separate data structures have been defined
to represent leaf and non-leaf power domain nodes in the tree.
```
/*******************************************************************************
* The following two data structures implement the power domain tree. The tree
* is used to track the state of all the nodes i.e. power domain instances
* described by the platform. The tree consists of nodes that describe CPU power
* domains i.e. leaf nodes and all other power domains which are parents of a
* CPU power domain i.e. non-leaf nodes.
******************************************************************************/
typedef struct non_cpu_pwr_domain_node {
/*
* Index of the first CPU power domain node level 0 which has this node
* as its parent.
*/
unsigned int cpu_start_idx;
/*
* Number of CPU power domains which are siblings of the domain indexed
* by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx
* -> cpu_start_idx + ncpus' have this node as their parent.
*/
unsigned int ncpus;
/* Index of the parent power domain node */
unsigned int parent_node;
-----
} non_cpu_pd_node_t;
typedef struct cpu_pwr_domain_node {
unsigned long mpidr;
/* Index of the parent power domain node */
unsigned int parent_node;
-----
} cpu_pd_node_t;
```
The power domain tree is implemented as a combination of the following data
structures.
```
non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS];
cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT];
```
### Populating the power domain tree
The `populate_power_domain_tree()` function in `psci_setup.c` implements the
algorithm to parse the power domain descriptor exported by the platform to
populate the two arrays. It is essentially a breadth-first-search. The nodes for
each level starting from the root are laid out one after another in the
`psci_non_cpu_pd_nodes` and `psci_cpu_pd_nodes` arrays as follows:
```
psci_non_cpu_pd_nodes -> [[Level 3 nodes][Level 2 nodes][Level 1 nodes]]
psci_cpu_pd_nodes -> [Level 0 nodes]
```
For the example power domain tree illustrated above, the `psci_cpu_pd_nodes`
will be populated as follows. The value in each entry is the index of the parent
node. Other fields have been ignored for simplicity.
```
+-------------+ ^
CPU0 | 3 | |
+-------------+ |
CPU1 | 3 | |
+-------------+ |
CPU2 | 3 | |
+-------------+ |
CPU3 | 4 | |
+-------------+ |
CPU4 | 4 | |
+-------------+ |
CPU5 | 4 | | PLATFORM_CORE_COUNT
+-------------+ |
CPU6 | 5 | |
+-------------+ |
CPU7 | 5 | |
+-------------+ |
CPU8 | 5 | |
+-------------+ |
CPU9 | 6 | |
+-------------+ |
CPU10 | 6 | |
+-------------+ |
CPU11 | 6 | |
+-------------+ |
CPU12 | 6 | v
+-------------+
```
The `psci_non_cpu_pd_nodes` array will be populated as follows. The value in
each entry is the index of the parent node.
```
+-------------+ ^
PD0 | -1 | |
+-------------+ |
PD1 | 0 | |
+-------------+ |
PD2 | 0 | |
+-------------+ |
PD3 | 1 | | PLAT_NUM_POWER_DOMAINS -
+-------------+ | PLATFORM_CORE_COUNT
PD4 | 1 | |
+-------------+ |
PD5 | 2 | |
+-------------+ |
PD6 | 2 | |
+-------------+ v
```
Each core can find its node in the `psci_cpu_pd_nodes` array using the
`plat_my_core_pos()` function. When a core is turned on, the normal world
provides an MPIDR. The `plat_core_pos_by_mpidr()` function is used to validate
the MPIDR before using it to find the corresponding core node. The non-core power
domain nodes do not need to be identified.
......@@ -351,7 +351,26 @@ performed.
* `PROGRAMMABLE_RESET_ADDRESS`: This option indicates whether the reset
vector address can be programmed or is fixed on the platform. It can take
either 0 (fixed) or 1 (programmable). Default is 0.
either 0 (fixed) or 1 (programmable). Default is 0. If the platform has a
programmable reset address, it is expected that a CPU will start executing
code directly at the right address, both on a cold and warm reset. In this
case, there is no need to identify the entrypoint on boot and this has
implication for `plat_get_my_entrypoint()` platform porting interface.
(see the [Porting Guide] for details)
* `PSCI_EXTENDED_STATE_ID`: As per PSCI1.0 Specification, there are 2 formats
possible for the PSCI power-state parameter viz original and extended
State-ID formats. This flag if set to 1, configures the generic PSCI layer
to use the extended format. The default value of this flag is 0, which
means by default the original power-state format is used by the PSCI
implementation. This flag should be specified by the platform makefile
and it governs the return value of PSCI_FEATURES API for CPU_SUSPEND
smc function id.
* `WARN_DEPRECATED`: This option decides whether to warn the usage of
deprecated platform APIs and context management helpers within Trusted
Firmware. It can take the value 1 (warn the use of deprecated APIs) or
0. The default is 0.
#### ARM development platform specific build options
......@@ -380,6 +399,14 @@ map is explained in the [Firmware Design].
this option, `arm_rotprivk_rsa.pem` must be specified as `ROT_KEY` when
creating the certificates.
* `ARM_RECOM_STATE_ID_ENC`: The PSCI1.0 specification recommends an encoding
for the construction of composite state-ID in the power-state parameter.
The existing PSCI clients currently do not support this encoding of
State-ID yet. Hence this flag is used to configure whether to use the
recommended State-ID encoding or not. The default value of this flag is 0,
in which case the platform is configured to expect NULL in the State-ID
field of power-state parameter.
#### ARM CSS platform specific build options
* `CSS_DETECT_PRE_1_7_0_SCP`: Boolean flag to detect SCP version
......@@ -1070,4 +1097,5 @@ _Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved._
[Juno Software Guide]: http://community.arm.com/docs/DOC-8396
[DS-5]: http://www.arm.com/products/tools/software-tools/ds-5/index.php
[mbedTLS Repository]: https://github.com/ARMmbed/mbedtls.git
[Porting Guide]: ./porting-guide.md
[Trusted Board Boot]: trusted-board-boot.md
/*
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2015, 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:
......@@ -31,6 +31,7 @@
#ifndef __CM_H__
#define __CM_H__
#include <common_def.h>
#include <cpu_data.h>
#include <stdint.h>
......@@ -43,13 +44,23 @@ struct entry_point_info;
* Function & variable prototypes
******************************************************************************/
void cm_init(void);
void *cm_get_context_by_mpidr(uint64_t mpidr, uint32_t security_state);
void *cm_get_context_by_mpidr(uint64_t mpidr,
uint32_t security_state) __warn_deprecated;
static inline void *cm_get_context(uint32_t security_state);
void cm_set_context_by_mpidr(uint64_t mpidr,
void *context,
uint32_t security_state);
uint32_t security_state) __warn_deprecated;
void *cm_get_context_by_index(unsigned int cpu_idx,
unsigned int security_state);
void cm_set_context_by_index(unsigned int cpu_idx,
void *context,
unsigned int security_state);
static inline void cm_set_context(void *context, uint32_t security_state);
void cm_init_context(uint64_t mpidr, const struct entry_point_info *ep);
void cm_init_context(uint64_t mpidr,
const struct entry_point_info *ep) __warn_deprecated;
void cm_init_my_context(const struct entry_point_info *ep);
void cm_init_context_by_index(unsigned int cpu_idx,
const struct entry_point_info *ep);
void cm_prepare_el3_exit(uint32_t security_state);
void cm_el1_sysregs_context_save(uint32_t security_state);
void cm_el1_sysregs_context_restore(uint32_t security_state);
......
/*
* Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2014-2015, 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:
......@@ -103,7 +103,6 @@ CASSERT(CPU_DATA_CPU_OPS_PTR == __builtin_offsetof
assert_cpu_data_cpu_ops_ptr_offset_mismatch);
struct cpu_data *_cpu_data_by_index(uint32_t cpu_index);
struct cpu_data *_cpu_data_by_mpidr(uint64_t mpidr);
/* Return the cpu_data structure for the current CPU. */
static inline struct cpu_data *_cpu_data(void)
......@@ -123,12 +122,13 @@ void init_cpu_ops(void);
#define set_cpu_data(_m, _v) _cpu_data()->_m = _v
#define get_cpu_data_by_index(_ix, _m) _cpu_data_by_index(_ix)->_m
#define set_cpu_data_by_index(_ix, _m, _v) _cpu_data_by_index(_ix)->_m = _v
#define get_cpu_data_by_mpidr(_id, _m) _cpu_data_by_mpidr(_id)->_m
#define set_cpu_data_by_mpidr(_id, _m, _v) _cpu_data_by_mpidr(_id)->_m = _v
#define flush_cpu_data(_m) flush_dcache_range((uint64_t) \
&(_cpu_data()->_m), \
sizeof(_cpu_data()->_m))
#define inv_cpu_data(_m) inv_dcache_range((uint64_t) \
&(_cpu_data()->_m), \
sizeof(_cpu_data()->_m))
#define flush_cpu_data_by_index(_ix, _m) \
flush_dcache_range((uint64_t) \
&(_cpu_data_by_index(_ix)->_m), \
......
/*
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2015, 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:
......@@ -32,17 +32,33 @@
#define __PSCI_H__
#include <bakery_lock.h>
#include <platform_def.h> /* for PLATFORM_NUM_AFFS */
#include <platform_def.h> /* for PLAT_NUM_PWR_DOMAINS */
#if ENABLE_PLAT_COMPAT
#include <psci_compat.h>
#endif
/*******************************************************************************
* Number of affinity instances whose state this psci imp. can track
* Number of power domains whose state this psci imp. can track
******************************************************************************/
#ifdef PLATFORM_NUM_AFFS
#define PSCI_NUM_AFFS PLATFORM_NUM_AFFS
#ifdef PLAT_NUM_PWR_DOMAINS
#define PSCI_NUM_PWR_DOMAINS PLAT_NUM_PWR_DOMAINS
#else
#define PSCI_NUM_AFFS (2 * PLATFORM_CORE_COUNT)
#define PSCI_NUM_PWR_DOMAINS (2 * PLATFORM_CORE_COUNT)
#endif
#define PSCI_NUM_NON_CPU_PWR_DOMAINS (PSCI_NUM_PWR_DOMAINS - \
PLATFORM_CORE_COUNT)
/* This is the power level corresponding to a CPU */
#define PSCI_CPU_PWR_LVL 0
/*
* The maximum power level supported by PSCI. Since PSCI CPU_SUSPEND
* uses the old power_state parameter format which has 2 bits to specify the
* power level, this constant is defined to be 3.
*/
#define PSCI_MAX_PWR_LVL 3
/*******************************************************************************
* Defines for runtime services func ids
******************************************************************************/
......@@ -84,27 +100,35 @@
* PSCI CPU_SUSPEND 'power_state' parameter specific defines
******************************************************************************/
#define PSTATE_ID_SHIFT 0
#define PSTATE_TYPE_SHIFT 16
#define PSTATE_AFF_LVL_SHIFT 24
#if PSCI_EXTENDED_STATE_ID
#define PSTATE_VALID_MASK 0xB0000000
#define PSTATE_TYPE_SHIFT 30
#define PSTATE_ID_MASK 0xfffffff
#else
#define PSTATE_VALID_MASK 0xFCFE0000
#define PSTATE_TYPE_SHIFT 16
#define PSTATE_PWR_LVL_SHIFT 24
#define PSTATE_ID_MASK 0xffff
#define PSTATE_TYPE_MASK 0x1
#define PSTATE_AFF_LVL_MASK 0x3
#define PSTATE_VALID_MASK 0xFCFE0000
#define PSTATE_PWR_LVL_MASK 0x3
#define psci_get_pstate_pwrlvl(pstate) (((pstate) >> PSTATE_PWR_LVL_SHIFT) & \
PSTATE_PWR_LVL_MASK)
#define psci_make_powerstate(state_id, type, pwrlvl) \
(((state_id) & PSTATE_ID_MASK) << PSTATE_ID_SHIFT) |\
(((type) & PSTATE_TYPE_MASK) << PSTATE_TYPE_SHIFT) |\
(((pwrlvl) & PSTATE_PWR_LVL_MASK) << PSTATE_PWR_LVL_SHIFT)
#endif /* __PSCI_EXTENDED_STATE_ID__ */
#define PSTATE_TYPE_STANDBY 0x0
#define PSTATE_TYPE_POWERDOWN 0x1
#define PSTATE_TYPE_MASK 0x1
#define psci_get_pstate_id(pstate) (((pstate) >> PSTATE_ID_SHIFT) & \
PSTATE_ID_MASK)
#define psci_get_pstate_type(pstate) (((pstate) >> PSTATE_TYPE_SHIFT) & \
PSTATE_TYPE_MASK)
#define psci_get_pstate_afflvl(pstate) (((pstate) >> PSTATE_AFF_LVL_SHIFT) & \
PSTATE_AFF_LVL_MASK)
#define psci_make_powerstate(state_id, type, afflvl) \
(((state_id) & PSTATE_ID_MASK) << PSTATE_ID_SHIFT) |\
(((type) & PSTATE_TYPE_MASK) << PSTATE_TYPE_SHIFT) |\
(((afflvl) & PSTATE_AFF_LVL_MASK) << PSTATE_AFF_LVL_SHIFT)
#define psci_check_power_state(pstate) ((pstate) & PSTATE_VALID_MASK)
/*******************************************************************************
* PSCI CPU_FEATURES feature flag specific defines
......@@ -113,6 +137,11 @@
#define FF_PSTATE_SHIFT 1
#define FF_PSTATE_ORIG 0
#define FF_PSTATE_EXTENDED 1
#if PSCI_EXTENDED_STATE_ID
#define FF_PSTATE FF_PSTATE_EXTENDED
#else
#define FF_PSTATE FF_PSTATE_ORIG
#endif
/* Features flags for CPU SUSPEND OS Initiated mode support. Bits [0:0] */
#define FF_MODE_SUPPORT_SHIFT 0
......@@ -136,33 +165,74 @@
#define PSCI_E_INTERN_FAIL -6
#define PSCI_E_NOT_PRESENT -7
#define PSCI_E_DISABLED -8
#define PSCI_E_INVALID_ADDRESS -9
/*******************************************************************************
* PSCI affinity state related constants. An affinity instance could be present
* or absent physically to cater for asymmetric topologies. If present then it
* could in one of the 4 further defined states.
******************************************************************************/
#define PSCI_STATE_SHIFT 1
#define PSCI_STATE_MASK 0xff
#define PSCI_INVALID_MPIDR ~((u_register_t)0)
#define PSCI_AFF_ABSENT 0x0
#define PSCI_AFF_PRESENT 0x1
#define PSCI_STATE_ON 0x0
#define PSCI_STATE_OFF 0x1
#define PSCI_STATE_ON_PENDING 0x2
#define PSCI_STATE_SUSPEND 0x3
#ifndef __ASSEMBLY__
#define PSCI_INVALID_DATA -1
#include <stdint.h>
#include <types.h>
#define get_phys_state(x) (x != PSCI_STATE_ON ? \
PSCI_STATE_OFF : PSCI_STATE_ON)
/*
* These are the states reported by the PSCI_AFFINITY_INFO API for the specified
* CPU. The definitions of these states can be found in Section 5.7.1 in the
* PSCI specification (ARM DEN 0022C).
*/
typedef enum {
AFF_STATE_ON = 0,
AFF_STATE_OFF = 1,
AFF_STATE_ON_PENDING = 2
} aff_info_state_t;
#define psci_validate_power_state(pstate) (pstate & PSTATE_VALID_MASK)
/*
* Macro to represent invalid affinity level within PSCI.
*/
#define PSCI_INVALID_PWR_LVL (PLAT_MAX_PWR_LVL + 1)
/*
* Type for representing the local power state at a particular level.
*/
typedef uint8_t plat_local_state_t;
#ifndef __ASSEMBLY__
/* The local state macro used to represent RUN state. */
#define PSCI_LOCAL_STATE_RUN 0
#include <stdint.h>
/*
* Macro to test whether the plat_local_state is RUN state
*/
#define is_local_state_run(plat_local_state) \
((plat_local_state) == PSCI_LOCAL_STATE_RUN)
/*
* Macro to test whether the plat_local_state is RETENTION state
*/
#define is_local_state_retn(plat_local_state) \
(((plat_local_state) > PSCI_LOCAL_STATE_RUN) && \
((plat_local_state) <= PLAT_MAX_RET_STATE))
/*
* Macro to test whether the plat_local_state is OFF state
*/
#define is_local_state_off(plat_local_state) \
(((plat_local_state) > PLAT_MAX_RET_STATE) && \
((plat_local_state) <= PLAT_MAX_OFF_STATE))
/*****************************************************************************
* This data structure defines the representation of the power state parameter
* for its exchange between the generic PSCI code and the platform port. For
* example, it is used by the platform port to specify the requested power
* states during a power management operation. It is used by the generic code to
* inform the platform about the target power states that each level should
* enter.
****************************************************************************/
typedef struct psci_power_state {
/*
* The pwr_domain_state[] stores the local power state at each level
* for the CPU.
*/
plat_local_state_t pwr_domain_state[PLAT_MAX_PWR_LVL + 1];
} psci_power_state_t;
/*******************************************************************************
* Structure used to store per-cpu information relevant to the PSCI service.
......@@ -170,11 +240,19 @@
* this information will not reside on a cache line shared with another cpu.
******************************************************************************/
typedef struct psci_cpu_data {
uint32_t power_state;
uint32_t max_phys_off_afflvl; /* Highest affinity level in physically
powered off state */
/* State as seen by PSCI Affinity Info API */
aff_info_state_t aff_info_state;
/*
* Highest power level which takes part in a power management
* operation.
*/
unsigned char target_pwrlvl;
/* The local power state of this CPU */
plat_local_state_t local_state;
#if !USE_COHERENT_MEM
bakery_info_t pcpu_bakery_info[PSCI_NUM_AFFS];
bakery_info_t pcpu_bakery_info[PSCI_NUM_NON_CPU_PWR_DOMAINS];
#endif
} psci_cpu_data_t;
......@@ -182,25 +260,22 @@ typedef struct psci_cpu_data {
* Structure populated by platform specific code to export routines which
* perform common low level pm functions
******************************************************************************/
typedef struct plat_pm_ops {
void (*affinst_standby)(unsigned int power_state);
int (*affinst_on)(unsigned long mpidr,
unsigned long sec_entrypoint,
unsigned int afflvl,
unsigned int state);
void (*affinst_off)(unsigned int afflvl, unsigned int state);
void (*affinst_suspend)(unsigned long sec_entrypoint,
unsigned int afflvl,
unsigned int state);
void (*affinst_on_finish)(unsigned int afflvl, unsigned int state);
void (*affinst_suspend_finish)(unsigned int afflvl,
unsigned int state);
typedef struct plat_psci_ops {
void (*cpu_standby)(plat_local_state_t cpu_state);
int (*pwr_domain_on)(u_register_t mpidr);
void (*pwr_domain_off)(const psci_power_state_t *target_state);
void (*pwr_domain_suspend)(const psci_power_state_t *target_state);
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 (*system_off)(void) __dead2;
void (*system_reset)(void) __dead2;
int (*validate_power_state)(unsigned int power_state);
int (*validate_ns_entrypoint)(unsigned long ns_entrypoint);
unsigned int (*get_sys_suspend_power_state)(void);
} plat_pm_ops_t;
int (*validate_power_state)(unsigned int power_state,
psci_power_state_t *req_state);
int (*validate_ns_entrypoint)(uintptr_t ns_entrypoint);
void (*get_sys_suspend_power_state)(
psci_power_state_t *req_state);
} plat_psci_ops_t;
/*******************************************************************************
* Optional structure populated by the Secure Payload Dispatcher to be given a
......@@ -224,22 +299,23 @@ typedef struct spd_pm_ops {
* Function & Data prototypes
******************************************************************************/
unsigned int psci_version(void);
int psci_affinity_info(unsigned long, unsigned int);
int psci_migrate(unsigned long);
int psci_cpu_on(u_register_t target_cpu,
uintptr_t entrypoint,
u_register_t context_id);
int psci_cpu_suspend(unsigned int power_state,
uintptr_t entrypoint,
u_register_t context_id);
int psci_system_suspend(uintptr_t entrypoint, u_register_t context_id);
int psci_cpu_off(void);
int psci_affinity_info(u_register_t target_affinity,
unsigned int lowest_affinity_level);
int psci_migrate(u_register_t target_cpu);
int psci_migrate_info_type(void);
long psci_migrate_info_up_cpu(void);
int psci_cpu_on(unsigned long,
unsigned long,
unsigned long);
int psci_features(unsigned int psci_fid);
void __dead2 psci_power_down_wfi(void);
void psci_aff_on_finish_entry(void);
void psci_aff_suspend_finish_entry(void);
void psci_entrypoint(void);
void psci_register_spd_pm_hook(const spd_pm_ops_t *);
int psci_get_suspend_stateid_by_mpidr(unsigned long);
int psci_get_suspend_stateid(void);
int psci_get_suspend_afflvl(void);
uint32_t psci_get_max_phys_off_afflvl(void);
uint64_t psci_smc_handler(uint32_t smc_fid,
uint64_t x1,
uint64_t x2,
......@@ -250,10 +326,8 @@ uint64_t psci_smc_handler(uint32_t smc_fid,
uint64_t flags);
/* PSCI setup function */
int32_t psci_setup(void);
int psci_setup(void);
#endif /*__ASSEMBLY__*/
#endif /* __PSCI_H__ */
/*
* Copyright (c) 2015, 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.
*/
#ifndef __PSCI_COMPAT_H__
#define __PSCI_COMPAT_H__
#include <arch.h>
#include <platform_def.h>
#ifndef __ASSEMBLY__
/*
* The below declarations are to enable compatibility for the platform ports
* using the old platform interface and psci helpers.
*/
#define PLAT_MAX_PWR_LVL PLATFORM_MAX_AFFLVL
#define PLAT_NUM_PWR_DOMAINS PLATFORM_NUM_AFFS
/*******************************************************************************
* PSCI affinity related constants. An affinity instance could
* be present or absent physically to cater for asymmetric topologies.
******************************************************************************/
#define PSCI_AFF_ABSENT 0x0
#define PSCI_AFF_PRESENT 0x1
#define PSCI_STATE_ON 0x0
#define PSCI_STATE_OFF 0x1
#define PSCI_STATE_ON_PENDING 0x2
#define PSCI_STATE_SUSPEND 0x3
/*
* Using the compatibility platform interfaces means that the local states
* used in psci_power_state_t need to only convey whether its power down
* or standby state. The onus is on the platform port to do the right thing
* including the state coordination in case multiple power down states are
* involved. Hence if we assume 3 generic states viz, run, standby and
* power down, we can assign 1 and 2 to standby and power down respectively.
*/
#define PLAT_MAX_RET_STATE 1
#define PLAT_MAX_OFF_STATE 2
/*
* Macro to represent invalid affinity level within PSCI.
*/
#define PSCI_INVALID_DATA -1
#define psci_get_pstate_afflvl(pstate) psci_get_pstate_pwrlvl(pstate)
/*
* This array stores the 'power_state' requests of each CPU during
* CPU_SUSPEND and SYSTEM_SUSPEND which will be populated by the
* compatibility layer when appropriate platform hooks are invoked.
*/
extern unsigned int psci_power_state_compat[PLATFORM_CORE_COUNT];
/*******************************************************************************
* Structure populated by platform specific code to export routines which
* perform common low level pm functions
******************************************************************************/
typedef struct plat_pm_ops {
void (*affinst_standby)(unsigned int power_state);
int (*affinst_on)(unsigned long mpidr,
unsigned long sec_entrypoint,
unsigned int afflvl,
unsigned int state);
void (*affinst_off)(unsigned int afflvl, unsigned int state);
void (*affinst_suspend)(unsigned long sec_entrypoint,
unsigned int afflvl,
unsigned int state);
void (*affinst_on_finish)(unsigned int afflvl, unsigned int state);
void (*affinst_suspend_finish)(unsigned int afflvl,
unsigned int state);
void (*system_off)(void) __dead2;
void (*system_reset)(void) __dead2;
int (*validate_power_state)(unsigned int power_state);
int (*validate_ns_entrypoint)(unsigned long ns_entrypoint);
unsigned int (*get_sys_suspend_power_state)(void);
} plat_pm_ops_t;
/*******************************************************************************
* Function & Data prototypes to enable compatibility for older platform ports
******************************************************************************/
int psci_get_suspend_stateid_by_mpidr(unsigned long);
int psci_get_suspend_stateid(void);
int psci_get_suspend_powerstate(void);
unsigned int psci_get_max_phys_off_afflvl(void);
int psci_get_suspend_afflvl(void);
#endif /* ____ASSEMBLY__ */
#endif /* __PSCI_COMPAT_H__ */
......@@ -99,6 +99,29 @@
.size \_name, . - \_name
.endm
/*
* Theses macros are used to create function labels for deprecated
* APIs. If WARN_DEPRECATED is non zero, the callers of these APIs
* will fail to link and cause build failure.
*/
#if WARN_DEPRECATED
.macro func_deprecated _name
func deprecated\_name
.endm
.macro endfunc_deprecated _name
endfunc deprecated\_name
.endm
#else
.macro func_deprecated _name
func \_name
.endm
.macro endfunc_deprecated _name
endfunc \_name
.endm
#endif
/*
* This macro declares an array of 1 or more stacks, properly
* aligned and in the requested section
......@@ -115,6 +138,7 @@
.space ((\_count) * (\_size)), 0
.endm
#if ENABLE_PLAT_COMPAT
/*
* This macro calculates the base address of an MP stack using the
* platform_get_core_pos() index, the name of the stack storage and
......@@ -129,6 +153,21 @@
mov x1, #\_size
madd x0, x0, x1, x2
.endm
#endif
/*
* This macro calculates the base address of the current CPU's MP stack
* using the plat_my_core_pos() index, the name of the stack storage
* and the size of each stack
* Out: X0 = physical address of stack base
* Clobber: X30, X1, X2
*/
.macro get_my_mp_stack _name, _size
bl plat_my_core_pos
ldr x2, =(\_name + \_size)
mov x1, #\_size
madd x0, x0, x1, x2
.endm
/*
* This macro calculates the base address of a UP stack using the
......
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