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
05a91fb0
Commit
05a91fb0
authored
Dec 08, 2015
by
danh-arm
Browse files
Merge pull request #452 from vwadekar/tegra-new-platform-apis-v2
Tegra new platform apis v2
parents
f3974ea5
71cb26ea
Changes
14
Hide whitespace changes
Inline
Side-by-side
plat/nvidia/tegra/common/aarch64/tegra_helpers.S
View file @
05a91fb0
...
...
@@ -36,9 +36,9 @@
#include <tegra_def.h>
/
*
Global
functions
*/
.
globl
plat
form_is
_primary
_cpu
.
globl
plat
form_get
_core_pos
.
globl
plat
form
_get_entrypoint
.
globl
plat
_is_my_cpu
_primary
.
globl
plat
_my
_core_pos
.
globl
plat_get_
my_
entrypoint
.
globl
plat_secondary_cold_boot_setup
.
globl
platform_mem_init
.
globl
plat_crash_console_init
...
...
@@ -47,7 +47,7 @@
.
globl
plat_reset_handler
/
*
Global
variables
*/
.
globl
sec_entry_point
.
globl
tegra_
sec_entry_point
.
globl
ns_image_entrypoint
.
globl
tegra_bl31_phys_base
...
...
@@ -115,28 +115,47 @@
.
endm
/
*
-----------------------------------------------------
*
int
platform_is_primary_cpu
(
int
mp
id
r
)
;
*
unsigned
int
plat_is_my_cpu_primary
(
vo
id
)
;
*
*
This
function
checks
if
this
is
the
Primary
CPU
*
-----------------------------------------------------
*/
func
platform_is_primary_cpu
func
plat_is_my_cpu_primary
mrs
x0
,
mpidr_el1
and
x0
,
x0
,
#(
MPIDR_CLUSTER_MASK
|
MPIDR_CPU_MASK
)
cmp
x0
,
#
TEGRA_PRIMARY_CPU
cset
x0
,
eq
ret
endfunc
plat
form_is
_primary
_cpu
endfunc
plat
_is_my_cpu
_primary
/
*
-----------------------------------------------------
*
int
platform_get_core_pos
(
int
mpidr
)
;
*
unsigned
int
plat_my_core_pos
(
void
)
;
*
*
result
:
CorePos
=
CoreId
+
(
ClusterId
<<
2
)
*
-----------------------------------------------------
*/
func
plat_my_core_pos
mrs
x0
,
mpidr_el1
and
x1
,
x0
,
#
MPIDR_CPU_MASK
and
x0
,
x0
,
#
MPIDR_CLUSTER_MASK
add
x0
,
x1
,
x0
,
LSR
#
6
ret
endfunc
plat_my_core_pos
/
*
-----------------------------------------------------
*
unsigned
long
plat_get_my_entrypoint
(
void
)
;
*
*
Main
job
of
this
routine
is
to
distinguish
between
*
a
cold
and
warm
boot
.
If
the
tegra_sec_entry_point
for
*
this
CPU
is
present
,
then
it
's a warm boot.
*
*
With
this
function
:
CorePos
=
CoreId
*
-----------------------------------------------------
*/
func
platform_get_core_pos
and
x0
,
x0
,
#
MPIDR_CPU_MASK
func
plat_get_my_entrypoint
adr
x1
,
tegra_sec_entry_point
ldr
x0
,
[
x1
]
ret
endfunc
plat
form
_get_
core_pos
endfunc
plat_get_
my_entrypoint
/
*
-----------------------------------------------------
*
void
plat_secondary_cold_boot_setup
(
void
)
;
...
...
@@ -151,22 +170,6 @@ func plat_secondary_cold_boot_setup
ret
endfunc
plat_secondary_cold_boot_setup
/
*
-----------------------------------------------------
*
void
platform_get_entrypoint
(
unsigned
int
mpidr
)
;
*
*
Main
job
of
this
routine
is
to
distinguish
between
*
a
cold
and
warm
boot
.
If
the
sec_entry_point
for
*
this
CPU
is
present
,
then
it
's a warm boot.
*
*
-----------------------------------------------------
*/
func
platform_get_entrypoint
and
x0
,
x0
,
#
MPIDR_CPU_MASK
adr
x1
,
sec_entry_point
ldr
x0
,
[
x1
,
x0
,
lsl
#
3
]
ret
endfunc
platform_get_entrypoint
/
*
--------------------------------------------------------
*
void
platform_mem_init
(
void
)
;
*
...
...
@@ -336,8 +339,7 @@ restore_oslock:
*
Get
secure
world
's entry point and jump to it
*
--------------------------------------------------
*/
mrs
x0
,
mpidr_el1
bl
platform_get_entrypoint
bl
plat_get_my_entrypoint
br
x0
endfunc
tegra_secure_entrypoint
...
...
@@ -345,13 +347,11 @@ endfunc tegra_secure_entrypoint
.
align
3
/
*
--------------------------------------------------
*
Per
-
CPU
Secure
entry
point
-
resume
from
suspend
*
CPU
Secure
entry
point
-
resume
from
suspend
*
--------------------------------------------------
*/
sec_entry_point
:
.
rept
PLATFORM_CORE_COUNT
tegra_sec_entry_point
:
.
quad
0
.
endr
/
*
--------------------------------------------------
*
NS
world
's cold boot entry point
...
...
plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c
View file @
05a91fb0
...
...
@@ -98,9 +98,9 @@ static void tegra_fc_prepare_suspend(int cpu_id, uint32_t csr)
}
/*******************************************************************************
*
Suspend
the current CPU
*
Powerdn
the current CPU
******************************************************************************/
void
tegra_fc_cpu_
idle
(
uint32_t
mpidr
)
void
tegra_fc_cpu_
powerdn
(
uint32_t
mpidr
)
{
int
cpu
=
mpidr
&
MPIDR_CPU_MASK
;
...
...
plat/nvidia/tegra/common/tegra_common.mk
View file @
05a91fb0
...
...
@@ -51,6 +51,7 @@ BL31_SOURCES += drivers/arm/gic/gic_v2.c \
drivers/delay_timer/delay_timer.c
\
drivers/ti/uart/16550_console.S
\
plat/common/aarch64/platform_mp_stack.S
\
plat/common/aarch64/plat_psci_common.c
\
${COMMON_DIR}
/aarch64/tegra_helpers.S
\
${COMMON_DIR}
/drivers/memctrl/memctrl.c
\
${COMMON_DIR}
/drivers/pmc/pmc.c
\
...
...
plat/nvidia/tegra/common/tegra_pm.c
View file @
05a91fb0
...
...
@@ -44,35 +44,34 @@
#include <tegra_private.h>
extern
uint64_t
tegra_bl31_phys_base
;
extern
uint64_t
sec_entry_point
[
PLATFORM_CORE_COUNT
];
static
int
system_suspended
;
extern
uint64_t
tegra_sec_entry_point
;
/*
* The following platform setup functions are weakly defined. They
* provide typical implementations that will be overridden by a SoC.
*/
#pragma weak tegra_soc_p
repare_cpu
_suspend
#pragma weak tegra_soc_p
repare_cpu
_on
#pragma weak tegra_soc_p
repare_cpu
_off
#pragma weak tegra_soc_p
repare_cpu
_on_finish
#pragma weak tegra_soc_p
wr_domain
_suspend
#pragma weak tegra_soc_p
wr_domain
_on
#pragma weak tegra_soc_p
wr_domain
_off
#pragma weak tegra_soc_p
wr_domain
_on_finish
#pragma weak tegra_soc_prepare_system_reset
int
tegra_soc_p
repare_cpu_suspend
(
unsigned
int
id
,
unsigned
int
afflvl
)
int
tegra_soc_p
wr_domain_suspend
(
const
psci_power_state_t
*
target_state
)
{
return
PSCI_E_NOT_SUPPORTED
;
}
int
tegra_soc_p
repare_cpu_on
(
unsigned
long
mpidr
)
int
tegra_soc_p
wr_domain_on
(
u_register_t
mpidr
)
{
return
PSCI_E_SUCCESS
;
}
int
tegra_soc_p
repare_cpu_off
(
unsigned
long
mpidr
)
int
tegra_soc_p
wr_domain_off
(
const
psci_power_state_t
*
target_state
)
{
return
PSCI_E_SUCCESS
;
}
int
tegra_soc_p
repare_cpu
_on_finish
(
unsigned
long
mpidr
)
int
tegra_soc_p
wr_domain
_on_finish
(
const
psci_power_state_t
*
target_state
)
{
return
PSCI_E_SUCCESS
;
}
...
...
@@ -83,33 +82,25 @@ int tegra_soc_prepare_system_reset(void)
}
/*******************************************************************************
* Track system suspend entry.
******************************************************************************/
void
tegra_pm_system_suspend_entry
(
void
)
{
system_suspended
=
1
;
}
/*******************************************************************************
* Track system suspend exit.
******************************************************************************/
void
tegra_pm_system_suspend_exit
(
void
)
* This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
* call to get the `power_state` parameter. This allows the platform to encode
* the appropriate State-ID field within the `power_state` parameter which can
* be utilized in `pwr_domain_suspend()` to suspend to system affinity level.
******************************************************************************/
void
tegra_get_sys_suspend_power_state
(
psci_power_state_t
*
req_state
)
{
system_suspended
=
0
;
}
/* lower affinities use PLAT_MAX_OFF_STATE */
for
(
int
i
=
MPIDR_AFFLVL0
;
i
<
PLAT_MAX_PWR_LVL
;
i
++
)
req_state
->
pwr_domain_state
[
i
]
=
PLAT_MAX_OFF_STATE
;
/*******************************************************************************
* Get the system suspend state.
******************************************************************************/
int
tegra_system_suspended
(
void
)
{
return
system_suspended
;
/* max affinity uses system suspend state id */
req_state
->
pwr_domain_state
[
PLAT_MAX_PWR_LVL
]
=
PSTATE_ID_SOC_POWERDN
;
}
/*******************************************************************************
* Handler called when an affinity instance is about to enter standby.
******************************************************************************/
void
tegra_
affinst
_standby
(
unsigned
int
power
_state
)
void
tegra_
cpu
_standby
(
plat_local_state_t
cpu
_state
)
{
/*
* Enter standby state
...
...
@@ -119,132 +110,45 @@ void tegra_affinst_standby(unsigned int power_state)
wfi
();
}
/*******************************************************************************
* This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
* call to get the `power_state` parameter. This allows the platform to encode
* the appropriate State-ID field within the `power_state` parameter which can
* be utilized in `affinst_suspend()` to suspend to system affinity level.
******************************************************************************/
unsigned
int
tegra_get_sys_suspend_power_state
(
void
)
{
unsigned
int
power_state
;
power_state
=
psci_make_powerstate
(
PLAT_SYS_SUSPEND_STATE_ID
,
PSTATE_TYPE_POWERDOWN
,
MPIDR_AFFLVL2
);
return
power_state
;
}
/*******************************************************************************
* Handler called to check the validity of the power state parameter.
******************************************************************************/
int32_t
tegra_validate_power_state
(
unsigned
int
power_state
)
{
return
tegra_soc_validate_power_state
(
power_state
);
}
/*******************************************************************************
* Handler called when an affinity instance is about to be turned on. The
* level and mpidr determine the affinity instance.
******************************************************************************/
int
tegra_affinst_on
(
unsigned
long
mpidr
,
unsigned
long
sec_entrypoint
,
unsigned
int
afflvl
,
unsigned
int
state
)
int
tegra_pwr_domain_on
(
u_register_t
mpidr
)
{
int
cpu
=
mpidr
&
MPIDR_CPU_MASK
;
/*
* Support individual CPU power on only.
*/
if
(
afflvl
>
MPIDR_AFFLVL0
)
return
PSCI_E_SUCCESS
;
/*
* Flush entrypoint variable to PoC since it will be
* accessed after a reset with the caches turned off.
*/
sec_entry_point
[
cpu
]
=
sec_entrypoint
;
flush_dcache_range
((
uint64_t
)
&
sec_entry_point
[
cpu
],
sizeof
(
uint64_t
));
return
tegra_soc_prepare_cpu_on
(
mpidr
);
return
tegra_soc_pwr_domain_on
(
mpidr
);
}
/*******************************************************************************
* Handler called when an affinity instance is about to be turned off. The
* level determines the affinity instance. The 'state' arg. allows the
* platform to decide whether the cluster is being turned off and take apt
* actions.
*
* CAUTION: This function is called with coherent stacks so that caches can be
* turned off, flushed and coherency disabled. There is no guarantee that caches
* will remain turned on across calls to this function as each affinity level is
* dealt with. So do not write & read global variables across calls. It will be
* wise to do flush a write to the global to prevent unpredictable results.
* Handler called when a power domain is about to be turned off. The
* target_state encodes the power state that each level should transition to.
******************************************************************************/
void
tegra_
affinst_off
(
unsigned
int
afflvl
,
unsigned
int
state
)
void
tegra_
pwr_domain_off
(
const
psci_power_state_t
*
target_
state
)
{
/*
* Support individual CPU power off only.
*/
if
(
afflvl
>
MPIDR_AFFLVL0
)
return
;
tegra_soc_prepare_cpu_off
(
read_mpidr
());
tegra_soc_pwr_domain_off
(
target_state
);
}
/*******************************************************************************
* Handler called when an affinity instance is about to be suspended. The
* level and mpidr determine the affinity instance. The 'state' arg. allows the
* platform to decide whether the cluster is being turned off and take apt
* actions.
*
* CAUTION: This function is called with coherent stacks so that caches can be
* turned off, flushed and coherency disabled. There is no guarantee that caches
* will remain turned on across calls to this function as each affinity level is
* dealt with. So do not write & read global variables across calls. It will be
* wise to flush a write to the global variable, to prevent unpredictable
* results.
* Handler called when called when a power domain is about to be suspended. The
* target_state encodes the power state that each level should transition to.
******************************************************************************/
void
tegra_affinst_suspend
(
unsigned
long
sec_entrypoint
,
unsigned
int
afflvl
,
unsigned
int
state
)
void
tegra_pwr_domain_suspend
(
const
psci_power_state_t
*
target_state
)
{
int
id
=
psci_get_suspend_stateid
();
int
cpu
=
read_mpidr
()
&
MPIDR_CPU_MASK
;
if
(
afflvl
>
PLATFORM_MAX_AFFLVL
)
return
;
/*
* Flush entrypoint variable to PoC since it will be
* accessed after a reset with the caches turned off.
*/
sec_entry_point
[
cpu
]
=
sec_entrypoint
;
flush_dcache_range
((
uint64_t
)
&
sec_entry_point
[
cpu
],
sizeof
(
uint64_t
));
tegra_soc_prepare_cpu_suspend
(
id
,
afflvl
);
tegra_soc_pwr_domain_suspend
(
target_state
);
/* disable GICC */
tegra_gic_cpuif_deactivate
();
}
/*******************************************************************************
* Handler called when an affinity instance has just been powered on after
* being turned off earlier. The level determines the affinity instance.
* The 'state' arg. allows the platform to decide whether the cluster was
* turned off prior to wakeup and do what's necessary to set it up.
* Handler called when a power domain has just been powered on after
* being turned off earlier. The target_state encodes the low power state that
* each level has woken up from.
******************************************************************************/
void
tegra_
affinst
_on_finish
(
unsigned
int
afflvl
,
unsigned
int
state
)
void
tegra_
pwr_domain
_on_finish
(
const
psci_power_state_t
*
target_
state
)
{
plat_params_from_bl2_t
*
plat_params
;
/*
* Support individual CPU power on only.
*/
if
(
afflvl
>
MPIDR_AFFLVL0
)
return
;
/*
* Initialize the GIC cpu and distributor interfaces
*/
...
...
@@ -253,7 +157,8 @@ void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state)
/*
* Check if we are exiting from deep sleep.
*/
if
(
tegra_system_suspended
())
{
if
(
target_state
->
pwr_domain_state
[
PLAT_MAX_PWR_LVL
]
==
PSTATE_ID_SOC_POWERDN
)
{
/*
* Lock scratch registers which hold the CPU vectors.
...
...
@@ -276,18 +181,17 @@ void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state)
/*
* Reset hardware settings.
*/
tegra_soc_p
repare_cpu
_on_finish
(
read_mpidr
()
);
tegra_soc_p
wr_domain
_on_finish
(
target_state
);
}
/*******************************************************************************
* Handler called when a
n affinity instance
has just been powered on after
* having been suspended earlier. The
level and mpidr determine the affinity
*
instance
.
* Handler called when a
power domain
has just been powered on after
* having been suspended earlier. The
target_state encodes the low power state
*
that each level has woken up from
.
******************************************************************************/
void
tegra_
affinst
_suspend_finish
(
unsigned
int
afflvl
,
unsigned
int
state
)
void
tegra_
pwr_domain
_suspend_finish
(
const
psci_power_state_t
*
target_
state
)
{
if
(
afflvl
==
MPIDR_AFFLVL0
)
tegra_affinst_on_finish
(
afflvl
,
state
);
tegra_pwr_domain_on_finish
(
target_state
);
}
/*******************************************************************************
...
...
@@ -313,36 +217,78 @@ __dead2 void tegra_system_reset(void)
tegra_pmc_system_reset
();
}
/*******************************************************************************
* Handler called to check the validity of the power state parameter.
******************************************************************************/
int32_t
tegra_validate_power_state
(
unsigned
int
power_state
,
psci_power_state_t
*
req_state
)
{
int
pwr_lvl
=
psci_get_pstate_pwrlvl
(
power_state
);
assert
(
req_state
);
if
(
pwr_lvl
>
PLAT_MAX_PWR_LVL
)
return
PSCI_E_INVALID_PARAMS
;
return
tegra_soc_validate_power_state
(
power_state
,
req_state
);
}
/*******************************************************************************
* Platform handler called to check the validity of the non secure entrypoint.
******************************************************************************/
int
tegra_validate_ns_entrypoint
(
uintptr_t
entrypoint
)
{
/*
* Check if the non secure entrypoint lies within the non
* secure DRAM.
*/
if
((
entrypoint
>=
TEGRA_DRAM_BASE
)
&&
(
entrypoint
<=
TEGRA_DRAM_END
))
return
PSCI_E_SUCCESS
;
return
PSCI_E_INVALID_ADDRESS
;
}
/*******************************************************************************
* Export the platform handlers to enable psci to invoke them
******************************************************************************/
static
const
plat_pm_ops_t
tegra_plat_pm_ops
=
{
.
affinst_standby
=
tegra_affinst_standby
,
.
affinst_on
=
tegra_affinst_on
,
.
affinst_off
=
tegra_affinst_off
,
.
affinst_suspend
=
tegra_affinst_suspend
,
.
affinst_on_finish
=
tegra_affinst_on_finish
,
.
affinst_suspend_finish
=
tegra_affinst_suspend_finish
,
.
system_off
=
tegra_system_off
,
.
system_reset
=
tegra_system_reset
,
.
validate_power_state
=
tegra_validate_power_state
,
.
get_sys_suspend_power_state
=
tegra_get_sys_suspend_power_state
static
const
plat_psci_ops_t
tegra_plat_psci_ops
=
{
.
cpu_standby
=
tegra_cpu_standby
,
.
pwr_domain_on
=
tegra_pwr_domain_on
,
.
pwr_domain_off
=
tegra_pwr_domain_off
,
.
pwr_domain_suspend
=
tegra_pwr_domain_suspend
,
.
pwr_domain_on_finish
=
tegra_pwr_domain_on_finish
,
.
pwr_domain_suspend_finish
=
tegra_pwr_domain_suspend_finish
,
.
system_off
=
tegra_system_off
,
.
system_reset
=
tegra_system_reset
,
.
validate_power_state
=
tegra_validate_power_state
,
.
validate_ns_entrypoint
=
tegra_validate_ns_entrypoint
,
.
get_sys_suspend_power_state
=
tegra_get_sys_suspend_power_state
,
};
/*******************************************************************************
* Export the platform specific power ops
&
initialize
the fvp p
ower
c
ontroller
* Export the platform specific power ops
and
initialize
P
ower
C
ontroller
******************************************************************************/
int
platform_setup_pm
(
const
plat_pm_ops_t
**
plat_ops
)
int
plat_setup_psci_ops
(
uintptr_t
sec_entrypoint
,
const
plat_psci_ops_t
**
psci_ops
)
{
psci_power_state_t
target_state
=
{
{
PSCI_LOCAL_STATE_RUN
}
};
/*
* Flush entrypoint variable to PoC since it will be
* accessed after a reset with the caches turned off.
*/
tegra_sec_entry_point
=
sec_entrypoint
;
flush_dcache_range
((
uint64_t
)
&
tegra_sec_entry_point
,
sizeof
(
uint64_t
));
/*
* Reset hardware settings.
*/
tegra_soc_p
repare_cpu
_on_finish
(
read_mpidr
()
);
tegra_soc_p
wr_domain
_on_finish
(
&
target_state
);
/*
* Initialize P
M
ops struct
* Initialize P
SCI
ops struct
*/
*
p
lat
_ops
=
&
tegra_plat_p
m
_ops
;
*
p
sci
_ops
=
&
tegra_plat_p
sci
_ops
;
return
0
;
}
plat/nvidia/tegra/common/tegra_topology.c
View file @
05a91fb0
...
...
@@ -28,45 +28,47 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arch
_helpers
.h>
#include <arch.h>
#include <platform_def.h>
#include <psci.h>
extern
const
unsigned
char
tegra_power_domain_tree_desc
[];
/*******************************************************************************
* This function implements a part of the critical interface between the psci
* generic layer and the platform to allow the former to detect the platform
* topology. psci queries the platform to determine how many affinity instances
* are present at a particular level for a given mpidr.
* This function returns the Tegra default topology tree information.
******************************************************************************/
unsigned
int
plat_get_aff_count
(
unsigned
int
aff_lvl
,
unsigned
long
mpidr
)
const
unsigned
char
*
plat_get_power_domain_tree_desc
(
void
)
{
switch
(
aff_lvl
)
{
case
MPIDR_AFFLVL2
:
/* Last supported affinity level */
return
1
;
case
MPIDR_AFFLVL1
:
/* Return # of clusters */
return
PLATFORM_CLUSTER_COUNT
;
case
MPIDR_AFFLVL0
:
/* # of cpus per cluster */
return
PLATFORM_MAX_CPUS_PER_CLUSTER
;
default:
return
PSCI_AFF_ABSENT
;
}
return
tegra_power_domain_tree_desc
;
}
/*******************************************************************************
* This function implements a part of the critical interface between the psci
* generic layer and the platform t
o
allow the former to
detect the state of a
*
affinity instance in the platform topology. psci queries the platform to
*
determine whether an affinity instance is present or absent
.
* generic layer and the platform t
hat
allow
s
the former to
query the platform
*
to convert an MPIDR to a unique linear index. An error code (-1) is returned
*
in case the MPIDR is invalid
.
******************************************************************************/
unsigned
int
plat_get_aff_state
(
unsigned
int
aff_lvl
,
unsigned
long
mpidr
)
int
plat_core_pos_by_mpidr
(
u_register_t
mpidr
)
{
return
(
aff_lvl
<=
MPIDR_AFFLVL2
)
?
PSCI_AFF_PRESENT
:
PSCI_AFF_ABSENT
;
unsigned
int
cluster_id
,
cpu_id
;
mpidr
&=
MPIDR_AFFINITY_MASK
;
if
(
mpidr
&
~
(
MPIDR_CLUSTER_MASK
|
MPIDR_CPU_MASK
))
return
-
1
;
cluster_id
=
(
mpidr
>>
MPIDR_AFF1_SHIFT
)
&
MPIDR_AFFLVL_MASK
;
cpu_id
=
(
mpidr
>>
MPIDR_AFF0_SHIFT
)
&
MPIDR_AFFLVL_MASK
;
if
(
cluster_id
>=
PLATFORM_CLUSTER_COUNT
)
return
-
1
;
/*
* Validate cpu_id by checking whether it represents a CPU in
* one of the two clusters present on the platform.
*/
if
(
cpu_id
>=
PLATFORM_MAX_CPUS_PER_CLUSTER
)
return
-
1
;
return
(
cpu_id
+
(
cluster_id
*
4
));
}
plat/nvidia/tegra/include/drivers/flowctrl.h
View file @
05a91fb0
...
...
@@ -73,8 +73,8 @@ static inline void tegra_fc_write_32(uint32_t off, uint32_t val)
mmio_write_32
(
TEGRA_FLOWCTRL_BASE
+
off
,
val
);
}
void
tegra_fc_cpu_idle
(
uint32_t
mpidr
);
void
tegra_fc_cluster_idle
(
uint32_t
midr
);
void
tegra_fc_cpu_powerdn
(
uint32_t
mpidr
);
void
tegra_fc_cluster_powerdn
(
uint32_t
midr
);
void
tegra_fc_soc_powerdn
(
uint32_t
midr
);
void
tegra_fc_cpu_on
(
int
cpu
);
...
...
plat/nvidia/tegra/include/platform_def.h
View file @
05a91fb0
...
...
@@ -33,6 +33,7 @@
#include <arch.h>
#include <common_def.h>
#include <tegra_def.h>
/*******************************************************************************
* Generic platform constants
...
...
@@ -47,12 +48,18 @@
#define TEGRA_PRIMARY_CPU 0x0
#define PLAT
FORM
_MAX_
AFF
LVL MPIDR_AFFLVL2
#define PLAT_MAX_
PWR_
LVL MPIDR_AFFLVL2
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
PLATFORM_MAX_CPUS_PER_CLUSTER)
#define PLAT
FORM
_NUM_
AFF
S (PLATFORM_CORE_COUNT + \
#define PLAT_NUM_
PWR_DOMAIN
S (PLATFORM_CORE_COUNT + \
PLATFORM_CLUSTER_COUNT + 1)
/*******************************************************************************
* Platform power states
******************************************************************************/
#define PLAT_MAX_RET_STATE 1
#define PLAT_MAX_OFF_STATE (PSTATE_ID_SOC_POWERDN + 1)
/*******************************************************************************
* Platform console related constants
******************************************************************************/
...
...
plat/nvidia/tegra/include/t132/tegra_def.h
View file @
05a91fb0
...
...
@@ -37,7 +37,7 @@
* This value is used by the PSCI implementation during the `SYSTEM_SUSPEND`
* call as the `state-id` field in the 'power state' parameter.
******************************************************************************/
#define P
LAT_SYS_SUSPEND_STATE_ID
0xD
#define P
STATE_ID_SOC_POWERDN
0xD
/*******************************************************************************
* GIC memory map
...
...
plat/nvidia/tegra/include/tegra_private.h
View file @
05a91fb0
...
...
@@ -31,8 +31,9 @@
#ifndef __TEGRA_PRIVATE_H__
#define __TEGRA_PRIVATE_H__
#include <
xlat_tables
.h>
#include <
arch
.h>
#include <platform_def.h>
#include <xlat_tables.h>
/*******************************************************************************
* Tegra DRAM memory base address
...
...
@@ -45,7 +46,8 @@ typedef struct plat_params_from_bl2 {
}
plat_params_from_bl2_t
;
/* Declarations for plat_psci_handlers.c */
int32_t
tegra_soc_validate_power_state
(
unsigned
int
power_state
);
int32_t
tegra_soc_validate_power_state
(
unsigned
int
power_state
,
psci_power_state_t
*
req_state
);
/* Declarations for plat_setup.c */
const
mmap_region_t
*
plat_get_mmio_map
(
void
);
...
...
plat/nvidia/tegra/platform.mk
View file @
05a91fb0
...
...
@@ -28,7 +28,10 @@
# POSSIBILITY OF SUCH DAMAGE.
#
SOC_DIR
:=
plat/nvidia/tegra/soc/
${TARGET_SOC}
SOC_DIR
:=
plat/nvidia/tegra/soc/
${TARGET_SOC}
# Disable the PSCI platform compatibility layer
ENABLE_PLAT_COMPAT
:=
0
include
plat/nvidia/tegra/common/tegra_common.mk
include
${SOC_DIR}/platform_${TARGET_SOC}.mk
...
...
plat/nvidia/tegra/soc/t132/plat_psci_handlers.c
View file @
05a91fb0
...
...
@@ -56,28 +56,55 @@
static
int
cpu_powergate_mask
[
PLATFORM_MAX_CPUS_PER_CLUSTER
];
int32_t
tegra_soc_validate_power_state
(
unsigned
int
power_state
)
int32_t
tegra_soc_validate_power_state
(
unsigned
int
power_state
,
psci_power_state_t
*
req_state
)
{
int
pwr_lvl
=
psci_get_pstate_pwrlvl
(
power_state
);
int
state_id
=
psci_get_pstate_id
(
power_state
);
int
cpu
=
read_mpidr
()
&
MPIDR_CPU_MASK
;
if
(
pwr_lvl
>
PLAT_MAX_PWR_LVL
)
return
PSCI_E_INVALID_PARAMS
;
/* Sanity check the requested afflvl */
if
(
psci_get_pstate_type
(
power_state
)
==
PSTATE_TYPE_STANDBY
)
{
/*
* It's possible to enter standby only on affinity level 0 i.e.
* a cpu on Tegra. Ignore any other affinity level.
*/
if
(
p
sci_get_pstate_afflvl
(
power_state
)
!=
MPIDR_AFFLVL0
)
if
(
p
wr_lvl
!=
MPIDR_AFFLVL0
)
return
PSCI_E_INVALID_PARAMS
;
/* power domain in standby state */
req_state
->
pwr_domain_state
[
pwr_lvl
]
=
PLAT_MAX_RET_STATE
;
return
PSCI_E_SUCCESS
;
}
/* Sanity check the requested state id */
if
(
psci_get_pstate_id
(
power_state
)
!=
PLAT_SYS_SUSPEND_STATE_ID
)
{
ERROR
(
"unsupported state id
\n
"
);
return
PSCI_E_NOT_SUPPORTED
;
/*
* Sanity check the requested state id, power level and CPU number.
* Currently T132 only supports SYSTEM_SUSPEND on last standing CPU
* i.e. CPU 0
*/
if
((
pwr_lvl
!=
PLAT_MAX_PWR_LVL
)
||
(
state_id
!=
PSTATE_ID_SOC_POWERDN
)
||
(
cpu
!=
0
))
{
ERROR
(
"unsupported state id @ power level
\n
"
);
return
PSCI_E_INVALID_PARAMS
;
}
/* Set lower power states to PLAT_MAX_OFF_STATE */
for
(
int
i
=
MPIDR_AFFLVL0
;
i
<
PLAT_MAX_PWR_LVL
;
i
++
)
req_state
->
pwr_domain_state
[
i
]
=
PLAT_MAX_OFF_STATE
;
/* Set the SYSTEM_SUSPEND state-id */
req_state
->
pwr_domain_state
[
PLAT_MAX_PWR_LVL
]
=
PSTATE_ID_SOC_POWERDN
;
return
PSCI_E_SUCCESS
;
}
int
tegra_soc_p
repare_cpu_on
(
unsigned
long
mpidr
)
int
tegra_soc_p
wr_domain_on
(
u_register_t
mpidr
)
{
int
cpu
=
mpidr
&
MPIDR_CPU_MASK
;
uint32_t
mask
=
CPU_CORE_RESET_MASK
<<
cpu
;
...
...
@@ -101,29 +128,29 @@ int tegra_soc_prepare_cpu_on(unsigned long mpidr)
return
PSCI_E_SUCCESS
;
}
int
tegra_soc_p
repare_cpu_off
(
unsigned
long
mpidr
)
int
tegra_soc_p
wr_domain_off
(
const
psci_power_state_t
*
target_state
)
{
tegra_fc_cpu_off
(
mpidr
&
MPIDR_CPU_MASK
);
tegra_fc_cpu_off
(
read_
mpidr
()
&
MPIDR_CPU_MASK
);
return
PSCI_E_SUCCESS
;
}
int
tegra_soc_p
repare_cpu_suspend
(
unsigned
int
id
,
unsigned
int
afflvl
)
int
tegra_soc_p
wr_domain_suspend
(
const
psci_power_state_t
*
target_state
)
{
/* Nothing to be done for lower affinity levels */
if
(
afflvl
<
MPIDR_AFFLVL2
)
return
PSCI_E_SUCCESS
;
#if DEBUG
int
cpu
=
read_mpidr
()
&
MPIDR_CPU_MASK
;
/* Enter system suspend state */
tegra_pm_system_suspend_entry
();
/* SYSTEM_SUSPEND only on CPU0 */
assert
(
cpu
==
0
);
#endif
/* Allow restarting CPU #1 using PMC on suspend exit */
cpu_powergate_mask
[
1
]
=
0
;
/* Program FC to enter suspend state */
tegra_fc_cpu_
idle
(
read_mpidr
());
tegra_fc_cpu_
powerdn
(
read_mpidr
());
/* Suspend DCO operations */
write_actlr_el1
(
id
);
write_actlr_el1
(
target_state
->
pwr_domain_state
[
PLAT_MAX_PWR_LVL
]
);
return
PSCI_E_SUCCESS
;
}
...
...
plat/nvidia/tegra/soc/t132/plat_setup.c
View file @
05a91fb0
...
...
@@ -31,6 +31,21 @@
#include <xlat_tables.h>
#include <tegra_def.h>
/*******************************************************************************
* The Tegra power domain tree has a single system level power domain i.e. a
* single root node. The first entry in the power domain descriptor specifies
* the number of power domains at the highest power level.
*******************************************************************************
*/
const
unsigned
char
tegra_power_domain_tree_desc
[]
=
{
/* No of root nodes */
1
,
/* No of clusters */
PLATFORM_CLUSTER_COUNT
,
/* No of CPU cores */
PLATFORM_CORE_COUNT
,
};
/* sets of MMIO ranges setup */
#define MMIO_RANGE_0_ADDR 0x50000000
#define MMIO_RANGE_1_ADDR 0x60000000
...
...
plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
View file @
05a91fb0
...
...
@@ -55,83 +55,139 @@
static
int
cpu_powergate_mask
[
PLATFORM_MAX_CPUS_PER_CLUSTER
];
int32_t
tegra_soc_validate_power_state
(
unsigned
int
power_state
)
int32_t
tegra_soc_validate_power_state
(
unsigned
int
power_state
,
psci_power_state_t
*
req_state
)
{
int
pwr_lvl
=
psci_get_pstate_pwrlvl
(
power_state
);
int
state_id
=
psci_get_pstate_id
(
power_state
);
if
(
pwr_lvl
>
PLAT_MAX_PWR_LVL
)
{
ERROR
(
"%s: unsupported power_state (0x%x)
\n
"
,
__func__
,
power_state
);
return
PSCI_E_INVALID_PARAMS
;
}
/* Sanity check the requested afflvl */
if
(
psci_get_pstate_type
(
power_state
)
==
PSTATE_TYPE_STANDBY
)
{
/*
* It's possible to enter standby only on affinity level 0 i.e.
* a cpu on Tegra. Ignore any other affinity level.
*/
if
(
p
sci_get_pstate_afflvl
(
power_state
)
!=
MPIDR_AFFLVL0
)
if
(
p
wr_lvl
!=
MPIDR_AFFLVL0
)
return
PSCI_E_INVALID_PARAMS
;
/* power domain in standby state */
req_state
->
pwr_domain_state
[
pwr_lvl
]
=
PLAT_MAX_RET_STATE
;
return
PSCI_E_SUCCESS
;
}
/* Sanity check the requested state id */
switch
(
psci_get_pstate_id
(
power_state
)
)
{
switch
(
state_id
)
{
case
PSTATE_ID_CORE_POWERDN
:
/*
* Core powerdown request only for afflvl 0
*/
if
(
pwr_lvl
!=
MPIDR_AFFLVL0
)
goto
error
;
req_state
->
pwr_domain_state
[
MPIDR_AFFLVL0
]
=
state_id
&
0xff
;
break
;
case
PSTATE_ID_CLUSTER_IDLE
:
case
PSTATE_ID_CLUSTER_POWERDN
:
/*
* Cluster powerdown/idle request only for afflvl 1
*/
if
(
pwr_lvl
!=
MPIDR_AFFLVL1
)
goto
error
;
req_state
->
pwr_domain_state
[
MPIDR_AFFLVL1
]
=
state_id
;
req_state
->
pwr_domain_state
[
MPIDR_AFFLVL0
]
=
PLAT_MAX_OFF_STATE
;
break
;
case
PSTATE_ID_SOC_POWERDN
:
/*
* System powerdown request only for afflvl 2
*/
if
(
pwr_lvl
!=
PLAT_MAX_PWR_LVL
)
goto
error
;
for
(
int
i
=
MPIDR_AFFLVL0
;
i
<
PLAT_MAX_PWR_LVL
;
i
++
)
req_state
->
pwr_domain_state
[
i
]
=
PLAT_MAX_OFF_STATE
;
req_state
->
pwr_domain_state
[
PLAT_MAX_PWR_LVL
]
=
PLAT_SYS_SUSPEND_STATE_ID
;
break
;
default:
ERROR
(
"unsupported state id
\n
"
);
return
PSCI_E_
NOT_SUPPORTED
;
ERROR
(
"
%s:
unsupported state id
(%d)
\n
"
,
__func__
,
state_id
);
return
PSCI_E_
INVALID_PARAMS
;
}
return
PSCI_E_SUCCESS
;
error:
ERROR
(
"%s: unsupported state id (%d)
\n
"
,
__func__
,
state_id
);
return
PSCI_E_INVALID_PARAMS
;
}
int
tegra_soc_p
repare_cpu_suspend
(
unsigned
int
id
,
unsigned
int
afflvl
)
int
tegra_soc_p
wr_domain_suspend
(
const
psci_power_state_t
*
target_state
)
{
/* There's nothing to be done for affinity level 1 */
if
(
afflvl
==
MPIDR_AFFLVL1
)
return
PSCI_E_SUCCESS
;
u_register_t
mpidr
=
read_mpidr
();
const
plat_local_state_t
*
pwr_domain_state
=
target_state
->
pwr_domain_state
;
unsigned
int
stateid_afflvl2
=
pwr_domain_state
[
MPIDR_AFFLVL2
];
unsigned
int
stateid_afflvl1
=
pwr_domain_state
[
MPIDR_AFFLVL1
];
unsigned
int
stateid_afflvl0
=
pwr_domain_state
[
MPIDR_AFFLVL0
];
switch
(
id
)
{
/* Prepare for cpu idle */
case
PSTATE_ID_CORE_POWERDN
:
tegra_fc_cpu_idle
(
read_mpidr
());
return
PSCI_E_SUCCESS
;
if
(
stateid_afflvl2
==
PSTATE_ID_SOC_POWERDN
)
{
/* Prepare for cluster idle */
case
PSTATE_ID_CLUSTER_IDLE
:
tegra_fc_cluster_idle
(
read_mpidr
());
return
PSCI_E_SUCCESS
;
assert
(
stateid_afflvl0
==
PLAT_MAX_OFF_STATE
);
assert
(
stateid_afflvl1
==
PLAT_MAX_OFF_STATE
);
/* Prepare for cluster powerdn */
case
PSTATE_ID_CLUSTER_POWERDN
:
tegra_fc_cluster_powerdn
(
read_mpidr
());
return
PSCI_E_SUCCESS
;
/* suspend the entire soc */
tegra_fc_soc_powerdn
(
mpidr
);
/* Prepare for system idle */
case
PSTATE_ID_SOC_POWERDN
:
}
else
if
(
stateid_afflvl1
==
PSTATE_ID_CLUSTER_IDLE
)
{
/* Enter system suspend state */
tegra_pm_system_suspend_entry
();
assert
(
stateid_afflvl0
==
PLAT_MAX_OFF_STATE
);
/*
suspend the entire soc
*/
tegra_fc_
soc_powerdn
(
read_
mpidr
()
);
/*
Prepare for cluster idle
*/
tegra_fc_
cluster_idle
(
mpidr
);
return
PSCI_E_SUCCESS
;
}
else
if
(
stateid_afflvl1
==
PSTATE_ID_CLUSTER_POWERDN
)
{
default:
ERROR
(
"Unknown state id (%d)
\n
"
,
id
);
break
;
assert
(
stateid_afflvl0
==
PLAT_MAX_OFF_STATE
);
/* Prepare for cluster powerdn */
tegra_fc_cluster_powerdn
(
mpidr
);
}
else
if
(
stateid_afflvl0
==
PSTATE_ID_CORE_POWERDN
)
{
/* Prepare for cpu powerdn */
tegra_fc_cpu_powerdn
(
mpidr
);
}
else
{
ERROR
(
"%s: Unknown state id
\n
"
,
__func__
);
return
PSCI_E_NOT_SUPPORTED
;
}
return
PSCI_E_
NOT_SUPPORTED
;
return
PSCI_E_
SUCCESS
;
}
int
tegra_soc_p
repare_cpu
_on_finish
(
unsigned
long
mpidr
)
int
tegra_soc_p
wr_domain
_on_finish
(
const
psci_power_state_t
*
target_state
)
{
uint32_t
val
;
/*
* Check if we are exiting from SOC_POWERDN.
*/
if
(
tegra_system_suspended
())
{
if
(
target_state
->
pwr_domain_state
[
PLAT_MAX_PWR_LVL
]
==
PLAT_SYS_SUSPEND_STATE_ID
)
{
/*
* Enable WRAP to INCR burst type conversions for
...
...
@@ -147,11 +203,6 @@ int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr)
* address and reset it.
*/
tegra_fc_reset_bpmp
();
/*
* System resume complete.
*/
tegra_pm_system_suspend_exit
();
}
/*
...
...
@@ -159,13 +210,12 @@ int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr)
* used for power management and boot purposes. Inform the BPMP that
* we have completed the cluster power up.
*/
if
(
psci_get_max_phys_off_afflvl
()
==
MPIDR_AFFLVL1
)
tegra_fc_lock_active_cluster
();
tegra_fc_lock_active_cluster
();
return
PSCI_E_SUCCESS
;
}
int
tegra_soc_p
repare_cpu_on
(
unsigned
long
mpidr
)
int
tegra_soc_p
wr_domain_on
(
u_register_t
mpidr
)
{
int
cpu
=
mpidr
&
MPIDR_CPU_MASK
;
uint32_t
mask
=
CPU_CORE_RESET_MASK
<<
cpu
;
...
...
@@ -184,9 +234,9 @@ int tegra_soc_prepare_cpu_on(unsigned long mpidr)
return
PSCI_E_SUCCESS
;
}
int
tegra_soc_p
repare_cpu_off
(
unsigned
long
mpidr
)
int
tegra_soc_p
wr_domain_off
(
const
psci_power_state_t
*
target_state
)
{
tegra_fc_cpu_off
(
mpidr
&
MPIDR_CPU_MASK
);
tegra_fc_cpu_off
(
read_
mpidr
()
&
MPIDR_CPU_MASK
);
return
PSCI_E_SUCCESS
;
}
...
...
plat/nvidia/tegra/soc/t210/plat_setup.c
View file @
05a91fb0
...
...
@@ -32,6 +32,23 @@
#include <tegra_def.h>
#include <xlat_tables.h>
/*******************************************************************************
* The Tegra power domain tree has a single system level power domain i.e. a
* single root node. The first entry in the power domain descriptor specifies
* the number of power domains at the highest power level.
*******************************************************************************
*/
const
unsigned
char
tegra_power_domain_tree_desc
[]
=
{
/* No of root nodes */
1
,
/* No of clusters */
PLATFORM_CLUSTER_COUNT
,
/* No of CPU cores - cluster0 */
PLATFORM_MAX_CPUS_PER_CLUSTER
,
/* No of CPU cores - cluster1 */
PLATFORM_MAX_CPUS_PER_CLUSTER
};
/* sets of MMIO ranges setup */
#define MMIO_RANGE_0_ADDR 0x50000000
#define MMIO_RANGE_1_ADDR 0x60000000
...
...
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