Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,14 @@ partitions {
read-only;
};

/* TRISC dest wipe firmware, loaded to Tensix L1 by wipe_dest() */
destwipe: partition@22c000 {
label = "destwipe";
reg = <0x22c000 DT_SIZE_K(4)>;
binary-path = "$BLOBS_DIR/tt_blackhole_trisc_dest_wipe.bin";
read-only;
};

/* Update firmware image for the DMC, as seen by mcuboot */
dmfw: partition@22d000 {
label = "dmfw";
Expand Down
171 changes: 170 additions & 1 deletion lib/tenstorrent/bh_arc/tensix_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,59 @@

#include "noc2axi.h"
#include "noc_init.h"
#include "harvesting.h"

#include <stdint.h>
#include <string.h>

#include <tenstorrent/post_code.h>
#include <tenstorrent/spi_flash_buf.h>
#include <tenstorrent/sys_init_defines.h>
#include <tenstorrent/tt_boot_fs.h>
#include <zephyr/device.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/drivers/misc/bh_fwtable.h>
#include <zephyr/drivers/dma.h>
#include <zephyr/drivers/dma/dma_tt_bh_noc.h>
#include <zephyr/init.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/util.h>

LOG_MODULE_REGISTER(tensix_init, CONFIG_TT_APP_LOG_LEVEL);

#define ARC_NOC0_X 8
#define ARC_NOC0_Y 0

#define TENSIX_X_START 2
#define TENSIX_Y_START 2
#define TENSIX_X_END 1
#define TENSIX_Y_END 11
#define TENSIX_L1_SIZE (1536 * 1024)

/* Tensix RISC control registers */
#define TRISC0_RESET_PC 0xFFB12228
#define TRISC_RESET_PC_OVERRIDE 0xFFB12234
#define SOFT_RESET_0 0xFFB121B0
#define ALL_RISC_SOFT_RESET 0x47800

/* TRISC0 wipe firmware parameters */
#define TRISC_WIPE_FW_TAG "destwipe"
#define TRISC_WIPE_FW_LOAD_ADDR 0x6000 /* TRISC0_CODE region start */

/* Scratchpad buffer size for SPI transfers */
#define SCRATCHPAD_SIZE CONFIG_TT_BH_ARC_SCRATCHPAD_SIZE

/* Counter location for wipe_dest */
#define COUNTER_TENSIX_X 1
#define COUNTER_TENSIX_Y 2
#define COUNTER_L1_ADDR 0x110000 /* Must match firmware hardcoded value */
#define NUM_TENSIX_ROWS 10
#define WIPE_DEST_TIMEOUT_US 10000 /* 10ms timeout */

static const struct device *const fwtable_dev = DEVICE_DT_GET(DT_NODELABEL(fwtable));
static const struct device *const dma_noc = DEVICE_DT_GET(DT_NODELABEL(dma1));
static const struct device *const flash = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(spi_flash));

/* Enable CG_CTRL_EN in each non-harvested Tensix node and set CG hystersis to 2. */
/* This requires NOC init so that broadcast is set up properly. */
Expand Down Expand Up @@ -142,13 +178,140 @@ static void wipe_l1(void)
dma_start(dma_noc, 1);
}

/**
* @brief Global synchronization for wipe_dest
*
* This function is used to synchronize the wipe_dest operation across all tensix cores.
* It reads the counter from the chosen tensix core and waits for it to reach the expected count.
* It returns 0 if the counter reached the expected count, -ETIMEDOUT otherwise.
*/
static int global_sync(uint8_t ring, uint8_t noc_tlb, uint32_t expected_count)
{
NOC2AXITlbSetup(ring, noc_tlb, COUNTER_TENSIX_X, COUNTER_TENSIX_Y, COUNTER_L1_ADDR);

if (!WAIT_FOR(NOC2AXIRead32(ring, noc_tlb, COUNTER_L1_ADDR) >= expected_count,
WIPE_DEST_TIMEOUT_US, k_busy_wait(10))) {
uint32_t actual = NOC2AXIRead32(ring, noc_tlb, COUNTER_L1_ADDR);

LOG_ERR("%s: timeout, counter=%u expected=%u", __func__, actual, expected_count);
return -ETIMEDOUT;
}

return 0;
}

/**
* @brief Helper function to write 32-bit words to NOC
*
* This function is used to write 32-bit words to NOC using DMA.
*/
static int noc2axi_write32_fw(uint8_t *src, uint8_t *dst, size_t len)
{
const uint32_t *fw_words = (const uint32_t *)src;
size_t num_words = len / sizeof(uint32_t);
uintptr_t addr = (uintptr_t)dst;

for (size_t i = 0; i < num_words; i++) {
NOC2AXIWrite32(0, 0, addr + i * sizeof(uint32_t), fw_words[i]);
}
return 0;
}

/**
* @brief Setup the multicast TLB for the unharvested tensix cores
*
* @param addr The address to load the firmware to
*/
static inline void setup_tensix_mcast_tlb(uint32_t addr)
{
uint8_t ring = 0;
uint8_t noc_tlb = 0;

NOC2AXIMulticastTlbSetup(ring, noc_tlb, TENSIX_X_START, TENSIX_Y_START, TENSIX_X_END,
TENSIX_Y_END, addr, kNoc2AxiOrderingStrict);
}

/**
* @brief Zeros the DEST register of every non-harvested tensix core
*
* The DEST register can only be written by code running on the local TRISC.
* This function loads a wipe firmware from SPI flash to each Tensix's L1,
* runs it on TRISC 0 to clear DEST using 32-bit stores, then puts TRISC 0
* back in reset.
*/
static int wipe_dest(void)
{
uint8_t ring = 0;
uint8_t noc_tlb = 0;
uint8_t wipe_dest_buf[SCRATCHPAD_SIZE] __aligned(4);

int rc;
tt_boot_fs_fd tag_fd;
size_t image_size;
size_t spi_address;

/* Find the TRISC wipe firmware in SPI flash */
rc = tt_boot_fs_find_fd_by_tag(flash, (const uint8_t *)TRISC_WIPE_FW_TAG, &tag_fd);
if (rc < 0) {
LOG_ERR("%s(%s) failed: %d", "tt_boot_fs_find_fd_by_tag", TRISC_WIPE_FW_TAG, rc);
return rc;
}
image_size = tag_fd.flags.f.image_size;
spi_address = tag_fd.spi_addr;
LOG_INF("%s: found %s at 0x%x, size %zu", __func__, TRISC_WIPE_FW_TAG, spi_address,
image_size);

/* Step 1: Zero the completion counter before releasing TRISCs */
NOC2AXITlbSetup(ring, noc_tlb, COUNTER_TENSIX_X, COUNTER_TENSIX_Y, COUNTER_L1_ADDR);
NOC2AXIWrite32(ring, noc_tlb, COUNTER_L1_ADDR, 0);

/* Step 2: Load wipe firmware to all non-harvested Tensix L1 using multicast */
setup_tensix_mcast_tlb(TRISC_WIPE_FW_LOAD_ADDR);

/* Round up to ensure all 32-bit writes are complete */
image_size = ROUND_UP(image_size, sizeof(uint32_t));

rc = spi_transfer_by_parts(
flash, spi_address, image_size, wipe_dest_buf, sizeof(wipe_dest_buf),
(uint8_t *)(uintptr_t)TRISC_WIPE_FW_LOAD_ADDR, noc2axi_write32_fw);
if (rc < 0) {
LOG_ERR("%s(%s) failed: %d", "spi_transfer_by_parts", TRISC_WIPE_FW_TAG, rc);
return rc;
}
LOG_INF("%s: firmware loaded", __func__);

/* Step 3: Set TRISC 0 reset PC to firmware load address on all Tensix */
setup_tensix_mcast_tlb(TRISC0_RESET_PC);
NOC2AXIWrite32(ring, noc_tlb, TRISC0_RESET_PC, TRISC_WIPE_FW_LOAD_ADDR);
NOC2AXIWrite32(ring, noc_tlb, TRISC_RESET_PC_OVERRIDE, 1);

/* Step 4: Release TRISC 0 from soft reset on all Tensix */
NOC2AXIWrite32(ring, noc_tlb, SOFT_RESET_0, ALL_RISC_SOFT_RESET & ~BIT(12));

/* Step 5: Wait for all cores to signal completion via atomic counter */
uint32_t expected = POPCOUNT(tile_enable.tensix_col_enabled) * NUM_TENSIX_ROWS;
int rc_sync = global_sync(ring, noc_tlb, expected);

if (rc_sync < 0) {
return rc_sync;
}

/* Step 6: Re-assert TRISC 0 soft reset on all Tensix */
setup_tensix_mcast_tlb(SOFT_RESET_0);
NOC2AXIWrite32(ring, noc_tlb, SOFT_RESET_0, ALL_RISC_SOFT_RESET);
NOC2AXIWrite32(ring, noc_tlb, TRISC_RESET_PC_OVERRIDE, 0);

LOG_INF("%s: completed", __func__);
return 0;
}

void TensixInit(void)
{
if (!tt_bh_fwtable_get_fw_table(fwtable_dev)->feature_enable.cg_en) {
EnableTensixCG();
}

/* wipe_l1() isn't here because it's only needed on boot & board reset. */
/* wipe_l1()/wipe_dest() aren't here because they're only needed on boot & board reset. */
}

static int tensix_init(void)
Expand All @@ -162,6 +325,12 @@ static int tensix_init(void)
TensixInit();

wipe_l1();
int rc_wipe_dest = wipe_dest();

if (rc_wipe_dest < 0) {
LOG_ERR("%s: wipe_dest failed: %d", __func__, rc_wipe_dest);
return rc_wipe_dest;
}

return 0;
}
Expand Down
Binary file added zephyr/blobs/tt_blackhole_trisc_dest_wipe.bin
Binary file not shown.
9 changes: 9 additions & 0 deletions zephyr/module.yml
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,12 @@ blobs:
raw/refs/heads/main/zephyr/blobs/fw_pack-grayskull.tar.gz"
description: "Grayskull FW"
doc-url: https://tenstorrent.com
- path: tt_blackhole_trisc_dest_wipe.bin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this merged to the internal repository?

If so we should document the git hash, or some version, from which it came from...

If not, we should do that first, then do above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sry I just caught 0.2. Is that accurate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be a good format to add git hash? I am not sure if having a commented source is good enough...

# Source: <full-commit-hash> in t6py

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appologies @ShLiTT ; you have a verion 0.2 there. I'm not sure if that's accurate or not but that'll probably do, so long as internally the verison is being tracked as well.

sha256: 038c8e7d1393c3f3cd076344c3cb9377c8cb9cb1c01e1d64c0b2e9767769184f
type: img
version: '0.1'
license-path: zephyr/blobs/license.txt
url: "https://github.com/tenstorrent/tt-zephyr-platforms/\
raw/refs/heads/main/zephyr/blobs/tt_blackhole_trisc_dest_wipe.bin"
description: "TRISC 0 DEST wipe firmware"
doc-url: https://tenstorrent.com
Loading