[PATCH v8 25/37] board: emulation: Add QEMU sbsa support

Moritz Fischer moritzf at google.com
Tue Oct 15 11:11:54 CEST 2024


Hi Patrick,

On Mon, Oct 14, 2024 at 6:17 AM Patrick Rudolph
<patrick.rudolph at 9elements.com> wrote:
>
> 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 at 9elements.com>
> Cc: Peter Robinson <pbrobinson at gmail.com>
> Cc: Simon Glass <sjg at chromium.org>
> Cc: Tom Rini <trini at konsulko.com>
> ---
> Changelog v3:
> - Add GIC and GIC-ITS to devicetree
> - Select GICv3 driver
> - Drop acpi_fill_madt and use driver model instead
> Changelog v4:
> - Drop CPU platform code
> - Enhance the DT to allow MADT generation from DT
> Changelog v5:
> - Add full DT and place it at the end of U-Boot
> - Merge DT with QEMU's DT
> - Drop DT generation code
> - Fix flash region length
> - Drop enable_caches()
> - Support platforms that do not pass FDT in x0
> Changelog v6:
> - Update header order
> - Drop pad-byte from DT
> - select BINMAN_FDT
> - select E1000_NO_NVM
> - drop config.h include
> - drop a few CFG_ defines that were used for SPL
> Changelog v8:
> - Use /bits/ 64 in DT
> - Drop flash access helper functions
> - Add cfi-flash to DT
> - Mark secure-flash as no execute
> - Only use defines in DT when it's also used in other files
> ---
>  arch/arm/Kconfig                            |   3 +-
>  arch/arm/dts/qemu-sbsa.dts                  | 137 ++++++
>  arch/arm/include/asm/arch-qemu-sbsa/boot0.h |  34 ++
>  arch/arm/mach-qemu/Kconfig                  |  36 +-
>  board/emulation/qemu-arm/MAINTAINERS        |   2 +
>  board/emulation/qemu-sbsa/Kconfig           |  58 +++
>  board/emulation/qemu-sbsa/Makefile          |   8 +
>  board/emulation/qemu-sbsa/acpi.c            | 192 ++++++++
>  board/emulation/qemu-sbsa/dsdt.asl          | 483 ++++++++++++++++++++
>  board/emulation/qemu-sbsa/lowlevel_init.S   |  22 +
>  board/emulation/qemu-sbsa/qemu-sbsa.c       | 273 +++++++++++
>  board/emulation/qemu-sbsa/qemu-sbsa.env     |  14 +
>  board/emulation/qemu-sbsa/qemu-sbsa.h       |  38 ++
>  board/emulation/qemu-sbsa/smc.c             |  71 +++
>  configs/qemu-arm-sbsa_defconfig             |  10 +
>  doc/board/emulation/index.rst               |   1 +
>  doc/board/emulation/qemu-sbsa.rst           |  98 ++++
>  doc/develop/driver-model/virtio.rst         |   1 +
>  include/configs/qemu-sbsa.h                 |  89 ++++
>  19 files changed, 1563 insertions(+), 7 deletions(-)
>  create mode 100644 arch/arm/dts/qemu-sbsa.dts
>  create mode 100644 arch/arm/include/asm/arch-qemu-sbsa/boot0.h
>  create mode 100644 board/emulation/qemu-sbsa/Kconfig
>  create mode 100644 board/emulation/qemu-sbsa/Makefile
>  create mode 100644 board/emulation/qemu-sbsa/acpi.c
>  create mode 100644 board/emulation/qemu-sbsa/dsdt.asl
>  create mode 100644 board/emulation/qemu-sbsa/lowlevel_init.S
>  create mode 100644 board/emulation/qemu-sbsa/qemu-sbsa.c
>  create mode 100644 board/emulation/qemu-sbsa/qemu-sbsa.env
>  create mode 100644 board/emulation/qemu-sbsa/qemu-sbsa.h
>  create mode 100644 board/emulation/qemu-sbsa/smc.c
>  create mode 100644 configs/qemu-arm-sbsa_defconfig
>  create mode 100644 doc/board/emulation/qemu-sbsa.rst
>  create mode 100644 include/configs/qemu-sbsa.h
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 263f85b0d0..0d0c731dd0 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1054,7 +1054,7 @@ config ARCH_QEMU
>         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/broadcom/bcmns3/Kconfig"
>  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 0000000000..d6f8a3ac58
> --- /dev/null
> +++ b/arch/arm/dts/qemu-sbsa.dts
> @@ -0,0 +1,137 @@
> +// 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"
> +
> +/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 = <1>;
> +               status = "okay";
> +               interrupt-controller;
> +               interrupts = <25>;
> +               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";
> +       };

I think usually its nodes are subnodes of the intc / gic node. See
examples here:
https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/arm%2Cgic-v3.txt

> +};
> +
> +&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 0000000000..4a1a254b92
> --- /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 186c3582eb..9c06c6a3a5 100644
> --- a/arch/arm/mach-qemu/Kconfig
> +++ b/arch/arm/mach-qemu/Kconfig
> @@ -3,12 +3,6 @@ if ARCH_QEMU
>  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 @@ config TARGET_QEMU_ARM_64BIT
>         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
> diff --git a/board/emulation/qemu-arm/MAINTAINERS b/board/emulation/qemu-arm/MAINTAINERS
> index 5154262f29..7bc0ee698c 100644
> --- a/board/emulation/qemu-arm/MAINTAINERS
> +++ b/board/emulation/qemu-arm/MAINTAINERS
> @@ -4,5 +4,7 @@ S:      Maintained
>  F:     board/emulation/qemu-arm/
>  F:     board/emulation/common/
>  F:     include/configs/qemu-arm.h
> +F:     include/configs/qemu-sbsa.h
>  F:     configs/qemu_arm_defconfig
>  F:     configs/qemu_arm64_defconfig
> +F:     configs/qemu-arm-sbsa_defconfig
> diff --git a/board/emulation/qemu-sbsa/Kconfig b/board/emulation/qemu-sbsa/Kconfig
> new file mode 100644
> index 0000000000..e8de29306c
> --- /dev/null
> +++ b/board/emulation/qemu-sbsa/Kconfig
> @@ -0,0 +1,58 @@
> +if TARGET_QEMU_ARM_SBSA
> +
> +config SYS_SOC
> +       default "qemu-sbsa"
> +
> +config TEXT_BASE
> +       default 0x10000100000
> +
> +config SYS_LOAD_ADDR
> +       default 0x10000100000
> +
> +config PRE_CON_BUF_ADDR
> +       default 0x100000FF000
> +
> +config DEFAULT_DEVICE_TREE
> +       default "qemu-sbsa"
> +
> +config BOARD_SPECIFIC_OPTIONS # dummy
> +       def_bool y
> +       select AHCI
> +       select ACPIGEN
> +       select ACPI
> +       select CPU
> +       select CPU_ARMV8
> +       select DM
> +       select DM_USB
> +       select DM_MTD
> +       select GENERATE_ACPI_TABLE
> +       select HAS_ROM
> +       select MTD
> +       select OF_LIBFDT_OVERLAY
> +       select OF_SEPARATE
> +       select PCI
> +       select PCIE_ECAM_GENERIC
> +       select USB
> +       select GIC_V3
> +       select GIC_V3_ITS
> +       select SYS_FLASH_CFI_WIDTH_16BIT
> +       imply AHCI_GENERIC
> +       imply USB_XHCI_HCD
> +       imply USB_XHCI_GENERIC
> +       imply USB_STORAGE
> +       imply E1000
> +       imply E1000_NO_NVM
> +       imply NET_RANDOM_ETHADDR
> +       imply VIDEO_BOCHS
> +       imply CFI_FLASH
> +       imply SYS_MTDPARTS_RUNTIME
> +       imply SET_DFU_ALT_INFO
> +
> +if DEBUG_UART
> +
> +config DEBUG_UART_BASE
> +       default 0x60000000
> +endif
> +
> +source "board/emulation/common/Kconfig"
> +endif
> diff --git a/board/emulation/qemu-sbsa/Makefile b/board/emulation/qemu-sbsa/Makefile
> new file mode 100644
> index 0000000000..bacae320e7
> --- /dev/null
> +++ b/board/emulation/qemu-sbsa/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +
> +obj-y  += qemu-sbsa.o
> +obj-y  += lowlevel_init.o
> +obj-y  += smc.o
> +
> +obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt_generated.o
> +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o
> diff --git a/board/emulation/qemu-sbsa/acpi.c b/board/emulation/qemu-sbsa/acpi.c
> new file mode 100644
> index 0000000000..ba85e08fc7
> --- /dev/null
> +++ b/board/emulation/qemu-sbsa/acpi.c
> @@ -0,0 +1,192 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2024 9elements GmbH
> + */
> +
> +#include <cpu.h>
> +#include <tables_csum.h>
> +#include <string.h>
> +#include <acpi/acpi_table.h>
> +#include <asm/acpi_table.h>
> +#include <asm/armv8/sec_firmware.h>
> +#include <configs/qemu-sbsa.h>
> +#include <dm/uclass.h>
> +#include <dm/device.h>
> +#include "qemu-sbsa.h"
> +
> +#define SBSAQEMU_MADT_GIC_VBASE          0x2c020000
> +#define SBSAQEMU_MADT_GIC_HBASE          0x2c010000
> +#define SBSAQEMU_MADT_GIC_PMU_IRQ        23
> +
> +#define SBSA_PLATFORM_WATCHDOG_COUNT    1
> +#define SBSA_PLATFORM_TIMER_COUNT       (SBSA_PLATFORM_WATCHDOG_COUNT)
> +
> +#define L2_ATTRIBUTES (ACPI_PPTT_READ_ALLOC | ACPI_PPTT_WRITE_ALLOC | \
> +                       (ACPI_PPTT_CACHE_TYPE_UNIFIED << \
> +                        ACPI_PPTT_CACHE_TYPE_SHIFT))
> +#define L2_SIZE 0x80000
> +#define L2_SETS 0x400
> +#define L2_WAYS 8
> +
> +#define L1D_ATTRIBUTES (ACPI_PPTT_READ_ALLOC | ACPI_PPTT_WRITE_ALLOC | \
> +                       (ACPI_PPTT_CACHE_TYPE_DATA << \
> +                        ACPI_PPTT_CACHE_TYPE_SHIFT))
> +#define L1D_SIZE 0x8000
> +#define L1D_SETS 0x100
> +#define L1D_WAYS 2
> +
> +#define L1I_ATTRIBUTES (ACPI_PPTT_READ_ALLOC | \
> +                       (ACPI_PPTT_CACHE_TYPE_INSTR << \
> +                        ACPI_PPTT_CACHE_TYPE_SHIFT))
> +#define L1I_SIZE 0x8000
> +#define L1I_SETS 0x100
> +#define L1I_WAYS 2
> +
> +int acpi_fill_iort(struct acpi_ctx *ctx)
> +{
> +       u32 its_offset, smmu_offset;
> +       u64 gic_its_base = 0;
> +
> +       smc_get_gic_its_base(&gic_its_base);
> +       if (gic_its_base == 0)
> +               return 0;
> +
> +       u32 identifiers[] = { 0 };
> +
> +       its_offset = acpi_iort_add_its_group(ctx, ARRAY_SIZE(identifiers),
> +                                            identifiers);
> +
> +       struct acpi_iort_id_mapping map_smmu[] = {{
> +               0, 0xffff, 0, its_offset, 0
> +       }};
> +
> +       smmu_offset = acpi_iort_add_smmu_v3(ctx,
> +                                           SBSA_SMMU_BASE_ADDR, // Base address
> +                                           ACPI_IORT_SMMU_V3_COHACC_OVERRIDE, // Flags
> +                                           0,  // VATOS address
> +                                           0,  // SMMUv3 Model
> +                                           74, // Event
> +                                           75, // Pri
> +                                           77, // Gerror
> +                                           76, // Sync
> +                                           0,  // Proximity domain
> +                                           1,  // DevIDMappingIndex
> +                                           ARRAY_SIZE(map_smmu),
> +                                           map_smmu);
> +
> +       struct acpi_iort_id_mapping map_rc[] = {{
> +               0, 0xffff, 0, smmu_offset, 0
> +       }};
> +
> +       acpi_iort_add_rc(ctx,
> +                        BIT(0) | BIT(56),  // CacheCoherent + CPM
> +                        0,  // AtsAttribute
> +                        0,  // PciSegmentNumber
> +                        64, // MemoryAddressSizeLimit
> +                        ARRAY_SIZE(map_rc),
> +                        map_rc);
> +       return 0;
> +}
> +
> +void acpi_fill_fadt(struct acpi_fadt *fadt)
> +{
> +       fadt->flags = ACPI_FADT_HW_REDUCED_ACPI | ACPI_FADT_LOW_PWR_IDLE_S0;
> +       fadt->preferred_pm_profile = ACPI_PM_PERFORMANCE_SERVER;
> +       fadt->arm_boot_arch = ACPI_ARM_PSCI_COMPLIANT;
> +}
> +
> +int acpi_fill_mcfg(struct acpi_ctx *ctx)
> +{
> +       size_t size;
> +
> +       /* PCI Segment Group 0, Start Bus Number 0, End Bus Number is 255 */
> +       size = acpi_create_mcfg_mmconfig((void *)ctx->current,
> +                                        SBSA_PCIE_ECAM_BASE_ADDR, 0, 0, 255);
> +       acpi_inc(ctx, size);
> +
> +       return 0;
> +}
> +
> +static int sbsa_write_gtdt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
> +{
> +       struct acpi_table_header *header;
> +       struct acpi_gtdt *gtdt;
> +
> +       gtdt = ctx->current;
> +       header = &gtdt->header;
> +
> +       memset(gtdt, '\0', sizeof(struct acpi_gtdt));
> +
> +       acpi_fill_header(header, "GTDT");
> +       header->length = sizeof(struct acpi_gtdt);
> +       header->revision = acpi_get_table_revision(ACPITAB_GTDT);
> +
> +       gtdt->cnt_ctrl_base = 0xFFFFFFFFFFFFFFFF;
> +       gtdt->sec_el1_gsiv = 29;
> +       gtdt->sec_el1_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> +       gtdt->el1_gsiv = 30;
> +       gtdt->el1_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> +       gtdt->virt_el1_gsiv = 27;
> +       gtdt->virt_el1_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> +       gtdt->el2_gsiv = 26;
> +       gtdt->el2_flags = GTDT_FLAG_INT_ACTIVE_LOW;
> +       gtdt->cnt_read_base = 0xffffffffffffffff;
> +
> +       // FIXME: VirtualPL2Timer
> +       header->checksum = table_compute_checksum(header, header->length);
> +
> +       acpi_add_table(ctx, gtdt);
> +
> +       acpi_inc(ctx, sizeof(struct acpi_gtdt));
> +
> +       return 0;
> +};
> +
> +ACPI_WRITER(5gtdt, "GTDT", sbsa_write_gtdt, 0);
> +
> +static int acpi_write_pptt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
> +{
> +       struct acpi_table_header *header;
> +       int cluster_offset, l2_offset;
> +       u32 offsets[2];
> +
> +       header = ctx->current;
> +       ctx->tab_start = ctx->current;
> +
> +       memset(header, '\0', sizeof(struct acpi_table_header));
> +
> +       acpi_fill_header(header, "PPTT");
> +       header->revision = acpi_get_table_revision(ACPITAB_PPTT);
> +       acpi_inc(ctx, sizeof(*header));
> +
> +       cluster_offset = acpi_pptt_add_proc(ctx, ACPI_PPTT_PHYSICAL_PACKAGE |
> +                                           ACPI_PPTT_CHILDREN_IDENTICAL,
> +                                           0, 0, 0, NULL);
> +
> +       l2_offset = acpi_pptt_add_cache(ctx, ACPI_PPTT_ALL_VALID, 0, L2_SIZE,
> +                                       L2_SETS, L2_WAYS, L2_ATTRIBUTES, 64);
> +
> +       offsets[0] = acpi_pptt_add_cache(ctx, ACPI_PPTT_ALL_VALID, l2_offset,
> +                                        L1D_SIZE, L1D_SETS, L1D_WAYS,
> +                                        L1D_ATTRIBUTES, 64);
> +
> +       offsets[1] = acpi_pptt_add_cache(ctx, ACPI_PPTT_ALL_BUT_WRITE_POL,
> +                                        l2_offset, L1I_SIZE, L1I_SETS,
> +                                        L1I_WAYS, L1I_ATTRIBUTES, 64);
> +
> +       for (int i = 0; i < uclass_id_count(UCLASS_CPU); i++) {
> +               acpi_pptt_add_proc(ctx, ACPI_PPTT_CHILDREN_IDENTICAL |
> +                                  ACPI_PPTT_NODE_IS_LEAF | ACPI_PPTT_PROC_ID_VALID,
> +                                  cluster_offset, i, 2, offsets);
> +       }
> +
> +       header->length = ctx->current - ctx->tab_start;
> +       header->checksum = table_compute_checksum(header, header->length);
> +
> +       acpi_inc(ctx, header->length);
> +       acpi_add_table(ctx, header);
> +
> +       return 0;
> +};
> +
> +ACPI_WRITER(5pptt, "PPTT", acpi_write_pptt, 0);
> diff --git a/board/emulation/qemu-sbsa/dsdt.asl b/board/emulation/qemu-sbsa/dsdt.asl
> new file mode 100644
> index 0000000000..f12cca04e2
> --- /dev/null
> +++ b/board/emulation/qemu-sbsa/dsdt.asl
> @@ -0,0 +1,483 @@
> +/** @file
> +*  Differentiated System Description Table Fields (DSDT).
> +*
> +*  Copyright (c) 2020, Linaro Ltd. All rights reserved.
> +*
> +*  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#include <configs/qemu-sbsa.h>
> +
> +#define LINK_DEVICE(Uid, LinkName, Irq)                                        \
> +        Device (LinkName) {                                                    \
> +            Name (_HID, EISAID("PNP0C0F"))                                     \
> +            Name (_UID, Uid)                                                   \
> +            Name (_PRS, ResourceTemplate() {                                   \
> +                Interrupt (ResourceProducer, Level, ActiveHigh, Exclusive) { Irq } \
> +            })                                                                 \
> +            Method (_STA) {                                                    \
> +              Return (0xF)                                                     \
> +            }                                                                  \
> +            Method (_CRS, 0) { Return (_PRS) }                                 \
> +            Method (_SRS, 1) { }                                               \
> +            Method (_DIS) { }                                                  \
> +        }
> +
> +#define PRT_ENTRY(Address, Pin, Link)                                          \
> +        Package (4) {                                                          \
> +            Address, Pin, Link, Zero                                           \
> +          }
> +
> +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "U-Boot", "SBSAQEMU", 2) {
> +  Scope (_SB) {
> +    // UART PL011
> +    Device (COM0) {
> +      Name (_HID, "ARMH0011")
> +      Name (_UID, Zero)
> +      Name (_CRS, ResourceTemplate () {
> +        Memory32Fixed (ReadWrite,
> +                       SBSA_UART_BASE_ADDR,
> +                       SBSA_UART_LENGTH)
> +        Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 33 }
> +      })
> +      Method (_STA) {
> +        Return (0xF)
> +      }
> +    }
> +
> +    // AHCI Host Controller
> +    Device (AHC0) {
> +      Name (_HID, "LNRO001E")
> +      Name (_CLS, Package (3) {
> +        0x01,
> +        0x06,
> +        0x01,
> +      })
> +      Name (_CCA, 1)
> +      Name (_CRS, ResourceTemplate() {
> +        Memory32Fixed (ReadWrite,
> +                       SBSA_AHCI_BASE_ADDR,
> +                       SBSA_AHCI_LENGTH)
> +        Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 42 }
> +      })
> +      Method (_STA) {
> +        Return (0xF)
> +      }
> +    }
> +
> +
> +    // USB XHCI Host Controller
> +    Device (USB0) {
> +        Name (_HID, "PNP0D10")      // _HID: Hardware ID
> +        Name (_UID, 0x00)            // _UID: Unique ID
> +        Name (_CCA, 0x01)            // _CCA: Cache Coherency Attribute
> +        Name (XHCI, 0xF)            // will be set using AcpiLib
> +        Method (_STA) {
> +          Return (XHCI)
> +        }
> +        Name (_CRS, ResourceTemplate() {
> +            Memory32Fixed (ReadWrite,
> +                           SBSA_XHCI_BASE_ADDR,
> +                           SBSA_XHCI_LENGTH)
> +            Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { 43 }
> +        })
> +
> +        // Root Hub
> +        Device (RHUB) {
> +            Name (_ADR, 0x00000000)  // Address of Root Hub should be 0 as per ACPI 5.0 spec
> +            Method (_STA) {
> +              Return (0xF)
> +            }
> +
> +            // Ports connected to Root Hub
> +            Device (HUB1) {
> +                Name (_ADR, 0x00000001)
> +                Name (_UPC, Package() {
> +                    0x00,       // Port is NOT connectable
> +                    0xFF,       // Don't care
> +                    0x00000000, // Reserved 0 must be zero
> +                    0x00000000  // Reserved 1 must be zero
> +                })
> +                Method (_STA) {
> +                  Return (0xF)
> +                }
> +
> +                Device (PRT1) {
> +                    Name (_ADR, 0x00000001)
> +                    Name (_UPC, Package() {
> +                        0xFF,        // Port is connectable
> +                        0x00,        // Port connector is A
> +                        0x00000000,
> +                        0x00000000
> +                    })
> +                    Name (_PLD, Package() {
> +                        Buffer(0x10) {
> +                            0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +                            0x31, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +                        }
> +                    })
> +                    Method (_STA) {
> +                      Return (0xF)
> +                    }
> +                } // USB0_RHUB_HUB1_PRT1
> +                Device (PRT2) {
> +                    Name (_ADR, 0x00000002)
> +                    Name (_UPC, Package() {
> +                        0xFF,        // Port is connectable
> +                        0x00,        // Port connector is A
> +                        0x00000000,
> +                        0x00000000
> +                    })
> +                    Name (_PLD, Package() {
> +                        Buffer(0x10) {
> +                            0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +                            0x31, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +                        }
> +                    })
> +                    Method (_STA) {
> +                      Return (0xF)
> +                    }
> +                } // USB0_RHUB_HUB1_PRT2
> +
> +                Device (PRT3) {
> +                    Name (_ADR, 0x00000003)
> +                    Name (_UPC, Package() {
> +                        0xFF,        // Port is connectable
> +                        0x09,        // Type C connector - USB2 and SS with Switch
> +                        0x00000000,
> +                        0x00000000
> +                    })
> +                    Name (_PLD, Package() {
> +                        Buffer (0x10) {
> +                            0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +                            0x31, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +                        }
> +                    })
> +                    Method (_STA) {
> +                      Return (0xF)
> +                    }
> +                } // USB0_RHUB_HUB1_PRT3
> +
> +                Device (PRT4) {
> +                    Name (_ADR, 0x00000004)
> +                    Name (_UPC, Package() {
> +                        0xFF,        // Port is connectable
> +                        0x09,        // Type C connector - USB2 and SS with Switch
> +                        0x00000000,
> +                        0x00000000
> +                    })
> +                    Name (_PLD, Package() {
> +                        Buffer (0x10){
> +                            0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +                            0x31, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +                        }
> +                    })
> +                    Method (_STA) {
> +                      Return (0xF)
> +                    }
> +                } // USB0_RHUB_HUB1_PRT4
> +            } // USB0_RHUB_HUB1
> +        } // USB0_RHUB
> +    } // USB0
> +
> +    Device (PCI0)
> +    {
> +      Name (_HID, EISAID ("PNP0A08")) // PCI Express Root Bridge
> +      Name (_CID, EISAID ("PNP0A03")) // Compatible PCI Root Bridge
> +      Name (_SEG, Zero) // PCI Segment Group number
> +      Name (_BBN, Zero) // PCI Base Bus Number
> +      Name (_UID, "PCI0")
> +      Name (_CCA, One)    // Initially mark the PCI coherent (for JunoR1)
> +
> +      Method (_STA) {
> +        Return (0xF)
> +      }
> +
> +      Method (_CBA, 0, NotSerialized) {
> +          return (SBSA_PCIE_ECAM_BASE_ADDR)
> +      }
> +
> +      LINK_DEVICE(0, GSI0, 0x23)
> +      LINK_DEVICE(1, GSI1, 0x24)
> +      LINK_DEVICE(2, GSI2, 0x25)
> +      LINK_DEVICE(3, GSI3, 0x26)
> +
> +      Name (_PRT, Package ()  // _PRT: PCI Routing Table
> +      {
> +        PRT_ENTRY(0x0000FFFF, 0, GSI0),
> +        PRT_ENTRY(0x0000FFFF, 0, GSI1),
> +        PRT_ENTRY(0x0000FFFF, 0, GSI2),
> +        PRT_ENTRY(0x0000FFFF, 0, GSI3),
> +
> +        PRT_ENTRY(0x0001FFFF, 0, GSI1),
> +        PRT_ENTRY(0x0001FFFF, 1, GSI2),
> +        PRT_ENTRY(0x0001FFFF, 2, GSI3),
> +        PRT_ENTRY(0x0001FFFF, 3, GSI0),
> +
> +        PRT_ENTRY(0x0002FFFF, 0, GSI2),
> +        PRT_ENTRY(0x0002FFFF, 1, GSI3),
> +        PRT_ENTRY(0x0002FFFF, 2, GSI0),
> +        PRT_ENTRY(0x0002FFFF, 3, GSI1),
> +
> +        PRT_ENTRY(0x0003FFFF, 0, GSI3),
> +        PRT_ENTRY(0x0003FFFF, 1, GSI0),
> +        PRT_ENTRY(0x0003FFFF, 2, GSI1),
> +        PRT_ENTRY(0x0003FFFF, 3, GSI2),
> +
> +        PRT_ENTRY(0x0004FFFF, 0, GSI0),
> +        PRT_ENTRY(0x0004FFFF, 1, GSI1),
> +        PRT_ENTRY(0x0004FFFF, 2, GSI2),
> +        PRT_ENTRY(0x0004FFFF, 3, GSI3),
> +
> +        PRT_ENTRY(0x0005FFFF, 0, GSI1),
> +        PRT_ENTRY(0x0005FFFF, 1, GSI2),
> +        PRT_ENTRY(0x0005FFFF, 2, GSI3),
> +        PRT_ENTRY(0x0005FFFF, 3, GSI0),
> +
> +        PRT_ENTRY(0x0006FFFF, 0, GSI2),
> +        PRT_ENTRY(0x0006FFFF, 1, GSI3),
> +        PRT_ENTRY(0x0006FFFF, 2, GSI0),
> +        PRT_ENTRY(0x0006FFFF, 3, GSI1),
> +
> +        PRT_ENTRY(0x0007FFFF, 0, GSI3),
> +        PRT_ENTRY(0x0007FFFF, 1, GSI0),
> +        PRT_ENTRY(0x0007FFFF, 2, GSI1),
> +        PRT_ENTRY(0x0007FFFF, 3, GSI2),
> +
> +        PRT_ENTRY(0x0008FFFF, 0, GSI0),
> +        PRT_ENTRY(0x0008FFFF, 1, GSI1),
> +        PRT_ENTRY(0x0008FFFF, 2, GSI2),
> +        PRT_ENTRY(0x0008FFFF, 3, GSI3),
> +
> +        PRT_ENTRY(0x0009FFFF, 0, GSI1),
> +        PRT_ENTRY(0x0009FFFF, 1, GSI2),
> +        PRT_ENTRY(0x0009FFFF, 2, GSI3),
> +        PRT_ENTRY(0x0009FFFF, 3, GSI0),
> +
> +        PRT_ENTRY(0x000AFFFF, 0, GSI2),
> +        PRT_ENTRY(0x000AFFFF, 1, GSI3),
> +        PRT_ENTRY(0x000AFFFF, 2, GSI0),
> +        PRT_ENTRY(0x000AFFFF, 3, GSI1),
> +
> +        PRT_ENTRY(0x000BFFFF, 0, GSI3),
> +        PRT_ENTRY(0x000BFFFF, 1, GSI0),
> +        PRT_ENTRY(0x000BFFFF, 2, GSI1),
> +        PRT_ENTRY(0x000BFFFF, 3, GSI2),
> +
> +        PRT_ENTRY(0x000CFFFF, 0, GSI0),
> +        PRT_ENTRY(0x000CFFFF, 1, GSI1),
> +        PRT_ENTRY(0x000CFFFF, 2, GSI2),
> +        PRT_ENTRY(0x000CFFFF, 3, GSI3),
> +
> +        PRT_ENTRY(0x000DFFFF, 0, GSI1),
> +        PRT_ENTRY(0x000DFFFF, 1, GSI2),
> +        PRT_ENTRY(0x000DFFFF, 2, GSI3),
> +        PRT_ENTRY(0x000DFFFF, 3, GSI0),
> +
> +        PRT_ENTRY(0x000EFFFF, 0, GSI2),
> +        PRT_ENTRY(0x000EFFFF, 1, GSI3),
> +        PRT_ENTRY(0x000EFFFF, 2, GSI0),
> +        PRT_ENTRY(0x000EFFFF, 3, GSI1),
> +
> +        PRT_ENTRY(0x000FFFFF, 0, GSI3),
> +        PRT_ENTRY(0x000FFFFF, 1, GSI0),
> +        PRT_ENTRY(0x000FFFFF, 2, GSI1),
> +        PRT_ENTRY(0x000FFFFF, 3, GSI2),
> +
> +        PRT_ENTRY(0x0010FFFF, 0, GSI0),
> +        PRT_ENTRY(0x0010FFFF, 1, GSI1),
> +        PRT_ENTRY(0x0010FFFF, 2, GSI2),
> +        PRT_ENTRY(0x0010FFFF, 3, GSI3),
> +
> +        PRT_ENTRY(0x0011FFFF, 0, GSI1),
> +        PRT_ENTRY(0x0011FFFF, 1, GSI2),
> +        PRT_ENTRY(0x0011FFFF, 2, GSI3),
> +        PRT_ENTRY(0x0011FFFF, 3, GSI0),
> +
> +        PRT_ENTRY(0x0012FFFF, 0, GSI2),
> +        PRT_ENTRY(0x0012FFFF, 1, GSI3),
> +        PRT_ENTRY(0x0012FFFF, 2, GSI0),
> +        PRT_ENTRY(0x0012FFFF, 3, GSI1),
> +
> +        PRT_ENTRY(0x0013FFFF, 0, GSI3),
> +        PRT_ENTRY(0x0013FFFF, 1, GSI0),
> +        PRT_ENTRY(0x0013FFFF, 2, GSI1),
> +        PRT_ENTRY(0x0013FFFF, 3, GSI2),
> +
> +        PRT_ENTRY(0x0014FFFF, 0, GSI0),
> +        PRT_ENTRY(0x0014FFFF, 1, GSI1),
> +        PRT_ENTRY(0x0014FFFF, 2, GSI2),
> +        PRT_ENTRY(0x0014FFFF, 3, GSI3),
> +
> +        PRT_ENTRY(0x0015FFFF, 0, GSI1),
> +        PRT_ENTRY(0x0015FFFF, 1, GSI2),
> +        PRT_ENTRY(0x0015FFFF, 2, GSI3),
> +        PRT_ENTRY(0x0015FFFF, 3, GSI0),
> +
> +        PRT_ENTRY(0x0016FFFF, 0, GSI2),
> +        PRT_ENTRY(0x0016FFFF, 1, GSI3),
> +        PRT_ENTRY(0x0016FFFF, 2, GSI0),
> +        PRT_ENTRY(0x0016FFFF, 3, GSI1),
> +
> +        PRT_ENTRY(0x0017FFFF, 0, GSI3),
> +        PRT_ENTRY(0x0017FFFF, 1, GSI0),
> +        PRT_ENTRY(0x0017FFFF, 2, GSI1),
> +        PRT_ENTRY(0x0017FFFF, 3, GSI2),
> +
> +        PRT_ENTRY(0x0018FFFF, 0, GSI0),
> +        PRT_ENTRY(0x0018FFFF, 1, GSI1),
> +        PRT_ENTRY(0x0018FFFF, 2, GSI2),
> +        PRT_ENTRY(0x0018FFFF, 3, GSI3),
> +
> +        PRT_ENTRY(0x0019FFFF, 0, GSI1),
> +        PRT_ENTRY(0x0019FFFF, 1, GSI2),
> +        PRT_ENTRY(0x0019FFFF, 2, GSI3),
> +        PRT_ENTRY(0x0019FFFF, 3, GSI0),
> +
> +        PRT_ENTRY(0x001AFFFF, 0, GSI2),
> +        PRT_ENTRY(0x001AFFFF, 1, GSI3),
> +        PRT_ENTRY(0x001AFFFF, 2, GSI0),
> +        PRT_ENTRY(0x001AFFFF, 3, GSI1),
> +
> +        PRT_ENTRY(0x001BFFFF, 0, GSI3),
> +        PRT_ENTRY(0x001BFFFF, 1, GSI0),
> +        PRT_ENTRY(0x001BFFFF, 2, GSI1),
> +        PRT_ENTRY(0x001BFFFF, 3, GSI2),
> +
> +        PRT_ENTRY(0x001CFFFF, 0, GSI0),
> +        PRT_ENTRY(0x001CFFFF, 1, GSI1),
> +        PRT_ENTRY(0x001CFFFF, 2, GSI2),
> +        PRT_ENTRY(0x001CFFFF, 3, GSI3),
> +
> +        PRT_ENTRY(0x001DFFFF, 0, GSI1),
> +        PRT_ENTRY(0x001DFFFF, 1, GSI2),
> +        PRT_ENTRY(0x001DFFFF, 2, GSI3),
> +        PRT_ENTRY(0x001DFFFF, 3, GSI0),
> +
> +        PRT_ENTRY(0x001EFFFF, 0, GSI2),
> +        PRT_ENTRY(0x001EFFFF, 1, GSI3),
> +        PRT_ENTRY(0x001EFFFF, 2, GSI0),
> +        PRT_ENTRY(0x001EFFFF, 3, GSI1),
> +
> +        PRT_ENTRY(0x001FFFFF, 0, GSI3),
> +        PRT_ENTRY(0x001FFFFF, 1, GSI0),
> +        PRT_ENTRY(0x001FFFFF, 2, GSI1),
> +        PRT_ENTRY(0x001FFFFF, 3, GSI2),
> +      })
> +
> +      // Root complex resources
> +      Name (_CRS, ResourceTemplate () {
> +        WordBusNumber ( // Bus numbers assigned to this root
> +        ResourceProducer,
> +        MinFixed, MaxFixed, PosDecode,
> +        0,   // AddressGranularity
> +        0,   // AddressMinimum - Minimum Bus Number
> +        0xff,// AddressMaximum - Maximum Bus Number
> +        0,   // AddressTranslation - Set to 0
> +        256  // RangeLength - Number of Busses
> +        )
> +
> +        // IO to mmio window
> +        QWordIO (
> +          ResourceProducer, MinFixed,
> +          MaxFixed, PosDecode,
> +          EntireRange,
> +          0x00000000,                              // Granularity
> +          0x0000,                                  // Min Base Address
> +          0xffff,                                  // Max Base Address
> +          SBSA_PIO_BASE_ADDR,                      // Translate
> +          SBSA_PIO_LENGTH                          // Length
> +        )
> +
> +        DWordMemory ( // 32-bit BAR Windows
> +          ResourceProducer, PosDecode,
> +          MinFixed, MaxFixed,
> +          Cacheable, ReadWrite,
> +          0x00000000,                              // Granularity
> +          SBSA_PCIE_MMIO_BASE_ADDR,                // Min Base Address
> +          SBSA_PCIE_MMIO_END,                      // Max Base Address
> +          0,                                       // Translate
> +          SBSA_PCIE_MMIO_LENGTH                    // Length
> +          )
> +
> +        QWordMemory ( // 64-bit BAR Windows
> +          ResourceProducer, PosDecode,
> +          MinFixed, MaxFixed,
> +          Cacheable, ReadWrite,
> +          0x00000000,                              // Granularity
> +          SBSA_PCIE_MMIO_HIGH_BASE_ADDR,           // Min Base Address
> +          SBSA_PCIE_MMIO_HIGH_END,                 // Max Base Address
> +          0,                                       // Translate
> +          SBSA_PCIE_MMIO_HIGH_LENGTH               // Length
> +          )
> +      }) // Name(_CRS)
> +
> +      Device (RES0)
> +      {
> +        Name (_HID, "PNP0C02" /* PNP Motherboard Resources */)  // _HID: Hardware ID
> +        Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
> +        {
> +           QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
> +           0x0000000000000000,                       // Granularity
> +           SBSA_PCIE_ECAM_BASE_ADDR,                 // Range Minimum
> +           SBSA_PCIE_ECAM_END,                       // Range Maximum
> +           0x0000000000000000,                       // Translation Offset
> +           SBSA_PCIE_ECAM_LENGTH,                    // Length
> +           ,, , AddressRangeMemory, TypeStatic)
> +        })
> +        Method (_STA) {
> +          Return (0xF)
> +        }
> +      }
> +
> +      // OS Control Handoff
> +      Name (SUPP, Zero) // PCI _OSC Support Field value
> +      Name (CTRL, Zero) // PCI _OSC Control Field value
> +
> +      /*
> +       * See [1] 6.2.10, [2] 4.5
> +       */
> +      Method (_OSC,4) {
> +        // Check for proper UUID
> +        If (Arg0 == ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766")) {
> +          // Create DWord-adressable fields from the Capabilities Buffer
> +          CreateDWordField (Arg3,0,CDW1)
> +          CreateDWordField (Arg3,4,CDW2)
> +          CreateDWordField (Arg3,8,CDW3)
> +
> +          // Save Capabilities DWord2 & 3
> +          Store (CDW2,SUPP)
> +          Store (CDW3,CTRL)
> +
> +          // Only allow native hot plug control if OS supports:
> +          // * ASPM
> +          // * Clock PM
> +          // * MSI/MSI-X
> +          If ((SUPP & 0x16) != 0x16) {
> +            CTRL &= 0x1E // Mask bit 0 (and undefined bits)
> +          }
> +
> +          // Always allow native PME, AER (no dependencies)
> +
> +          // Never allow SHPC (no SHPC controller in this system)
> +          CTRL &= 0x1D
> +
> +          If (Arg1 != One) {         // Unknown revision
> +            CDW1 |= 0x08
> +          }
> +
> +          If (CDW3 != CTRL) {        // Capabilities bits were masked
> +            CDW1 |= 0x10
> +          }
> +
> +          // Update DWORD3 in the buffer
> +          Store (CTRL,CDW3)
> +          Return (Arg3)
> +        } Else {
> +          CDW1 |= 4 // Unrecognized UUID
> +          Return (Arg3)
> +        }
> +      } // End _OSC
> +    }
> +  } // Scope (_SB)
> +}
> diff --git a/board/emulation/qemu-sbsa/lowlevel_init.S b/board/emulation/qemu-sbsa/lowlevel_init.S
> new file mode 100644
> index 0000000000..c997721af9
> --- /dev/null
> +++ b/board/emulation/qemu-sbsa/lowlevel_init.S
> @@ -0,0 +1,22 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * (C) Copyright 2016
> + * Cédric Schieli <cschieli at gmail.com>
> + */
> +
> +#include <config.h>
> +
> +/*
> + * Routine: save_boot_params (called after reset from start.S)
> + * Description: save ATAG/FDT address provided by the firmware at boot time
> + */
> +
> +.global save_boot_params
> +save_boot_params:
> +       /* The firmware provided ATAG/FDT address can be found in r2/x0 */
> +       adr     x8, fw_dtb_pointer
> +       str     x0, [x8]
> +
> +
> +       /* Returns */
> +       b       save_boot_params_ret
> diff --git a/board/emulation/qemu-sbsa/qemu-sbsa.c b/board/emulation/qemu-sbsa/qemu-sbsa.c
> new file mode 100644
> index 0000000000..3943c92432
> --- /dev/null
> +++ b/board/emulation/qemu-sbsa/qemu-sbsa.c
> @@ -0,0 +1,273 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2017 Tuomas Tynkkynen
> + */
> +
> +#include <cpu_func.h>
> +#include <dm.h>
> +#include <env.h>
> +#include <fdtdec.h>
> +#include <fdt_support.h>
> +#include <init.h>
> +#include <log.h>
> +#include <usb.h>
> +#include <asm/armv8/mmu.h>
> +
> +#include "qemu-sbsa.h"
> +
> +/* Assigned in lowlevel_init.S
> + * Push the variable into the .data section so that it
> + * does not get cleared later.
> + */
> +unsigned long __section(".data") fw_dtb_pointer;
> +
> +static struct mm_region qemu_sbsa_mem_map[] = {
> +       {
> +               /* Secure flash */
> +               .virt = SBSA_SECURE_FLASH_BASE_ADDR,
> +               .phys = SBSA_SECURE_FLASH_BASE_ADDR,
> +               .size = SBSA_SECURE_FLASH_LENGTH,
> +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> +                        PTE_BLOCK_INNER_SHARE |
> +                        PTE_BLOCK_PXN | PTE_BLOCK_UXN
> +       }, {
> +               /* Flash */
> +               .virt = SBSA_FLASH_BASE_ADDR,
> +               .phys = SBSA_FLASH_BASE_ADDR,
> +               .size = SBSA_FLASH_LENGTH,
> +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> +                        PTE_BLOCK_INNER_SHARE
> +       }, {
> +               /* Lowmem peripherals */
> +               .virt = SBSA_PERIPH_BASE_ADDR,
> +               .phys = SBSA_PERIPH_BASE_ADDR,
> +               .size = SBSA_PCIE_MMIO_BASE_ADDR - SBSA_PERIPH_BASE_ADDR,
> +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> +                        PTE_BLOCK_NON_SHARE |
> +                        PTE_BLOCK_PXN | PTE_BLOCK_UXN
> +       }, {
> +               /* 32-bit address PCIE MMIO space */
> +               .virt = SBSA_PCIE_MMIO_BASE_ADDR,
> +               .phys = SBSA_PCIE_MMIO_BASE_ADDR,
> +               .size = SBSA_PCIE_MMIO_LENGTH,
> +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> +                        PTE_BLOCK_NON_SHARE |
> +                        PTE_BLOCK_PXN | PTE_BLOCK_UXN
> +       }, {
> +               /* PCI-E ECAM memory area */
> +               .virt = SBSA_PCIE_ECAM_BASE_ADDR,
> +               .phys = SBSA_PCIE_ECAM_BASE_ADDR,
> +               .size = SBSA_PCIE_ECAM_LENGTH,
> +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> +                        PTE_BLOCK_NON_SHARE |
> +                        PTE_BLOCK_PXN | PTE_BLOCK_UXN
> +       }, {
> +               /* Highmem PCI-E MMIO memory area */
> +               .virt = SBSA_PCIE_MMIO_HIGH_BASE_ADDR,
> +               .phys = SBSA_PCIE_MMIO_HIGH_BASE_ADDR,
> +               .size = SBSA_PCIE_MMIO_HIGH_LENGTH,
> +               .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
> +                        PTE_BLOCK_NON_SHARE |
> +                        PTE_BLOCK_PXN | PTE_BLOCK_UXN
> +       }, {
> +               /* DRAM */
> +               .virt = SBSA_MEM_BASE_ADDR,
> +               .phys = SBSA_MEM_BASE_ADDR,
> +               .size = 0x800000000000ULL,
> +               .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
> +                        PTE_BLOCK_INNER_SHARE
> +       }, {
> +               /* List terminator */
> +               0,
> +       }
> +};
> +
> +struct mm_region *mem_map = qemu_sbsa_mem_map;
> +
> +int board_late_init(void)
> +{
> +       /* start usb so that usb keyboard can be used as input device */
> +       if (CONFIG_IS_ENABLED(USB_KEYBOARD))
> +               usb_init();
> +
> +       return 0;
> +}
> +
> +int board_init(void)
> +{
> +       return 0;
> +}
> +
> +/**
> + * dtb_dt_qemu - Return the address of the QEMU provided FDT.
> + *
> + * @return: Pointer to FDT or NULL on failure
> + */
> +static void *dtb_dt_qemu(void)
> +{
> +       /* FDT might be at start of DRAM */
> +       if (fdt_magic(SBSA_MEM_BASE_ADDR) == FDT_MAGIC)
> +               return (void *)(u64)SBSA_MEM_BASE_ADDR;
> +
> +       /* When ARM_LINUX_KERNEL_AS_BL33 is enabled in ATF, it's passed in x0 */
> +       if (fw_dtb_pointer >= SBSA_MEM_BASE_ADDR &&
> +           fdt_magic(fw_dtb_pointer) == FDT_MAGIC) {
> +               return (void *)fw_dtb_pointer;
> +       }
> +
> +       return NULL;
> +}
> +
> +/*
> + * QEMU doesn't set compatible on cpus.
> + * Add them to make sure the U-Boot driver properly bind.
> + */
> +static int fdtdec_fix_cpus(void *fdt_blob)
> +{
> +       int cpus_offset, off, ret;
> +       u64 mpidr, i = 0;
> +
> +       cpus_offset = fdt_path_offset(fdt_blob, "/cpus");
> +       if (cpus_offset < 0) {
> +               puts("couldn't find /cpus node\n");
> +               return cpus_offset;
> +       }
> +
> +       fdt_for_each_subnode(off, fdt_blob, cpus_offset) {
> +               if (strncmp(fdt_get_name(fdt_blob, off, NULL), "cpu@", 4))
> +                       continue;
> +
> +               mpidr = 0;
> +               ret = smc_get_mpidr(i, &mpidr);
> +               if (ret) {
> +                       log_warning("Failed to get MPIDR for processor %lld from SMC: %d\n",
> +                                   i, ret);
> +                       mpidr = i;
> +               }
> +
> +               ret = fdt_setprop_string(fdt_blob, off, "compatible", "arm,armv8");
> +               if (ret < 0)
> +                       return ret;
> +
> +               ret = fdt_setprop_string(fdt_blob, off, "device_type", "cpu");
> +               if (ret < 0)
> +                       return ret;
> +
> +               ret = fdt_setprop_u64(fdt_blob, off, "reg", mpidr);
> +               if (ret < 0)
> +                       return ret;
> +               i++;
> +       }
> +       return 0;
> +}
> +
> +/*
> + * Update the GIC node when necessary and add optional ITS when it has a
> + * non zero base-address.
> + */
> +static int fdtdec_fix_gic(void *fdt)
> +{
> +       u64 gic_dist_base = SBSA_GIC_DIST_BASE_ADDR;
> +       u64 gic_redist_base = SBSA_GIC_REDIST_BASE_ADDR;
> +       u64 gic_its_base = 0;
> +       int offs, ret;
> +       u64 reg[10];
> +
> +       /* Invoke SMC to get real base-address */
> +       smc_get_gic_dist_base(&gic_dist_base);
> +       smc_get_gic_redist_base(&gic_redist_base);
> +
> +       if ((gic_dist_base != SBSA_GIC_DIST_BASE_ADDR) ||
> +           (gic_redist_base != SBSA_GIC_REDIST_BASE_ADDR)) {
> +               offs = fdt_path_offset(fdt, "/interrupt-controller");
> +               if (offs < 0) {
> +                       puts("couldn't find /interrupt-controller node\n");
> +                       return offs;
> +               }
> +
> +               reg[0] = cpu_to_fdt64(gic_dist_base);
> +               reg[1] = cpu_to_fdt64((u64)SBSA_GIC_DIST_LENGTH);
> +               reg[2] = cpu_to_fdt64(gic_redist_base);
> +               reg[3] = cpu_to_fdt64((u64)SBSA_GIC_REDIST_LENGTH);
> +               reg[4] = cpu_to_fdt64(0);
> +               reg[5] = cpu_to_fdt64(0);
> +               reg[6] = cpu_to_fdt64(SBSA_GIC_HBASE_ADDR);
> +               reg[7] = cpu_to_fdt64((u64)SBSA_GIC_HBASE_LENGTH);
> +               reg[8] = cpu_to_fdt64(SBSA_GIC_VBASE_ADDR);
> +               reg[9] = cpu_to_fdt64((u64)SBSA_GIC_VBASE_LENGTH);
> +
> +               ret = fdt_setprop_inplace(fdt, offs, "reg", reg, sizeof(reg));
> +       }
> +
> +       smc_get_gic_its_base(&gic_its_base);
> +
> +       if (gic_its_base != 0) {
> +               offs = fdt_path_offset(fdt, "/its");
> +               if (offs < 0)
> +                       return offs;
> +
> +               ret = fdt_setprop_string(fdt, offs, "status", "okay");
> +               if (ret < 0)
> +                       return ret;
> +
> +               reg[0] = cpu_to_fdt64(gic_its_base);
> +               reg[1] = 0;
> +
> +               ret = fdt_setprop(fdt, offs, "reg", reg, sizeof(u64) * 2);
> +               if (ret < 0)
> +                       return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +int fdtdec_board_setup(const void *fdt_blob)
> +{
> +       void *qemu_fdt;
> +       int ret;
> +
> +       /*
> +        * Locate the QEMU provided DTB that contains the CPUs and amount of DRAM.
> +        */
> +       qemu_fdt = dtb_dt_qemu();
> +       if (!qemu_fdt) {
> +               log_err("QEMU FDT not found\n");
> +               return -ENODEV;
> +       }
> +
> +       ret = fdt_increase_size((void *)fdt_blob, 1024 + fdt_totalsize(qemu_fdt));
> +       if (ret)
> +               return -ENOMEM;
> +
> +       /*
> +        * Merge the QEMU DTB as overlay into the U-Boot provided DTB.
> +        */
> +       ret = fdt_overlay_apply_node((void *)fdt_blob, 0, qemu_fdt, 0);
> +       if (ret < 0)
> +               log_err("Failed to apply overlay: %d\n", ret);
> +
> +       /* Fix QEMU nodes to make sure U-Boot drivers are properly working */
> +       ret = fdtdec_fix_cpus((void *)fdt_blob);
> +       if (ret < 0)
> +               log_err("Failed to fix CPUs in FDT: %d\n", ret);
> +
> +       ret = fdtdec_fix_gic((void *)fdt_blob);
> +       if (ret < 0)
> +               log_err("Failed to fix INTC in FDT: %d\n", ret);
> +
> +       return 0;
> +}
> +
> +int misc_init_r(void)
> +{
> +       return env_set_hex("fdt_addr", (uintptr_t)gd->fdt_blob);
> +}
> +
> +void reset_cpu(void)
> +{
> +}
> +
> +int dram_init(void)
> +{
> +       return fdtdec_setup_mem_size_base();
> +}
> \ No newline at end of file
> diff --git a/board/emulation/qemu-sbsa/qemu-sbsa.env b/board/emulation/qemu-sbsa/qemu-sbsa.env
> new file mode 100644
> index 0000000000..88fdb0ec1c
> --- /dev/null
> +++ b/board/emulation/qemu-sbsa/qemu-sbsa.env
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +/* environment for qemu-arm and qemu-arm64 */
> +
> +stdin=serial,usbkbd
> +stdout=serial,vidconsole
> +stderr=serial,vidconsole
> +fdt_high=0xffffffffffffffff
> +initrd_high=0xffffffffffffffff
> +scriptaddr=0x100000300000
> +pxefile_addr_r=0x10000400000
> +kernel_addr_r=0x10000200000
> +ramdisk_addr_r=0x10001000000
> +boot_targets=qfw usb scsi virtio nvme dhcp
> diff --git a/board/emulation/qemu-sbsa/qemu-sbsa.h b/board/emulation/qemu-sbsa/qemu-sbsa.h
> new file mode 100644
> index 0000000000..391a70bdc4
> --- /dev/null
> +++ b/board/emulation/qemu-sbsa/qemu-sbsa.h
> @@ -0,0 +1,38 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2024 9elements GmbH
> + */
> +
> +/**
> + * smc_get_mpidr() - Call into SMC and get the MPIDR for given CPU
> + *
> + * @id:                CPU index
> + * @mpidr:     Pointer where to place the MPIDR
> + * @return 0 if OK, other -ve on error
> + */
> +int smc_get_mpidr(unsigned long id, u64 *mpidr);
> +
> +/**
> + * smc_get_gic_dist_base() - Call into SMC and get GIC dist base address
> + *
> + * @mpidr:     Pointer where to place the base address
> + * @return 0 if OK, other -ve on error
> + */
> +int smc_get_gic_dist_base(u64 *base);
> +
> +/**
> + * smc_get_gic_redist_base() - Call into SMC and get the GIC redistributor
> + *                             base address
> + *
> + * @mpidr:     Pointer where to place the base address
> + * @return 0 if OK, other -ve on error
> + */
> +int smc_get_gic_redist_base(u64 *base);
> +
> +/**
> + * smc_get_gic_its_base() - Call into SMC and get the ITS base address
> + *
> + * @mpidr:     Pointer where to place the base address
> + * @return 0 if OK, other -ve on error
> + */
> +int smc_get_gic_its_base(u64 *base);
> diff --git a/board/emulation/qemu-sbsa/smc.c b/board/emulation/qemu-sbsa/smc.c
> new file mode 100644
> index 0000000000..9a2d091bea
> --- /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;
> +}
> diff --git a/configs/qemu-arm-sbsa_defconfig b/configs/qemu-arm-sbsa_defconfig
> new file mode 100644
> index 0000000000..a58c3dec4c
> --- /dev/null
> +++ b/configs/qemu-arm-sbsa_defconfig
> @@ -0,0 +1,10 @@
> +CONFIG_ARM=y
> +CONFIG_ARCH_QEMU=y
> +CONFIG_TARGET_QEMU_ARM_SBSA=y
> +CONFIG_USE_BOOTCOMMAND=y
> +CONFIG_BOOTCOMMAND="bootflow scan"
> +CONFIG_EFI_PARTITION=y
> +CONFIG_PARTITION_TYPE_GUID=y
> +CONFIG_EFI_MEDIA=y
> +CONFIG_FS_FAT=y
> +CONFIG_EFI_VARIABLE_NO_STORE=y
> diff --git a/doc/board/emulation/index.rst b/doc/board/emulation/index.rst
> index 98a0b26ad2..0419d72415 100644
> --- a/doc/board/emulation/index.rst
> +++ b/doc/board/emulation/index.rst
> @@ -13,5 +13,6 @@ Emulation
>     qemu-mips
>     qemu-ppce500
>     qemu-riscv
> +   qemu-sbsa
>     qemu-x86
>     qemu-xtensa
> diff --git a/doc/board/emulation/qemu-sbsa.rst b/doc/board/emulation/qemu-sbsa.rst
> new file mode 100644
> index 0000000000..fe1dc3249e
> --- /dev/null
> +++ b/doc/board/emulation/qemu-sbsa.rst
> @@ -0,0 +1,98 @@
> +.. SPDX-License-Identifier: GPL-2.0+
> +.. Copyright (C) 2024, Patrick Rudolph <patrick.rudolph at 9elements.com>
> +
> +QEMU ARM SBSA
> +=============
> +
> +QEMU for ARM supports Arm Server Base System Architecture Reference board,
> +short 'sbsa-ref' that utilizes ACPI over FDT. This document describes how to run
> +U-Boot under it. Only AArch64 is supported.
> +
> +The 'sbsa' platform provides the following as the basic functionality:
> +
> +    - A freely configurable amount of CPU cores
> +    - U-Boot loaded and executing in the emulated flash at address 0x10000000
> +    - No device tree blob
> +    - A freely configurable amount of RAM
> +    - A PL011 serial port
> +    - An ARMv8/ARMv8 architected timer
> +    - PSCI for rebooting the system
> +    - A generic ECAM-based PCI host controller
> +
> +Additionally, a number of optional peripherals can be added to the PCI bus.
> +
> +Compile ARM Trusted Firmware (ATF)
> +----------------------------------
> +
> +Get and Build the ARM Trusted firmware
> +--------------------------------------
> +
> +Note: srctree is U-Boot source directory
> +Get ATF from: https://github.com/ARM-software/arm-trusted-firmware
> +
> +.. code-block:: bash
> +
> +  git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git tfa
> +  cd tfa
> +  make CROSS_COMPILE=aarch64-linux-gnu- all fip \
> +    ARM_LINUX_KERNEL_AS_BL33=1 DEBUG=1 PLAT=qemu_sbsa
> +
> +Copy the resulting FIP and BL1 binary
> +
> +.. code-block:: bash
> +
> +  cp build/qemu_sbsa/debug/fip.bin ../
> +  cp build/qemu_sbsa/debug/bl1.bin ../
> +
> +Building U-Boot
> +---------------
> +Set the CROSS_COMPILE environment variable as usual, and run:
> +
> +.. code-block:: bash
> +
> +    make qemu-arm-sbsa_defconfig
> +    make
> +
> +Running U-Boot
> +--------------
> +The minimal QEMU command line to get U-Boot up and running is:
> +
> +.. code-block:: bash
> +
> +    qemu-system-aarch64 -machine sbsa-ref -nographic -cpu cortex-a57 \
> +                        -pflash secure-world.rom \
> +                        -pflash unsecure-world.rom
> +
> +Note that for some odd reason qemu-system-aarch64 needs to be explicitly
> +told to use a 64-bit CPU or it will boot in 32-bit mode. The -nographic argument
> +ensures that output appears on the terminal. Use Ctrl-A X to quit.
> +
> +Booting distros
> +---------------
> +
> +It is possible to install and boot a standard Linux distribution using
> +sbsa by setting up a root disk::
> +
> +.. code-block:: bash
> +
> +    qemu-img create root.img 20G
> +
> +then using the installer to install. For example, with Debian 12::
> +
> +.. code-block:: bash
> +
> +    qemu-system-aarch64 \
> +      -machine sbsa-ref -cpu cortex-a57 -m 4G -smp 4 \
> +      -pflash secure-world.rom \
> +      -pflash unsecure-world.rom \
> +      -device virtio-rng-pci \
> +      -device usb-kbd -device usb-tablet \
> +      -cdrom debian-12.0.0-arm64-netinst.iso \
> +      -hda root.img
> +
> +Debug UART
> +----------
> +
> +The debug UART on the ARM sbsa board uses these settings::
> +
> +    CONFIG_DEBUG_UART=y
> diff --git a/doc/develop/driver-model/virtio.rst b/doc/develop/driver-model/virtio.rst
> index 8ac9c94caf..31b94d0467 100644
> --- a/doc/develop/driver-model/virtio.rst
> +++ b/doc/develop/driver-model/virtio.rst
> @@ -34,6 +34,7 @@ The following QEMU targets are supported.
>
>    - qemu_arm_defconfig
>    - qemu_arm64_defconfig
> +  - qemu-arm-sbsa_defconfig
>    - qemu-riscv32_defconfig
>    - qemu-riscv64_defconfig
>    - qemu-x86_defconfig
> diff --git a/include/configs/qemu-sbsa.h b/include/configs/qemu-sbsa.h
> new file mode 100644
> index 0000000000..aff78160e1
> --- /dev/null
> +++ b/include/configs/qemu-sbsa.h
> @@ -0,0 +1,89 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2024 9elements GmbH
> + */
> +
> +#ifndef __CONFIG_H
> +#define __CONFIG_H
> +
> +/* Physical memory map */
> +
> +/* SECURE_FLASH */
> +#define SBSA_SECURE_FLASH_BASE_ADDR    0x00000000
> +#define SBSA_SECURE_FLASH_LENGTH       0x10000000
> +
> +/* FLASH */
> +#define SBSA_FLASH_BASE_ADDR           0x10000000
> +#define SBSA_FLASH_LENGTH              0x10000000
> +
> +/* PERIPH */
> +#define SBSA_PERIPH_BASE_ADDR          0x40000000
> +
> +/* GIC_DIST */
> +#define SBSA_GIC_DIST_BASE_ADDR                0x40060000
> +#define SBSA_GIC_DIST_LENGTH           0x00020000
> +
> +#define SBSA_GIC_VBASE_ADDR            0x2c020000
> +#define SBSA_GIC_VBASE_LENGTH          0x00010000
> +
> +#define SBSA_GIC_HBASE_ADDR            0x2c010000
> +#define SBSA_GIC_HBASE_LENGTH          0x00010000
> +
> +/* GIC_REDIST */
> +#define SBSA_GIC_REDIST_BASE_ADDR      0x40080000
> +#define SBSA_GIC_REDIST_LENGTH         0x04000000
> +
> +/* GIC_ITS */
> +#define SBSA_GIC_ITS_BASE_ADDR         0x44081000
> +
> +/* UART */
> +#define SBSA_UART_BASE_ADDR            0x60000000
> +#define SBSA_UART_LENGTH               0x00001000
> +
> +/* SMMU */
> +#define SBSA_SMMU_BASE_ADDR            0x60050000
> +
> +/* SATA */
> +#define SBSA_AHCI_BASE_ADDR            0x60100000
> +#define SBSA_AHCI_LENGTH               0x00010000
> +
> +/* xHCI */
> +#define SBSA_XHCI_BASE_ADDR            0x60110000
> +#define SBSA_XHCI_LENGTH               0x00010000
> +
> +/* PIO */
> +#define SBSA_PIO_BASE_ADDR             0x7fff0000
> +#define SBSA_PIO_LENGTH                        0x00010000
> +
> +/* PCIE_MMIO */
> +#define SBSA_PCIE_MMIO_BASE_ADDR       0x80000000
> +#define SBSA_PCIE_MMIO_LENGTH          0x70000000
> +#define SBSA_PCIE_MMIO_END             0xefffffff
> +
> +/* PCIE_ECAM */
> +#define SBSA_PCIE_ECAM_BASE_ADDR       0xf0000000
> +#define SBSA_PCIE_ECAM_LENGTH          0x10000000
> +#define SBSA_PCIE_ECAM_END             0xffffffff
> +
> +/* PCIE_MMIO_HIGH */
> +#ifdef __ACPI__
> +#define SBSA_PCIE_MMIO_HIGH_BASE_ADDR  0x100000000
> +#define SBSA_PCIE_MMIO_HIGH_LENGTH     0xFF00000000
> +#define SBSA_PCIE_MMIO_HIGH_END                0xFFFFFFFFFF
> +#else
> +#define SBSA_PCIE_MMIO_HIGH_BASE_ADDR  0x100000000ULL
> +#define SBSA_PCIE_MMIO_HIGH_LENGTH     0xFF00000000ULL
> +#define SBSA_PCIE_MMIO_HIGH_END                0xFFFFFFFFFFULL
> +#endif
> +
> +/* MEM */
> +#ifdef __ACPI__
> +#define SBSA_MEM_BASE_ADDR             0x10000000000
> +#else
> +#define SBSA_MEM_BASE_ADDR             0x10000000000ULL
> +#endif
> +
> +#define CFG_SYS_INIT_RAM_ADDR          SBSA_MEM_BASE_ADDR
> +#define CFG_SYS_INIT_RAM_SIZE          0x1000000
> +
> +#endif /* __CONFIG_H */
> --
> 2.46.2
>

Thanks,
Moritz


More information about the U-Boot mailing list