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
7963671c
Commit
7963671c
authored
Aug 20, 2014
by
danh-arm
Browse files
Merge pull request #194 from danh-arm/sm/tf-issues#98
Implement the CPU Specific operations framework v3
parents
f139a39a
3fd5ddfe
Changes
40
Hide whitespace changes
Inline
Side-by-side
include/lib/cpus/aarch64/cpu_macros.S
0 → 100644
View file @
7963671c
/*
*
Copyright
(
c
)
2014
,
ARM
Limited
and
Contributors
.
All
rights
reserved
.
*
*
Redistribution
and
use
in
source
and
binary
forms
,
with
or
without
*
modification
,
are
permitted
provided
that
the
following
conditions
are
met
:
*
*
Redistributions
of
source
code
must
retain
the
above
copyright
notice
,
this
*
list
of
conditions
and
the
following
disclaimer
.
*
*
Redistributions
in
binary
form
must
reproduce
the
above
copyright
notice
,
*
this
list
of
conditions
and
the
following
disclaimer
in
the
documentation
*
and
/
or
other
materials
provided
with
the
distribution
.
*
*
Neither
the
name
of
ARM
nor
the
names
of
its
contributors
may
be
used
*
to
endorse
or
promote
products
derived
from
this
software
without
specific
*
prior
written
permission
.
*
*
THIS
SOFTWARE
IS
PROVIDED
BY
THE
COPYRIGHT
HOLDERS
AND
CONTRIBUTORS
"AS IS"
*
AND
ANY
EXPRESS
OR
IMPLIED
WARRANTIES
,
INCLUDING
,
BUT
NOT
LIMITED
TO
,
THE
*
IMPLIED
WARRANTIES
OF
MERCHANTABILITY
AND
FITNESS
FOR
A
PARTICULAR
PURPOSE
*
ARE
DISCLAIMED
.
IN
NO
EVENT
SHALL
THE
COPYRIGHT
HOLDER
OR
CONTRIBUTORS
BE
*
LIABLE
FOR
ANY
DIRECT
,
INDIRECT
,
INCIDENTAL
,
SPECIAL
,
EXEMPLARY
,
OR
*
CONSEQUENTIAL
DAMAGES
(
INCLUDING
,
BUT
NOT
LIMITED
TO
,
PROCUREMENT
OF
*
SUBSTITUTE
GOODS
OR
SERVICES
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
*
INTERRUPTION
)
HOWEVER
CAUSED
AND
ON
ANY
THEORY
OF
LIABILITY
,
WHETHER
IN
*
CONTRACT
,
STRICT
LIABILITY
,
OR
TORT
(
INCLUDING
NEGLIGENCE
OR
OTHERWISE
)
*
ARISING
IN
ANY
WAY
OUT
OF
THE
USE
OF
THIS
SOFTWARE
,
EVEN
IF
ADVISED
OF
THE
*
POSSIBILITY
OF
SUCH
DAMAGE
.
*/
#include <arch.h>
#define CPU_IMPL_PN_MASK (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \
(
MIDR_PN_MASK
<<
MIDR_PN_SHIFT
)
/
*
*
Define
the
offsets
to
the
fields
in
cpu_ops
structure
.
*/
.
struct
0
CPU_MIDR
:
/
*
cpu_ops
midr
*/
.
space
8
/*
Reset
fn
is
needed
in
BL
at
reset
vector
*/
#if IMAGE_BL1 || (IMAGE_BL31 && RESET_TO_BL31)
CPU_RESET_FUNC
:
/
*
cpu_ops
reset_func
*/
.
space
8
#endif
#if IMAGE_BL31 /* The power down core and cluster is needed only in BL3-1 */
CPU_PWR_DWN_CORE
:
/
*
cpu_ops
core_pwr_dwn
*/
.
space
8
CPU_PWR_DWN_CLUSTER
:
/
*
cpu_ops
cluster_pwr_dwn
*/
.
space
8
#endif
#if (IMAGE_BL31 && CRASH_REPORTING)
CPU_REG_DUMP
:
/
*
cpu
specific
register
dump
for
crash
reporting
*/
.
space
8
#endif
CPU_OPS_SIZE
=
.
/
*
*
Convenience
macro
to
declare
cpu_ops
structure
.
*
Make
sure
the
structure
fields
are
as
per
the
offsets
*
defined
above
.
*/
.
macro
declare_cpu_ops
_name
:
req
,
_midr
:
req
,
_noresetfunc
=
0
.
section
cpu_ops
,
"a"
; .align 3
.
type
cpu_ops_
\
_name
,
%
object
.
quad
\
_midr
#if IMAGE_BL1 || (IMAGE_BL31 && RESET_TO_BL31)
.
if
\
_noresetfunc
.
quad
0
.
else
.
quad
\
_name
\
()
_reset_func
.
endif
#endif
#if IMAGE_BL31
.
quad
\
_name
\
()
_core_pwr_dwn
.
quad
\
_name
\
()
_cluster_pwr_dwn
#endif
#if (IMAGE_BL31 && CRASH_REPORTING)
.
quad
\
_name
\
()
_cpu_reg_dump
#endif
.
endm
include/plat/common/plat_config.h
View file @
7963671c
...
@@ -39,14 +39,12 @@
...
@@ -39,14 +39,12 @@
enum
plat_config_flags
{
enum
plat_config_flags
{
/* Whether CPUECTLR SMP bit should be enabled */
CONFIG_CPUECTLR_SMP_BIT
=
0x1
,
/* Whether Base FVP memory map is in use */
/* Whether Base FVP memory map is in use */
CONFIG_BASE_MMAP
=
0x
2
,
CONFIG_BASE_MMAP
=
0x
1
,
/* Whether CCI should be enabled */
/* Whether CCI should be enabled */
CONFIG_HAS_CCI
=
0x
4
,
CONFIG_HAS_CCI
=
0x
2
,
/* Whether TZC should be configured */
/* Whether TZC should be configured */
CONFIG_HAS_TZC
=
0x
8
CONFIG_HAS_TZC
=
0x
4
};
};
typedef
struct
plat_config
{
typedef
struct
plat_config
{
...
...
lib/cpus/aarch64/aem_generic.S
0 → 100644
View file @
7963671c
/*
*
Copyright
(
c
)
2014
,
ARM
Limited
and
Contributors
.
All
rights
reserved
.
*
*
Redistribution
and
use
in
source
and
binary
forms
,
with
or
without
*
modification
,
are
permitted
provided
that
the
following
conditions
are
met
:
*
*
Redistributions
of
source
code
must
retain
the
above
copyright
notice
,
this
*
list
of
conditions
and
the
following
disclaimer
.
*
*
Redistributions
in
binary
form
must
reproduce
the
above
copyright
notice
,
*
this
list
of
conditions
and
the
following
disclaimer
in
the
documentation
*
and
/
or
other
materials
provided
with
the
distribution
.
*
*
Neither
the
name
of
ARM
nor
the
names
of
its
contributors
may
be
used
*
to
endorse
or
promote
products
derived
from
this
software
without
specific
*
prior
written
permission
.
*
*
THIS
SOFTWARE
IS
PROVIDED
BY
THE
COPYRIGHT
HOLDERS
AND
CONTRIBUTORS
"AS IS"
*
AND
ANY
EXPRESS
OR
IMPLIED
WARRANTIES
,
INCLUDING
,
BUT
NOT
LIMITED
TO
,
THE
*
IMPLIED
WARRANTIES
OF
MERCHANTABILITY
AND
FITNESS
FOR
A
PARTICULAR
PURPOSE
*
ARE
DISCLAIMED
.
IN
NO
EVENT
SHALL
THE
COPYRIGHT
HOLDER
OR
CONTRIBUTORS
BE
*
LIABLE
FOR
ANY
DIRECT
,
INDIRECT
,
INCIDENTAL
,
SPECIAL
,
EXEMPLARY
,
OR
*
CONSEQUENTIAL
DAMAGES
(
INCLUDING
,
BUT
NOT
LIMITED
TO
,
PROCUREMENT
OF
*
SUBSTITUTE
GOODS
OR
SERVICES
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
*
INTERRUPTION
)
HOWEVER
CAUSED
AND
ON
ANY
THEORY
OF
LIABILITY
,
WHETHER
IN
*
CONTRACT
,
STRICT
LIABILITY
,
OR
TORT
(
INCLUDING
NEGLIGENCE
OR
OTHERWISE
)
*
ARISING
IN
ANY
WAY
OUT
OF
THE
USE
OF
THIS
SOFTWARE
,
EVEN
IF
ADVISED
OF
THE
*
POSSIBILITY
OF
SUCH
DAMAGE
.
*/
#include <aem_generic.h>
#include <arch.h>
#include <asm_macros.S>
#include <cpu_macros.S>
func
aem_generic_core_pwr_dwn
/
*
---------------------------------------------
*
Disable
the
Data
Cache
.
*
---------------------------------------------
*/
mrs
x1
,
sctlr_el3
bic
x1
,
x1
,
#
SCTLR_C_BIT
msr
sctlr_el3
,
x1
isb
mov
x0
,
#
DCCISW
/
*
---------------------------------------------
*
Flush
L1
cache
to
PoU
.
*
---------------------------------------------
*/
b
dcsw_op_louis
func
aem_generic_cluster_pwr_dwn
/
*
---------------------------------------------
*
Disable
the
Data
Cache
.
*
---------------------------------------------
*/
mrs
x1
,
sctlr_el3
bic
x1
,
x1
,
#
SCTLR_C_BIT
msr
sctlr_el3
,
x1
isb
/
*
---------------------------------------------
*
Flush
L1
and
L2
caches
to
PoC
.
*
---------------------------------------------
*/
mov
x0
,
#
DCCISW
b
dcsw_op_all
/
*
---------------------------------------------
*
This
function
provides
cpu
specific
*
register
information
for
crash
reporting
.
*
It
needs
to
return
with
x6
pointing
to
*
a
list
of
register
names
in
ascii
and
*
x8
-
x15
having
values
of
registers
to
be
*
reported
.
*
---------------------------------------------
*/
func
aem_generic_cpu_reg_dump
mov
x6
,
#
0
/*
no
registers
to
report
*/
ret
/*
cpu_ops
for
Base
AEM
FVP
*/
declare_cpu_ops
aem_generic
,
BASE_AEM_MIDR
,
1
/*
cpu_ops
for
Foundation
FVP
*/
declare_cpu_ops
aem_generic
,
FOUNDATION_AEM_MIDR
,
1
lib/cpus/aarch64/cortex_a53.S
0 → 100644
View file @
7963671c
/*
*
Copyright
(
c
)
2014
,
ARM
Limited
and
Contributors
.
All
rights
reserved
.
*
*
Redistribution
and
use
in
source
and
binary
forms
,
with
or
without
*
modification
,
are
permitted
provided
that
the
following
conditions
are
met
:
*
*
Redistributions
of
source
code
must
retain
the
above
copyright
notice
,
this
*
list
of
conditions
and
the
following
disclaimer
.
*
*
Redistributions
in
binary
form
must
reproduce
the
above
copyright
notice
,
*
this
list
of
conditions
and
the
following
disclaimer
in
the
documentation
*
and
/
or
other
materials
provided
with
the
distribution
.
*
*
Neither
the
name
of
ARM
nor
the
names
of
its
contributors
may
be
used
*
to
endorse
or
promote
products
derived
from
this
software
without
specific
*
prior
written
permission
.
*
*
THIS
SOFTWARE
IS
PROVIDED
BY
THE
COPYRIGHT
HOLDERS
AND
CONTRIBUTORS
"AS IS"
*
AND
ANY
EXPRESS
OR
IMPLIED
WARRANTIES
,
INCLUDING
,
BUT
NOT
LIMITED
TO
,
THE
*
IMPLIED
WARRANTIES
OF
MERCHANTABILITY
AND
FITNESS
FOR
A
PARTICULAR
PURPOSE
*
ARE
DISCLAIMED
.
IN
NO
EVENT
SHALL
THE
COPYRIGHT
HOLDER
OR
CONTRIBUTORS
BE
*
LIABLE
FOR
ANY
DIRECT
,
INDIRECT
,
INCIDENTAL
,
SPECIAL
,
EXEMPLARY
,
OR
*
CONSEQUENTIAL
DAMAGES
(
INCLUDING
,
BUT
NOT
LIMITED
TO
,
PROCUREMENT
OF
*
SUBSTITUTE
GOODS
OR
SERVICES
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
*
INTERRUPTION
)
HOWEVER
CAUSED
AND
ON
ANY
THEORY
OF
LIABILITY
,
WHETHER
IN
*
CONTRACT
,
STRICT
LIABILITY
,
OR
TORT
(
INCLUDING
NEGLIGENCE
OR
OTHERWISE
)
*
ARISING
IN
ANY
WAY
OUT
OF
THE
USE
OF
THIS
SOFTWARE
,
EVEN
IF
ADVISED
OF
THE
*
POSSIBILITY
OF
SUCH
DAMAGE
.
*/
#include <arch.h>
#include <asm_macros.S>
#include <cortex_a53.h>
#include <cpu_macros.S>
#include <plat_macros.S>
/
*
---------------------------------------------
*
Disable
L1
data
cache
and
unified
L2
cache
*
---------------------------------------------
*/
func
cortex_a53_disable_dcache
mrs
x1
,
sctlr_el3
bic
x1
,
x1
,
#
SCTLR_C_BIT
msr
sctlr_el3
,
x1
isb
ret
/
*
---------------------------------------------
*
Disable
intra
-
cluster
coherency
*
---------------------------------------------
*/
func
cortex_a53_disable_smp
mrs
x0
,
CPUECTLR_EL1
bic
x0
,
x0
,
#
CPUECTLR_SMP_BIT
msr
CPUECTLR_EL1
,
x0
isb
dsb
sy
ret
func
cortex_a53_reset_func
/
*
---------------------------------------------
*
As
a
bare
minimum
enable
the
SMP
bit
.
*
---------------------------------------------
*/
mrs
x0
,
CPUECTLR_EL1
orr
x0
,
x0
,
#
CPUECTLR_SMP_BIT
msr
CPUECTLR_EL1
,
x0
isb
ret
func
cortex_a53_core_pwr_dwn
mov
x18
,
x30
/
*
---------------------------------------------
*
Turn
off
caches
.
*
---------------------------------------------
*/
bl
cortex_a53_disable_dcache
/
*
---------------------------------------------
*
Flush
L1
cache
to
PoU
.
*
---------------------------------------------
*/
mov
x0
,
#
DCCISW
bl
dcsw_op_louis
/
*
---------------------------------------------
*
Come
out
of
intra
cluster
coherency
*
---------------------------------------------
*/
mov
x30
,
x18
b
cortex_a53_disable_smp
func
cortex_a53_cluster_pwr_dwn
mov
x18
,
x30
/
*
---------------------------------------------
*
Turn
off
caches
.
*
---------------------------------------------
*/
bl
cortex_a53_disable_dcache
/
*
---------------------------------------------
*
Disable
the
optional
ACP
.
*
---------------------------------------------
*/
bl
plat_disable_acp
/
*
---------------------------------------------
*
Flush
L1
and
L2
caches
to
PoC
.
*
---------------------------------------------
*/
mov
x0
,
#
DCCISW
bl
dcsw_op_all
/
*
---------------------------------------------
*
Come
out
of
intra
cluster
coherency
*
---------------------------------------------
*/
mov
x30
,
x18
b
cortex_a53_disable_smp
/
*
---------------------------------------------
*
This
function
provides
cortex_a53
specific
*
register
information
for
crash
reporting
.
*
It
needs
to
return
with
x6
pointing
to
*
a
list
of
register
names
in
ascii
and
*
x8
-
x15
having
values
of
registers
to
be
*
reported
.
*
---------------------------------------------
*/
.
section
.
rodata.
cortex_a53_regs
,
"aS"
cortex_a53_regs
:
/
*
The
ascii
list
of
register
names
to
be
reported
*/
.
asciz
"cpuectlr_el1"
,
""
func
cortex_a53_cpu_reg_dump
adr
x6
,
cortex_a53_regs
mrs
x8
,
CPUECTLR_EL1
ret
declare_cpu_ops
cortex_a53
,
CORTEX_A53_MIDR
lib/cpus/aarch64/cortex_a57.S
0 → 100644
View file @
7963671c
/*
*
Copyright
(
c
)
2014
,
ARM
Limited
and
Contributors
.
All
rights
reserved
.
*
*
Redistribution
and
use
in
source
and
binary
forms
,
with
or
without
*
modification
,
are
permitted
provided
that
the
following
conditions
are
met
:
*
*
Redistributions
of
source
code
must
retain
the
above
copyright
notice
,
this
*
list
of
conditions
and
the
following
disclaimer
.
*
*
Redistributions
in
binary
form
must
reproduce
the
above
copyright
notice
,
*
this
list
of
conditions
and
the
following
disclaimer
in
the
documentation
*
and
/
or
other
materials
provided
with
the
distribution
.
*
*
Neither
the
name
of
ARM
nor
the
names
of
its
contributors
may
be
used
*
to
endorse
or
promote
products
derived
from
this
software
without
specific
*
prior
written
permission
.
*
*
THIS
SOFTWARE
IS
PROVIDED
BY
THE
COPYRIGHT
HOLDERS
AND
CONTRIBUTORS
"AS IS"
*
AND
ANY
EXPRESS
OR
IMPLIED
WARRANTIES
,
INCLUDING
,
BUT
NOT
LIMITED
TO
,
THE
*
IMPLIED
WARRANTIES
OF
MERCHANTABILITY
AND
FITNESS
FOR
A
PARTICULAR
PURPOSE
*
ARE
DISCLAIMED
.
IN
NO
EVENT
SHALL
THE
COPYRIGHT
HOLDER
OR
CONTRIBUTORS
BE
*
LIABLE
FOR
ANY
DIRECT
,
INDIRECT
,
INCIDENTAL
,
SPECIAL
,
EXEMPLARY
,
OR
*
CONSEQUENTIAL
DAMAGES
(
INCLUDING
,
BUT
NOT
LIMITED
TO
,
PROCUREMENT
OF
*
SUBSTITUTE
GOODS
OR
SERVICES
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
*
INTERRUPTION
)
HOWEVER
CAUSED
AND
ON
ANY
THEORY
OF
LIABILITY
,
WHETHER
IN
*
CONTRACT
,
STRICT
LIABILITY
,
OR
TORT
(
INCLUDING
NEGLIGENCE
OR
OTHERWISE
)
*
ARISING
IN
ANY
WAY
OUT
OF
THE
USE
OF
THIS
SOFTWARE
,
EVEN
IF
ADVISED
OF
THE
*
POSSIBILITY
OF
SUCH
DAMAGE
.
*/
#include <arch.h>
#include <asm_macros.S>
#include <assert_macros.S>
#include <cortex_a57.h>
#include <cpu_macros.S>
#include <plat_macros.S>
/
*
---------------------------------------------
*
Disable
L1
data
cache
and
unified
L2
cache
*
---------------------------------------------
*/
func
cortex_a57_disable_dcache
mrs
x1
,
sctlr_el3
bic
x1
,
x1
,
#
SCTLR_C_BIT
msr
sctlr_el3
,
x1
isb
ret
/
*
---------------------------------------------
*
Disable
all
types
of
L2
prefetches
.
*
---------------------------------------------
*/
func
cortex_a57_disable_l2_prefetch
mrs
x0
,
CPUECTLR_EL1
orr
x0
,
x0
,
#
CPUECTLR_DIS_TWD_ACC_PFTCH_BIT
mov
x1
,
#
CPUECTLR_L2_IPFTCH_DIST_MASK
orr
x1
,
x1
,
#
CPUECTLR_L2_DPFTCH_DIST_MASK
bic
x0
,
x0
,
x1
msr
CPUECTLR_EL1
,
x0
isb
dsb
sy
ret
/
*
---------------------------------------------
*
Disable
intra
-
cluster
coherency
*
---------------------------------------------
*/
func
cortex_a57_disable_smp
mrs
x0
,
CPUECTLR_EL1
bic
x0
,
x0
,
#
CPUECTLR_SMP_BIT
msr
CPUECTLR_EL1
,
x0
ret
/
*
---------------------------------------------
*
Disable
debug
interfaces
*
---------------------------------------------
*/
func
cortex_a57_disable_ext_debug
mov
x0
,
#
1
msr
osdlr_el1
,
x0
isb
dsb
sy
ret
func
cortex_a57_reset_func
#if ERRATA_A57_806969 || ERRATA_A57_813420
/
*
---------------------------------------------
*
Ensure
that
the
following
errata
is
only
*
applied
on
r0p0
parts
.
*
---------------------------------------------
*/
#if ASM_ASSERTION
mrs
x0
,
midr_el1
ubfx
x1
,
x0
,
#
MIDR_VAR_SHIFT
,
#
4
ubfx
x2
,
x0
,
#
MIDR_REV_SHIFT
,
#
4
orr
x0
,
x1
,
x2
cmp
x0
,
#
0
ASM_ASSERT
(
eq
)
#endif
mov
x1
,
xzr
#if ERRATA_A57_806969
orr
x1
,
x1
,
#
CPUACTLR_NO_ALLOC_WBWA
#endif
#if ERRATA_A57_813420
orr
x1
,
x1
,
#
CPUACTLR_DCC_AS_DCCI
#endif
mrs
x0
,
CPUACTLR_EL1
orr
x0
,
x0
,
x1
msr
CPUACTLR_EL1
,
x0
#endif
/
*
---------------------------------------------
*
As
a
bare
minimum
enable
the
SMP
bit
.
*
---------------------------------------------
*/
mrs
x0
,
CPUECTLR_EL1
orr
x0
,
x0
,
#
CPUECTLR_SMP_BIT
msr
CPUECTLR_EL1
,
x0
isb
ret
func
cortex_a57_core_pwr_dwn
mov
x18
,
x30
/
*
---------------------------------------------
*
Turn
off
caches
.
*
---------------------------------------------
*/
bl
cortex_a57_disable_dcache
/
*
---------------------------------------------
*
Disable
the
L2
prefetches
.
*
---------------------------------------------
*/
bl
cortex_a57_disable_l2_prefetch
/
*
---------------------------------------------
*
Flush
L1
cache
to
PoU
.
*
---------------------------------------------
*/
mov
x0
,
#
DCCISW
bl
dcsw_op_louis
/
*
---------------------------------------------
*
Come
out
of
intra
cluster
coherency
*
---------------------------------------------
*/
bl
cortex_a57_disable_smp
/
*
---------------------------------------------
*
Force
the
debug
interfaces
to
be
quiescent
*
---------------------------------------------
*/
mov
x30
,
x18
b
cortex_a57_disable_ext_debug
func
cortex_a57_cluster_pwr_dwn
mov
x18
,
x30
/
*
---------------------------------------------
*
Turn
off
caches
.
*
---------------------------------------------
*/
bl
cortex_a57_disable_dcache
/
*
---------------------------------------------
*
Disable
the
L2
prefetches
.
*
---------------------------------------------
*/
bl
cortex_a57_disable_l2_prefetch
/
*
---------------------------------------------
*
Disable
the
optional
ACP
.
*
---------------------------------------------
*/
bl
plat_disable_acp
/
*
---------------------------------------------
*
Flush
L1
and
L2
caches
to
PoC
.
*
---------------------------------------------
*/
mov
x0
,
#
DCCISW
bl
dcsw_op_all
/
*
---------------------------------------------
*
Come
out
of
intra
cluster
coherency
*
---------------------------------------------
*/
bl
cortex_a57_disable_smp
/
*
---------------------------------------------
*
Force
the
debug
interfaces
to
be
quiescent
*
---------------------------------------------
*/
mov
x30
,
x18
b
cortex_a57_disable_ext_debug
/
*
---------------------------------------------
*
This
function
provides
cortex_a57
specific
*
register
information
for
crash
reporting
.
*
It
needs
to
return
with
x6
pointing
to
*
a
list
of
register
names
in
ascii
and
*
x8
-
x15
having
values
of
registers
to
be
*
reported
.
*
---------------------------------------------
*/
.
section
.
rodata.
cortex_a57_regs
,
"aS"
cortex_a57_regs
:
/
*
The
ascii
list
of
register
names
to
be
reported
*/
.
asciz
"cpuectlr_el1"
,
""
func
cortex_a57_cpu_reg_dump
adr
x6
,
cortex_a57_regs
mrs
x8
,
CPUECTLR_EL1
ret
declare_cpu_ops
cortex_a57
,
CORTEX_A57_MIDR
lib/cpus/aarch64/cpu_helpers.S
0 → 100644
View file @
7963671c
/*
*
Copyright
(
c
)
2014
,
ARM
Limited
and
Contributors
.
All
rights
reserved
.
*
*
Redistribution
and
use
in
source
and
binary
forms
,
with
or
without
*
modification
,
are
permitted
provided
that
the
following
conditions
are
met
:
*
*
Redistributions
of
source
code
must
retain
the
above
copyright
notice
,
this
*
list
of
conditions
and
the
following
disclaimer
.
*
*
Redistributions
in
binary
form
must
reproduce
the
above
copyright
notice
,
*
this
list
of
conditions
and
the
following
disclaimer
in
the
documentation
*
and
/
or
other
materials
provided
with
the
distribution
.
*
*
Neither
the
name
of
ARM
nor
the
names
of
its
contributors
may
be
used
*
to
endorse
or
promote
products
derived
from
this
software
without
specific
*
prior
written
permission
.
*
*
THIS
SOFTWARE
IS
PROVIDED
BY
THE
COPYRIGHT
HOLDERS
AND
CONTRIBUTORS
"AS IS"
*
AND
ANY
EXPRESS
OR
IMPLIED
WARRANTIES
,
INCLUDING
,
BUT
NOT
LIMITED
TO
,
THE
*
IMPLIED
WARRANTIES
OF
MERCHANTABILITY
AND
FITNESS
FOR
A
PARTICULAR
PURPOSE
*
ARE
DISCLAIMED
.
IN
NO
EVENT
SHALL
THE
COPYRIGHT
HOLDER
OR
CONTRIBUTORS
BE
*
LIABLE
FOR
ANY
DIRECT
,
INDIRECT
,
INCIDENTAL
,
SPECIAL
,
EXEMPLARY
,
OR
*
CONSEQUENTIAL
DAMAGES
(
INCLUDING
,
BUT
NOT
LIMITED
TO
,
PROCUREMENT
OF
*
SUBSTITUTE
GOODS
OR
SERVICES
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
*
INTERRUPTION
)
HOWEVER
CAUSED
AND
ON
ANY
THEORY
OF
LIABILITY
,
WHETHER
IN
*
CONTRACT
,
STRICT
LIABILITY
,
OR
TORT
(
INCLUDING
NEGLIGENCE
OR
OTHERWISE
)
*
ARISING
IN
ANY
WAY
OUT
OF
THE
USE
OF
THIS
SOFTWARE
,
EVEN
IF
ADVISED
OF
THE
*
POSSIBILITY
OF
SUCH
DAMAGE
.
*/
#include <arch.h>
#include <asm_macros.S>
#include <assert_macros.S>
#include <cpu_macros.S>
#if IMAGE_BL31
#include <cpu_data.h>
#endif
/
*
Reset
fn
is
needed
in
BL
at
reset
vector
*/
#if IMAGE_BL1 || (IMAGE_BL31 && RESET_TO_BL31)
/
*
*
The
reset
handler
common
to
all
platforms
.
After
a
matching
*
cpu_ops
structure
entry
is
found
,
the
correponding
reset_handler
*
in
the
cpu_ops
is
invoked
.
*/
.
globl
reset_handler
func
reset_handler
mov
x10
,
x30
bl
plat_reset_handler
/
*
Get
the
matching
cpu_ops
pointer
*/
bl
get_cpu_ops_ptr
#if ASM_ASSERTION
cmp
x0
,
#
0
ASM_ASSERT
(
ne
)
#endif
/
*
Get
the
cpu_ops
reset
handler
*/
ldr
x2
,
[
x0
,
#
CPU_RESET_FUNC
]
cbz
x2
,
1
f
blr
x2
1
:
ret
x10
#endif /* IMAGE_BL1 || (IMAGE_BL31 && RESET_TO_BL31) */
#if IMAGE_BL31 /* The power down core and cluster is needed only in BL31 */
/
*
*
The
prepare
core
power
down
function
for
all
platforms
.
After
*
the
cpu_ops
pointer
is
retrieved
from
cpu_data
,
the
corresponding
*
pwr_dwn_core
in
the
cpu_ops
is
invoked
.
*/
.
globl
prepare_core_pwr_dwn
func
prepare_core_pwr_dwn
mrs
x1
,
tpidr_el3
ldr
x0
,
[
x1
,
#
CPU_DATA_CPU_OPS_PTR
]
#if ASM_ASSERTION
cmp
x0
,
#
0
ASM_ASSERT
(
ne
)
#endif
/
*
Get
the
cpu_ops
core_pwr_dwn
handler
*/
ldr
x1
,
[
x0
,
#
CPU_PWR_DWN_CORE
]
br
x1
/
*
*
The
prepare
cluster
power
down
function
for
all
platforms
.
After
*
the
cpu_ops
pointer
is
retrieved
from
cpu_data
,
the
corresponding
*
pwr_dwn_cluster
in
the
cpu_ops
is
invoked
.
*/
.
globl
prepare_cluster_pwr_dwn
func
prepare_cluster_pwr_dwn
mrs
x1
,
tpidr_el3
ldr
x0
,
[
x1
,
#
CPU_DATA_CPU_OPS_PTR
]
#if ASM_ASSERTION
cmp
x0
,
#
0
ASM_ASSERT
(
ne
)
#endif
/
*
Get
the
cpu_ops
cluster_pwr_dwn
handler
*/
ldr
x1
,
[
x0
,
#
CPU_PWR_DWN_CLUSTER
]
br
x1
/
*
*
Initializes
the
cpu_ops_ptr
if
not
already
initialized
*
in
cpu_data
.
This
can
be
called
without
a
runtime
stack
.
*
clobbers
:
x0
-
x6
,
x10
*/
.
globl
init_cpu_ops
func
init_cpu_ops
mrs
x6
,
tpidr_el3
ldr
x0
,
[
x6
,
#
CPU_DATA_CPU_OPS_PTR
]
cbnz
x0
,
1
f
mov
x10
,
x30
bl
get_cpu_ops_ptr
#if ASM_ASSERTION
cmp
x0
,
#
0
ASM_ASSERT
(
ne
)
#endif
str
x0
,
[
x6
,
#
CPU_DATA_CPU_OPS_PTR
]
mov
x30
,
x10
1
:
ret
#endif /* IMAGE_BL31 */
#if IMAGE_BL31 && CRASH_REPORTING
/
*
*
The
cpu
specific
registers
which
need
to
be
reported
in
a
crash
*
are
reported
via
cpu_ops
cpu_reg_dump
function
.
After
a
matching
*
cpu_ops
structure
entry
is
found
,
the
correponding
cpu_reg_dump
*
in
the
cpu_ops
is
invoked
.
*/
.
globl
do_cpu_reg_dump
func
do_cpu_reg_dump
mov
x16
,
x30
/
*
Get
the
matching
cpu_ops
pointer
*/
bl
get_cpu_ops_ptr
cbz
x0
,
1
f
/
*
Get
the
cpu_ops
cpu_reg_dump
*/
ldr
x2
,
[
x0
,
#
CPU_REG_DUMP
]
cbz
x2
,
1
f
blr
x2
1
:
mov
x30
,
x16
ret
#endif
/
*
*
The
below
function
returns
the
cpu_ops
structure
matching
the
*
midr
of
the
core
.
It
reads
the
MIDR_EL1
and
finds
the
matching
*
entry
in
cpu_ops
entries
.
Only
the
implementation
and
part
number
*
are
used
to
match
the
entries
.
*
Return
:
*
x0
-
The
matching
cpu_ops
pointer
on
Success
*
x0
-
0
on
failure
.
*
Clobbers
:
x0
-
x5
*/
.
globl
get_cpu_ops_ptr
func
get_cpu_ops_ptr
/
*
Get
the
cpu_ops
start
and
end
locations
*/
adr
x4
,
(
__CPU_OPS_START__
+
CPU_MIDR
)
adr
x5
,
(
__CPU_OPS_END__
+
CPU_MIDR
)
/
*
Initialize
the
return
parameter
*/
mov
x0
,
#
0
/
*
Read
the
MIDR_EL1
*/
mrs
x2
,
midr_el1
mov_imm
x3
,
CPU_IMPL_PN_MASK
/
*
Retain
only
the
implementation
and
part
number
using
mask
*/
and
w2
,
w2
,
w3
1
:
/
*
Check
if
we
have
reached
end
of
list
*/
cmp
x4
,
x5
b.eq
error_exit
/
*
load
the
midr
from
the
cpu_ops
*/
ldr
x1
,
[
x4
],
#
CPU_OPS_SIZE
and
w1
,
w1
,
w3
/
*
Check
if
midr
matches
to
midr
of
this
core
*/
cmp
w1
,
w2
b.ne
1
b
/
*
Subtract
the
increment
and
offset
to
get
the
cpu
-
ops
pointer
*/
sub
x0
,
x4
,
#(
CPU_OPS_SIZE
+
CPU_MIDR
)
error_exit
:
ret
lib/cpus/cpu-errata.mk
0 → 100644
View file @
7963671c
#
# Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of ARM nor the names of its contributors may be used
# to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# CPU Errata Build flags. These should be enabled by the
# platform if the errata needs to be applied.
# Flag to apply errata 806969 during reset. This errata applies only to
# revision r0p0 of the Cortex A57 cpu.
ERRATA_A57_806969
?=
0
# Flag to apply errata 813420 during reset. This errata applies only to
# revision r0p0 of the Cortex A57 cpu.
ERRATA_A57_813420
?=
0
# Process ERRATA_A57_806969 flag
$(eval
$(call
assert_boolean,ERRATA_A57_806969))
$(eval
$(call
add_define,ERRATA_A57_806969))
# Process ERRATA_A57_813420 flag
$(eval
$(call
assert_boolean,ERRATA_A57_813420))
$(eval
$(call
add_define,ERRATA_A57_813420))
plat/common/aarch64/platform_helpers.S
View file @
7963671c
...
@@ -38,6 +38,8 @@
...
@@ -38,6 +38,8 @@
.
weak
plat_report_exception
.
weak
plat_report_exception
.
weak
plat_crash_console_init
.
weak
plat_crash_console_init
.
weak
plat_crash_console_putc
.
weak
plat_crash_console_putc
.
weak
plat_reset_handler
.
weak
plat_disable_acp
/
*
-----------------------------------------------------
/
*
-----------------------------------------------------
*
int
platform_get_core_pos
(
int
mpidr
)
;
*
int
platform_get_core_pos
(
int
mpidr
)
;
...
@@ -84,3 +86,20 @@ func plat_crash_console_init
...
@@ -84,3 +86,20 @@ func plat_crash_console_init
*/
*/
func
plat_crash_console_putc
func
plat_crash_console_putc
ret
ret
/
*
-----------------------------------------------------
*
Placeholder
function
which
should
be
redefined
by
*
each
platform
.
This
function
should
preserve
x10
.
*
-----------------------------------------------------
*/
func
plat_reset_handler
ret
/
*
-----------------------------------------------------
*
Placeholder
function
which
should
be
redefined
by
*
each
platform
.
This
function
is
allowed
to
use
*
registers
x0
-
x17
.
*
-----------------------------------------------------
*/
func
plat_disable_acp
ret
plat/fvp/aarch64/fvp_common.c
View file @
7963671c
...
@@ -134,7 +134,7 @@ DEFINE_CONFIGURE_MMU_EL(3)
...
@@ -134,7 +134,7 @@ DEFINE_CONFIGURE_MMU_EL(3)
******************************************************************************/
******************************************************************************/
int
fvp_config_setup
(
void
)
int
fvp_config_setup
(
void
)
{
{
unsigned
int
rev
,
hbi
,
bld
,
arch
,
sys_id
,
midr_pn
;
unsigned
int
rev
,
hbi
,
bld
,
arch
,
sys_id
;
sys_id
=
mmio_read_32
(
VE_SYSREGS_BASE
+
V2M_SYS_ID
);
sys_id
=
mmio_read_32
(
VE_SYSREGS_BASE
+
V2M_SYS_ID
);
rev
=
(
sys_id
>>
SYS_ID_REV_SHIFT
)
&
SYS_ID_REV_MASK
;
rev
=
(
sys_id
>>
SYS_ID_REV_SHIFT
)
&
SYS_ID_REV_MASK
;
...
@@ -193,11 +193,6 @@ int fvp_config_setup(void)
...
@@ -193,11 +193,6 @@ int fvp_config_setup(void)
}
}
break
;
break
;
case
HBI_FVP_BASE
:
case
HBI_FVP_BASE
:
midr_pn
=
(
read_midr
()
>>
MIDR_PN_SHIFT
)
&
MIDR_PN_MASK
;
plat_config
.
flags
=
((
midr_pn
==
MIDR_PN_A57
)
||
(
midr_pn
==
MIDR_PN_A53
))
?
CONFIG_CPUECTLR_SMP_BIT
:
0
;
plat_config
.
max_aff0
=
4
;
plat_config
.
max_aff0
=
4
;
plat_config
.
max_aff1
=
2
;
plat_config
.
max_aff1
=
2
;
plat_config
.
flags
|=
CONFIG_BASE_MMAP
|
CONFIG_HAS_CCI
|
plat_config
.
flags
|=
CONFIG_BASE_MMAP
|
CONFIG_HAS_CCI
|
...
...
plat/fvp/fvp_pm.c
View file @
7963671c
...
@@ -39,10 +39,83 @@
...
@@ -39,10 +39,83 @@
#include <plat_config.h>
#include <plat_config.h>
#include <platform_def.h>
#include <platform_def.h>
#include <psci.h>
#include <psci.h>
#include <errno.h>
#include "drivers/pwrc/fvp_pwrc.h"
#include "drivers/pwrc/fvp_pwrc.h"
#include "fvp_def.h"
#include "fvp_def.h"
#include "fvp_private.h"
#include "fvp_private.h"
/*******************************************************************************
* Private FVP function to program the mailbox for a cpu before it is released
* from reset.
******************************************************************************/
static
void
fvp_program_mailbox
(
uint64_t
mpidr
,
uint64_t
address
)
{
uint64_t
linear_id
;
mailbox_t
*
fvp_mboxes
;
linear_id
=
platform_get_core_pos
(
mpidr
);
fvp_mboxes
=
(
mailbox_t
*
)
MBOX_BASE
;
fvp_mboxes
[
linear_id
].
value
=
address
;
flush_dcache_range
((
unsigned
long
)
&
fvp_mboxes
[
linear_id
],
sizeof
(
unsigned
long
));
}
/*******************************************************************************
* Function which implements the common FVP specific operations to power down a
* cpu in response to a CPU_OFF or CPU_SUSPEND request.
******************************************************************************/
static
void
fvp_cpu_pwrdwn_common
()
{
/* Prevent interrupts from spuriously waking up this cpu */
arm_gic_cpuif_deactivate
();
/* Program the power controller to power off this cpu. */
fvp_pwrc_write_ppoffr
(
read_mpidr_el1
());
}
/*******************************************************************************
* Function which implements the common FVP specific operations to power down a
* cluster in response to a CPU_OFF or CPU_SUSPEND request.
******************************************************************************/
static
void
fvp_cluster_pwrdwn_common
()
{
uint64_t
mpidr
=
read_mpidr_el1
();
/* Disable coherency if this cluster is to be turned off */
if
(
get_plat_config
()
->
flags
&
CONFIG_HAS_CCI
)
cci_disable_cluster_coherency
(
mpidr
);
/* Program the power controller to turn the cluster off */
fvp_pwrc_write_pcoffr
(
mpidr
);
}
/*******************************************************************************
* Private FVP function which is used to determine if any platform actions
* should be performed for the specified affinity instance given its
* state. Nothing needs to be done if the 'state' is not off or if this is not
* the highest affinity level which will enter the 'state'.
******************************************************************************/
static
int32_t
fvp_do_plat_actions
(
unsigned
int
afflvl
,
unsigned
int
state
)
{
unsigned
int
max_phys_off_afflvl
;
assert
(
afflvl
<=
MPIDR_AFFLVL1
);
if
(
state
!=
PSCI_STATE_OFF
)
return
-
EAGAIN
;
/*
* Find the highest affinity level which will be suspended and postpone
* all the platform specific actions until that level is hit.
*/
max_phys_off_afflvl
=
psci_get_max_phys_off_afflvl
();
assert
(
max_phys_off_afflvl
!=
PSCI_INVALID_DATA
);
if
(
afflvl
!=
max_phys_off_afflvl
)
return
-
EAGAIN
;
return
0
;
}
/*******************************************************************************
/*******************************************************************************
* FVP handler called when an affinity instance is about to enter standby.
* FVP handler called when an affinity instance is about to enter standby.
******************************************************************************/
******************************************************************************/
...
@@ -81,8 +154,6 @@ int fvp_affinst_on(unsigned long mpidr,
...
@@ -81,8 +154,6 @@ int fvp_affinst_on(unsigned long mpidr,
unsigned
int
state
)
unsigned
int
state
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
int
rc
=
PSCI_E_SUCCESS
;
unsigned
long
linear_id
;
mailbox_t
*
fvp_mboxes
;
unsigned
int
psysr
;
unsigned
int
psysr
;
/*
/*
...
@@ -90,7 +161,7 @@ int fvp_affinst_on(unsigned long mpidr,
...
@@ -90,7 +161,7 @@ int fvp_affinst_on(unsigned long mpidr,
* on the FVP. Ignore any other affinity level.
* on the FVP. Ignore any other affinity level.
*/
*/
if
(
afflvl
!=
MPIDR_AFFLVL0
)
if
(
afflvl
!=
MPIDR_AFFLVL0
)
goto
exit
;
return
rc
;
/*
/*
* Ensure that we do not cancel an inflight power off request
* Ensure that we do not cancel an inflight power off request
...
@@ -103,15 +174,9 @@ int fvp_affinst_on(unsigned long mpidr,
...
@@ -103,15 +174,9 @@ int fvp_affinst_on(unsigned long mpidr,
psysr
=
fvp_pwrc_read_psysr
(
mpidr
);
psysr
=
fvp_pwrc_read_psysr
(
mpidr
);
}
while
(
psysr
&
PSYSR_AFF_L0
);
}
while
(
psysr
&
PSYSR_AFF_L0
);
linear_id
=
platform_get_core_pos
(
mpidr
);
fvp_program_mailbox
(
mpidr
,
sec_entrypoint
);
fvp_mboxes
=
(
mailbox_t
*
)
MBOX_BASE
;
fvp_mboxes
[
linear_id
].
value
=
sec_entrypoint
;
flush_dcache_range
((
unsigned
long
)
&
fvp_mboxes
[
linear_id
],
sizeof
(
unsigned
long
));
fvp_pwrc_write_pponr
(
mpidr
);
fvp_pwrc_write_pponr
(
mpidr
);
exit:
return
rc
;
return
rc
;
}
}
...
@@ -130,60 +195,21 @@ int fvp_affinst_off(unsigned long mpidr,
...
@@ -130,60 +195,21 @@ int fvp_affinst_off(unsigned long mpidr,
unsigned
int
afflvl
,
unsigned
int
afflvl
,
unsigned
int
state
)
unsigned
int
state
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
/* Determine if any platform actions need to be executed */
unsigned
int
ectlr
;
if
(
fvp_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
return
PSCI_E_SUCCESS
;
switch
(
afflvl
)
{
case
MPIDR_AFFLVL1
:
if
(
state
==
PSCI_STATE_OFF
)
{
/*
* Disable coherency if this cluster is to be
* turned off
*/
if
(
get_plat_config
()
->
flags
&
CONFIG_HAS_CCI
)
cci_disable_cluster_coherency
(
mpidr
);
/*
* Program the power controller to turn the
* cluster off
*/
fvp_pwrc_write_pcoffr
(
mpidr
);
}
break
;
case
MPIDR_AFFLVL0
:
if
(
state
==
PSCI_STATE_OFF
)
{
/*
* Take this cpu out of intra-cluster coherency if
* the FVP flavour supports the SMP bit.
*/
if
(
get_plat_config
()
->
flags
&
CONFIG_CPUECTLR_SMP_BIT
)
{
ectlr
=
read_cpuectlr
();
ectlr
&=
~
CPUECTLR_SMP_BIT
;
write_cpuectlr
(
ectlr
);
}
/*
* Prevent interrupts from spuriously waking up
* this cpu
*/
arm_gic_cpuif_deactivate
();
/*
* Program the power controller to power this
* cpu off
*/
fvp_pwrc_write_ppoffr
(
mpidr
);
}
break
;
default:
assert
(
0
);
}
return
rc
;
/*
* If execution reaches this stage then this affinity level will be
* suspended. Perform at least the cpu specific actions followed the
* cluster specific operations if applicable.
*/
fvp_cpu_pwrdwn_common
();
if
(
afflvl
!=
MPIDR_AFFLVL0
)
fvp_cluster_pwrdwn_common
();
return
PSCI_E_SUCCESS
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -203,69 +229,24 @@ int fvp_affinst_suspend(unsigned long mpidr,
...
@@ -203,69 +229,24 @@ int fvp_affinst_suspend(unsigned long mpidr,
unsigned
int
afflvl
,
unsigned
int
afflvl
,
unsigned
int
state
)
unsigned
int
state
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
/* Determine if any platform actions need to be executed. */
unsigned
int
ectlr
;
if
(
fvp_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
unsigned
long
linear_id
;
return
PSCI_E_SUCCESS
;
mailbox_t
*
fvp_mboxes
;
switch
(
afflvl
)
{
/* Program the jump address for the target cpu */
case
MPIDR_AFFLVL1
:
fvp_program_mailbox
(
read_mpidr_el1
(),
sec_entrypoint
);
if
(
state
==
PSCI_STATE_OFF
)
{
/*
* Disable coherency if this cluster is to be
* turned off
*/
if
(
get_plat_config
()
->
flags
&
CONFIG_HAS_CCI
)
cci_disable_cluster_coherency
(
mpidr
);
/*
* Program the power controller to turn the
* cluster off
*/
fvp_pwrc_write_pcoffr
(
mpidr
);
}
break
;
case
MPIDR_AFFLVL0
:
if
(
state
==
PSCI_STATE_OFF
)
{
/*
* Take this cpu out of intra-cluster coherency if
* the FVP flavour supports the SMP bit.
*/
if
(
get_plat_config
()
->
flags
&
CONFIG_CPUECTLR_SMP_BIT
)
{
ectlr
=
read_cpuectlr
();
ectlr
&=
~
CPUECTLR_SMP_BIT
;
write_cpuectlr
(
ectlr
);
}
/* Program the jump address for the target cpu */
linear_id
=
platform_get_core_pos
(
mpidr
);
fvp_mboxes
=
(
mailbox_t
*
)
MBOX_BASE
;
fvp_mboxes
[
linear_id
].
value
=
sec_entrypoint
;
flush_dcache_range
((
unsigned
long
)
&
fvp_mboxes
[
linear_id
],
sizeof
(
unsigned
long
));
/*
* Prevent interrupts from spuriously waking up
* this cpu
*/
arm_gic_cpuif_deactivate
();
/*
* Program the power controller to power this
* cpu off and enable wakeup interrupts.
*/
fvp_pwrc_set_wen
(
mpidr
);
fvp_pwrc_write_ppoffr
(
mpidr
);
}
break
;
default:
assert
(
0
);
}
return
rc
;
/* Program the power controller to enable wakeup interrupts. */
fvp_pwrc_set_wen
(
mpidr
);
/* Perform the common cpu specific operations */
fvp_cpu_pwrdwn_common
();
/* Perform the common cluster specific operations */
if
(
afflvl
!=
MPIDR_AFFLVL0
)
fvp_cluster_pwrdwn_common
();
return
PSCI_E_SUCCESS
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -280,73 +261,42 @@ int fvp_affinst_on_finish(unsigned long mpidr,
...
@@ -280,73 +261,42 @@ int fvp_affinst_on_finish(unsigned long mpidr,
unsigned
int
state
)
unsigned
int
state
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
int
rc
=
PSCI_E_SUCCESS
;
unsigned
long
linear_id
;
mailbox_t
*
fvp_mboxes
;
unsigned
int
ectlr
;
switch
(
afflvl
)
{
case
MPIDR_AFFLVL1
:
/* Enable coherency if this cluster was off */
if
(
state
==
PSCI_STATE_OFF
)
{
/*
* This CPU might have woken up whilst the
* cluster was attempting to power down. In
* this case the FVP power controller will
* have a pending cluster power off request
* which needs to be cleared by writing to the
* PPONR register. This prevents the power
* controller from interpreting a subsequent
* entry of this cpu into a simple wfi as a
* power down request.
*/
fvp_pwrc_write_pponr
(
mpidr
);
fvp_cci_enable
();
}
break
;
case
MPIDR_AFFLVL0
:
/*
* Ignore the state passed for a cpu. It could only have
* been off if we are here.
*/
/*
/* Determine if any platform actions need to be executed. */
* Turn on intra-cluster coherency if the FVP flavour supports
if
(
fvp_do_plat_actions
(
afflvl
,
state
)
==
-
EAGAIN
)
* it.
return
PSCI_E_SUCCESS
;
*/
if
(
get_plat_config
()
->
flags
&
CONFIG_CPUECTLR_SMP_BIT
)
{
ectlr
=
read_cpuectlr
();
ectlr
|=
CPUECTLR_SMP_BIT
;
write_cpuectlr
(
ectlr
);
}
/* Perform the common cluster specific operations */
if
(
afflvl
!=
MPIDR_AFFLVL0
)
{
/*
/*
* Clear PWKUPR.WEN bit to ensure interrupts do not interfere
* This CPU might have woken up whilst the cluster was
* with a cpu power down unless the bit is set again
* attempting to power down. In this case the FVP power
* controller will have a pending cluster power off request
* which needs to be cleared by writing to the PPONR register.
* This prevents the power controller from interpreting a
* subsequent entry of this cpu into a simple wfi as a power
* down request.
*/
*/
fvp_pwrc_
clr_wen
(
mpidr
);
fvp_pwrc_
write_pponr
(
mpidr
);
/* Zero the jump address in the mailbox for this cpu */
/* Enable coherency if this cluster was off */
fvp_mboxes
=
(
mailbox_t
*
)
MBOX_BASE
;
fvp_cci_enable
();
linear_id
=
platform_get_core_pos
(
mpidr
);
}
fvp_mboxes
[
linear_id
].
value
=
0
;
flush_dcache_range
((
unsigned
long
)
&
fvp_mboxes
[
linear_id
],
sizeof
(
unsigned
long
));
/* Enable the gic cpu interface */
/*
arm_gic_cpuif_setup
();
* Clear PWKUPR.WEN bit to ensure interrupts do not interfere
* with a cpu power down unless the bit is set again
*/
fvp_pwrc_clr_wen
(
mpidr
);
/*
TODO: This setup is needed only after a cold boot
*/
/*
Zero the jump address in the mailbox for this cpu
*/
arm_gic_pcpu_distif_setup
(
);
fvp_program_mailbox
(
read_mpidr_el1
(),
0
);
break
;
/* Enable the gic cpu interface */
arm_gic_cpuif_setup
();
default:
/* TODO: This setup is needed only after a cold boot */
assert
(
0
);
arm_gic_pcpu_distif_setup
();
}
return
rc
;
return
rc
;
}
}
...
...
plat/fvp/include/plat_macros.S
View file @
7963671c
...
@@ -52,7 +52,7 @@ spacer:
...
@@ -52,7 +52,7 @@ spacer:
.
macro
plat_print_gic_regs
.
macro
plat_print_gic_regs
adr
x0
,
plat_config
adr
x0
,
plat_config
ldr
w16
,
[
x0
,
#
CONFIG_GICC_BASE_OFFSET
]
ldr
w16
,
[
x0
,
#
CONFIG_GICC_BASE_OFFSET
]
cbz
x16
,
1
f
cbz
x16
,
exit_print_gic_regs
/
*
gic
base
address
is
now
in
x16
*/
/
*
gic
base
address
is
now
in
x16
*/
adr
x6
,
gic_regs
/*
Load
the
gic
reg
list
to
x6
*/
adr
x6
,
gic_regs
/*
Load
the
gic
reg
list
to
x6
*/
/
*
Load
the
gic
regs
to
gp
regs
used
by
str_in_crash_buf_print
*/
/
*
Load
the
gic
regs
to
gp
regs
used
by
str_in_crash_buf_print
*/
...
@@ -66,10 +66,10 @@ spacer:
...
@@ -66,10 +66,10 @@ spacer:
add
x7
,
x16
,
#
GICD_ISPENDR
add
x7
,
x16
,
#
GICD_ISPENDR
adr
x4
,
gicd_pend_reg
adr
x4
,
gicd_pend_reg
bl
asm_print_str
bl
asm_print_str
2
:
gicd_ispendr_loop
:
sub
x4
,
x7
,
x16
sub
x4
,
x7
,
x16
cmp
x4
,
#
0x280
cmp
x4
,
#
0x280
b.eq
1
f
b.eq
exit_print_gic_regs
bl
asm_print_hex
bl
asm_print_hex
adr
x4
,
spacer
adr
x4
,
spacer
bl
asm_print_str
bl
asm_print_str
...
@@ -77,8 +77,8 @@ spacer:
...
@@ -77,8 +77,8 @@ spacer:
bl
asm_print_hex
bl
asm_print_hex
adr
x4
,
newline
adr
x4
,
newline
bl
asm_print_str
bl
asm_print_str
b
2
b
b
gicd_ispendr_loop
1
:
exit_print_gic_regs
:
.
endm
.
endm
.
section
.
rodata.
cci_reg_name
,
"aS"
.
section
.
rodata.
cci_reg_name
,
"aS"
...
...
plat/fvp/platform.mk
View file @
7963671c
...
@@ -74,6 +74,9 @@ PLAT_BL_COMMON_SOURCES := drivers/arm/pl011/pl011_console.S \
...
@@ -74,6 +74,9 @@ PLAT_BL_COMMON_SOURCES := drivers/arm/pl011/pl011_console.S \
plat/fvp/fvp_io_storage.c
plat/fvp/fvp_io_storage.c
BL1_SOURCES
+=
drivers/arm/cci400/cci400.c
\
BL1_SOURCES
+=
drivers/arm/cci400/cci400.c
\
lib/cpus/aarch64/aem_generic.S
\
lib/cpus/aarch64/cortex_a53.S
\
lib/cpus/aarch64/cortex_a57.S
\
plat/common/aarch64/platform_up_stack.S
\
plat/common/aarch64/platform_up_stack.S
\
plat/fvp/bl1_fvp_setup.c
\
plat/fvp/bl1_fvp_setup.c
\
plat/fvp/aarch64/fvp_common.c
\
plat/fvp/aarch64/fvp_common.c
\
...
@@ -90,6 +93,9 @@ BL31_SOURCES += drivers/arm/cci400/cci400.c \
...
@@ -90,6 +93,9 @@ BL31_SOURCES += drivers/arm/cci400/cci400.c \
drivers/arm/gic/gic_v2.c
\
drivers/arm/gic/gic_v2.c
\
drivers/arm/gic/gic_v3.c
\
drivers/arm/gic/gic_v3.c
\
drivers/arm/tzc400/tzc400.c
\
drivers/arm/tzc400/tzc400.c
\
lib/cpus/aarch64/aem_generic.S
\
lib/cpus/aarch64/cortex_a53.S
\
lib/cpus/aarch64/cortex_a57.S
\
plat/common/plat_gic.c
\
plat/common/plat_gic.c
\
plat/common/aarch64/platform_mp_stack.S
\
plat/common/aarch64/platform_mp_stack.S
\
plat/fvp/bl31_fvp_setup.c
\
plat/fvp/bl31_fvp_setup.c
\
...
...
services/std_svc/psci/psci_afflvl_off.c
View file @
7963671c
...
@@ -42,14 +42,10 @@ typedef int (*afflvl_off_handler_t)(aff_map_node_t *);
...
@@ -42,14 +42,10 @@ typedef int (*afflvl_off_handler_t)(aff_map_node_t *);
******************************************************************************/
******************************************************************************/
static
int
psci_afflvl0_off
(
aff_map_node_t
*
cpu_node
)
static
int
psci_afflvl0_off
(
aff_map_node_t
*
cpu_node
)
{
{
unsigned
int
plat_state
;
int
rc
;
int
rc
;
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
/* State management: mark this cpu as turned off */
psci_set_state
(
cpu_node
,
PSCI_STATE_OFF
);
/*
/*
* Generic management: Get the index for clearing any lingering re-entry
* Generic management: Get the index for clearing any lingering re-entry
* information and allow the secure world to switch itself off
* information and allow the secure world to switch itself off
...
@@ -72,88 +68,68 @@ static int psci_afflvl0_off(aff_map_node_t *cpu_node)
...
@@ -72,88 +68,68 @@ static int psci_afflvl0_off(aff_map_node_t *cpu_node)
*/
*/
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL0
);
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL0
);
if
(
!
psci_plat_pm_ops
->
affinst_off
)
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Perform platform specific actions to turn this
* Plat. management: Perform platform specific actions to turn this
* cpu off e.g. exit cpu coherency, program the power controller etc.
* cpu off e.g. exit cpu coherency, program the power controller etc.
*/
*/
rc
=
PSCI_E_SUCCESS
;
return
psci_plat_pm_ops
->
affinst_off
(
read_mpidr_el1
(),
if
(
psci_plat_pm_ops
->
affinst_off
)
{
cpu_node
->
level
,
psci_get_phys_state
(
cpu_node
));
/* Get the current physical state of this cpu */
plat_state
=
psci_get_phys_state
(
cpu_node
);
rc
=
psci_plat_pm_ops
->
affinst_off
(
read_mpidr_el1
(),
cpu_node
->
level
,
plat_state
);
}
return
rc
;
}
}
static
int
psci_afflvl1_off
(
aff_map_node_t
*
cluster_node
)
static
int
psci_afflvl1_off
(
aff_map_node_t
*
cluster_node
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
unsigned
int
plat_state
;
/* Sanity check the cluster level */
/* Sanity check the cluster level */
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
/* State management: Decrement the cluster reference count */
psci_set_state
(
cluster_node
,
PSCI_STATE_OFF
);
/*
* Keep the physical state of this cluster handy to decide
* what action needs to be taken
*/
plat_state
=
psci_get_phys_state
(
cluster_node
);
/*
/*
* Arch. Management. Flush all levels of caches to PoC if
* Arch. Management. Flush all levels of caches to PoC if
* the cluster is to be shutdown
* the cluster is to be shutdown
.
*/
*/
if
(
plat_state
==
PSCI_STATE_OFF
)
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL1
);
dcsw_op_all
(
DCCISW
);
if
(
!
psci_plat_pm_ops
->
affinst_off
)
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. Management. Allow the platform to do its cluster
* Plat. Management. Allow the platform to do its cluster
* specific bookeeping e.g. turn off interconnect coherency,
* specific bookeeping e.g. turn off interconnect coherency,
* program the power controller etc.
* program the power controller etc.
*/
*/
if
(
psci_plat_pm_ops
->
affinst_off
)
return
psci_plat_pm_ops
->
affinst_off
(
read_mpidr_el1
(),
rc
=
psci_plat_pm_ops
->
affinst_off
(
read_mpidr_el1
(),
cluster_node
->
level
,
cluster_node
->
level
,
psci_get_phys_state
(
cluster_node
));
plat_state
);
return
rc
;
}
}
static
int
psci_afflvl2_off
(
aff_map_node_t
*
system_node
)
static
int
psci_afflvl2_off
(
aff_map_node_t
*
system_node
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
unsigned
int
plat_state
;
/* Cannot go beyond this level */
/* Cannot go beyond this level */
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
/* State management: Decrement the system reference count */
psci_set_state
(
system_node
,
PSCI_STATE_OFF
);
/*
/*
* Keep the physical state of the system handy to decide what
* Keep the physical state of the system handy to decide what
* action needs to be taken
* action needs to be taken
*/
*/
plat_state
=
psci_get_phys_state
(
system_node
);
/* No arch. and generic bookeeping to do here currently */
/*
* Arch. Management. Flush all levels of caches to PoC if
* the system is to be shutdown.
*/
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL2
);
if
(
!
psci_plat_pm_ops
->
affinst_off
)
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. Management : Allow the platform to do its bookeeping
* Plat. Management : Allow the platform to do its bookeeping
* at this affinity level
* at this affinity level
*/
*/
if
(
psci_plat_pm_ops
->
affinst_off
)
return
psci_plat_pm_ops
->
affinst_off
(
read_mpidr_el1
(),
rc
=
psci_plat_pm_ops
->
affinst_off
(
read_mpidr_el1
(),
system_node
->
level
,
system_node
->
level
,
psci_get_phys_state
(
system_node
));
plat_state
);
return
rc
;
}
}
static
const
afflvl_off_handler_t
psci_afflvl_off_handlers
[]
=
{
static
const
afflvl_off_handler_t
psci_afflvl_off_handlers
[]
=
{
...
@@ -167,7 +143,7 @@ static const afflvl_off_handler_t psci_afflvl_off_handlers[] = {
...
@@ -167,7 +143,7 @@ static const afflvl_off_handler_t psci_afflvl_off_handlers[] = {
* topology tree and calls the off handler for the corresponding affinity
* topology tree and calls the off handler for the corresponding affinity
* levels
* levels
******************************************************************************/
******************************************************************************/
static
int
psci_call_off_handlers
(
mpidr_
aff_map_node
s
_t
mpidr_nodes
,
static
int
psci_call_off_handlers
(
aff_map_node_t
*
mpidr_nodes
[]
,
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
)
int
end_afflvl
)
{
{
...
@@ -216,7 +192,7 @@ int psci_afflvl_off(int start_afflvl,
...
@@ -216,7 +192,7 @@ int psci_afflvl_off(int start_afflvl,
{
{
int
rc
=
PSCI_E_SUCCESS
;
int
rc
=
PSCI_E_SUCCESS
;
mpidr_aff_map_nodes_t
mpidr_nodes
;
mpidr_aff_map_nodes_t
mpidr_nodes
;
unsigned
int
max_phys_off_afflvl
;
/*
/*
* Collect the pointers to the nodes in the topology tree for
* Collect the pointers to the nodes in the topology tree for
...
@@ -240,11 +216,37 @@ int psci_afflvl_off(int start_afflvl,
...
@@ -240,11 +216,37 @@ int psci_afflvl_off(int start_afflvl,
end_afflvl
,
end_afflvl
,
mpidr_nodes
);
mpidr_nodes
);
/*
* This function updates the state of each affinity instance
* corresponding to the mpidr in the range of affinity levels
* specified.
*/
psci_do_afflvl_state_mgmt
(
start_afflvl
,
end_afflvl
,
mpidr_nodes
,
PSCI_STATE_OFF
);
max_phys_off_afflvl
=
psci_find_max_phys_off_afflvl
(
start_afflvl
,
end_afflvl
,
mpidr_nodes
);
assert
(
max_phys_off_afflvl
!=
PSCI_INVALID_DATA
);
/* Stash the highest affinity level that will enter the OFF state. */
psci_set_max_phys_off_afflvl
(
max_phys_off_afflvl
);
/* Perform generic, architecture and platform specific handling */
/* Perform generic, architecture and platform specific handling */
rc
=
psci_call_off_handlers
(
mpidr_nodes
,
rc
=
psci_call_off_handlers
(
mpidr_nodes
,
start_afflvl
,
start_afflvl
,
end_afflvl
);
end_afflvl
);
/*
* Invalidate the entry for the highest affinity level stashed earlier.
* This ensures that any reads of this variable outside the power
* up/down sequences return PSCI_INVALID_DATA.
*
*/
psci_set_max_phys_off_afflvl
(
PSCI_INVALID_DATA
);
/*
/*
* Release the locks corresponding to each affinity level in the
* Release the locks corresponding to each affinity level in the
* reverse order to which they were acquired.
* reverse order to which they were acquired.
...
...
services/std_svc/psci/psci_afflvl_on.c
View file @
7963671c
...
@@ -75,7 +75,6 @@ static int psci_afflvl0_on(unsigned long target_cpu,
...
@@ -75,7 +75,6 @@ static int psci_afflvl0_on(unsigned long target_cpu,
unsigned
long
ns_entrypoint
,
unsigned
long
ns_entrypoint
,
unsigned
long
context_id
)
unsigned
long
context_id
)
{
{
unsigned
int
plat_state
;
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
uint32_t
ns_scr_el3
=
read_scr_el3
();
uint32_t
ns_scr_el3
=
read_scr_el3
();
uint32_t
ns_sctlr_el1
=
read_sctlr_el1
();
uint32_t
ns_sctlr_el1
=
read_sctlr_el1
();
...
@@ -113,26 +112,19 @@ static int psci_afflvl0_on(unsigned long target_cpu,
...
@@ -113,26 +112,19 @@ static int psci_afflvl0_on(unsigned long target_cpu,
/* Set the secure world (EL3) re-entry point after BL1 */
/* Set the secure world (EL3) re-entry point after BL1 */
psci_entrypoint
=
(
unsigned
long
)
psci_aff_on_finish_entry
;
psci_entrypoint
=
(
unsigned
long
)
psci_aff_on_finish_entry
;
/* State management: Set this cpu's state as ON PENDING */
if
(
!
psci_plat_pm_ops
->
affinst_on
)
psci_set_state
(
cpu_node
,
PSCI_STATE_ON_PENDING
)
;
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Give the platform the current state
* Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary
* of the target cpu to allow it to perform the necessary
* steps to power on.
* steps to power on.
*/
*/
if
(
psci_plat_pm_ops
->
affinst_on
)
{
return
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
psci_entrypoint
,
/* Get the current physical state of this cpu */
ns_entrypoint
,
plat_state
=
psci_get_phys_state
(
cpu_node
);
cpu_node
->
level
,
rc
=
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
psci_get_phys_state
(
cpu_node
));
psci_entrypoint
,
ns_entrypoint
,
cpu_node
->
level
,
plat_state
);
}
return
rc
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -145,8 +137,6 @@ static int psci_afflvl1_on(unsigned long target_cpu,
...
@@ -145,8 +137,6 @@ static int psci_afflvl1_on(unsigned long target_cpu,
unsigned
long
ns_entrypoint
,
unsigned
long
ns_entrypoint
,
unsigned
long
context_id
)
unsigned
long
context_id
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
unsigned
int
plat_state
;
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
...
@@ -158,22 +148,20 @@ static int psci_afflvl1_on(unsigned long target_cpu,
...
@@ -158,22 +148,20 @@ static int psci_afflvl1_on(unsigned long target_cpu,
/* State management: Is not required while turning a cluster on */
/* State management: Is not required while turning a cluster on */
if
(
!
psci_plat_pm_ops
->
affinst_on
)
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Give the platform the current state
* Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary
* of the target cpu to allow it to perform the necessary
* steps to power on.
* steps to power on.
*/
*/
if
(
psci_plat_pm_ops
->
affinst_on
)
{
psci_entrypoint
=
(
unsigned
long
)
psci_aff_on_finish_entry
;
plat_state
=
psci_get_phys_state
(
cluster_node
);
return
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
psci_entrypoint
=
(
unsigned
long
)
psci_aff_on_finish_entry
;
psci_entrypoint
,
rc
=
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
ns_entrypoint
,
psci_entrypoint
,
cluster_node
->
level
,
ns_entrypoint
,
psci_get_phys_state
(
cluster_node
));
cluster_node
->
level
,
plat_state
);
}
return
rc
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -186,8 +174,6 @@ static int psci_afflvl2_on(unsigned long target_cpu,
...
@@ -186,8 +174,6 @@ static int psci_afflvl2_on(unsigned long target_cpu,
unsigned
long
ns_entrypoint
,
unsigned
long
ns_entrypoint
,
unsigned
long
context_id
)
unsigned
long
context_id
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
unsigned
int
plat_state
;
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
/* Cannot go beyond affinity level 2 in this psci imp. */
/* Cannot go beyond affinity level 2 in this psci imp. */
...
@@ -200,22 +186,20 @@ static int psci_afflvl2_on(unsigned long target_cpu,
...
@@ -200,22 +186,20 @@ static int psci_afflvl2_on(unsigned long target_cpu,
/* State management: Is not required while turning a system on */
/* State management: Is not required while turning a system on */
if
(
!
psci_plat_pm_ops
->
affinst_on
)
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Give the platform the current state
* Plat. management: Give the platform the current state
* of the target cpu to allow it to perform the necessary
* of the target cpu to allow it to perform the necessary
* steps to power on.
* steps to power on.
*/
*/
if
(
psci_plat_pm_ops
->
affinst_on
)
{
psci_entrypoint
=
(
unsigned
long
)
psci_aff_on_finish_entry
;
plat_state
=
psci_get_phys_state
(
system_node
);
return
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
psci_entrypoint
=
(
unsigned
long
)
psci_aff_on_finish_entry
;
psci_entrypoint
,
rc
=
psci_plat_pm_ops
->
affinst_on
(
target_cpu
,
ns_entrypoint
,
psci_entrypoint
,
system_node
->
level
,
ns_entrypoint
,
psci_get_phys_state
(
system_node
));
system_node
->
level
,
plat_state
);
}
return
rc
;
}
}
/* Private data structure to make this handlers accessible through indexing */
/* Private data structure to make this handlers accessible through indexing */
...
@@ -230,7 +214,7 @@ static const afflvl_on_handler_t psci_afflvl_on_handlers[] = {
...
@@ -230,7 +214,7 @@ static const afflvl_on_handler_t psci_afflvl_on_handlers[] = {
* topology tree and calls the on handler for the corresponding affinity
* topology tree and calls the on handler for the corresponding affinity
* levels
* levels
******************************************************************************/
******************************************************************************/
static
int
psci_call_on_handlers
(
mpidr_
aff_map_node
s
_t
target_cpu_nodes
,
static
int
psci_call_on_handlers
(
aff_map_node_t
*
target_cpu_nodes
[]
,
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
,
unsigned
long
target_cpu
,
unsigned
long
target_cpu
,
...
@@ -317,6 +301,17 @@ int psci_afflvl_on(unsigned long target_cpu,
...
@@ -317,6 +301,17 @@ int psci_afflvl_on(unsigned long target_cpu,
entrypoint
,
entrypoint
,
context_id
);
context_id
);
/*
* This function updates the state of each affinity instance
* corresponding to the mpidr in the range of affinity levels
* specified.
*/
if
(
rc
==
PSCI_E_SUCCESS
)
psci_do_afflvl_state_mgmt
(
start_afflvl
,
end_afflvl
,
target_cpu_nodes
,
PSCI_STATE_ON_PENDING
);
/*
/*
* This loop releases the lock corresponding to each affinity level
* This loop releases the lock corresponding to each affinity level
* in the reverse order to which they were acquired.
* in the reverse order to which they were acquired.
...
@@ -385,9 +380,6 @@ static unsigned int psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
...
@@ -385,9 +380,6 @@ static unsigned int psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
*/
*/
cm_prepare_el3_exit
(
NON_SECURE
);
cm_prepare_el3_exit
(
NON_SECURE
);
/* State management: mark this cpu as on */
psci_set_state
(
cpu_node
,
PSCI_STATE_ON
);
/* Clean caches before re-entering normal world */
/* Clean caches before re-entering normal world */
dcsw_op_louis
(
DCCSW
);
dcsw_op_louis
(
DCCSW
);
...
@@ -397,10 +389,13 @@ static unsigned int psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
...
@@ -397,10 +389,13 @@ static unsigned int psci_afflvl0_on_finish(aff_map_node_t *cpu_node)
static
unsigned
int
psci_afflvl1_on_finish
(
aff_map_node_t
*
cluster_node
)
static
unsigned
int
psci_afflvl1_on_finish
(
aff_map_node_t
*
cluster_node
)
{
{
unsigned
int
plat_state
,
rc
=
PSCI_E_SUCCESS
;
unsigned
int
plat_state
;
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
if
(
!
psci_plat_pm_ops
->
affinst_on_finish
)
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Perform the platform specific actions
* Plat. management: Perform the platform specific actions
* as per the old state of the cluster e.g. enabling
* as per the old state of the cluster e.g. enabling
...
@@ -409,30 +404,23 @@ static unsigned int psci_afflvl1_on_finish(aff_map_node_t *cluster_node)
...
@@ -409,30 +404,23 @@ static unsigned int psci_afflvl1_on_finish(aff_map_node_t *cluster_node)
* then assert as there is no way to recover from this
* then assert as there is no way to recover from this
* situation.
* situation.
*/
*/
if
(
psci_plat_pm_ops
->
affinst_on_finish
)
{
plat_state
=
psci_get_phys_state
(
cluster_node
);
return
psci_plat_pm_ops
->
affinst_on_finish
(
read_mpidr_el1
(),
/* Get the physical state of this cluster */
cluster_node
->
level
,
plat_state
=
psci_get_phys_state
(
cluster_node
);
plat_state
);
rc
=
psci_plat_pm_ops
->
affinst_on_finish
(
read_mpidr_el1
(),
cluster_node
->
level
,
plat_state
);
assert
(
rc
==
PSCI_E_SUCCESS
);
}
/* State management: Increment the cluster reference count */
psci_set_state
(
cluster_node
,
PSCI_STATE_ON
);
return
rc
;
}
}
static
unsigned
int
psci_afflvl2_on_finish
(
aff_map_node_t
*
system_node
)
static
unsigned
int
psci_afflvl2_on_finish
(
aff_map_node_t
*
system_node
)
{
{
unsigned
int
plat_state
,
rc
=
PSCI_E_SUCCESS
;
unsigned
int
plat_state
;
/* Cannot go beyond this affinity level */
/* Cannot go beyond this affinity level */
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
if
(
!
psci_plat_pm_ops
->
affinst_on_finish
)
return
PSCI_E_SUCCESS
;
/*
/*
* Currently, there are no architectural actions to perform
* Currently, there are no architectural actions to perform
* at the system level.
* at the system level.
...
@@ -446,20 +434,10 @@ static unsigned int psci_afflvl2_on_finish(aff_map_node_t *system_node)
...
@@ -446,20 +434,10 @@ static unsigned int psci_afflvl2_on_finish(aff_map_node_t *system_node)
* then assert as there is no way to recover from this
* then assert as there is no way to recover from this
* situation.
* situation.
*/
*/
if
(
psci_plat_pm_ops
->
affinst_on_finish
)
{
plat_state
=
psci_get_phys_state
(
system_node
);
return
psci_plat_pm_ops
->
affinst_on_finish
(
read_mpidr_el1
(),
/* Get the physical state of the system */
system_node
->
level
,
plat_state
=
psci_get_phys_state
(
system_node
);
plat_state
);
rc
=
psci_plat_pm_ops
->
affinst_on_finish
(
read_mpidr_el1
(),
system_node
->
level
,
plat_state
);
assert
(
rc
==
PSCI_E_SUCCESS
);
}
/* State management: Increment the system reference count */
psci_set_state
(
system_node
,
PSCI_STATE_ON
);
return
rc
;
}
}
const
afflvl_power_on_finisher_t
psci_afflvl_on_finishers
[]
=
{
const
afflvl_power_on_finisher_t
psci_afflvl_on_finishers
[]
=
{
...
@@ -467,4 +445,3 @@ const afflvl_power_on_finisher_t psci_afflvl_on_finishers[] = {
...
@@ -467,4 +445,3 @@ const afflvl_power_on_finisher_t psci_afflvl_on_finishers[] = {
psci_afflvl1_on_finish
,
psci_afflvl1_on_finish
,
psci_afflvl2_on_finish
,
psci_afflvl2_on_finish
,
};
};
services/std_svc/psci/psci_afflvl_suspend.c
View file @
7963671c
...
@@ -34,6 +34,7 @@
...
@@ -34,6 +34,7 @@
#include <arch_helpers.h>
#include <arch_helpers.h>
#include <context.h>
#include <context.h>
#include <context_mgmt.h>
#include <context_mgmt.h>
#include <cpu_data.h>
#include <platform.h>
#include <platform.h>
#include <runtime_svc.h>
#include <runtime_svc.h>
#include <stddef.h>
#include <stddef.h>
...
@@ -45,76 +46,59 @@ typedef int (*afflvl_suspend_handler_t)(aff_map_node_t *,
...
@@ -45,76 +46,59 @@ typedef int (*afflvl_suspend_handler_t)(aff_map_node_t *,
unsigned
int
);
unsigned
int
);
/*******************************************************************************
/*******************************************************************************
* This function se
t
s the power state
of
the current
cpu while
* This function s
av
es the power state
parameter passed in
the current
PSCI
*
powering down during a cpu_suspend call
*
cpu_suspend call in the per-cpu data array.
******************************************************************************/
******************************************************************************/
void
psci_set_suspend_power_state
(
aff_map_node_t
*
node
,
unsigned
int
power_state
)
void
psci_set_suspend_power_state
(
unsigned
int
power_state
)
{
{
/*
set_cpu_data
(
psci_svc_cpu_data
.
power_state
,
power_state
);
* Check that nobody else is calling this function on our behalf &
flush_cpu_data
(
psci_svc_cpu_data
.
power_state
);
* this information is being set only in the cpu node
*/
assert
(
node
->
mpidr
==
(
read_mpidr
()
&
MPIDR_AFFINITY_MASK
));
assert
(
node
->
level
==
MPIDR_AFFLVL0
);
/*
* Save PSCI power state parameter for the core in suspend context.
* The node is in always-coherent RAM so it does not need to be flushed
*/
node
->
power_state
=
power_state
;
}
}
/*******************************************************************************
/*******************************************************************************
* This function gets the affinity level till which
a cpu is powered down
* This function gets the affinity level till which
the current cpu could be
* during a cpu_suspend call. Returns PSCI_INVALID_DATA if the
*
powered down
during a cpu_suspend call. Returns PSCI_INVALID_DATA if the
* power state
saved for the node
is invalid
* power state is invalid
.
******************************************************************************/
******************************************************************************/
int
psci_get_suspend_afflvl
(
unsigned
long
mpidr
)
int
psci_get_suspend_afflvl
()
{
{
aff_map_node_t
*
nod
e
;
unsigned
int
power_stat
e
;
node
=
psci_get_aff_map_node
(
mpidr
&
MPIDR_AFFINITY_MASK
,
power_state
=
get_cpu_data
(
psci_svc_cpu_data
.
power_state
);
MPIDR_AFFLVL0
);
assert
(
node
);
return
psci_get_aff_map_node_suspend_afflvl
(
node
);
return
((
power_state
==
PSCI_INVALID_DATA
)
?
power_state
:
psci_get_pstate_afflvl
(
power_state
));
}
}
/*******************************************************************************
/*******************************************************************************
* This function gets the
affinity level till which the current cpu was powered
* This function gets the
state id of the current cpu from the power state
*
down during a cpu_suspend call
. Returns PSCI_INVALID_DATA if the
*
parameter saved in the per-cpu data array
. Returns PSCI_INVALID_DATA if the
* power state saved
for the node
is invalid
* power state saved is invalid
.
******************************************************************************/
******************************************************************************/
int
psci_get_
aff_map_node_suspend_afflvl
(
aff_map_node_t
*
node
)
int
psci_get_
suspend_stateid
(
)
{
{
unsigned
int
power_state
;
unsigned
int
power_state
;
assert
(
node
->
level
==
MPIDR_AFFLVL0
);
power_state
=
get_cpu_data
(
psci_svc_cpu_data
.
power_state
);
power_state
=
node
->
power_state
;
return
((
power_state
==
PSCI_INVALID_DATA
)
?
return
((
power_state
==
PSCI_INVALID_DATA
)
?
power_state
:
psci_get_pstate_
afflvl
(
power_state
));
power_state
:
psci_get_pstate_
id
(
power_state
));
}
}
/*******************************************************************************
/*******************************************************************************
* This function gets the state id of
a
cpu s
tored in suspend context
* This function gets the state id of
the
cpu s
pecified by the 'mpidr' parameter
*
while powering down during a cpu_suspend call. Returns 0xFFFFFFFF
*
from the power state parameter saved in the per-cpu data array. Returns
* if the power state saved
for the node
is invalid
*
PSCI_INVALID_DATA
if the power state saved is invalid
.
******************************************************************************/
******************************************************************************/
int
psci_get_suspend_stateid
(
unsigned
long
mpidr
)
int
psci_get_suspend_stateid
_by_mpidr
(
unsigned
long
mpidr
)
{
{
aff_map_node_t
*
node
;
unsigned
int
power_state
;
unsigned
int
power_state
;
node
=
psci_get_aff_map_node
(
mpidr
&
MPIDR_AFFINITY_MASK
,
power_state
=
get_cpu_data_by_mpidr
(
mpidr
,
MPIDR_AFFLVL0
);
psci_svc_cpu_data
.
power_state
);
assert
(
node
);
assert
(
node
->
level
==
MPIDR_AFFLVL0
);
power_state
=
node
->
power_state
;
return
((
power_state
==
PSCI_INVALID_DATA
)
?
return
((
power_state
==
PSCI_INVALID_DATA
)
?
power_state
:
psci_get_pstate_id
(
power_state
));
power_state
:
psci_get_pstate_id
(
power_state
));
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -126,7 +110,6 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
...
@@ -126,7 +110,6 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
unsigned
long
context_id
,
unsigned
long
context_id
,
unsigned
int
power_state
)
unsigned
int
power_state
)
{
{
unsigned
int
plat_state
;
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
uint32_t
ns_scr_el3
=
read_scr_el3
();
uint32_t
ns_scr_el3
=
read_scr_el3
();
uint32_t
ns_sctlr_el1
=
read_sctlr_el1
();
uint32_t
ns_sctlr_el1
=
read_sctlr_el1
();
...
@@ -136,7 +119,7 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
...
@@ -136,7 +119,7 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
assert
(
cpu_node
->
level
==
MPIDR_AFFLVL0
);
/* Save PSCI power state parameter for the core in suspend context */
/* Save PSCI power state parameter for the core in suspend context */
psci_set_suspend_power_state
(
cpu_node
,
power_state
);
psci_set_suspend_power_state
(
power_state
);
/*
/*
* Generic management: Store the re-entry information for the non-secure
* Generic management: Store the re-entry information for the non-secure
...
@@ -151,9 +134,6 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
...
@@ -151,9 +134,6 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
if
(
psci_spd_pm
&&
psci_spd_pm
->
svc_suspend
)
if
(
psci_spd_pm
&&
psci_spd_pm
->
svc_suspend
)
psci_spd_pm
->
svc_suspend
(
power_state
);
psci_spd_pm
->
svc_suspend
(
power_state
);
/* State management: mark this cpu as suspended */
psci_set_state
(
cpu_node
,
PSCI_STATE_SUSPEND
);
/*
/*
* Generic management: Store the re-entry information for the
* Generic management: Store the re-entry information for the
* non-secure world
* non-secure world
...
@@ -172,24 +152,20 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
...
@@ -172,24 +152,20 @@ static int psci_afflvl0_suspend(aff_map_node_t *cpu_node,
*/
*/
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL0
);
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL0
);
if
(
!
psci_plat_pm_ops
->
affinst_suspend
)
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. management: Allow the platform to perform the
* Plat. management: Allow the platform to perform the
* necessary actions to turn off this cpu e.g. set the
* necessary actions to turn off this cpu e.g. set the
* platform defined mailbox with the psci entrypoint,
* platform defined mailbox with the psci entrypoint,
* program the power controller etc.
* program the power controller etc.
*/
*/
rc
=
PSCI_E_SUCCESS
;
return
psci_plat_pm_ops
->
affinst_suspend
(
read_mpidr_el1
(),
psci_entrypoint
,
if
(
psci_plat_pm_ops
->
affinst_suspend
)
{
ns_entrypoint
,
plat_state
=
psci_get_phys_state
(
cpu_node
);
cpu_node
->
level
,
rc
=
psci_plat_pm_ops
->
affinst_suspend
(
read_mpidr_el1
(),
psci_get_phys_state
(
cpu_node
));
psci_entrypoint
,
ns_entrypoint
,
cpu_node
->
level
,
plat_state
);
}
return
rc
;
}
}
static
int
psci_afflvl1_suspend
(
aff_map_node_t
*
cluster_node
,
static
int
psci_afflvl1_suspend
(
aff_map_node_t
*
cluster_node
,
...
@@ -197,51 +173,36 @@ static int psci_afflvl1_suspend(aff_map_node_t *cluster_node,
...
@@ -197,51 +173,36 @@ static int psci_afflvl1_suspend(aff_map_node_t *cluster_node,
unsigned
long
context_id
,
unsigned
long
context_id
,
unsigned
int
power_state
)
unsigned
int
power_state
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
unsigned
int
plat_state
;
unsigned
int
plat_state
;
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
/* Sanity check the cluster level */
/* Sanity check the cluster level */
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
assert
(
cluster_node
->
level
==
MPIDR_AFFLVL1
);
/* State management: Decrement the cluster reference count */
psci_set_state
(
cluster_node
,
PSCI_STATE_SUSPEND
);
/*
* Keep the physical state of this cluster handy to decide
* what action needs to be taken
*/
plat_state
=
psci_get_phys_state
(
cluster_node
);
/*
/*
* Arch. management: Flush all levels of caches to PoC if the
* Arch. management: Flush all levels of caches to PoC if the
* cluster is to be shutdown
* cluster is to be shutdown
.
*/
*/
if
(
plat_state
==
PSCI_STATE_OFF
)
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL1
);
dcsw_op_all
(
DCCISW
);
if
(
!
psci_plat_pm_ops
->
affinst_suspend
)
return
PSCI_E_SUCCESS
;
/*
/*
* Plat. Management. Allow the platform to do its cluster
* Plat. Management. Allow the platform to do its cluster specific
* specific bookeeping e.g. turn off interconnect coherency,
* bookeeping e.g. turn off interconnect coherency, program the power
* program the power controller etc.
* controller etc. Sending the psci entrypoint is currently redundant
* beyond affinity level 0 but one never knows what a platform might
* do. Also it allows us to keep the platform handler prototype the
* same.
*/
*/
if
(
psci_plat_pm_ops
->
affinst_suspend
)
{
plat_state
=
psci_get_phys_state
(
cluster_node
);
psci_entrypoint
=
(
unsigned
long
)
psci_aff_suspend_finish_entry
;
/*
return
psci_plat_pm_ops
->
affinst_suspend
(
read_mpidr_el1
(),
* Sending the psci entrypoint is currently redundant
psci_entrypoint
,
* beyond affinity level 0 but one never knows what a
ns_entrypoint
,
* platform might do. Also it allows us to keep the
cluster_node
->
level
,
* platform handler prototype the same.
plat_state
);
*/
psci_entrypoint
=
(
unsigned
long
)
psci_aff_suspend_finish_entry
;
rc
=
psci_plat_pm_ops
->
affinst_suspend
(
read_mpidr_el1
(),
psci_entrypoint
,
ns_entrypoint
,
cluster_node
->
level
,
plat_state
);
}
return
rc
;
}
}
...
@@ -250,43 +211,44 @@ static int psci_afflvl2_suspend(aff_map_node_t *system_node,
...
@@ -250,43 +211,44 @@ static int psci_afflvl2_suspend(aff_map_node_t *system_node,
unsigned
long
context_id
,
unsigned
long
context_id
,
unsigned
int
power_state
)
unsigned
int
power_state
)
{
{
int
rc
=
PSCI_E_SUCCESS
;
unsigned
int
plat_state
;
unsigned
int
plat_state
;
unsigned
long
psci_entrypoint
;
unsigned
long
psci_entrypoint
;
/* Cannot go beyond this */
/* Cannot go beyond this */
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
assert
(
system_node
->
level
==
MPIDR_AFFLVL2
);
/* State management: Decrement the system reference count */
psci_set_state
(
system_node
,
PSCI_STATE_SUSPEND
);
/*
/*
* Keep the physical state of the system handy to decide what
* Keep the physical state of the system handy to decide what
* action needs to be taken
* action needs to be taken
*/
*/
plat_state
=
psci_get_phys_state
(
system_node
);
plat_state
=
psci_get_phys_state
(
system_node
);
/*
* Arch. management: Flush all levels of caches to PoC if the
* system is to be shutdown.
*/
psci_do_pwrdown_cache_maintenance
(
MPIDR_AFFLVL2
);
/*
/*
* Plat. Management : Allow the platform to do its bookeeping
* Plat. Management : Allow the platform to do its bookeeping
* at this affinity level
* at this affinity level
*/
*/
if
(
psci_plat_pm_ops
->
affinst_suspend
)
{
if
(
!
psci_plat_pm_ops
->
affinst_suspend
)
return
PSCI_E_SUCCESS
;
/*
/*
* Sending the psci entrypoint is currently redundant
* Sending the psci entrypoint is currently redundant
* beyond affinity level 0 but one never knows what a
* beyond affinity level 0 but one never knows what a
* platform might do. Also it allows us to keep the
* platform might do. Also it allows us to keep the
* platform handler prototype the same.
* platform handler prototype the same.
*/
*/
psci_entrypoint
=
(
unsigned
long
)
psci_aff_suspend_finish_entry
;
plat_state
=
psci_get_phys_state
(
system_node
);
rc
=
psci_plat_pm_ops
->
affinst_suspend
(
read_mpidr_el1
(),
psci_entrypoint
=
(
unsigned
long
)
psci_aff_suspend_finish_entry
;
psci_entrypoint
,
return
psci_plat_pm_ops
->
affinst_suspend
(
read_mpidr_el1
(),
ns_entrypoint
,
psci_entrypoint
,
system_node
->
level
,
ns_entrypoint
,
plat_state
);
system_node
->
level
,
}
plat_state
);
return
rc
;
}
}
static
const
afflvl_suspend_handler_t
psci_afflvl_suspend_handlers
[]
=
{
static
const
afflvl_suspend_handler_t
psci_afflvl_suspend_handlers
[]
=
{
...
@@ -300,7 +262,7 @@ static const afflvl_suspend_handler_t psci_afflvl_suspend_handlers[] = {
...
@@ -300,7 +262,7 @@ static const afflvl_suspend_handler_t psci_afflvl_suspend_handlers[] = {
* topology tree and calls the suspend handler for the corresponding affinity
* topology tree and calls the suspend handler for the corresponding affinity
* levels
* levels
******************************************************************************/
******************************************************************************/
static
int
psci_call_suspend_handlers
(
mpidr_
aff_map_node
s
_t
mpidr_nodes
,
static
int
psci_call_suspend_handlers
(
aff_map_node_t
*
mpidr_nodes
[]
,
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
,
unsigned
long
entrypoint
,
unsigned
long
entrypoint
,
...
@@ -358,6 +320,7 @@ int psci_afflvl_suspend(unsigned long entrypoint,
...
@@ -358,6 +320,7 @@ int psci_afflvl_suspend(unsigned long entrypoint,
{
{
int
rc
=
PSCI_E_SUCCESS
;
int
rc
=
PSCI_E_SUCCESS
;
mpidr_aff_map_nodes_t
mpidr_nodes
;
mpidr_aff_map_nodes_t
mpidr_nodes
;
unsigned
int
max_phys_off_afflvl
;
/*
/*
* Collect the pointers to the nodes in the topology tree for
* Collect the pointers to the nodes in the topology tree for
...
@@ -381,6 +344,24 @@ int psci_afflvl_suspend(unsigned long entrypoint,
...
@@ -381,6 +344,24 @@ int psci_afflvl_suspend(unsigned long entrypoint,
end_afflvl
,
end_afflvl
,
mpidr_nodes
);
mpidr_nodes
);
/*
* This function updates the state of each affinity instance
* corresponding to the mpidr in the range of affinity levels
* specified.
*/
psci_do_afflvl_state_mgmt
(
start_afflvl
,
end_afflvl
,
mpidr_nodes
,
PSCI_STATE_SUSPEND
);
max_phys_off_afflvl
=
psci_find_max_phys_off_afflvl
(
start_afflvl
,
end_afflvl
,
mpidr_nodes
);
assert
(
max_phys_off_afflvl
!=
PSCI_INVALID_DATA
);
/* Stash the highest affinity level that will be turned off */
psci_set_max_phys_off_afflvl
(
max_phys_off_afflvl
);
/* Perform generic, architecture and platform specific handling */
/* Perform generic, architecture and platform specific handling */
rc
=
psci_call_suspend_handlers
(
mpidr_nodes
,
rc
=
psci_call_suspend_handlers
(
mpidr_nodes
,
start_afflvl
,
start_afflvl
,
...
@@ -389,6 +370,13 @@ int psci_afflvl_suspend(unsigned long entrypoint,
...
@@ -389,6 +370,13 @@ int psci_afflvl_suspend(unsigned long entrypoint,
context_id
,
context_id
,
power_state
);
power_state
);
/*
* Invalidate the entry for the highest affinity level stashed earlier.
* This ensures that any reads of this variable outside the power
* up/down sequences return PSCI_INVALID_DATA.
*/
psci_set_max_phys_off_afflvl
(
PSCI_INVALID_DATA
);
/*
/*
* Release the locks corresponding to each affinity level in the
* Release the locks corresponding to each affinity level in the
* reverse order to which they were acquired.
* reverse order to which they were acquired.
...
@@ -451,13 +439,13 @@ static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
...
@@ -451,13 +439,13 @@ static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
* error, it's expected to assert within
* error, it's expected to assert within
*/
*/
if
(
psci_spd_pm
&&
psci_spd_pm
->
svc_suspend
)
{
if
(
psci_spd_pm
&&
psci_spd_pm
->
svc_suspend
)
{
suspend_level
=
psci_get_
aff_map_node_
suspend_afflvl
(
cpu_node
);
suspend_level
=
psci_get_suspend_afflvl
();
assert
(
suspend_level
!=
PSCI_INVALID_DATA
);
assert
(
suspend_level
!=
PSCI_INVALID_DATA
);
psci_spd_pm
->
svc_suspend_finish
(
suspend_level
);
psci_spd_pm
->
svc_suspend_finish
(
suspend_level
);
}
}
/* Invalidate the suspend context for the node */
/* Invalidate the suspend context for the node */
psci_set_suspend_power_state
(
cpu_node
,
PSCI_INVALID_DATA
);
psci_set_suspend_power_state
(
PSCI_INVALID_DATA
);
/*
/*
* Generic management: Now we just need to retrieve the
* Generic management: Now we just need to retrieve the
...
@@ -466,9 +454,6 @@ static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
...
@@ -466,9 +454,6 @@ static unsigned int psci_afflvl0_suspend_finish(aff_map_node_t *cpu_node)
*/
*/
cm_prepare_el3_exit
(
NON_SECURE
);
cm_prepare_el3_exit
(
NON_SECURE
);
/* State management: mark this cpu as on */
psci_set_state
(
cpu_node
,
PSCI_STATE_ON
);
/* Clean caches before re-entering normal world */
/* Clean caches before re-entering normal world */
dcsw_op_louis
(
DCCSW
);
dcsw_op_louis
(
DCCSW
);
...
@@ -500,9 +485,6 @@ static unsigned int psci_afflvl1_suspend_finish(aff_map_node_t *cluster_node)
...
@@ -500,9 +485,6 @@ static unsigned int psci_afflvl1_suspend_finish(aff_map_node_t *cluster_node)
assert
(
rc
==
PSCI_E_SUCCESS
);
assert
(
rc
==
PSCI_E_SUCCESS
);
}
}
/* State management: Increment the cluster reference count */
psci_set_state
(
cluster_node
,
PSCI_STATE_ON
);
return
rc
;
return
rc
;
}
}
...
@@ -537,9 +519,6 @@ static unsigned int psci_afflvl2_suspend_finish(aff_map_node_t *system_node)
...
@@ -537,9 +519,6 @@ static unsigned int psci_afflvl2_suspend_finish(aff_map_node_t *system_node)
assert
(
rc
==
PSCI_E_SUCCESS
);
assert
(
rc
==
PSCI_E_SUCCESS
);
}
}
/* State management: Increment the system reference count */
psci_set_state
(
system_node
,
PSCI_STATE_ON
);
return
rc
;
return
rc
;
}
}
...
...
services/std_svc/psci/psci_common.c
View file @
7963671c
...
@@ -58,40 +58,102 @@ __attribute__ ((section("tzfw_coherent_mem")));
...
@@ -58,40 +58,102 @@ __attribute__ ((section("tzfw_coherent_mem")));
******************************************************************************/
******************************************************************************/
const
plat_pm_ops_t
*
psci_plat_pm_ops
;
const
plat_pm_ops_t
*
psci_plat_pm_ops
;
/*******************************************************************************
* This function is passed an array of pointers to affinity level nodes in the
* topology tree for an mpidr. It iterates through the nodes to find the highest
* affinity level which is marked as physically powered off.
******************************************************************************/
uint32_t
psci_find_max_phys_off_afflvl
(
uint32_t
start_afflvl
,
uint32_t
end_afflvl
,
aff_map_node_t
*
mpidr_nodes
[])
{
uint32_t
max_afflvl
=
PSCI_INVALID_DATA
;
for
(;
start_afflvl
<=
end_afflvl
;
start_afflvl
++
)
{
if
(
mpidr_nodes
[
start_afflvl
]
==
NULL
)
continue
;
if
(
psci_get_phys_state
(
mpidr_nodes
[
start_afflvl
])
==
PSCI_STATE_OFF
)
max_afflvl
=
start_afflvl
;
}
return
max_afflvl
;
}
/*******************************************************************************
* This function saves the highest affinity level which is in OFF state. The
* affinity instance with which the level is associated is determined by the
* caller.
******************************************************************************/
void
psci_set_max_phys_off_afflvl
(
uint32_t
afflvl
)
{
set_cpu_data
(
psci_svc_cpu_data
.
max_phys_off_afflvl
,
afflvl
);
/*
* Ensure that the saved value is flushed to main memory and any
* speculatively pre-fetched stale copies are invalidated from the
* caches of other cpus in the same coherency domain. This ensures that
* the value can be safely read irrespective of the state of the data
* cache.
*/
flush_cpu_data
(
psci_svc_cpu_data
.
max_phys_off_afflvl
);
}
/*******************************************************************************
* This function reads the saved highest affinity level which is in OFF
* state. The affinity instance with which the level is associated is determined
* by the caller.
******************************************************************************/
uint32_t
psci_get_max_phys_off_afflvl
(
void
)
{
/*
* Ensure that the last update of this value in this cpu's cache is
* flushed to main memory and any speculatively pre-fetched stale copies
* are invalidated from the caches of other cpus in the same coherency
* domain. This ensures that the value is always read from the main
* memory when it was written before the data cache was enabled.
*/
flush_cpu_data
(
psci_svc_cpu_data
.
max_phys_off_afflvl
);
return
get_cpu_data
(
psci_svc_cpu_data
.
max_phys_off_afflvl
);
}
/*******************************************************************************
/*******************************************************************************
* Routine to return the maximum affinity level to traverse to after a cpu has
* Routine to return the maximum affinity level to traverse to after a cpu has
* been physically powered up. It is expected to be called immediately after
* been physically powered up. It is expected to be called immediately after
* reset from assembler code. It has to find its 'aff_map_node' instead of
* reset from assembler code.
* getting it as an argument.
* TODO: Calling psci_get_aff_map_node() with the MMU disabled is slow. Add
* support to allow faster access to the target affinity level.
******************************************************************************/
******************************************************************************/
int
get_power_on_target_afflvl
(
unsigned
long
mpidr
)
int
get_power_on_target_afflvl
()
{
{
aff_map_node_t
*
node
;
unsigned
int
state
;
int
afflvl
;
int
afflvl
;
#if DEBUG
unsigned
int
state
;
aff_map_node_t
*
node
;
/* Retrieve our node from the topology tree */
/* Retrieve our node from the topology tree */
node
=
psci_get_aff_map_node
(
mpidr
&
MPIDR_AFFINITY_MASK
,
node
=
psci_get_aff_map_node
(
read_mpidr_el1
()
&
MPIDR_AFFINITY_MASK
,
MPIDR_AFFLVL0
);
MPIDR_AFFLVL0
);
assert
(
node
);
assert
(
node
);
/*
/*
* Return the maximum supported affinity level if this cpu was off.
* Sanity check the state of the cpu. It should be either suspend or "on
* Call the handler in the suspend code if this cpu had been suspended.
* pending"
* Any other state is invalid.
*/
*/
state
=
psci_get_state
(
node
);
state
=
psci_get_state
(
node
);
if
(
state
==
PSCI_STATE_ON_PENDING
)
assert
(
state
==
PSCI_STATE_SUSPEND
||
state
==
PSCI_STATE_ON_PENDING
)
;
return
get_max_afflvl
();
#endif
if
(
state
==
PSCI_STATE_SUSPEND
)
{
/*
afflvl
=
psci_get_aff_map_node_suspend_afflvl
(
node
);
* Assume that this cpu was suspended and retrieve its target affinity
assert
(
afflvl
!=
PSCI_INVALID_DATA
);
* level. If it is invalid then it could only have been turned off
return
afflvl
;
* earlier. get_max_afflvl() will return the highest affinity level a
}
* cpu can be turned off to.
return
PSCI_E_INVALID_PARAMS
;
*/
afflvl
=
psci_get_suspend_afflvl
();
if
(
afflvl
==
PSCI_INVALID_DATA
)
afflvl
=
get_max_afflvl
();
return
afflvl
;
}
}
/*******************************************************************************
/*******************************************************************************
...
@@ -151,6 +213,25 @@ int psci_check_afflvl_range(int start_afflvl, int end_afflvl)
...
@@ -151,6 +213,25 @@ int psci_check_afflvl_range(int start_afflvl, int end_afflvl)
return
PSCI_E_SUCCESS
;
return
PSCI_E_SUCCESS
;
}
}
/*******************************************************************************
* This function is passed an array of pointers to affinity level nodes in the
* topology tree for an mpidr and the state which each node should transition
* to. It updates the state of each node between the specified affinity levels.
******************************************************************************/
void
psci_do_afflvl_state_mgmt
(
uint32_t
start_afflvl
,
uint32_t
end_afflvl
,
aff_map_node_t
*
mpidr_nodes
[],
uint32_t
state
)
{
uint32_t
level
;
for
(
level
=
start_afflvl
;
level
<=
end_afflvl
;
level
++
)
{
if
(
mpidr_nodes
[
level
]
==
NULL
)
continue
;
psci_set_state
(
mpidr_nodes
[
level
],
state
);
}
}
/*******************************************************************************
/*******************************************************************************
* This function is passed an array of pointers to affinity level nodes in the
* This function is passed an array of pointers to affinity level nodes in the
* topology tree for an mpidr. It picks up locks for each affinity level bottom
* topology tree for an mpidr. It picks up locks for each affinity level bottom
...
@@ -158,7 +239,7 @@ int psci_check_afflvl_range(int start_afflvl, int end_afflvl)
...
@@ -158,7 +239,7 @@ int psci_check_afflvl_range(int start_afflvl, int end_afflvl)
******************************************************************************/
******************************************************************************/
void
psci_acquire_afflvl_locks
(
int
start_afflvl
,
void
psci_acquire_afflvl_locks
(
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
,
mpidr_
aff_map_node
s
_t
mpidr_nodes
)
aff_map_node_t
*
mpidr_nodes
[]
)
{
{
int
level
;
int
level
;
...
@@ -176,7 +257,7 @@ void psci_acquire_afflvl_locks(int start_afflvl,
...
@@ -176,7 +257,7 @@ void psci_acquire_afflvl_locks(int start_afflvl,
******************************************************************************/
******************************************************************************/
void
psci_release_afflvl_locks
(
int
start_afflvl
,
void
psci_release_afflvl_locks
(
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
,
mpidr_
aff_map_node
s
_t
mpidr_nodes
)
aff_map_node_t
*
mpidr_nodes
[]
)
{
{
int
level
;
int
level
;
...
@@ -348,7 +429,7 @@ unsigned short psci_get_phys_state(aff_map_node_t *node)
...
@@ -348,7 +429,7 @@ unsigned short psci_get_phys_state(aff_map_node_t *node)
* topology tree and calls the physical power on handler for the corresponding
* topology tree and calls the physical power on handler for the corresponding
* affinity levels
* affinity levels
******************************************************************************/
******************************************************************************/
static
int
psci_call_power_on_handlers
(
mpidr_
aff_map_node
s
_t
mpidr_nodes
,
static
int
psci_call_power_on_handlers
(
aff_map_node_t
*
mpidr_nodes
[]
,
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
,
afflvl_power_on_finisher_t
*
pon_handlers
)
afflvl_power_on_finisher_t
*
pon_handlers
)
...
@@ -397,6 +478,8 @@ void psci_afflvl_power_on_finish(int start_afflvl,
...
@@ -397,6 +478,8 @@ void psci_afflvl_power_on_finish(int start_afflvl,
{
{
mpidr_aff_map_nodes_t
mpidr_nodes
;
mpidr_aff_map_nodes_t
mpidr_nodes
;
int
rc
;
int
rc
;
unsigned
int
max_phys_off_afflvl
;
/*
/*
* Collect the pointers to the nodes in the topology tree for
* Collect the pointers to the nodes in the topology tree for
...
@@ -420,6 +503,17 @@ void psci_afflvl_power_on_finish(int start_afflvl,
...
@@ -420,6 +503,17 @@ void psci_afflvl_power_on_finish(int start_afflvl,
end_afflvl
,
end_afflvl
,
mpidr_nodes
);
mpidr_nodes
);
max_phys_off_afflvl
=
psci_find_max_phys_off_afflvl
(
start_afflvl
,
end_afflvl
,
mpidr_nodes
);
assert
(
max_phys_off_afflvl
!=
PSCI_INVALID_DATA
);
/*
* Stash the highest affinity level that will come out of the OFF or
* SUSPEND states.
*/
psci_set_max_phys_off_afflvl
(
max_phys_off_afflvl
);
/* Perform generic, architecture and platform specific handling */
/* Perform generic, architecture and platform specific handling */
rc
=
psci_call_power_on_handlers
(
mpidr_nodes
,
rc
=
psci_call_power_on_handlers
(
mpidr_nodes
,
start_afflvl
,
start_afflvl
,
...
@@ -428,6 +522,23 @@ void psci_afflvl_power_on_finish(int start_afflvl,
...
@@ -428,6 +522,23 @@ void psci_afflvl_power_on_finish(int start_afflvl,
if
(
rc
!=
PSCI_E_SUCCESS
)
if
(
rc
!=
PSCI_E_SUCCESS
)
panic
();
panic
();
/*
* This function updates the state of each affinity instance
* corresponding to the mpidr in the range of affinity levels
* specified.
*/
psci_do_afflvl_state_mgmt
(
start_afflvl
,
end_afflvl
,
mpidr_nodes
,
PSCI_STATE_ON
);
/*
* Invalidate the entry for the highest affinity level stashed earlier.
* This ensures that any reads of this variable outside the power
* up/down sequences return PSCI_INVALID_DATA
*/
psci_set_max_phys_off_afflvl
(
PSCI_INVALID_DATA
);
/*
/*
* This loop releases the lock corresponding to each affinity level
* This loop releases the lock corresponding to each affinity level
* in the reverse order to which they were acquired.
* in the reverse order to which they were acquired.
...
...
services/std_svc/psci/psci_entry.S
View file @
7963671c
...
@@ -35,8 +35,6 @@
...
@@ -35,8 +35,6 @@
.
globl
psci_aff_on_finish_entry
.
globl
psci_aff_on_finish_entry
.
globl
psci_aff_suspend_finish_entry
.
globl
psci_aff_suspend_finish_entry
.
globl
__psci_cpu_off
.
globl
__psci_cpu_suspend
.
globl
psci_power_down_wfi
.
globl
psci_power_down_wfi
/
*
-----------------------------------------------------
/
*
-----------------------------------------------------
...
@@ -79,6 +77,12 @@ psci_aff_common_finish_entry:
...
@@ -79,6 +77,12 @@ psci_aff_common_finish_entry:
*/
*/
bl
init_cpu_data_ptr
bl
init_cpu_data_ptr
/
*
---------------------------------------------
*
Initialize
the
cpu_ops
pointer
.
*
---------------------------------------------
*/
bl
init_cpu_ops
/
*
---------------------------------------------
/
*
---------------------------------------------
*
Set
the
exception
vectors
*
Set
the
exception
vectors
*
---------------------------------------------
*
---------------------------------------------
...
@@ -134,18 +138,13 @@ psci_aff_common_finish_entry:
...
@@ -134,18 +138,13 @@ psci_aff_common_finish_entry:
*
level
0
.
*
level
0
.
*
---------------------------------------------
*
---------------------------------------------
*/
*/
mrs
x0
,
mpidr_el1
bl
get_power_on_target_afflvl
bl
get_power_on_target_afflvl
cmp
x0
,
xzr
b.lt
_panic
mov
x2
,
x23
mov
x2
,
x23
mov
x1
,
x0
mov
x1
,
x0
mov
x0
,
#
MPIDR_AFFLVL0
mov
x0
,
#
MPIDR_AFFLVL0
bl
psci_afflvl_power_on_finish
bl
psci_afflvl_power_on_finish
b
el3_exit
b
el3_exit
_panic
:
b
_panic
/
*
--------------------------------------------
/
*
--------------------------------------------
*
This
function
is
called
to
indicate
to
the
*
This
function
is
called
to
indicate
to
the
...
...
services/std_svc/psci/psci_helpers.S
View file @
7963671c
...
@@ -30,7 +30,9 @@
...
@@ -30,7 +30,9 @@
#include <arch.h>
#include <arch.h>
#include <asm_macros.S>
#include <asm_macros.S>
#include <assert_macros.S>
#include <platform_def.h>
#include <platform_def.h>
#include <psci.h>
.
globl
psci_do_pwrdown_cache_maintenance
.
globl
psci_do_pwrdown_cache_maintenance
.
globl
psci_do_pwrup_cache_maintenance
.
globl
psci_do_pwrup_cache_maintenance
...
@@ -38,26 +40,30 @@
...
@@ -38,26 +40,30 @@
/*
-----------------------------------------------------------------------
/*
-----------------------------------------------------------------------
*
void
psci_do_pwrdown_cache_maintenance
(
uint32_t
affinity
level
)
;
*
void
psci_do_pwrdown_cache_maintenance
(
uint32_t
affinity
level
)
;
*
*
*
This
function
performs
cache
maintenance
before
this
cpu
is
powered
*
This
function
performs
cache
maintenance
if
the
specified
affinity
*
off
.
The
levels
of
cache
affected
are
determined
by
the
affinity
level
*
level
is
the
equal
to
the
level
of
the
highest
affinity
instance
which
*
which
is
passed
as
the
argument
.
Additionally
,
this
function
also
*
will
be
/
is
physically
powered
off
.
The
levels
of
cache
affected
are
*
ensures
that
stack
memory
is
correctly
flushed
out
to
avoid
coherency
*
determined
by
the
affinity
level
which
is
passed
as
the
argument
i
.
e
.
*
issues
due
to
a
change
in
its
memory
attributes
after
the
data
cache
*
level
0
results
in
a
flush
of
the
L1
cache
.
Both
the
L1
and
L2
caches
*
is
disabled
.
*
are
flushed
for
a
higher
affinity
level
.
*
*
Additionally
,
this
function
also
ensures
that
stack
memory
is
correctly
*
flushed
out
to
avoid
coherency
issues
due
to
a
change
in
its
memory
*
attributes
after
the
data
cache
is
disabled
.
*
-----------------------------------------------------------------------
*
-----------------------------------------------------------------------
*/
*/
func
psci_do_pwrdown_cache_maintenance
func
psci_do_pwrdown_cache_maintenance
stp
x29
,
x30
,
[
sp
,#-
16
]!
stp
x29
,
x30
,
[
sp
,#-
16
]!
stp
x19
,
x20
,
[
sp
,#-
16
]!
stp
x19
,
x20
,
[
sp
,#-
16
]!
/
*
---------------------------------------------
mov
x19
,
x0
*
Disable
the
Data
Cache
.
bl
psci_get_max_phys_off_afflvl
*
---------------------------------------------
#if ASM_ASSERTION
*/
cmp
x0
,
#
PSCI_INVALID_DATA
mrs
x1
,
sctlr_el3
ASM_ASSERT
(
ne
)
bic
x1
,
x1
,
#
SCTLR_C_BIT
#endif
msr
sctlr_el3
,
x1
cmp
x0
,
x1
9
isb
b.ne
1
f
/
*
---------------------------------------------
/
*
---------------------------------------------
*
Determine
to
how
many
levels
of
cache
will
be
*
Determine
to
how
many
levels
of
cache
will
be
...
@@ -72,29 +78,12 @@ func psci_do_pwrdown_cache_maintenance
...
@@ -72,29 +78,12 @@ func psci_do_pwrdown_cache_maintenance
*
---------------------------------------------
*
---------------------------------------------
*/
*/
cmp
x0
,
#
MPIDR_AFFLVL0
cmp
x0
,
#
MPIDR_AFFLVL0
mov
x0
,
#
DCCISW
b.eq
do_core_pwr_dwn
b.ne
flush_caches_to_poc
bl
prepare_cluster_pwr_dwn
/
*
---------------------------------------------
*
Flush
L1
cache
to
PoU
.
*
---------------------------------------------
*/
bl
dcsw_op_louis
b
do_stack_maintenance
b
do_stack_maintenance
/
*
---------------------------------------------
do_core_pwr_dwn
:
*
Flush
L1
and
L2
caches
to
PoC
.
bl
prepare_core_pwr_dwn
*
---------------------------------------------
*/
flush_caches_to_poc
:
bl
dcsw_op_all
/
*
---------------------------------------------
*
TODO
:
Intra
-
cluster
coherency
should
be
*
turned
off
here
once
cpu
-
specific
*
abstractions
are
in
place
.
*
---------------------------------------------
*/
/
*
---------------------------------------------
/
*
---------------------------------------------
*
Do
stack
maintenance
by
flushing
the
used
*
Do
stack
maintenance
by
flushing
the
used
...
@@ -127,6 +116,7 @@ do_stack_maintenance:
...
@@ -127,6 +116,7 @@ do_stack_maintenance:
sub
x1
,
sp
,
x0
sub
x1
,
sp
,
x0
bl
inv_dcache_range
bl
inv_dcache_range
1
:
ldp
x19
,
x20
,
[
sp
],
#
16
ldp
x19
,
x20
,
[
sp
],
#
16
ldp
x29
,
x30
,
[
sp
],
#
16
ldp
x29
,
x30
,
[
sp
],
#
16
ret
ret
...
...
services/std_svc/psci/psci_private.h
View file @
7963671c
...
@@ -52,7 +52,6 @@ typedef struct aff_map_node {
...
@@ -52,7 +52,6 @@ typedef struct aff_map_node {
unsigned
short
ref_count
;
unsigned
short
ref_count
;
unsigned
char
state
;
unsigned
char
state
;
unsigned
char
level
;
unsigned
char
level
;
unsigned
int
power_state
;
bakery_lock_t
lock
;
bakery_lock_t
lock
;
}
aff_map_node_t
;
}
aff_map_node_t
;
...
@@ -85,7 +84,7 @@ unsigned short psci_get_phys_state(aff_map_node_t *node);
...
@@ -85,7 +84,7 @@ unsigned short psci_get_phys_state(aff_map_node_t *node);
void
psci_set_state
(
aff_map_node_t
*
node
,
unsigned
short
state
);
void
psci_set_state
(
aff_map_node_t
*
node
,
unsigned
short
state
);
unsigned
long
mpidr_set_aff_inst
(
unsigned
long
,
unsigned
char
,
int
);
unsigned
long
mpidr_set_aff_inst
(
unsigned
long
,
unsigned
char
,
int
);
int
psci_validate_mpidr
(
unsigned
long
,
int
);
int
psci_validate_mpidr
(
unsigned
long
,
int
);
int
get_power_on_target_afflvl
(
unsigned
long
mp
id
r
);
int
get_power_on_target_afflvl
(
vo
id
);
void
psci_afflvl_power_on_finish
(
int
,
void
psci_afflvl_power_on_finish
(
int
,
int
,
int
,
afflvl_power_on_finisher_t
*
);
afflvl_power_on_finisher_t
*
);
...
@@ -93,19 +92,27 @@ int psci_save_ns_entry(uint64_t mpidr,
...
@@ -93,19 +92,27 @@ int psci_save_ns_entry(uint64_t mpidr,
uint64_t
entrypoint
,
uint64_t
context_id
,
uint64_t
entrypoint
,
uint64_t
context_id
,
uint32_t
caller_scr_el3
,
uint32_t
caller_sctlr_el1
);
uint32_t
caller_scr_el3
,
uint32_t
caller_sctlr_el1
);
int
psci_check_afflvl_range
(
int
start_afflvl
,
int
end_afflvl
);
int
psci_check_afflvl_range
(
int
start_afflvl
,
int
end_afflvl
);
void
psci_do_afflvl_state_mgmt
(
uint32_t
start_afflvl
,
uint32_t
end_afflvl
,
aff_map_node_t
*
mpidr_nodes
[],
uint32_t
state
);
void
psci_acquire_afflvl_locks
(
int
start_afflvl
,
void
psci_acquire_afflvl_locks
(
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
,
mpidr_
aff_map_node
s
_t
mpidr_nodes
);
aff_map_node_t
*
mpidr_nodes
[]
);
void
psci_release_afflvl_locks
(
int
start_afflvl
,
void
psci_release_afflvl_locks
(
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
,
mpidr_aff_map_nodes_t
mpidr_nodes
);
mpidr_aff_map_nodes_t
mpidr_nodes
);
void
psci_print_affinity_map
(
void
);
void
psci_print_affinity_map
(
void
);
void
psci_set_max_phys_off_afflvl
(
uint32_t
afflvl
);
uint32_t
psci_find_max_phys_off_afflvl
(
uint32_t
start_afflvl
,
uint32_t
end_afflvl
,
aff_map_node_t
*
mpidr_nodes
[]);
/* Private exported functions from psci_setup.c */
/* Private exported functions from psci_setup.c */
int
psci_get_aff_map_nodes
(
unsigned
long
mpidr
,
int
psci_get_aff_map_nodes
(
unsigned
long
mpidr
,
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
,
mpidr_
aff_map_node
s
_t
mpidr_nodes
);
aff_map_node_t
*
mpidr_nodes
[]
);
aff_map_node_t
*
psci_get_aff_map_node
(
unsigned
long
,
int
);
aff_map_node_t
*
psci_get_aff_map_node
(
unsigned
long
,
int
);
/* Private exported functions from psci_affinity_on.c */
/* Private exported functions from psci_affinity_on.c */
...
@@ -119,15 +126,13 @@ int psci_afflvl_on(unsigned long,
...
@@ -119,15 +126,13 @@ int psci_afflvl_on(unsigned long,
int
psci_afflvl_off
(
int
,
int
);
int
psci_afflvl_off
(
int
,
int
);
/* Private exported functions from psci_affinity_suspend.c */
/* Private exported functions from psci_affinity_suspend.c */
void
psci_set_suspend_power_state
(
aff_map_node_t
*
node
,
unsigned
int
power_state
);
int
psci_get_aff_map_node_suspend_afflvl
(
aff_map_node_t
*
node
);
int
psci_afflvl_suspend
(
unsigned
long
,
int
psci_afflvl_suspend
(
unsigned
long
,
unsigned
long
,
unsigned
long
,
unsigned
int
,
unsigned
int
,
int
,
int
,
int
);
int
);
unsigned
int
psci_afflvl_suspend_finish
(
int
,
int
);
unsigned
int
psci_afflvl_suspend_finish
(
int
,
int
);
void
psci_set_suspend_power_state
(
unsigned
int
power_state
);
/* Private exported functions from psci_helpers.S */
/* Private exported functions from psci_helpers.S */
void
psci_do_pwrdown_cache_maintenance
(
uint32_t
affinity_level
);
void
psci_do_pwrdown_cache_maintenance
(
uint32_t
affinity_level
);
...
...
services/std_svc/psci/psci_setup.c
View file @
7963671c
...
@@ -116,7 +116,7 @@ aff_map_node_t *psci_get_aff_map_node(unsigned long mpidr, int aff_lvl)
...
@@ -116,7 +116,7 @@ aff_map_node_t *psci_get_aff_map_node(unsigned long mpidr, int aff_lvl)
int
psci_get_aff_map_nodes
(
unsigned
long
mpidr
,
int
psci_get_aff_map_nodes
(
unsigned
long
mpidr
,
int
start_afflvl
,
int
start_afflvl
,
int
end_afflvl
,
int
end_afflvl
,
mpidr_
aff_map_node
s
_t
mpidr_nodes
)
aff_map_node_t
*
mpidr_nodes
[]
)
{
{
int
rc
=
PSCI_E_INVALID_PARAMS
,
level
;
int
rc
=
PSCI_E_INVALID_PARAMS
,
level
;
aff_map_node_t
*
node
;
aff_map_node_t
*
node
;
...
@@ -189,9 +189,6 @@ static void psci_init_aff_map_node(unsigned long mpidr,
...
@@ -189,9 +189,6 @@ static void psci_init_aff_map_node(unsigned long mpidr,
if
(
state
&
PSCI_AFF_PRESENT
)
if
(
state
&
PSCI_AFF_PRESENT
)
psci_set_state
(
&
psci_aff_map
[
idx
],
PSCI_STATE_OFF
);
psci_set_state
(
&
psci_aff_map
[
idx
],
PSCI_STATE_OFF
);
/* Invalidate the suspend context for the node */
psci_aff_map
[
idx
].
power_state
=
PSCI_INVALID_DATA
;
/*
/*
* Associate a non-secure context with this affinity
* Associate a non-secure context with this affinity
* instance through the context management library.
* instance through the context management library.
...
@@ -199,6 +196,20 @@ static void psci_init_aff_map_node(unsigned long mpidr,
...
@@ -199,6 +196,20 @@ static void psci_init_aff_map_node(unsigned long mpidr,
linear_id
=
platform_get_core_pos
(
mpidr
);
linear_id
=
platform_get_core_pos
(
mpidr
);
assert
(
linear_id
<
PLATFORM_CORE_COUNT
);
assert
(
linear_id
<
PLATFORM_CORE_COUNT
);
/* Invalidate the suspend context for the node */
set_cpu_data_by_index
(
linear_id
,
psci_svc_cpu_data
.
power_state
,
PSCI_INVALID_DATA
);
/*
* There is no state associated with the current execution
* context so ensure that any reads of the highest affinity
* level in a powered down state return PSCI_INVALID_DATA.
*/
set_cpu_data_by_index
(
linear_id
,
psci_svc_cpu_data
.
max_phys_off_afflvl
,
PSCI_INVALID_DATA
);
cm_set_context_by_mpidr
(
mpidr
,
cm_set_context_by_mpidr
(
mpidr
,
(
void
*
)
&
psci_ns_context
[
linear_id
],
(
void
*
)
&
psci_ns_context
[
linear_id
],
NON_SECURE
);
NON_SECURE
);
...
...
Prev
1
2
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