Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
432b9905
Commit
432b9905
authored
Aug 17, 2015
by
Achin Gupta
Browse files
Merge pull request #361 from achingupta/for_sm/psci_proto_v5
For sm/psci proto v5
parents
9caf7e36
9d070b99
Changes
70
Show whitespace changes
Inline
Side-by-side
Makefile
View file @
432b9905
...
...
@@ -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__
\
...
...
bl2/aarch64/bl2_entrypoint.S
View file @
432b9905
/*
*
Copyright
(
c
)
2013
-
201
4
,
ARM
Limited
and
Contributors
.
All
rights
reserved
.
*
Copyright
(
c
)
2013
-
201
5
,
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
...
...
bl31/aarch64/cpu_data.S
View file @
432b9905
/*
*
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
)
*
...
...
bl31/bl31.mk
View file @
432b9905
#
# Copyright (c) 2013-201
4
, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2013-201
5
, 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
\
...
...
bl31/bl31_main.c
View file @
432b9905
/*
* Copyright (c) 2013-201
4
, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-201
5
, 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
);
}
...
...
bl31/context_mgmt.c
View file @
432b9905
/*
* Copyright (c) 2013-201
4
, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-201
5
, 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_c
pu_data_by_mpidr
(
mpidr
,
cpu_context
[
security_state
]
);
return
cm_
get_c
ontext_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 ex
e
cution 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
*
...
...
bl32/tsp/aarch64/tsp_entrypoint.S
View file @
432b9905
/*
*
Copyright
(
c
)
2013
-
201
4
,
ARM
Limited
and
Contributors
.
All
rights
reserved
.
*
Copyright
(
c
)
2013
-
201
5
,
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
...
...
bl32/tsp/tsp_interrupt.c
View file @
432b9905
...
...
@@ -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
;
...
...
bl32/tsp/tsp_main.c
View file @
432b9905
/*
* Copyright (c) 2013-201
4
, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-201
5
, 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
=
plat
form_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
);
...
...
bl32/tsp/tsp_timer.c
View file @
432b9905
/*
* 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
=
plat
form_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
=
plat
form_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
);
...
...
docs/diagrams/psci-suspend-sequence.png
0 → 100644
View file @
432b9905
418 KB
docs/platform-migration-guide.md
0 → 100644
View file @
432b9905
Guide to migrate to new Platform porting interface
==================================================
Contents
--------
1.
[
Introduction
](
#1--introduction
)
2.
[
Platform API modification due to PSCI framework changes
](
#2--platform-api-modification-due-to-psci-framework-changes
)
*
[
Power domain topology framework platform API modifications
](
#21-power-domain-topology-framework-platform-api-modifications
)
*
[
Composite power state framework platform API modifications
](
#22-composite-power-state-framework-platform-api-modifications
)
*
[
Miscellaneous modifications
](
#23-miscellaneous-modifications
)
3.
[
Compatibility layer
](
#3--compatibility-layer
)
4.
[
Deprecated Platform API
](
#4--deprecated-platform-api
)
- - - - - - - - - - - - - - - - - -
1.
Introduction
----------------
The PSCI implementation in Trusted Firmware has undergone a redesign because of
three requirements that the PSCI 1.0 specification introduced :
*
Removing the framework assumption about the structure of the MPIDR, and
its relation to the power topology enables support for deeper and more
complex hierarchies.
*
Reworking the power state coordination implementation in the framework
to support the more detailed PSCI 1.0 requirements and reduce platform
port complexity
*
Enable the use of the extended power_state parameter and the larger StateID
field
The PSCI 1.0 implementation introduces new frameworks to fulfill the above
requirements. These framework changes mean that the platform porting API must
also be modified. This document is a guide to assist migration of the existing
platform ports to the new platform API.
This document describes the new platform API and compares it with the
deprecated API. It also describes the compatibility layer that enables the
existing platform ports to work with the PSCI 1.0 implementation. The
deprecated platform API is documented for reference.
2. Platform API modification due to PSCI framework changes
-----------------------------------------------------------
This section describes changes to the platform APIs.
2.1 Power domain topology framework platform API modifications
--------------------------------------------------------------
This removes the assumption in the PSCI implementation that MPIDR
based affinity instances map directly to power domains. A power domain, as
described in section 4.2 of [PSCI], could contain a core or a logical group
of cores (a cluster) which share some state on which power management
operations can be performed. The existing affinity instance based APIs
`plat_get_aff_count()`
and
`plat_get_aff_count()`
are deprecated. The new
platform interfaces that are introduced for this framework are:
*
`plat_core_pos_by_mpidr()`
*
`plat_my_core_pos()`
*
`plat_get_power_domain_tree_desc()`
`plat_my_core_pos()`
and
`plat_core_pos_by_mpidr()`
are mandatory
and are meant to replace the existing
`platform_get_core_pos()`
API.
The description of these APIs can be found in the
[
Porting Guide
][
my_core_pos
]
.
These are used by the power domain topology framework such that:
1.
The generic PSCI code does not generate MPIDRs or use them to query the
platform about the number of power domains at a particular power level. The
`plat_get_power_domain_tree_desc()`
provides a description of the power
domain tree on the SoC through a pointer to the byte array containing the
power domain topology tree description data structure.
2.
The linear indices returned by
`plat_core_pos_by_mpidr()`
and
`plat_my_core_pos()`
are used to retrieve core power domain nodes from
the power domain tree. These core indices are unique for a core and it is a
number between
`0`
and
`PLATFORM_CORE_COUNT - 1`
. The platform can choose
to implement a static mapping between
`MPIDR`
and core index or implement
a dynamic mapping, choosing to skip the unavailable/unused cores to compact
the core indices.
In addition, the platforms must define the macros
`PLAT_NUM_PWR_DOMAINS`
and
`PLAT_MAX_PWR_LVL`
which replace the macros
`PLAT_NUM_AFFS`
and
`PLATFORM_MAX_AFFLVL`
respectively. On platforms where the affinity instances
correspond to power domains, the values of new macros remain the same as the
old ones.
More details on the power domain topology description and its platform
interface can be found in [psci pd tree].
2.2 Composite power state framework platform API modifications
--------------------------------------------------------------
The state-ID field in the power-state parameter of a CPU_SUSPEND call can be
used to describe the composite power states specific to a platform. The existing
PSCI state coordination had the limitation that it operates on a run/off
granularity of power states and it did not interpret the state-ID field. This
was acceptable as the specification requirement in PSCI 0.2. The framework's
approach to coordination only requires maintaining a reference
count of the number of cores that have requested the cluster to remain powered.
In the PSCI 1.0 specification, this approach is non optimal. If composite
power states are used, the PSCI implementation cannot make global
decisions about state coordination required because it does not understand the
platform specific states.
The PSCI 1.0 implementation now defines a generic representation of the
power-state parameter :
typedef struct psci_power_state {
plat_local_state_t pwr_domain_state[PLAT_MAX_PWR_LVL + 1];
} psci_power_state_t;
`pwr_domain_state`
is an array where each index corresponds to a power level.
Each entry in the array contains the local power state the power domain at
that power level could enter. The meaning of the local power state value is
platform defined, and can vary between levels in a single platform. The PSCI
implementation constraints the values only so that it can classify the state
as RUN, RETENTION or OFF as required by the specification:
1.
Zero means RUN
2.
All OFF state values at all levels must be higher than all
RETENTION state values at all levels
The platform is required to define the macros
`PLAT_MAX_RET_STATE`
and
`PLAT_MAX_OFF_STATE`
to the framework. The requirement for these macros can
be found in the [Porting Guide].
The PSCI 1.0 implementation adds support to involve the platform in state
coordination. This enables the platform to decide the final target state.
During a request to place a power domain in a low power state, the platform
is passed an array of requested
`plat_local_state_t`
for that power domain by
each core within it through the
`plat_get_target_pwr_state()`
API. This API
coordinates amongst these requested states to determine a target
`plat_local_state_t`
for that power domain. A default weak implementation of
this API is provided in the platform layer which returns the minimum of the
requested local states back to the PSCI state coordination. More details
of
`plat_get_target_pwr_state()`
API can be found in the
[
Porting Guide
][
get_target_pwr_state
]
.
The PSCI Generic implementation expects platform ports to populate the handlers
for the
`plat_psci_ops`
structure which is declared as :
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,
psci_power_state_t *req_state);
int (*validate_ns_entrypoint)(unsigned long ns_entrypoint);
void (*get_sys_suspend_power_state)(
psci_power_state_t *req_state);
} plat_psci_ops_t;
The description of these handlers can be found in the
[
Porting Guide
][
psci_ops
]
.
The previous
`plat_pm_ops`
structure is deprecated. Compared with the previous
handlers, the major differences are:
*
Difference in parameters
The PSCI 1.0 implementation depends on the
`validate_power_state`
handler to
convert the power-state parameter (possibly encoding a composite power state)
passed in a PSCI
`CPU_SUSPEND`
to the
`psci_power_state`
format.
The
`plat_psci_ops`
handlers,
`pwr_domain_off`
and
`pwr_domain_suspend`
, are
passed the target local state for each affected power domain. The platform
must execute operations specific to these target states. Similarly,
`pwr_domain_on_finish`
and
`pwr_domain_suspend_finish`
are passed the local
states of the affected power domains before wakeup. The platform
must execute actions to restore these power domains from these specific
local states.
*
Difference in invocation
Whereas the power management handlers in
`plat_pm_ops`
used to be invoked
for each affinity level till the target affinity level, the new handlers
are only invoked once. The
`target_state`
encodes the target low power
state or the low power state woken up from for each affected power domain.
*
Difference in semantics
Although the previous
`suspend`
handlers could be used for power down as well
as retention at different affinity levels, the new handlers make this support
explicit. The
`pwr_domain_suspend`
can be used to specify powerdown and
retention at various power domain levels subject to the conditions mentioned
in section 4.2.1 of [PSCI]
Unlike the previous
`standby`
handler, the
`cpu_standby()`
handler is only used
as a fast path for placing a core power domain into a standby or retention
state.
The below diagram shows the sequence of a PSCI SUSPEND call and the interaction
with the platform layer depicting the exchange of data between PSCI Generic
layer and the platform layer.

Refer [plat/arm/board/fvp/fvp_pm.c] for the implementation details of
these handlers for the FVP. The commit b6df6ccbc88cc14592f5e603ef580d3cbf4733c3
demonstrates the migration of ARM reference platforms to the new platform API.
2.3 Miscellaneous modifications
-------------------------------
In addition to the framework changes, unification of warm reset entry points on
wakeup from low power modes has led to a change in the platform API. In the
earlier implementation, the warm reset entry used to be programmed into the
mailboxes by the 'ON' and 'SUSPEND' power management hooks. In the PSCI 1.0
implementation, this information is not required, because it can figure that
out by querying affinity info state whether to execute the 'suspend_finisher
`
or 'on_finisher'.
As a result, the warm reset entry point must be programmed only once. The
`
plat_setup_psci_ops()
` API takes the secure entry point as an
additional parameter to enable the platforms to configure their mailbox. The
plat_psci_ops handlers `
pwr_domain_on
` and `
pwr_domain_suspend
` no longer take
the warm reset entry point as a parameter.
Also, some platform APIs which took `
MPIDR
` as an argument were only ever
invoked to perform actions specific to the caller core which makes the argument
redundant. Therefore the platform APIs `
plat_get_my_entrypoint()
`,
`
plat_is_my_cpu_primary()
`, `
plat_set_my_stack()
` and
`
plat_get_my_stack()
` are defined which are meant to be invoked only for
operations on the current caller core instead of `
platform_get_entrypoint()
`,
`
platform_is_primary_cpu()
`, `
platform_set_stack()
` and `
platform_get_stack()
`.
3. Compatibility layer
----------------------
To ease the migration of the platform ports to the new porting interface,
a compatibility layer is introduced that essentially implements a glue layer
between the old platform API and the new API. The build flag
`
ENABLE_PLAT_COMPAT
` (enabled by default), specifies whether to enable this
layer or not. A platform port which has migrated to the new API can disable
this flag within the platform specific makefile.
The compatibility layer works on the assumption that the onus of
state coordination, in case multiple low power states are supported,
is with the platform. The generic PSCI implementation only takes into
account whether the suspend request is power down or not. This corresponds
with the behavior of the PSCI implementation before the introduction of
new frameworks. Also, it assumes that the affinity levels of the platform
correspond directly to the power domain levels.
The compatibility layer dynamically constructs the new topology
description array by querying the platform using `
plat_get_aff_count()
`
and `
plat_get_aff_count()
` APIs. The linear index returned by
`
platform_get_core_pos()
` is used as the core index for the cores. The
higher level (non-core) power domain nodes must know the cores contained
within its domain. It does so by storing the core index of first core
within it and number of core indexes following it. This means that core
indices returned by `
platform_get_core_pos()
` for cores within a particular
power domain must be consecutive. We expect that this is the case for most
platform ports including ARM reference platforms.
The old PSCI helpers like `
psci_get_suspend_powerstate()
`,
`
psci_get_suspend_stateid()
`, `
psci_get_suspend_stateid_by_mpidr()
`,
`
psci_get_max_phys_off_afflvl()
` and `
psci_get_suspend_afflvl()
` are also
implemented for the compatibility layer. This allows the existing
platform ports to work with the new PSCI frameworks without significant
rework.
4. Deprecated Platform API
---------------------------
This section documents the deprecated platform porting API.
## Common mandatory modifications
The mandatory macros to be defined by the platform port in `
platform_def.h
`
* **#define : PLATFORM_NUM_AFFS**
Defines the total number of nodes in the affinity hierarchy at all affinity
levels used by the platform.
* **#define : PLATFORM_MAX_AFFLVL**
Defines the maximum affinity level that the power management operations
should apply to. ARMv8-A has support for four affinity levels. It is likely
that hardware will implement fewer affinity levels. This macro allows the
PSCI implementation to consider only those affinity levels in the system
that the platform implements. For example, the Base AEM FVP implements two
clusters with a configurable number of cores. It reports the maximum
affinity level as 1, resulting in PSCI power control up to the cluster
level.
The following functions must be implemented by the platform port to enable
the reset vector code to perform the required tasks.
### Function : platform_get_entrypoint() [mandatory]
Argument : unsigned long
Return : unsigned long
This function is called with the `
SCTLR.M
` and `
SCTLR.C
` bits disabled. The core
is identified by its `
MPIDR
`, which is passed as the argument. The function is
responsible for distinguishing between a warm and cold reset using platform-
specific means. If it is a warm reset, it returns the entrypoint into the
BL3-1 image that the core must jump to. If it is a cold reset, this function
must return zero.
This function is also responsible for implementing a platform-specific mechanism
to handle the condition where the core has been warm reset but there is no
entrypoint to jump to.
This function does not follow the Procedure Call Standard used by the
Application Binary Interface for the ARM 64-bit architecture. The caller should
not assume that callee saved registers are preserved across a call to this
function.
### Function : platform_is_primary_cpu() [mandatory]
Argument : unsigned long
Return : unsigned int
This function identifies a core by its `
MPIDR
`, which is passed as the argument,
to determine whether this core is the primary core or a secondary core. A return
value of zero indicates that the core is not the primary core, while a non-zero
return value indicates that the core is the primary core.
## Common optional modifications
### Function : platform_get_core_pos()
Argument : unsigned long
Return : int
A platform may need to convert the `
MPIDR
` of a core to an absolute number, which
can be used as a core-specific linear index into blocks of memory (for example
while allocating per-core stacks). This routine contains a simple mechanism
to perform this conversion, using the assumption that each cluster contains a
maximum of four cores:
linear index = cpu_id + (cluster_id * 4)
cpu_id = 8-bit value in MPIDR at affinity level 0
cluster_id = 8-bit value in MPIDR at affinity level 1
### Function : platform_set_stack()
Argument : unsigned long
Return : void
This function sets the current stack pointer to the normal memory stack that
has been allocated for the core specified by MPIDR. For BL images that only
require a stack for the primary core the parameter is ignored. The size of
the stack allocated to each core is specified by the platform defined constant
`
PLATFORM_STACK_SIZE
`.
Common implementations of this function for the UP and MP BL images are
provided in [plat/common/aarch64/platform_up_stack.S] and
[plat/common/aarch64/platform_mp_stack.S]
### Function : platform_get_stack()
Argument : unsigned long
Return : unsigned long
This function returns the base address of the normal memory stack that
has been allocated for the core specificed by MPIDR. For BL images that only
require a stack for the primary core the parameter is ignored. The size of
the stack allocated to each core is specified by the platform defined constant
`
PLATFORM_STACK_SIZE
`.
Common implementations of this function for the UP and MP BL images are
provided in [plat/common/aarch64/platform_up_stack.S] and
[plat/common/aarch64/platform_mp_stack.S]
## Modifications for Power State Coordination Interface (in BL3-1)
The following functions must be implemented to initialize PSCI functionality in
the ARM Trusted Firmware.
### Function : plat_get_aff_count() [mandatory]
Argument : unsigned int, unsigned long
Return : unsigned int
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in `
bl31_plat_arch_setup()
`. It is only
called by the primary core.
This function is called by the PSCI initialization code to detect the system
topology. Its purpose is to return the number of affinity instances implemented
at a given `
affinity level
` (specified by the first argument) and a given
`
MPIDR
` (specified by the second argument). For example, on a dual-cluster
system where first cluster implements two cores and the second cluster
implements four cores, a call to this function with an `
MPIDR
` corresponding
to the first cluster (`
0x0
`) and affinity level 0, would return 2. A call
to this function with an `
MPIDR
` corresponding to the second cluster (`
0x100
`)
and affinity level 0, would return 4.
### Function : plat_get_aff_state() [mandatory]
Argument : unsigned int, unsigned long
Return : unsigned int
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in `
bl31_plat_arch_setup()
`. It is only
called by the primary core.
This function is called by the PSCI initialization code. Its purpose is to
return the state of an affinity instance. The affinity instance is determined by
the affinity ID at a given `
affinity level
` (specified by the first argument)
and an `
MPIDR
` (specified by the second argument). The state can be one of
`
PSCI_AFF_PRESENT
` or `
PSCI_AFF_ABSENT
`. The latter state is used to cater for
system topologies where certain affinity instances are unimplemented. For
example, consider a platform that implements a single cluster with four cores and
another core implemented directly on the interconnect with the cluster. The
`
MPIDR
`s of the cluster would range from `
0x0-0x3
`. The `
MPIDR
` of the single
core is 0x100 to indicate that it does not belong to cluster 0. Cluster 1
is missing but needs to be accounted for to reach this single core in the
topology tree. Therefore it is marked as `
PSCI_AFF_ABSENT
`.
### Function : platform_setup_pm() [mandatory]
Argument : const plat_pm_ops **
Return : int
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in `
bl31_plat_arch_setup()
`. It is only
called by the primary core.
This function is called by PSCI initialization code. Its purpose is to export
handler routines for platform-specific power management actions by populating
the passed pointer with a pointer to the private `
plat_pm_ops
` structure of
BL3-1.
A description of each member of this structure is given below. A platform port
is expected to implement these handlers if the corresponding PSCI operation
is to be supported and these handlers are expected to succeed if the return
type is `
void
`.
#### plat_pm_ops.affinst_standby()
Perform the platform-specific setup to enter the standby state indicated by the
passed argument. The generic code expects the handler to succeed.
#### plat_pm_ops.affinst_on()
Perform the platform specific setup to power on an affinity instance, specified
by the `
MPIDR
` (first argument) and `
affinity level
` (third argument). The
`
state
` (fourth argument) contains the current state of that affinity instance
(ON or OFF). This is useful to determine whether any action must be taken. For
example, while powering on a core, the cluster that contains this core might
already be in the ON state. The platform decides what actions must be taken to
transition from the current state to the target state (indicated by the power
management operation). The generic code expects the platform to return
E_SUCCESS on success or E_INTERN_FAIL for any failure.
#### plat_pm_ops.affinst_off()
Perform the platform specific setup to power off an affinity instance of the
calling core. It is called by the PSCI `
CPU_OFF
` API implementation.
The `
affinity level
` (first argument) and `
state
` (second argument) have
a similar meaning as described in the `
affinst_on()
` operation. They
identify the affinity instance on which the call is made and its
current state. This gives the platform port an indication of the
state transition it must make to perform the requested action. For example, if
the calling core is the last powered on core in the cluster, after powering down
affinity level 0 (the core), the platform port should power down affinity
level 1 (the cluster) as well. The generic code expects the handler to succeed.
#### plat_pm_ops.affinst_suspend()
Perform the platform specific setup to power off an affinity instance of the
calling core. It is called by the PSCI `
CPU_SUSPEND
` API and `
SYSTEM_SUSPEND
`
API implementation
The `
affinity level
` (second argument) and `
state
` (third argument) have a
similar meaning as described in the `
affinst_on()
` operation. They are used to
identify the affinity instance on which the call is made and its current state.
This gives the platform port an indication of the state transition it must
make to perform the requested action. For example, if the calling core is the
last powered on core in the cluster, after powering down affinity level 0
(the core), the platform port should power down affinity level 1 (the cluster)
as well.
The difference between turning an affinity instance off and suspending it
is that in the former case, the affinity instance is expected to re-initialize
its state when it is next powered on (see `
affinst_on_finish()
`). In the latter
case, the affinity instance is expected to save enough state so that it can
resume execution by restoring this state when it is powered on (see
`
affinst_suspend_finish()
`).The generic code expects the handler to succeed.
#### plat_pm_ops.affinst_on_finish()
This function is called by the PSCI implementation after the calling core is
powered on and released from reset in response to an earlier PSCI `
CPU_ON
` call.
It performs the platform-specific setup required to initialize enough state for
this core to enter the Normal world and also provide secure runtime firmware
services.
The `
affinity level
` (first argument) and `
state
` (second argument) have a
similar meaning as described in the previous operations. The generic code
expects the handler to succeed.
#### plat_pm_ops.affinst_suspend_finish()
This function is called by the PSCI implementation after the calling core is
powered on and released from reset in response to an asynchronous wakeup
event, for example a timer interrupt that was programmed by the core during the
`
CPU_SUSPEND
` call or `
SYSTEM_SUSPEND
` call. It performs the platform-specific
setup required to restore the saved state for this core to resume execution
in the Normal world and also provide secure runtime firmware services.
The `
affinity level
` (first argument) and `
state
` (second argument) have a
similar meaning as described in the previous operations. The generic code
expects the platform to succeed.
#### plat_pm_ops.validate_power_state()
This function is called by the PSCI implementation during the `
CPU_SUSPEND
`
call to validate the `
power_state
` parameter of the PSCI API. If the
`
power_state
` is known to be invalid, the platform must return
PSCI_E_INVALID_PARAMS as an error, which is propagated back to the Normal
world PSCI client.
#### plat_pm_ops.validate_ns_entrypoint()
This function is called by the PSCI implementation during the `
CPU_SUSPEND
`,
`
SYSTEM_SUSPEND
` and `
CPU_ON
` calls to validate the Non-secure `
entry_point
`
parameter passed by the Normal world. If the `
entry_point
` is known to be
invalid, the platform must return PSCI_E_INVALID_PARAMS as an error, which is
propagated back to the Normal world PSCI client.
#### plat_pm_ops.get_sys_suspend_power_state()
This function is called by the PSCI implementation during the `
SYSTEM_SUSPEND
`
call to return the `
power_state
` parameter. This allows the platform to encode
the appropriate State-ID field within the `
power_state
` parameter which can be
utilized in `
affinst_suspend()
` to suspend to system affinity level. The
`
power_state
`
parameter should be in the same format as specified by the
PSCI specification for the CPU_SUSPEND API.
- - - - - - - - - - - - - - - - - - - - - - - - - -
_Copyright (c) 2015, ARM Limited and Contributors. All rights reserved._
[
Porting Guide
]:
porting-guide.md
[
Power Domain Topology Design
]:
psci-pd-tree.md
[
PSCI
]:
http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
[
psci pd tree
]:
psci-pd-tree.md
[
my_core_pos
]:
porting-guide.md#function--plat_my_core_pos
[
get_target_pwr_state
]:
porting-guide.md#function--plat_get_target_pwr_state-optional
[
psci_ops
]:
porting-guide.md#function--plat_setup_psci_ops-mandatory
[
plat/arm/board/fvp/fvp_pm.c
]:
../plat/arm/board/fvp/fvp_pm.c
[
plat/common/aarch64/platform_mp_stack.S
]:
../plat/common/aarch64/platform_mp_stack.S
[
plat/common/aarch64/platform_up_stack.S
]:
../plat/common/aarch64/platform_up_stack.S
docs/porting-guide.md
View file @
432b9905
...
...
@@ -8,7 +8,8 @@ Contents
2.
[
Common Modifications
](
#2--common-modifications
)
*
[
Common mandatory modifications
](
#21-common-mandatory-modifications
)
*
[
Handling reset
](
#22-handling-reset
)
*
[
Common optional modifications
](
#23-common-optional-modifications
)
*
[
Common mandatory modifications
](
#23-common-mandatory-modifications
)
*
[
Common optional modifications
](
#24-common-optional-modifications
)
3.
[
Boot Loader stage specific modifications
](
#3--modifications-specific-to-a-boot-loader-stage
)
*
[
Boot Loader stage 1 (BL1)
](
#31-boot-loader-stage-1-bl1
)
*
[
Boot Loader stage 2 (BL2)
](
#32-boot-loader-stage-2-bl2
)
...
...
@@ -25,6 +26,10 @@ Contents
1.
Introduction
----------------
Please note that this document has been updated for the new platform API
as required by the PSCI v1.0 implementation. Please refer to the
[Migration Guide] for the previous platform API.
Porting the ARM Trusted Firmware to a new platform involves making some
mandatory and optional modifications for both the cold and warm boot paths.
Modifications consist of:
...
...
@@ -139,21 +144,39 @@ platform port to define additional platform porting constants in
Defines the total number of CPUs implemented by the platform across all
clusters in the system.
*
**#define : PLATFORM_NUM_AFFS**
*
**#define : PLAT_NUM_PWR_DOMAINS**
Defines the total number of nodes in the power domain topology
tree at all the power domain levels used by the platform.
This macro is used by the PSCI implementation to allocate
data structures to represent power domain topology.
*
**#define : PLAT_MAX_PWR_LVL**
Defines the total number of nodes in the affinity heirarchy at all affinity
levels used by the platform.
Defines the maximum power domain level that the power management operations
should apply to. More often, but not always, the power domain level
corresponds to affinity level. This macro allows the PSCI implementation
to know the highest power domain level that it should consider for power
management operations in the system that the platform implements. For
example, the Base AEM FVP implements two clusters with a configurable
number of CPUs and it reports the maximum power domain level as 1.
*
**#define : PLAT
FORM
_MAX_
A
FF
LVL
**
*
**#define : PLAT_MAX_
O
FF
_STATE
**
Defines the maximum affinity level that the power management operations
should apply to. ARMv8-A has support for 4 affinity levels. It is likely
that hardware will implement fewer affinity levels. This macro allows the
PSCI implementation to consider only those affinity levels in the system
that the platform implements. For example, the Base AEM FVP implements two
clusters with a configurable number of CPUs. It reports the maximum
affinity level as 1, resulting in PSCI power control up to the cluster
level.
Defines the local power state corresponding to the deepest power down
possible at every power domain level in the platform. The local power
states for each level may be sparsely allocated between 0 and this value
with 0 being reserved for the RUN state. The PSCI implementation uses this
value to initialize the local power states of the power domain nodes and
to specify the requested power state for a PSCI_CPU_OFF call.
*
**#define : PLAT_MAX_RET_STATE**
Defines the local power state corresponding to the deepest retention state
possible at every power domain level in the platform. This macro should be
a value less than PLAT_MAX_OFF_STATE and greater than 0. It is used by the
PSCI implementation to distuiguish between retention and power down local
power states within PSCI_CPU_SUSPEND call.
*
**#define : BL1_RO_BASE**
...
...
@@ -408,21 +431,17 @@ The following functions need to be implemented by the platform port to enable
reset vector code to perform the above tasks.
### Function : plat
form
_get_entrypoint() [mandatory]
### Function : plat_get_
my_
entrypoint() [mandatory
when PROGRAMMABLE_RESET_ADDRESS == 0
]
Argument : unsigned long
Return : unsigned int
This function is called with the
`SCTLR.M`
and
`SCTLR.C`
bits disabled. The CPU
is identified by its
`MPIDR`
, which is passed as the argument. The function is
responsible for distinguishing between a warm and cold reset using platform-
specific means. If it's a warm reset then it returns the entrypoint into the
BL3-1 image that the CPU must jump to. If it's a cold reset then this function
must return zero.
Argument : void
Return : unsigned long
This function is also responsible for implementing a platform-specific mechanism
to handle the condition where the CPU has been warm reset but there is no
entrypoint to jump to.
This function is called with the called with the MMU and caches disabled
(
`SCTLR_EL3.M`
= 0 and
`SCTLR_EL3.C`
= 0). The function is responsible for
distinguishing between a warm and cold reset for the current CPU using
platform-specific means. If it's a warm reset, then it returns the warm
reset entrypoint point provided to
`plat_setup_psci_ops()`
during
BL3-1 initialization. If it's a cold reset then this function must return zero.
This function does not follow the Procedure Call Standard used by the
Application Binary Interface for the ARM 64-bit architecture. The caller should
...
...
@@ -431,11 +450,16 @@ function.
This function fulfills requirement 1 and 3 listed above.
Note that for platforms that support programming the 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
type of reset nor to query the warm reset entrypoint. Therefore, implementing
this function is not required on such platforms.
### Function : plat_secondary_cold_boot_setup() [mandatory]
Argument : void
Return : void
This function is called with the MMU and data caches disabled. It is responsible
for placing the executing secondary CPU in a platform-specific state until the
...
...
@@ -449,15 +473,15 @@ requires them.
This function fulfills requirement 2 above.
### Function : plat
form_is
_primary
_cpu
() [mandatory]
### Function : plat
_is_my_cpu
_primary() [mandatory]
Argument :
unsigned long
Argument :
void
Return : unsigned int
This function identifies
a
CPU
by
i
t
s
`MPIDR`
, which is passed as the argument,
to determine whether this CPU is the primary CPU or a secondary CPU. A return
value of zero indicates that the CPU is not the primary CPU, while a non-zero
return value indicates that the CPU is the
primary CPU.
This function identifies
whether the current
CPU is
the primary CPU or a
secondary CPU. A return value of zero indicates that the CPU is not the
primary CPU, while a non-zero return value indicates that the CPU is the
primary CPU.
### Function : platform_mem_init() [mandatory]
...
...
@@ -468,9 +492,6 @@ return value indicates that the CPU is the primary CPU.
This function is called before any access to data is made by the firmware, in
order to carry out any essential memory initialization.
The ARM FVP port uses this function to initialize the mailbox memory used for
providing the warm-boot entry-point addresses.
### Function: plat_get_rotpk_info()
...
...
@@ -504,58 +525,75 @@ retrieved from the platform. The function also reports extra information related
to the ROTPK in the flags parameter.
2.3 Common optional modifications
2.3 Common mandatory modifications
---------------------------------
The following are helper functions implemented by the firmware that perform
common platform-specific tasks. A platform may choose to override these
definitions.
The following functions are mandatory functions which need to be implemented
by the platform port.
### Function : plat_my_core_pos()
Argument : void
Return : unsigned int
This funtion returns the index of the calling CPU which is used as a
CPU-specific linear index into blocks of memory (for example while allocating
per-CPU stacks). This function will be invoked very early in the
initialization sequence which mandates that this function should be
implemented in assembly and should not rely on the avalability of a C
runtime environment.
This function plays a crucial role in the power domain topology framework in
PSCI and details of this can be found in [Power Domain Topology Design].
### Function : plat
form_get
_core_pos()
### Function : plat_core_pos
_by_mpidr
()
Argument : u
nsigned long
Argument : u
_register_t
Return : int
A platform may need to convert the
`MPIDR`
of a CPU to an absolute number, which
can be used as a CPU-specific linear index into blocks of memory (for example
while allocating per-CPU stacks). This routine contains a simple mechanism
to perform this conversion, using the assumption that each cluster contains a
maximum of 4 CPUs:
This function validates the
`MPIDR`
of a CPU and converts it to an index,
which can be used as a CPU-specific linear index into blocks of memory. In
case the
`MPIDR`
is invalid, this function returns -1. This function will only
be invoked by BL3-1 after the power domain topology is initialized and can
utilize the C runtime environment. For further details about how ARM Trusted
Firmware represents the power domain topology and how this relates to the
linear CPU index, please refer [Power Domain Topology Design].
linear index = cpu_id + (cluster_id * 4)
cpu_id = 8-bit value in MPIDR at affinity level 0
cluster_id = 8-bit value in MPIDR at affinity level 1
2.4 Common optional modifications
---------------------------------
The following are helper functions implemented by the firmware that perform
common platform-specific tasks. A platform may choose to override these
definitions.
### Function : plat
form
_set_stack()
### Function : plat_set_
my_
stack()
Argument :
unsigned long
Argument :
void
Return : void
This function sets the current stack pointer to the normal memory stack that
has been allocated for the
CPU specificed by MPIDR
. For BL images that only
require a
stack for the primary CPU the
parameter is ignor
ed. The size
of
the stack allocated to each CPU is specified by the platform defined
constant
`PLATFORM_STACK_SIZE`
.
has been allocated for the
current CPU
. For BL images that only
require a
stack for the primary CPU
,
the
UP version of the function is us
ed. The size
of
the stack allocated to each CPU is specified by the platform defined
constant
`PLATFORM_STACK_SIZE`
.
Common implementations of this function for the UP and MP BL images are
provided in [plat/common/aarch64/platform_up_stack.S] and
[plat/common/aarch64/platform_mp_stack.S]
### Function : plat
form
_get_stack()
### Function : plat_get_
my_
stack()
Argument :
unsigned long
Argument :
void
Return : unsigned long
This function returns the base address of the normal memory stack that
has been allocated for the
CPU specificed by MPIDR
. For BL images that only
require a
stack for the primary CPU the
parameter is ignor
ed. The size
of
the stack allocated to each CPU is specified by the platform defined
constant
`PLATFORM_STACK_SIZE`
.
has been allocated for the
current CPU
. For BL images that only
require a
stack for the primary CPU
,
the
UP version of the function is us
ed. The size
of
the stack allocated to each CPU is specified by the platform defined
constant
`PLATFORM_STACK_SIZE`
.
Common implementations of this function for the UP and MP BL images are
provided in [plat/common/aarch64/platform_up_stack.S] and
...
...
@@ -1116,147 +1154,159 @@ modes table.
------------------------------------------------
The ARM Trusted Firmware's implementation of the PSCI API is based around the
concept of an _affinity instance_. Each _affinity instance_ can be uniquely
identified in a system by a CPU ID (the processor
`MPIDR`
is used in the PSCI
interface) and an _affinity level_. A processing element (for example, a
CPU) is at level 0. If the CPUs in the system are described in a tree where the
node above a CPU is a logical grouping of CPUs that share some state, then
affinity level 1 is that group of CPUs (for example, a cluster), and affinity
level 2 is a group of clusters (for example, the system). The implementation
assumes that the affinity level 1 ID can be computed from the affinity level 0
ID (for example, a unique cluster ID can be computed from the CPU ID). The
current implementation computes this on the basis of the recommended use of
`MPIDR`
affinity fields in the ARM Architecture Reference Manual.
concept of a _power domain_. A _power domain_ is a CPU or a logical group of
CPUs which share some state on which power management operations can be
performed as specified by [PSCI]. Each CPU in the system is assigned a cpu
index which is a unique number between
`0`
and
`PLATFORM_CORE_COUNT - 1`
.
The _power domains_ are arranged in a hierarchial tree structure and
each _power domain_ can be identified in a system by the cpu index of any CPU
that is part of that domain and a _power domain level_. A processing element
(for example, a CPU) is at level 0. If the _power domain_ node above a CPU is
a logical grouping of CPUs that share some state, then level 1 is that group
of CPUs (for example, a cluster), and level 2 is a group of clusters
(for example, the system). More details on the power domain topology and its
organization can be found in [Power Domain Topology Design].
BL3-1's platform initialization code exports a pointer to the platform-specific
power management operations required for the PSCI implementation to function
correctly. This information is populated in the
`plat_pm_ops`
structure. The
PSCI implementation calls members of the
`plat_pm_ops`
structure for performing
power management operations for each affinity instance. For example, the target
CPU is specified by its
`MPIDR`
in a PSCI
`CPU_ON`
call. The
`affinst_on()`
handler (if present) is called for each affinity instance as the PSCI
implementation powers up each affinity level implemented in the
`MPIDR`
(for
example, CPU, cluster and system).
correctly. This information is populated in the
`plat_psci_ops`
structure. The
PSCI implementation calls members of the
`plat_psci_ops`
structure for performing
power management operations on the power domains. For example, the target
CPU is specified by its
`MPIDR`
in a PSCI
`CPU_ON`
call. The
`pwr_domain_on()`
handler (if present) is called for the CPU power domain.
The
`power-state`
parameter of a PSCI
`CPU_SUSPEND`
call can be used to
describe composite power states specific to a platform. The PSCI implementation
defines a generic representation of the power-state parameter viz which is an
array of local power states where each index corresponds to a power domain
level. Each entry contains the local power state the power domain at that power
level could enter. It depends on the
`validate_power_state()`
handler to
convert the power-state parameter (possibly encoding a composite power state)
passed in a PSCI
`CPU_SUSPEND`
call to this representation.
The following functions must be implemented to initialize PSCI functionality in
the ARM Trusted Firmware.
### Function : plat_get_aff_count() [mandatory]
Argument : unsigned int, unsigned long
Return : unsigned int
### Function : plat_get_target_pwr_state() [optional]
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in
`bl31_plat_arch_setup()`
. It is only
called by the primary CPU.
Argument : unsigned int, const plat_local_state_t *, unsigned int
Return : plat_local_state_t
Th
is function is called by the PSCI initialization code to detect the system
topology. Its purpose is to return the number of affinity instances implement
ed
a
t a given
`affinity level`
(specified by the first argument) and a given
`MPIDR`
(specified by the second argument). For example, on a dual-cluste
r
system where first cluster implements 2 CPUs and the second cluster implements 4
CPUs, a call to this function with an
`MPIDR`
corresponding to the first cluster
(
`0x0`
) and affinity level 0, would return 2. A call to this function with an
`MPIDR`
corresponding to the second cluster (
`0x100`
) and affinity level 0,
would return 4
.
Th
e PSCI generic code uses this function to let the platform participate in
state coordination during a power management operation. The function is pass
ed
a
pointer to an array of platform specific local power state
`states`
(second
argument) which contains the requested power state for each CPU at a particula
r
power domain level
`lvl`
(first argument) within the power domain. The function
is expected to traverse this array of upto
`ncpus`
(third argument) and return
a coordinated target power state by the comparing all the requested power
states. The target power state should not be deeper than any of the requested
power states
.
A weak definition of this API is provided by default wherein it assumes
that the platform assigns a local state value in order of increasing depth
of the power state i.e. for two power states X & Y, if X < Y
then X represents a shallower power state than Y. As a result, the
coordinated target local power state for a power domain will be the minimum
of the requested local power state values.
### Function : plat_get_aff_state() [mandatory]
Argument : unsigned int, unsigned long
Return : unsigned int
### Function : plat_get_power_domain_tree_desc() [mandatory]
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in
`bl31_plat_arch_setup()`
. It is only
called by the primary CPU.
Argument : void
Return : const unsigned char *
This function is called by the PSCI initialization code. Its purpose is to
return the state of an affinity instance. The affinity instance is determined by
the affinity ID at a given
`affinity level`
(specified by the first argument)
and an
`MPIDR`
(specified by the second argument). The state can be one of
`PSCI_AFF_PRESENT`
or
`PSCI_AFF_ABSENT`
. The latter state is used to cater for
system topologies where certain affinity instances are unimplemented. For
example, consider a platform that implements a single cluster with 4 CPUs and
another CPU implemented directly on the interconnect with the cluster. The
`MPIDR`
s of the cluster would range from
`0x0-0x3`
. The
`MPIDR`
of the single
CPU would be 0x100 to indicate that it does not belong to cluster 0. Cluster 1
is missing but needs to be accounted for to reach this single CPU in the
topology tree. Hence it is marked as
`PSCI_AFF_ABSENT`
.
This function returns a pointer to the byte array containing the power domain
topology tree description. The format and method to construct this array are
described in [Power Domain Topology Design]. The BL3-1 PSCI initilization code
requires this array to be described by the platform, either statically or
dynamically, to initialize the power domain topology tree. In case the array
is populated dynamically, then plat_core_pos_by_mpidr() and
plat_my_core_pos() should also be implemented suitably so that the topology
tree description matches the CPU indices returned by these APIs. These APIs
together form the platform interface for the PSCI topology framework.
##
#
Function : plat
form
_setup_p
m
() [mandatory]
## Function : plat_setup_p
sci_ops
() [mandatory]
Argument : const plat_p
m
_ops **
Argument :
uintptr_t,
const plat_p
sci
_ops **
Return : int
This function may execute with the MMU and data caches enabled if the platform
port does the necessary initializations in
`bl31_plat_arch_setup()`
. It is only
called by the primary CPU.
This function is called by PSCI initialization code. Its purpose is to export
handler routines for platform-specific power management actions by populating
the passed pointer with a pointer to BL3-1's private
`plat_pm_ops`
structure.
This function is called by PSCI initialization code. Its purpose is to let
the platform layer know about the warm boot entrypoint through the
`sec_entrypoint`
(first argument) and to export handler routines for
platform-specific psci power management actions by populating the passed
pointer with a pointer to BL3-1's private
`plat_psci_ops`
structure.
A description of each member of this structure is given below. Please refer to
the ARM FVP specific implementation of these handlers in
[plat/arm/board/fvp/fvp_pm.c] as an example. A platform port is expected to
implement these handlers if the corresponding PSCI operation is to be supported
and these handlers are expected to succeed if the return type is
`void`
.
#### plat_pm_ops.affinst_standby()
Perform the platform-specific setup to enter the standby state indicated by the
passed argument. The generic code expects the handler to succeed.
#### plat_pm_ops.affinst_on()
Perform the platform specific setup to power on an affinity instance, specified
by the
`MPIDR`
(first argument) and
`affinity level`
(third argument). The
`state`
(fourth argument) contains the current state of that affinity instance
(ON or OFF). This is useful to determine whether any action must be taken. For
example, while powering on a CPU, the cluster that contains this CPU might
already be in the ON state. The platform decides what actions must be taken to
transition from the current state to the target state (indicated by the power
management operation). The generic code expects the platform to return
E_SUCCESS on success or E_INTERN_FAIL for any failure.
#### plat_pm_ops.affinst_off()
Perform the platform specific setup to power off an affinity instance of the
calling CPU. It is called by the PSCI
`CPU_OFF`
API implementation.
The
`affinity level`
(first argument) and
`state`
(second argument) have
a similar meaning as described in the
`affinst_on()`
operation. They are
used to identify the affinity instance on which the call is made and its
current state. This gives the platform port an indication of the
state transition it must make to perform the requested action. For example, if
the calling CPU is the last powered on CPU in the cluster, after powering down
affinity level 0 (CPU), the platform port should power down affinity level 1
(the cluster) as well. The generic code expects the handler to succeed.
#### plat_pm_ops.affinst_suspend()
Perform the platform specific setup to power off an affinity instance of the
calling CPU. It is called by the PSCI
`CPU_SUSPEND`
API and
`SYSTEM_SUSPEND`
API implementation
The
`affinity level`
(second argument) and
`state`
(third argument) have a
similar meaning as described in the
`affinst_on()`
operation. They are used to
identify the affinity instance on which the call is made and its current state.
This gives the platform port an indication of the state transition it must
make to perform the requested action. For example, if the calling CPU is the
last powered on CPU in the cluster, after powering down affinity level 0 (CPU),
the platform port should power down affinity level 1 (the cluster) as well.
The difference between turning an affinity instance off versus suspending it
is that in the former case, the affinity instance is expected to re-initialize
its state when its next powered on (see
`affinst_on_finish()`
). In the latter
case, the affinity instance is expected to save enough state so that it can
[plat/arm/board/fvp/fvp_pm.c] as an example. For each PSCI function that the
platform wants to support, the associated operation or operations in this
structure must be provided and implemented (Refer section 4 of
[Firmware Design] for the PSCI API supported in Trusted Firmware). To disable
a PSCI function in a platform port, the operation should be removed from this
structure instead of providing an empty implementation.
#### plat_psci_ops.cpu_standby()
Perform the platform-specific actions to enter the standby state for a cpu
indicated by the passed argument. This provides a fast path for CPU standby
wherein overheads of PSCI state management and lock acquistion is avoided.
For this handler to be invoked by the PSCI
`CPU_SUSPEND`
API implementation,
the suspend state type specified in the
`power-state`
parameter should be
STANDBY and the target power domain level specified should be the CPU. The
handler should put the CPU into a low power retention state (usually by
issuing a wfi instruction) and ensure that it can be woken up from that
state by a normal interrupt. The generic code expects the handler to succeed.
#### plat_psci_ops.pwr_domain_on()
Perform the platform specific actions to power on a CPU, specified
by the
`MPIDR`
(first argument). The generic code expects the platform to
return PSCI_E_SUCCESS on success or PSCI_E_INTERN_FAIL for any failure.
#### plat_psci_ops.pwr_domain_off()
Perform the platform specific actions to prepare to power off the calling CPU
and its higher parent power domain levels as indicated by the
`target_state`
(first argument). It is called by the PSCI
`CPU_OFF`
API implementation.
The
`target_state`
encodes the platform coordinated target local power states
for the CPU power domain and its parent power domain levels. The handler
needs to perform power management operation corresponding to the local state
at each power level.
For this handler, the local power state for the CPU power domain will be a
power down state where as it could be either power down, retention or run state
for the higher power domain levels depending on the result of state
coordination. The generic code expects the handler to succeed.
#### plat_psci_ops.pwr_domain_suspend()
Perform the platform specific actions to prepare to suspend the calling
CPU and its higher parent power domain levels as indicated by the
`target_state`
(first argument). It is called by the PSCI
`CPU_SUSPEND`
API implementation.
The
`target_state`
has a similar meaning as described in
the
`pwr_domain_off()`
operation. It encodes the platform coordinated
target local power states for the CPU power domain and its parent
power domain levels. The handler needs to perform power management operation
corresponding to the local state at each power level. The generic code
expects the handler to succeed.
The difference between turning a power domain off versus suspending it
is that in the former case, the power domain is expected to re-initialize
its state when it is next powered on (see
`pwr_domain_on_finish()`
). In the
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
`
affinst
_suspend_finish()`
).
The generic code expects the handler to succeed.
`
pwr_domain
_suspend_finish()`
).
#### plat_p
m
_ops.
affinst
_on_finish()
#### plat_p
sci
_ops.
pwr_domain
_on_finish()
This function is called by the PSCI implementation after the calling CPU is
powered on and released from reset in response to an earlier PSCI
`CPU_ON`
call.
...
...
@@ -1264,11 +1314,12 @@ It performs the platform-specific setup required to initialize enough state for
this CPU to enter the normal world and also provide secure runtime firmware
services.
The
`affinity level`
(first argument) and
`state`
(second argument) have a
similar meaning as described in the previous operations. The generic code
expects the handler to succeed.
The
`target_state`
(first argument) is the prior state of the power domains
immediately before the CPU was turned on. It indicates which power domains
above the CPU might require initialization due to having previously been in
low power states. The generic code expects the handler to succeed.
#### plat_p
m
_ops.
affinst
_suspend_finish()
#### plat_p
sci
_ops.
pwr_domain
_suspend_finish()
This function is called by the PSCI implementation after the calling CPU is
powered on and released from reset in response to an asynchronous wakeup
...
...
@@ -1277,40 +1328,36 @@ event, for example a timer interrupt that was programmed by the CPU during the
setup required to restore the saved state for this CPU to resume execution
in the normal world and also provide secure runtime firmware services.
The
`
affinity level
`
(first argument)
and
`state`
(second argument) have a
similar meaning as described in the previous
operation
s
. The generic code
expects the platform
to succeed.
The
`
target_state
`
(first argument)
has a similar meaning as described in
the
`pwr_domain_on_finish()`
operation. The generic code
expects the platform
to succeed.
#### plat_p
m
_ops.validate_power_state()
#### plat_p
sci
_ops.validate_power_state()
This function is called by the PSCI implementation during the
`CPU_SUSPEND`
call to validate the
`power_state`
parameter of the PSCI API. If the
`power_state`
is known to be invalid, the platform must return
PSCI_E_INVALID_PARAMS as error, which is propagated back to the normal
world PSCI client.
call to validate the
`power_state`
parameter of the PSCI API and if valid,
populate it in
`req_state`
(second argument) array as power domain level
specific local states. If the
`power_state`
is invalid, the platform must
return PSCI_E_INVALID_PARAMS as error, which is propagated back to the
normal world PSCI client.
#### plat_p
m
_ops.validate_ns_entrypoint()
#### plat_p
sci
_ops.validate_ns_entrypoint()
This function is called by the PSCI implementation during the
`CPU_SUSPEND`
,
`SYSTEM_SUSPEND`
and
`CPU_ON`
calls to validate the non-secure
`entry_point`
parameter passed by the normal world. If the
`entry_point`
is
known to be
invalid,
the platform must return PSCI_E_INVALID_
PARAM
S as error, which is
parameter passed by the normal world. If the
`entry_point`
is
invalid,
the platform must return PSCI_E_INVALID_
ADDRES
S as error, which is
propagated back to the normal world PSCI client.
#### plat_p
m
_ops.get_sys_suspend_power_state()
#### plat_p
sci
_ops.get_sys_suspend_power_state()
This function is called by the PSCI implementation during the
`SYSTEM_SUSPEND`
call to return the
`power_state`
parameter. This allows the platform to encode
the appropriate State-ID field within the
`power_state`
parameter which can be
utilized in
`affinst_suspend()`
to suspend to system affinity level. The
`power_state`
parameter should be in the same format as specified by the
PSCI specification for the CPU_SUSPEND API.
BL3-1 platform initialization code must also detect the system topology and
the state of each affinity instance in the topology. This information is
critical for the PSCI runtime service to function correctly. More details are
provided in the description of the
`plat_get_aff_count()`
and
`plat_get_aff_state()`
functions above.
call to get the
`req_state`
parameter from platform which encodes the power
domain level specific local states to suspend to system affinity level. The
`req_state`
will be utilized to do the PSCI state coordination and
`pwr_domain_suspend()`
will be invoked with the coordinated target state to
enter system suspend.
3.4 Interrupt Management framework (in BL3-1)
----------------------------------------------
...
...
@@ -1478,6 +1525,12 @@ register x0.
4.
Build flags
---------------
*
**ENABLE_PLAT_COMPAT**
All the platforms ports conforming to this API specification should define
the build flag
`ENABLE_PLAT_COMPAT`
to 0 as the compatibility layer should
be disabled. For more details on compatibility layer, refer
[Migration Guide].
There are some build flags which can be defined by the platform to control
inclusion or exclusion of certain BL stages from the FIP image. These flags
need to be defined in the platform makefile which will get included by the
...
...
@@ -1592,6 +1645,9 @@ _Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved._
[
User Guide
]:
user-guide.md
[
FreeBSD
]:
http://www.freebsd.org
[
Firmware Design
]:
firmware-design.md
[
Power Domain Topology Design
]:
psci-pd-tree.md
[
PSCI
]:
http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
[
Migration Guide
]:
platform-migration-guide.md
[
plat/common/aarch64/platform_mp_stack.S
]:
../plat/common/aarch64/platform_mp_stack.S
[
plat/common/aarch64/platform_up_stack.S
]:
../plat/common/aarch64/platform_up_stack.S
...
...
docs/psci-pd-tree.md
0 → 100644
View file @
432b9905
------------
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.
docs/user-guide.md
View file @
432b9905
...
...
@@ -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
include/bl31/context_mgmt.h
View file @
432b9905
/*
* Copyright (c) 2013-201
4
, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-201
5
, 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
);
...
...
include/bl31/cpu_data.h
View file @
432b9905
/*
* 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), \
...
...
include/bl31/services/psci.h
View file @
432b9905
/*
* Copyright (c) 2013-201
4
, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-201
5
, 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 instance
s whose state this psci imp. can track
* Number of
power domain
s whose state this psci imp. can track
******************************************************************************/
#ifdef PLAT
FORM
_NUM_
AFF
S
#define PSCI_NUM_
AFF
S
PLAT
FORM
_NUM_
AFF
S
#ifdef PLAT_NUM_
PWR_DOMAIN
S
#define PSCI_NUM_
PWR_DOMAIN
S PLAT_NUM_
PWR_DOMAIN
S
#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
#define PSTATE_ID_MASK 0xffff
#define PSTATE_TYPE_MASK 0x1
#define PSTATE_AFF_LVL_MASK 0x3
#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_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_
AFF
S
];
bakery_info_t
pcpu_bakery_info
[
PSCI_NUM_
NON_CPU_PWR_DOMAIN
S
];
#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__ */
include/bl31/services/psci_compat.h
0 → 100644
View file @
432b9905
/*
* 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__ */
include/common/asm_macros.S
View file @
432b9905
...
...
@@ -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
...
...
Prev
1
2
3
4
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment