feat(amd): populate handoff from TL

Handoff structures are populated by executable entry point
information tag based bl32/bl33 entries present in transfer list.

The upstream code is having problem with the last TL entry
particularly when the tags for two entries are same.
While tlc tool dumps all entries correctly, transfer_list_dump() in
upstream code does not provide information about the last entry in TL.

Enabling TRANSFER_LIST also enables BL1_SOURCES and BL2_SOURCES in
transfer_list.mk thereby enabling bl1/bl2 builds.
bl1/bl2 builds are disabled by turning off NEED_BL1/NEED_BL2
build flags.

Change-Id: I55ddccc1ab266cc5a609423d304a5e5c282e17f6
Signed-off-by: Amit Nagal <amit.nagal@amd.com>
diff --git a/plat/amd/versal2/bl31_setup.c b/plat/amd/versal2/bl31_setup.c
index d00e50d..64c356a 100644
--- a/plat/amd/versal2/bl31_setup.c
+++ b/plat/amd/versal2/bl31_setup.c
@@ -27,6 +27,7 @@
 #include <plat_fdt.h>
 #include <plat_private.h>
 #include <plat_startup.h>
+#include <plat_xfer_list.h>
 #include <pm_api_sys.h>
 #include <pm_client.h>
 
@@ -80,6 +81,7 @@
 	(void)arg2;
 	(void)arg3;
 	uint32_t uart_clock;
+	int32_t rc;
 
 	board_detection();
 
@@ -145,7 +147,12 @@
 	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
 	SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
 	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
-	bl31_set_default_config();
+
+	rc = transfer_list_populate_ep_info(&bl32_image_ep_info, &bl33_image_ep_info);
+	if (rc == TL_OPS_NON || rc == TL_OPS_CUS) {
+		NOTICE("BL31: TL not found, using default config\n");
+		bl31_set_default_config();
+	}
 
 	long rev_var = cpu_get_rev_var();
 
diff --git a/plat/amd/versal2/platform.mk b/plat/amd/versal2/platform.mk
index 0827e18..3114976 100644
--- a/plat/amd/versal2/platform.mk
+++ b/plat/amd/versal2/platform.mk
@@ -6,6 +6,9 @@
 
 PLAT_PATH := plat/amd/versal2
 
+override NEED_BL1 := no
+override NEED_BL2 := no
+
 # A78 Erratum for SoC
 ERRATA_A78_AE_1941500 := 1
 ERRATA_A78_AE_1951502 := 1
@@ -148,3 +151,9 @@
 CORTEX_A78_AE_H_INC     := 1
 $(eval $(call add_define, CORTEX_A78_AE_H_INC))
 endif
+
+# Enable Handoff protocol using transfer lists
+TRANSFER_LIST                   := 1
+
+include lib/transfer_list/transfer_list.mk
+BL31_SOURCES           +=      plat/xilinx/common/plat_xfer_list.c
diff --git a/plat/xilinx/common/include/plat_xfer_list.h b/plat/xilinx/common/include/plat_xfer_list.h
new file mode 100644
index 0000000..cc79a2c
--- /dev/null
+++ b/plat/xilinx/common/include/plat_xfer_list.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_XFER_LIST_H
+#define PLAT_XFER_LIST_H
+
+#include <lib/transfer_list.h>
+
+int32_t transfer_list_populate_ep_info(entry_point_info_t *bl32,
+				       entry_point_info_t *bl33);
+
+#endif /* PLAT_XFER_LIST_H */
diff --git a/plat/xilinx/common/plat_xfer_list.c b/plat/xilinx/common/plat_xfer_list.c
new file mode 100644
index 0000000..eae7ce4
--- /dev/null
+++ b/plat/xilinx/common/plat_xfer_list.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stddef.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/transfer_list.h>
+
+/*
+ * FIXME: This address should come from firmware before TF-A runs
+ * Having this to make sure the transfer list functionality works
+ */
+#define FW_HANDOFF_BASE		U(0x1200000)
+#define FW_HANDOFF_SIZE		U(0x600000)
+
+static struct transfer_list_header *tl_hdr;
+
+int32_t transfer_list_populate_ep_info(entry_point_info_t *bl32,
+				       entry_point_info_t *bl33)
+{
+	struct transfer_list_entry *te = NULL;
+	struct entry_point_info *ep;
+	int32_t ret;
+
+	tl_hdr = (struct transfer_list_header *)FW_HANDOFF_BASE;
+	ret = transfer_list_check_header(tl_hdr);
+	if ((ret == TL_OPS_ALL) || (ret == TL_OPS_RO)) {
+		transfer_list_dump(tl_hdr);
+		while ((te = transfer_list_next(tl_hdr, te)) != NULL) {
+			ep = transfer_list_entry_data(te);
+			if (te->tag_id == TL_TAG_EXEC_EP_INFO64) {
+				switch (GET_SECURITY_STATE(ep->h.attr)) {
+				case NON_SECURE:
+					*bl33 = *ep;
+					continue;
+				case SECURE:
+					*bl32 = *ep;
+					continue;
+				default:
+					ERROR("Unrecognized Image Security State %lu\n",
+					      GET_SECURITY_STATE(ep->h.attr));
+					ret = TL_OPS_NON;
+				}
+			}
+		}
+	}
+	return ret;
+}