From 6767861c484d07f180f3dd710b5dc59f0c525374 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 24 Apr 2026 16:25:19 +1000 Subject: [PATCH] platform: generic: Tenstorrent Atlantis support Add the Tenstorrent Atlantis as a generic-platform. This initial support enables the single_fw_region option, and verifies and prints HART PMA CSR configuration. Signed-off-by: Nicholas Piggin Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260424062520.238403-1-npiggin@gmail.com Signed-off-by: Anup Patel --- docs/platform/generic.md | 2 + docs/platform/tt-atlantis.md | 35 +++++ platform/generic/Kconfig | 6 + platform/generic/configs/defconfig | 1 + .../generic/include/tenstorrent/ascalon.h | 12 ++ platform/generic/include/tenstorrent/pma.h | 17 +++ platform/generic/tenstorrent/Kconfig | 5 + platform/generic/tenstorrent/ascalon.c | 53 +++++++ platform/generic/tenstorrent/atlantis.c | 50 +++++++ platform/generic/tenstorrent/objects.mk | 12 ++ platform/generic/tenstorrent/pma.c | 138 ++++++++++++++++++ 11 files changed, 331 insertions(+) create mode 100644 docs/platform/tt-atlantis.md create mode 100644 platform/generic/include/tenstorrent/ascalon.h create mode 100644 platform/generic/include/tenstorrent/pma.h create mode 100644 platform/generic/tenstorrent/Kconfig create mode 100644 platform/generic/tenstorrent/ascalon.c create mode 100644 platform/generic/tenstorrent/atlantis.c create mode 100644 platform/generic/tenstorrent/objects.mk create mode 100644 platform/generic/tenstorrent/pma.c diff --git a/docs/platform/generic.md b/docs/platform/generic.md index c48d6a9a..0b896ede 100644 --- a/docs/platform/generic.md +++ b/docs/platform/generic.md @@ -47,6 +47,7 @@ RISC-V Platforms Using Generic Platform * **SiFive HiFive Unleashed** (*[sifive_fu540.md]*) * **Spike** (*[spike.md]*) * **T-HEAD C9xx series Processors** (*[thead-c9xx.md]*) +* **Tenstorrent Atlantis Platform** (*[tt-atlantis.md]*) * **OpenPiton FPGA SoC** (*[fpga-openpiton.md]*) * **Ariane FPGA SoC** (*[fpga-ariane.md]*) @@ -57,5 +58,6 @@ RISC-V Platforms Using Generic Platform [sifive_fu540.md]: sifive_fu540.md [spike.md]: spike.md [thead-c9xx.md]: thead-c9xx.md +[tt-atlantis.md]: tt-atlantis.md [fpga-openpiton.md]: fpga-openpiton.md [fpga-ariane.md]: fpga-ariane.md diff --git a/docs/platform/tt-atlantis.md b/docs/platform/tt-atlantis.md new file mode 100644 index 00000000..b9bdd238 --- /dev/null +++ b/docs/platform/tt-atlantis.md @@ -0,0 +1,35 @@ +Tenstorrent Atlantis Platform +============================= + +The Tenstorrent Atlantis is an SoC and development board from +Tenstorrent in partnership with CoreLab Technology. It contains 8 RISC-V +RVA23 compliant Tenstorrent Ascalon cores with RISC-V AIA, RISC-V IOMMU, +and a range of devices and IO connectivity. + +To build the platform-specific library and firmware images, provide the +*PLATFORM=generic* parameter to the top level `make` command. + +Platform Options +---------------- + +The *Tenstorrent Atlantis* platform does not have any platform-specific +options. + +Building Tenstorrent Atlantis Platform +-------------------------------------- + +The Atlantis Platform is still under development. This section will be +expanded as firmware and support become available. + +QEMU support is currently being developed and initial support has been +proposed for upstream. To run QEMU that is patched with 'tt-atlantis' +machine support, run: + +``` +qemu-system-riscv64 -M tt-atlantis -nographic \ + -bios build/platform/generic/firmware/fw_payload.bin \ + -kernel /Image +``` + +Recent (6.18) Linux/riscv 64-bit defconfig kernels should run the QEMU +tt-atlantis machine. diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig index 600273d1..d594b140 100644 --- a/platform/generic/Kconfig +++ b/platform/generic/Kconfig @@ -89,6 +89,11 @@ config PLATFORM_STARFIVE_JH7110 bool "StarFive JH7110 support" default n +config PLATFORM_TENSTORRENT_ATLANTIS + bool "Tenstorrent Atlantis support" + select CPU_TENSTORRENT_ASCALON + default n + config PLATFORM_THEAD bool "THEAD C9xx support" select THEAD_C9XX_ERRATA @@ -114,6 +119,7 @@ config PLATFORM_MIPS_P8700_BOSTON source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig" source "$(OPENSBI_SRC_DIR)/platform/generic/eswin/Kconfig" +source "$(OPENSBI_SRC_DIR)/platform/generic/tenstorrent/Kconfig" source "$(OPENSBI_SRC_DIR)/platform/generic/thead/Kconfig" endif diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig index 1d3431e7..800f3f14 100644 --- a/platform/generic/configs/defconfig +++ b/platform/generic/configs/defconfig @@ -10,6 +10,7 @@ CONFIG_PLATFORM_SIFIVE_FU540=y CONFIG_PLATFORM_SIFIVE_FU740=y CONFIG_PLATFORM_SOPHGO_SG2042=y CONFIG_PLATFORM_STARFIVE_JH7110=y +CONFIG_PLATFORM_TENSTORRENT_ATLANTIS=y CONFIG_PLATFORM_THEAD=y CONFIG_PLATFORM_MIPS_P8700_EYEQ7H=y CONFIG_PLATFORM_MIPS_P8700_BOSTON=y diff --git a/platform/generic/include/tenstorrent/ascalon.h b/platform/generic/include/tenstorrent/ascalon.h new file mode 100644 index 00000000..5d7b7635 --- /dev/null +++ b/platform/generic/include/tenstorrent/ascalon.h @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef __TENSTORRENT_ASCALON_H__ +#define __TENSTORRENT_ASCALON_H__ + +void tt_ascalon_discover_pmas_from_boot_hart(void); +void tt_ascalon_verify_pmas_nonboot_hart(void); + +#endif diff --git a/platform/generic/include/tenstorrent/pma.h b/platform/generic/include/tenstorrent/pma.h new file mode 100644 index 00000000..db8310e6 --- /dev/null +++ b/platform/generic/include/tenstorrent/pma.h @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef __TENSTORRENT_PMA_H__ +#define __TENSTORRENT_PMA_H__ + +/* Max number of PMAs for devices (CPU, IOMMU) for Tenstorrent platforms. */ +#define TT_MAX_PMAS 32 + +u64 tt_pma_get(unsigned int n); +void tt_pma_set(unsigned int n, u64 pma); +bool tt_pma_validate(unsigned int i, u64 pma); +void tt_pma_print(unsigned int i, u64 pma); + +#endif diff --git a/platform/generic/tenstorrent/Kconfig b/platform/generic/tenstorrent/Kconfig new file mode 100644 index 00000000..76c7fb32 --- /dev/null +++ b/platform/generic/tenstorrent/Kconfig @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc. +# SPDX-License-Identifier: BSD-2-Clause + +config CPU_TENSTORRENT_ASCALON + bool diff --git a/platform/generic/tenstorrent/ascalon.c b/platform/generic/tenstorrent/ascalon.c new file mode 100644 index 00000000..485144cd --- /dev/null +++ b/platform/generic/tenstorrent/ascalon.c @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +#include +#include + +#define CSR_PMACFG0 0x7e0 + +void tt_ascalon_discover_pmas_from_boot_hart(void) +{ + struct sbi_trap_info trap = {0}; + + /* Whisper virtual platform does not implement PMA */ + csr_read_allowed(CSR_PMACFG0, &trap); + if (trap.cause) + return; + + for (unsigned int i = 0; i < TT_MAX_PMAS; i++) { + u64 pma = csr_read_num(CSR_PMACFG0 + i); + if (!tt_pma_validate(i, pma)) { + sbi_printf("HART%d: Bad boot PMA%02d 0x%016lx\n", + current_hartid(), i, pma); + } + tt_pma_set(i, pma); + + if (pma) + tt_pma_print(i, pma); + } +} + +void tt_ascalon_verify_pmas_nonboot_hart(void) +{ + struct sbi_trap_info trap = {0}; + + /* Whisper virtual platform does not implement PMA */ + csr_read_allowed(CSR_PMACFG0, &trap); + if (trap.cause) + return; + + for (unsigned int i = 0; i < TT_MAX_PMAS; i++) { + u64 pma = csr_read_num(CSR_PMACFG0 + i); + if (pma != tt_pma_get(i)) { + sbi_printf("HART%d: Bad boot PMA%02d 0x%016lx does not match boot HART\n", + current_hartid(), i, pma); + } + } +} diff --git a/platform/generic/tenstorrent/atlantis.c b/platform/generic/tenstorrent/atlantis.c new file mode 100644 index 00000000..4c312f7e --- /dev/null +++ b/platform/generic/tenstorrent/atlantis.c @@ -0,0 +1,50 @@ +/* + * SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +static int tt_atlantis_final_init(bool cold_boot) +{ + if (cold_boot) { + /* Boot firmware sets HART PMAs. Read and verify them. */ + tt_ascalon_discover_pmas_from_boot_hart(); + } else { + /* Verify nonboot HARTs have PMAs matching boot HART */ + tt_ascalon_verify_pmas_nonboot_hart(); + } + + return generic_final_init(cold_boot); +} + +static bool tt_atlantis_single_fw_region(void) +{ + return true; +} + +static int tt_atlantis_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match) +{ + generic_platform_ops.final_init = tt_atlantis_final_init; + generic_platform_ops.single_fw_region = tt_atlantis_single_fw_region; + + return 0; +} + +static const struct fdt_match tt_atlantis_match[] = { + { .compatible = "tenstorrent,atlantis" }, + { }, +}; + +const struct fdt_driver tenstorrent_atlantis = { + .match_table = tt_atlantis_match, + .init = tt_atlantis_platform_init, +}; diff --git a/platform/generic/tenstorrent/objects.mk b/platform/generic/tenstorrent/objects.mk new file mode 100644 index 00000000..17da2c5e --- /dev/null +++ b/platform/generic/tenstorrent/objects.mk @@ -0,0 +1,12 @@ +# +# SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc. +# SPDX-License-Identifier: BSD-2-Clause +# + +ifeq ($(PLATFORM_RISCV_XLEN), 64) +platform-objs-y += tenstorrent/pma.o +platform-objs-$(CONFIG_CPU_TENSTORRENT_ASCALON) += tenstorrent/ascalon.o + +carray-platform_override_modules-$(CONFIG_PLATFORM_TENSTORRENT_ATLANTIS) += tenstorrent_atlantis +platform-objs-$(CONFIG_PLATFORM_TENSTORRENT_ATLANTIS) += tenstorrent/atlantis.o +endif diff --git a/platform/generic/tenstorrent/pma.c b/platform/generic/tenstorrent/pma.c new file mode 100644 index 00000000..daf60192 --- /dev/null +++ b/platform/generic/tenstorrent/pma.c @@ -0,0 +1,138 @@ +/* + * SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include + +/* + * All PMAs in the system should be the same (after boot). The init code + * must have set PMAs for all HARTs. + */ + +/* + * Ascalon CPU and IOMMU PMA layout: + * Field + * [2:0] Permission [0] Read, [1] Write, [2] Execute + * [4:3] Memory type 00: Main memory, 01: IO memory relaxed, + * 10: IO memory channel 0, 11: IO memory channel 1 + * [6:5] AMO type 00: AMONone, 01: AMOSwap, + * 10: AMOLogical, 11: AMOArithmetic + * [7] Cacheability (main memory type) + * 1: Cacheable, 0: Non-cacheable + * Combining Capability (IO memory type) + * 1: Combining allowed, 0: Combining disallowed + * [8] Routing (coherency) + * 1: Coherent network, 0: Non-coherent network + * [11:9] Reserved + * [51:12] Physical address [51:12] base + * [63:58] Size log 2 (number of address LSB to ignore when matching) + * 0 = invalid entry (no match) + */ + +#define PMA_PERMISSION_R 0x1 +#define PMA_PERMISSION_W 0x2 +#define PMA_PERMISSION_X 0x4 +#define PMA_PERMISSION_MASK 0x7 + +#define PMA_TYPE_MAIN_MEMORY 0x0 +#define PMA_TYPE_IO_RELAXED 0x8 +#define PMA_TYPE_IO_ORDERED_0 0x10 +#define PMA_TYPE_IO_ORDERED_1 0x18 +#define PMA_TYPE_MASK 0x18 + +#define PMA_AMO_NONE 0x0 +#define PMA_AMO_SWAP 0x20 +#define PMA_AMO_LOGICAL 0x40 +#define PMA_AMO_ARITHMETIC 0x60 +#define PMA_AMO_MASK 0x60 + +#define PMA_MEMORY_CACHEABLE 0x80 +#define PMA_IO_COMBINING 0x80 +#define PMA_ROUTING_COHERENT 0x100 + +#define PMA_FLAGS_MASK 0x00000000000001ffULL +#define PMA_ADDRESS_MASK 0x000ffffffffff000ULL +#define PMA_SIZE_MASK 0xfc00000000000000ULL +#define PMA_RESERVED_MASK 0x0300000000000e00ULL + +#define PMA_SIZE_SHIFT 58 + +static u64 tt_pma_size(u64 pma) +{ + if ((pma & PMA_SIZE_MASK) == 0) + return 0; + + return 1ULL << ((pma & PMA_SIZE_MASK) >> PMA_SIZE_SHIFT); +} + +static u64 tt_pma_address(u64 pma) +{ + return (pma & PMA_ADDRESS_MASK) & ~((tt_pma_size(pma) - 1)); +} + +bool tt_pma_validate(unsigned int i, u64 pma) +{ + if (!pma) + return true; + + if (pma & PMA_RESERVED_MASK) { + sbi_printf("PMA%02u 0x%016lx contains reserved bits\n", i, pma); + return false; + } + + if (tt_pma_size(pma) < 4096) { + sbi_printf("PMA%02u 0x%016lx size < 4KB\n", i, pma); + return false; + } + + if (tt_pma_address(pma) != (pma & PMA_ADDRESS_MASK)) { + sbi_printf("PMA%02u 0x%016lx address is not aligned to size\n", i, pma); + return false; + } + + return true; +} + +void tt_pma_print(unsigned int i, u64 pma) +{ + sbi_printf("PMA%02d : 0x%016lx-0x%016lx perm:%s%s%s type:%s %s %s amo:%s\n", i, + tt_pma_address(pma), tt_pma_address(pma) + tt_pma_size(pma) - 1, + pma & PMA_PERMISSION_R ? "R" : " ", + pma & PMA_PERMISSION_W ? "W" : " ", + pma & PMA_PERMISSION_X ? "X" : " ", + (pma & PMA_TYPE_MASK) == PMA_TYPE_MAIN_MEMORY ? "main-memory" : + ((pma & PMA_TYPE_MASK) == PMA_TYPE_IO_RELAXED ? "io-relaxed" : + ((pma & PMA_TYPE_MASK) == PMA_TYPE_IO_ORDERED_0 ? "io-ordered-0" : "io-ordered-1")), + (pma & PMA_TYPE_MASK) == PMA_TYPE_MAIN_MEMORY ? + (pma & PMA_MEMORY_CACHEABLE ? "cacheable" : "non-cacheable") : + (pma & PMA_IO_COMBINING ? "combining" : "non-combining"), + pma & PMA_ROUTING_COHERENT ? "coherent" : "non-coherent", + (pma & PMA_AMO_MASK) == PMA_AMO_NONE ? "none" : + ((pma & PMA_AMO_MASK) == PMA_AMO_SWAP ? "swap" : + ((pma & PMA_AMO_MASK) == PMA_AMO_LOGICAL ? "logical" : "arithmetic"))); +} + +static u64 pmas[TT_MAX_PMAS]; + +void tt_pma_set(unsigned int n, u64 pma) +{ + if (n >= TT_MAX_PMAS) + sbi_panic("PMA exceeded TT_MAX_PMAS"); + + pmas[n] = pma; +} + +u64 tt_pma_get(unsigned int n) +{ + if (n >= TT_MAX_PMAS) + sbi_panic("PMA exceeded TT_MAX_PMAS"); + + return pmas[n]; +}