From 6d2e72ab63d2369a8408a514fc3ebc9ff4f43cab Mon Sep 17 00:00:00 2001 From: Ivan Velickovic Date: Tue, 14 Oct 2025 14:47:57 +1100 Subject: [PATCH 1/4] libplatsupport: fix FDT macros for expressions I had this line: READ_CELL(num_size_cells, curr_range, x + y)); which ended up being evaluated to addr + (x + y * sizeof(uint32_t)) which gave the completely wrong thing. Now the macros should work if addr or offset are expressions. Signed-off-by: Ivan Velickovic --- libplatsupport/include/platsupport/fdt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libplatsupport/include/platsupport/fdt.h b/libplatsupport/include/platsupport/fdt.h index 6060b6e11..505e62609 100644 --- a/libplatsupport/include/platsupport/fdt.h +++ b/libplatsupport/include/platsupport/fdt.h @@ -15,8 +15,8 @@ * RISCV does have 128 bits but there are no platforms that use that bit length (yet) */ #define READ_CELL32(addr) fdt32_ld(addr) #define READ_CELL64(addr) fdt64_ld(addr) -#define READ_CELL(size, addr, offset) (size == 2 ? READ_CELL64(addr + (offset * sizeof(uint32_t))) : \ - READ_CELL32(addr + (offset * sizeof(uint32_t)))) +#define READ_CELL(size, addr, offset) (size == 2 ? READ_CELL64((addr) + ((offset) * sizeof(uint32_t))) : \ + READ_CELL32((addr) + ((offset) * sizeof(uint32_t)))) /* * Type of the callback function that is called for each device register instance From b7f5e61f14676dc5c983fd1ad9caf41c5802a341 Mon Sep 17 00:00:00 2001 From: Ivan Velickovic Date: Wed, 24 Sep 2025 17:40:46 +1000 Subject: [PATCH 2/4] libplatsupport: fix FDT translation of 'reg' The Device Tree nodes for devices on certain platforms does not describe the actual MMIO address in the 'reg' field. Instead, it can be an offset of the parent bus address. Rather than taking the values of 'reg' as the MMIO registers directly, we have to check that the 'ranges' field exists on the parent and then use it to potentially translate the child node's address. I ran into this when porting the Raspberry Pi 5 to sel4test, where the timer peripheral is allocated via the DTB node unlike other platform support where the device address/IRQs are hard-coded. See section 2.3.8 of v0.4 of the Device Tree specification for more details. Signed-off-by: Ivan Velickovic --- libplatsupport/src/fdt.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/libplatsupport/src/fdt.c b/libplatsupport/src/fdt.c index f5078d40a..c80dacf70 100644 --- a/libplatsupport/src/fdt.c +++ b/libplatsupport/src/fdt.c @@ -116,6 +116,20 @@ int ps_fdt_walk_registers(ps_io_fdt_t *io_fdt, ps_fdt_cookie_t *cookie, reg_walk } int total_cells = prop_len / sizeof(uint32_t); + int parent_ranges_prop_len = 0; + const uint32_t *parent_ranges_prop = fdt_getprop(dtb_blob, parent_offset, "ranges", &parent_ranges_prop_len); + bool parent_has_ranges = parent_ranges_prop != NULL; + + int num_parent_bus_address_cells = 0; + if (parent_has_ranges) { + int parent_bus_node_offset = fdt_parent_offset(dtb_blob, parent_offset); + /* If the parent has the ranges field, it should have its own parent node. */ + if (parent_bus_node_offset < 0) { + return parent_bus_node_offset; + } + num_parent_bus_address_cells = fdt_address_cells(dtb_blob, parent_bus_node_offset); + } + /* sanity check */ assert(total_cells % (num_address_cells + num_size_cells) == 0); @@ -128,6 +142,23 @@ int ps_fdt_walk_registers(ps_io_fdt_t *io_fdt, ps_fdt_cookie_t *cookie, reg_walk curr_pmem.type = PMEM_TYPE_DEVICE; curr_pmem.base_addr = READ_CELL(num_address_cells, curr, 0); curr_pmem.length = READ_CELL(num_size_cells, curr, num_address_cells); + + if (parent_has_ranges) { + assert(num_parent_bus_address_cells != 0); + int parent_ranges_cells = parent_ranges_prop_len / sizeof(uint32_t); + int num_ranges = parent_ranges_cells / (num_parent_bus_address_cells + num_address_cells + num_size_cells); + for (int j = 0; j < num_ranges; j++) { + const void *curr_range = (const void *)(&parent_ranges_prop[j]); + uint64_t child_bus_addr = READ_CELL(num_address_cells, curr_range, 0); + uint64_t parent_bus_addr = READ_CELL(num_parent_bus_address_cells, curr_range, num_address_cells); + uint64_t range_length = READ_CELL(num_size_cells, curr_range, num_address_cells + num_parent_bus_address_cells); + if (child_bus_addr <= curr_pmem.base_addr && child_bus_addr + range_length > curr_pmem.base_addr) { + uint64_t offset = curr_pmem.base_addr - child_bus_addr; + curr_pmem.base_addr = parent_bus_addr + offset; + } + } + } + int error = callback(curr_pmem, i, num_regs, token); if (error) { return error; From 4185108388d0b2254e9f53edd908e1a172f04d16 Mon Sep 17 00:00:00 2001 From: Julia Vassiliki Date: Tue, 7 Jul 2026 13:22:37 +1000 Subject: [PATCH 3/4] trivial: fix libplatsupport CMake style CI complains otherwise. Signed-off-by: Julia Vassiliki --- libplatsupport/CMakeLists.txt | 207 +++++++++++++++------------------- 1 file changed, 89 insertions(+), 118 deletions(-) diff --git a/libplatsupport/CMakeLists.txt b/libplatsupport/CMakeLists.txt index c6b89fa27..5944bcc76 100644 --- a/libplatsupport/CMakeLists.txt +++ b/libplatsupport/CMakeLists.txt @@ -14,154 +14,130 @@ project(libplatsupport C) # Some projects in particular that need to be fixed: # - rumprun-sel4-demoapps if(NOT ${PLATSUPPORT_HELPERS} STREQUAL "") - include(${PLATSUPPORT_HELPERS}) + include(${PLATSUPPORT_HELPERS}) endif() set(configure_string "") config_choice( - LibPlatSupportX86ConsoleDevice - LIB_PLAT_SUPPORT_X86_CONSOLE_DEVICE - "X86 console device. The serial port that libplatsupport will use for communication \ + LibPlatSupportX86ConsoleDevice + LIB_PLAT_SUPPORT_X86_CONSOLE_DEVICE + "X86 console device. The serial port that libplatsupport will use for communication \ com1 -> 0x3f8 \ com2 -> 0x2f8 \ com3 -> 0x3e8 \ com4 -> 0x2e8 \ ega -> 80x25 text mode ega screen" - "com1;LibPlatSupportX86ConsoleDeviceCom1;LIB_PLAT_SUPPORT_SERIAL_PORT_X86_COM1;KernelPlatPC99" - "com2;LibPlatSupportX86ConsoleDeviceCom2;LIB_PLAT_SUPPORT_SERIAL_PORT_X86_COM2;KernelPlatPC99" - "com3;LibPlatSupportX86ConsoleDeviceCom3;LIB_PLAT_SUPPORT_SERIAL_PORT_X86_COM3;KernelPlatPC99" - "com4;LibPlatSupportX86ConsoleDeviceCom4;LIB_PLAT_SUPPORT_SERIAL_PORT_X86_COM4;KernelPlatPC99" - "ega;LibPlatSupportX86ConsoleDeviceEGA;LIB_PLAT_SUPPORT_SERIAL_TEXT_EGA;KernelPlatPC99" -) + "com1;LibPlatSupportX86ConsoleDeviceCom1;LIB_PLAT_SUPPORT_SERIAL_PORT_X86_COM1;KernelPlatPC99" + "com2;LibPlatSupportX86ConsoleDeviceCom2;LIB_PLAT_SUPPORT_SERIAL_PORT_X86_COM2;KernelPlatPC99" + "com3;LibPlatSupportX86ConsoleDeviceCom3;LIB_PLAT_SUPPORT_SERIAL_PORT_X86_COM3;KernelPlatPC99" + "com4;LibPlatSupportX86ConsoleDeviceCom4;LIB_PLAT_SUPPORT_SERIAL_PORT_X86_COM4;KernelPlatPC99" + "ega;LibPlatSupportX86ConsoleDeviceEGA;LIB_PLAT_SUPPORT_SERIAL_TEXT_EGA;KernelPlatPC99") config_choice( - LibPlatSupportLPTMRclock - LIB_PLAT_SUPPORT_LPTMR_CLOCK - "Which input clock to use for the Low Power Timer\ + LibPlatSupportLPTMRclock + LIB_PLAT_SUPPORT_LPTMR_CLOCK + "Which input clock to use for the Low Power Timer\ 32.768 kHz -> High accuracy, but low precision.\ 24 MHz -> Higher precision, but lower accuracy. Synchronous with the scheduling clock." - "32kHz;LibPlatSupportLPTMRclock24MHz;LIB_PLAT_SUPPORT_LPTMR_CLOCK_32kHZ;KernelPlatformIMX93" - "24MHz;LibPlatSupportLPTMRclock32kHz;LIB_PLAT_SUPPORT_LPTMR_CLOCK_24MHz;KernelPlatformIMX93" -) + "32kHz;LibPlatSupportLPTMRclock24MHz;LIB_PLAT_SUPPORT_LPTMR_CLOCK_32kHZ;KernelPlatformIMX93" + "24MHz;LibPlatSupportLPTMRclock32kHz;LIB_PLAT_SUPPORT_LPTMR_CLOCK_24MHz;KernelPlatformIMX93") mark_as_advanced(CLEAR LibPlatSupportX86ConsoleDevice LibPlatSupportLPTMRclock) # Some platforms don't have a platform timer. if((KernelPlatformQEMUArmVirt AND NOT (KernelArmExportPCNTUser AND KernelArmExportPTMRUser)) - OR KernelPlatformRocketchip - OR KernelPlatformRocketchipZCU102 - OR KernelPlatformCheshire - OR (SIMULATION AND (KernelArchRiscV OR KernelArchARM)) -) - set(LibPlatSupportHaveTimer OFF) + OR KernelPlatformRocketchip OR KernelPlatformRocketchipZCU102 OR KernelPlatformCheshire + OR (SIMULATION AND (KernelArchRiscV OR KernelArchARM))) + set(LibPlatSupportHaveTimer OFF) else() - set(LibPlatSupportHaveTimer ON) + set(LibPlatSupportHaveTimer ON) endif() -config_option( - LibPlatSupportHaveTimer LIB_PLAT_SUPPORT_HAVE_TIMER - "Indicates that this platform has support for platform ltimers" DEFAULT ON -) +config_option(LibPlatSupportHaveTimer LIB_PLAT_SUPPORT_HAVE_TIMER + "Indicates that this platform has support for platform ltimers" DEFAULT ON) mark_as_advanced(LibPlatSupportHaveTimer) set(LibPlatSupportMach "") if(KernelPlatformRpi3 OR KernelPlatformRpi4) - set(LibPlatSupportMach "bcm") + set(LibPlatSupportMach "bcm") elseif(KernelPlatformCheshire OR KernelPlatformAriane) - set(LibPlatSupportMach "cva6") + set(LibPlatSupportMach "cva6") elseif(KernelPlatformHifiveP550) - set(LibPlatSupportMach "eswin") + set(LibPlatSupportMach "eswin") elseif(KernelPlatformBananapiF3) - set(LibPlatSupportMach "spacemit") + set(LibPlatSupportMach "spacemit") elseif(KernelPlatformRockpro64 OR KernelPlatformRock3b) - set(LibPlatSupportMach "rockchip") + set(LibPlatSupportMach "rockchip") elseif(NOT ${KernelArmMach} STREQUAL "") - # falling back to kernel settings is done to keep legacy compatibility - set(LibPlatSupportMach "${KernelArmMach}") + # falling back to kernel settings is done to keep legacy compatibility + set(LibPlatSupportMach "${KernelArmMach}") endif() file(GLOB deps src/plat/${KernelPlatform}/*.c src/*.c src/plat/${KernelPlatform}/acpi/*.c) if(NOT ${LibPlatSupportMach} STREQUAL "") - file(GLOB lib_deps "src/mach/${LibPlatSupportMach}/*.c") - list(APPEND deps ${lib_deps}) + file(GLOB lib_deps "src/mach/${LibPlatSupportMach}/*.c") + list(APPEND deps ${lib_deps}) endif() if(KernelArchARM) - list(APPEND deps src/arch/arm/clock.c) - list(APPEND deps src/arch/arm/delay.c) - list(APPEND deps src/arch/arm/dma330.c) - list(APPEND deps src/arch/arm/i2c.c) - list(APPEND deps src/arch/arm/i2c_bitbang.c) - list(APPEND deps src/arch/arm/generic_timer.c) - list(APPEND deps src/arch/arm/irqchip/gic.c) - list(APPEND deps src/arch/arm/irqchip/tegra.c) - list(APPEND deps src/arch/arm/irqchip/gicv3.c) - list(APPEND deps src/arch/arm/irqchip/omap3.c) - # Link the IRQ chip parser modules - list(APPEND irqchip_modules - "-Wl,--undefined=arm_gic_ptr,--undefined=tegra_ictlr_ptr,--undefined=arm_gicv3_ptr,\ ---undefined=fsl_avic_ptr,--undefined=ti_omap3_ptr" - ) + list(APPEND deps src/arch/arm/clock.c) + list(APPEND deps src/arch/arm/delay.c) + list(APPEND deps src/arch/arm/dma330.c) + list(APPEND deps src/arch/arm/i2c.c) + list(APPEND deps src/arch/arm/i2c_bitbang.c) + list(APPEND deps src/arch/arm/generic_timer.c) + list(APPEND deps src/arch/arm/irqchip/gic.c) + list(APPEND deps src/arch/arm/irqchip/tegra.c) + list(APPEND deps src/arch/arm/irqchip/gicv3.c) + list(APPEND deps src/arch/arm/irqchip/omap3.c) + # Link the IRQ chip parser modules + list(APPEND irqchip_modules + "-Wl,--undefined=arm_gic_ptr,--undefined=tegra_ictlr_ptr,--undefined=arm_gicv3_ptr,\ +--undefined=fsl_avic_ptr,--undefined=ti_omap3_ptr") elseif(KernelArchX86) - list(APPEND deps src/arch/x86/delay.c) - list(APPEND deps src/arch/x86/tsc.c) + list(APPEND deps src/arch/x86/delay.c) + list(APPEND deps src/arch/x86/tsc.c) elseif(KernelArchRiscV) - list(APPEND deps src/arch/riscv/irqchip/plic.c) - list(APPEND irqchip_modules "-Wl,--undefined=riscv_plic_ptr") + list(APPEND deps src/arch/riscv/irqchip/plic.c) + list(APPEND irqchip_modules "-Wl,--undefined=riscv_plic_ptr") else() - message(FATAL_ERROR "Unsupported KernelArch '${KernelArch}'") + message(FATAL_ERROR "Unsupported KernelArch '${KernelArch}'") endif() -if(KernelPlatformQEMUArmVirt - OR KernelPlatformQuartz64 - OR KernelPlatformIMX93 -) - if(KernelArmExportPCNTUser AND KernelArmExportPTMRUser) - list(APPEND deps src/arch/arm/generic_ltimer.c) - endif() +if(KernelPlatformQEMUArmVirt OR KernelPlatformQuartz64 OR KernelPlatformIMX93) + if(KernelArmExportPCNTUser AND KernelArmExportPTMRUser) + list(APPEND deps src/arch/arm/generic_ltimer.c) + endif() endif() if(KernelPlatformExynos5422) - list(APPEND deps src/mach/${LibPlatSupportMach}/clock/exynos_5422_clock.c) -elseif( - KernelPlatformExynos4 - OR KernelPlatformExynos5410 - OR KernelPlatformExynos5250 -) - list(APPEND deps src/mach/${LibPlatSupportMach}/clock/exynos_common_clock.c) + list(APPEND deps src/mach/${LibPlatSupportMach}/clock/exynos_5422_clock.c) +elseif(KernelPlatformExynos4 OR KernelPlatformExynos5410 OR KernelPlatformExynos5250) + list(APPEND deps src/mach/${LibPlatSupportMach}/clock/exynos_common_clock.c) endif() if(KernelPlatImx6 OR KernelPlatformImx7Sabre) - list(APPEND deps src/mach/${LibPlatSupportMach}/epit/epit.c) + list(APPEND deps src/mach/${LibPlatSupportMach}/epit/epit.c) endif() -if(KernelPlatImx6 - OR KernelPlatformImx7Sabre - OR KernelPlatformImx8mq-evk - OR KernelPlatformImx8mm-evk - OR KernelPlatformImx8mp-evk - OR KernelPlatformMaaxboard -) - list(APPEND deps src/mach/${LibPlatSupportMach}/serial/serial.c) +if(KernelPlatImx6 OR KernelPlatformImx7Sabre OR KernelPlatformImx8mq-evk OR KernelPlatformImx8mm-evk + OR KernelPlatformImx8mp-evk OR KernelPlatformMaaxboard) + list(APPEND deps src/mach/${LibPlatSupportMach}/serial/serial.c) endif() -if(KernelPlatImx8mq - OR KernelPlatformImx8mm-evk - OR KernelPlatformImx8mp-evk -) - list(APPEND deps src/plat/imx8m/chardev.c) - # There's no clock driver at the moment, but this is to allow the - # libethdrivers to build for imx8mq - list(APPEND deps src/plat/imx8m/clock.c) +if(KernelPlatImx8mq OR KernelPlatformImx8mm-evk OR KernelPlatformImx8mp-evk) + list(APPEND deps src/plat/imx8m/chardev.c) + # There's no clock driver at the moment, but this is to allow the + # libethdrivers to build for imx8mq + list(APPEND deps src/plat/imx8m/clock.c) endif() if(KernelPlatPC99) - set_source_files_properties( - src/plat/pc99/keyboard_vkey.c PROPERTIES COMPILE_FLAGS -Wno-initializer-overrides - ) + set_source_files_properties(src/plat/pc99/keyboard_vkey.c PROPERTIES COMPILE_FLAGS + -Wno-initializer-overrides) endif() list(SORT deps) @@ -170,47 +146,42 @@ add_config_library(platsupport "${configure_string}") add_library(platsupport EXCLUDE_FROM_ALL ${deps}) -if(KernelPlatImx8mq - OR KernelPlatformImx8mm-evk - OR KernelPlatformImx8mp-evk -) - if(KernelPlatformImx8mp-evk) - # For the imx8mp, the DTS is in a different format compared to those of - # the imx8mm and imx8mq, there are some constants in the headers that - # point to the proper path - target_compile_definitions(platsupport PRIVATE USE_IMX8MP_GPT_PATH) - endif() - target_include_directories(platsupport PUBLIC plat_include/imx8m) +if(KernelPlatImx8mq OR KernelPlatformImx8mm-evk OR KernelPlatformImx8mp-evk) + if(KernelPlatformImx8mp-evk) + # For the imx8mp, the DTS is in a different format compared to those of + # the imx8mm and imx8mq, there are some constants in the headers that + # point to the proper path + target_compile_definitions(platsupport PRIVATE USE_IMX8MP_GPT_PATH) + endif() + target_include_directories(platsupport PUBLIC plat_include/imx8m) endif() if(KernelPlatformZynqmp) - # This still needs to be cleaned up, so there is a mach folder "zynqmp" and - # the board specific folders "zcu102" and "ultra96". Then we don't need to - # include this folder here explicitly - target_include_directories(platsupport PUBLIC plat_include/zynqmp) + # This still needs to be cleaned up, so there is a mach folder "zynqmp" and + # the board specific folders "zcu102" and "ultra96". Then we don't need to + # include this folder here explicitly + target_include_directories(platsupport PUBLIC plat_include/zynqmp) endif() if(NOT "${LibPlatSupportMach}" STREQUAL "") - target_include_directories(platsupport PUBLIC mach_include/${LibPlatSupportMach}) + target_include_directories(platsupport PUBLIC mach_include/${LibPlatSupportMach}) endif() # special handling for "arm_hyp", it's an add-on-hack over "aarch32" set(_inc_folder_KernelSel4Arch "${KernelSel4Arch}") if("${KernelSel4Arch}" STREQUAL "arm_hyp") - set(_inc_folder_KernelSel4Arch "aarch32") + set(_inc_folder_KernelSel4Arch "aarch32") endif() target_include_directories( - platsupport PUBLIC include plat_include/${KernelPlatform} - sel4_arch_include/${_inc_folder_KernelSel4Arch} arch_include/${KernelArch} -) + platsupport PUBLIC include plat_include/${KernelPlatform} + sel4_arch_include/${_inc_folder_KernelSel4Arch} arch_include/${KernelArch}) target_link_libraries( - platsupport - muslc - utils - fdt - sel4_autoconf - platsupport_Config - ${irqchip_modules} -) + platsupport + muslc + utils + fdt + sel4_autoconf + platsupport_Config + ${irqchip_modules}) From 5fd42d34e127087d7fdcec9432c3417bad6dd82d Mon Sep 17 00:00:00 2001 From: Ivan Velickovic Date: Wed, 24 Sep 2025 16:56:25 +1000 Subject: [PATCH 4/4] Add support for BCM2712/Raspberry Pi 5B My main goal with this patch is to allow for sel4test to work on the Raspberry Pi 5B, for this reason I have not supported as many peripherals as there is for BCM2711. Mainly GPIO is not supported. My understanding is that the default UART, unlike previous BCM SoCs supported, is not on the GPIO pins anymore. The BCM2712 does still have support for the BCM mini UART however it is now placed on the PCIe bus rather than being directly connected to the SoC. The default UART for BCM2712 is instead the PL011 so I've added support for that. Signed-off-by: Ivan Velickovic --- libplatsupport/CMakeLists.txt | 2 +- .../bcm2712/platsupport/plat/clock.h | 17 ++++++++++ .../bcm2712/platsupport/plat/gpio.h | 10 ++++++ .../bcm2712/platsupport/plat/i2c.h | 11 ++++++ .../bcm2712/platsupport/plat/mailbox.h | 12 +++++++ .../bcm2712/platsupport/plat/serial.h | 34 +++++++++++++++++++ .../bcm2712/platsupport/plat/system_timer.h | 19 +++++++++++ libplatsupport/src/mach/bcm/bcm_uart.c | 7 ++++ libplatsupport/src/mach/bcm/chardev.c | 8 +++++ libplatsupport/src/mach/bcm/pl011_uart.c | 11 ++++++ libplatsupport/src/mach/bcm/serial.c | 14 ++++++++ 11 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 libplatsupport/plat_include/bcm2712/platsupport/plat/clock.h create mode 100644 libplatsupport/plat_include/bcm2712/platsupport/plat/gpio.h create mode 100644 libplatsupport/plat_include/bcm2712/platsupport/plat/i2c.h create mode 100644 libplatsupport/plat_include/bcm2712/platsupport/plat/mailbox.h create mode 100644 libplatsupport/plat_include/bcm2712/platsupport/plat/serial.h create mode 100644 libplatsupport/plat_include/bcm2712/platsupport/plat/system_timer.h diff --git a/libplatsupport/CMakeLists.txt b/libplatsupport/CMakeLists.txt index 5944bcc76..5e3b9896e 100644 --- a/libplatsupport/CMakeLists.txt +++ b/libplatsupport/CMakeLists.txt @@ -60,7 +60,7 @@ config_option(LibPlatSupportHaveTimer LIB_PLAT_SUPPORT_HAVE_TIMER mark_as_advanced(LibPlatSupportHaveTimer) set(LibPlatSupportMach "") -if(KernelPlatformRpi3 OR KernelPlatformRpi4) +if(KernelPlatformRpi3 OR KernelPlatformRpi4 OR KernelPlatformRpi5) set(LibPlatSupportMach "bcm") elseif(KernelPlatformCheshire OR KernelPlatformAriane) set(LibPlatSupportMach "cva6") diff --git a/libplatsupport/plat_include/bcm2712/platsupport/plat/clock.h b/libplatsupport/plat_include/bcm2712/platsupport/plat/clock.h new file mode 100644 index 000000000..0f5085c3e --- /dev/null +++ b/libplatsupport/plat_include/bcm2712/platsupport/plat/clock.h @@ -0,0 +1,17 @@ +/* + * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) + * Copyright (C) 2021, Hensoldt Cyber GmbH + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#pragma once + +enum clk_id { + CLK_MASTER, + /* ----- */ + NCLOCKS, +}; + +enum clock_gate { + NCLKGATES +}; diff --git a/libplatsupport/plat_include/bcm2712/platsupport/plat/gpio.h b/libplatsupport/plat_include/bcm2712/platsupport/plat/gpio.h new file mode 100644 index 000000000..464677185 --- /dev/null +++ b/libplatsupport/plat_include/bcm2712/platsupport/plat/gpio.h @@ -0,0 +1,10 @@ +/* + * Copyright (C) 2021, HENSOLDT Cyber GmbH + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include diff --git a/libplatsupport/plat_include/bcm2712/platsupport/plat/i2c.h b/libplatsupport/plat_include/bcm2712/platsupport/plat/i2c.h new file mode 100644 index 000000000..91bc9c978 --- /dev/null +++ b/libplatsupport/plat_include/bcm2712/platsupport/plat/i2c.h @@ -0,0 +1,11 @@ +/* + * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) + * Copyright (C) 2021, Hensoldt Cyber GmbH + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#pragma once + +enum i2c_id { + NI2C +}; diff --git a/libplatsupport/plat_include/bcm2712/platsupport/plat/mailbox.h b/libplatsupport/plat_include/bcm2712/platsupport/plat/mailbox.h new file mode 100644 index 000000000..74f80199d --- /dev/null +++ b/libplatsupport/plat_include/bcm2712/platsupport/plat/mailbox.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2021, HENSOLDT Cyber GmbH + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +#define MAILBOX_PADDR 0x107c013880 +#define MAILBOX_SIZE 0x1000 diff --git a/libplatsupport/plat_include/bcm2712/platsupport/plat/serial.h b/libplatsupport/plat_include/bcm2712/platsupport/plat/serial.h new file mode 100644 index 000000000..c2b7a84b3 --- /dev/null +++ b/libplatsupport/plat_include/bcm2712/platsupport/plat/serial.h @@ -0,0 +1,34 @@ +/* + * Copyright 2025, UNSW + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +/* Corresponds to the Device Tree node '/soc@107c000000/serial@7d001000' */ +#define PL011_UART_BASE 0x107d001000 + +#define UART0_OFFSET 0x0 // UART0: PL011 + +#define UART0_PADDR (PL011_UART_BASE) + +#define UART0_IRQ 153 + +#define DEFAULT_SERIAL_PADDR UART0_PADDR +#define DEFAULT_SERIAL_INTERRUPT UART0_IRQ + +enum chardev_id { + BCM2xxx_UART0, + + NUM_CHARDEV, + + /* Aliases */ + PS_SERIAL0 = BCM2xxx_UART0, + + /* Defaults */ + PS_SERIAL_DEFAULT = BCM2xxx_UART0 +}; diff --git a/libplatsupport/plat_include/bcm2712/platsupport/plat/system_timer.h b/libplatsupport/plat_include/bcm2712/platsupport/plat/system_timer.h new file mode 100644 index 000000000..48bc3b986 --- /dev/null +++ b/libplatsupport/plat_include/bcm2712/platsupport/plat/system_timer.h @@ -0,0 +1,19 @@ +/* + * Copyright 2025, UNSW + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#pragma once + +#include + +/* + * The Device Tree by default for BCM2712 will contain the timer IRQs + * for each channel. Channels 0 and 2 are used by the VideoCore, so + * we use 1 instead. + */ +#define BCM_SYSTEM_TIMER_CHANNEL (1) +#define BCM_SYSTEM_TIMER_FREQ (MHZ) +#define BCM_SYSTEM_TIMER_FDT_PATH "/soc@107c000000/timer@7c003000" +#define BCM_SYSTEM_TIMER_REG_CHOICE (0) +#define BCM_SYSTEM_TIMER_IRQ_CHOICE (1) diff --git a/libplatsupport/src/mach/bcm/bcm_uart.c b/libplatsupport/src/mach/bcm/bcm_uart.c index 5c56cc6e3..b19824ad5 100644 --- a/libplatsupport/src/mach/bcm/bcm_uart.c +++ b/libplatsupport/src/mach/bcm/bcm_uart.c @@ -121,9 +121,16 @@ int bcm_uart_init(const struct dev_defn *defn, const ps_io_ops_t *ops, ps_charde uint32_t addr_offset = 0; switch (defn->id) { +#if defined(CONFIG_PLAT_BCM2711) || defined(CONFIG_PLAT_BCM2837) case 1: addr_offset = UART1_OFFSET; break; +#elif defined (CONFIG_PLAT_BCM2712) + /* BCM UART is not supported on BCM2712 as it is on the PCIe bus rather + * than the SoC itself. */ +#else +#error "bcm_uart_init: unknown platform" +#endif default: ZF_LOGE("Mini-UART with ID %d does not exist!", defn->id); return -1; diff --git a/libplatsupport/src/mach/bcm/chardev.c b/libplatsupport/src/mach/bcm/chardev.c index e13324178..f0b9093dd 100644 --- a/libplatsupport/src/mach/bcm/chardev.c +++ b/libplatsupport/src/mach/bcm/chardev.c @@ -44,6 +44,14 @@ static const struct dev_defn dev_defn[] = { UART_DEFN(5) }; +#elif defined(CONFIG_PLAT_BCM2712) + +static const int uart_irqs_0[] = { UART0_IRQ, -1 }; + +static const struct dev_defn dev_defn[] = { + UART_DEFN(0), +}; + #elif defined(CONFIG_PLAT_BCM2837) static const int uart_irqs_0[] = { UART0_IRQ, -1 }; diff --git a/libplatsupport/src/mach/bcm/pl011_uart.c b/libplatsupport/src/mach/bcm/pl011_uart.c index 9463728aa..029c24835 100644 --- a/libplatsupport/src/mach/bcm/pl011_uart.c +++ b/libplatsupport/src/mach/bcm/pl011_uart.c @@ -277,6 +277,17 @@ int pl011_uart_init(const struct dev_defn *defn, const ps_io_ops_t *ops, ps_char return -1; } +#elif defined(CONFIG_PLAT_BCM2712) + + switch (defn->id) { + case BCM2xxx_UART0: + addr_offset = UART0_OFFSET; + break; + default: + ZF_LOGE("PL011 UART with ID %d does not exist!", defn->id); + return -1; + } + #elif defined(CONFIG_PLAT_BCM2837) switch (defn->id) { diff --git a/libplatsupport/src/mach/bcm/serial.c b/libplatsupport/src/mach/bcm/serial.c index 0091c15f7..37a7921da 100644 --- a/libplatsupport/src/mach/bcm/serial.c +++ b/libplatsupport/src/mach/bcm/serial.c @@ -45,6 +45,10 @@ static const uart_gpio_defn_t gpio_defs[NUM_CHARDEV] = { UART_GPIO_DEFN(BCM2xxx_UART5, 12, 13, BCM2711_GPIO_FSEL_ALT4) // UART 5 uses GPIO pins 12-13 }; +#elif defined(CONFIG_PLAT_BCM2712) + +/* GPIO is not supported on BCM2712. */ + #elif defined(CONFIG_PLAT_BCM2837) static const uart_gpio_defn_t gpio_defs[NUM_CHARDEV] = { @@ -96,6 +100,7 @@ int uart_gpio_configure(enum chardev_id id, const ps_io_ops_t *o) // control (CTS/RTS pins) for now. uart_gpio_defn_t pindef = { -1, -1, -1, -1 }; +#ifndef CONFIG_PLAT_BCM2712 for (int i = 0; i < NUM_CHARDEV; i++) { if (id == gpio_defs[i].uart_id) { pindef = gpio_defs[i]; @@ -137,6 +142,8 @@ int uart_gpio_configure(enum chardev_id id, const ps_io_ops_t *o) #else #error "Unknown BCM2xxx platform!" +#endif + #endif return 0; @@ -163,6 +170,13 @@ int uart_init(const struct dev_defn *defn, const ps_io_ops_t *ops, ps_chardevice uart_funcs.uart_putchar = &pl011_uart_putchar; break; +#elif defined(CONFIG_PLAT_BCM2712) + case BCM2xxx_UART0: + uart_funcs.uart_init = &pl011_uart_init; + uart_funcs.uart_getchar = &pl011_uart_getchar; + uart_funcs.uart_putchar = &pl011_uart_putchar; + break; + #elif defined(CONFIG_PLAT_BCM2837) case 0: