diff options
author | Naresh Solanki <naresh.solanki@9elements.com> | 2023-11-17 02:21:57 +0530 |
---|---|---|
committer | Martin L Roth <gaumless@gmail.com> | 2024-10-16 15:30:31 +0000 |
commit | 6d1dbe12d2f869388ddb51e0cef7bf30ce80b255 (patch) | |
tree | d6db121cfc41e5d750e00dc80d3cfadda482ea15 /src/mainboard/arm/rdn2 | |
parent | f6ecfbc12b4d4c02cc33b1d854ec9a473fe3f2fb (diff) |
mb/arm/rdn2: Add support for Arm Neoverse N2
Add support for Arm Neoverse N2 Reference design.
Based on Arm Neoverse N2 reference design
Revision: Release D
TEST=Build Arm Neoverse N2 & make sure there is no error.
Change-Id: I17908d3ce773d4a88924bafb1d0e9e2a043c7fbc
Signed-off-by: Naresh Solanki <naresh.solanki@9elements.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/79103
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Maximilian Brune <maximilian.brune@9elements.com>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Diffstat (limited to 'src/mainboard/arm/rdn2')
-rw-r--r-- | src/mainboard/arm/rdn2/Kconfig | 64 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/Kconfig.name | 8 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/Makefile.mk | 19 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/acpi.c | 207 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/board_info.txt | 3 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/bootblock.c | 37 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/bootblock_custom.S | 31 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/cbmem.c | 11 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/chip.h | 11 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/devicetree.cb | 10 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/dsdt.asl | 227 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/flash.fmd | 9 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/include/mainboard/addressmap.h | 97 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/mainboard.c | 156 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/media.c | 13 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/memlayout.ld | 27 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/pptt.c | 218 | ||||
-rw-r--r-- | src/mainboard/arm/rdn2/uart.c | 9 |
18 files changed, 1157 insertions, 0 deletions
diff --git a/src/mainboard/arm/rdn2/Kconfig b/src/mainboard/arm/rdn2/Kconfig new file mode 100644 index 0000000000..106684ccb0 --- /dev/null +++ b/src/mainboard/arm/rdn2/Kconfig @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if BOARD_ARM_RDN2 + +config BOARD_SPECIFIC_OPTIONS + def_bool y + select ARCH_BOOTBLOCK_ARMV8_64 + select ARCH_VERSTAGE_ARMV8_64 + select ARCH_ROMSTAGE_ARMV8_64 + select ARCH_RAMSTAGE_ARMV8_64 + select ARM64_USE_ARCH_TIMER + select BOARD_ROMSIZE_KB_65536 + select BOOTBLOCK_CUSTOM + select DRIVERS_UART_PL011 + select HAVE_ACPI_TABLES + select ACPI_GTDT + select ACPI_COMMON_MADT_GICC_V3 + select MISSING_BOARD_RESET + select PCI + select PROBE_RAM + select ACPI_IORT + select ACPI_GTDT + select ACPI_COMMON_MADT_GICC_V3 + select ACPI_PPTT + select GENERATE_SMBIOS_TABLES + +config ARM64_CURRENT_EL + default 2 + +config ECAM_MMCONF_BASE_ADDRESS + default 0x1010000000 + +config ECAM_MMCONF_BUS_NUMBER + default 256 + +config MEMLAYOUT_LD_FILE + string + default "src/mainboard/arm/rdn2/memlayout.ld" + +config FATAL_ASSERTS + default y + +config FMDFILE + default "src/mainboard/arm/rdn2/flash.fmd" + +config MAINBOARD_DIR + default "arm/rdn2" + +config MAINBOARD_PART_NUMBER + default "Neoverse N2" + +config MAX_CPUS + int + default 128 + +config MAINBOARD_VENDOR + string + default "Arm" + +config DRAM_SIZE_MB + int + default 2048 + +endif # BOARD_ARM_RDN2 diff --git a/src/mainboard/arm/rdn2/Kconfig.name b/src/mainboard/arm/rdn2/Kconfig.name new file mode 100644 index 0000000000..1a9eed5f82 --- /dev/null +++ b/src/mainboard/arm/rdn2/Kconfig.name @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config BOARD_ARM_RDN2 + bool "Neoverse N2" + help + To execute, do: + FVP_RD_N2\models\Win64_VC2019\FVP_RD_N2 -C board.flashloader0.fname=coreboot.rom \ + -C css.trustedBootROMloader.fname=bl1.bin diff --git a/src/mainboard/arm/rdn2/Makefile.mk b/src/mainboard/arm/rdn2/Makefile.mk new file mode 100644 index 0000000000..efc6de97f9 --- /dev/null +++ b/src/mainboard/arm/rdn2/Makefile.mk @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +bootblock-y += bootblock.c + +romstage-y += cbmem.c + +bootblock-y += media.c +romstage-y += media.c +ramstage-y += media.c + +bootblock-y += uart.c +romstage-y += uart.c +ramstage-y += uart.c +ramstage-y += acpi.c +ramstage-$(CONFIG_ACPI_PPTT) += pptt.c + +bootblock-y += bootblock_custom.S + +CPPFLAGS_common += -I$(src)/mainboard/$(MAINBOARDDIR)/include diff --git a/src/mainboard/arm/rdn2/acpi.c b/src/mainboard/arm/rdn2/acpi.c new file mode 100644 index 0000000000..941c2f4767 --- /dev/null +++ b/src/mainboard/arm/rdn2/acpi.c @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi.h> +#include <acpi/acpi_iort.h> +#include <console/console.h> +#include <mainboard/addressmap.h> +#include <stdio.h> + +void acpi_fill_fadt(acpi_fadt_t *fadt) +{ +} + +unsigned long acpi_fill_madt(unsigned long current) +{ + return current; +} + +uintptr_t platform_get_gicd_base(void) +{ + return RDN2_GIC_DIST; +} + +uintptr_t platform_get_gicr_base(void) +{ + return RDN2_GIC_REDIST; +} + +void platform_fill_gicc(acpi_madt_gicc_t *gicc) +{ + gicc->physical_base_address = platform_get_gicd_base(); + gicc->gicv = RDN2_VGIC_BASE; + gicc->gich = RDN2_HGIC_BASE; + + if (gicc->mpidr >> 16 == 0xf) + gicc->trbe_interrupt = 0x180c; + else + gicc->trbe_interrupt = 0x500b; +} + +static uintptr_t gic_its[] = { + RDN2_GIC_ITS(0), + RDN2_GIC_ITS(1), + RDN2_GIC_ITS(2), + RDN2_GIC_ITS(3), + RDN2_GIC_ITS(4), + RDN2_GIC_ITS(5) +}; + +int platform_get_gic_its(uintptr_t **base) +{ + *base = gic_its; + return ARRAY_SIZE(gic_its); +} + +void mainboard_fill_fadt(acpi_fadt_t *fadt) +{ + fadt->preferred_pm_profile = PM_DESKTOP; + fadt->ARM_boot_arch = 1; +} + +void acpi_soc_fill_gtdt(acpi_gtdt_t *gtdt) +{ + /* his value is optional if the system implements EL3 (Security + Extensions). If not provided, this field must be 0xFFFFFFFFFFFFFFFF. */ + gtdt->counter_block_address = UINT64_MAX; + gtdt->secure_el1_interrupt = SEC_EL1_TIMER_GISV; + gtdt->secure_el1_flags = RDN2_TIMER_FLAGS; + gtdt->non_secure_el1_interrupt = NONSEC_EL1_TIMER_GSIV; + gtdt->non_secure_el1_flags = RDN2_TIMER_FLAGS; + gtdt->virtual_timer_interrupt = VIRTUAL_TIMER_GSIV; + gtdt->virtual_timer_flags = RDN2_TIMER_FLAGS; + gtdt->non_secure_el2_interrupt = NONSEC_EL2_TIMER_GSIV; + gtdt->non_secure_el2_flags = RDN2_TIMER_FLAGS; + /* his value is optional if the system implements EL3 + (Security Extensions). If not provided, this field must be + 0xFFFFFFFFFFFFFFF. */ + gtdt->counter_read_block_address = UINT64_MAX; +} + +unsigned long acpi_soc_gtdt_add_timers(uint32_t *count, unsigned long current) +{ + struct acpi_gtdt_timer_entry timers[2]; + + memset(timers, 0, sizeof(timers)); + (*count)++; + timers[0].frame_number = 0; + timers[0].base_address = RDN2_GT_FRAME1_CTL_BASE; + timers[0].el0_base_address = UINT64_MAX; + timers[0].timer_interrupt = RDN2_GT_FRAME1_GSIV; + timers[0].timer_flags = 0; + timers[0].virtual_timer_interrupt = 0; + timers[0].virtual_timer_flags = 0; + timers[0].common_flags = ACPI_GTDT_GT_ALWAYS_ON; + + + (*count)++; + timers[1].frame_number = 1; + timers[1].base_address = RDN2_GT_FRAME0_CTL_BASE; + timers[1].el0_base_address = UINT64_MAX; + timers[1].timer_interrupt = RDN2_GT_FRAME0_GSIV; + timers[1].timer_flags = 0; + timers[1].virtual_timer_interrupt = 0; + timers[1].virtual_timer_flags = 0; + timers[1].common_flags = ACPI_GTDT_GT_ALWAYS_ON | ACPI_GTDT_GT_IS_SECURE_TIMER; + + current = acpi_gtdt_add_timer_block(current, RDN2_GT_CTL_BASE, timers, 2); + + (*count)++; + current = acpi_gtdt_add_watchdog(current, RDN2_GWDT_REFRESH, RDN2_GWDT_CONTROL, + RDN2_GWDT_WS0_GSIV, 0); + /* Secure */ + current = acpi_gtdt_add_watchdog(current, RDN2_GWDT_REFRESH, RDN2_GWDT_CONTROL, + RDN2_GWDT_WS1_GSIV, ACPI_GTDT_WATCHDOG_SECURE); + + return current; +} + +static unsigned long acpi_soc_fill_iort_tcu4(acpi_iort_t *iort, unsigned long current) +{ + acpi_iort_node_t *its, *smmu_v3, *named_comp; + u32 identifiers[] = {4}; + u32 its_reference, smmuv3_reference; + + current = acpi_iort_its_entry(current, iort, &its, 1, identifiers); + its_reference = (unsigned long)its - (unsigned long)iort; + + current = acpi_iort_smmuv3_entry(current, iort, &smmu_v3, RDN2_SMMU_V3(4), ACPI_IORT_SMMU_V3_FLAGS); + smmuv3_reference = (unsigned long)smmu_v3 - (unsigned long)iort; + + /* Individual maps here */ + current = acpi_iort_id_map_entry(current, smmu_v3, 0, 1, 0x80000, its_reference, + ACPI_IORT_ID_SINGLE_MAPPING); + + current = acpi_iort_id_map_entry(current, smmu_v3, 0x10000, 10, 0x10000, its_reference, 0); + + current = acpi_iort_id_map_entry(current, smmu_v3, 0x30000, 10, 0x30000, its_reference, 0); + + /* SMMUV3 entry length includes mapping */ + + for (int n = 0 ; n < 2 ; n++) { + /* DMA */ + char dma[32]; + snprintf(dma, sizeof(dma), "\\_SB_.DMA%d", n); + + current = acpi_iort_nc_entry(current, iort, &named_comp, 0, 0, 0x30, dma); + + for (int i = 0 ; i < 9 ; i++) { + /* ID */ + current = acpi_iort_id_map_entry(current, named_comp, i, 1, 0x10000 + n * 0x20000 + i, + smmuv3_reference, ACPI_IORT_ID_SINGLE_MAPPING); + } + } + + + return current; +} + +static unsigned long acpi_soc_fill_iort_tcu(u32 i, u16 id_count, u32 *smmu_offset, + acpi_iort_t *iort, unsigned long current) +{ + + acpi_iort_node_t *its, *smmu_v3; + static u32 id_base = 0x30000; + u32 its_reference; + + current = acpi_iort_its_entry(current, iort, &its, 1, &i); + its_reference = (unsigned long)its - (unsigned long)iort; + + current = acpi_iort_smmuv3_entry(current, iort, &smmu_v3, RDN2_SMMU_V3(i), ACPI_IORT_SMMU_V3_FLAGS); + + *smmu_offset = (unsigned long)smmu_v3 - (unsigned long)iort; + + /* Individual maps here */ + current = acpi_iort_id_map_entry(current, smmu_v3, 0, 1, 0x80000, its_reference, + ACPI_IORT_ID_SINGLE_MAPPING); + + current = acpi_iort_id_map_entry(current, smmu_v3, id_base, id_count, id_base, its_reference, 0); + id_base += id_count; + + /* SMMUV3 entry length includes mapping */ + + return current; +} + +unsigned long acpi_soc_fill_iort(acpi_iort_t *iort, unsigned long current) +{ + acpi_iort_node_t *root_comp; + u32 smmu_offset[4]; + uint32_t id_count[] = {768, 256, 256, 256}; + + for (int i = 0; i < 4; i++) + current = acpi_soc_fill_iort_tcu(i, id_count[i], &smmu_offset[i], iort, current); + + current = acpi_soc_fill_iort_tcu4(iort, current); + + current = acpi_iort_rc_entry(current, iort, &root_comp, 0, ACPI_IORT_ATS_SUPPORTED, 0, + 0x30, 0); + + u32 base = 0; + for (int i = 0 ; i < 4 ; i++) { + current = acpi_iort_id_map_entry(current, root_comp, base, id_count[i], 0x30000 + base, + smmu_offset[i], 0); + base += id_count[i]; + } + + return current; +} diff --git a/src/mainboard/arm/rdn2/board_info.txt b/src/mainboard/arm/rdn2/board_info.txt new file mode 100644 index 0000000000..1338ec2c9b --- /dev/null +++ b/src/mainboard/arm/rdn2/board_info.txt @@ -0,0 +1,3 @@ +Board name: Neoverse N2 +Category: emulation +Board URL: https://developer.arm.com/documentation/102337/latest/ diff --git a/src/mainboard/arm/rdn2/bootblock.c b/src/mainboard/arm/rdn2/bootblock.c new file mode 100644 index 0000000000..5b59e7e033 --- /dev/null +++ b/src/mainboard/arm/rdn2/bootblock.c @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/mmu.h> +#include <bootblock_common.h> +#include <console/console.h> +#include <mainboard/addressmap.h> +#include <symbols.h> + +DECLARE_REGION(dev_mem) + +void bootblock_mainboard_init(void) +{ + mmu_init(); + + /* NOR Flash 0 */ + mmu_config_range((void *)RDN2_FLASH_BASE, (uintptr_t)RDN2_FLASH_SIZE, + MA_MEM | MA_RO | MA_MEM_NC); + + /* device memory */ + mmu_config_range(_dev_mem, _dram - _dev_mem, MA_DEV | MA_RW); + + /* Set a dummy value for DRAM. ramstage should update the mapping. */ + mmu_config_range(_dram, ((size_t) 2 * GiB) - 16*MiB, MA_MEM | MA_RW); + + mmu_config_range((void *)RDN2_DRAM2_BASE, RDN2_DRAM2_SIZE, MA_MEM | MA_RW); + + mmu_config_range(_ttb, REGION_SIZE(ttb), MA_MEM | MA_S | MA_RW); + + mmu_config_range(_stack, REGION_SIZE(stack), MA_MEM | MA_S | MA_RW); + mmu_config_range(_cbfs_mcache, REGION_SIZE(cbfs_mcache), MA_MEM | MA_S | MA_RW); + mmu_config_range(_fmap_cache, REGION_SIZE(fmap_cache), MA_MEM | MA_S | MA_RW); + mmu_config_range(_timestamp, REGION_SIZE(timestamp), MA_MEM | MA_S | MA_RW); + + mmu_config_range((void *)CONFIG_ECAM_MMCONF_BASE_ADDRESS, CONFIG_ECAM_MMCONF_LENGTH, + MA_DEV | MA_RW); + mmu_enable(); +} diff --git a/src/mainboard/arm/rdn2/bootblock_custom.S b/src/mainboard/arm/rdn2/bootblock_custom.S new file mode 100644 index 0000000000..f8cca02d9f --- /dev/null +++ b/src/mainboard/arm/rdn2/bootblock_custom.S @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <arch/asm.h> + +/* + * Note: This board uses boot flow: TFA -> coreboot. + */ +ENTRY(_start) + + /* TF-A arg which contains a pointer to fdt */ + ldr x1, =_fdt_pointer + str x0, [x1] + + msr SPSel, #0 /* use SP_EL0 */ + + /* ==== stack init from arm64_init_cpu ==== */ + ldr x2, =0xdeadbeefdeadbeef + ldr x0, =_stack + ldr x1, =_estack +1: + stp x2, x2, [x0], #16 + cmp x0, x1 + bne 1b + + sub sp, x0, #16 + + /* ==== END ==== */ + + /* Jump to main() in DRAM. */ + bl main +ENDPROC(_start) diff --git a/src/mainboard/arm/rdn2/cbmem.c b/src/mainboard/arm/rdn2/cbmem.c new file mode 100644 index 0000000000..a8ad03399c --- /dev/null +++ b/src/mainboard/arm/rdn2/cbmem.c @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <cbmem.h> +#include <console/console.h> +#include <ramdetect.h> +#include <symbols.h> + +uintptr_t cbmem_top_chipset(void) +{ + return (uintptr_t)_dram + (probe_ramsize((uintptr_t)_dram, CONFIG_DRAM_SIZE_MB) * MiB); +} diff --git a/src/mainboard/arm/rdn2/chip.h b/src/mainboard/arm/rdn2/chip.h new file mode 100644 index 0000000000..ae19df9763 --- /dev/null +++ b/src/mainboard/arm/rdn2/chip.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef MAINBOARD_ARM_RDN2_CHIP_H +#define MAINBOARD_ARM_RDN2_CHIP_H + +#include <types.h> + +struct mainboard_arm_rdn2_config { +}; + +#endif diff --git a/src/mainboard/arm/rdn2/devicetree.cb b/src/mainboard/arm/rdn2/devicetree.cb new file mode 100644 index 0000000000..f85d243e48 --- /dev/null +++ b/src/mainboard/arm/rdn2/devicetree.cb @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +chip mainboard/arm/rdn2 + + device cpu_cluster 0 on ops rdn2_aarch64_cpu_ops end + + device domain 0 on ops rdn2_aarch64_pci_domain_ops + device pci 00.0 on end + end +end diff --git a/src/mainboard/arm/rdn2/dsdt.asl b/src/mainboard/arm/rdn2/dsdt.asl new file mode 100644 index 0000000000..2e795b8eed --- /dev/null +++ b/src/mainboard/arm/rdn2/dsdt.asl @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi.h> +#include <mainboard/addressmap.h> +DefinitionBlock( + "dsdt.aml", + "DSDT", + ACPI_DSDT_REV_2, + OEM_ID, + ACPI_TABLE_CREATOR, + 0x20230621 // OEM revision +) +{ + #include <acpi/dsdt_top.asl> + + Device (COM0) + { + Name (_HID, "ARMH0011") // _HID: Hardware ID + Name (_UID, Zero) // _UID: Unique ID + Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings + { + Memory32Fixed (ReadWrite, + RDN2_UART_NS_BASE, // Address Base + 0x00001000, // Address Length + ) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) + { + RDN2_UART_NS_GSIV, + } + }) + Method (_STA, 0, NotSerialized) // _STA: Status + { + Return (0xf) + } + } + + Device (VR00) + { + Name (_HID, "LNRO0005") // _HID: Hardware ID + Name (_UID, Zero) // _UID: Unique ID + Name (_CCA, One) // _CCA: Cache Coherency Attribute + Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings + { + Memory32Fixed (ReadWrite, + 0x0C130000, // Address Base + 0x00010000, // Address Length + ) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) + { + 0x000001CA, + } + }) + } + + Device (VR01) + { + Name (_HID, "LNRO0005") // _HID: Hardware ID + Name (_UID, One) // _UID: Unique ID + Name (_CCA, One) // _CCA: Cache Coherency Attribute + Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings + { + Memory32Fixed (ReadWrite, + 0x0C150000, // Address Base + 0x00010000, // Address Length + ) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) + { + 0x000001CC, + } + }) + } + + + Device (\_SB.DMA0) + { + Name (_HID, "ARMH0330") // _HID: Hardware ID + Name (_UID, Zero) // _UID: Unique ID + Name (_CCA, One) // _CCA: Cache Coherency Attribute + Name (_STA, 0x0F) // _STA: Status + Method (_CRS, 0, Serialized) // _CRS: Current Resource Settings + { + Name (RBUF, ResourceTemplate () + { + QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, + 0x0000000000000000, // Granularity + 0x0000000000000000, // Range Minimum + 0x0000000000000001, // Range Maximum + 0x0000000000000000, // Translation Offset + 0x0000000000000002, // Length + ,, _Y02, AddressRangeMemory, TypeStatic) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) + { + 0x000001ED, + 0x000001EE, + 0x000001EF, + 0x000001F0, + 0x000001F1, + 0x000001F2, + 0x000001F3, + 0x000001F4, + 0x000001F5, + } + }) + CreateQWordField (RBUF, \_SB.DMA0._CRS._Y02._MIN, MIN2) // _MIN: Minimum Base Address + CreateQWordField (RBUF, \_SB.DMA0._CRS._Y02._MAX, MAX2) // _MAX: Maximum Base Address + CreateQWordField (RBUF, \_SB.DMA0._CRS._Y02._LEN, LEN2) // _LEN: Length + MIN2 = RDN2_DMA0_BASE + MAX2 = (MIN2 + 0xFFFF) + LEN2 = 0x00010000 + Return (RBUF) /* \_SB_.DMA0._CRS.RBUF */ + } + } + + Device (\_SB.DMA1) + { + Name (_HID, "ARMH0330") // _HID: Hardware ID + Name (_UID, One) // _UID: Unique ID + Name (_CCA, One) // _CCA: Cache Coherency Attribute + Name (_STA, 0x0F) // _STA: Status + Method (_CRS, 0, Serialized) // _CRS: Current Resource Settings + { + Name (RBUF, ResourceTemplate () + { + QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, + 0x0000000000000000, // Granularity + 0x0000000000000000, // Range Minimum + 0x0000000000000001, // Range Maximum + 0x0000000000000000, // Translation Offset + 0x0000000000000002, // Length + ,, _Y03, AddressRangeMemory, TypeStatic) + Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) + { + 0x000001F7, + 0x000001F8, + 0x000001F9, + 0x000001FA, + 0x000001FB, + 0x000001FC, + 0x000001FD, + 0x000001FE, + 0x000001FF, + } + }) + CreateQWordField (RBUF, \_SB.DMA1._CRS._Y03._MIN, MIN2) // _MIN: Minimum Base Address + CreateQWordField (RBUF, \_SB.DMA1._CRS._Y03._MAX, MAX2) // _MAX: Maximum Base Address + CreateQWordField (RBUF, \_SB.DMA1._CRS._Y03._LEN, LEN2) // _LEN: Length + MIN2 = RDN2_DMA1_BASE + MAX2 = (MIN2 + 0xFFFF) + LEN2 = 0x00010000 + Return (RBUF) /* \_SB_.DMA1._CRS.RBUF */ + } + } + Device (PCI0) + { + Name (_HID, EisaId ("PNP0A08")) // PCI Express Bus _HID: Hardware ID + Name (_CID, EisaId ("PNP0A03")) // PCI Bus _CID: Compatible ID + Name (_SEG, Zero) // _SEG: PCI Segment + Name (_BBN, Zero) // _BBN: BIOS Bus Number + Name (_UID, "PCI0") // _UID: Unique ID + Name (_CCA, One) // _CCA: Cache Coherency Attribute + + Method (_STA, 0, NotSerialized) // _STA: Status + { + Return (0xf) + } + + Method (_CBA, 0, NotSerialized) // _CBA: Configuration Base Address + { + Return (RDN2_PCIE_ECAM_BASE) + } + + Method (_CRS, 0, Serialized) // _CRS: Current Resource Settings + { + Name (RBUF, ResourceTemplate () + { + WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, + 0x0000, // Granularity + 0x0000, // Range Minimum + 0x00FF, // Range Maximum + 0x0000, // Translation Offset + 0x0100, // Length + ,, ) + DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + 0x00000000, // Granularity + RDN2_PCIE_MMIO_BASE, // Range Minimum + RDN2_PCIE_MMIO_LIMIT, // Range Maximum + 0x00000000, // Translation Offset + RDN2_PCIE_MMIO_SIZE, // Length + ,, , AddressRangeMemory, TypeStatic) + QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + 0x0000000000000000, // Granularity + RDN2_PCIE_MMIO_HIGH_BASE, // Range Minimum + RDN2_PCIE_MMIO_HIGH_LIMIT, // Range Maximum + 0x0000000000000000, // Translation Offset + RDN2_PCIE_MMIO_HIGH_SIZE, // Length + ,, , AddressRangeMemory, TypeStatic) + DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x00000000, // Granularity + 0x00000000, // Range Minimum + 0x007FFFFF, // Range Maximum + 0x77800000, // Translation Offset + 0x00800000, // Length + ,, , TypeTranslation, DenseTranslation) + }) + Return (RBUF) /* \PCI0._CRS.RBUF */ + } + + 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 + RDN2_PCIE_ECAM_BASE, // Range Minimum + RDN2_PCIE_ECAM_LIMIT, // Range Maximum + 0x0000000000000000, // Translation Offset + RDN2_PCIE_ECAM_SIZE, // Length + ,, , AddressRangeMemory, TypeStatic) + }) + Method (_STA, 0, NotSerialized) // _STA: Status + { + Return (0xf) + } + } + } +} diff --git a/src/mainboard/arm/rdn2/flash.fmd b/src/mainboard/arm/rdn2/flash.fmd new file mode 100644 index 0000000000..2b75d355d1 --- /dev/null +++ b/src/mainboard/arm/rdn2/flash.fmd @@ -0,0 +1,9 @@ +FLASH@0x08000000 CONFIG_ROM_SIZE { + + BIOS@0x0 CONFIG_ROM_SIZE { + + BOOTBLOCK 128K + FMAP@0x20000 0x200 + COREBOOT(CBFS) + } +} diff --git a/src/mainboard/arm/rdn2/include/mainboard/addressmap.h b/src/mainboard/arm/rdn2/include/mainboard/addressmap.h new file mode 100644 index 0000000000..5d218c2585 --- /dev/null +++ b/src/mainboard/arm/rdn2/include/mainboard/addressmap.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Memory map for Neoverse N2 + * See Technical Reference: Table 5-2: FVP board peripherals + */ + +#define RDN2_FLASH_BASE 0x08000000 +#define RDN2_FLASH_SIZE (64 * MiB) + +/* Actual DRAM size should be probed */ +#define RDN2_DRAM_BASE 0x80000000 +#define RDN2_DRAM_SIZE (2 * GiB) + +#define RDN2_SECMEM_BASE 0xff000000 +#define RDN2_SECMEM_SIZE (16 * MiB) + +#define RDN2_DRAM2_BASE 0x8080000000 +#define RDN2_DRAM2_SIZE (6UL * GiB) + +#define RDN2_GIC_DIST 0x30000000 +#define RDN2_GIC_REDIST 0x301C0000 +#define RDN2_VGIC_BASE 0x2c020000 +#define RDN2_HGIC_BASE 0x2c010000 + +#define RDN2_GIC_ITS_BASE 0x30040000 +#define RDN2_GIC_ITS_SIZE 0x40000 +#define RDN2_GIC_ITS(i) (RDN2_GIC_ITS_BASE + i * RDN2_GIC_ITS_SIZE) + +#define SEC_EL1_TIMER_GISV 29 +#define NONSEC_EL1_TIMER_GSIV 30 +#define VIRTUAL_TIMER_GSIV 27 +#define NONSEC_EL2_TIMER_GSIV 26 + +#define RDN2_TIMER_FLAGS (ACPI_GTDT_INTERRUPT_POLARITY) +#define RDN2_GT_CTL_BASE 0x2A810000 +#define RDN2_GT_FRAME0_CTL_BASE 0x2A820000 +#define RDN2_GT_FRAME0_EL0_BASE -1 +#define RDN2_GT_FRAME0_GSIV 0x6c + +#define RDN2_GT_FRAME1_CTL_BASE 0x2A830000 +#define RDN2_GT_FRAME1_EL0_BASE -1 +#define RDN2_GT_FRAME1_GSIV 0x6d + +#define RDN2_GWDT_REFRESH 0x2a450000 +#define RDN2_GWDT_CONTROL 0x2a440000 +#define RDN2_GWDT_WS0_GSIV 0x6e +#define RDN2_GWDT_WS1_GSIV 0x6f + +#define RDN2_UART_CLK_HZ 7372800 +#define RDN2_UART_NS_BASE 0x2a400000 +#define RDN2_UART_NS_GSIV 112 +#define RDN2_SECURE_UART_BASE 0x2a410000 +#define RDN2_SECURE_UART_GSIV 81 + +#define RDN2_RTC_BASE 0x0C170000 +#define RDN2_RTC1_BASE 0x0C180000 +#define RDN2_GPIO_BASE 0x0c1d0000 +#define RDN2_GPIO1_BASE 0x0c1e0000 + +#define RDN2_SMMU_BASE 0x40000000 +#define RDN2_SMMU_SIZE 0x2000000 + + + + +#define RDN2_SMMU_V3(i) (RDN2_SMMU_BASE + i * RDN2_SMMU_SIZE) +#define ACPI_IORT_SMMU_V3_FLAGS (ACPI_IORT_SMMU_V3_COHACC_OVERRIDE | ACPI_IORT_SMMU_V3_DEVICEID_VALID) + +#define RDN2_DMA0_BASE 0x1090000000 +#define RDN2_DMA1_BASE 0x10B0000000 +/* Virtio block device */ +#define RDN2_AHCI_BASE 0x0C130000 +#define RDN2_AHCI_INT 458 + +/* Virtio net */ +#define RDN2_VNET_BASE 0x0C150000 +#define RDN2_VNET_INT 460 + +/* Arm Dual-Timer Module */ +#define RDN2_DUAL_TIMER 0x0C110000 +#define RDN2_DUAL_TIMER_INT 486 + +#define RDN2_GPIO0 0x0C1D0000 +#define RDN2_GPIO0_INT 392 + +#define RDN2_EHCI_BASE 0x60110000 + +#define RDN2_PCIE_MMIO_BASE 0x60000000 +#define RDN2_PCIE_MMIO_LIMIT 0x7fffffff +#define RDN2_PCIE_MMIO_SIZE 0x20000000 +#define RDN2_PCIE_ECAM_BASE 0x1010000000 +#define RDN2_PCIE_ECAM_LIMIT 0x101FFFFFFF +#define RDN2_PCIE_ECAM_SIZE 0x10000000 +#define RDN2_PCIE_MMIO_HIGH_BASE 0x4000000000 +#define RDN2_PCIE_MMIO_HIGH_LIMIT 0x807fffffff +#define RDN2_PCIE_MMIO_HIGH_SIZE 0x4080000000 diff --git a/src/mainboard/arm/rdn2/mainboard.c b/src/mainboard/arm/rdn2/mainboard.c new file mode 100644 index 0000000000..d5f7df4e7b --- /dev/null +++ b/src/mainboard/arm/rdn2/mainboard.c @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "chip.h" +#include <acpi/acpigen.h> +#include <arch/mmu.h> +#include <bootmem.h> +#include <cbfs.h> +#include <device/device.h> +#include <mainboard/addressmap.h> +#include <ramdetect.h> +#include <stdint.h> +#include <symbols.h> + +static size_t ram_size(void) +{ + return (size_t)cbmem_top() - (uintptr_t)_dram; +} + +static size_t ram2_size(void) +{ + return (size_t)probe_ramsize((uintptr_t)RDN2_DRAM2_BASE, RDN2_DRAM2_SIZE) * MiB; +} + +static void mainboard_init(void *chip_info) +{ + mmu_config_range(_dram, ram_size(), MA_MEM | MA_RW); + mmu_config_range((void *)RDN2_DRAM2_BASE, ram2_size(), MA_MEM | MA_RW); +} + +DECLARE_REGION(fdt_pointer) + +void smbios_cpu_get_core_counts(u16 *core_count, u16 *thread_count) +{ + *core_count = 0; + struct device *dev = NULL; + while ((dev = dev_find_path(dev, DEVICE_PATH_GICC_V3))) + *core_count += 1; + + *thread_count = 1; +} + + +static void rdn2_aarch64_init(struct device *dev) +{ + struct memory_info *mem_info; + + mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info)); + if (mem_info == NULL) + return; + + memset(mem_info, 0, sizeof(*mem_info)); + + mem_info->ecc_type = MEMORY_ARRAY_ECC_UNKNOWN; + mem_info->max_capacity_mib = 0x800000; + mem_info->number_of_devices = mem_info->dimm_cnt = 1; + + mem_info->dimm[0].dimm_size = (ram_size() + ram2_size()) / MiB; + mem_info->dimm[0].ddr_type = MEMORY_TYPE_DRAM; + mem_info->dimm[0].ddr_frequency = 0; + mem_info->dimm[0].channel_num = mem_info->dimm[0].dimm_num = 0; + mem_info->dimm[0].bank_locator = 0; + + mem_info->dimm[0].bus_width = 0x03; // 64-bit, no parity + mem_info->dimm[0].vdd_voltage = 0; + mem_info->dimm[0].max_speed_mts = mem_info->dimm[0].configured_speed_mts = 0; +} + +static unsigned long mb_write_acpi_tables(const struct device *dev, unsigned long current, + acpi_rsdp_t *rsdp) +{ + printk(BIOS_DEBUG, "ACPI: * DBG2\n"); + return acpi_pl011_write_dbg2_uart(rsdp, current, RDN2_UART_NS_BASE, "\\_SB.COM0"); +} + + +static void mainboard_enable(struct device *dev) +{ + dev->ops->init = rdn2_aarch64_init; + dev->ops->write_acpi_tables = mb_write_acpi_tables; +} + + +struct chip_operations mainboard_ops = { + .init = mainboard_init, + .enable_dev = mainboard_enable, +}; + +struct chip_operations mainboard_arm_rdn2_ops = { }; + +static void rdn2_aarch64_domain_read_resources(struct device *dev) +{ + struct resource *res; + int index = 0; + + /* Initialize the system-wide I/O space constraints. */ + res = new_resource(dev, index++); + res->limit = 0xffffUL; + res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED; + + /* Initialize the system-wide memory resources constraints. */ + res = new_resource(dev, index++); + res->base = RDN2_PCIE_MMIO_BASE; + res->limit = RDN2_PCIE_MMIO_LIMIT; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED; + + res = new_resource(dev, index++); + res->base = RDN2_PCIE_MMIO_HIGH_BASE; + res->limit = RDN2_PCIE_MMIO_HIGH_LIMIT; + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED; + + ram_range(dev, index++, (uintptr_t)_dram, ram_size()); + reserved_ram_range(dev, index++, (uintptr_t)RDN2_SECMEM_BASE, RDN2_SECMEM_SIZE); + + ram_range(dev, index++, (uintptr_t)RDN2_DRAM2_BASE, ram2_size()); + + mmio_range(dev, index++, RDN2_FLASH_BASE, RDN2_FLASH_SIZE); +} + +struct device_operations rdn2_aarch64_pci_domain_ops = { + .read_resources = rdn2_aarch64_domain_read_resources, + .set_resources = pci_domain_set_resources, + .scan_bus = pci_host_bridge_scan_bus, +}; + +static void rdn2_fill_cpu_ssdt(const struct device *dev) +{ + acpigen_write_processor_device(dev->path.gicc_v3.mpidr); + acpigen_write_processor_device_end(); +} + +struct device_operations rdn2_cpu_ops = { + .acpi_fill_ssdt = rdn2_fill_cpu_ssdt, +}; + +static void rdn2_aarch64_scan_bus(struct device *dev) +{ + u16 i = 0; + struct bus *bus = alloc_bus(dev); + + for (i = 0; i < 16; i++) { + printk(BIOS_DEBUG, "Allocating CPU %d\n", i); + struct device_path devpath = { .type = DEVICE_PATH_GICC_V3, + .gicc_v3 = { .mpidr = i << 16, + .vgic_mi = 0x19, + .pi_gsiv = 0x17, }, + }; + struct device *cpu = alloc_dev(bus, &devpath); + assert(cpu); + cpu->ops = &rdn2_cpu_ops; + } + +} + +struct device_operations rdn2_aarch64_cpu_ops = { + .scan_bus = rdn2_aarch64_scan_bus, +}; diff --git a/src/mainboard/arm/rdn2/media.c b/src/mainboard/arm/rdn2/media.c new file mode 100644 index 0000000000..cf6ab06789 --- /dev/null +++ b/src/mainboard/arm/rdn2/media.c @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <boot_device.h> +#include <mainboard/addressmap.h> + +/* Maps directly to NOR flash up to ROM size. */ +static const struct mem_region_device boot_dev = + MEM_REGION_DEV_RO_INIT((void *)RDN2_FLASH_BASE, RDN2_FLASH_SIZE); + +const struct region_device *boot_device_ro(void) +{ + return &boot_dev.rdev; +} diff --git a/src/mainboard/arm/rdn2/memlayout.ld b/src/mainboard/arm/rdn2/memlayout.ld new file mode 100644 index 0000000000..de7aad5086 --- /dev/null +++ b/src/mainboard/arm/rdn2/memlayout.ld @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <memlayout.h> +#include <arch/header.ld> + +/* + * Memory map for Neoverse N2 + * See Technical Reference: Table 5-2: FVP board peripherals + */ +SECTIONS +{ + REGION(flash, 0x8000000, CONFIG_ROM_SIZE, 8) + + REGION(dev_mem, 0x0c010000, 2M, 8) + DRAM_START(0x80000000) + BOOTBLOCK(0xe0000000, 64K) + STACK(0xe0010000, 64K) + CBFS_MCACHE(0xe0020000, 8K) + FMAP_CACHE(0xe0022000 , 4K) + TIMESTAMP(0xe0023000, 4K) + ROMSTAGE(0xe0024000, 128K) + TTB(0xe0060000, 128K) + RAMSTAGE(0xe00a0000, 16M) + REGION(fdt_pointer, 0xe10a0000, ARCH_POINTER_ALIGN_SIZE, ARCH_POINTER_ALIGN_SIZE) + + POSTRAM_CBFS_CACHE(0xe11f0000, 1M) +} diff --git a/src/mainboard/arm/rdn2/pptt.c b/src/mainboard/arm/rdn2/pptt.c new file mode 100644 index 0000000000..ca06cc8c94 --- /dev/null +++ b/src/mainboard/arm/rdn2/pptt.c @@ -0,0 +1,218 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <stdlib.h> +#include <cpu/cpu.h> +#include <arch/cache.h> +#include <acpi/acpi.h> +#include <console/console.h> + +#define CACHE_NODE_FLAGS 0xd7 // everything valid except, write-policy and allocation type +#define CLUSTER_FLAGS 0x11 // physical package, ID invalid, no thread, no leaf, identical impl. +#define CORE_FLAGS 0x0a // no physical package, ID valid, no thread, leaf. +#define CORE_FLAGS_1 0x12 // no physical package, ID valid, no thread, identical i. + +/* + * L2 cache (LLC) + */ +struct pptt_cache l2 = { + + .next_level = NULL +}; + +/* + * L1D cache + */ +struct pptt_cache l1d = { + .next_level = &l2 +}; + +/* + * L1I cache + */ +struct pptt_cache l1i = { + //.sibling = &l1d, + .next_level = &l2 +}; + +/* + * private resources of a cpu core. Same for + * each core, thus we can reuse this struture + * instead of creating it dynamically. + */ +struct pptt_cpu_resources core_resources = { + .cache = &l1i, +}; + +struct pptt_topology root_topology = { + + .flags.raw = CLUSTER_FLAGS, + .resources = NULL, + .sibling = NULL, + + .child = &(struct pptt_topology) { + + .processor_id = 0, + .flags.raw = CORE_FLAGS_1, + + .resources = NULL, + + .child = &(struct pptt_topology) { + .processor_id = 0, + .flags.raw = CORE_FLAGS, + + .resources = &(struct pptt_cpu_resources) { + + .cache = &l1i, + + }, + + .sibling = NULL, + .child = NULL, + }, + .sibling = NULL, // updated in runtime + } +}; + +/* --- Helpers --- */ + +static u8 cache_attributes(const enum cache_type type) +{ + /* + * 'write-policy' and 'allocation type' currently + * unsupported. cache flags set accordingly. + * + * maybe a todo for the future. + */ + + u8 attr = 0x0; + + if (type == CACHE_INSTRUCTION) + attr |= (0x1 << 2); + else if (type == CACHE_UNIFIED) + attr |= (0x1 << 3); + + return attr; +} + +/* --- ACPI hook --- */ + +struct pptt_topology *acpi_get_pptt_topology(void) +{ + struct cache_info info; + + /* Dump Cache info */ + for (int cache_level = CACHE_L1; cache_level <= CACHE_L7; cache_level++) { + int cache_type = cpu_get_cache_type(cache_level); + if (cache_type == NO_CACHE) + continue; + + if (cache_type == CACHE_SEPARATE) { + printk(BIOS_DEBUG, "Fetching cache info for: level:%d, type:%d\n", + cache_level, cache_type); + cpu_get_cache_info(cache_level, cache_type, &info); + printk(BIOS_DEBUG, "Size: %lld, associativity: %lld\n", info.size, + info.associativity); + + cache_type = CACHE_INSTRUCTION; + + printk(BIOS_DEBUG, "Fetching cache info for: level:%d, type:%d\n", + cache_level, cache_type); + cpu_get_cache_info(cache_level, cache_type, &info); + printk(BIOS_DEBUG, "Size: %lld, associativity: %lld\n", info.size, + info.associativity); + + cache_type = CACHE_DATA; + } + + printk(BIOS_DEBUG, "Fetching cache info for: level:%d, type:%d\n", cache_level, + cache_type); + cpu_get_cache_info(cache_level, cache_type, &info); + printk(BIOS_DEBUG, "Size: %lld, associativity: %lld\n", info.size, + info.associativity); + } + + /* update cache information (L1I) */ + + cpu_get_cache_info(CACHE_L1, CACHE_INSTRUCTION, &info); + + l1i.size = info.size; + l1i.associativity = info.associativity; + l1i.numsets = info.numsets; + l1i.line_size = info.line_bytes; + l1i.attributes = cache_attributes(CACHE_INSTRUCTION); + l1i.flags.raw = CACHE_NODE_FLAGS | 0xff; + + /* update cache information (L1D) */ + + cpu_get_cache_info(CACHE_L1, CACHE_DATA, &info); + + l1d.size = info.size; + l1d.associativity = info.associativity; + l1d.numsets = info.numsets; + l1d.line_size = info.line_bytes; + l1d.attributes = cache_attributes(CACHE_DATA) | (0x2); + l1d.flags.raw = CACHE_NODE_FLAGS | 0xff; + + /* update cache information (L2) */ + + cpu_get_cache_info(CACHE_L2, CACHE_UNIFIED, &info); + + l2.size = info.size; + l2.associativity = info.associativity; + l2.numsets = info.numsets; + l2.line_size = info.line_bytes; + l2.attributes = cache_attributes(CACHE_UNIFIED) | (0x2); + l2.flags.raw = CACHE_NODE_FLAGS | 0xff; + + /* add secondary CPUs */ + + u32 cpu_id = 0; + + struct device *dev = NULL; + struct pptt_topology **it = &root_topology.child->sibling; + struct pptt_topology **sibling; + + while ((dev = dev_find_path(dev, DEVICE_PATH_GICC_V3))) { + if (cpu_id == 0) { + + cpu_id += 1; + continue; + } + + if ((*it = malloc(sizeof(struct pptt_topology))) == NULL) { + + printk(BIOS_ERR, "Could not allocate pptt structure!\n"); + break; + } + + memset(*it, 0, sizeof(struct pptt_topology)); + + (*it)->processor_id = cpu_id; + (*it)->flags.raw = CORE_FLAGS_1; + (*it)->resources = NULL; + + //sibling = (*it)->sibling; + sibling = &(*it)->sibling; + + it = &(*it)->child; + + if ((*it = malloc(sizeof(struct pptt_topology))) == NULL) { + + printk(BIOS_ERR, "Could not allocate pptt structure!\n"); + break; + } + + memset(*it, 0, sizeof(struct pptt_topology)); + + (*it)->processor_id = cpu_id; + (*it)->flags.raw = CORE_FLAGS; + (*it)->resources = &core_resources; + + //it = &(*it)->sibling; + it = sibling; + + cpu_id += 1; + } + + return &root_topology; +} diff --git a/src/mainboard/arm/rdn2/uart.c b/src/mainboard/arm/rdn2/uart.c new file mode 100644 index 0000000000..1b872056d0 --- /dev/null +++ b/src/mainboard/arm/rdn2/uart.c @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <console/uart.h> +#include <mainboard/addressmap.h> + +uintptr_t uart_platform_base(unsigned int idx) +{ + return RDN2_UART_NS_BASE; +} |