board: emulation: Add QEMU sbsa support

Add support for Arm sbsa [1] v0.3+ that is supported by QEMU [2].

Unlike other Arm based platforms the machine only provides a minimal
FDT that contains number of CPUs, ammount of memory and machine-version.
The boot firmware has to provide ACPI tables to the OS.
Due to this design a full DTB is added here as well that allows U-Boot's
driver to properly function. The DTB is appended at the end of the U-Boot
image and will be merged with the QEMU provided DTB.

In addition provide documentation how to use, enable binman to fabricate both
ROMs that are required to boot and add ACPI tables to make it full compatible
to the EDK2 reference implementation.

The board was tested using Fedora 40 Aarch64 Workstation. It's able
to boot from USB and AHCI or network.

Tested and found working:
- serial
- PCI
- xHCI
- Bochs display
- AHCI
- network using e1000e
- CPU init
- Booting Fedora 40

1: Server Base System Architecture (SBSA)
2: https://www.qemu.org/docs/master/system/arm/sbsa.html

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Cc: Peter Robinson <pbrobinson@gmail.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: Tom Rini <trini@konsulko.com>
diff --git a/board/emulation/qemu-sbsa/smc.c b/board/emulation/qemu-sbsa/smc.c
new file mode 100644
index 0000000..9a2d091
--- /dev/null
+++ b/board/emulation/qemu-sbsa/smc.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2024 9elements GmbH
+ */
+
+#include <cpu.h>
+#include <init.h>
+#include <log.h>
+#include <linux/arm-smccc.h>
+
+#define SMC_SIP_FUNCTION_ID(n)  (0xC2000000 | (n))
+
+#define SIP_SVC_VERSION        SMC_SIP_FUNCTION_ID(1)
+#define SIP_SVC_GET_GIC        SMC_SIP_FUNCTION_ID(100)
+#define SIP_SVC_GET_GIC_ITS    SMC_SIP_FUNCTION_ID(101)
+#define SIP_SVC_GET_CPU_COUNT  SMC_SIP_FUNCTION_ID(200)
+#define SIP_SVC_GET_CPU_NODE   SMC_SIP_FUNCTION_ID(201)
+#define SIP_SVC_GET_MEMORY_NODE_COUNT SMC_SIP_FUNCTION_ID(300)
+#define SIP_SVC_GET_MEMORY_NODE SMC_SIP_FUNCTION_ID(301)
+
+int smc_get_mpidr(unsigned long id, u64 *mpidr)
+{
+	struct arm_smccc_res res;
+
+	res.a0 = ~0;
+	arm_smccc_smc(SIP_SVC_GET_CPU_NODE, id, 0, 0, 0, 0, 0, 0, &res);
+
+	if (!res.a0)
+		*mpidr = res.a2;
+
+	return res.a0;
+}
+
+int smc_get_gic_dist_base(u64 *base)
+{
+	struct arm_smccc_res res;
+
+	res.a0 = ~0;
+	arm_smccc_smc(SIP_SVC_GET_GIC, 0, 0, 0, 0, 0, 0, 0, &res);
+
+	if (!res.a0)
+		*base = res.a1;
+
+	return res.a0;
+}
+
+int smc_get_gic_redist_base(u64 *base)
+{
+	struct arm_smccc_res res;
+
+	res.a0 = ~0;
+	arm_smccc_smc(SIP_SVC_GET_GIC, 0, 0, 0, 0, 0, 0, 0, &res);
+
+	if (!res.a0)
+		*base = res.a2;
+
+	return res.a0;
+}
+
+int smc_get_gic_its_base(u64 *base)
+{
+	struct arm_smccc_res res;
+
+	res.a0 = ~0;
+	arm_smccc_smc(SIP_SVC_GET_GIC_ITS, 0, 0, 0, 0, 0, 0, 0, &res);
+
+	if (!res.a0)
+		*base = res.a1;
+
+	return res.a0;
+}