Merge changes I9d06e0ee,I6980e84f into integration
* changes:
feat(tegra): implement 'pwr_domain_off_early' handler
feat(psci): introduce 'pwr_domain_off_early' hook
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index bc309dd..1225a9f 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -2785,6 +2785,22 @@
by the ``MPIDR`` (first argument). The generic code expects the platform to
return PSCI_E_SUCCESS on success or PSCI_E_INTERN_FAIL for any failure.
+plat_psci_ops.pwr_domain_off_early() [optional]
+...............................................
+
+This optional function performs the platform specific actions to check if
+powering off the calling CPU and its higher parent power domain levels as
+indicated by the ``target_state`` (first argument) is possible or allowed.
+
+The ``target_state`` encodes the platform coordinated target local power states
+for the CPU power domain and its parent power domain levels.
+
+For this handler, the local power state for the CPU power domain will be a
+power down state where as it could be either power down, retention or run state
+for the higher power domain levels depending on the result of state
+coordination. The generic code expects PSCI_E_DENIED return code if the
+platform thinks that CPU_OFF should not proceed on the calling CPU.
+
plat_psci_ops.pwr_domain_off()
..............................
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
index 6d27b7b..4d7e58e 100644
--- a/include/lib/psci/psci.h
+++ b/include/lib/psci/psci.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -317,6 +318,7 @@
void (*cpu_standby)(plat_local_state_t cpu_state);
int (*pwr_domain_on)(u_register_t mpidr);
void (*pwr_domain_off)(const psci_power_state_t *target_state);
+ int (*pwr_domain_off_early)(const psci_power_state_t *target_state);
void (*pwr_domain_suspend_pwrdown_early)(
const psci_power_state_t *target_state);
#if PSCI_OS_INIT_MODE
diff --git a/lib/psci/psci_off.c b/lib/psci/psci_off.c
index 637adb9..9f36ac7 100644
--- a/lib/psci/psci_off.c
+++ b/lib/psci/psci_off.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -57,6 +58,19 @@
psci_set_power_off_state(&state_info);
/*
+ * Call the platform provided early CPU_OFF handler to allow
+ * platforms to perform any housekeeping activities before
+ * actually powering the CPU off. PSCI_E_DENIED indicates that
+ * the CPU off sequence should be aborted at this time.
+ */
+ if (psci_plat_pm_ops->pwr_domain_off_early) {
+ rc = psci_plat_pm_ops->pwr_domain_off_early(&state_info);
+ if (rc == PSCI_E_DENIED) {
+ return rc;
+ }
+ }
+
+ /*
* Get the parent nodes here, this is important to do before we
* initiate the power down sequence as after that point the core may
* have exited coherency and its cache may be disabled, any access to
diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
index 6c8c4f0..72ecd54 100644
--- a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
+++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
@@ -125,15 +125,18 @@
.endm
/* -----------------------------------------------------
- * unsigned int plat_is_my_cpu_primary(void);
+ * bool plat_is_my_cpu_primary(void);
*
* This function checks if this is the Primary CPU
+ *
+ * Registers clobbered: x0, x1
* -----------------------------------------------------
*/
func plat_is_my_cpu_primary
mrs x0, mpidr_el1
- and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
- cmp x0, #TEGRA_PRIMARY_CPU
+ adr x1, tegra_primary_cpu_mpid
+ ldr x1, [x1]
+ cmp x0, x1
cset x0, eq
ret
endfunc plat_is_my_cpu_primary
@@ -251,6 +254,14 @@
adr x18, bl31_entrypoint
str x18, [x17]
+ /* -----------------------------------
+ * save the boot CPU MPID value
+ * -----------------------------------
+ */
+ mrs x0, mpidr_el1
+ adr x1, tegra_primary_cpu_mpid
+ str x0, [x1]
+
1: cpu_init_common
ret
@@ -426,3 +437,10 @@
*/
tegra_console_base:
.quad 0
+
+ /* --------------------------------------------------
+ * MPID value for the boot CPU
+ * --------------------------------------------------
+ */
+tegra_primary_cpu_mpid:
+ .quad 0
diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c
index ec34a85..8edb024 100644
--- a/plat/nvidia/tegra/common/tegra_pm.c
+++ b/plat/nvidia/tegra/common/tegra_pm.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
- * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2020-2023, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -92,6 +92,16 @@
/*******************************************************************************
* 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.
+ * Return error if CPU off sequence is not allowed for the current core.
+ ******************************************************************************/
+static int tegra_pwr_domain_off_early(const psci_power_state_t *target_state)
+{
+ return tegra_soc_pwr_domain_off_early(target_state);
+}
+
+/*******************************************************************************
+ * 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.
******************************************************************************/
static void tegra_pwr_domain_off(const psci_power_state_t *target_state)
{
@@ -268,6 +278,7 @@
static plat_psci_ops_t tegra_plat_psci_ops = {
.cpu_standby = tegra_cpu_standby,
.pwr_domain_on = tegra_pwr_domain_on,
+ .pwr_domain_off_early = tegra_pwr_domain_off_early,
.pwr_domain_off = tegra_pwr_domain_off,
.pwr_domain_suspend_pwrdown_early = tegra_pwr_domain_suspend_pwrdown_early,
.pwr_domain_suspend = tegra_pwr_domain_suspend,
diff --git a/plat/nvidia/tegra/include/platform_def.h b/plat/nvidia/tegra/include/platform_def.h
index 84b3297..958a3f9 100644
--- a/plat/nvidia/tegra/include/platform_def.h
+++ b/plat/nvidia/tegra/include/platform_def.h
@@ -41,8 +41,6 @@
#define PLATFORM_STACK_SIZE U(0x400)
#endif
-#define TEGRA_PRIMARY_CPU U(0x0)
-
#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
PLATFORM_MAX_CPUS_PER_CLUSTER)
diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h
index cc2ad86..71bea08 100644
--- a/plat/nvidia/tegra/include/tegra_private.h
+++ b/plat/nvidia/tegra/include/tegra_private.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
- * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2020-2023, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -98,6 +98,9 @@
int32_t tegra_fiq_get_intr_context(void);
void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint);
+/* Declarations for tegra_helpers.S */
+bool plat_is_my_cpu_primary(void);
+
/* Declarations for tegra_security.c */
void tegra_security_setup(void);
void tegra_security_setup_videomem(uintptr_t base, uint64_t size);
@@ -109,6 +112,7 @@
int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state);
int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state);
int32_t tegra_soc_pwr_domain_on(u_register_t mpidr);
+int32_t tegra_soc_pwr_domain_off_early(const psci_power_state_t *target_state);
int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state);
int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state);
int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state);
diff --git a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
index af4182e..8f88e28 100644
--- a/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c
@@ -433,6 +433,16 @@
return PSCI_E_SUCCESS;
}
+int32_t tegra_soc_pwr_domain_off_early(const psci_power_state_t *target_state)
+{
+ /* Do not power off the boot CPU */
+ if (plat_is_my_cpu_primary()) {
+ return PSCI_E_DENIED;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
{
uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK;
diff --git a/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c
index 41a85ee..83d815a 100644
--- a/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t194/plat_psci_handlers.c
@@ -463,6 +463,16 @@
return PSCI_E_SUCCESS;
}
+int32_t tegra_soc_pwr_domain_off_early(const psci_power_state_t *target_state)
+{
+ /* Do not power off the boot CPU */
+ if (plat_is_my_cpu_primary()) {
+ return PSCI_E_DENIED;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
{
uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
diff --git a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
index 7f73ea5..2ec044c 100644
--- a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
@@ -575,6 +575,16 @@
return PSCI_E_SUCCESS;
}
+int32_t tegra_soc_pwr_domain_off_early(const psci_power_state_t *target_state)
+{
+ /* Do not power off the boot CPU */
+ if (plat_is_my_cpu_primary()) {
+ return PSCI_E_DENIED;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
{
tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);