Commit 0715b617 authored by Raptor Engineering Development Team's avatar Raptor Engineering Development Team
Browse files

Add triple read mode for SPI hardware / HDL diagnostics

This optional debug mode will attempt to read each Flash chunk three
times, comparing all three read values to determine if bus instability
exists.  This mode is slower than a straight read, but is useful in
initial bringup of new hardware designs or when modifying the SPI
core HDL and for CI/CD checks.
parent e4b65f5d
......@@ -29,9 +29,11 @@
// Performance controls
#define ENABLE_LPC_FW_CYCLE_IRQ_HANDLER
#define ENABLE_LPC_FW_CYCLE_DMA
#define ALLOW_SPI_QUAD_MODE 1
// Debug knobs
// #define DEBUG_HOST_SPI_FLASH_READ 1
#define SPI_FLASH_TRIPLE_READ 0 // Set to 1 to enable triple-read data checks (slow)
// General RCS platform registers
#define HOST_PLATFORM_FPGA_I2C_REG_STATUS 0x7
......@@ -2378,11 +2380,13 @@ static int host_spi_flash_init(void)
dword |= ((TERCEL_SPI_PHY_4BA_MODE & TERCEL_SPI_PHY_4BA_ENABLE_MASK) << TERCEL_SPI_PHY_4BA_ENABLE_SHIFT);
write_tercel_register(HOSTSPIFLASHCFG_BASE, TERCEL_SPI_REG_SYS_PHY_CFG1, dword);
#if (ALLOW_SPI_QUAD_MODE)
// Set SPI controller to QSPI mode
dword = read_tercel_register(HOSTSPIFLASHCFG_BASE, TERCEL_SPI_REG_SYS_PHY_CFG1);
dword &= ~(TERCEL_SPI_PHY_IO_TYPE_MASK << TERCEL_SPI_PHY_IO_TYPE_SHIFT);
dword |= ((TERCEL_SPI_PHY_IO_TYPE_QUAD & TERCEL_SPI_PHY_IO_TYPE_MASK) << TERCEL_SPI_PHY_IO_TYPE_SHIFT);
write_tercel_register(HOSTSPIFLASHCFG_BASE, TERCEL_SPI_REG_SYS_PHY_CFG1, dword);
#endif
// Set SPI clock cycle divider to 5
dword = read_tercel_register(HOSTSPIFLASHCFG_BASE, TERCEL_SPI_REG_SYS_PHY_CFG1);
......@@ -2415,6 +2419,92 @@ static int host_spi_flash_init(void)
}
#endif
#ifdef WITH_SPI
#define SPI_READ_TRANSFER_SIZE (1 * 1024 * 1024LL)
int copy_spi_flash_to_internal_buffer(uintptr_t flash_data, uintptr_t flash_ctl, uint8_t *buffer)
{
int retcode;
int chunk;
int redundancy_chunk;
uintptr_t redundancy_buffer_offset;
#if (SPI_FLASH_TRIPLE_READ)
uintptr_t buffer_check_offset;
uint32_t value1;
uint32_t value2;
uint32_t value3;
uint32_t final_value;
#endif
printf("Copying host Flash ROM (%p) to internal buffer (%p)...\n", flash_data, buffer);
retcode = 0;
for (chunk = 0; chunk < FLASH_SIZE_BYTES / SPI_READ_TRANSFER_SIZE; chunk++)
{
#if (SPI_FLASH_TRIPLE_READ)
for (redundancy_chunk = 0; redundancy_chunk < 3; redundancy_chunk++)
{
#else
for (redundancy_chunk = 0; redundancy_chunk < 1; redundancy_chunk++)
{
#endif
redundancy_buffer_offset = redundancy_chunk * SPI_READ_TRANSFER_SIZE;
memcpy32((uint32_t *)(buffer + redundancy_buffer_offset + (chunk * SPI_READ_TRANSFER_SIZE)),
(uint32_t *)(flash_data + (chunk * SPI_READ_TRANSFER_SIZE)), SPI_READ_TRANSFER_SIZE / 4);
printf("\r[%d/%d]", chunk + 1, FLASH_SIZE_BYTES / SPI_READ_TRANSFER_SIZE);
// Reset ongoing multibyte access due to die switch requirements on the N25Q
// Flash devices
write_tercel_register(flash_ctl, TERCEL_SPI_REG_SYS_FLASH_CFG5,
read_tercel_register(flash_ctl, TERCEL_SPI_REG_SYS_FLASH_CFG5) &
~(TERCEL_SPI_FLASH_EN_MULTCYC_READ_MASK << TERCEL_SPI_FLASH_EN_MULTCYC_READ_SHIFT));
write_tercel_register(flash_ctl, TERCEL_SPI_REG_SYS_FLASH_CFG5,
read_tercel_register(flash_ctl, TERCEL_SPI_REG_SYS_FLASH_CFG5) |
(TERCEL_SPI_FLASH_EN_MULTCYC_READ_MASK << TERCEL_SPI_FLASH_EN_MULTCYC_READ_SHIFT));
}
#if (SPI_FLASH_TRIPLE_READ)
for (buffer_check_offset = 0; buffer_check_offset < SPI_READ_TRANSFER_SIZE; buffer_check_offset = buffer_check_offset + 4)
{
value1 = *((uint32_t *)(buffer + buffer_check_offset + (chunk * SPI_READ_TRANSFER_SIZE)));
value2 = *((uint32_t *)(buffer + buffer_check_offset + SPI_READ_TRANSFER_SIZE + (chunk * SPI_READ_TRANSFER_SIZE)));
value3 = *((uint32_t *)(buffer + buffer_check_offset + (2 * SPI_READ_TRANSFER_SIZE) + (chunk * SPI_READ_TRANSFER_SIZE)));
if (!((value1 == value2) && (value1 == value3)))
{
printf("[WARNING] Triple read FAILED integrity check at address 0x%08x! Values 0x%08x/0x%08x/0x%08x\n",
buffer + buffer_check_offset + (chunk * SPI_READ_TRANSFER_SIZE), value1, value2, value3);
if (value1 == value2)
{
final_value = value1;
}
else if (value2 == value3)
{
final_value = value2;
}
else if (value1 == value3)
{
final_value = value1;
}
else
{
printf("[ERROR] UNCORRECTABLE data read at address 0x%08x!\n", buffer + buffer_check_offset + (chunk * SPI_READ_TRANSFER_SIZE));
final_value = 0xdeadbeef;
retcode = -1;
}
*((uint32_t *)(buffer + buffer_check_offset + (chunk * SPI_READ_TRANSFER_SIZE))) = final_value;
if (retcode)
{
// Fast abort on fatal error
break;
}
}
}
#endif
}
printf("\r%dMB copied\n", chunk);
return retcode;
}
#endif
int main(void)
{
uint32_t dword;
......@@ -2480,7 +2570,7 @@ int main(void)
}
// Allocate internal host SPI Flash ROM buffer
host_flash_buffer = (uint8_t *)(MAIN_RAM_BASE + 0x4000000);
host_flash_buffer = (uint8_t *)(MAIN_RAM_BASE + 0x3e00000);
// Clear SPI Flash buffer
printf("Clearing host ROM internal buffer...");
......@@ -2498,25 +2588,8 @@ int main(void)
reset_flash_device();
configure_flash_device();
// Allocate internal host SPI Flash ROM buffer
printf("Copying host Flash ROM (%p) to internal buffer (%p)...\n", HOSTSPIFLASH_BASE, host_flash_buffer);
int chunk;
for (chunk = 0; chunk < 64; chunk++)
{
memcpy32((uint32_t *)(host_flash_buffer + (chunk * (1 * 1024 * 1024LL))), (uint32_t *)(HOSTSPIFLASH_BASE + (chunk * (1 * 1024 * 1024LL))),
(1 * 1024 * 1024LL) / 4);
printf("\r[%d/64]", chunk + 1);
// Reset ongoing multibyte access due to die switch requirements on the N25Q
// Flash devices
write_tercel_register(HOSTSPIFLASHCFG_BASE, TERCEL_SPI_REG_SYS_FLASH_CFG5,
read_tercel_register(HOSTSPIFLASHCFG_BASE, TERCEL_SPI_REG_SYS_FLASH_CFG5) &
~(TERCEL_SPI_FLASH_EN_MULTCYC_READ_MASK << TERCEL_SPI_FLASH_EN_MULTCYC_READ_SHIFT));
write_tercel_register(HOSTSPIFLASHCFG_BASE, TERCEL_SPI_REG_SYS_FLASH_CFG5,
read_tercel_register(HOSTSPIFLASHCFG_BASE, TERCEL_SPI_REG_SYS_FLASH_CFG5) |
(TERCEL_SPI_FLASH_EN_MULTCYC_READ_MASK << TERCEL_SPI_FLASH_EN_MULTCYC_READ_SHIFT));
}
printf("\r%dMB copied\n", chunk);
// Copy external SPI Flash ROM contents to internal host SPI Flash ROM buffer
copy_spi_flash_to_internal_buffer(HOSTSPIFLASH_BASE, HOSTSPIFLASHCFG_BASE, host_flash_buffer);
#ifdef DEBUG_HOST_SPI_FLASH_READ
printf("host_flash_buffer: %p First 1KB:\n", host_flash_buffer);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment