diff options
113 files changed, 6519 insertions, 542 deletions
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 3ff1b44a6bc..4ecf76eaa0b 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -255,6 +255,11 @@ stages: wget -O - https://github.com/riscv-software-src/opensbi/releases/download/v1.3.1/opensbi-1.3.1-rv-bin.tar.xz | tar -C /tmp -xJ; export OPENSBI=/tmp/opensbi-1.3.1-rv-bin/share/opensbi/lp64/generic/firmware/fw_dynamic.bin; fi + if [[ "\${TEST_PY_BD}" == "qemu-arm-sbsa" ]]; then + wget -O /tmp/bl1.bin https://artifacts.codelinaro.org/artifactory/linaro-419-sbsa-ref/latest/tf-a/bl1.bin; + wget -O /tmp/fip.bin https://artifacts.codelinaro.org/artifactory/linaro-419-sbsa-ref/latest/tf-a/fip.bin; + export BINMAN_INDIRS=/tmp + fi # the below corresponds to .gitlab-ci.yml "script" cd \${WORK_DIR} export UBOOT_TRAVIS_BUILD_DIR=/tmp/\${TEST_PY_BD} @@ -426,6 +431,9 @@ stages: qemu_arm64_lwip: TEST_PY_BD: "qemu_arm64_lwip" TEST_PY_TEST_SPEC: "test_net_dhcp or test_net_ping or test_net_tftpboot" + qemu_arm_sbsa_ref: + TEST_PY_BD: "qemu-arm-sbsa" + TEST_PY_TEST_SPEC: "not sleep" qemu_m68k: TEST_PY_BD: "M5208EVBE" TEST_PY_ID: "--id qemu" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d89657e28b3..0aeda53bc2d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -42,6 +42,11 @@ stages: wget -O - https://github.com/riscv-software-src/opensbi/releases/download/v1.3.1/opensbi-1.3.1-rv-bin.tar.xz | tar -C /tmp -xJ; export OPENSBI=/tmp/opensbi-1.3.1-rv-bin/share/opensbi/lp64/generic/firmware/fw_dynamic.bin; fi + - if [[ "${TEST_PY_BD}" == "qemu-arm-sbsa" ]]; then + wget -O /tmp/bl1.bin https://artifacts.codelinaro.org/artifactory/linaro-419-sbsa-ref/latest/tf-a/bl1.bin; + wget -O /tmp/fip.bin https://artifacts.codelinaro.org/artifactory/linaro-419-sbsa-ref/latest/tf-a/fip.bin; + export BINMAN_INDIRS=/tmp; + fi after_script: - cp -v /tmp/${TEST_PY_BD}/*.{html,css,xml} . @@ -357,6 +362,12 @@ qemu_arm64_lwip test.py: TEST_PY_TEST_SPEC: "test_net_dhcp or test_net_ping or test_net_tftpboot" <<: *buildman_and_testpy_dfn +qemu_arm_sbsa test.py: + variables: + TEST_PY_BD: "qemu-arm-sbsa" + TEST_PY_TEST_SPEC: "not sleep" + <<: *buildman_and_testpy_dfn + qemu_m68k test.py: variables: TEST_PY_BD: "M5208EVBE" diff --git a/MAINTAINERS b/MAINTAINERS index 8e375e75e53..38c714cf46a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -355,7 +355,7 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-marvell.git F: arch/arm/mach-kirkwood/ F: arch/arm/mach-mvebu/ -F: drivers/ata/ahci_mvebu.c +F: drivers/ata/ahci_generic.c F: drivers/clk/mvebu/ F: drivers/ddr/marvell/ F: drivers/gpio/mvebu_gpio.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 060636e9e2d..787f983ffd4 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -113,6 +113,13 @@ config GICV2 config GICV3 bool +config DRIVER_GICV2 + bool "ARM GICV2 driver" + select IRQ + help + ARM GICV2 driver. + Basic support for parsing the GICV2 node and generate ACPI tables. + config GIC_V3_ITS bool "ARM GICV3 ITS" select IRQ @@ -644,6 +651,7 @@ config ARCH_ORION5X config ARCH_BCM283X bool "Broadcom BCM283X family" + select CPU select DM select DM_GPIO select DM_SERIAL @@ -1047,7 +1055,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 @@ -2374,6 +2382,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/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile index 8747d2eb186..2e71ff2dc97 100644 --- a/arch/arm/cpu/armv8/Makefile +++ b/arch/arm/cpu/armv8/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_ARM_SMCCC) += smccc-call.o ifndef CONFIG_XPL_BUILD obj-$(CONFIG_ARMV8_SPIN_TABLE) += spin_table.o spin_table_v8.o +obj-$(CONFIG_ACPI_PARKING_PROTOCOL) += acpi_park_v8.o else obj-$(CONFIG_ARCH_SUNXI) += fel_utils.o endif diff --git a/arch/arm/cpu/armv8/acpi_park_v8.S b/arch/arm/cpu/armv8/acpi_park_v8.S new file mode 100644 index 00000000000..0bc605d28df --- /dev/null +++ b/arch/arm/cpu/armv8/acpi_park_v8.S @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2024 9elements GmbH + * Author: Patrick Rudolph <patrick.rudolph@9elements.com> + * + * This file provides ARMv8 specific code for the generic part of the + * ACPI parking protocol implementation. It contains the spinning code + * that will be installed into the parking protocol and it points the + * secondary CPUs to their own parking protocol page once it has been + * set up by the generic part. + */ + +#include <asm/acpi_table.h> +#include <linux/linkage.h> + +/* Filled by C code */ +.global acpi_pp_tables +acpi_pp_tables: + .quad 0 + +.global acpi_pp_etables +acpi_pp_etables: + .quad 0 + +/* Read by C code */ +.global acpi_pp_code_size +acpi_pp_code_size: + .word __secondary_pp_code_end - __secondary_pp_code_start + +.global acpi_pp_secondary_jump +ENTRY(acpi_pp_secondary_jump) +0: + /* + * Cannot use atomic operations since the MMU and D-cache + * might be off. Use the MPIDR instead to find the spintable. + */ + + /* Check if parking protocol table is ready */ + ldr x1, =acpi_pp_tables + ldr x0, [x1] + cbnz x0, 0f + wfe + b 0b + +0: /* Get end of page tables in x3 */ + ldr x1, =acpi_pp_etables + ldr x3, [x1] + + /* Get own CPU ID in w2 */ + mrs x2, mpidr_el1 + lsr x9, x2, #32 + bfi x2, x9, #24, #8 /* w2 is aff3:aff2:aff1:aff0 */ + +0: /* Loop over all parking protocol pages */ + cmp x0, x3 + b.ge hlt + + /* Fetch CPU_ID from current page */ + ldr x1, [x0, #ACPI_PP_CPU_ID_OFFSET] + lsr x9, x1, #32 + bfi x1, x9, #24, #8 /* w1 is aff3:aff2:aff1:aff0 */ + + /* Compare CPU_IDs */ + cmp w1, w2 + b.eq 0f + + add x0, x0, #ACPI_PP_PAGE_SIZE + b 0b + +hlt: wfi + b hlt /* Should never happen. */ + +0: /* x0 points to the 4K-aligned, parking protocol page */ + add x2, x0, #ACPI_PP_CPU_CODE_OFFSET + + /* Jump to spin code in own parking protocol page */ + br x2 +ENDPROC(acpi_pp_secondary_jump) + +.align 8 +__secondary_pp_code_start: +.global acpi_pp_code_start +ENTRY(acpi_pp_code_start) + /* x0 points to the 4K-aligned, parking protocol page */ + + /* Prepare defines for spinning code */ + mov w3, #ACPI_PP_CPU_ID_INVALID + mov x2, #ACPI_PP_JMP_ADR_INVALID + + /* Mark parking protocol page as ready */ + str w3, [x0, #ACPI_PP_CPU_ID_OFFSET] + dsb sy + +0: wfe + ldr w1, [x0, #ACPI_PP_CPU_ID_OFFSET] + + /* Check CPU ID is valid */ + cmp w1, w3 + b.eq 0b + + /* Check jump address valid */ + ldr x1, [x0, #ACPI_PP_CPU_JMP_OFFSET] + cmp x1, x2 + b.eq 0b + + /* Clear jump address before jump */ + str x2, [x0, #ACPI_PP_CPU_JMP_OFFSET] + dsb sy + + br x1 +ENDPROC(acpi_pp_code_start) + /* Secondary Boot Code ends here */ +__secondary_pp_code_end: diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S index 4a3b9f60e46..d3a8a7c4787 100644 --- a/arch/arm/cpu/armv8/start.S +++ b/arch/arm/cpu/armv8/start.S @@ -178,6 +178,18 @@ pie_fixup_done: branch_if_master x0, master_cpu b spin_table_secondary_jump /* never return */ +#elif defined(CONFIG_ACPI_PARKING_PROTOCOL) && !defined(CONFIG_SPL_BUILD) + branch_if_master x0, master_cpu + /* + * Waits for ACPI parking protocol memory to be allocated and the spin-table + * code to be written. Once ready the secondary CPUs will jump and spin in + * their own 4KiB memory region, which is also used as mailbox, until released + * by the OS. + * The mechanism is similar to the DT enable-method = "spin-table", but works + * with ACPI enabled platforms. + */ + b acpi_pp_secondary_jump + /* never return */ #elif defined(CONFIG_ARMV8_MULTIENTRY) branch_if_master x0, master_cpu diff --git a/arch/arm/dts/qemu-sbsa.dts b/arch/arm/dts/qemu-sbsa.dts new file mode 100644 index 00000000000..ed00e501366 --- /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/acpi_table.h b/arch/arm/include/asm/acpi_table.h index e69de29bb2d..7386f55ad34 100644 --- a/arch/arm/include/asm/acpi_table.h +++ b/arch/arm/include/asm/acpi_table.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef __ASM_ACPI_TABLE_H__ +#define __ASM_ACPI_TABLE_H__ + +#ifndef __ACPI__ +#ifndef __ASSEMBLY__ + +#include <acpi/acpi_table.h> + +/** + * acpi_write_madt_gicc() - Write out a MADT GICC sub-table + * + * Write out the GIC CPU Interface sub-table. + * + * @gicc: Pointer to place to put the sub-table + * @cpu_num: GIC's CPU Interface Number + * @perf_gsiv: The GSIV used for Performance Monitoring Interrupts + * @phys_base: Address at which the processor can access this + * GIC CPU Interface + * @gicv: Address of the GIC virtual CPU interface registers + * @gich: Address of the GIC virtual interface control block + * registers + * @vgic_maint_irq: GSIV for Virtual GIC maintenance interrupt + * @gicr_base: Physical address of the associated Redistributor + * @mpidr: MPIDR as defined by ARM architecture + * @efficiency: Describes the relative power efficiency + */ +void acpi_write_madt_gicc(struct acpi_madt_gicc *gicc, uint cpu_num, + uint perf_gsiv, ulong phys_base, ulong gicv, + ulong gich, uint vgic_maint_irq, u64 gicr_base, + ulong mpidr, uint efficiency); + +/** + * acpi_write_madt_gicd() - Write out a MADT GICD sub-table + * + * Write out the GIC Distributor sub-table. + * + * @gicd: Pointer to place to put the sub-table + * @gic_id: This GIC Distributor's hardware ID + * @phys_base: The 64-bit physical address for this Distributor + * @gic_version: GIC version + */ +void acpi_write_madt_gicd(struct acpi_madt_gicd *gicd, uint gic_id, + ulong phys_base, uint gic_version); + +/** + * acpi_write_madt_gicr() - Write out a MADT GICR sub-table + * + * Write out the GIC Redistributor sub-table. + * + * @gicr: Pointer to place to put the sub-table + * @discovery_range_base_address: Physical address of a page range + * containing all GIC Redistributors + * @discovery_range_length: Length of the GIC Redistributor + * Discovery page range + */ +void acpi_write_madt_gicr(struct acpi_madt_gicr *gicr, + u64 discovery_range_base_address, + u32 discovery_range_length); + +/** + * acpi_write_madt_its() - Write out a MADT ITS sub-table + * + * Write out the GIC Interrupt Translation Service sub-table. + * + * @its: Pointer to place to put the sub-table + * @its_id: Uniqueue GIC ITS ID + * @physical_base_address: Physical address for the Interrupt + * Translation Service + */ +void acpi_write_madt_its(struct acpi_madt_its *its, + u32 its_id, + u64 physical_base_address); + +/** + * acpi_pptt_add_proc() - Write out a PPTT processor sub-table + * + * Write out the Processor Properties Topology Table processor sub-table. + * + * @ctx: ACPI context pointer + * @flags: Processor Structure Flags + * @parent: Reference to parent processor + * @proc_id: ACPI processor ID as defined in MADT + * @num_resources: Number of resource structure references + * @resource_list: References to other PPTT structures + * Return: offset from start of PPTT in bytes + */ +int acpi_pptt_add_proc(struct acpi_ctx *ctx, const u32 flags, const u32 parent, + const u32 proc_id, const u32 num_resources, + const u32 *resource_list); + +/** + * acpi_pptt_add_cache() - Write out a PPTT cache sub-table + * + * Write out the Processor Properties Topology Table cache sub-table. + * + * @ctx: ACPI context pointer + * @flags: Cache Structure Flags + * @next_cache_level: Reference to next level of cache + * @size: Size of the cache in bytes + * @sets: Number of sets in the cache + * @assoc: Integer number of ways + * @attributes: Allocation type, Cache type, policy + * @line_size: Line size in bytes + * Return: offset from start of PPTT in bytes + */ +int acpi_pptt_add_cache(struct acpi_ctx *ctx, const u32 flags, + const u32 next_cache_level, const u32 size, + const u32 sets, const u8 assoc, const u8 attributes, + const u16 line_size); + +/* Multi-processor Startup for ARM Platforms */ +/** + * struct acpi_pp_page - MP startup handshake mailbox + * + * Defines a 4096 byte memory region that is used for starting secondary CPUs on + * an Arm system that follows the "Multi-processor Startup for ARM Platforms" spec. + * + * @cpu_id: MPIDR as returned by the Multiprocessor Affinity Register. + * On 32bit Arm systems the upper bits are unused. + * @jumping_address: On 32bit Arm systems the address must be below 4 GiB + * @os_reserved: Reserved for OS use. Firmware must not access this memory. + * @spinning_code: Reserved for firmware use. OS must not access this memory. + * The spinning code will be installed by firmware and the secondary + * CPUs will enter it before the control is handed over to the OS. + */ +struct acpi_pp_page { + u64 cpu_id; + u64 jumping_address; + u8 os_reserved[2032]; + u8 spinning_code[2048]; +} __packed; + +#endif /* !__ASSEMBLY__ */ +#endif /* !__ACPI__ */ + +/* Multi-processor Startup for ARM Platforms defines */ +#define ACPI_PP_CPU_ID_INVALID 0xffffffff +#define ACPI_PP_JMP_ADR_INVALID 0 +#define ACPI_PP_PAGE_SIZE 4096 +#define ACPI_PP_CPU_ID_OFFSET 0 +#define ACPI_PP_CPU_JMP_OFFSET 8 +#define ACPI_PP_CPU_CODE_OFFSET 2048 +#define ACPI_PP_VERSION 1 + +#endif /* __ASM_ACPI_TABLE_H__ */ 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 00000000000..4a1a254b923 --- /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/include/asm/system.h b/arch/arm/include/asm/system.h index 2237d7d0066..9eb30c2ade8 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -394,6 +394,15 @@ void switch_to_hypervisor_ret(void); #define wfi() #endif +static inline unsigned long read_mpidr(void) +{ + unsigned long val; + + asm volatile("mrc p15, 0, %0, c0, c0, 5" : "=r" (val)); + + return val; +} + static inline unsigned long get_cpsr(void) { unsigned long cpsr; diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index f254186c525..1c95dd6fed2 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_FSL_LAYERSCAPE) += ccn504.o ifneq ($(CONFIG_GICV2)$(CONFIG_GICV3),) obj-y += gic_64.o endif +obj-$(CONFIG_DRIVER_GICV2) += gic-v2.o obj-$(CONFIG_GIC_V3_ITS) += gic-v3-its.o obj-y += interrupts_64.o else @@ -86,6 +87,7 @@ obj-y += psci-dt.o obj-$(CONFIG_DEBUG_LL) += debug.o obj-$(CONFIG_BLOBLIST) += xferlist.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o # For EABI conformant tool chains, provide eabi_compat() ifneq (,$(findstring -mabi=aapcs-linux,$(PLATFORM_CPPFLAGS))) diff --git a/arch/arm/lib/acpi_table.c b/arch/arm/lib/acpi_table.c new file mode 100644 index 00000000000..f760b7fbce4 --- /dev/null +++ b/arch/arm/lib/acpi_table.c @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Based on acpi.c from coreboot + * + * Copyright (C) 2024 9elements GmbH + */ + +#define LOG_CATEGORY LOGC_ACPI + +#include <bloblist.h> +#include <cpu_func.h> +#include <efi_loader.h> +#include <malloc.h> +#include <string.h> +#include <tables_csum.h> +#include <acpi/acpigen.h> +#include <acpi/acpi_device.h> +#include <acpi/acpi_table.h> +#include <asm-generic/io.h> +#include <dm/acpi.h> +#include <dm/uclass.h> +#include <linux/log2.h> +#include <linux/sizes.h> + +/* defined in assembly file */ +/** + * acpi_pp_code_size - Spinloop code size * + */ +extern u16 acpi_pp_code_size; + +/** + * acpi_pp_tables - Start of ACPI PP tables. + */ +extern ulong acpi_pp_tables; + +/** + * acpi_pp_etables - End of ACPI PP tables. + */ +extern ulong acpi_pp_etables; + +/** + * acpi_pp_code_start() - Spinloop code + * + * Architectural spinloop code to be installed in each parking protocol + * page. The spinloop code must be less than 2048 bytes. + * + * The spinloop code will be entered after calling + * acpi_parking_protocol_install(). + * + */ +void acpi_pp_code_start(void); + +void acpi_write_madt_gicc(struct acpi_madt_gicc *gicc, uint cpu_num, + uint perf_gsiv, ulong phys_base, ulong gicv, + ulong gich, uint vgic_maint_irq, u64 gicr_base, + ulong mpidr, uint efficiency) +{ + memset(gicc, '\0', sizeof(struct acpi_madt_gicc)); + gicc->type = ACPI_APIC_GICC; + gicc->length = sizeof(struct acpi_madt_gicc); + gicc->cpu_if_num = cpu_num; + gicc->processor_id = cpu_num; + gicc->flags = ACPI_MADTF_ENABLED; + gicc->perf_gsiv = perf_gsiv; + gicc->phys_base = phys_base; + gicc->gicv = gicv; + gicc->gich = gich; + gicc->vgic_maint_irq = vgic_maint_irq; + gicc->gicr_base = gicr_base; + gicc->mpidr = mpidr; + gicc->efficiency = efficiency; +} + +void acpi_write_madt_gicd(struct acpi_madt_gicd *gicd, uint gic_id, + ulong phys_base, uint gic_version) +{ + memset(gicd, '\0', sizeof(struct acpi_madt_gicd)); + gicd->type = ACPI_APIC_GICD; + gicd->length = sizeof(struct acpi_madt_gicd); + gicd->gic_id = gic_id; + gicd->phys_base = phys_base; + gicd->gic_version = gic_version; +} + +void acpi_write_madt_gicr(struct acpi_madt_gicr *gicr, + u64 discovery_range_base_address, + u32 discovery_range_length) +{ + memset(gicr, '\0', sizeof(struct acpi_madt_gicr)); + gicr->type = ACPI_APIC_GICR; + gicr->length = sizeof(struct acpi_madt_gicr); + gicr->discovery_range_base_address = discovery_range_base_address; + gicr->discovery_range_length = discovery_range_length; +} + +void acpi_write_madt_its(struct acpi_madt_its *its, + u32 its_id, + u64 physical_base_address) +{ + memset(its, '\0', sizeof(struct acpi_madt_its)); + its->type = ACPI_APIC_ITS; + its->length = sizeof(struct acpi_madt_its); + its->gic_its_id = its_id; + its->physical_base_address = physical_base_address; +} + +int acpi_pptt_add_proc(struct acpi_ctx *ctx, const u32 flags, const u32 parent, + const u32 proc_id, const u32 num_resources, + const u32 *resource_list) +{ + struct acpi_pptt_proc *proc = ctx->current; + int offset; + + offset = ctx->current - ctx->tab_start; + proc->hdr.type = ACPI_PPTT_TYPE_PROC; + proc->flags = flags; + proc->parent = parent; + proc->proc_id = proc_id; + proc->num_resources = num_resources; + proc->hdr.length = sizeof(struct acpi_pptt_proc) + + sizeof(u32) * num_resources; + + if (resource_list) + memcpy(proc + 1, resource_list, sizeof(u32) * num_resources); + + acpi_inc(ctx, proc->hdr.length); + + return offset; +} + +int acpi_pptt_add_cache(struct acpi_ctx *ctx, const u32 flags, + const u32 next_cache_level, const u32 size, + const u32 sets, const u8 assoc, const u8 attributes, + const u16 line_size) +{ + struct acpi_pptt_cache *cache = ctx->current; + int offset; + + offset = ctx->current - ctx->tab_start; + cache->hdr.type = ACPI_PPTT_TYPE_CACHE; + cache->hdr.length = sizeof(struct acpi_pptt_cache); + cache->flags = flags; + cache->next_cache_level = next_cache_level; + cache->size = size; + cache->sets = sets; + cache->assoc = assoc; + cache->attributes = attributes; + cache->line_size = line_size; + acpi_inc(ctx, cache->hdr.length); + + return offset; +} + +void *acpi_fill_madt(struct acpi_madt *madt, struct acpi_ctx *ctx) +{ + uclass_probe_all(UCLASS_CPU); + uclass_probe_all(UCLASS_IRQ); + + /* All SoCs must use the driver model */ + acpi_fill_madt_subtbl(ctx); + + return ctx->current; +} + +/** + * acpi_write_pp_setup_one_page() - Fill out one page used by the PP + * + * Fill out the struct acpi_pp_page to contain the spin-loop + * code and the mailbox area. After this function the page is ready for + * the secondary core's to enter the spin-loop code. + * + * @page: Pointer to current parking protocol page + * @gicc: Pointer to corresponding GICC sub-table + */ +static void acpi_write_pp_setup_one_page(struct acpi_pp_page *page, + struct acpi_madt_gicc *gicc) +{ + void *reloc; + + /* Update GICC. Mark parking protocol as available. */ + gicc->parking_proto = ACPI_PP_VERSION; + gicc->parked_addr = virt_to_phys(page); + + /* Prepare parking protocol page */ + memset(page, '\0', sizeof(struct acpi_pp_page)); + + /* Init mailbox. Set MPIDR so core's will find their page. */ + page->cpu_id = gicc->mpidr; + page->jumping_address = ACPI_PP_JMP_ADR_INVALID; + + /* Relocate spinning code */ + reloc = &page->spinning_code[0]; + + log_debug("Relocating spin table from %lx to %lx (size %x)\n", + (ulong)&acpi_pp_code_start, (ulong)reloc, acpi_pp_code_size); + memcpy(reloc, &acpi_pp_code_start, acpi_pp_code_size); + + if (!CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) + flush_dcache_range((unsigned long)page, + (unsigned long)(page + 1)); +} + +void acpi_write_park(struct acpi_madt *madt) +{ + struct acpi_pp_page *start, *page; + struct acpi_madt_gicc *gicc; + int ret, i, ncpus = 0; + + /* + * According to the "Multi-processor Startup for ARM Platforms": + * - Every CPU as specified by MADT GICC has it's own 4K page + * - Every page is divided into two sections: OS and FW reserved + * - Memory occupied by "Parking Protocol" must be marked 'Reserved' + * - Spinloop code should reside in FW reserved 2048 bytes + * - Spinloop code will check the mailbox in OS reserved area + */ + + if (acpi_pp_code_size > sizeof(page->spinning_code)) { + log_err("Spinning code too big to fit: %d\n", + acpi_pp_code_size); + return; + } + + /* Count all MADT GICCs including BSP */ + for (i = sizeof(struct acpi_madt); i < madt->header.length; + i += gicc->length) { + gicc = (struct acpi_madt_gicc *)((void *)madt + i); + if (gicc->type != ACPI_APIC_GICC) + continue; + ncpus++; + } + log_debug("Found %#x GICCs in MADT\n", ncpus); + + /* Allocate pages linearly due to assembly code requirements */ + start = bloblist_add(BLOBLISTT_ACPI_PP, ACPI_PP_PAGE_SIZE * ncpus, + ilog2(SZ_4K)); + if (!start) { + log_err("Failed to allocate memory for ACPI-parking-protocol pages\n"); + return; + } + log_debug("Allocated parking protocol at %p\n", start); + page = start; + + if (IS_ENABLED(CONFIG_EFI_LOADER)) { + /* Default mapping is 'BOOT CODE'. Mark as reserved instead. */ + ret = efi_add_memory_map((u64)(uintptr_t)start, + ncpus * ACPI_PP_PAGE_SIZE, + EFI_RESERVED_MEMORY_TYPE); + + if (ret) + log_err("Reserved memory mapping failed addr %p size %x\n", + start, ncpus * ACPI_PP_PAGE_SIZE); + } + + /* Prepare the parking protocol pages */ + for (i = sizeof(struct acpi_madt); i < madt->header.length; + i += gicc->length) { + gicc = (struct acpi_madt_gicc *)((void *)madt + i); + if (gicc->type != ACPI_APIC_GICC) + continue; + + acpi_write_pp_setup_one_page(page++, gicc); + } + + acpi_pp_etables = virt_to_phys(start) + + ACPI_PP_PAGE_SIZE * ncpus; + acpi_pp_tables = virt_to_phys(start); + + /* Make sure other cores see written value in memory */ + if (!CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) + flush_dcache_all(); + + /* Send an event to wake up the secondary CPU. */ + asm("dsb ishst\n" + "sev"); +} diff --git a/arch/arm/lib/gic-v2.c b/arch/arm/lib/gic-v2.c new file mode 100644 index 00000000000..b70434a45d4 --- /dev/null +++ b/arch/arm/lib/gic-v2.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Broadcom. + */ +#include <dm.h> +#include <irq.h> +#include <asm/gic.h> +#include <asm/acpi_table.h> +#include <cpu_func.h> +#include <dm/acpi.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> + +#ifdef CONFIG_ACPIGEN +/** + * acpi_gicv2_fill_madt() - Fill out the body of the MADT + * + * Write GICD and GICR tables based on collected devicetree data. + * + * @dev: Device to write ACPI tables for + * @ctx: ACPI context to write MADT sub-tables to + * Return: 0 if OK + */ +static int acpi_gicv2_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + struct acpi_madt_gicd *gicd; + fdt_addr_t addr; + + addr = dev_read_addr_index(dev, 0); + if (addr == FDT_ADDR_T_NONE) { + pr_err("%s: failed to get GICD address\n", __func__); + return -EINVAL; + } + + gicd = ctx->current; + acpi_write_madt_gicd(gicd, dev_seq(dev), addr, 2); + acpi_inc(ctx, gicd->length); + + return 0; +} + +static struct acpi_ops gic_v2_acpi_ops = { + .fill_madt = acpi_gicv2_fill_madt, +}; +#endif + +static const struct udevice_id gic_v2_ids[] = { + { .compatible = "arm,arm11mp-gic" }, + { .compatible = "arm,cortex-a15-gic" }, + { .compatible = "arm,cortex-a7-gic" }, + { .compatible = "arm,cortex-a5-gic" }, + { .compatible = "arm,cortex-a9-gic" }, + { .compatible = "arm,eb11mp-gic" }, + { .compatible = "arm,gic-400" }, + { .compatible = "arm,pl390" }, + { .compatible = "arm,tc11mp-gic" }, + { .compatible = "qcom,msm-8660-qgic" }, + { .compatible = "qcom,msm-qgic2" }, + {} +}; + +static int arm_gic_v2_of_xlate(struct irq *irq, struct ofnode_phandle_args *args) +{ + if (args->args_count != 3) { + log_debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + /* ARM Generic Interrupt Controller v1 and v2 */ + if (args->args[0] == GIC_SPI) + irq->id = args->args[1] + 32; + else + irq->id = args->args[1] + 16; + + irq->flags = args->args[2]; + + return 0; +} + +static const struct irq_ops arm_gic_v2_ops = { + .of_xlate = arm_gic_v2_of_xlate, +}; + +U_BOOT_DRIVER(arm_gic_v2) = { + .name = "gic-v2", + .id = UCLASS_IRQ, + .of_match = gic_v2_ids, + .ops = &arm_gic_v2_ops, + ACPI_OPS_PTR(&gic_v2_acpi_ops) +}; diff --git a/arch/arm/lib/gic-v3-its.c b/arch/arm/lib/gic-v3-its.c index 2cc0a32f9d4..51cc2397768 100644 --- a/arch/arm/lib/gic-v3-its.c +++ b/arch/arm/lib/gic-v3-its.c @@ -4,9 +4,13 @@ */ #include <cpu_func.h> #include <dm.h> +#include <irq.h> +#include <asm/acpi_table.h> #include <asm/gic.h> #include <asm/gic-v3.h> #include <asm/io.h> +#include <dm/acpi.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> #include <linux/bitops.h> #include <linux/printk.h> #include <linux/sizes.h> @@ -26,19 +30,21 @@ static u32 lpi_id_bits; struct gic_v3_its_priv { ulong gicd_base; ulong gicr_base; + ulong gicr_length; }; static int gic_v3_its_get_gic_addr(struct gic_v3_its_priv *priv) { struct udevice *dev; fdt_addr_t addr; + fdt_size_t size; int ret; ret = uclass_get_device_by_driver(UCLASS_IRQ, - DM_DRIVER_GET(arm_gic_v3_its), &dev); + DM_DRIVER_GET(arm_gic_v3), &dev); if (ret) { pr_err("%s: failed to get %s irq device\n", __func__, - DM_DRIVER_GET(arm_gic_v3_its)->name); + DM_DRIVER_GET(arm_gic_v3)->name); return ret; } @@ -49,12 +55,13 @@ static int gic_v3_its_get_gic_addr(struct gic_v3_its_priv *priv) } priv->gicd_base = addr; - addr = dev_read_addr_index(dev, 1); + addr = dev_read_addr_size_index(dev, 1, &size); if (addr == FDT_ADDR_T_NONE) { pr_err("%s: failed to get GICR address\n", __func__); return -EINVAL; } priv->gicr_base = addr; + priv->gicr_length = size; return 0; } @@ -158,13 +165,117 @@ int gic_lpi_tables_init(u64 base, u32 num_redist) return 0; } -static const struct udevice_id gic_v3_its_ids[] = { +#ifdef CONFIG_ACPIGEN +/** + * acpi_gicv3_fill_madt() - Fill out the body of the MADT + * + * Write GICD and GICR tables based on collected devicetree data. + * + * @dev: Device to write ACPI tables for + * @ctx: ACPI context to write MADT sub-tables to + * Return: 0 if OK + */ +static int acpi_gicv3_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + struct acpi_madt_gicd *gicd; + struct acpi_madt_gicr *gicr; + + struct gic_v3_its_priv priv; + + if (gic_v3_its_get_gic_addr(&priv)) + return -EINVAL; + + gicd = ctx->current; + acpi_write_madt_gicd(gicd, dev_seq(dev), priv.gicd_base, 3); + acpi_inc(ctx, gicd->length); + + gicr = ctx->current; + acpi_write_madt_gicr(gicr, priv.gicr_base, priv.gicr_length); + acpi_inc(ctx, gicr->length); + + return 0; +} + +struct acpi_ops gic_v3_acpi_ops = { + .fill_madt = acpi_gicv3_fill_madt, +}; +#endif + +static const struct udevice_id gic_v3_ids[] = { { .compatible = "arm,gic-v3" }, {} }; -U_BOOT_DRIVER(arm_gic_v3_its) = { +static int arm_gic_v3_of_xlate(struct irq *irq, struct ofnode_phandle_args *args) +{ + if (args->args_count < 3) { + log_debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args[0] == GIC_SPI) + irq->id = args->args[1] + 32; + else + irq->id = args->args[1] + 16; + + irq->flags = args->args[2]; + + return 0; +} + +static const struct irq_ops arm_gic_v3_ops = { + .of_xlate = arm_gic_v3_of_xlate, +}; + +U_BOOT_DRIVER(arm_gic_v3) = { .name = "gic-v3", .id = UCLASS_IRQ, + .of_match = gic_v3_ids, + .ops = &arm_gic_v3_ops, + ACPI_OPS_PTR(&gic_v3_acpi_ops) +}; + +#ifdef CONFIG_ACPIGEN +/** + * acpi_gic_its_fill_madt() - Fill out the body of the MADT + * + * Write ITS tables based on collected devicetree data. + * + * @dev: Device to write ACPI tables for + * @ctx: ACPI context to write MADT sub-tables to + * Return: 0 if OK + */ +static int acpi_gic_its_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + struct acpi_madt_its *its; + fdt_addr_t addr; + + addr = dev_read_addr_index(dev, 0); + if (addr == FDT_ADDR_T_NONE) { + pr_err("%s: failed to get GIC ITS address\n", __func__); + return -EINVAL; + } + + its = ctx->current; + acpi_write_madt_its(its, dev_seq(dev), addr); + acpi_inc(ctx, its->length); + + return 0; +} + +struct acpi_ops gic_v3_its_acpi_ops = { + .fill_madt = acpi_gic_its_fill_madt, +}; +#endif + +static const struct udevice_id gic_v3_its_ids[] = { + { .compatible = "arm,gic-v3-its" }, + {} +}; + +U_BOOT_DRIVER(arm_gic_v3_its) = { + .name = "gic-v3-its", + .id = UCLASS_IRQ, .of_match = gic_v3_its_ids, + ACPI_OPS_PTR(&gic_v3_its_acpi_ops) }; diff --git a/arch/arm/mach-bcm283x/Kconfig b/arch/arm/mach-bcm283x/Kconfig index b3287ce8bce..d9303e8c281 100644 --- a/arch/arm/mach-bcm283x/Kconfig +++ b/arch/arm/mach-bcm283x/Kconfig @@ -24,7 +24,13 @@ config BCM2837_64B bool "Broadcom BCM2837 SoC 64-bit support" depends on ARCH_BCM283X select BCM2837 + select DRIVER_GICV2 select ARM64 + select CPU_ARMV8 + select ARMV8_MULTIENTRY if GENERATE_ACPI_TABLE + select BLOBLIST if GENERATE_ACPI_TABLE + select BLOBLIST_ALLOC if GENERATE_ACPI_TABLE + select BLOBLIST_TABLES if GENERATE_ACPI_TABLE config BCM2711 bool "Broadcom BCM2711 SoC support" @@ -42,11 +48,16 @@ config BCM2711_64B bool "Broadcom BCM2711 SoC 64-bit support" depends on ARCH_BCM283X select BCM2711 + select DRIVER_GICV2 select ARM64 + select CPU_ARMV8 + select ARMV8_MULTIENTRY if GENERATE_ACPI_TABLE + select BLOBLIST if GENERATE_ACPI_TABLE + select BLOBLIST_ALLOC if GENERATE_ACPI_TABLE + select BLOBLIST_TABLES if GENERATE_ACPI_TABLE menu "Broadcom BCM283X family" depends on ARCH_BCM283X - choice prompt "Broadcom BCM283X board select" optional @@ -210,6 +221,9 @@ config SYS_SOC config SYS_CONFIG_NAME default "rpi" +config BLOBLIST_SIZE_RELOC + default 0x20000 + source "board/raspberrypi/rpi/Kconfig" endmenu diff --git a/arch/arm/mach-bcm283x/Makefile b/arch/arm/mach-bcm283x/Makefile index 7cd068832f3..38e320307d9 100644 --- a/arch/arm/mach-bcm283x/Makefile +++ b/arch/arm/mach-bcm283x/Makefile @@ -4,3 +4,7 @@ obj-$(CONFIG_BCM2835) += lowlevel_init.o obj-y += init.o reset.o mbox.o msg.o phys2bus.o + +ifeq ($(CONFIG_GENERATE_ACPI_TABLE),y) +obj-$(CONFIG_BCM2711) += bcm2711_acpi.o +endif
\ No newline at end of file diff --git a/arch/arm/mach-bcm283x/bcm2711_acpi.c b/arch/arm/mach-bcm283x/bcm2711_acpi.c new file mode 100644 index 00000000000..79b283353cf --- /dev/null +++ b/arch/arm/mach-bcm283x/bcm2711_acpi.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2024 9elements GmbH + * + * See file CREDITS for list of people who contributed to this + * project. + */ + +#include <string.h> +#include <tables_csum.h> +#include <acpi/acpi_table.h> +#include <asm/acpi_table.h> +#include <asm/armv8/sec_firmware.h> +#include <asm/arch/acpi/bcm2711.h> +#include <dm/uclass.h> + +void acpi_fill_fadt(struct acpi_fadt *fadt) +{ + fadt->flags = ACPI_FADT_HW_REDUCED_ACPI | ACPI_FADT_LOW_PWR_IDLE_S0; + + if (CONFIG_IS_ENABLED(SEC_FIRMWARE_ARMV8_PSCI) && + sec_firmware_support_psci_version() != PSCI_INVALID_VER) + fadt->arm_boot_arch = ACPI_ARM_PSCI_COMPLIANT; +} + +#define L3_ATTRIBUTES (ACPI_PPTT_READ_ALLOC | ACPI_PPTT_WRITE_ALLOC | \ + (ACPI_PPTT_CACHE_TYPE_UNIFIED << \ + ACPI_PPTT_CACHE_TYPE_SHIFT)) +#define L3_SIZE 0x100000 +#define L3_SETS 0x400 +#define L3_WAYS 0x10 + +#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 0xc000 +#define L1I_SETS 0x100 +#define L1I_WAYS 3 + +static int acpi_write_pptt(struct acpi_ctx *ctx, const struct acpi_writer *entry) +{ + struct acpi_table_header *header; + int cluster_offset, l3_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)); + + l3_offset = acpi_pptt_add_cache(ctx, ACPI_PPTT_ALL_VALID, 0, L3_SIZE, + L3_SETS, L3_WAYS, L3_ATTRIBUTES, 64); + + cluster_offset = acpi_pptt_add_proc(ctx, ACPI_PPTT_PHYSICAL_PACKAGE | + ACPI_PPTT_CHILDREN_IDENTICAL, + 0, 0, 1, &l3_offset); + + offsets[0] = acpi_pptt_add_cache(ctx, ACPI_PPTT_ALL_VALID, 0, L1D_SIZE, + L1D_SETS, L1D_WAYS, L1D_ATTRIBUTES, 64); + + offsets[1] = acpi_pptt_add_cache(ctx, ACPI_PPTT_ALL_BUT_WRITE_POL, 0, + 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); + +static int rpi_write_gtdt(struct acpi_ctx *ctx, const struct acpi_writer *entry) +{ + struct acpi_table_header *header; + struct acpi_gtdt *gtdt; + + gtdt = ctx->current; + header = >dt->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 = BCM2711_ARM_LOCAL_BASE_ADDRESS + 0x1c; + 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; + + 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", rpi_write_gtdt, 0); diff --git a/arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h new file mode 100644 index 00000000000..a86875b1833 --- /dev/null +++ b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2711.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: BSD-2-Clause-Patent */ +/** + * + * Copyright (c) 2019, Jeremy Linton + * Copyright (c) 2019, Pete Batard <pete@akeo.ie>. + * + **/ + +#ifndef BCM2711_H__ +#define BCM2711_H__ + +#define BCM2711_SOC_REGISTERS 0xfc000000 +#define BCM2711_SOC_REGISTER_LENGTH 0x02000000 + +#define BCM2711_ARM_LOCAL_REGISTERS 0xfe000000 +#define BCM2711_ARM_LOCAL_REGISTER_LENGTH 0x02000000 + +/* arm local addresses */ +#define BCM2711_ARMC_OFFSET 0x0000b000 +#define BCM2711_ARMC_BASE_ADDRESS (BCM2711_ARM_LOCAL_REGISTERS + BCM2711_ARMC_OFFSET) +#define BCM2711_ARMC_LENGTH 0x00000400 + +#define BCM2711_ARM_LOCAL_OFFSET 0x01800000 +#define BCM2711_ARM_LOCAL_BASE_ADDRESS (BCM2711_ARM_LOCAL_REGISTERS + BCM2711_ARM_LOCAL_OFFSET) +#define BCM2711_ARM_LOCAL_LENGTH 0x00000080 + +#define BCM2711_GIC400_OFFSET 0x01840000 +#define BCM2711_GIC400_BASE_ADDRESS (BCM2711_ARM_LOCAL_REGISTERS + BCM2711_GIC400_OFFSET) +#define BCM2711_GIC400_LENGTH 0x00008000 + +/* Generic PCI addresses */ +#define PCIE_TOP_OF_MEM_WIN 0xf8000000 +#define PCIE_CPU_MMIO_WINDOW 0x600000000 +#define PCIE_BRIDGE_MMIO_LEN 0x3ffffff + +/* PCI root bridge control registers location */ +#define PCIE_REG_BASE 0xfd500000 +#define PCIE_REG_LIMIT 0x9310 + +/* PCI root bridge control registers */ +#define BRCM_PCIE_CAP_REGS 0x00ac +#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 0x0188 +#define VENDOR_SPECIFIC_REG1_LITTLE_ENDIAN 0x0 +#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c +#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc +#define LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00 + +#define PCIE_RC_DL_MDIO_ADDR 0x1100 +#define PCIE_RC_DL_MDIO_WR_DATA 0x1104 +#define PCIE_RC_DL_MDIO_RD_DATA 0x1108 + +#define PCIE_MISC_MISC_CTRL 0x4008 +#define MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000 +#define MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000 +#define MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000 +#define MISC_CTRL_MAX_BURST_SIZE_128 0x0 +#define MISC_CTRL_SCB0_SIZE_MASK 0xf8000000 + +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010 +#define PCIE_MEM_WIN0_LO(win) \ + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 4) + +#define PCIE_MEM_WIN0_HI(win) \ + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 4) +#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c +#define RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f +#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034 +#define RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f +#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038 +#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c +#define RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f +#define PCIE_MISC_PCIE_STATUS 0x4068 +#define STATUS_PCIE_PORT_MASK 0x80 +#define STATUS_PCIE_PORT_SHIFT 7 +#define STATUS_PCIE_DL_ACTIVE_MASK 0x20 +#define STATUS_PCIE_DL_ACTIVE_SHIFT 5 +#define STATUS_PCIE_PHYLINKUP_MASK 0x10 +#define STATUS_PCIE_PHYLINKUP_SHIFT 4 +#define PCIE_MISC_REVISION 0x406c +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070 +#define MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000 +#define MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0 +#define MEM_WIN0_BASE_LIMIT_BASE_HI_SHIFT 12 +#define PCIE_MEM_WIN0_BASE_LIMIT(win) \ + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT + ((win) * 4) +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080 +#define MEM_WIN0_BASE_HI_BASE_MASK 0xff +#define PCIE_MEM_WIN0_BASE_HI(win) \ + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI + ((win) * 8) +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084 +#define PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff +#define PCIE_MEM_WIN0_LIMIT_HI(win) \ + PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8) + +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204 +#define PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 + +#define PCIE_INTR2_CPU_STATUS 0x4300 +#define PCIE_INTR2_CPU_SET 0x4304 +#define PCIE_INTR2_CPU_CLR 0x4308 +#define PCIE_INTR2_CPU_MASK_STATUS 0x430c +#define PCIE_INTR2_CPU_MASK_SET 0x4310 +#define PCIE_INTR2_CPU_MASK_CLR 0x4314 + +#define PCIE_MSI_INTR2_CLR 0x4508 +#define PCIE_MSI_INTR2_MASK_SET 0x4510 + +#define PCIE_RGR1_SW_INIT_1 0x9210 +#define PCIE_EXT_CFG_INDEX 0x9000 +/* A small window pointing at the ECAM of the device selected by CFG_INDEX */ +#define PCIE_EXT_CFG_DATA 0x8000 + +#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc +#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff + +#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000 +#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000 +#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000 +#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000 +#define PCIE_MISC_MISC_CTRL_SCB1_SIZE_MASK 0x7c00000 +#define PCIE_MISC_MISC_CTRL_SCB2_SIZE_MASK 0x1f +#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f + +#define PCIE_RGR1_SW_INIT_1_INIT_MASK 0x2 +#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1 + +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 + +#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2 + +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000 +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0 +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK 0xff +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff +#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_MASK_BITS 0xc + +#define PCIE_MISC_REVISION_MAJMIN_MASK 0xffff + +#define BURST_SIZE_128 0 +#define BURST_SIZE_256 1 +#define BURST_SIZE_512 2 + +#define BCM2711_THERM_SENSOR_OFFSET 0x015d2200 +#define BCM2711_THERM_SENSOR_BASE_ADDRESS (BCM2711_SOC_REGISTERS + BCM2711_THERM_SENSOR_OFFSET) +#define BCM2711_THERM_SENSOR_LENGTH 0x00000008 + +#define BCM2711_GENET_BASE_OFFSET 0x01580000 +#define BCM2711_GENET_BASE_ADDRESS (BCM2711_SOC_REGISTERS + BCM2711_GENET_BASE_OFFSET) +#define BCM2711_GENET_LENGTH 0x10000 + +#endif /* BCM2711_H__ */ diff --git a/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836.h b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836.h new file mode 100644 index 00000000000..64cec36a948 --- /dev/null +++ b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: BSD-2-Clause-Patent */ +/** + * + * Copyright (c) 2019, ARM Limited. All rights reserved. + * Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com> + * Copyright (c) 2016, Linaro Limited. All rights reserved. + * + **/ + +#ifndef __BCM2836_H__ +#define __BCM2836_H__ + +/* + * Both "core" and SoC perpherals (1M each). + */ +#define BCM2836_SOC_REGISTERS 0xfe000000 +#define BCM2836_SOC_REGISTER_LENGTH 0x02000000 + +/* + * Offset between the CPU's view and the VC's view of system memory. + */ +#define BCM2836_DMA_DEVICE_OFFSET 0xc0000000 + +/* watchdog constants */ +#define BCM2836_WDOG_OFFSET 0x00100000 +#define BCM2836_WDOG_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_WDOG_OFFSET) +#define BCM2836_WDOG_PASSWORD 0x5a000000 +#define BCM2836_WDOG_RSTC_OFFSET 0x0000001c +#define BCM2836_WDOG_WDOG_OFFSET 0x00000024 +#define BCM2836_WDOG_RSTC_WRCFG_MASK 0x00000030 +#define BCM2836_WDOG_RSTC_WRCFG_FULL_RESET 0x00000020 + +/* clock manager constants */ +#define BCM2836_CM_OFFSET 0x00101000 +#define BCM2836_CM_BASE (BCM2836_SOC_REGISTERS + BCM2836_CM_OFFSET) +#define BCM2836_CM_GEN_CLOCK_CONTROL 0x0000 +#define BCM2836_CM_GEN_CLOCK_DIVISOR 0x0004 +#define BCM2836_CM_VPU_CLOCK_CONTROL 0x0008 +#define BCM2836_CM_VPU_CLOCK_DIVISOR 0x000c +#define BCM2836_CM_SYSTEM_CLOCK_CONTROL 0x0010 +#define BCM2836_CM_SYSTEM_CLOCK_DIVISOR 0x0014 +#define BCM2836_CM_H264_CLOCK_CONTROL 0x0028 +#define BCM2836_CM_H264_CLOCK_DIVISOR 0x002c +#define BCM2836_CM_PWM_CLOCK_CONTROL 0x00a0 +#define BCM2836_CM_PWM_CLOCK_DIVISOR 0x00a4 +#define BCM2836_CM_UART_CLOCK_CONTROL 0x00f0 +#define BCM2836_CM_UART_CLOCK_DIVISOR 0x00f4 +#define BCM2836_CM_SDC_CLOCK_CONTROL 0x01a8 +#define BCM2836_CM_SDC_CLOCK_DIVISOR 0x01ac +#define BCM2836_CM_ARM_CLOCK_CONTROL 0x01b0 +#define BCM2836_CM_ARM_CLOCK_DIVISOR 0x01b4 +#define BCM2836_CM_EMMC_CLOCK_CONTROL 0x01c0 +#define BCM2836_CM_EMMC_CLOCK_DIVISOR 0x01c4 + +/* mailbox interface constants */ +#define BCM2836_MBOX_OFFSET 0x0000b880 +#define BCM2836_MBOX_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_MBOX_OFFSET) +#define BCM2836_MBOX_LENGTH 0x00000024 +#define BCM2836_MBOX_READ_OFFSET 0x00000000 +#define BCM2836_MBOX_STATUS_OFFSET 0x00000018 +#define BCM2836_MBOX_CONFIG_OFFSET 0x0000001c +#define BCM2836_MBOX_WRITE_OFFSET 0x00000020 + +#define BCM2836_MBOX_STATUS_FULL 0x1f +#define BCM2836_MBOX_STATUS_EMPTY 0x1e + +#define BCM2836_MBOX_NUM_CHANNELS 16 + +/* interrupt controller constants */ +#define BCM2836_INTC_TIMER_CONTROL_OFFSET 0x00000040 +#define BCM2836_INTC_TIMER_PENDING_OFFSET 0x00000060 + +/* usb constants */ +#define BCM2836_USB_OFFSET 0x00980000 +#define BCM2836_USB_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_USB_OFFSET) +#define BCM2836_USB_LENGTH 0x00010000 + +/* serial based protocol constants */ +#define BCM2836_PL011_UART_OFFSET 0x00201000 +#define BCM2836_PL011_UART_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_PL011_UART_OFFSET) +#define BCM2836_PL011_UART_LENGTH 0x00001000 + +#define BCM2836_MINI_UART_OFFSET 0x00215000 +#define BCM2836_MINI_UART_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_MINI_UART_OFFSET) +#define BCM2836_MINI_UART_LENGTH 0x00000070 + +#define BCM2836_I2C0_OFFSET 0x00205000 +#define BCM2836_I2C0_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_I2C0_OFFSET) +#define BCM2836_I2C0_LENGTH 0x00000020 + +#define BCM2836_I2C1_OFFSET 0x00804000 +#define BCM2836_I2C1_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_I2C1_OFFSET) +#define BCM2836_I2C1_LENGTH 0x00000020 + +#define BCM2836_I2C2_OFFSET 0x00805000 +#define BCM2836_I2C2_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_I2C2_OFFSET) +#define BCM2836_I2C2_LENGTH 0x00000020 + +#define BCM2836_SPI0_OFFSET 0x00204000 +#define BCM2836_SPI0_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_SPI0_OFFSET) +#define BCM2836_SPI0_LENGTH 0x00000020 + +#define BCM2836_SPI1_OFFSET 0x00215080 +#define BCM2836_SPI1_LENGTH 0x00000040 +#define BCM2836_SPI1_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_SPI1_OFFSET) + +#define BCM2836_SPI2_OFFSET 0x002150C0 +#define BCM2836_SPI2_LENGTH 0x00000040 +#define BCM2836_SPI2_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_SPI2_OFFSET) + +#define BCM2836_SYSTEM_TIMER_OFFSET 0x00003000 +#define BCM2836_SYSTEM_TIMER_LENGTH 0x00000020 +#define BCM2836_SYSTEM_TIMER_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_SYSTEM_TIMER_OFFSET) + +/* dma constants */ +#define BCM2836_DMA0_OFFSET 0x00007000 +#define BCM2836_DMA0_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_DMA0_OFFSET) + +#define BCM2836_DMA15_OFFSET 0x00E05000 +#define BCM2836_DMA15_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_DMA15_OFFSET) + +#define BCM2836_DMA_CTRL_OFFSET 0x00007FE0 +#define BCM2836_DMA_CTRL_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_DMA_CTRL_OFFSET) + +#define BCM2836_DMA_CHANNEL_LENGTH 0x00000100 + +#endif /*__BCM2836_H__ */ diff --git a/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_gpio.h b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_gpio.h new file mode 100644 index 00000000000..c5b858b412d --- /dev/null +++ b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_gpio.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-2-Clause-Patent */ +/** + * + * Copyright (c) 2020, Pete Batard <pete@akeo.ie> + * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com> + * Copyright (c) Microsoft Corporation. All rights reserved. + * + **/ + +#include <asm/arch/acpi/bcm2836.h> + +#ifndef __BCM2836_GPIO_H__ +#define __BCM2836_GPIO_H__ + +#define GPIO_OFFSET 0x00200000 +#define GPIO_BASE_ADDRESS (BCM2836_SOC_REGISTERS + GPIO_OFFSET) +#define GPIO_LENGTH 0x000000B4 + +#endif /* __BCM2836_GPIO_H__ */ diff --git a/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_gpu.h b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_gpu.h new file mode 100644 index 00000000000..5857d7581a9 --- /dev/null +++ b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_gpu.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: BSD-2-Clause-Patent */ +/** + * + * Copyright (c) 2020, Pete Batard <pete@akeo.ie> + * + **/ + +#include <asm/arch/acpi/bcm2836.h> + +#ifndef __BCM2836_GPU_H__ +#define __BCM2836_GPU_H__ + +/* VideoCore constants */ + +#define BCM2836_VCHIQ_OFFSET 0x0000B840 +#define BCM2836_VCHIQ_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_VCHIQ_OFFSET) +#define BCM2836_VCHIQ_LENGTH 0x00000010 + +#define BCM2836_V3D_BUS_OFFSET 0x00C00000 +#define BCM2836_V3D_BUS_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_V3D_BUS_OFFSET) +#define BCM2836_V3D_BUS_LENGTH 0x00001000 + +#define BCM2836_HVS_OFFSET 0x00400000 +#define BCM2836_HVS_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_HVS_OFFSET) +#define BCM2836_HVS_LENGTH 0x00006000 + +#define BCM2836_PV0_OFFSET 0x00206000 +#define BCM2836_PV0_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_PV0_OFFSET) +#define BCM2836_PV0_LENGTH 0x00000100 + +#define BCM2836_PV1_OFFSET 0x00207000 +#define BCM2836_PV1_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_PV1_OFFSET) +#define BCM2836_PV1_LENGTH 0x00000100 + +#define BCM2836_PV2_OFFSET 0x00807000 +#define BCM2836_PV2_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_PV2_OFFSET) +#define BCM2836_PV2_LENGTH 0x00000100 + +#define BCM2836_HDMI0_OFFSET 0x00902000 +#define BCM2836_HDMI0_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_HDMI0_OFFSET) +#define BCM2836_HDMI0_LENGTH 0x00000600 + +#define BCM2836_HDMI1_OFFSET 0x00808000 +#define BCM2836_HDMI1_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_HDMI1_OFFSET) +#define BCM2836_HDMI1_LENGTH 0x00000100 + +#endif /* __BCM2836_MISC_H__ */ diff --git a/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_pwm.h b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_pwm.h new file mode 100644 index 00000000000..78a84866732 --- /dev/null +++ b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_pwm.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: BSD-2-Clause-Patent */ +/** + * + * Copyright (c) 2020, Pete Batard <pete@akeo.ie> + * + **/ + +#include <asm/arch/acpi/bcm2836.h> + +#ifndef __BCM2836_PWM_H__ +#define __BCM2836_PWM_H__ + +/* PWM controller constants */ + +#define BCM2836_PWM_DMA_OFFSET 0x00007B00 +#define BCM2836_PWM_DMA_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_PWM_DMA_OFFSET) +#define BCM2836_PWM_DMA_LENGTH 0x00000100 + +#define BCM2836_PWM_CLK_OFFSET 0x001010A0 +#define BCM2836_PWM_CLK_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_PWM_CLK_OFFSET) +#define BCM2836_PWM_CLK_LENGTH 0x00000008 + +#define BCM2836_PWM_CTRL_OFFSET 0x0020C000 +#define BCM2836_PWM_CTRL_BASE_ADDRESS (BCM2836_SOC_REGISTERS + BCM2836_PWM_CTRL_OFFSET) +#define BCM2836_PWM_CTRL_LENGTH 0x00000028 + +#define BCM2836_PWM_BUS_BASE_ADDRESS 0x7E20C000 +#define BCM2836_PWM_BUS_LENGTH 0x00000028 + +#define BCM2836_PWM_CTRL_UNCACHED_BASE_ADDRESS 0xFF20C000 +#define BCM2836_PWM_CTRL_UNCACHED_LENGTH 0x00000028 + +#endif /* __BCM2836_PWM_H__ */ diff --git a/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_sdhost.h b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_sdhost.h new file mode 100644 index 00000000000..9b1afe84401 --- /dev/null +++ b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_sdhost.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: BSD-2-Clause-Patent */ +/** + * + * Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com> + * Copyright (c) Microsoft Corporation. All rights reserved. + * + **/ + +#include <asm/arch/acpi/bcm2836.h> + +#ifndef __BCM2836_SDHOST_H__ +#define __BCM2836_SDHOST_H__ + +#define SDHOST_OFFSET 0x00202000 +#define SDHOST_BASE_ADDRESS (BCM2836_SOC_REGISTERS + SDHOST_OFFSET) +#define SDHOST_LENGTH 0x00000100 + +#endif /*__BCM2836_SDHOST_H__ */ diff --git a/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_sdio.h b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_sdio.h new file mode 100644 index 00000000000..48d073d4340 --- /dev/null +++ b/arch/arm/mach-bcm283x/include/mach/acpi/bcm2836_sdio.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: BSD-2-Clause-Patent */ +/** + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * + **/ + +#include <asm/arch/acpi/bcm2836.h> + +#ifndef __BCM2836_SDIO_H__ +#define __BCM2836_SDIO_H__ + +// MMC/SD/SDIO1 register definitions. +#define MMCHS1_OFFSET 0x00300000 +#define MMCHS2_OFFSET 0x00340000 +#define MMCHS1_BASE (BCM2836_SOC_REGISTERS + MMCHS1_OFFSET) +#define MMCHS2_BASE (BCM2836_SOC_REGISTERS + MMCHS2_OFFSET) +#define MMCHS1_LENGTH 0x00000100 +#define MMCHS2_LENGTH 0x00000100 + +#endif /* __BCM2836_SDIO_H__ */ diff --git a/arch/arm/mach-bcm283x/init.c b/arch/arm/mach-bcm283x/init.c index 1b459707bc6..7a1de22e0ae 100644 --- a/arch/arm/mach-bcm283x/init.c +++ b/arch/arm/mach-bcm283x/init.c @@ -50,7 +50,7 @@ static struct mm_region bcm2711_mem_map[MEM_MAP_MAX_ENTRIES] = { }, { .virt = 0xfc000000UL, .phys = 0xfc000000UL, - .size = 0x03800000UL, + .size = 0x04000000UL, .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN diff --git a/arch/arm/mach-qemu/Kconfig b/arch/arm/mach-qemu/Kconfig index 186c3582ebf..9c06c6a3a5c 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/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 9bf44ae3b0b..3017b33d67b 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -527,6 +527,9 @@ }; f-test { + #interrupt-cells = <2>; + interrupt-parent = <&irq>; + interrupts = <4 0>; compatible = "denx,u-boot-fdt-test"; }; diff --git a/arch/sandbox/lib/Makefile b/arch/sandbox/lib/Makefile index d7d15a50bb6..5d7beb250cd 100644 --- a/arch/sandbox/lib/Makefile +++ b/arch/sandbox/lib/Makefile @@ -5,7 +5,8 @@ # (C) Copyright 2002-2006 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -obj-y += fdt_fixup.o interrupts.o -obj-$(CONFIG_PCI) += pci_io.o -obj-$(CONFIG_CMD_BOOTM) += bootm.o -obj-$(CONFIG_CMD_BOOTZ) += bootm.o +obj-y += fdt_fixup.o interrupts.o +obj-$(CONFIG_PCI) += pci_io.o +obj-$(CONFIG_CMD_BOOTM) += bootm.o +obj-$(CONFIG_CMD_BOOTZ) += bootm.o +obj-$(CONFIG_$(SPL_)ACPIGEN) += acpi_table.o diff --git a/arch/sandbox/lib/acpi_table.c b/arch/sandbox/lib/acpi_table.c new file mode 100644 index 00000000000..90bb96d1e35 --- /dev/null +++ b/arch/sandbox/lib/acpi_table.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include <acpi/acpi_table.h> + +void acpi_fill_fadt(struct acpi_fadt *fadt) +{ +} + +void *acpi_fill_madt(struct acpi_madt *madt, struct acpi_ctx *ctx) +{ + return ctx->current; +} diff --git a/arch/x86/cpu/apollolake/acpi.c b/arch/x86/cpu/apollolake/acpi.c index 76230aea837..93040e7bb37 100644 --- a/arch/x86/cpu/apollolake/acpi.c +++ b/arch/x86/cpu/apollolake/acpi.c @@ -128,8 +128,10 @@ int arch_madt_sci_irq_polarity(int sci) return MP_IRQ_POLARITY_LOW; } -void fill_fadt(struct acpi_fadt *fadt) +void acpi_fill_fadt(struct acpi_fadt *fadt) { + intel_acpi_fill_fadt(fadt); + fadt->pm_tmr_blk = IOMAP_ACPI_BASE + PM1_TMR; fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED; @@ -143,23 +145,9 @@ void fill_fadt(struct acpi_fadt *fadt) fadt->x_pm_tmr_blk.space_id = 1; fadt->x_pm_tmr_blk.bit_width = fadt->pm_tmr_len * 8; fadt->x_pm_tmr_blk.addrl = IOMAP_ACPI_BASE + PM1_TMR; -} - -static int apl_write_fadt(struct acpi_ctx *ctx, const struct acpi_writer *entry) -{ - struct acpi_table_header *header; - struct acpi_fadt *fadt; - - fadt = ctx->current; - acpi_fadt_common(fadt, ctx->facs, ctx->dsdt); - intel_acpi_fill_fadt(fadt); - fill_fadt(fadt); - header = &fadt->header; - header->checksum = table_compute_checksum(fadt, header->length); - return acpi_add_fadt(ctx, fadt); + fadt->preferred_pm_profile = ACPI_PM_MOBILE; } -ACPI_WRITER(5fadt, "FADT", apl_write_fadt, 0); int apl_acpi_fill_dmar(struct acpi_ctx *ctx) { diff --git a/arch/x86/cpu/baytrail/acpi.c b/arch/x86/cpu/baytrail/acpi.c index 7821964f1fc..7e1c2de3d39 100644 --- a/arch/x86/cpu/baytrail/acpi.c +++ b/arch/x86/cpu/baytrail/acpi.c @@ -15,20 +15,13 @@ #include <asm/arch/iomap.h> #include <dm/uclass-internal.h> -static int baytrail_write_fadt(struct acpi_ctx *ctx, - const struct acpi_writer *entry) +void acpi_fill_fadt(struct acpi_fadt *fadt) { struct acpi_table_header *header; - struct acpi_fadt *fadt; - fadt = ctx->current; header = &fadt->header; u16 pmbase = ACPI_BASE_ADDRESS; - memset(fadt, '\0', sizeof(struct acpi_fadt)); - - acpi_fill_header(header, "FACP"); - header->length = sizeof(struct acpi_fadt); header->revision = 4; fadt->preferred_pm_profile = ACPI_PM_MOBILE; @@ -77,9 +70,6 @@ static int baytrail_write_fadt(struct acpi_ctx *ctx, fadt->reset_reg.addrh = 0; fadt->reset_value = SYS_RST | RST_CPU | FULL_RST; - fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs); - fadt->x_dsdt = map_to_sysmem(ctx->dsdt); - fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO; fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8; fadt->x_pm1a_evt_blk.bit_offset = 0; @@ -135,12 +125,7 @@ static int baytrail_write_fadt(struct acpi_ctx *ctx, fadt->x_gpe1_blk.access_size = 0; fadt->x_gpe1_blk.addrl = 0x0; fadt->x_gpe1_blk.addrh = 0x0; - - header->checksum = table_compute_checksum(fadt, header->length); - - return acpi_add_fadt(ctx, fadt); } -ACPI_WRITER(5fadt, "FADT", baytrail_write_fadt, 0); int acpi_create_gnvs(struct acpi_global_nvs *gnvs) { diff --git a/arch/x86/cpu/intel_common/acpi.c b/arch/x86/cpu/intel_common/acpi.c index 29676b4abfa..982149b394e 100644 --- a/arch/x86/cpu/intel_common/acpi.c +++ b/arch/x86/cpu/intel_common/acpi.c @@ -19,6 +19,7 @@ #include <asm/global_data.h> #include <asm/intel_acpi.h> #include <asm/ioapic.h> +#include <asm/lapic.h> #include <asm/mpspec.h> #include <asm/smm.h> #include <asm/turbo.h> @@ -80,33 +81,40 @@ static int acpi_sci_irq(void) return sci_irq; } -static unsigned long acpi_madt_irq_overrides(unsigned long current) +static void *acpi_madt_irq_overrides(void *current) { int sci = acpi_sci_irq(); u16 flags = MP_IRQ_TRIGGER_LEVEL; - if (sci < 0) - return log_msg_ret("sci irq", sci); + if (sci < 0) { + log_err("sci irq %d", sci); + return current; + } /* INT_SRC_OVR */ - current += acpi_create_madt_irqoverride((void *)current, 0, 0, 2, 0); + current += acpi_create_madt_irqoverride(current, 0, 0, 2, 0); flags |= arch_madt_sci_irq_polarity(sci); /* SCI */ current += - acpi_create_madt_irqoverride((void *)current, 0, sci, sci, flags); + acpi_create_madt_irqoverride(current, 0, sci, sci, flags); return current; } -u32 acpi_fill_madt(u32 current) +void *acpi_fill_madt(struct acpi_madt *madt, struct acpi_ctx *ctx) { + void *current = ctx->current; + + madt->lapic_addr = LAPIC_DEFAULT_BASE; + madt->flags = ACPI_MADT_PCAT_COMPAT; + /* Local APICs */ current += acpi_create_madt_lapics(current); /* IOAPIC */ - current += acpi_create_madt_ioapic((void *)current, 2, IO_APIC_ADDR, 0); + current += acpi_create_madt_ioapic(current, 2, IO_APIC_ADDR, 0); return acpi_madt_irq_overrides(current); } diff --git a/arch/x86/cpu/quark/acpi.c b/arch/x86/cpu/quark/acpi.c index 80e94600fc5..0fe5f2bafb4 100644 --- a/arch/x86/cpu/quark/acpi.c +++ b/arch/x86/cpu/quark/acpi.c @@ -11,23 +11,14 @@ #include <asm/arch/iomap.h> #include <linux/string.h> -static int quark_write_fadt(struct acpi_ctx *ctx, - const struct acpi_writer *entry) +void acpi_fill_fadt(struct acpi_fadt *fadt) { u16 pmbase = ACPI_PM1_BASE_ADDRESS; struct acpi_table_header *header; - struct acpi_fadt *fadt; - fadt = ctx->current; header = &fadt->header; - - memset(fadt, '\0', sizeof(struct acpi_fadt)); - - acpi_fill_header(header, "FACP"); - header->length = sizeof(struct acpi_fadt); header->revision = 4; - fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED; fadt->sci_int = 9; fadt->smi_cmd = 0; fadt->acpi_enable = 0; @@ -73,9 +64,6 @@ static int quark_write_fadt(struct acpi_ctx *ctx, fadt->reset_reg.addrh = 0; fadt->reset_value = SYS_RST | RST_CPU | FULL_RST; - fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs); - fadt->x_dsdt = map_to_sysmem(ctx->dsdt); - fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO; fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8; fadt->x_pm1a_evt_blk.bit_offset = 0; @@ -131,12 +119,7 @@ static int quark_write_fadt(struct acpi_ctx *ctx, fadt->x_gpe1_blk.access_size = 0; fadt->x_gpe1_blk.addrl = 0x0; fadt->x_gpe1_blk.addrh = 0x0; - - header->checksum = table_compute_checksum(fadt, header->length); - - return acpi_add_fadt(ctx, fadt); } -ACPI_WRITER(5fadt, "FADT", quark_write_fadt, 0); int acpi_create_gnvs(struct acpi_global_nvs *gnvs) { diff --git a/arch/x86/cpu/tangier/acpi.c b/arch/x86/cpu/tangier/acpi.c index d4d0ef6f855..8ea764f7cc1 100644 --- a/arch/x86/cpu/tangier/acpi.c +++ b/arch/x86/cpu/tangier/acpi.c @@ -10,27 +10,15 @@ #include <mapmem.h> #include <acpi/acpi_table.h> #include <asm/ioapic.h> +#include <asm/lapic.h> #include <asm/mpspec.h> #include <asm/tables.h> #include <asm/arch/global_nvs.h> #include <asm/arch/iomap.h> #include <dm/uclass-internal.h> -static int tangier_write_fadt(struct acpi_ctx *ctx, - const struct acpi_writer *entry) +void acpi_fill_fadt(struct acpi_fadt *fadt) { - struct acpi_table_header *header; - struct acpi_fadt *fadt; - - fadt = ctx->current; - header = &fadt->header; - - memset(fadt, '\0', sizeof(struct acpi_fadt)); - - acpi_fill_header(header, "FACP"); - header->length = sizeof(struct acpi_fadt); - header->revision = 6; - fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED; fadt->iapc_boot_arch = ACPI_FADT_VGA_NOT_PRESENT | @@ -40,20 +28,15 @@ static int tangier_write_fadt(struct acpi_ctx *ctx, ACPI_FADT_POWER_BUTTON | ACPI_FADT_SLEEP_BUTTON | ACPI_FADT_SEALED_CASE | ACPI_FADT_HEADLESS | ACPI_FADT_HW_REDUCED_ACPI; - - fadt->minor_revision = 2; - - fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs); - fadt->x_dsdt = map_to_sysmem(ctx->dsdt); - - header->checksum = table_compute_checksum(fadt, header->length); - - return acpi_add_fadt(ctx, fadt); } -ACPI_WRITER(5fadt, "FADT", tangier_write_fadt, 0); -u32 acpi_fill_madt(u32 current) +void *acpi_fill_madt(struct acpi_madt *madt, struct acpi_ctx *ctx) { + void *current = ctx->current; + + madt->lapic_addr = LAPIC_DEFAULT_BASE; + madt->flags = ACPI_MADT_PCAT_COMPAT; + current += acpi_create_madt_lapics(current); current += acpi_create_madt_ioapic((struct acpi_madt_ioapic *)current, diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h index 57e41654ce3..ff60384e620 100644 --- a/arch/x86/include/asm/acpi_table.h +++ b/arch/x86/include/asm/acpi_table.h @@ -24,16 +24,13 @@ struct acpi_table_header; /* These can be used by the target port */ -int acpi_create_madt_lapics(u32 current); +int acpi_create_madt_lapics(void *current); int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr, u32 gsi_base); int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride, u8 bus, u8 source, u32 gsirq, u16 flags); int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, u8 cpu, u16 flags, u8 lint); -u32 acpi_fill_madt(u32 current); -int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, u32 base, - u16 seg_nr, u8 start, u8 end); /** * acpi_write_hpet() - Write out a HPET table @@ -46,17 +43,6 @@ int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, u32 base, int acpi_write_hpet(struct acpi_ctx *ctx); /** - * acpi_write_dbg2_pci_uart() - Write out a DBG2 table - * - * @ctx: Current ACPI context - * @dev: Debug UART device to describe - * @access_size: Access size for UART (e.g. ACPI_ACCESS_SIZE_DWORD_ACCESS) - * Return: 0 if OK, -ve on error - */ -int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev, - uint access_size); - -/** * acpi_create_gnvs() - Create a GNVS (Global Non Volatile Storage) table * * @gnvs: Table to fill in @@ -180,18 +166,6 @@ int acpi_create_dmar_ds_msi_hpet(struct acpi_ctx *ctx, uint enumeration_id, pci_dev_t bdf); /** - * acpi_fadt_common() - Handle common parts of filling out an FADT - * - * This sets up the Fixed ACPI Description Table - * - * @fadt: Pointer to place to put FADT - * @facs: Pointer to the FACS - * @dsdt: Pointer to the DSDT - */ -void acpi_fadt_common(struct acpi_fadt *fadt, struct acpi_facs *facs, - void *dsdt); - -/** * intel_acpi_fill_fadt() - Set up the contents of the FADT * * This sets up parts of the Fixed ACPI Description Table that are common to diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index e38ce19ff7c..3186e48d63b 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -40,7 +40,7 @@ static int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic, return lapic->length; } -int acpi_create_madt_lapics(u32 current) +int acpi_create_madt_lapics(void *current) { struct udevice *dev; int total_length = 0; @@ -100,23 +100,28 @@ int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, return lapic_nmi->length; } -static int acpi_create_madt_irq_overrides(u32 current) +static int acpi_create_madt_irq_overrides(void *current) { struct acpi_madt_irqoverride *irqovr; u16 sci_flags = MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_HIGH; int length = 0; - irqovr = (void *)current; + irqovr = current; length += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0); - irqovr = (void *)(current + length); + irqovr = current + length; length += acpi_create_madt_irqoverride(irqovr, 0, 9, 9, sci_flags); return length; } -__weak u32 acpi_fill_madt(u32 current) +__weak void *acpi_fill_madt(struct acpi_madt *madt, struct acpi_ctx *ctx) { + void *current = ctx->current; + + madt->lapic_addr = LAPIC_DEFAULT_BASE; + madt->flags = ACPI_MADT_PCAT_COMPAT; + current += acpi_create_madt_lapics(current); current += acpi_create_madt_ioapic((struct acpi_madt_ioapic *)current, @@ -127,39 +132,6 @@ __weak u32 acpi_fill_madt(u32 current) return current; } -int acpi_write_madt(struct acpi_ctx *ctx, const struct acpi_writer *entry) -{ - struct acpi_table_header *header; - struct acpi_madt *madt; - u32 current; - - madt = ctx->current; - - memset(madt, '\0', sizeof(struct acpi_madt)); - header = &madt->header; - - /* Fill out header fields */ - acpi_fill_header(header, "APIC"); - header->length = sizeof(struct acpi_madt); - header->revision = ACPI_MADT_REV_ACPI_3_0; - - madt->lapic_addr = LAPIC_DEFAULT_BASE; - madt->flags = ACPI_MADT_PCAT_COMPAT; - - current = (u32)madt + sizeof(struct acpi_madt); - current = acpi_fill_madt(current); - - /* (Re)calculate length and checksum */ - header->length = current - (u32)madt; - - header->checksum = table_compute_checksum((void *)madt, header->length); - acpi_add_table(ctx, madt); - acpi_inc(ctx, madt->header.length); - - return 0; -} -ACPI_WRITER(5x86, NULL, acpi_write_madt, 0); - /** * acpi_create_tcpa() - Create a TCPA table * @@ -279,140 +251,6 @@ static int acpi_write_tpm2(struct acpi_ctx *ctx, } ACPI_WRITER(5tpm2, "TPM2", acpi_write_tpm2, 0); -int acpi_write_spcr(struct acpi_ctx *ctx, const struct acpi_writer *entry) -{ - struct serial_device_info serial_info = {0}; - ulong serial_address, serial_offset; - struct acpi_table_header *header; - struct acpi_spcr *spcr; - struct udevice *dev; - uint serial_config; - uint serial_width; - int access_size; - int space_id; - int ret = -ENODEV; - - spcr = ctx->current; - header = &spcr->header; - - memset(spcr, '\0', sizeof(struct acpi_spcr)); - - /* Fill out header fields */ - acpi_fill_header(header, "SPCR"); - header->length = sizeof(struct acpi_spcr); - header->revision = 2; - - /* Read the device once, here. It is reused below */ - dev = gd->cur_serial_dev; - if (dev) - ret = serial_getinfo(dev, &serial_info); - if (ret) - serial_info.type = SERIAL_CHIP_UNKNOWN; - - /* Encode chip type */ - switch (serial_info.type) { - case SERIAL_CHIP_16550_COMPATIBLE: - spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE; - break; - case SERIAL_CHIP_UNKNOWN: - default: - spcr->interface_type = ACPI_DBG2_UNKNOWN; - break; - } - - /* Encode address space */ - switch (serial_info.addr_space) { - case SERIAL_ADDRESS_SPACE_MEMORY: - space_id = ACPI_ADDRESS_SPACE_MEMORY; - break; - case SERIAL_ADDRESS_SPACE_IO: - default: - space_id = ACPI_ADDRESS_SPACE_IO; - break; - } - - serial_width = serial_info.reg_width * 8; - serial_offset = serial_info.reg_offset << serial_info.reg_shift; - serial_address = serial_info.addr + serial_offset; - - /* Encode register access size */ - switch (serial_info.reg_shift) { - case 0: - access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS; - break; - case 1: - access_size = ACPI_ACCESS_SIZE_WORD_ACCESS; - break; - case 2: - access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS; - break; - case 3: - access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS; - break; - default: - access_size = ACPI_ACCESS_SIZE_UNDEFINED; - break; - } - - debug("UART type %u @ %lx\n", spcr->interface_type, serial_address); - - /* Fill GAS */ - spcr->serial_port.space_id = space_id; - spcr->serial_port.bit_width = serial_width; - spcr->serial_port.bit_offset = 0; - spcr->serial_port.access_size = access_size; - spcr->serial_port.addrl = lower_32_bits(serial_address); - spcr->serial_port.addrh = upper_32_bits(serial_address); - - /* Encode baud rate */ - switch (serial_info.baudrate) { - case 9600: - spcr->baud_rate = 3; - break; - case 19200: - spcr->baud_rate = 4; - break; - case 57600: - spcr->baud_rate = 6; - break; - case 115200: - spcr->baud_rate = 7; - break; - default: - spcr->baud_rate = 0; - break; - } - - serial_config = SERIAL_DEFAULT_CONFIG; - if (dev) - ret = serial_getconfig(dev, &serial_config); - - spcr->parity = SERIAL_GET_PARITY(serial_config); - spcr->stop_bits = SERIAL_GET_STOP(serial_config); - - /* No PCI devices for now */ - spcr->pci_device_id = 0xffff; - spcr->pci_vendor_id = 0xffff; - - /* - * SPCR has no clue if the UART base clock speed is different - * to the default one. However, the SPCR 1.04 defines baud rate - * 0 as a preconfigured state of UART and OS is supposed not - * to touch the configuration of the serial device. - */ - if (serial_info.clock != SERIAL_DEFAULT_CLOCK) - spcr->baud_rate = 0; - - /* Fix checksum */ - header->checksum = table_compute_checksum((void *)spcr, header->length); - - acpi_add_table(ctx, spcr); - acpi_inc(ctx, spcr->header.length); - - return 0; -} -ACPI_WRITER(5spcr, "SPCR", acpi_write_spcr, 0); - int acpi_write_gnvs(struct acpi_ctx *ctx, const struct acpi_writer *entry) { ulong addr; @@ -515,69 +353,6 @@ int acpi_write_hpet(struct acpi_ctx *ctx) return 0; } -int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev, - uint access_size) -{ - struct acpi_dbg2_header *dbg2 = ctx->current; - char path[ACPI_PATH_MAX]; - struct acpi_gen_regaddr address; - phys_addr_t addr; - int ret; - - if (!device_active(dev)) { - log_info("Device not enabled\n"); - return -EACCES; - } - /* - * PCI devices don't remember their resource allocation information in - * U-Boot at present. We assume that MMIO is used for the UART and that - * the address space is 32 bytes: ns16550 uses 8 registers of up to - * 32-bits each. This is only for debugging so it is not a big deal. - */ - addr = dm_pci_read_bar32(dev, 0); - log_debug("UART addr %lx\n", (ulong)addr); - - memset(&address, '\0', sizeof(address)); - address.space_id = ACPI_ADDRESS_SPACE_MEMORY; - address.addrl = (uint32_t)addr; - address.addrh = (uint32_t)((addr >> 32) & 0xffffffff); - address.access_size = access_size; - - ret = acpi_device_path(dev, path, sizeof(path)); - if (ret) - return log_msg_ret("path", ret); - acpi_create_dbg2(dbg2, ACPI_DBG2_SERIAL_PORT, - ACPI_DBG2_16550_COMPATIBLE, &address, 0x1000, path); - - acpi_inc_align(ctx, dbg2->header.length); - acpi_add_table(ctx, dbg2); - - return 0; -} - -void acpi_fadt_common(struct acpi_fadt *fadt, struct acpi_facs *facs, - void *dsdt) -{ - struct acpi_table_header *header = &fadt->header; - - memset((void *)fadt, '\0', sizeof(struct acpi_fadt)); - - acpi_fill_header(header, "FACP"); - header->length = sizeof(struct acpi_fadt); - header->revision = 4; - memcpy(header->oem_id, OEM_ID, 6); - memcpy(header->oem_table_id, OEM_TABLE_ID, 8); - memcpy(header->creator_id, ASLC_ID, 4); - - fadt->x_firmware_ctrl = map_to_sysmem(facs); - fadt->x_dsdt = map_to_sysmem(dsdt); - - fadt->preferred_pm_profile = ACPI_PM_MOBILE; - - /* Use ACPI 3.0 revision */ - fadt->header.revision = 4; -} - void acpi_create_dmar_drhd(struct acpi_ctx *ctx, uint flags, uint segment, u64 bar) { diff --git a/board/emulation/qemu-arm/MAINTAINERS b/board/emulation/qemu-arm/MAINTAINERS index 5154262f29e..7bc0ee698c5 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 00000000000..72c76b351fa --- /dev/null +++ b/board/emulation/qemu-sbsa/Kconfig @@ -0,0 +1,59 @@ +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 BLOBLIST + 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 00000000000..bacae320e79 --- /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 00000000000..ba85e08fc7d --- /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 = >dt->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 00000000000..f12cca04e2c --- /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 00000000000..c997721af95 --- /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@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 00000000000..3943c924320 --- /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 00000000000..88fdb0ec1c5 --- /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 00000000000..391a70bdc40 --- /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 00000000000..9a2d091bea6 --- /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/board/raspberrypi/rpi/.gitignore b/board/raspberrypi/rpi/.gitignore new file mode 100644 index 00000000000..39e46ba0ae7 --- /dev/null +++ b/board/raspberrypi/rpi/.gitignore @@ -0,0 +1,3 @@ +dsdt_generated.aml +dsdt_generated.asl.tmp +dsdt_generated.c diff --git a/board/raspberrypi/rpi/Makefile b/board/raspberrypi/rpi/Makefile index b1186cdf100..bb1b7cc630f 100644 --- a/board/raspberrypi/rpi/Makefile +++ b/board/raspberrypi/rpi/Makefile @@ -4,3 +4,5 @@ obj-y := rpi.o obj-y += lowlevel_init.o + +obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt_generated.o diff --git a/board/raspberrypi/rpi/acpitables.h b/board/raspberrypi/rpi/acpitables.h new file mode 100644 index 00000000000..3ba8f19808c --- /dev/null +++ b/board/raspberrypi/rpi/acpitables.h @@ -0,0 +1,90 @@ +/** @file + * + * RPi defines for constructing ACPI tables + * + * Copyright (c) 2020, Pete Batard <pete@akeo.ie> + * Copyright (c) 2019, ARM Ltd. All rights reserved. + * Copyright (c) 2018, Andrei Warkentin <andrey.warkentin@gmail.com> + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __RPI_ACPITABLES_H__ +#define __RPI_ACPITABLES_H__ + +#include <acpi/acpi_table.h> + +// The ASL compiler can't perform arithmetic on MEMORY32FIXED () +// parameters so you can't pass a constant like BASE + OFFSET. +// We therefore define a macro that can perform arithmetic base +// address update with an offset. +#define MEMORY32SETBASE(BufName, MemName, VarName, Offset) \ + CreateDwordField (^BufName, ^MemName._BAS, VarName) \ + Add (BCM2836_SOC_REGISTERS, Offset, VarName) + +//------------------------------------------------------------------------ +// Interrupts. These are specific to each platform +//------------------------------------------------------------------------ +#if defined(CONFIG_TARGET_RPI_3) +#define BCM2836_V3D_BUS_INTERRUPT 0x2A +#define BCM2836_DMA_INTERRUPT 0x3B +#define BCM2836_SPI1_INTERRUPT 0x3D +#define BCM2836_SPI2_INTERRUPT 0x3D +#define BCM2836_HVS_INTERRUPT 0x41 +#define BCM2836_HDMI0_INTERRUPT 0x48 +#define BCM2836_HDMI1_INTERRUPT 0x49 +#define BCM2836_PV2_INTERRUPT 0x4A +#define BCM2836_PV0_INTERRUPT 0x4D +#define BCM2836_PV1_INTERRUPT 0x4E +#define BCM2836_MBOX_INTERRUPT 0x61 +#define BCM2836_VCHIQ_INTERRUPT 0x62 +#define BCM2386_GPIO_INTERRUPT0 0x51 +#define BCM2386_GPIO_INTERRUPT1 0x52 +#define BCM2386_GPIO_INTERRUPT2 0x53 +#define BCM2386_GPIO_INTERRUPT3 0x54 +#define BCM2836_I2C1_INTERRUPT 0x55 +#define BCM2836_I2C2_INTERRUPT 0x55 +#define BCM2836_SPI0_INTERRUPT 0x56 +#define BCM2836_USB_INTERRUPT 0x29 +#define BCM2836_SDHOST_INTERRUPT 0x58 +#define BCM2836_MMCHS1_INTERRUPT 0x5E +#define BCM2836_MINI_UART_INTERRUPT 0x3D +#define BCM2836_PL011_UART_INTERRUPT 0x59 +#elif defined(CONFIG_TARGET_RPI_4) +#define BCM2836_V3D_BUS_INTERRUPT 0x2A +#define BCM2836_DMA_INTERRUPT 0x3B +#define BCM2836_SPI1_INTERRUPT 0x7D +#define BCM2836_SPI2_INTERRUPT 0x7D +#define BCM2836_HVS_INTERRUPT 0x41 +#define BCM2836_HDMI0_INTERRUPT 0x48 +#define BCM2836_HDMI1_INTERRUPT 0x49 +#define BCM2836_PV2_INTERRUPT 0x4A +#define BCM2836_PV0_INTERRUPT 0x4D +#define BCM2836_PV1_INTERRUPT 0x4E +#define BCM2836_MBOX_INTERRUPT 0x41 +#define BCM2836_VCHIQ_INTERRUPT 0x42 +#define BCM2386_GPIO_INTERRUPT0 0x91 +#define BCM2386_GPIO_INTERRUPT1 0x92 +#define BCM2386_GPIO_INTERRUPT2 0x93 +#define BCM2386_GPIO_INTERRUPT3 0x94 +#define BCM2836_I2C1_INTERRUPT 0x95 +#define BCM2836_I2C2_INTERRUPT 0x95 +#define BCM2836_SPI0_INTERRUPT 0x96 +#define BCM2836_USB_INTERRUPT 0x69 +#define BCM2836_SDHOST_INTERRUPT 0x98 +#define BCM2836_MMCHS1_INTERRUPT 0x9E +#define BCM2836_MINI_UART_INTERRUPT 0x7D +#define BCM2836_PL011_UART_INTERRUPT 0x99 +#define GENET_INTERRUPT0 0xBD +#define GENET_INTERRUPT1 0xBE +#define GENET_BASE_ADDRESS 0xFD580000 +#define GENET_LENGTH 0x10000 +#define THERM_SENSOR_BASE_ADDRESS 0xFD5d2200 +#define THERM_SENSOR_LENGTH 0x8 +#else +#error "Unsupported rpi module for ACPI tables" +#endif + +#endif // __ACPITABLES_H__ diff --git a/board/raspberrypi/rpi/dsdt.asl b/board/raspberrypi/rpi/dsdt.asl new file mode 100644 index 00000000000..c89b08d5ea1 --- /dev/null +++ b/board/raspberrypi/rpi/dsdt.asl @@ -0,0 +1,254 @@ +/** @file + * + * Differentiated System Definition Table (DSDT) + * + * Copyright (c) 2020, Pete Batard <pete@akeo.ie> + * Copyright (c) 2018-2020, Andrey Warkentin <andrey.warkentin@gmail.com> + * Copyright (c) Microsoft Corporation. All rights reserved. + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include <asm/arch/acpi/bcm2711.h> +#include <asm/arch/acpi/bcm2836.h> +#include <asm/arch/acpi/bcm2836_gpio.h> +#include <asm/arch/acpi/bcm2836_gpu.h> +#include <asm/arch/acpi/bcm2836_pwm.h> +#include <asm/arch/acpi/bcm2836_sdio.h> +#include <asm/arch/acpi/bcm2836_sdhost.h> + +#include "acpitables.h" + +#define BCM_ALT0 0x4 +#define BCM_ALT1 0x5 +#define BCM_ALT2 0x6 +#define BCM_ALT3 0x7 +#define BCM_ALT4 0x3 +#define BCM_ALT5 0x2 + +// +// The ASL compiler does not support argument arithmetic in functions +// like QWordMemory (). So we need to instantiate dummy qword regions +// that we can then update the Min, Max and Length attributes of. +// The three macros below help accomplish this. +// +// QWORDMEMORYSET specifies a CPU memory range (whose base address is +// BCM2836_SOC_REGISTERS + Offset), and QWORDBUSMEMORYSET specifies +// a VPU memory range (whose base address is provided directly). +// +#define QWORDMEMORYBUF(Index) \ + QWordMemory (ResourceProducer,, \ + MinFixed, MaxFixed, NonCacheable, ReadWrite, \ + 0x0, 0x0, 0x0, 0x0, 0x1,,, RB ## Index) + +#define QWORDMEMORYSET(Index, Offset, Length) \ + CreateQwordField (RBUF, RB ## Index._MIN, MI ## Index) \ + CreateQwordField (RBUF, RB ## Index._MAX, MA ## Index) \ + CreateQwordField (RBUF, RB ## Index._LEN, LE ## Index) \ + Store (Length, LE ## Index) \ + Add (BCM2836_SOC_REGISTERS, Offset, MI ## Index) \ + Add (MI ## Index, LE ## Index - 1, MA ## Index) + +#define QWORDBUSMEMORYSET(Index, Base, Length) \ + CreateQwordField (RBUF, RB ## Index._MIN, MI ## Index) \ + CreateQwordField (RBUF, RB ## Index._MAX, MA ## Index) \ + CreateQwordField (RBUF, RB ## Index._LEN, LE ## Index) \ + Store (Base, MI ## Index) \ + Store (Length, LE ## Index) \ + Add (MI ## Index, LE ## Index - 1, MA ## Index) + +DefinitionBlock ("Dsdt.aml", "DSDT", 2, "RPIFDN", "RPI", 2) +{ + External (\_PR.CP00, DeviceObj) + External (\_PR.CP01, DeviceObj) + External (\_PR.CP02, DeviceObj) + External (\_PR.CP03, DeviceObj) + Scope (\_SB_) + { + include ("pep.asl") + + // + // GPU device container describes the DMA translation required + // when a device behind the GPU wants to access Arm memory. + // Only the first GB can be addressed. + // + Device (GDV0) + { + Name (_HID, "ACPI0004") + Name (_UID, 0x1) + Name (_CCA, 0x0) + + Method (_CRS, 0, Serialized) { + // + // Container devices with _DMA must have _CRS, meaning GDV0 + // to provide all resources that GpuDevs.asl consume (except + // interrupts). + // + Name (RBUF, ResourceTemplate () { + QWORDMEMORYBUF(01) + QWORDMEMORYBUF(02) + QWORDMEMORYBUF(03) + // QWORDMEMORYBUF(04) + // QWORDMEMORYBUF(05) + QWORDMEMORYBUF(06) + QWORDMEMORYBUF(07) + QWORDMEMORYBUF(08) + QWORDMEMORYBUF(09) + QWORDMEMORYBUF(10) + QWORDMEMORYBUF(11) + QWORDMEMORYBUF(12) + QWORDMEMORYBUF(13) + QWORDMEMORYBUF(14) + QWORDMEMORYBUF(15) + // QWORDMEMORYBUF(16) + QWORDMEMORYBUF(17) + QWORDMEMORYBUF(18) + QWORDMEMORYBUF(19) + QWORDMEMORYBUF(20) + QWORDMEMORYBUF(21) + QWORDMEMORYBUF(22) + QWORDMEMORYBUF(23) + QWORDMEMORYBUF(24) + QWORDMEMORYBUF(25) + }) + + // USB + QWORDMEMORYSET(01, BCM2836_USB_OFFSET, BCM2836_USB_LENGTH) + + // GPU + QWORDMEMORYSET(02, BCM2836_V3D_BUS_OFFSET, BCM2836_V3D_BUS_LENGTH) + QWORDMEMORYSET(03, BCM2836_HVS_OFFSET, BCM2836_HVS_LENGTH) + // QWORDMEMORYSET(04, BCM2836_PV0_OFFSET, BCM2836_PV0_LENGTH) + // QWORDMEMORYSET(05, BCM2836_PV1_OFFSET, BCM2836_PV1_LENGTH) + QWORDMEMORYSET(06, BCM2836_PV2_OFFSET, BCM2836_PV2_LENGTH) + QWORDMEMORYSET(07, BCM2836_HDMI0_OFFSET, BCM2836_HDMI0_LENGTH) + QWORDMEMORYSET(08, BCM2836_HDMI1_OFFSET, BCM2836_HDMI1_LENGTH) + + // Mailbox + QWORDMEMORYSET(09, BCM2836_MBOX_OFFSET, BCM2836_MBOX_LENGTH) + + // VCHIQ + QWORDMEMORYSET(10, BCM2836_VCHIQ_OFFSET, BCM2836_VCHIQ_LENGTH) + + // GPIO + QWORDMEMORYSET(11, GPIO_OFFSET, GPIO_LENGTH) + + // I2C + QWORDMEMORYSET(12, BCM2836_I2C1_OFFSET, BCM2836_I2C1_LENGTH) + QWORDMEMORYSET(13, BCM2836_I2C2_OFFSET, BCM2836_I2C2_LENGTH) + + // SPI + QWORDMEMORYSET(14, BCM2836_SPI0_OFFSET, BCM2836_SPI0_LENGTH) + QWORDMEMORYSET(15, BCM2836_SPI1_OFFSET, BCM2836_SPI1_LENGTH) + // QWORDMEMORYSET(16, BCM2836_SPI2_OFFSET, BCM2836_SPI2_LENGTH) + + // PWM + QWORDMEMORYSET(17, BCM2836_PWM_DMA_OFFSET, BCM2836_PWM_DMA_LENGTH) + QWORDMEMORYSET(18, BCM2836_PWM_CTRL_OFFSET, BCM2836_PWM_CTRL_LENGTH) + QWORDBUSMEMORYSET(19, BCM2836_PWM_BUS_BASE_ADDRESS, BCM2836_PWM_BUS_LENGTH) + QWORDBUSMEMORYSET(20, BCM2836_PWM_CTRL_UNCACHED_BASE_ADDRESS, BCM2836_PWM_CTRL_UNCACHED_LENGTH) + QWORDMEMORYSET(21, BCM2836_PWM_CLK_OFFSET, BCM2836_PWM_CLK_LENGTH) + + // UART + QWORDMEMORYSET(22, BCM2836_PL011_UART_OFFSET, BCM2836_PL011_UART_LENGTH) + QWORDMEMORYSET(23, BCM2836_MINI_UART_OFFSET, BCM2836_MINI_UART_LENGTH) + + // SDC + QWORDMEMORYSET(24, MMCHS1_OFFSET, MMCHS1_LENGTH) + QWORDMEMORYSET(25, SDHOST_OFFSET, SDHOST_LENGTH) + + Return (RBUF) + } + + Name (_DMA, ResourceTemplate() { + // + // Only the first GB is available. + // Bus 0xC0000000 -> CPU 0x00000000. + // + QWordMemory (ResourceProducer, + , + MinFixed, + MaxFixed, + NonCacheable, + ReadWrite, + 0x0, + 0x00000000C0000000, // MIN + 0x00000000FFFFFFFF, // MAX + 0xFFFFFFFF40000000, // TRA + 0x0000000040000000, // LEN + , + , + ) + }) +#include "gpudevs.asl" + } + +#if defined(CONFIG_TARGET_RPI_4) + Device (ETH0) + { + Name (_HID, "BCM6E4E") + Name (_CID, "BCM6E4E") + Name (_UID, 0x0) + Name (_CCA, 0x0) + + Method (_CRS, 0x0, Serialized) + { + Return (ResourceTemplate () + { + // No need for MEMORY32SETBASE on Genet as we have a straight base address constant + MEMORY32FIXED (ReadWrite, GENET_BASE_ADDRESS, GENET_LENGTH, ) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { GENET_INTERRUPT0, GENET_INTERRUPT1 } + }) + } + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "brcm,max-dma-burst-size", 0x08 }, + Package () { "phy-mode", "rgmii-rxid" }, + } + }) + } + + // Define a simple thermal zone. The idea here is we compute the SOC temp + // via a register we can read, and give it to the OS. This enables basic + // reports from the "sensors" utility, and the OS can then poll and take + // actions if that temp exceeds any of the given thresholds. + Device (EC00) + { + Name (_HID, EISAID ("PNP0C06")) + Name (_CCA, 0x0) + + // all temps in are tenths of K (aka 2732 is the min temps in Linux (aka 0C)) + ThermalZone (TZ00) { + OperationRegion (TEMS, SystemMemory, THERM_SENSOR_BASE_ADDRESS, THERM_SENSOR_LENGTH) + Field (TEMS, DWordAcc, NoLock, Preserve) { + TMPS, 32 + } + Method (_TMP, 0, Serialized) { + return (((410040 - ((TMPS & 0x3ff) * 487)) / 100) + 2732); + } + + Method (_SCP, 3) { } // receive cooling policy from OS + + Method (_CRT) { Return (3632) } // (90C) Critical temp point (immediate power-off) + Method (_HOT) { Return (3582) } // (85C) HOT state where OS should hibernate + Method (_PSV) { Return (3532) } // (80C) Passive cooling (CPU throttling) trip point + + // SSDT inserts _AC0/_AL0 @60C here, if a FAN is configured + + Name (_TZP, 10) //The OSPM must poll this device every 1 seconds + Name (_PSL, Package () { \_PR.CP00, \_PR.CP01, \_PR.CP02, \_PR.CP03 }) + } + } +#endif + + +#include "uart.asl" +#include "rhpx.asl" +#include "sdhc.asl" +#include "emmc.asl" +#include "pci.asl" + } +} diff --git a/board/raspberrypi/rpi/emmc.asl b/board/raspberrypi/rpi/emmc.asl new file mode 100644 index 00000000000..63f01362c91 --- /dev/null +++ b/board/raspberrypi/rpi/emmc.asl @@ -0,0 +1,136 @@ +/** @file + * + * Copyright (c) 2021, ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include <asm/arch/acpi/bcm2836_sdhost.h> +#include <asm/arch/acpi/bcm2836_sdio.h> +#include <asm/arch/acpi/bcm2711.h> + +Device (GDV1) { + Name (_HID, "ACPI0004") + Name (_UID, 0x2) + Name (_CCA, 0x0) + + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, MMCHS2_LENGTH, RMEM) + }) + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, MMCHS2_OFFSET) + Return (^RBUF) + } + + // Translated DMA region for BCM2711 silicon revisions older than C0 + Name (DMTR, ResourceTemplate() { + QWordMemory (ResourceProducer, + , + MinFixed, + MaxFixed, + NonCacheable, + ReadWrite, + 0x0, + 0x00000000C0000000, // MIN + 0x00000000FFFFFFFF, // MAX + 0xFFFFFFFF40000000, // TRA + 0x0000000040000000, // LEN + , + , + ) + }) + + // Non translated DMA region for BCM2711 revisions C0 and newer + Name (DMNT, ResourceTemplate() { + QWordMemory (ResourceProducer, + , + MinFixed, + MaxFixed, + NonCacheable, + ReadWrite, + 0x0, + 0x0000000000000000, // MIN + 0x000000FFFFFFFFFF, // MAX + 0x0000000000000000, // TRA + 0x0000010000000000, // LEN + , + , + ) + }) + + // emmc2 Host Controller. (brcm,bcm2711-emmc2) + Device (SDC3) + { + Name (_HID, "BRCME88C") + Name (_UID, 0x1) + Name (_CCA, 0x0) + Name (_S1D, 0x1) + Name (_S2D, 0x1) + Name (_S3D, 0x1) + Name (_S4D, 0x1) + Name (SDMA, 0x2) + + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, MMCHS2_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Shared) { BCM2836_MMCHS1_INTERRUPT } + }) + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, MMCHS2_OFFSET) + Return (^RBUF) + } + + // Unfortunately this controller doesn't honor the + // standard SDHCI voltage control registers + // (or at least Linux's standard code can't + // lower the voltage) So, UHS mode is disabled with caps + Name (DSD1, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "sdhci-caps-mask", 0x0000000500080000 }, + } + }) + // Along with disabling UHS, here both SDMA and ADMA2 + // are also disabled until the linux _DMA() mask/translate + // works properly. + Name (DSD2, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "sdhci-caps-mask", 0x0000000504480000 }, + } + }) + Method (_DSD, 0x0, Serialized) + { + // Select one of the sdhci-caps-mask definitions + // depending on whether we also want to disable DMA + if (SDMA == 0) + { + return (^DSD2) + } + else + { + return (^DSD1) + } + } + + // + // A child device that represents the + // sd card, which is marked as non-removable. + // + Device (SDMM) + { + Method (_ADR) + { + Return (0) + } + Method (_RMV) // Is removable + { + Return (0) // 0 - fixed + } + } + } //SDC3 +} //GDV1 diff --git a/board/raspberrypi/rpi/gpudevs.asl b/board/raspberrypi/rpi/gpudevs.asl new file mode 100644 index 00000000000..a3077a9c3bd --- /dev/null +++ b/board/raspberrypi/rpi/gpudevs.asl @@ -0,0 +1,372 @@ +/** @file + * + * [DSDT] Devices behind the GPU. + * + * Copyright (c) 2018-2020, Andrey Warkentin <andrey.warkentin@gmail.com> + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +// DWC OTG Controller +Device (USB0) +{ + Name (_HID, "BCM2848") +#if defined(CONFIG_TARGET_RPI_3) + Name (_CID, "DWC_OTG") +#elif defined(CONFIG_TARGET_RPI_4) + Name (_CID, "BCM2848") +#endif + Name (_UID, 0x0) + Name (_CCA, 0x0) + Method (_STA) + { + Return (0xf) + } + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, BCM2836_USB_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_USB_INTERRUPT } + }) + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_USB_OFFSET) + Return (^RBUF) + } +} + +// Video Core 4 GPU +Device (GPU0) +{ + Name (_HID, "BCM2850") + Name (_CID, "BCM2850") + Name (_UID, 0x0) + Name (_CCA, 0x0) + Method (_STA) + { + Return (0xf) + } + Name (RBUF, ResourceTemplate () + { + // Memory and interrupt for the GPU + MEMORY32FIXED (ReadWrite, 0, BCM2836_V3D_BUS_LENGTH, RM01) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_V3D_BUS_INTERRUPT } + + // HVS - Hardware Video Scalar + MEMORY32FIXED (ReadWrite, 0, BCM2836_HVS_LENGTH, RM02) + // The HVS interrupt is reserved by the VPU + // Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_HVS_INTERRUPT } + + // PixelValve0 - DSI0 or DPI + // MEMORY32FIXED (ReadWrite, BCM2836_PV0_BASE_ADDRESS, BCM2836_PV0_LENGTH, RM03) + // Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_PV0_INTERRUPT } + + // PixelValve1 - DS1 or SMI + // MEMORY32FIXED (ReadWrite, BCM2836_PV1_BASE_ADDRESS, BCM2836_PV1_LENGTH, RM04) + // Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_PV1_INTERRUPT } + + // PixelValve2 - HDMI output - connected to HVS display FIFO 1 + MEMORY32FIXED (ReadWrite, 0, BCM2836_PV2_LENGTH, RM05) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_PV2_INTERRUPT } + + // HDMI registers + MEMORY32FIXED (ReadWrite, 0, BCM2836_HDMI0_LENGTH, RM06) + MEMORY32FIXED (ReadWrite, 0, BCM2836_HDMI1_LENGTH, RM07) + // hdmi_int[0] + // Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_HDMI0_INTERRUPT } + // hdmi_int[1] + // Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_HDMI1_INTERRUPT } + + // HDMI DDC connection + I2CSerialBus (0x50,, 100000,, "\\_SB.GDV0.I2C2",,,,) // EDID + I2CSerialBus (0x30,, 100000,, "\\_SB.GDV0.I2C2",,,,) // E-DDC Segment Pointer + }) + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RM01, RB01, BCM2836_V3D_BUS_OFFSET) + MEMORY32SETBASE (RBUF, RM02, RB02, BCM2836_HVS_OFFSET) + MEMORY32SETBASE (RBUF, RM05, RB05, BCM2836_PV2_OFFSET) + MEMORY32SETBASE (RBUF, RM06, RB06, BCM2836_HDMI0_OFFSET) + MEMORY32SETBASE (RBUF, RM07, RB07, BCM2836_HDMI1_OFFSET) + Return (^RBUF) + } + + // GPU Power Management Component Data + // Reference : https://github.com/Microsoft/graphics-driver-samples/wiki/Install-Driver-in-a-Windows-VM + Method (PMCD, 0, Serialized) + { + Name (RBUF, Package () + { + 1, // Version + 1, // Number of graphics power components + Package () // Power components package + { + Package () // GPU component package + { + 0, // Component Index + 0, // DXGK_POWER_COMPONENT_MAPPING.ComponentType (0 = DXGK_POWER_COMPONENT_ENGINE) + 0, // DXGK_POWER_COMPONENT_MAPPING.NodeIndex + + Buffer () // DXGK_POWER_RUNTIME_COMPONENT.ComponentGuid + { // 9B2D1E26-1575-4747-8FC0-B9EB4BAA2D2B + 0x26, 0x1E, 0x2D, 0x9B, 0x75, 0x15, 0x47, 0x47, + 0x8f, 0xc0, 0xb9, 0xeb, 0x4b, 0xaa, 0x2d, 0x2b + }, + + "VC4_Engine_00",// DXGK_POWER_RUNTIME_COMPONENT.ComponentName + 2, // DXGK_POWER_RUNTIME_COMPONENT.StateCount + + Package () // DXGK_POWER_RUNTIME_COMPONENT.States[] package + { + Package () // F0 + { + 0, // DXGK_POWER_RUNTIME_STATE.TransitionLatency + 0, // DXGK_POWER_RUNTIME_STATE.ResidencyRequirement + 1210000, // DXGK_POWER_RUNTIME_STATE.NominalPower (microwatt) + }, + + Package () // F1 - Placeholder + { + 10000, // DXGK_POWER_RUNTIME_STATE.TransitionLatency + 10000, // DXGK_POWER_RUNTIME_STATE.ResidencyRequirement + 4, // DXGK_POWER_RUNTIME_STATE.NominalPower + }, + } + } + } + }) + Return (RBUF) + } +} + +// PiQ Mailbox Driver +Device (RPIQ) +{ + Name (_HID, "BCM2849") + Name (_CID, "BCM2849") + Name (_UID, 0) + Name (_CCA, 0x0) + + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, BCM2836_MBOX_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_MBOX_INTERRUPT } + }) + + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_MBOX_OFFSET) + Return (^RBUF) + } +} + +// VCHIQ Driver +Device (VCIQ) +{ + Name (_HID, "BCM2835") + Name (_CID, "BCM2835") + Name (_UID, 0) + Name (_CCA, 0x0) + Name (_DEP, Package() { \_SB.GDV0.RPIQ }) + Method (_STA) + { + Return (0xf) + } + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, BCM2836_VCHIQ_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_VCHIQ_INTERRUPT } + }) + + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_VCHIQ_OFFSET) + Return (^RBUF) + } +} + +// VC Shared Memory Driver +Device (VCSM) +{ + Name (_HID, "BCM2856") + Name (_CID, "BCM2856") + Name (_UID, 0) + Name (_CCA, 0x0) + Name (_DEP, Package() { \_SB.GDV0.VCIQ }) + Method (_STA) + { + Return (0xf) + } +} + +// Description: GPIO +Device (GPI0) +{ + Name (_HID, "BCM2845") + Name (_CID, "BCM2845") + Name (_UID, 0x0) + Name (_CCA, 0x0) + + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, GPIO_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Shared) + { + BCM2386_GPIO_INTERRUPT0, BCM2386_GPIO_INTERRUPT1, + BCM2386_GPIO_INTERRUPT2, BCM2386_GPIO_INTERRUPT3 + } + }) + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, GPIO_OFFSET) + Return (^RBUF) + } +} + +// Description: I2C +Device (I2C1) +{ + Name (_HID, "BCM2841") + Name (_CID, "BCM2841") + Name (_UID, 0x1) + Name (_CCA, 0x0) + + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, BCM2836_I2C1_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Shared) { BCM2836_I2C1_INTERRUPT } + PinFunction (Exclusive, PullUp, BCM_ALT0, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 2, 3 } + }) + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_I2C1_OFFSET) + Return (^RBUF) + } +} + +// I2C2 is the HDMI DDC connection +Device (I2C2) +{ + Name (_HID, "BCM2841") + Name (_CID, "BCM2841") + Name (_UID, 0x2) + Name (_CCA, 0x0) + + Name (RBUF, ResourceTemplate() + { + MEMORY32FIXED (ReadWrite, 0, BCM2836_I2C2_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Shared) { BCM2836_I2C2_INTERRUPT } + }) + + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_I2C2_OFFSET) + Return (^RBUF) + } +} + +// SPI +Device (SPI0) +{ + Name (_HID, "BCM2838") + Name (_CID, "BCM2838") + Name (_UID, 0x0) + Name (_CCA, 0x0) + + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, BCM2836_SPI0_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Shared) { BCM2836_SPI0_INTERRUPT } + PinFunction (Exclusive, PullDown, BCM_ALT0, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 9, 10, 11 } // MISO, MOSI, SCLK + PinFunction (Exclusive, PullUp, BCM_ALT0, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 8 } // CE0 + PinFunction (Exclusive, PullUp, BCM_ALT0, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 7 } // CE1 + }) + + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_SPI0_OFFSET) + Return (^RBUF) + } +} + +Device (SPI1) +{ + Name (_HID, "BCM2839") + Name (_CID, "BCM2839") + Name (_UID, 0x1) + Name (_CCA, 0x0) + Name (_DEP, Package() { \_SB.GDV0.RPIQ }) + + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, BCM2836_SPI1_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Shared,) { BCM2836_SPI1_INTERRUPT } + PinFunction (Exclusive, PullDown, BCM_ALT4, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 19, 20, 21 } // MISO, MOSI, SCLK + PinFunction (Exclusive, PullDown, BCM_ALT4, "\\_SB.GDV0.GPI0", 0, ResourceConsumer, , ) { 16 } // CE2 + }) + + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_SPI1_OFFSET) + Return (^RBUF) + } +} + +// SPI2 has no pins on GPIO header +// Device (SPI2) +// { +// Name (_HID, "BCM2839") +// Name (_CID, "BCM2839") +// Name (_UID, 0x2) +// Name (_CCA, 0x0) +// Name (_DEP, Package() { \_SB.GDV0.RPIQ }) +// Method (_STA) +// { +// Return (0xf) // Disabled +// } +// Method (_CRS, 0x0, Serialized) +// { +// Name (RBUF, ResourceTemplate () +// { +// MEMORY32FIXED (ReadWrite, BCM2836_SPI2_BASE_ADDRESS, BCM2836_SPI2_LENGTH, RMEM) +// Interrupt (ResourceConsumer, Level, ActiveHigh, Shared,) { BCM2836_SPI2_INTERRUPT } +// }) +// Return (RBUF) +// } +// } + +// PWM Driver +Device (PWM0) +{ + Name (_HID, "BCM2844") + Name (_CID, "BCM2844") + Name (_UID, 0) + Name (_CCA, 0x0) + + Name (RBUF, ResourceTemplate () + { + // DMA channel 11 control + MEMORY32FIXED (ReadWrite, 0, BCM2836_PWM_DMA_LENGTH, RM01) + // PWM control + MEMORY32FIXED (ReadWrite, 0, BCM2836_PWM_CTRL_LENGTH, RM02) + // PWM control bus + MEMORY32FIXED (ReadWrite, BCM2836_PWM_BUS_BASE_ADDRESS, BCM2836_PWM_BUS_LENGTH, ) + // PWM control uncached + MEMORY32FIXED (ReadWrite, BCM2836_PWM_CTRL_UNCACHED_BASE_ADDRESS, BCM2836_PWM_CTRL_UNCACHED_LENGTH, ) + // PWM clock control + MEMORY32FIXED (ReadWrite, 0, BCM2836_PWM_CLK_LENGTH, RM03) + // Interrupt DMA channel 11 + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_DMA_INTERRUPT } + // DMA channel 11, DREQ 5 for PWM + FixedDMA (5, 11, Width32Bit, ) + }) + + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RM01, RB01, BCM2836_PWM_DMA_OFFSET) + MEMORY32SETBASE (RBUF, RM02, RB02, BCM2836_PWM_CTRL_OFFSET) + MEMORY32SETBASE (RBUF, RM03, RB03, BCM2836_PWM_CLK_OFFSET) + Return (^RBUF) + } +}
\ No newline at end of file diff --git a/board/raspberrypi/rpi/pci.asl b/board/raspberrypi/rpi/pci.asl new file mode 100644 index 00000000000..a7a09df5cd9 --- /dev/null +++ b/board/raspberrypi/rpi/pci.asl @@ -0,0 +1,177 @@ +/** @file + * + * Copyright (c) 2019 Linaro, Limited. All rights reserved. + * Copyright (c) 2021 Arm + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +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(_CCA, 0) // Mark the PCI noncoherent + + // PCIe can only DMA to first 3GB with early SOC's + // But we keep the restriction on the later ones + // To avoid DMA translation problems. + Name (_DMA, ResourceTemplate() { + QWordMemory (ResourceProducer, + , + MinFixed, + MaxFixed, + NonCacheable, + ReadWrite, + 0x0, + 0x0, // MIN + 0xbfffffff, // MAX + 0x0, // TRA + 0xc0000000, // LEN + , + , + ) + }) + + // PCI Routing Table + Name(_PRT, Package() { + Package (4) { 0x0000FFFF, 0, zero, 175 }, + Package (4) { 0x0000FFFF, 1, zero, 176 }, + Package (4) { 0x0000FFFF, 2, zero, 177 }, + Package (4) { 0x0000FFFF, 3, zero, 178 } + }) + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "linux-ecam-quirk-id", "bcm2711" }, + } + }) + + // Root complex resources + Method (_CRS, 0, Serialized) { + Name (RBUF, ResourceTemplate () { + + // bus numbers assigned to this root + WordBusNumber ( + ResourceProducer, + MinFixed, MaxFixed, PosDecode, + 0, // AddressGranularity + 0, // AddressMinimum - Minimum Bus Number + 255, // AddressMaximum - Maximum Bus Number + 0, // AddressTranslation - Set to 0 + 256 // RangeLength - Number of Busses + ) + + // 32-bit mmio window in 64-bit addr + QWordMemory ( + ResourceProducer, PosDecode, + MinFixed, MaxFixed, + NonCacheable, ReadWrite, // cacheable + 0x00000000, // Granularity + 0, // PCIE_PCI_MMIO_BEGIN + 1, // PCIE_MMIO_LEN + PCIE_PCI_MMIO_BEGIN + PCIE_CPU_MMIO_WINDOW, // PCIE_PCI_MMIO_BEGIN - PCIE_CPU_MMIO_WINDOW + 2 // PCIE_MMIO_LEN + 1 + ,,,MMI1 + ) + + // root port registers, not to be used if SMCCC is utilized + QWordMemory ( + ResourceConsumer, , + MinFixed, MaxFixed, + NonCacheable, ReadWrite, // cacheable + 0x00000000, // Granularity + 0xFD500000, // Root port begin + 0xFD509FFF, // Root port end + 0x00000000, // no translation + 0x0000A000, // size + ,, + ) + }) // end Name(RBUF) + + // Work around ASL's inability to add in a resource definition + // or for that matter compute the min,max,len properly + CreateQwordField (RBUF, MMI1._MIN, MMIB) + CreateQwordField (RBUF, MMI1._MAX, MMIE) + CreateQwordField (RBUF, MMI1._TRA, MMIT) + CreateQwordField (RBUF, MMI1._LEN, MMIL) + Add (MMIB, PCIE_TOP_OF_MEM_WIN, MMIB) + Add (PCIE_BRIDGE_MMIO_LEN, PCIE_TOP_OF_MEM_WIN, MMIE) + Subtract (MMIT, PCIE_TOP_OF_MEM_WIN, MMIT) + Add (PCIE_BRIDGE_MMIO_LEN, 1 , MMIL) + + Return (RBUF) + } // end Method(_CRS) + + // 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) { + // Note, This code is very similar to the code in the PCIe firmware + // specification which can be used as a reference + // Check for proper UUID + If(LEqual(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) + // Mask out Native HotPlug + And(CTRL,0x1E,CTRL) + // Always allow native PME, AER (no dependencies) + // Never allow SHPC (no SHPC controller in this system) + And(CTRL,0x1D,CTRL) + + If(LNotEqual(Arg1,One)) { // Unknown revision + Or(CDW1,0x08,CDW1) + } + + If(LNotEqual(CDW3,CTRL)) { // Capabilities bits were masked + Or(CDW1,0x10,CDW1) + } + // Update DWORD3 in the buffer + Store(CTRL,CDW3) + Return(Arg3) + } Else { + Or(CDW1,4,CDW1) // Unrecognized UUID + Return(Arg3) + } + } // End _OSC + + Device (XHC0) + { + Name (_ADR, 0x00010000) + Name (_CID, "PNP0D10") + Name (_UID, 0x0) // _UID: Unique ID + Name (_CCA, 0x0) // _CCA: Cache Coherency Attribute + + /* + * Microsoft's USB Device-Specific Methods. See: + * https://docs.microsoft.com/en-us/windows-hardware/drivers/bringup/usb-device-specific-method---dsm- + */ + Name (DSMU, ToUUID ("ce2ee385-00e6-48cb-9f05-2edb927c4899")) + + Method (_DSM, 4, Serialized) { + If (LEqual (Arg0, DSMU)) { // USB capabilities UUID + Switch (ToInteger (Arg2)) { + Case (0) { // Function 0: List of supported functions + Return (Buffer () { 0x41 }) // 0x41 - Functions 0 and 6 supported + } + Case (6) { // Function 6: RegisterAccessType + Return (Buffer () { 0x01 }) // 0x01 - Must use 32bit register access + } + Default { } // Unsupported + } + } + return (Buffer () { 0x00 }) // Return 0x00 for anything unsupported + } + } // end XHC0 + +} // PCI0
\ No newline at end of file diff --git a/board/raspberrypi/rpi/pep.asl b/board/raspberrypi/rpi/pep.asl new file mode 100644 index 00000000000..87469e2e5a9 --- /dev/null +++ b/board/raspberrypi/rpi/pep.asl @@ -0,0 +1,90 @@ +/** @file + * + * Platform Extension Plugin (PEP). + * + * Copyright (c) 2019, ARM Ltd. All rights reserved. + * Copyright (c) 2018, Andrey Warkentin <andrey.warkentin@gmail.com> + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +Device(PEPD) +{ + // + // PEP virtual device. + // + Name (_HID, "BCM2854") // Note: Since PEP on RPi is a virtual device, + Name (_CID, "BCM2854") // its device id needs to be generated by Microsoft + Name (_UID, 0x0) + Name (_CRS, ResourceTemplate () + { + // No hardware resources for PEP driver are needed. + }) + + // + // Processor info. PEP proprietary method to return + // PEP_PROCESSOR_TABLE_PLAT structure. + // + // See Pep.h and Pep.c. + // + Name (_GPI, Buffer() + { + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x5F, 0x00, 0x53, + 0x00, 0x42, 0x00, 0x2E, 0x00, 0x43, 0x00, 0x50, 0x00, 0x55, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }) + + // + // Coordinated state info. PEP proprietary method to return + // PEP_COORDINATED_STATE_TABLE_PLAT structure. + // + // See Pep.h and Pep.c. + // + Name (_GCI, Buffer() + { + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 + }) + + // + // Device info. PEP proprietary method to return + // PEP_DEVICE_TABLE_PLAT structure. + // + // See Pep.h and Pep.c. + // + Name (_GDI, Buffer() + { + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x5F, 0x00, 0x53, + 0x00, 0x42, 0x00, 0x2E, 0x00, 0x49, 0x00, 0x32, 0x00, 0x43, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }) +} diff --git a/board/raspberrypi/rpi/rhpx.asl b/board/raspberrypi/rpi/rhpx.asl new file mode 100644 index 00000000000..214b55c6564 --- /dev/null +++ b/board/raspberrypi/rpi/rhpx.asl @@ -0,0 +1,195 @@ +/** @file + * + * [DSDT] RHProxy device to enable WinRT API (RHPX) + * + * Copyright (c) 2018, Andrey Warkentin <andrey.warkentin@gmail.com> + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +Device (RHPX) +{ + Name (_HID, "MSFT8000") + Name (_CID, "MSFT8000") + Name (_UID, 1) + + Name(_CRS, ResourceTemplate () + { + // Index 0 + SPISerialBus ( // SCKL - GPIO 11 - Pin 23 + // MOSI - GPIO 10 - Pin 19 + // MISO - GPIO 9 - Pin 21 + // CE0 - GPIO 8 - Pin 24 + 0, // Device selection (CE0) + PolarityLow, // Device selection polarity + FourWireMode, // WireMode + 8, // DataBit len + ControllerInitiated, // Slave mode + 4000000, // Connection speed + ClockPolarityLow, // Clock polarity + ClockPhaseFirst, // Clock phase + "\\_SB.GDV0.SPI0", // ResourceSource: SPI bus controller name + 0, // ResourceSourceIndex + // Resource usage + // DescriptorName: creates name for offset of resource descriptor + ) // Vendor Data + + // Index 1 + SPISerialBus ( // SCKL - GPIO 11 - Pin 23 + // MOSI - GPIO 10 - Pin 19 + // MISO - GPIO 9 - Pin 21 + // CE1 - GPIO 7 - Pin 26 + 1, // Device selection (CE1) + PolarityLow, // Device selection polarity + FourWireMode, // WireMode + 8, // DataBit len + ControllerInitiated, // Slave mode + 4000000, // Connection speed + ClockPolarityLow, // Clock polarity + ClockPhaseFirst, // Clock phase + "\\_SB.GDV0.SPI0", // ResourceSource: SPI bus controller name + 0, // ResourceSourceIndex + // Resource usage + // DescriptorName: creates name for offset of resource descriptor + ) // Vendor Data + + // Index 2 + I2CSerialBus ( // Pin 3 (GPIO2, SDA1), 5 (GPIO3, SCL1) + 0xFFFF, // SlaveAddress: placeholder + , // SlaveMode: default to ControllerInitiated + 0, // ConnectionSpeed: placeholder + , // Addressing Mode: default to 7 bit + "\\_SB.GDV0.I2C1", // ResourceSource: I2C bus controller name + , + , + , // Descriptor Name: creates name for offset of resource descriptor + ) // Vendor Data + + // Index 3 + SPISerialBus ( // SPI1_SCLK - GPIO21 + // SPI1_MOSI - GPIO20 + // SPI1_MISO - GPIO19 + // SPI1_CE2_N - GPIO16 + 2, // Device selection (CE2) + PolarityLow, // Device selection polarity + FourWireMode, // WireMode + 8, // DataBit len + ControllerInitiated, // Slave mode + 4000000, // Connection speed + ClockPolarityLow, // Clock polarity + ClockPhaseFirst, // Clock phase + "\\_SB.GDV0.SPI1", // ResourceSource: SPI bus controller name + 0, // ResourceSourceIndex + // Resource usage + // DescriptorName: creates name for offset of resource descriptor + ) // Vendor Data + + // GPIO 2 + GpioIO (Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 2 } + GpioInt (Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GDV0.GPI0",) { 2 } + // GPIO 3 + GpioIO (Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 3 } + GpioInt (Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GDV0.GPI0",) { 3 } + // GPIO 4 + GpioIO (Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 4 } + GpioInt (Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GDV0.GPI0",) { 4 } + // GPIO 5 + GpioIO (Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 5 } + GpioInt (Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GDV0.GPI0",) { 5 } + // GPIO 6 + GpioIO (Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 6 } + GpioInt (Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GDV0.GPI0",) { 6 } + // GPIO 7 + GpioIO (Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 7 } + GpioInt (Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GDV0.GPI0",) { 7 } + // GPIO 8 + GpioIO (Shared, PullUp, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 8 } + GpioInt (Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GDV0.GPI0",) { 8 } + // GPIO 9 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 9 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 9 } + // GPIO 10 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 10 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 10 } + // GPIO 11 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 11 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 11 } + // GPIO 12 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 12 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 12 } + // GPIO 13 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 13 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 13 } + // NTRAID#MSFT-7141401-2016/04/7-jordanrh - disable UART muxing + // until a proper solution can be created for the dmap conflict + // GPIO 14 - UART TX + // GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 14 } + // GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 14 } + // GPIO 15 - UART RX + // GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 15 } + // GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 15 } + // GPIO 16 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 16 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 16 } + // GPIO 17 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 17 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 17 } + // GPIO 18 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 18 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 18 } + // GPIO 19 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 19 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 19 } + // GPIO 20 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 20 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 20 } + // GPIO 21 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 21 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 21 } + // GPIO 22 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 22 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 22 } + // GPIO 23 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 23 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 23 } + // GPIO 24 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 24 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 24 } + // GPIO 25 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 25 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 25 } + // GPIO 26 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 26 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 26 } + // GPIO 27 + GpioIO (Shared, PullDown, 0, 0, IoRestrictionNone, "\\_SB.GDV0.GPI0", 0, ResourceConsumer,,) { 27 } + GpioInt (Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GDV0.GPI0",) { 27 } + }) + + Name (_DSD, Package() + { + ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () + { + // Reference http://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md + // SPI 0 + Package (2) { "bus-SPI-SPI0", Package() { 0, 1 } }, // Index 0 & 1 + Package (2) { "SPI0-MinClockInHz", 7629 }, // 7629 Hz + Package (2) { "SPI0-MaxClockInHz", 125000000 }, // 125 MHz + Package (2) { "SPI0-SupportedDataBitLengths", Package() { 8 } }, // Data Bit Length + // I2C1 + Package (2) { "bus-I2C-I2C1", Package() { 2 } }, + // GPIO Pin Count and supported drive modes + Package (2) { "GPIO-PinCount", 54 }, + Package (2) { "GPIO-UseDescriptorPinNumbers", 1 }, + Package (2) { "GPIO-SupportedDriveModes", 0xf }, // InputHighImpedance, InputPullUp, InputPullDown, OutputCmos + // SPI 1 + Package (2) { "bus-SPI-SPI1", Package() { 3 }}, // Index 3 + Package (2) { "SPI1-MinClockInHz", 30511 }, // 30.5 kHz + Package (2) { "SPI1-MaxClockInHz", 20000000 }, // 20 MHz + Package (2) { "SPI1-SupportedDataBitLengths", Package() { 8 } }, // Data Bit Length + } + }) +} diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c index ab5ea85cf9f..9122f33d88d 100644 --- a/board/raspberrypi/rpi/rpi.c +++ b/board/raspberrypi/rpi/rpi.c @@ -23,6 +23,11 @@ #endif #include <watchdog.h> #include <dm/pinctrl.h> +#include <dm/ofnode.h> +#include <acpi/acpi_table.h> +#include <acpi/acpigen.h> +#include <dm/lists.h> +#include <tables_csum.h> DECLARE_GLOBAL_DATA_PTR; @@ -583,3 +588,181 @@ int ft_board_setup(void *blob, struct bd_info *bd) return 0; } + +#if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) +static bool is_rpi4(void) +{ + return of_machine_is_compatible("brcm,bcm2711") || + of_machine_is_compatible("brcm,bcm2712"); +} + +static bool is_rpi3(void) +{ + return of_machine_is_compatible("brcm,bcm2837"); +} + +static int acpi_rpi_board_fill_ssdt(struct acpi_ctx *ctx) +{ + int node, ret, uart_in_use, mini_clock_rate; + bool enabled; + struct udevice *dev; + struct { + const char *fdt_compatible; + const char *acpi_scope; + bool on_rpi4; + bool on_rpi3; + u32 mmio_address; + } map[] = { + {"brcm,bcm2711-pcie", "\\_SB.PCI0", true, false}, + {"brcm,bcm2711-emmc2", "\\_SB.GDV1.SDC3", true, false}, + {"brcm,bcm2835-pwm", "\\_SB.GDV0.PWM0", true, true}, + {"brcm,bcm2711-genet-v5", "\\_SB.ETH0", true, false}, + {"brcm,bcm2711-thermal", "\\_SB.EC00", true, true}, + {"brcm,bcm2835-sdhci", "\\_SB.SDC1", true, true}, + {"brcm,bcm2835-sdhost", "\\_SB.SDC2", false, true}, + {"brcm,bcm2835-mbox", "\\_SB.GDV0.RPIQ", true, true}, + {"brcm,bcm2835-i2c", "\\_SB.GDV0.I2C1", true, true, 0xfe205000}, + {"brcm,bcm2835-i2c", "\\_SB.GDV0.I2C2", true, true, 0xfe804000}, + {"brcm,bcm2835-spi", "\\_SB.GDV0.SPI0", true, true}, + {"brcm,bcm2835-aux-spi", "\\_SB.GDV0.SPI1", true, true, 0xfe215080}, + {"arm,pl011", "\\_SB.URT0", true, true}, + {"brcm,bcm2835-aux-uart", "\\_SB.URTM", true, true}, + { /* Sentinel */ } + }; + + /* Device enable */ + for (int i = 0; map[i].fdt_compatible; i++) { + if ((is_rpi4() && !map[i].on_rpi4) || + (is_rpi3() && !map[i].on_rpi3)) { + enabled = false; + } else { + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, + map[i].fdt_compatible); + while (node != -FDT_ERR_NOTFOUND && map[i].mmio_address) { + struct fdt_resource r; + + ret = fdt_get_resource(gd->fdt_blob, node, "reg", 0, &r); + if (ret) { + node = -FDT_ERR_NOTFOUND; + break; + } + + if (r.start == map[i].mmio_address) + break; + + node = fdt_node_offset_by_compatible(gd->fdt_blob, node, + map[i].fdt_compatible); + } + + enabled = (node > 0) ? fdtdec_get_is_enabled(gd->fdt_blob, node) : 0; + } + acpigen_write_scope(ctx, map[i].acpi_scope); + acpigen_write_name_integer(ctx, "_STA", enabled ? 0xf : 0); + acpigen_pop_len(ctx); + } + + /* GPIO quirks */ + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "brcm,bcm2835-gpio"); + if (node <= 0) + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "brcm,bcm2711-gpio"); + + acpigen_write_scope(ctx, "\\_SB.GDV0.GPI0"); + enabled = (node > 0) ? fdtdec_get_is_enabled(gd->fdt_blob, node) : 0; + acpigen_write_name_integer(ctx, "_STA", enabled ? 0xf : 0); + acpigen_pop_len(ctx); + + if (is_rpi4()) { + /* eMMC quirks */ + node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "brcm,bcm2711-emmc2"); + if (node) { + phys_addr_t cpu; + dma_addr_t bus; + u64 size; + + ret = fdt_get_dma_range(gd->fdt_blob, node, &cpu, &bus, &size); + + acpigen_write_scope(ctx, "\\_SB.GDV1"); + acpigen_write_method_serialized(ctx, "_DMA", 0); + acpigen_emit_byte(ctx, RETURN_OP); + + if (!ret && bus != cpu) /* Translated DMA range */ + acpigen_emit_namestring(ctx, "\\_SB.GDV1.DMTR"); + else if (!ret && bus == cpu) /* Non translated DMA */ + acpigen_emit_namestring(ctx, "\\_SB.GDV1.DMNT"); + else /* Silicon revisions older than C0: Translated DMA range */ + acpigen_emit_namestring(ctx, "\\_SB.GDV1.DMTR"); + acpigen_pop_len(ctx); + } + } + + /* Serial */ + uart_in_use = ~0; + mini_clock_rate = 0x1000000; + + ret = uclass_get_device_by_driver(UCLASS_SERIAL, + DM_DRIVER_GET(bcm283x_pl011_uart), + &dev); + if (!ret) + uart_in_use = 0; + + ret = uclass_get_device_by_driver(UCLASS_SERIAL, + DM_DRIVER_GET(serial_bcm283x_mu), + &dev); + if (!ret) { + if (uart_in_use == 0) + log_err("Invalid config: PL011 and MiniUART are both enabled."); + else + uart_in_use = 1; + + mini_clock_rate = dev_read_u32_default(dev, "clock", 0x1000000); + } + if (uart_in_use > 1) + log_err("No working serial: PL011 and MiniUART are both disabled."); + + acpigen_write_scope(ctx, "\\_SB.BTH0"); + acpigen_write_name_integer(ctx, "URIU", uart_in_use); + acpigen_pop_len(ctx); + + acpigen_write_scope(ctx, "\\_SB.URTM"); + acpigen_write_name_integer(ctx, "MUCR", mini_clock_rate); + acpigen_pop_len(ctx); + + return 0; +} + +static int rpi_acpi_write_ssdt(struct acpi_ctx *ctx, const struct acpi_writer *entry) +{ + struct acpi_table_header *ssdt; + int ret; + + ssdt = ctx->current; + memset(ssdt, '\0', sizeof(struct acpi_table_header)); + + acpi_fill_header(ssdt, "SSDT"); + ssdt->revision = acpi_get_table_revision(ACPITAB_SSDT); + ssdt->creator_revision = 1; + ssdt->length = sizeof(struct acpi_table_header); + + acpi_inc(ctx, sizeof(struct acpi_table_header)); + + ret = acpi_rpi_board_fill_ssdt(ctx); + if (ret) { + ctx->current = ssdt; + return log_msg_ret("fill", ret); + } + + /* (Re)calculate length and checksum */ + ssdt->length = ctx->current - (void *)ssdt; + ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length); + log_debug("SSDT at %p, length %x\n", ssdt, ssdt->length); + + /* Drop the table if it is empty */ + if (ssdt->length == sizeof(struct acpi_table_header)) + return log_msg_ret("fill", -ENOENT); + acpi_add_table(ctx, ssdt); + + return 0; +} + +ACPI_WRITER(5ssdt, "SSDT", rpi_acpi_write_ssdt, 0); +#endif diff --git a/board/raspberrypi/rpi/sdhc.asl b/board/raspberrypi/rpi/sdhc.asl new file mode 100644 index 00000000000..3feac14acf2 --- /dev/null +++ b/board/raspberrypi/rpi/sdhc.asl @@ -0,0 +1,111 @@ +/** @file + * + * [DSDT] SD controller/card definition (SDHC) + * + * Copyright (c) 2020, Pete Batard <pete@akeo.ie> + * Copyright (c) 2018, Andrey Warkentin <andrey.warkentin@gmail.com> + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include <asm/arch/acpi/bcm2836_sdhost.h> +#include <asm/arch/acpi/bcm2836_sdio.h> + +#include "acpitables.h" + +// +// Note: UEFI can use either SDHost or Arasan. We expose both to the OS. +// + +// ArasanSD 3.0 SD Host Controller. (brcm,bcm2835-sdhci) +Device (SDC1) +{ + Name (_HID, "BCM2847") + Name (_CID, "BCM2847") + Name (_UID, 0x0) + Name (_CCA, 0x0) + Name (_S1D, 0x1) + Name (_S2D, 0x1) + Name (_S3D, 0x1) + Name (_S4D, 0x1) + + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, MMCHS1_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Shared) { BCM2836_MMCHS1_INTERRUPT } + }) + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, MMCHS1_OFFSET) + Return (^RBUF) + } + + // The standard CAPs registers on this controller + // appear to be 0, lets set some minimal defaults + // Since this cap doesn't indicate DMA capability + // we don't need a _DMA() + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "sdhci-caps", 0x0120fa81 }, + } + }) + + // + // A child device that represents the + // sd card, which is marked as non-removable. + // + Device (SDMM) + { + Method (_ADR) + { + Return (0) + } + Method (_RMV) // Is removable + { + Return (0) // 0 - fixed + } + } +} + +// Broadcom SDHost 2.0 SD Host Controller +Device (SDC2) +{ + Name (_HID, "BCM2855") + Name (_CID, "BCM2855") + Name (_UID, 0x0) + Name (_CCA, 0x0) + Name (_S1D, 0x1) + Name (_S2D, 0x1) + Name (_S3D, 0x1) + Name (_S4D, 0x1) + + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, SDHOST_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_SDHOST_INTERRUPT } + }) + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, SDHOST_OFFSET) + Return (^RBUF) + } + + // + // A child device that represents the + // sd card, which is marked as non-removable. + // + Device (SDMM) + { + Method (_ADR) + { + Return (0) + } + Method (_RMV) // Is removable + { + Return (0) // 0 - fixed + } + } +}
\ No newline at end of file diff --git a/board/raspberrypi/rpi/uart.asl b/board/raspberrypi/rpi/uart.asl new file mode 100644 index 00000000000..78dc9a74dfc --- /dev/null +++ b/board/raspberrypi/rpi/uart.asl @@ -0,0 +1,208 @@ +/** @file + * + * [DSDT] Serial devices (UART). + * + * Copyright (c) 2021, ARM Limited. All rights reserved. + * Copyright (c) 2020, Pete Batard <pete@akeo.ie> + * Copyright (c) 2018, Andrey Warkentin <andrey.warkentin@gmail.com> + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include <asm/arch/acpi/bcm2836.h> + +#include "acpitables.h" + +// PL011 based UART. +Device (URT0) +{ + Name (_HID, "BCM2837") + Name (_CID, "ARMH0011") + Name (_UID, 0x4) + Name (_CCA, 0x0) + + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, BCM2836_PL011_UART_LENGTH, RMEM) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive) { BCM2836_PL011_UART_INTERRUPT } + }) + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_PL011_UART_OFFSET) + Return (^RBUF) + } + + Name (CLCK, 48000000) + + Name (_DSD, Package () + { + ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () + { + Package (2) { "clock-frequency", CLCK }, + } + }) +} + +// +// UART Mini. +// +// This device is referenced in the DBG2 table, which will cause the system to +// not start the driver when the debugger is enabled and to mark the device +// with problem code 53 (CM_PROB_USED_BY_DEBUGGER). +// + +Device (URTM) +{ + Name (_HID, "BCM2836") + Name (_CID, "BCM2836") + Name (_UID, 0x0) + Name (_CCA, 0x0) + + Name (RBUF, ResourceTemplate () + { + MEMORY32FIXED (ReadWrite, 0, BCM2836_MINI_UART_LENGTH, RMEM) + Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) { BCM2836_MINI_UART_INTERRUPT } + + }) + Method (_CRS, 0x0, Serialized) + { + MEMORY32SETBASE (RBUF, RMEM, RBAS, BCM2836_MINI_UART_OFFSET) + Return (^RBUF) + } + + // + // Mini Uart Clock Rate will be dynamically updated during boot + // + External (\_SB.URTM.MUCR, IntObj) + + Name (_DSD, Package () + { + ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () + { + Package (2) { "clock-frequency", MUCR }, + } + }) +} + +// +// Multifunction serial bus device to support Bluetooth function. +// +Device(BTH0) +{ + Name (_HID, "BCM2EA6") + Name (_CID, "BCM2EA6") + + // + // UART In Use will be dynamically updated during boot + // + External (\_SB.BTH0.URIU, IntObj) + + Method (_STA) + { + Return (0xf) + } + + // + // Resource for URT0 (PL011) + // + Name (BTPL, ResourceTemplate () + { + UARTSerialBus( + 115200, // InitialBaudRate: in BPS + , // BitsPerByte: default to 8 bits + , // StopBits: Defaults to one bit + 0x00, // LinesInUse: 8 1-bit flags to + // declare enabled control lines. + // Raspberry Pi does not exposed + // HW control signals -> not supported. + // Optional bits: + // - Bit 7 (0x80) Request To Send (RTS) + // - Bit 6 (0x40) Clear To Send (CTS) + // - Bit 5 (0x20) Data Terminal Ready (DTR) + // - Bit 4 (0x10) Data Set Ready (DSR) + // - Bit 3 (0x08) Ring Indicator (RI) + // - Bit 2 (0x04) Data Carrier Detect (DTD) + // - Bit 1 (0x02) Reserved. Must be 0. + // - Bit 0 (0x01) Reserved. Must be 0. + , // IsBigEndian: + // default to LittleEndian. + , // Parity: Defaults to no parity + , // FlowControl: Defaults to + // no flow control. + 16, // ReceiveBufferSize + 16, // TransmitBufferSize + "\\_SB.GDV0.URT0", // ResourceSource: + // UART bus controller name + , // ResourceSourceIndex: assumed to be 0 + , // ResourceUsage: assumed to be + // ResourceConsumer + UAR0, // DescriptorName: creates name + // for offset of resource descriptor + ) // Vendor data + }) + + // + // Resource for URTM (miniUART) + // + Name (BTMN, ResourceTemplate () + { + // + // BT UART: ResourceSource will be dynamically updated to + // either URT0 (PL011) or URTM (miniUART) during boot + // + UARTSerialBus( + 115200, // InitialBaudRate: in BPS + , // BitsPerByte: default to 8 bits + , // StopBits: Defaults to one bit + 0x00, // LinesInUse: 8 1-bit flags to + // declare enabled control lines. + // Raspberry Pi does not exposed + // HW control signals -> not supported. + // Optional bits: + // - Bit 7 (0x80) Request To Send (RTS) + // - Bit 6 (0x40) Clear To Send (CTS) + // - Bit 5 (0x20) Data Terminal Ready (DTR) + // - Bit 4 (0x10) Data Set Ready (DSR) + // - Bit 3 (0x08) Ring Indicator (RI) + // - Bit 2 (0x04) Data Carrier Detect (DTD) + // - Bit 1 (0x02) Reserved. Must be 0. + // - Bit 0 (0x01) Reserved. Must be 0. + , // IsBigEndian: + // default to LittleEndian. + , // Parity: Defaults to no parity + , // FlowControl: Defaults to + // no flow control. + 16, // ReceiveBufferSize + 16, // TransmitBufferSize + "\\_SB.GDV0.URTM", // ResourceSource: + // UART bus controller name + , // ResourceSourceIndex: assumed to be 0 + , // ResourceUsage: assumed to be + // ResourceConsumer + UARM, // DescriptorName: creates name + // for offset of resource descriptor + ) // Vendor data + }) + + Method (_CRS, 0x0, Serialized) + { + if (URIU == 0) + { + // + // PL011 UART is configured for console output + // Return Mini UART for Bluetooth + // + return (^BTMN) + } + else + { + // + // Mini UART is configured for console output + // Return PL011 UART for Bluetooth + // + return (^BTPL) + } + } +} diff --git a/boot/bootflow.c b/boot/bootflow.c index 59d77d2385f..d8807eb109d 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -936,11 +936,15 @@ int bootflow_cmdline_auto(struct bootflow *bflow, const char *arg) return ret; *buf = '\0'; - if (!strcmp("earlycon", arg)) { + if (!strcmp("earlycon", arg) && info.type == SERIAL_CHIP_16550_COMPATIBLE) { snprintf(buf, sizeof(buf), "uart8250,mmio32,%#lx,%dn8", info.addr, info.baudrate); - } else if (!strcmp("console", arg)) { + } else if (!strcmp("earlycon", arg) && info.type == SERIAL_CHIP_PL01X) { + snprintf(buf, sizeof(buf), + "pl011,mmio32,%#lx,%dn8", info.addr, + info.baudrate); + } else if (!strcmp("console", arg) && info.type == SERIAL_CHIP_16550_COMPATIBLE) { snprintf(buf, sizeof(buf), "ttyS0,%dn8", info.baudrate); } diff --git a/common/Kconfig b/common/Kconfig index 14a6c44c804..e8d89bf6eb9 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1081,6 +1081,7 @@ config BLOBLIST_SIZE_RELOC hex "Size of bloblist after relocation" default BLOBLIST_SIZE if BLOBLIST_FIXED || BLOBLIST_ALLOC default 0x0 if BLOBLIST_PASSAGE + default 0x20000 if (ARM && EFI_LOADER && GENERATE_ACPI_TABLE) help Sets the size of the bloblist in bytes after relocation. Since U-Boot has a lot more memory available then, it is possible to use a larger diff --git a/common/bloblist.c b/common/bloblist.c index 6640ad1fd69..ec6ff7a5a93 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -499,7 +499,7 @@ int bloblist_init(void) { bool fixed = IS_ENABLED(CONFIG_BLOBLIST_FIXED); int ret = -ENOENT; - ulong addr, size; + ulong addr = 0, size; /* * If U-Boot is not in the first phase, an existing bloblist must be * at a fixed address. diff --git a/configs/clearfog_defconfig b/configs/clearfog_defconfig index f251d69253a..bba25e09494 100644 --- a/configs/clearfog_defconfig +++ b/configs/clearfog_defconfig @@ -53,7 +53,7 @@ CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_OF_TRANSLATE=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_DM_PCA953X=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_MVTWSI=y diff --git a/configs/clearfog_gt_8k_defconfig b/configs/clearfog_gt_8k_defconfig index cabd2226d78..eaa8a333049 100644 --- a/configs/clearfog_gt_8k_defconfig +++ b/configs/clearfog_gt_8k_defconfig @@ -46,7 +46,7 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 CONFIG_NET_RANDOM_ETHADDR=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_DM_I2C=y diff --git a/configs/clearfog_sata_defconfig b/configs/clearfog_sata_defconfig index 8d4b54cb12e..b82d604c237 100644 --- a/configs/clearfog_sata_defconfig +++ b/configs/clearfog_sata_defconfig @@ -53,7 +53,7 @@ CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_OF_TRANSLATE=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_DM_PCA953X=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_MVTWSI=y diff --git a/configs/clearfog_spi_defconfig b/configs/clearfog_spi_defconfig index 2f58e94a62b..cef80d69a38 100644 --- a/configs/clearfog_spi_defconfig +++ b/configs/clearfog_spi_defconfig @@ -53,7 +53,7 @@ CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_OF_TRANSLATE=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_DM_PCA953X=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_MVTWSI=y diff --git a/configs/db-88f6820-gp_defconfig b/configs/db-88f6820-gp_defconfig index b327149ad72..5b69a20ae5d 100644 --- a/configs/db-88f6820-gp_defconfig +++ b/configs/db-88f6820-gp_defconfig @@ -58,7 +58,7 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 CONFIG_SPL_OF_TRANSLATE=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_SYS_I2C_LEGACY=y CONFIG_SPL_SYS_I2C_LEGACY=y CONFIG_SYS_I2C_MVTWSI=y diff --git a/configs/ds116_defconfig b/configs/ds116_defconfig index 0bb7e301a64..c321e6f484d 100644 --- a/configs/ds116_defconfig +++ b/configs/ds116_defconfig @@ -65,7 +65,7 @@ CONFIG_NET_RETRY_COUNT=50 CONFIG_NET_RANDOM_ETHADDR=y CONFIG_NETCONSOLE=y CONFIG_SPL_OF_TRANSLATE=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_DM_I2C=y diff --git a/configs/helios4_defconfig b/configs/helios4_defconfig index 61d110e6f4c..e45446c2d05 100644 --- a/configs/helios4_defconfig +++ b/configs/helios4_defconfig @@ -53,7 +53,7 @@ CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_OF_TRANSLATE=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_DM_PCA953X=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_MVTWSI=y diff --git a/configs/mvebu_crb_cn9130_defconfig b/configs/mvebu_crb_cn9130_defconfig index 505f063605f..e8984b663b5 100644 --- a/configs/mvebu_crb_cn9130_defconfig +++ b/configs/mvebu_crb_cn9130_defconfig @@ -46,7 +46,7 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_SYS_MMC_ENV_DEV=1 CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_DM_I2C=y diff --git a/configs/mvebu_db-88f3720_defconfig b/configs/mvebu_db-88f3720_defconfig index 962edb790b7..e5de34c85fc 100644 --- a/configs/mvebu_db-88f3720_defconfig +++ b/configs/mvebu_db-88f3720_defconfig @@ -43,7 +43,7 @@ CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_CLK=y diff --git a/configs/mvebu_db_armada8k_defconfig b/configs/mvebu_db_armada8k_defconfig index 7c6b53ed3a6..f9b03a7e77a 100644 --- a/configs/mvebu_db_armada8k_defconfig +++ b/configs/mvebu_db_armada8k_defconfig @@ -42,7 +42,7 @@ CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_DM_I2C=y diff --git a/configs/mvebu_db_cn9130_defconfig b/configs/mvebu_db_cn9130_defconfig index f80812c811a..6dd6be788d3 100644 --- a/configs/mvebu_db_cn9130_defconfig +++ b/configs/mvebu_db_cn9130_defconfig @@ -47,7 +47,7 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_SYS_MMC_ENV_DEV=1 CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_DM_GPIO_LOOKUP_LABEL=y diff --git a/configs/mvebu_espressobin-88f3720_defconfig b/configs/mvebu_espressobin-88f3720_defconfig index 375705caa4b..e9ee88594e9 100644 --- a/configs/mvebu_espressobin-88f3720_defconfig +++ b/configs/mvebu_espressobin-88f3720_defconfig @@ -54,7 +54,7 @@ CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 CONFIG_NET_RANDOM_ETHADDR=y CONFIG_AHCI_PCI=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_CLK=y diff --git a/configs/mvebu_espressobin_ultra-88f3720_defconfig b/configs/mvebu_espressobin_ultra-88f3720_defconfig index fe3def1fe6b..aa9026acc34 100644 --- a/configs/mvebu_espressobin_ultra-88f3720_defconfig +++ b/configs/mvebu_espressobin_ultra-88f3720_defconfig @@ -53,7 +53,7 @@ CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 CONFIG_NET_RANDOM_ETHADDR=y CONFIG_AHCI_PCI=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_CLK=y diff --git a/configs/mvebu_mcbin-88f8040_defconfig b/configs/mvebu_mcbin-88f8040_defconfig index c1b470c9825..90d341e0a4c 100644 --- a/configs/mvebu_mcbin-88f8040_defconfig +++ b/configs/mvebu_mcbin-88f8040_defconfig @@ -46,7 +46,7 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 CONFIG_NET_RANDOM_ETHADDR=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_DM_I2C=y diff --git a/configs/mvebu_puzzle-m801-88f8040_defconfig b/configs/mvebu_puzzle-m801-88f8040_defconfig index 1d86e26833d..21ab2177058 100644 --- a/configs/mvebu_puzzle-m801-88f8040_defconfig +++ b/configs/mvebu_puzzle-m801-88f8040_defconfig @@ -50,7 +50,7 @@ CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_ARP_TIMEOUT=200 CONFIG_NET_RETRY_COUNT=50 CONFIG_NET_RANDOM_ETHADDR=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_DM_PCA953X=y diff --git a/configs/n2350_defconfig b/configs/n2350_defconfig index 8d54882ee85..7851bc470c0 100644 --- a/configs/n2350_defconfig +++ b/configs/n2350_defconfig @@ -65,7 +65,7 @@ CONFIG_NET_RETRY_COUNT=50 CONFIG_NET_RANDOM_ETHADDR=y CONFIG_NETCONSOLE=y CONFIG_SPL_OF_TRANSLATE=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_DM_I2C=y diff --git a/configs/octeon_nic23_defconfig b/configs/octeon_nic23_defconfig index 0febe80bd96..76adbf201e3 100644 --- a/configs/octeon_nic23_defconfig +++ b/configs/octeon_nic23_defconfig @@ -46,7 +46,7 @@ CONFIG_EFI_PARTITION=y CONFIG_ENV_IS_IN_SPI_FLASH=y CONFIG_TFTP_TSIZE=y CONFIG_SATA=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_LBA48=y CONFIG_SYS_64BIT_LBA=y CONFIG_CLK=y diff --git a/configs/qemu-arm-sbsa_defconfig b/configs/qemu-arm-sbsa_defconfig new file mode 100644 index 00000000000..69195afeedf --- /dev/null +++ b/configs/qemu-arm-sbsa_defconfig @@ -0,0 +1,12 @@ +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 +CONFIG_BLOBLIST_ALLOC=y +CONFIG_BLOBLIST_SIZE_RELOC=0x20000 diff --git a/configs/rpi_4_acpi_defconfig b/configs/rpi_4_acpi_defconfig new file mode 100644 index 00000000000..b32dfc16a19 --- /dev/null +++ b/configs/rpi_4_acpi_defconfig @@ -0,0 +1,10 @@ +#include <configs/rpi_4_defconfig> + +CONFIG_ARM=y +CONFIG_ARCH_BCM283X=y +CONFIG_TARGET_RPI_4=y +CONFIG_BLOBLIST_ALLOC=y +CONFIG_OF_BOARD=y +CONFIG_ACPI=y +CONFIG_GENERATE_ACPI_TABLE=y + diff --git a/configs/turris_omnia_defconfig b/configs/turris_omnia_defconfig index 3bb85591834..dd1a45bd258 100644 --- a/configs/turris_omnia_defconfig +++ b/configs/turris_omnia_defconfig @@ -90,7 +90,7 @@ CONFIG_NET_RETRY_COUNT=50 CONFIG_NETCONSOLE=y CONFIG_SPL_OF_TRANSLATE=y CONFIG_AHCI_PCI=y -CONFIG_AHCI_MVEBU=y +CONFIG_AHCI_GENERIC=y CONFIG_DM_PCA953X=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_MV=y diff --git a/doc/board/emulation/index.rst b/doc/board/emulation/index.rst index 98a0b26ad24..0419d724150 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 00000000000..fe1dc3249e4 --- /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@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 ARMv7/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 8ac9c94cafe..31b94d04675 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/drivers/ata/Kconfig b/drivers/ata/Kconfig index 6cca561f974..4fbb63a148a 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -78,14 +78,16 @@ config MTK_AHCI Enable this driver to support Sata devices through Mediatek AHCI controller (e.g. MT7622). -config AHCI_MVEBU - bool "Marvell EBU AHCI SATA support" - depends on ARCH_MVEBU || ARCH_OCTEON +config AHCI_GENERIC + bool "Generic AHCI SATA support" + depends on OF_CONTROL select SCSI_AHCI select SCSI help - This option enables support for the Marvell EBU SoC's - onboard AHCI SATA. + This option enables support for generic onboard AHCI SATA controller + that do not need platform specific quirks, like emulated devices, + Marvell EBU SoC's onboard AHCI SATA controllers or Cavium's Octeon + 7130 AHCI controllers. If unsure, say N. diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index ee10c4445b0..69fa9b707e0 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -14,6 +14,6 @@ obj-$(CONFIG_SATA) += sata.o sata_bootdev.o obj-$(CONFIG_SATA_CEVA) += sata_ceva.o obj-$(CONFIG_SATA_MV) += sata_mv.o obj-$(CONFIG_SATA_SIL) += sata_sil.o -obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o +obj-$(CONFIG_AHCI_GENERIC) += ahci_generic.o obj-$(CONFIG_SUNXI_AHCI) += ahci_sunxi.o obj-$(CONFIG_MTK_AHCI) += mtk_ahci.o diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_generic.c index f6e2d6bee45..6e5a6cbafd8 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_generic.c @@ -16,7 +16,7 @@ __weak int board_ahci_enable(void) return 0; } -static int mvebu_ahci_bind(struct udevice *dev) +static int generic_ahci_bind(struct udevice *dev) { struct udevice *scsi_dev; int ret; @@ -30,7 +30,7 @@ static int mvebu_ahci_bind(struct udevice *dev) return 0; } -static int mvebu_ahci_probe(struct udevice *dev) +static int generic_ahci_probe(struct udevice *dev) { /* * Board specific SATA / AHCI enable code, e.g. enable the @@ -43,18 +43,19 @@ static int mvebu_ahci_probe(struct udevice *dev) return 0; } -static const struct udevice_id mvebu_ahci_ids[] = { +static const struct udevice_id generic_ahci_ids[] = { { .compatible = "marvell,armada-380-ahci" }, { .compatible = "marvell,armada-3700-ahci" }, { .compatible = "marvell,armada-8k-ahci" }, { .compatible = "cavium,octeon-7130-ahci" }, + { .compatible = "generic-ahci" }, { } }; -U_BOOT_DRIVER(ahci_mvebu_drv) = { - .name = "ahci_mvebu", +U_BOOT_DRIVER(ahci_generic_drv) = { + .name = "ahci_generic", .id = UCLASS_AHCI, - .of_match = mvebu_ahci_ids, - .bind = mvebu_ahci_bind, - .probe = mvebu_ahci_probe, + .of_match = generic_ahci_ids, + .bind = generic_ahci_bind, + .probe = generic_ahci_probe, }; diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index 9f784228921..4763963914b 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -48,6 +48,7 @@ enum method_t { METHOD_FILL_SSDT, METHOD_INJECT_DSDT, METHOD_SETUP_NHLT, + METHOD_FILL_MADT, }; /* Prototype for all methods */ @@ -282,6 +283,8 @@ acpi_method acpi_get_method(struct udevice *dev, enum method_t method) switch (method) { case METHOD_WRITE_TABLES: return aops->write_tables; + case METHOD_FILL_MADT: + return aops->fill_madt; case METHOD_FILL_SSDT: return aops->fill_ssdt; case METHOD_INJECT_DSDT: @@ -328,6 +331,19 @@ int acpi_recurse_method(struct acpi_ctx *ctx, struct udevice *parent, return 0; } +int acpi_fill_madt_subtbl(struct acpi_ctx *ctx) +{ + int ret; + + log_debug("Writing MADT table\n"); + ret = acpi_recurse_method(ctx, dm_root(), METHOD_FILL_MADT, TYPE_NONE); + log_debug("Writing MADT finished, err=%d\n", ret); + if (ret) + return log_msg_ret("build", ret); + + return ret; +} + int acpi_fill_ssdt(struct acpi_ctx *ctx) { void *start = ctx->current; diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig index 5c06cd9f60e..4cc3679c009 100644 --- a/drivers/cpu/Kconfig +++ b/drivers/cpu/Kconfig @@ -26,6 +26,13 @@ config CPU_RISCV help Support CPU cores for RISC-V architecture. +config CPU_ARMV8 + bool "Enable generic ARMv8 CPU driver" + depends on CPU && ARM64 + select IRQ + help + Support CPU cores for armv8 architecture. + config CPU_MICROBLAZE bool "Enable Microblaze CPU driver" depends on CPU && MICROBLAZE diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile index bc75d9b974e..eaf494706e2 100644 --- a/drivers/cpu/Makefile +++ b/drivers/cpu/Makefile @@ -6,10 +6,12 @@ obj-$(CONFIG_CPU) += cpu-uclass.o +obj-$(CONFIG_ARCH_BCM283X) += bcm283x_cpu.o obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o obj-$(CONFIG_ARCH_IMX8) += imx8_cpu.o obj-$(CONFIG_ARCH_AT91) += at91_cpu.o obj-$(CONFIG_ARCH_MEDIATEK) += mtk_cpu.o +obj-$(CONFIG_CPU_ARMV8) += armv8_cpu.o obj-$(CONFIG_CPU_IMX) += imx8_cpu.o obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o diff --git a/drivers/cpu/armv8_cpu.c b/drivers/cpu/armv8_cpu.c new file mode 100644 index 00000000000..4eedfe5e2c5 --- /dev/null +++ b/drivers/cpu/armv8_cpu.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 9elements GmbH + */ +#include <cpu.h> +#include <dm.h> +#include <irq.h> +#include <acpi/acpigen.h> +#include <asm/armv8/cpu.h> +#include <asm/io.h> +#include <dm/acpi.h> +#include <linux/bitops.h> +#include <linux/printk.h> +#include <linux/sizes.h> + +static int armv8_cpu_get_desc(const struct udevice *dev, char *buf, int size) +{ + int cpuid; + + cpuid = (read_midr() & MIDR_PARTNUM_MASK) >> MIDR_PARTNUM_SHIFT; + + snprintf(buf, size, "CPU MIDR %04x", cpuid); + + return 0; +} + +static int armv8_cpu_get_info(const struct udevice *dev, + struct cpu_info *info) +{ + info->cpu_freq = 0; + info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU); + + return 0; +} + +static int armv8_cpu_get_count(const struct udevice *dev) +{ + return uclass_id_count(UCLASS_CPU); +} + +#ifdef CONFIG_ACPIGEN +int armv8_cpu_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + uint core_id = dev_seq(dev); + + acpigen_write_processor_device(ctx, core_id); + + return 0; +} + +int armv8_cpu_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + struct acpi_madt_gicc *gicc; + struct cpu_plat *cpu_plat; + struct udevice *gic; + u64 gicc_gicv = 0; + u64 gicc_gich = 0; + u64 gicc_gicr_base = 0; + u64 gicc_phys_base = 0; + u32 gicc_perf_gsiv = 0; + u64 gicc_mpidr; + u32 gicc_vgic_maint_irq = 0; + int addr_index; + fdt_addr_t addr; + int ret; + struct irq req_irq; + + cpu_plat = dev_get_parent_plat(dev); + if (!cpu_plat) + return 0; + + ret = irq_get_interrupt_parent(dev, &gic); + if (ret) { + log_err("%s: Failed to find interrupt parent for %s\n", + __func__, dev->name); + return -ENODEV; + } + + addr_index = 1; + + if (device_is_compatible(gic, "arm,gic-v3")) { + addr = dev_read_addr_index(gic, addr_index++); + if (addr != FDT_ADDR_T_NONE) + gicc_gicr_base = addr; + } + + addr = dev_read_addr_index(gic, addr_index++); + if (addr != FDT_ADDR_T_NONE) + gicc_phys_base = addr; + + addr = dev_read_addr_index(gic, addr_index++); + if (addr != FDT_ADDR_T_NONE) + gicc_gich = addr; + + addr = dev_read_addr_index(gic, addr_index++); + if (addr != FDT_ADDR_T_NONE) + gicc_gicv = addr; + + ret = irq_get_by_index(gic, 0, &req_irq); + if (!ret) + gicc_vgic_maint_irq = req_irq.id; + + gicc_mpidr = dev_read_u64_default(dev, "reg", 0); + if (!gicc_mpidr) + gicc_mpidr = dev_read_u32_default(dev, "reg", 0); + + /* + * gicc_vgic_maint_irq and gicc_gicv are the same for every CPU + */ + gicc = ctx->current; + acpi_write_madt_gicc(gicc, + dev_seq(dev), + gicc_perf_gsiv, /* FIXME: needs a PMU driver */ + gicc_phys_base, + gicc_gicv, + gicc_gich, + gicc_vgic_maint_irq, + gicc_gicr_base, + gicc_mpidr, + 0); /* FIXME: Not defined in DT */ + + acpi_inc(ctx, gicc->length); + + return 0; +} + +struct acpi_ops armv8_cpu_acpi_ops = { + .fill_ssdt = armv8_cpu_fill_ssdt, + .fill_madt = armv8_cpu_fill_madt, +}; +#endif + +static const struct cpu_ops cpu_ops = { + .get_count = armv8_cpu_get_count, + .get_desc = armv8_cpu_get_desc, + .get_info = armv8_cpu_get_info, +}; + +static const struct udevice_id cpu_ids[] = { + { .compatible = "arm,armv8" }, + {} +}; + +U_BOOT_DRIVER(arm_cpu) = { + .name = "arm-cpu", + .id = UCLASS_CPU, + .of_match = cpu_ids, + .ops = &cpu_ops, + .flags = DM_FLAG_PRE_RELOC, + ACPI_OPS_PTR(&armv8_cpu_acpi_ops) +}; diff --git a/drivers/cpu/armv8_cpu.h b/drivers/cpu/armv8_cpu.h new file mode 100644 index 00000000000..48c705e98de --- /dev/null +++ b/drivers/cpu/armv8_cpu.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 9elements GmbH + */ +#include <dm/acpi.h> +#include <dm/device.h> + +#ifndef _ARMV8_CPU_H_ +#define _ARMV8_CPU_H_ + +/** + * armv8_cpu_fill_ssdt() - Fill the SSDT + * Parses the FDT and writes the SSDT nodes. + * + * @dev: cpu device to generate ACPI tables for + * @ctx: ACPI context pointer + * @return: 0 if OK, or a negative error code. + */ +int armv8_cpu_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx); + +/** + * armv8_cpu_fill_madt() - Fill the MADT + * Parses the FDT and writes the MADT subtables. + * + * @dev: cpu device to generate ACPI tables for + * @ctx: ACPI context pointer + * @return: 0 if OK, or a negative error code. + */ +int armv8_cpu_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx); + +#endif
\ No newline at end of file diff --git a/drivers/cpu/bcm283x_cpu.c b/drivers/cpu/bcm283x_cpu.c new file mode 100644 index 00000000000..59a7b142c95 --- /dev/null +++ b/drivers/cpu/bcm283x_cpu.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 9elements GmbH + */ + +#include <cpu.h> +#include <cpu_func.h> +#include <dm.h> +#include <fdt_support.h> +#include <acpi/acpigen.h> +#include <asm/armv8/cpu.h> +#include <asm/cache.h> +#include <asm/io.h> +#include <asm/global_data.h> +#include <asm/system.h> +#include <asm-generic/sections.h> +#include <linux/bitops.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include "armv8_cpu.h" + +DECLARE_GLOBAL_DATA_PTR; + +struct bcm_plat { + u64 release_addr; +}; + +static int cpu_bcm_get_desc(const struct udevice *dev, char *buf, int size) +{ + struct cpu_plat *plat = dev_get_parent_plat(dev); + const char *name; + + if (size < 32) + return -ENOSPC; + + if (device_is_compatible(dev, "arm,cortex-a53")) + name = "A53"; + else if (device_is_compatible(dev, "arm,cortex-a72")) + name = "A72"; + else + name = "?"; + + snprintf(buf, size, "Broadcom Cortex-%s at %u MHz\n", + name, plat->timebase_freq); + + return 0; +} + +static int cpu_bcm_get_info(const struct udevice *dev, struct cpu_info *info) +{ + struct cpu_plat *plat = dev_get_parent_plat(dev); + + info->cpu_freq = plat->timebase_freq * 1000; + info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU); + + return 0; +} + +static int cpu_bcm_get_count(const struct udevice *dev) +{ + return uclass_id_count(UCLASS_CPU); +} + +static int cpu_bcm_get_vendor(const struct udevice *dev, char *buf, int size) +{ + snprintf(buf, size, "Broadcom"); + + return 0; +} + +static int cpu_bcm_is_current(struct udevice *dev) +{ + struct cpu_plat *plat = dev_get_parent_plat(dev); + + if (plat->cpu_id == (read_mpidr() & 0xffff)) + return 1; + + return 0; +} + +/** + * bcm_cpu_on - Releases the secondary CPU from it's spintable + * + * Write the CPU's spintable mailbox and let the CPU enter U-Boot. + * + * @dev: Device to start + * @return: zero on success or error code on failure. + */ +static int bcm_cpu_on(struct udevice *dev) +{ + struct bcm_plat *plat = dev_get_plat(dev); + ulong *start_address; + + if (plat->release_addr == ~0ULL) + return -ENODATA; + + start_address = map_physmem(plat->release_addr, sizeof(uintptr_t), MAP_NOCACHE); + + /* Point secondary CPU to U-Boot entry */ + *start_address = (uintptr_t)_start; + + /* Make sure the other CPUs see the written start address */ + if (!CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) + flush_dcache_all(); + + /* Send an event to wake up the secondary CPU. */ + asm("dsb ishst\n" + "sev"); + + unmap_physmem(start_address, MAP_NOCACHE); + + return 0; +} + +static const struct cpu_ops cpu_bcm_ops = { + .get_desc = cpu_bcm_get_desc, + .get_info = cpu_bcm_get_info, + .get_count = cpu_bcm_get_count, + .get_vendor = cpu_bcm_get_vendor, + .is_current = cpu_bcm_is_current, +}; + +static const struct udevice_id cpu_bcm_ids[] = { + { .compatible = "arm,cortex-a53" }, /* RPi 3 */ + { .compatible = "arm,cortex-a72" }, /* RPi 4 */ + { } +}; + +static int bcm_cpu_bind(struct udevice *dev) +{ + struct cpu_plat *plat = dev_get_parent_plat(dev); + + plat->cpu_id = dev_read_addr(dev); + + return 0; +} + +/** + * bcm_cpu_of_to_plat - Gather spin-table release address + * + * Read the spin-table release address to allow all seconary CPUs to enter + * U-Boot when necessary. + * + * @dev: Device to start + */ +static int bcm_cpu_of_to_plat(struct udevice *dev) +{ + struct bcm_plat *plat = dev_get_plat(dev); + const char *prop; + + if (CONFIG_IS_ENABLED(ARMV8_MULTIENTRY)) { + plat->release_addr = ~0ULL; + + prop = dev_read_string(dev, "enable-method"); + if (!prop || strcmp(prop, "spin-table")) + return -ENODEV; + + plat->release_addr = dev_read_u64_default(dev, "cpu-release-addr", ~0ULL); + + if (plat->release_addr == ~0ULL) + return -ENODEV; + } + + return 0; +} + +static int bcm_cpu_probe(struct udevice *dev) +{ + struct cpu_plat *plat = dev_get_parent_plat(dev); + struct clk clk; + int ret; + + /* Get a clock if it exists */ + ret = clk_get_by_index(dev, 0, &clk); + if (!ret) { + ret = clk_enable(&clk); + if (ret && (ret != -ENOSYS || ret != -EOPNOTSUPP)) + return ret; + ret = clk_get_rate(&clk); + if (IS_ERR_VALUE(ret)) + return ret; + plat->timebase_freq = ret; + } + + /* + * The armstub holds the secondary CPUs in a spinloop. When + * ARMV8_MULTIENTRY is enabled release the secondary CPUs and + * let them enter U-Boot as well. + */ + if (CONFIG_IS_ENABLED(ARMV8_MULTIENTRY)) { + ret = bcm_cpu_on(dev); + if (ret) + return ret; + } + + return ret; +} + +struct acpi_ops bcm283x_cpu_acpi_ops = { + .fill_ssdt = armv8_cpu_fill_ssdt, + .fill_madt = armv8_cpu_fill_madt, +}; + +U_BOOT_DRIVER(cpu_bcm_drv) = { + .name = "bcm283x_cpu", + .id = UCLASS_CPU, + .of_match = cpu_bcm_ids, + .ops = &cpu_bcm_ops, + .probe = bcm_cpu_probe, + .bind = bcm_cpu_bind, + .of_to_plat = bcm_cpu_of_to_plat, + .plat_auto = sizeof(struct bcm_plat), + ACPI_OPS_PTR(&bcm283x_cpu_acpi_ops) +}; diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c index 79eb7c200dc..ac778593c96 100644 --- a/drivers/misc/irq-uclass.c +++ b/drivers/misc/irq-uclass.c @@ -62,6 +62,40 @@ int irq_read_and_clear(struct irq *irq) return ops->read_and_clear(irq); } +int irq_get_interrupt_parent(const struct udevice *dev, + struct udevice **interrupt_parent) +{ + struct ofnode_phandle_args phandle_args; + struct udevice *irq = NULL; + ofnode node; + int ret; + + if (!dev || !interrupt_parent) + return -EINVAL; + + *interrupt_parent = NULL; + + node = dev_ofnode(dev); + if (!ofnode_valid(node)) + return -EINVAL; + + while (ofnode_valid(node)) { + ret = ofnode_parse_phandle_with_args(node, "interrupt-parent", + NULL, 0, 0, &phandle_args); + if (!ret && !device_get_global_by_ofnode(phandle_args.node, &irq)) + break; + node = ofnode_get_parent(node); + } + + if (!irq) { + log_err("Cannot find an interrupt parent for device %s\n", dev->name); + return -ENODEV; + } + *interrupt_parent = irq; + + return 0; +} + #if CONFIG_IS_ENABLED(OF_PLATDATA) int irq_get_by_phandle(struct udevice *dev, const struct phandle_2_arg *cells, struct irq *irq) @@ -142,10 +176,40 @@ err: int irq_get_by_index(struct udevice *dev, int index, struct irq *irq) { struct ofnode_phandle_args args; - int ret; + struct udevice *interrupt_parent; + int ret, size, i; + const __be32 *list; + u32 count; ret = dev_read_phandle_with_args(dev, "interrupts-extended", "#interrupt-cells", 0, index, &args); + if (ret) { + list = dev_read_prop(dev, "interrupts", &size); + if (!list) + return -ENOENT; + + ret = irq_get_interrupt_parent(dev, &interrupt_parent); + if (ret) + return -ENODEV; + args.node = dev_ofnode(interrupt_parent); + + if (dev_read_u32(interrupt_parent, "#interrupt-cells", &count)) { + log_err("%s: could not get #interrupt-cells for %s\n", + __func__, dev->name); + return -ENOENT; + } + + if (index * count >= size / sizeof(*list)) + return -ENOENT; + if (count > OF_MAX_PHANDLE_ARGS) + count = OF_MAX_PHANDLE_ARGS; + args.args_count = count; + for (i = 0; i < count; i++) + args.args[i] = be32_to_cpup(&list[index * count + i]); + + return irq_get_by_index_tail(ret, dev_ofnode(dev), &args, + "interrupts", index, irq); + } return irq_get_by_index_tail(ret, dev_ofnode(dev), &args, "interrupts-extended", index > 0, irq); diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c index f978c64365c..f089c48f028 100644 --- a/drivers/pci/pcie_brcmstb.c +++ b/drivers/pci/pcie_brcmstb.c @@ -12,6 +12,7 @@ * Copyright (C) 2020 Nicolas Saenz Julienne <nsaenzjulienne@suse.de> */ +#include <asm/arch/acpi/bcm2711.h> #include <errno.h> #include <dm.h> #include <dm/ofnode.h> @@ -21,88 +22,6 @@ #include <linux/log2.h> #include <linux/iopoll.h> -/* Offset of the mandatory PCIe capability config registers */ -#define BRCM_PCIE_CAP_REGS 0x00ac - -/* The PCIe controller register offsets */ -#define PCIE_RC_CFG_VENDOR_SPECIFIC_REG1 0x0188 -#define VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc -#define VENDOR_SPECIFIC_REG1_LITTLE_ENDIAN 0x0 - -#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c -#define CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff - -#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc -#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00 - -#define PCIE_RC_DL_MDIO_ADDR 0x1100 -#define PCIE_RC_DL_MDIO_WR_DATA 0x1104 -#define PCIE_RC_DL_MDIO_RD_DATA 0x1108 - -#define PCIE_MISC_MISC_CTRL 0x4008 -#define MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000 -#define MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000 -#define MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000 -#define MISC_CTRL_MAX_BURST_SIZE_128 0x0 -#define MISC_CTRL_SCB0_SIZE_MASK 0xf8000000 - -#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c -#define PCIE_MEM_WIN0_LO(win) \ - PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 4) - -#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010 -#define PCIE_MEM_WIN0_HI(win) \ - PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 4) - -#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c -#define RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f - -#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034 -#define RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f -#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038 - -#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c -#define RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f - -#define PCIE_MISC_PCIE_STATUS 0x4068 -#define STATUS_PCIE_PORT_MASK 0x80 -#define STATUS_PCIE_PORT_SHIFT 7 -#define STATUS_PCIE_DL_ACTIVE_MASK 0x20 -#define STATUS_PCIE_DL_ACTIVE_SHIFT 5 -#define STATUS_PCIE_PHYLINKUP_MASK 0x10 -#define STATUS_PCIE_PHYLINKUP_SHIFT 4 - -#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070 -#define MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000 -#define MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0 -#define MEM_WIN0_BASE_LIMIT_BASE_HI_SHIFT 12 -#define PCIE_MEM_WIN0_BASE_LIMIT(win) \ - PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT + ((win) * 4) - -#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080 -#define MEM_WIN0_BASE_HI_BASE_MASK 0xff -#define PCIE_MEM_WIN0_BASE_HI(win) \ - PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI + ((win) * 8) - -#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084 -#define PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff -#define PCIE_MEM_WIN0_LIMIT_HI(win) \ - PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8) - -#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204 -#define PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 - -#define PCIE_MSI_INTR2_CLR 0x4508 -#define PCIE_MSI_INTR2_MASK_SET 0x4510 - -#define PCIE_EXT_CFG_DATA 0x8000 - -#define PCIE_EXT_CFG_INDEX 0x9000 - -#define PCIE_RGR1_SW_INIT_1 0x9210 -#define RGR1_SW_INIT_1_PERST_MASK 0x1 -#define RGR1_SW_INIT_1_INIT_MASK 0x2 - /* PCIe parameters */ #define BRCM_NUM_PCIE_OUT_WINS 4 @@ -447,7 +366,7 @@ static int brcm_pcie_probe(struct udevice *dev) * This will need to be changed when support for other SoCs is added. */ setbits_le32(base + PCIE_RGR1_SW_INIT_1, - RGR1_SW_INIT_1_INIT_MASK | RGR1_SW_INIT_1_PERST_MASK); + PCIE_RGR1_SW_INIT_1_INIT_MASK | PCIE_RGR1_SW_INIT_1_PERST_MASK); /* * The delay is a safety precaution to preclude the reset signal * from looking like a glitch. @@ -455,7 +374,7 @@ static int brcm_pcie_probe(struct udevice *dev) udelay(100); /* Take the bridge out of reset */ - clrbits_le32(base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_INIT_MASK); + clrbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_INIT_MASK); clrbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG, PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); @@ -508,7 +427,7 @@ static int brcm_pcie_probe(struct udevice *dev) /* Unassert the fundamental reset */ clrbits_le32(pcie->base + PCIE_RGR1_SW_INIT_1, - RGR1_SW_INIT_1_PERST_MASK); + PCIE_RGR1_SW_INIT_1_PERST_MASK); /* * Wait for 100ms after PERST# deassertion; see PCIe CEM specification @@ -552,7 +471,7 @@ static int brcm_pcie_probe(struct udevice *dev) * a PCIe-PCIe bridge (the default setting is to be EP mode). */ clrsetbits_le32(base + PCIE_RC_CFG_PRIV1_ID_VAL3, - CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK, 0x060400); + PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK, 0x060400); if (pcie->ssc) { ret = brcm_pcie_set_ssc(pcie->base); @@ -570,8 +489,8 @@ static int brcm_pcie_probe(struct udevice *dev) nlw, ssc_good ? "(SSC)" : "(!SSC)"); /* PCIe->SCB endian mode for BAR */ - clrsetbits_le32(base + PCIE_RC_CFG_VENDOR_SPECIFIC_REG1, - VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK, + clrsetbits_le32(base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1, + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK, VENDOR_SPECIFIC_REG1_LITTLE_ENDIAN); /* @@ -584,7 +503,7 @@ static int brcm_pcie_probe(struct udevice *dev) * let's instead just unadvertise ASPM support. */ clrbits_le32(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY, - PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK); + LINK_CAPABILITY_ASPM_SUPPORT_MASK); return 0; } @@ -595,14 +514,14 @@ static int brcm_pcie_remove(struct udevice *dev) void __iomem *base = pcie->base; /* Assert fundamental reset */ - setbits_le32(base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_PERST_MASK); + setbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_PERST_MASK); /* Turn off SerDes */ setbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG, PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); /* Shutdown bridge */ - setbits_le32(base + PCIE_RGR1_SW_INIT_1, RGR1_SW_INIT_1_INIT_MASK); + setbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_INIT_MASK); return 0; } diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index 80c35963b8f..e6bf0c2935b 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -19,6 +19,7 @@ #include <watchdog.h> #include <asm/io.h> #include <serial.h> +#include <spl.h> #include <dm/device_compat.h> #include <dm/platform_data/serial_pl01x.h> #include <linux/compiler.h> @@ -272,6 +273,28 @@ __weak struct serial_device *default_serial_console(void) return &pl01x_serial_drv; } #else + +static int pl01x_serial_getinfo(struct udevice *dev, + struct serial_device_info *info) +{ + struct pl01x_serial_plat *plat = dev_get_plat(dev); + + /* save code size */ + if (!not_xpl()) + return -ENOSYS; + + info->type = SERIAL_CHIP_PL01X; + info->addr_space = SERIAL_ADDRESS_SPACE_MEMORY; + info->addr = plat->base; + info->size = 0x1000; + info->reg_width = 4; + info->reg_shift = 2; + info->reg_offset = 0; + info->clock = plat->clock; + + return 0; +} + int pl01x_serial_setbrg(struct udevice *dev, int baudrate) { struct pl01x_serial_plat *plat = dev_get_plat(dev); @@ -341,6 +364,7 @@ static const struct dm_serial_ops pl01x_serial_ops = { .pending = pl01x_serial_pending, .getc = pl01x_serial_getc, .setbrg = pl01x_serial_setbrg, + .getinfo = pl01x_serial_getinfo, }; #if CONFIG_IS_ENABLED(OF_REAL) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 6e10b629a3c..bb5893d56db 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -68,6 +68,14 @@ config USB_XHCI_MVEBU SoCs, which includes Armada8K, Armada3700 and other Armada family SoCs. +config USB_XHCI_GENERIC + bool "Generic SoC USB 3.0 support" + depends on OF_CONTROL + default n + help + Choose this option to add support for USB 3.0 driver for SoCs + that do not need platform specific code, like on emulated targets. + config USB_XHCI_OCTEON bool "Support for Marvell Octeon family on-chip xHCI USB controller" depends on ARCH_OCTEON diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 792956e647a..301bb9fdee1 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o +obj-$(CONFIG_USB_XHCI_GENERIC) += xhci-generic.o obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o obj-$(CONFIG_USB_XHCI_RCAR) += xhci-rcar.o diff --git a/drivers/usb/host/xhci-generic.c b/drivers/usb/host/xhci-generic.c new file mode 100644 index 00000000000..355d4883176 --- /dev/null +++ b/drivers/usb/host/xhci-generic.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 9elements GmbH + * + * GENERIC USB HOST xHCI Controller + */ +#include <dm.h> +#include <fdtdec.h> +#include <log.h> +#include <usb.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <usb/xhci.h> + +struct generic_xhci_plat { + fdt_addr_t hcd_base; +}; + +/** + * Contains pointers to register base addresses + * for the usb controller. + */ +struct generic_xhci { + struct xhci_ctrl ctrl; /* Needs to come first in this struct! */ + struct usb_plat usb_plat; + struct xhci_hccr *hcd; +}; + +static int xhci_usb_probe(struct udevice *dev) +{ + struct generic_xhci_plat *plat = dev_get_plat(dev); + struct generic_xhci *ctx = dev_get_priv(dev); + struct xhci_hcor *hcor; + int len; + + ctx->hcd = (struct xhci_hccr *)phys_to_virt(plat->hcd_base); + len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase)); + hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len); + + return xhci_register(dev, ctx->hcd, hcor); +} + +static int xhci_usb_of_to_plat(struct udevice *dev) +{ + struct generic_xhci_plat *plat = dev_get_plat(dev); + + /* + * Get the base address for XHCI controller from the device node + */ + plat->hcd_base = dev_read_addr(dev); + if (plat->hcd_base == FDT_ADDR_T_NONE) { + dev_dbg(dev, "Can't get the XHCI register base address\n"); + return -ENXIO; + } + + return 0; +} + +static const struct udevice_id xhci_usb_ids[] = { + { .compatible = "generic-xhci" }, + { } +}; + +U_BOOT_DRIVER(usb_xhci) = { + .name = "xhci_generic", + .id = UCLASS_USB, + .of_match = xhci_usb_ids, + .of_to_plat = xhci_usb_of_to_plat, + .probe = xhci_usb_probe, + .remove = xhci_deregister, + .ops = &xhci_usb_ops, + .plat_auto = sizeof(struct generic_xhci_plat), + .priv_auto = sizeof(struct generic_xhci), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h index 15fd61a51d7..b8b1f1338c6 100644 --- a/include/acpi/acpi_table.h +++ b/include/acpi/acpi_table.h @@ -290,7 +290,8 @@ struct __packed acpi_fadt { #define ACPI_MADT_REV_ACPI_3_0 2 #define ACPI_MADT_REV_ACPI_4_0 3 #define ACPI_MADT_REV_ACPI_5_0 3 -#define ACPI_MADT_REV_ACPI_6_0 5 +#define ACPI_MADT_REV_ACPI_6_2 4 +#define ACPI_MADT_REV_ACPI_6_3 5 #define ACPI_MCFG_REV_ACPI_3_0 1 @@ -342,7 +343,10 @@ enum acpi_apic_types { ACPI_APIC_LX2APIC, /* Processor local x2APIC */ ACPI_APIC_LX2APIC_NMI, /* Local x2APIC NMI */ ACPI_APIC_GICC, /* Generic Interrupt Ctlr CPU i/f */ - ACPI_APIC_GICD /* Generic Interrupt Ctlr Distributor */ + ACPI_APIC_GICD, /* Generic Interrupt Ctlr Distributor */ + ACPI_APIC_MSI_FRAME, /* Generic Interrupt MSI Frame */ + ACPI_APIC_GICR, /* Generic Interrupt Ctlr Redistributor */ + ACPI_APIC_ITS, /* Interrupt Translation Service */ }; /* MADT: Processor Local APIC Structure */ @@ -386,20 +390,20 @@ struct __packed acpi_madt_lapic_nmi { u8 lint; /* Local APIC LINT# */ }; -/* flags for acpi_madr_gicc flags word */ +/* flags for acpi_madt_gicc flags word */ enum { - ACPI_MADRF_ENABLED = BIT(0), - ACPI_MADRF_PERF = BIT(1), - ACPI_MADRF_VGIC = BIT(2), + ACPI_MADTF_ENABLED = BIT(0), + ACPI_MADTF_PERF = BIT(1), + ACPI_MADTF_VGIC = BIT(2), }; /** - * struct __packed acpi_madr_gicc - GIC CPU interface (type 0xb) + * struct __packed acpi_madt_gicc - GIC CPU interface (type 0xb) * * This holds information about the Generic Interrupt Controller (GIC) CPU * interface. See ACPI Spec v6.3 section 5.2.12.14 */ -struct acpi_madr_gicc { +struct acpi_madt_gicc { u8 type; u8 length; u16 reserved; @@ -421,12 +425,12 @@ struct acpi_madr_gicc { } __packed; /** - * struct __packed acpi_madr_gicc - GIC distributor (type 0xc) + * struct __packed acpi_madt_gicc - GIC distributor (type 0xc) * * This holds information about the Generic Interrupt Controller (GIC) * Distributor interface. See ACPI Spec v6.3 section 5.2.12.15 */ -struct acpi_madr_gicd { +struct acpi_madt_gicd { u8 type; u8 length; u16 reserved; @@ -437,6 +441,35 @@ struct acpi_madr_gicd { u8 reserved3[3]; } __packed; +/** + * struct __packed acpi_madt_gicr - GIC Redistributor (type 0xe) + * + * This holds information about the Generic Interrupt Controller (GIC) + * Redistributor interface. See ACPI Spec v6.3 section 5.2.12.17 + */ +struct acpi_madt_gicr { + u8 type; + u8 length; + u16 reserved; + u64 discovery_range_base_address; + u32 discovery_range_length; +} __packed; + +/** + * struct __packed acpi_madt_its - GIC Interrupt Translation Service (type 0xf) + * + * This holds information about the Interrupt Translation Service (ITS) + * Structure. See ACPI Spec v6.3 section 5.2.12.18 + */ +struct acpi_madt_its { + u8 type; + u8 length; + u16 reserved; + u32 gic_its_id; + u64 physical_base_address; + u32 reserved2; +} __packed; + /* MCFG (PCI Express MMIO config space BAR description table) */ struct acpi_mcfg { struct acpi_table_header header; @@ -707,6 +740,8 @@ struct acpi_gtdt { u32 virt_el2_flags; } __packed; +#define GTDT_FLAG_INT_ACTIVE_LOW BIT(1) + /** * struct acpi_bgrt - Boot Graphics Resource Table (BGRT) * @@ -797,6 +832,117 @@ struct acpi_pptt_cache { u16 line_size; } __packed; +/** IORT - IO Remapping Table revision 6 + * Document number: ARM DEN 0049E.e, Sep 2022 + */ +struct acpi_table_iort { + struct acpi_table_header header; + u32 node_count; + u32 node_offset; + u32 reserved; +} __packed; + +/* + * IORT subtables + */ +struct acpi_iort_node { + u8 type; + u16 length; + u8 revision; + u32 identifier; + u32 mapping_count; + u32 mapping_offset; + char node_data[]; +} __packed; + +/* Values for subtable Type above */ +enum acpi_iort_node_type { + ACPI_IORT_NODE_ITS_GROUP = 0x00, + ACPI_IORT_NODE_NAMED_COMPONENT = 0x01, + ACPI_IORT_NODE_PCI_ROOT_COMPLEX = 0x02, + ACPI_IORT_NODE_SMMU = 0x03, + ACPI_IORT_NODE_SMMU_V3 = 0x04, + ACPI_IORT_NODE_PMCG = 0x05, + ACPI_IORT_NODE_RMR = 0x06, +}; + +/* ITS Group revision 1 */ +struct acpi_iort_its_group { + u32 its_count; + u32 identifiers[]; /* GIC ITS identifier array */ +} __packed; + +/* PCI root complex node revision 2 */ +struct acpi_iort_rc { + u64 mem_access_properties; + u32 ats_attributes; + u32 pci_segment_number; + u8 memory_address_size_limit; + u8 reserved[3]; +} __packed; + +/* SMMUv3 revision 5 */ +struct acpi_iort_smmu_v3 { + u64 base_address; /* SMMUv3 base address */ + u32 flags; + u32 reserved; + u64 vatos_address; + u32 model; + u32 event_gsiv; + u32 pri_gsiv; + u32 gerr_gsiv; + u32 sync_gsiv; + u32 pxm; + u32 id_mapping_index; +} __packed; + +/* Masks for Flags field above */ +#define ACPI_IORT_SMMU_V3_COHACC_OVERRIDE (1) +#define ACPI_IORT_SMMU_V3_HTTU_OVERRIDE (3 << 1) +#define ACPI_IORT_SMMU_V3_PXM_VALID (1 << 3) +#define ACPI_IORT_SMMU_V3_DEVICEID_VALID (1 << 4) + +struct acpi_iort_id_mapping { + u32 input_base; /* Lowest value in input range */ + u32 id_count; /* Number of IDs */ + u32 output_base; /* Lowest value in output range */ + u32 output_reference; /* A reference to the output node */ + u32 flags; +} __packed; + +/* Masks for Flags field above for IORT subtable */ +#define ACPI_IORT_ID_SINGLE_MAPPING (1) + +/* Named Component revision 4 */ +struct acpi_iort_named_component { + u32 node_flags; + u64 memory_properties; /* Memory access properties */ + u8 memory_address_limit; /* Memory address size limit */ + char device_name[]; /* Path of namespace object */ +} __packed; + +/* Masks for Flags field above */ +#define ACPI_IORT_NC_STALL_SUPPORTED (1) +#define ACPI_IORT_NC_PASID_BITS (31 << 1) + +struct acpi_iort_root_complex { + u64 memory_properties; /* Memory access properties */ + u32 ats_attribute; + u32 pci_segment_number; + u8 memory_address_limit;/* Memory address size limit */ + u16 pasid_capabilities; /* PASID Capabilities */ + u8 reserved; /* Reserved, must be zero */ + u32 flags; /* Flags */ +} __packed; + +/* Masks for ats_attribute field above */ +#define ACPI_IORT_ATS_SUPPORTED (1) /* The root complex ATS support */ +#define ACPI_IORT_PRI_SUPPORTED (1 << 1) /* The root complex PRI support */ +#define ACPI_IORT_PASID_FWD_SUPPORTED (1 << 2) /* The root complex PASID forward support */ + +/* Masks for pasid_capabilities field above */ +#define ACPI_IORT_PASID_MAX_WIDTH (0x1F) /* Bits 0-4 */ + /* Tables defined/reserved by ACPI and generated by U-Boot */ enum acpi_tables { ACPITAB_BERT, @@ -806,12 +952,14 @@ enum acpi_tables { ACPITAB_ECDT, ACPITAB_FACS, ACPITAB_FADT, + ACPITAB_GTDT, ACPITAB_HEST, ACPITAB_HPET, ACPITAB_IVRS, ACPITAB_MADT, ACPITAB_MCFG, ACPITAB_NHLT, + ACPITAB_PPTT, ACPITAB_RSDP, ACPITAB_RSDT, ACPITAB_SLIT, @@ -847,6 +995,19 @@ int acpi_get_table_revision(enum acpi_tables table); int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags); /** + * acpi_create_mcfg_mmconfig() - Create a MCFG table entry + * + * @mmconfig: Place to put the table + * @base: Base address of the ECAM space + * @seg_nr: PCI segment number + * @start: PCI bus start number + * @end: PCI bus end number + * Return: size of data written in bytes + */ +int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, u32 base, + u16 seg_nr, u8 start, u8 end); + +/** * acpi_create_dbg2() - Create a DBG2 table * * This table describes how to access the debug UART @@ -914,6 +1075,17 @@ static inline int acpi_add_fadt(struct acpi_ctx *ctx, struct acpi_fadt *fadt) } /** + * acpi_write_dbg2_pci_uart() - Write out a DBG2 table + * + * @ctx: Current ACPI context + * @dev: Debug UART device to describe + * @access_size: Access size for UART (e.g. ACPI_ACCESS_SIZE_DWORD_ACCESS) + * Return: 0 if OK, -ve on error + */ +int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev, + uint access_size); + +/** * acpi_write_rsdp() - Write out an RSDP indicating where the ACPI tables are * * @rsdp: Address to write RSDP @@ -944,6 +1116,138 @@ void acpi_fill_header(struct acpi_table_header *header, char *signature); int acpi_fill_csrt(struct acpi_ctx *ctx); /** + * acpi_fill_fadt() - Fill out the body of the FADT + * + * Must be implemented in SoC specific code or in mainboard code. + * + * @fadt: Pointer to FADT to update + */ +void acpi_fill_fadt(struct acpi_fadt *fadt); + +/** + * acpi_fill_iort() - Fill out the body of the IORT table + * + * Should be implemented in SoC specific code. + * + * @ctx: ACPI context to write to + * @offset: Offset from the start of the IORT + */ +int acpi_fill_iort(struct acpi_ctx *ctx); + +/** + * acpi_iort_add_its_group() - Add ITS group node to IORT table + * + * Called by SoC specific code within acpi_fill_iort(). + * + * @ctx: ACPI context to write to + * @its_count: Elements in identifiers + * @identifiers: The array of ITS identifiers. These IDs must match the value + * used in the Multiple APIC Description Table (MADT) GIC ITS + * structure for each relevant ITS unit. + * @return Offset of table within parent + */ +int acpi_iort_add_its_group(struct acpi_ctx *ctx, + const u32 its_count, + const u32 *identifiers); + +/** + * acpi_iort_add_named_component() - Add named component to IORT table + * + * Called by SoC specific code within acpi_fill_iort(). + * + * @ctx: ACPI context to write to + * @node_flags: Node flags + * @memory_properties: Memory properties + * @memory_address_limit: Memory address limit + * @device_name: ACPI device path + * @return Offset of table within parent + */ +int acpi_iort_add_named_component(struct acpi_ctx *ctx, + const u32 node_flags, + const u64 memory_properties, + const u8 memory_address_limit, + const char *device_name); + +/** + * acpi_iort_add_rc() - Add PCI root complex node to IORT table + * + * Called by SoC specific code within acpi_fill_iort(). + * + * @ctx: ACPI context to write to + * @mem_access_properties: Memory access properties + * @ats_attributes: Support for ATS and its ancillary feature + * @pci_segment_number: The PCI segment number, as in MCFG + * @memory_address_size_limit: The number of address bits, starting from LSB + * @num_mappings: Number of elements in map + * @map: ID mappings for this node + * @return Offset of table within parent + */ +int acpi_iort_add_rc(struct acpi_ctx *ctx, + const u64 mem_access_properties, + const u32 ats_attributes, + const u32 pci_segment_number, + const u8 memory_address_size_limit, + const int num_mappings, + const struct acpi_iort_id_mapping *map); + +/** + * acpi_iort_add_smmu_v3() - Add PCI root complex node to IORT table + * + * Called by SoC specific code within acpi_fill_iort(). + * + * @ctx: ACPI context to write to + * @base_address: Base address of SMMU + * @flags: SMMUv3 flags + * @vatos_address: Optional, set to zero if not supported + * @model: Model ID + * @event_gsiv: GSIV of the Event interrupt if SPI based + * @pri_gsiv: GSIV of the PRI interrupt if SPI based + * @gerr_gsiv: GSIV of the GERR interrupt if GSIV based + * @sync_gsiv: TGSIV of the Sync interrupt if GSIV based + * @pxm: Proximity Domain + * @id_mapping_index: If all the SMMU control interrupts are GSIV based, + * this field is ignored. Index into the array of ID + * mapping otherwise. + * @num_mappings: Number of elements in map + * @map: ID mappings for this node + * @return Offset of table within parent + */ +int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx, + const u64 base_address, + const u32 flags, + const u64 vatos_address, + const u32 model, + const u32 event_gsiv, + const u32 pri_gsiv, + const u32 gerr_gsiv, + const u32 sync_gsiv, + const u32 pxm, + const u32 id_mapping_index, + const int num_mappings, + const struct acpi_iort_id_mapping *map); + +/** + * acpi_fill_madt() - Fill out the body of the MADT + * + * Must be implemented in SoC specific code. + * + * @madt: The MADT to update + * @ctx: ACPI context to write MADT sub-tables to + * @return Pointer to the end of tables, where the next tables can be written + */ +void *acpi_fill_madt(struct acpi_madt *madt, struct acpi_ctx *ctx); + +/** + * acpi_write_park() - Installs the ACPI parking protocol. + * + * Sets up the ACPI parking protocol and installs the spinning code for + * secondary CPUs. + * + * @madt: The MADT to update + */ +void acpi_write_park(struct acpi_madt *madt); + +/** * acpi_get_rsdp_addr() - get ACPI RSDP table address * * This routine returns the ACPI RSDP table address in the system memory. diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h index 3aa94d70b9c..16df85b9c1b 100644 --- a/include/acpi/acpigen.h +++ b/include/acpi/acpigen.h @@ -833,6 +833,7 @@ void acpigen_write_dsm_end(struct acpi_ctx *ctx); * * This emits a Processor package header with the required information. The * caller must complete the information and call acpigen_pop_len() at the end + * Deprecated since ACPI 6.0. * * @ctx: ACPI context pointer * @cpuindex: CPU number @@ -843,6 +844,17 @@ void acpigen_write_processor(struct acpi_ctx *ctx, uint cpuindex, u32 pblock_addr, uint pblock_len); /** + * acpigen_write_processor_device() - Write a Processor device + * + * Write a device with _HID ACPI0007 identifying a processor. + * Replacement for the Processor OpCode. + * + * @ctx: ACPI context pointer + * @cpuindex: CPU number + */ +void acpigen_write_processor_device(struct acpi_ctx *ctx, uint cpuindex); + +/** * acpigen_write_processor_package() - Write a package containing the processors * * The package containins the name of each processor in the SoC diff --git a/include/bloblist.h b/include/bloblist.h index b0706b5637d..ff32d3fecfd 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -110,6 +110,7 @@ enum bloblist_tag_t { BLOBLISTT_ACPI_TABLES = 4, BLOBLISTT_TPM_EVLOG = 5, BLOBLISTT_TPM_CRB_BASE = 6, + BLOBLISTT_ACPI_PP = 7, /* Standard area to allocate blobs used across firmware components */ BLOBLISTT_AREA_FIRMWARE = 0x10, diff --git a/include/configs/qemu-sbsa.h b/include/configs/qemu-sbsa.h new file mode 100644 index 00000000000..aff78160e12 --- /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 */ diff --git a/include/dm/acpi.h b/include/dm/acpi.h index 3adfe217678..d6bc0c099ad 100644 --- a/include/dm/acpi.h +++ b/include/dm/acpi.h @@ -147,6 +147,22 @@ struct acpi_ops { int (*write_tables)(const struct udevice *dev, struct acpi_ctx *ctx); /** + * fill_madt() - Generate MADT sub-tables for a device + * + * This is called to create the MADT table. The method should write out + * whatever sub-table is needed by this device. It will end up in the + * MADT table. + * + * Note that this is called 'fill' because the entire contents of the + * MADT is build by calling this method on all devices. + * + * @dev: Device to write + * @ctx: ACPI context to use + * @return 0 if OK, -ve on error + */ + int (*fill_madt)(const struct udevice *dev, struct acpi_ctx *ctx); + + /** * fill_ssdt() - Generate SSDT code for a device * * This is called to create the SSDT code. The method should write out @@ -232,6 +248,16 @@ int acpi_copy_name(char *out_name, const char *name); int acpi_write_dev_tables(struct acpi_ctx *ctx); /** + * acpi_fill_madt_subtbl() - Generate ACPI tables for MADT + * + * This is called to create the MADT sub-tables for all devices. + * + * @ctx: ACPI context to use + * Return: 0 if OK, -ve on error + */ +int acpi_fill_madt_subtbl(struct acpi_ctx *ctx); + +/** * acpi_fill_ssdt() - Generate ACPI tables for SSDT * * This is called to create the SSDT code for all devices. diff --git a/include/irq.h b/include/irq.h index 5638c10128e..0fbc1a5f485 100644 --- a/include/irq.h +++ b/include/irq.h @@ -200,6 +200,20 @@ int irq_restore_polarities(struct udevice *dev); */ int irq_read_and_clear(struct irq *irq); +/** + * irq_get_interrupt_parent() - returns the interrupt parent + * + * Walks the devicetree and returns the interrupt parent's ofnode + * for the specified device. + * + * @dev: device + * @interrupt_parent: The interrupt parent's ofnode' + * Return: 0 success, or error value + * + */ +int irq_get_interrupt_parent(const struct udevice *dev, + struct udevice **interrupt_parent); + struct phandle_2_arg; /** * irq_get_by_phandle() - Get an irq by its phandle information (of-platadata) diff --git a/include/serial.h b/include/serial.h index eabc49f820f..e5f6d984d28 100644 --- a/include/serial.h +++ b/include/serial.h @@ -124,6 +124,7 @@ enum serial_stop { enum serial_chip_type { SERIAL_CHIP_UNKNOWN = -1, SERIAL_CHIP_16550_COMPATIBLE, + SERIAL_CHIP_PL01X, }; enum adr_space_type { diff --git a/lib/Kconfig b/lib/Kconfig index fc2db747dcc..56ffdfa1839 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -315,6 +315,22 @@ config GENERATE_ACPI_TABLE by the operating system. It defines platform-independent interfaces for configuration and power management monitoring. +config ACPI_PARKING_PROTOCOL + bool "Support ACPI parking protocol method" + depends on GENERATE_ACPI_TABLE + depends on ARMV8_MULTIENTRY + depends on BLOBLIST_TABLES + default y if !SEC_FIRMWARE_ARMV8_PSCI && !ARMV8_PSCI + help + Say Y here to support "ACPI parking protocol" enable method + for booting Linux. + + To use this feature, you must do: + - Bring secondary CPUs into U-Boot proper in a board-specific + manner. This must be done *after* relocation. Otherwise, the + secondary CPUs will spin in unprotected memory-area because the + master CPU protects the relocated spin code. + config SPL_TINY_MEMSET bool "Use a very small memset() in SPL" depends on SPL @@ -988,12 +1004,15 @@ menu "System tables" config BLOBLIST_TABLES bool "Put tables in a bloblist" - depends on X86 && BLOBLIST - help - Normally tables are placed at address 0xf0000 and can be up to 64KB - long. With this option, tables are instead placed in the bloblist - with a pointer from 0xf0000. The size can then be larger and the - tables can be placed high in memory. + depends on BLOBLIST + default y if (ARM && EFI_LOADER && GENERATE_ACPI_TABLE) + default n + help + On x86 normally tables are placed at address 0xf0000 and can be up + to 64KB long. With this option, tables are instead placed in the + bloblist with a pointer from 0xf0000. The size can then be larger + and the tables can be placed high in memory. + On other architectures the tables are always placed in high memory. config GENERATE_SMBIOS_TABLE bool "Generate an SMBIOS (System Management BIOS) table" diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 6dbfdb22dec..6473d95c102 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -5,15 +5,28 @@ * Copyright 2019 Google LLC */ -#include <dm.h> +#include <bloblist.h> #include <cpu.h> +#include <dm.h> +#include <efi_api.h> +#include <efi_loader.h> #include <log.h> #include <mapmem.h> #include <tables_csum.h> +#include <serial.h> #include <version_string.h> #include <acpi/acpi_table.h> +#include <acpi/acpi_device.h> #include <asm/global_data.h> #include <dm/acpi.h> +#include <linux/sizes.h> +#include <linux/log2.h> + +enum { + TABLE_SIZE = SZ_64K, +}; + +DECLARE_GLOBAL_DATA_PTR; /* * OEM_REVISION is 32-bit unsigned number. It should be increased only when @@ -61,9 +74,9 @@ int acpi_get_table_revision(enum acpi_tables table) { switch (table) { case ACPITAB_FADT: - return ACPI_FADT_REV_ACPI_3_0; + return ACPI_FADT_REV_ACPI_6_0; case ACPITAB_MADT: - return ACPI_MADT_REV_ACPI_3_0; + return ACPI_MADT_REV_ACPI_6_2; case ACPITAB_MCFG: return ACPI_MCFG_REV_ACPI_3_0; case ACPITAB_TCPA: @@ -105,6 +118,10 @@ int acpi_get_table_revision(enum acpi_tables table) return 1; case ACPITAB_SPCR: return 2; + case ACPITAB_PPTT: /* ACPI 6.2: 1 */ + return 1; + case ACPITAB_GTDT: /* ACPI 6.2: 2, ACPI 6.3: 3 */ + return 2; default: return -EINVAL; } @@ -151,55 +168,148 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table) struct acpi_rsdt *rsdt; struct acpi_xsdt *xsdt; - /* The RSDT is mandatory while the XSDT is not */ - rsdt = ctx->rsdt; + /* On legacy x86 platforms the RSDT is mandatory while the XSDT is not. + * On other platforms there might be no memory below 4GiB, thus RSDT is NULL. + */ + if (ctx->rsdt) { + rsdt = ctx->rsdt; + + /* This should always be MAX_ACPI_TABLES */ + entries_num = ARRAY_SIZE(rsdt->entry); + + for (i = 0; i < entries_num; i++) { + if (rsdt->entry[i] == 0) + break; + } + + if (i >= entries_num) { + log_err("ACPI: Error: too many tables\n"); + return -E2BIG; + } + + /* Add table to the RSDT */ + rsdt->entry[i] = nomap_to_sysmem(table); - /* This should always be MAX_ACPI_TABLES */ - entries_num = ARRAY_SIZE(rsdt->entry); + /* Fix RSDT length or the kernel will assume invalid entries */ + rsdt->header.length = sizeof(struct acpi_table_header) + + (sizeof(u32) * (i + 1)); - for (i = 0; i < entries_num; i++) { - if (rsdt->entry[i] == 0) - break; + /* Re-calculate checksum */ + rsdt->header.checksum = 0; + rsdt->header.checksum = table_compute_checksum((u8 *)rsdt, + rsdt->header.length); } - if (i >= entries_num) { - log_err("ACPI: Error: too many tables\n"); - return -E2BIG; + if (ctx->xsdt) { + /* + * And now the same thing for the XSDT. We use the same index as for + * now we want the XSDT and RSDT to always be in sync in U-Boot + */ + xsdt = ctx->xsdt; + + /* This should always be MAX_ACPI_TABLES */ + entries_num = ARRAY_SIZE(xsdt->entry); + + for (i = 0; i < entries_num; i++) { + if (xsdt->entry[i] == 0) + break; + } + + if (i >= entries_num) { + log_err("ACPI: Error: too many tables\n"); + return -E2BIG; + } + + /* Add table to the XSDT */ + xsdt->entry[i] = nomap_to_sysmem(table); + + /* Fix XSDT length */ + xsdt->header.length = sizeof(struct acpi_table_header) + + (sizeof(u64) * (i + 1)); + + /* Re-calculate checksum */ + xsdt->header.checksum = 0; + xsdt->header.checksum = table_compute_checksum((u8 *)xsdt, + xsdt->header.length); } - /* Add table to the RSDT */ - rsdt->entry[i] = nomap_to_sysmem(table); + return 0; +} - /* Fix RSDT length or the kernel will assume invalid entries */ - rsdt->header.length = sizeof(struct acpi_table_header) + - (sizeof(u32) * (i + 1)); +int acpi_write_fadt(struct acpi_ctx *ctx, const struct acpi_writer *entry) +{ + struct acpi_table_header *header; + struct acpi_fadt *fadt; - /* Re-calculate checksum */ - rsdt->header.checksum = 0; - rsdt->header.checksum = table_compute_checksum((u8 *)rsdt, - rsdt->header.length); + fadt = ctx->current; + header = &fadt->header; - /* - * And now the same thing for the XSDT. We use the same index as for - * now we want the XSDT and RSDT to always be in sync in U-Boot - */ - xsdt = ctx->xsdt; + memset((void *)fadt, '\0', sizeof(struct acpi_fadt)); + + acpi_fill_header(header, "FACP"); + header->length = sizeof(struct acpi_fadt); + header->revision = acpi_get_table_revision(ACPITAB_FADT); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, OEM_TABLE_ID, 8); + memcpy(header->creator_id, ASLC_ID, 4); + header->creator_revision = 1; + fadt->minor_revision = 2; - /* Add table to the XSDT */ - xsdt->entry[i] = nomap_to_sysmem(table); + fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs); + fadt->x_dsdt = map_to_sysmem(ctx->dsdt); - /* Fix XSDT length */ - xsdt->header.length = sizeof(struct acpi_table_header) + - (sizeof(u64) * (i + 1)); + if (fadt->x_firmware_ctrl < 0x100000000ULL) + fadt->firmware_ctrl = fadt->x_firmware_ctrl; - /* Re-calculate checksum */ - xsdt->header.checksum = 0; - xsdt->header.checksum = table_compute_checksum((u8 *)xsdt, - xsdt->header.length); + if (fadt->x_dsdt < 0x100000000ULL) + fadt->dsdt = fadt->x_dsdt; + + fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED; + + acpi_fill_fadt(fadt); + + header->checksum = table_compute_checksum(fadt, header->length); + + return acpi_add_fadt(ctx, fadt); +} + +ACPI_WRITER(5fadt, "FADT", acpi_write_fadt, 0); + +int acpi_write_madt(struct acpi_ctx *ctx, const struct acpi_writer *entry) +{ + struct acpi_table_header *header; + struct acpi_madt *madt; + void *current; + + madt = ctx->current; + + memset(madt, '\0', sizeof(struct acpi_madt)); + header = &madt->header; + + /* Fill out header fields */ + acpi_fill_header(header, "APIC"); + header->length = sizeof(struct acpi_madt); + header->revision = acpi_get_table_revision(ACPITAB_MADT); + + acpi_inc(ctx, sizeof(struct acpi_madt)); + /* TODO: Get rid of acpi_fill_madt and use driver model */ + current = acpi_fill_madt(madt, ctx); + + /* (Re)calculate length and checksum */ + header->length = (uintptr_t)current - (uintptr_t)madt; + + if (IS_ENABLED(CONFIG_ACPI_PARKING_PROTOCOL)) + acpi_write_park(madt); + + header->checksum = table_compute_checksum((void *)madt, header->length); + acpi_add_table(ctx, madt); + ctx->current = (void *)madt + madt->header.length; return 0; } +ACPI_WRITER(5madt, "MADT", acpi_write_madt, 0); + void acpi_create_dbg2(struct acpi_dbg2_header *dbg2, int port_type, int port_subtype, struct acpi_gen_regaddr *address, u32 address_size, @@ -262,3 +372,451 @@ void acpi_create_dbg2(struct acpi_dbg2_header *dbg2, header->length = current - (uintptr_t)dbg2; header->checksum = table_compute_checksum(dbg2, header->length); } + +int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev, + uint access_size) +{ + struct acpi_dbg2_header *dbg2 = ctx->current; + char path[ACPI_PATH_MAX]; + struct acpi_gen_regaddr address; + u64 addr; + int ret; + + if (!device_active(dev)) { + log_info("Device not enabled\n"); + return -EACCES; + } + /* + * PCI devices don't remember their resource allocation information in + * U-Boot at present. We assume that MMIO is used for the UART and that + * the address space is 32 bytes: ns16550 uses 8 registers of up to + * 32-bits each. This is only for debugging so it is not a big deal. + */ + addr = dm_pci_read_bar32(dev, 0); + log_debug("UART addr %lx\n", (ulong)addr); + + ret = acpi_device_path(dev, path, sizeof(path)); + if (ret) + return log_msg_ret("path", ret); + + memset(&address, '\0', sizeof(address)); + address.space_id = ACPI_ADDRESS_SPACE_MEMORY; + address.addrl = (uint32_t)addr; + address.addrh = (uint32_t)((addr >> 32) & 0xffffffff); + address.access_size = access_size; + + ret = acpi_device_path(dev, path, sizeof(path)); + if (ret) + return log_msg_ret("path", ret); + acpi_create_dbg2(dbg2, ACPI_DBG2_SERIAL_PORT, + ACPI_DBG2_16550_COMPATIBLE, &address, 0x1000, path); + + acpi_inc_align(ctx, dbg2->header.length); + acpi_add_table(ctx, dbg2); + + return 0; +} + +static int acpi_write_spcr(struct acpi_ctx *ctx, const struct acpi_writer *entry) +{ + struct serial_device_info serial_info = {0}; + ulong serial_address, serial_offset; + struct acpi_table_header *header; + struct acpi_spcr *spcr; + struct udevice *dev; + uint serial_config; + uint serial_width; + int access_size; + int space_id; + int ret = -ENODEV; + + spcr = ctx->current; + header = &spcr->header; + + memset(spcr, '\0', sizeof(struct acpi_spcr)); + + /* Fill out header fields */ + acpi_fill_header(header, "SPCR"); + header->length = sizeof(struct acpi_spcr); + header->revision = 2; + + /* Read the device once, here. It is reused below */ + dev = gd->cur_serial_dev; + if (dev) + ret = serial_getinfo(dev, &serial_info); + if (ret) + serial_info.type = SERIAL_CHIP_UNKNOWN; + + /* Encode chip type */ + switch (serial_info.type) { + case SERIAL_CHIP_16550_COMPATIBLE: + spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE; + break; + case SERIAL_CHIP_PL01X: + spcr->interface_type = ACPI_DBG2_ARM_PL011; + break; + case SERIAL_CHIP_UNKNOWN: + default: + spcr->interface_type = ACPI_DBG2_UNKNOWN; + break; + } + + /* Encode address space */ + switch (serial_info.addr_space) { + case SERIAL_ADDRESS_SPACE_MEMORY: + space_id = ACPI_ADDRESS_SPACE_MEMORY; + break; + case SERIAL_ADDRESS_SPACE_IO: + default: + space_id = ACPI_ADDRESS_SPACE_IO; + break; + } + + serial_width = serial_info.reg_width * 8; + serial_offset = serial_info.reg_offset << serial_info.reg_shift; + serial_address = serial_info.addr + serial_offset; + + /* Encode register access size */ + switch (serial_info.reg_shift) { + case 0: + access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS; + break; + case 1: + access_size = ACPI_ACCESS_SIZE_WORD_ACCESS; + break; + case 2: + access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS; + break; + case 3: + access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS; + break; + default: + access_size = ACPI_ACCESS_SIZE_UNDEFINED; + break; + } + + debug("UART type %u @ %lx\n", spcr->interface_type, serial_address); + + /* Fill GAS */ + spcr->serial_port.space_id = space_id; + spcr->serial_port.bit_width = serial_width; + spcr->serial_port.bit_offset = 0; + spcr->serial_port.access_size = access_size; + spcr->serial_port.addrl = lower_32_bits(serial_address); + spcr->serial_port.addrh = upper_32_bits(serial_address); + + /* Encode baud rate */ + switch (serial_info.baudrate) { + case 9600: + spcr->baud_rate = 3; + break; + case 19200: + spcr->baud_rate = 4; + break; + case 57600: + spcr->baud_rate = 6; + break; + case 115200: + spcr->baud_rate = 7; + break; + default: + spcr->baud_rate = 0; + break; + } + + serial_config = SERIAL_DEFAULT_CONFIG; + if (dev) + ret = serial_getconfig(dev, &serial_config); + + spcr->parity = SERIAL_GET_PARITY(serial_config); + spcr->stop_bits = SERIAL_GET_STOP(serial_config); + + /* No PCI devices for now */ + spcr->pci_device_id = 0xffff; + spcr->pci_vendor_id = 0xffff; + + /* + * SPCR has no clue if the UART base clock speed is different + * to the default one. However, the SPCR 1.04 defines baud rate + * 0 as a preconfigured state of UART and OS is supposed not + * to touch the configuration of the serial device. + */ + if (serial_info.clock != SERIAL_DEFAULT_CLOCK) + spcr->baud_rate = 0; + + /* Fix checksum */ + header->checksum = table_compute_checksum((void *)spcr, header->length); + + acpi_add_table(ctx, spcr); + acpi_inc(ctx, spcr->header.length); + + return 0; +} + +ACPI_WRITER(5spcr, "SPCR", acpi_write_spcr, 0); + +__weak int acpi_fill_iort(struct acpi_ctx *ctx) +{ + return 0; +} + +int acpi_iort_add_its_group(struct acpi_ctx *ctx, + const u32 its_count, + const u32 *identifiers) +{ + struct acpi_iort_node *node; + struct acpi_iort_its_group *group; + int offset; + + offset = ctx->current - ctx->tab_start; + + node = ctx->current; + memset(node, '\0', sizeof(struct acpi_iort_node)); + + node->type = ACPI_IORT_NODE_ITS_GROUP; + node->revision = 1; + + node->length = sizeof(struct acpi_iort_node); + node->length += sizeof(struct acpi_iort_its_group); + node->length += sizeof(u32) * its_count; + + group = (struct acpi_iort_its_group *)node->node_data; + group->its_count = its_count; + memcpy(&group->identifiers, identifiers, sizeof(u32) * its_count); + + ctx->current += node->length; + + return offset; +} + +int acpi_iort_add_named_component(struct acpi_ctx *ctx, + const u32 node_flags, + const u64 memory_properties, + const u8 memory_address_limit, + const char *device_name) +{ + struct acpi_iort_node *node; + struct acpi_iort_named_component *comp; + int offset; + + offset = ctx->current - ctx->tab_start; + + node = ctx->current; + memset(node, '\0', sizeof(struct acpi_iort_node)); + + node->type = ACPI_IORT_NODE_NAMED_COMPONENT; + node->revision = 4; + node->length = sizeof(struct acpi_iort_node); + node->length += sizeof(struct acpi_iort_named_component); + node->length += strlen(device_name) + 1; + + comp = (struct acpi_iort_named_component *)node->node_data; + + comp->node_flags = node_flags; + comp->memory_properties = memory_properties; + comp->memory_address_limit = memory_address_limit; + memcpy(comp->device_name, device_name, strlen(device_name) + 1); + + ctx->current += node->length; + + return offset; +} + +int acpi_iort_add_rc(struct acpi_ctx *ctx, + const u64 mem_access_properties, + const u32 ats_attributes, + const u32 pci_segment_number, + const u8 memory_address_size_limit, + const int num_mappings, + const struct acpi_iort_id_mapping *map) +{ + struct acpi_iort_id_mapping *mapping; + struct acpi_iort_node *node; + struct acpi_iort_rc *rc; + int offset; + + offset = ctx->current - ctx->tab_start; + + node = ctx->current; + memset(node, '\0', sizeof(struct acpi_iort_node)); + + node->type = ACPI_IORT_NODE_PCI_ROOT_COMPLEX; + node->revision = 2; + + node->length = sizeof(struct acpi_iort_node); + node->length += sizeof(struct acpi_iort_rc); + node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings; + + rc = (struct acpi_iort_rc *)node->node_data; + rc->mem_access_properties = mem_access_properties; + rc->ats_attributes = ats_attributes; + rc->pci_segment_number = pci_segment_number; + rc->memory_address_size_limit = memory_address_size_limit; + + mapping = (struct acpi_iort_id_mapping *)(rc + 1); + for (int i = 0; i < num_mappings; i++) { + memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping)); + mapping++; + } + + ctx->current += node->length; + + return offset; +} + +int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx, + const u64 base_address, + const u32 flags, + const u64 vatos_address, + const u32 model, + const u32 event_gsiv, + const u32 pri_gsiv, + const u32 gerr_gsiv, + const u32 sync_gsiv, + const u32 pxm, + const u32 id_mapping_index, + const int num_mappings, + const struct acpi_iort_id_mapping *map) +{ + struct acpi_iort_node *node; + struct acpi_iort_smmu_v3 *smmu; + struct acpi_iort_id_mapping *mapping; + int offset; + + offset = ctx->current - ctx->tab_start; + + node = ctx->current; + memset(node, '\0', sizeof(struct acpi_iort_node)); + + node->type = ACPI_IORT_NODE_SMMU_V3; + node->revision = 5; + node->mapping_count = num_mappings; + node->mapping_offset = sizeof(struct acpi_iort_node) + sizeof(struct acpi_iort_smmu_v3); + + node->length = sizeof(struct acpi_iort_node); + node->length += sizeof(struct acpi_iort_smmu_v3); + node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings; + + smmu = (struct acpi_iort_smmu_v3 *)node->node_data; + + smmu->base_address = base_address; + smmu->flags = flags; + smmu->vatos_address = vatos_address; + smmu->model = model; + smmu->event_gsiv = event_gsiv; + smmu->pri_gsiv = pri_gsiv; + smmu->gerr_gsiv = gerr_gsiv; + smmu->sync_gsiv = sync_gsiv; + smmu->pxm = pxm; + smmu->id_mapping_index = id_mapping_index; + + mapping = (struct acpi_iort_id_mapping *)(smmu + 1); + for (int i = 0; i < num_mappings; i++) { + memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping)); + mapping++; + } + + ctx->current += node->length; + + return offset; +} + +static int acpi_write_iort(struct acpi_ctx *ctx, const struct acpi_writer *entry) +{ + struct acpi_table_iort *iort; + struct acpi_iort_node *node; + u32 offset; + int ret; + + iort = ctx->current; + ctx->tab_start = ctx->current; + memset(iort, '\0', sizeof(struct acpi_table_iort)); + + acpi_fill_header(&iort->header, "IORT"); + iort->header.revision = 1; + iort->header.creator_revision = 1; + iort->header.length = sizeof(struct acpi_table_iort); + iort->node_offset = sizeof(struct acpi_table_iort); + + acpi_inc(ctx, sizeof(struct acpi_table_iort)); + + offset = sizeof(struct acpi_table_iort); + ret = acpi_fill_iort(ctx); + if (ret) { + ctx->current = iort; + return log_msg_ret("fill", ret); + } + + /* Count nodes filled in */ + for (node = (void *)iort + iort->node_offset; + node->length > 0 && (void *)node < ctx->current; + node = (void *)node + node->length) + iort->node_count++; + + /* (Re)calculate length and checksum */ + iort->header.length = ctx->current - (void *)iort; + iort->header.checksum = table_compute_checksum((void *)iort, iort->header.length); + log_debug("IORT at %p, length %x\n", iort, iort->header.length); + + /* Drop the table if it is empty */ + if (iort->header.length == sizeof(struct acpi_table_iort)) + return log_msg_ret("fill", -ENOENT); + acpi_add_table(ctx, iort); + + return 0; +} + +ACPI_WRITER(5iort, "IORT", acpi_write_iort, 0); + +/* + * Allocate memory for ACPI tables and write ACPI tables to the + * allocated buffer. + * + * Return: status code + */ +static int alloc_write_acpi_tables(void) +{ + u64 table_end; + void *addr; + + if (IS_ENABLED(CONFIG_X86) || + IS_ENABLED(CONFIG_QFW_ACPI) || + IS_ENABLED(CONFIG_SANDBOX)) { + log_debug("Skipping writing ACPI tables as already done\n"); + return 0; + } + + if (!IS_ENABLED(CONFIG_BLOBLIST_TABLES)) { + log_debug("Skipping writing ACPI tables as BLOBLIST_TABLES is not selected\n"); + return 0; + } + + /* Align the table to a 4KB boundary to keep EFI happy */ + addr = bloblist_add(BLOBLISTT_ACPI_TABLES, TABLE_SIZE, + ilog2(SZ_4K)); + + if (!addr) + return log_msg_ret("mem", -ENOMEM); + + gd->arch.table_start_high = virt_to_phys(addr); + gd->arch.table_end_high = gd->arch.table_start_high + TABLE_SIZE; + + table_end = write_acpi_tables(gd->arch.table_start_high); + if (!table_end) { + log_err("Can't create ACPI configuration table\n"); + return -EINTR; + } + + log_debug("- wrote 'acpi' to %lx, end %llx\n", gd->arch.table_start_high, table_end); + if (table_end > gd->arch.table_end_high) { + log_err("Out of space for configuration tables: need %llx, have %x\n", + table_end - gd->arch.table_start_high, TABLE_SIZE); + return log_msg_ret("acpi", -ENOSPC); + } + + log_debug("- done writing tables\n"); + + return 0; +} + +EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, alloc_write_acpi_tables); diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c index ecff5a50d50..fa9dad32a3f 100644 --- a/lib/acpi/acpigen.c +++ b/lib/acpi/acpigen.c @@ -361,6 +361,17 @@ void acpigen_write_processor(struct acpi_ctx *ctx, uint cpuindex, acpigen_emit_byte(ctx, pblock_len); } +void acpigen_write_processor_device(struct acpi_ctx *ctx, uint cpuindex) +{ + char pscope[16]; + + snprintf(pscope, sizeof(pscope), ACPI_CPU_STRING, cpuindex); + acpigen_write_device(ctx, pscope); + acpigen_write_name_string(ctx, "_HID", "ACPI0007"); + acpigen_write_name_integer(ctx, "_UID", cpuindex); + acpigen_pop_len(ctx); /* Device */ +} + void acpigen_write_processor_package(struct acpi_ctx *ctx, const char *const name, const uint first_core, diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 7ccd7f8d20a..39a26bbb492 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -95,6 +95,21 @@ static int testacpi_get_name(const struct udevice *dev, char *out_name) return acpi_copy_name(out_name, ACPI_TEST_DEV_NAME); } +static int testacpi_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx) +{ + u64 *data = ctx->current; + + /* Only fill madt once */ + if (device_get_uclass_id(dev->parent) != UCLASS_TEST_ACPI) + return 0; + + *data = 0xdeadbeef; + + acpi_inc(ctx, sizeof(u64)); + + return 0; +} + static int testacpi_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx) { const char *data; @@ -124,6 +139,7 @@ static int testacpi_inject_dsdt(const struct udevice *dev, struct acpi_ctx *ctx) struct acpi_ops testacpi_ops = { .get_name = testacpi_get_name, .write_tables = testacpi_write_tables, + .fill_madt = testacpi_fill_madt, .fill_ssdt = testacpi_fill_ssdt, .inject_dsdt = testacpi_inject_dsdt, }; @@ -527,6 +543,33 @@ static int dm_test_acpi_fill_ssdt(struct unit_test_state *uts) } DM_TEST(dm_test_acpi_fill_ssdt, UTF_SCAN_PDATA | UTF_SCAN_FDT); +/* Test acpi_fill_madt() */ +static int dm_test_acpi_fill_madt(struct unit_test_state *uts) +{ + struct acpi_ctx ctx; + u64 *buf; + + buf = malloc(BUF_SIZE); + ut_assertnonnull(buf); + + acpi_reset_items(); + ctx.current = buf; + buf[1] = 'z'; /* sentinel */ + ut_assertok(acpi_fill_madt_subtbl(&ctx)); + + /* + * These values come from acpi-test2's acpi-ssdt-test-data property. + * This device comes first because of u-boot,acpi-ssdt-order + */ + ut_asserteq(0xdeadbeef, buf[0]); + + ut_asserteq('z', buf[1]); + + return 0; +} + +DM_TEST(dm_test_acpi_fill_madt, UTF_SCAN_PDATA | UTF_SCAN_FDT); + /* Test acpi_inject_dsdt() */ static int dm_test_acpi_inject_dsdt(struct unit_test_state *uts) { diff --git a/test/dm/irq.c b/test/dm/irq.c index 836f2d82e71..ca3e1880656 100644 --- a/test/dm/irq.c +++ b/test/dm/irq.c @@ -76,6 +76,21 @@ static int dm_test_request(struct unit_test_state *uts) } DM_TEST(dm_test_request, UTF_SCAN_PDATA | UTF_SCAN_FDT); +/* Test of irq_get_by_index() */ +static int dm_test_irq_get_by_index(struct unit_test_state *uts) +{ + struct udevice *dev; + struct irq irq; + + ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "f-test", + &dev)); + ut_assertok(irq_get_by_index(dev, 0, &irq)); + ut_asserteq(4, irq.id); + + return 0; +} +DM_TEST(dm_test_irq_get_by_index, UTF_SCAN_PDATA | UTF_SCAN_FDT); + /* Test of irq_get_acpi() */ static int dm_test_irq_get_acpi(struct unit_test_state *uts) { diff --git a/test/py/tests/test_event_dump.py b/test/py/tests/test_event_dump.py index e282c67335c..45143c1c7d9 100644 --- a/test/py/tests/test_event_dump.py +++ b/test/py/tests/test_event_dump.py @@ -18,6 +18,7 @@ def test_event_dump(u_boot_console): -------------------- ------------------------------ ------------------------------ EVT_FT_FIXUP bootmeth_vbe_ft_fixup .*boot/vbe_request.c:.* EVT_FT_FIXUP bootmeth_vbe_simple_ft_fixup .*boot/vbe_simple_os.c:.* +EVT_LAST_STAGE_INIT alloc_write_acpi_tables .*lib/acpi/acpi_table.c:.* EVT_LAST_STAGE_INIT install_smbios_table .*lib/efi_loader/efi_smbios.c:.* EVT_MISC_INIT_F sandbox_early_getopt_check .*arch/sandbox/cpu/start.c:.* EVT_TEST h_adder_simple .*test/common/event.c:''' |