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/arch/arm/Kconfig b/arch/arm/Kconfig
index 263f85b..0d0c731 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1054,7 +1054,7 @@
 	imply DM_RNG
 	imply DM_RTC
 	imply RTC_PL031
-	imply OF_HAS_PRIOR_STAGE
+	imply OF_HAS_PRIOR_STAGE if !TARGET_QEMU_ARM_SBSA
 	imply VIDEO
 	imply VIDEO_BOCHS
 	imply SYS_WHITE_ON_BLACK
@@ -2381,6 +2381,7 @@
 source "board/cavium/thunderx/Kconfig"
 source "board/eets/pdu001/Kconfig"
 source "board/emulation/qemu-arm/Kconfig"
+source "board/emulation/qemu-sbsa/Kconfig"
 source "board/freescale/ls2080aqds/Kconfig"
 source "board/freescale/ls2080ardb/Kconfig"
 source "board/freescale/ls1088a/Kconfig"
diff --git a/arch/arm/dts/qemu-sbsa.dts b/arch/arm/dts/qemu-sbsa.dts
new file mode 100644
index 0000000..ed00e50
--- /dev/null
+++ b/arch/arm/dts/qemu-sbsa.dts
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Devicetree with onboard devices for qemu_sbsa-ref for internal use only!
+ * DO NOT PASS TO THE OS!
+ *
+ * As QEMU provides only a minimal devicetree this one is merged with
+ * it and then fixed at runtime.
+ *
+ * Copyright 2024 9elements GmbH
+ */
+#include "configs/qemu-sbsa.h"
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/dts-v1/;
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <2>;
+	interrupt-parent = <&intc>;
+	compatible = "linux,sbsa-ref";
+
+	binman: binman {
+		multiple-images;
+	};
+
+	cpus {
+		/* Filled by fdtdec_board_setup() */
+	};
+
+	memory {
+		/* Filled by fdtdec_board_setup() */
+	};
+
+	soc {
+		compatible = "simple-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		cfi_flash {
+			compatible = "cfi-flash";
+			reg = /bits/ 64 <SBSA_FLASH_BASE_ADDR
+					 SBSA_FLASH_LENGTH>;
+			status = "okay";
+		};
+
+		uart0 {
+			compatible = "arm,pl011";
+			status = "okay";
+			reg = /bits/ 64 <SBSA_UART_BASE_ADDR
+					 SBSA_UART_LENGTH>;
+		};
+
+		ahci {
+			compatible = "generic-ahci";
+			status = "okay";
+			reg = /bits/ 64 <0x60100000 0x00010000>;
+		};
+
+		xhci {
+			compatible = "generic-xhci";
+			status = "okay";
+			reg = /bits/ 64 <0x60110000 0x00010000>;
+		};
+
+		pci {
+			#address-cells = <3>;
+			#size-cells = <2>;
+			compatible = "pci-host-ecam-generic";
+			device_type = "pci";
+			status = "okay";
+			reg = /bits/ 64 <0xf0000000 0x10000000>;
+			bus-range = <0 0xff>;
+			ranges = /bits/ 32 <0x01000000>,
+				 /bits/ 64 <0
+					    SBSA_PIO_BASE_ADDR
+					    SBSA_PIO_LENGTH>,
+				 /bits/ 32 <0x02000000>,
+				 /bits/ 64 <SBSA_PCIE_MMIO_BASE_ADDR
+					    SBSA_PCIE_MMIO_BASE_ADDR
+					    SBSA_PCIE_MMIO_LENGTH>,
+				 /bits/ 32 <0x43000000>,
+				 /bits/ 64 <SBSA_PCIE_MMIO_HIGH_BASE_ADDR
+					    SBSA_PCIE_MMIO_HIGH_BASE_ADDR
+					    SBSA_PCIE_MMIO_HIGH_LENGTH>;
+		};
+	};
+
+	intc: interrupt-controller {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		status = "okay";
+		interrupt-controller;
+		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+		reg = /bits/ 64 <SBSA_GIC_DIST_BASE_ADDR SBSA_GIC_DIST_LENGTH>,
+		      /bits/ 64 <SBSA_GIC_REDIST_BASE_ADDR SBSA_GIC_REDIST_LENGTH>,
+		      /bits/ 64 <0 0>,
+		      /bits/ 64 <SBSA_GIC_HBASE_ADDR SBSA_GIC_HBASE_LENGTH>,
+		      /bits/ 64 <SBSA_GIC_VBASE_ADDR SBSA_GIC_VBASE_LENGTH>;
+	};
+
+	its {
+		compatible = "arm,gic-v3-its";
+		status = "disabled";
+	};
+};
+
+&binman {
+	secure-world {
+		filename = "secure-world.rom";
+		size = <SBSA_SECURE_FLASH_LENGTH>;
+
+		bl1 {
+			offset = <0x0>;
+			description = "ARM Trusted Firmware BL1";
+			filename = "bl1.bin";
+			type = "blob-ext";
+		};
+
+		fip {
+			offset = <0x12000>;
+			description = "ARM Trusted Firmware FIP";
+			filename = "fip.bin";
+			type = "blob-ext";
+		};
+	};
+
+	unsecure-world {
+		filename = "unsecure-world.rom";
+		size = <SBSA_FLASH_LENGTH>;
+
+		u-boot {
+		};
+		u-boot-dtb {
+			compress = "lz4";
+		};
+	};
+};
diff --git a/arch/arm/include/asm/arch-qemu-sbsa/boot0.h b/arch/arm/include/asm/arch-qemu-sbsa/boot0.h
new file mode 100644
index 0000000..4a1a254
--- /dev/null
+++ b/arch/arm/include/asm/arch-qemu-sbsa/boot0.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * sbsa-ref starts U-Boot in XIP memory. Need to relocate U-Boot
+ * to DRAM which is already up. Instead of using SPL this simple loader
+ * is being used.
+ */
+relocate_check:
+	/* x0 contains the pointer to FDT provided by ATF */
+	adr	x1, _start		/* x1 <- Runtime value of _start */
+	ldr	x2, _TEXT_BASE		/* x2 <- Linked value of _start */
+	subs	x9, x1, x2		/* x9 <- Run-vs-link offset */
+	beq	reset
+
+	adrp	x1, __image_copy_start		/* x2 <- address bits [31:12] */
+	add	x1, x1, :lo12:__image_copy_start/* x2 <- address bits [11:00] */
+	adrp	x3, __image_copy_end		/* x3 <- address bits [31:12] */
+	add	x3, x3, :lo12:__image_copy_end	/* x3 <- address bits [11:00] */
+	add	x3, x3, #0x100000		/* 1 MiB for the DTB found at _end */
+
+copy_loop:
+	ldp	x10, x11, [x1], #16	/* copy from source address [x1] */
+	stp	x10, x11, [x2], #16	/* copy to   target address [x2] */
+	cmp	x1, x3			/* until source end address [x3] */
+	b.lo	copy_loop
+
+	isb
+	ldr	x2, _TEXT_BASE		/* x2 <- Linked value of _start */
+	br	x2			/* Jump to linked address */
+	/* Never reaches this point */
+1:
+	wfi
+	b 1b
+
+relocate_done:
\ No newline at end of file
diff --git a/arch/arm/mach-qemu/Kconfig b/arch/arm/mach-qemu/Kconfig
index 186c358..9c06c6a 100644
--- a/arch/arm/mach-qemu/Kconfig
+++ b/arch/arm/mach-qemu/Kconfig
@@ -3,12 +3,6 @@
 config SYS_VENDOR
 	default "emulation"
 
-config SYS_BOARD
-	default "qemu-arm"
-
-config SYS_CONFIG_NAME
-	default "qemu-arm"
-
 choice
 	prompt "QEMU ARM architecture"
 	default TARGET_QEMU_ARM_64BIT
@@ -25,6 +19,36 @@
 	select ARM64
 	select BOARD_LATE_INIT
 
+config TARGET_QEMU_ARM_SBSA
+	bool "SBSA Reference"
+	select ARM64
+	select BINMAN
+	select BOARD_LATE_INIT
+	select ENABLE_ARM_SOC_BOOT0_HOOK
+	select MISC_INIT_R
 endchoice
 
+if TARGET_QEMU_ARM_32BIT || TARGET_QEMU_ARM_64BIT
+
+config SYS_BOARD
+	default "qemu-arm"
+
+config SYS_CONFIG_NAME
+	default "qemu-arm"
+
+endif
+
+if TARGET_QEMU_ARM_SBSA
+
+config SYS_BOARD
+	default "qemu-sbsa"
+
+config SYS_CONFIG_NAME
+	default "qemu-sbsa"
+
+config SYS_SOC
+	default "qemu-sbsa"
+
+endif
+
 endif