mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2026-05-23 14:21:32 +01:00
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 <npiggin@gmail.com> Reviewed-by: Anup Patel <anup@brainfault.org> Link: https://lore.kernel.org/r/20260424062520.238403-1-npiggin@gmail.com Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
committed by
Anup Patel
parent
1932ee3f0a
commit
6767861c48
@@ -0,0 +1,5 @@
|
||||
# SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc.
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
config CPU_TENSTORRENT_ASCALON
|
||||
bool
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc.
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <sbi/riscv_asm.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_csr_detect.h>
|
||||
|
||||
#include <tenstorrent/ascalon.h>
|
||||
#include <tenstorrent/pma.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc.
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <platform_override.h>
|
||||
#include <libfdt.h>
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_hart.h>
|
||||
#include <sbi/sbi_system.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
|
||||
#include <tenstorrent/ascalon.h>
|
||||
#include <tenstorrent/pma.h>
|
||||
|
||||
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,
|
||||
};
|
||||
@@ -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
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc.
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <sbi/sbi_error.h>
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_math.h>
|
||||
#include <libfdt.h>
|
||||
#include <sbi_utils/fdt/fdt_helper.h>
|
||||
|
||||
#include <tenstorrent/pma.h>
|
||||
|
||||
/*
|
||||
* 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];
|
||||
}
|
||||
Reference in New Issue
Block a user