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
Expand all
Hide 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
This diff is collapsed.
Click to expand it.
docs/porting-guide.md
View file @
432b9905
This diff is collapsed.
Click to expand it.
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
#if PSCI_EXTENDED_STATE_ID
#define PSTATE_VALID_MASK 0xB0000000
#define PSTATE_TYPE_SHIFT 30
#define PSTATE_ID_MASK 0xfffffff
#else
#define PSTATE_VALID_MASK 0xFCFE0000
#define PSTATE_TYPE_SHIFT 16
#define PSTATE_PWR_LVL_SHIFT 24
#define PSTATE_ID_MASK 0xffff
#define PSTATE_TYPE_MASK 0x1
#define PSTATE_AFF_LVL_MASK 0x3
#define PSTATE_VALID_MASK 0xFCFE0000
#define PSTATE_PWR_LVL_MASK 0x3
#define psci_get_pstate_pwrlvl(pstate) (((pstate) >> PSTATE_PWR_LVL_SHIFT) & \
PSTATE_PWR_LVL_MASK)
#define psci_make_powerstate(state_id, type, pwrlvl) \
(((state_id) & PSTATE_ID_MASK) << PSTATE_ID_SHIFT) |\
(((type) & PSTATE_TYPE_MASK) << PSTATE_TYPE_SHIFT) |\
(((pwrlvl) & PSTATE_PWR_LVL_MASK) << PSTATE_PWR_LVL_SHIFT)
#endif
/* __PSCI_EXTENDED_STATE_ID__ */
#define PSTATE_TYPE_STANDBY 0x0
#define PSTATE_TYPE_POWERDOWN 0x1
#define PSTATE_TYPE_MASK 0x1
#define psci_get_pstate_id(pstate) (((pstate) >> PSTATE_ID_SHIFT) & \
PSTATE_ID_MASK)
#define psci_get_pstate_type(pstate) (((pstate) >> PSTATE_TYPE_SHIFT) & \
PSTATE_TYPE_MASK)
#define psci_get_pstate_afflvl(pstate) (((pstate) >> PSTATE_AFF_LVL_SHIFT) & \
PSTATE_AFF_LVL_MASK)
#define psci_make_powerstate(state_id, type, afflvl) \
(((state_id) & PSTATE_ID_MASK) << PSTATE_ID_SHIFT) |\
(((type) & PSTATE_TYPE_MASK) << PSTATE_TYPE_SHIFT) |\
(((afflvl) & PSTATE_AFF_LVL_MASK) << PSTATE_AFF_LVL_SHIFT)
#define psci_check_power_state(pstate) ((pstate) & PSTATE_VALID_MASK)
/*******************************************************************************
* PSCI CPU_FEATURES feature flag specific defines
...
...
@@ -113,6 +137,11 @@
#define FF_PSTATE_SHIFT 1
#define FF_PSTATE_ORIG 0
#define FF_PSTATE_EXTENDED 1
#if PSCI_EXTENDED_STATE_ID
#define FF_PSTATE FF_PSTATE_EXTENDED
#else
#define FF_PSTATE FF_PSTATE_ORIG
#endif
/* Features flags for CPU SUSPEND OS Initiated mode support. Bits [0:0] */
#define FF_MODE_SUPPORT_SHIFT 0
...
...
@@ -136,33 +165,74 @@
#define PSCI_E_INTERN_FAIL -6
#define PSCI_E_NOT_PRESENT -7
#define PSCI_E_DISABLED -8
#define PSCI_E_INVALID_ADDRESS -9
/*******************************************************************************
* PSCI affinity state related constants. An affinity instance could be present
* or absent physically to cater for asymmetric topologies. If present then it
* could in one of the 4 further defined states.
******************************************************************************/
#define PSCI_STATE_SHIFT 1
#define PSCI_STATE_MASK 0xff
#define PSCI_INVALID_MPIDR ~((u_register_t)0)
#define PSCI_AFF_ABSENT 0x0
#define PSCI_AFF_PRESENT 0x1
#define PSCI_STATE_ON 0x0
#define PSCI_STATE_OFF 0x1
#define PSCI_STATE_ON_PENDING 0x2
#define PSCI_STATE_SUSPEND 0x3
#ifndef __ASSEMBLY__
#define PSCI_INVALID_DATA -1
#include <stdint.h>
#include <types.h>
#define get_phys_state(x) (x != PSCI_STATE_ON ? \
PSCI_STATE_OFF : PSCI_STATE_ON)
/*
* These are the states reported by the PSCI_AFFINITY_INFO API for the specified
* CPU. The definitions of these states can be found in Section 5.7.1 in the
* PSCI specification (ARM DEN 0022C).
*/
typedef
enum
{
AFF_STATE_ON
=
0
,
AFF_STATE_OFF
=
1
,
AFF_STATE_ON_PENDING
=
2
}
aff_info_state_t
;
#define psci_validate_power_state(pstate) (pstate & PSTATE_VALID_MASK)
/*
* Macro to represent invalid affinity level within PSCI.
*/
#define PSCI_INVALID_PWR_LVL (PLAT_MAX_PWR_LVL + 1)
/*
* Type for representing the local power state at a particular level.
*/
typedef
uint8_t
plat_local_state_t
;
#ifndef __ASSEMBLY__
/* The local state macro used to represent RUN state. */
#define PSCI_LOCAL_STATE_RUN 0
#include <stdint.h>
/*
* Macro to test whether the plat_local_state is RUN state
*/
#define is_local_state_run(plat_local_state) \
((plat_local_state) == PSCI_LOCAL_STATE_RUN)
/*
* Macro to test whether the plat_local_state is RETENTION state
*/
#define is_local_state_retn(plat_local_state) \
(((plat_local_state) > PSCI_LOCAL_STATE_RUN) && \
((plat_local_state) <= PLAT_MAX_RET_STATE))
/*
* Macro to test whether the plat_local_state is OFF state
*/
#define is_local_state_off(plat_local_state) \
(((plat_local_state) > PLAT_MAX_RET_STATE) && \
((plat_local_state) <= PLAT_MAX_OFF_STATE))
/*****************************************************************************
* This data structure defines the representation of the power state parameter
* for its exchange between the generic PSCI code and the platform port. For
* example, it is used by the platform port to specify the requested power
* states during a power management operation. It is used by the generic code to
* inform the platform about the target power states that each level should
* enter.
****************************************************************************/
typedef
struct
psci_power_state
{
/*
* The pwr_domain_state[] stores the local power state at each level
* for the CPU.
*/
plat_local_state_t
pwr_domain_state
[
PLAT_MAX_PWR_LVL
+
1
];
}
psci_power_state_t
;
/*******************************************************************************
* Structure used to store per-cpu information relevant to the PSCI service.
...
...
@@ -170,11 +240,19 @@
* this information will not reside on a cache line shared with another cpu.
******************************************************************************/
typedef
struct
psci_cpu_data
{
uint32_t
power_state
;
uint32_t
max_phys_off_afflvl
;
/* Highest affinity level in physically
powered off state */
/* State as seen by PSCI Affinity Info API */
aff_info_state_t
aff_info_state
;
/*
* Highest power level which takes part in a power management
* operation.
*/
unsigned
char
target_pwrlvl
;
/* The local power state of this CPU */
plat_local_state_t
local_state
;
#if !USE_COHERENT_MEM
bakery_info_t
pcpu_bakery_info
[
PSCI_NUM_
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