feat(common): add support for kernel DT handoff convention

TF-A currently supports multiple DT handoff conventions:

1. Firmware Handoff (FH): DT passed in x0, with x1–x3 carrying
   additional data.
2. Kernel-compatible handoff (ARM_LINUX_KERNEL_AS_BL33): DT passed in
   x0, x1–x3 zeroed.
3. Legacy TF-A convention: DT passed in x1, with x0 used for MPIDR or
   NT_FW_CONFIG.

After discussions with folks in EDK2 and U-Boot, it's clear that there
is no strict requirement for placing the DT in x1. Both projects support
x0 for Arm platforms. To standardize behavior and support firmware
handoff migration, this patch introduces USE_KERNEL_DT_CONVENTION as a
configurable build flag. When enabled, the DT will be passed in x0 for
BL33.

This aligns TF-A’s behavior with Linux boot expectations and simplifies
integration across bootloaders.

Change-Id: I6bd7154fe07cb2e16e25c058f7cf862f9ae007e7
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
diff --git a/Makefile b/Makefile
index b147b03..a6c6784 100644
--- a/Makefile
+++ b/Makefile
@@ -627,6 +627,7 @@
 	TRUSTED_BOARD_BOOT \
 	USE_COHERENT_MEM \
 	USE_DEBUGFS \
+	USE_KERNEL_DT_CONVENTION \
 	ARM_IO_IN_DTB \
 	SDEI_IN_FCONF \
 	SEC_INT_DESC_IN_FCONF \
@@ -830,6 +831,7 @@
 	SEC_INT_DESC_IN_FCONF \
 	USE_ROMLIB \
 	USE_TBBR_DEFS \
+	USE_KERNEL_DT_CONVENTION \
 	WARMBOOT_ENABLE_DCACHE_EARLY \
 	RESET_TO_BL2 \
 	BL2_RUNS_AT_EL3	\
diff --git a/common/desc_image_load.c b/common/desc_image_load.c
index 30b97e0..0626de9 100644
--- a/common/desc_image_load.c
+++ b/common/desc_image_load.c
@@ -1,11 +1,13 @@
 /*
- * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2025, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <assert.h>
 
+#include <plat/common/platform.h>
+
 #include <arch_helpers.h>
 #include <common/bl_common.h>
 #include <common/desc_image_load.h>
@@ -212,6 +214,12 @@
  ******************************************************************************/
 void populate_next_bl_params_config(bl_params_t *bl2_to_next_bl_params)
 {
+	/*
+	 * With Firmware Handoff configuration data is shared dynamically, most of
+	 * the *_CONFIG files will be deprecated. Avoid populating the entry point
+	 * arguments with their information as they're discarded anyway.
+	 */
+#if !TRANSFER_LIST
 	bl_params_node_t *params_node;
 	unsigned int fw_config_id;
 	uintptr_t fw_config_base;
@@ -276,8 +284,9 @@
 		 */
 		if (params_node->image_id == BL32_IMAGE_ID) {
 			params_node->ep_info->args.arg3 = fw_config_base;
-		} else {
+		} else
 #endif
+		{
 			/*
 			 * Pass hw and tb_fw config addresses to next images.
 			 * NOTE - for EL3 runtime images (BL31 for AArch64
@@ -292,18 +301,30 @@
 				if (params_node->ep_info->args.arg2 == 0U)
 					params_node->ep_info->args.arg2 =
 								hw_config_base;
-			} else {
-				if (params_node->ep_info->args.arg0 == 0U)
-					params_node->ep_info->args.arg0 =
-								fw_config_base;
-				if (params_node->ep_info->args.arg1 == 0U)
-					params_node->ep_info->args.arg1 =
-								hw_config_base;
 			}
-#ifdef SPD_opteed
+#if USE_KERNEL_DT_CONVENTION
+			else if (params_node->image_id == BL33_IMAGE_ID) {
+				hw_config_base = plat_get_hw_dt_base();
+
+				if (params_node->ep_info->args.arg0 == 0U) {
+					params_node->ep_info->args.arg0 =
+						hw_config_base;
+				}
+			}
+#endif /* USE_KERNEL_DT_CONVENTION */
+			else {
+				if (params_node->ep_info->args.arg0 == 0U) {
+					params_node->ep_info->args.arg0 =
+						fw_config_base;
+				}
+				if (params_node->ep_info->args.arg1 == 0U) {
+					params_node->ep_info->args.arg1 =
+						hw_config_base;
+				}
+			}
 		}
-#endif
 	}
+#endif /* !TRANSFER_LIST */
 }
 
 /*******************************************************************************
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index e2fba99..6d3fea1 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -1130,6 +1130,14 @@
    (Coherent memory region is included) or 0 (Coherent memory region is
    excluded). Default is 1.
 
+-  ``USE_KERNEL_DT_CONVENTION``: When this option is enabled, the hardware
+   device tree is passed to BL33 using register x0, aligning with the expectations
+   of the Linux kernel on Arm platforms. If this option is disabled, a different
+   register, typically x1, may be used instead. This build option is
+   not necessary when firmware handoff is active (that is, when TRANSFER_LIST=1
+   is set), and it will be removed once all platforms have transitioned to that
+   convention.
+
 -  ``USE_DSU_DRIVER``: This flag enables DSU (DynamIQ Shared Unit) driver.
    The DSU driver allows save/restore of DSU PMU registers through
    ``PRESERVE_DSU_PMU_REGS`` build option and allows platforms to
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index d7c5ed9..8dc0123 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -505,6 +505,12 @@
  */
 int32_t plat_is_smccc_feature_available(u_register_t fid);
 
+/*
+ * Optional function to retrieve the base address of hardware DT from the
+ * platform.
+ */
+uintptr_t plat_get_hw_dt_base(void);
+
 /*******************************************************************************
  * FWU platform specific functions
  ******************************************************************************/
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 1ddcd6f..e8d25f8 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -296,6 +296,10 @@
 # Build option to add debugfs support
 USE_DEBUGFS			:= 0
 
+# Build option to enable passing the FDT in x0 to BL33, following the kernel
+# convention.
+USE_KERNEL_DT_CONVENTION	:= 0
+
 # Build option to fconf based io
 ARM_IO_IN_DTB			:= 0