rp: Entirely rewrote the SPI Flash read routine so we can implement SFDP support

This commit is contained in:
dragonmux 2022-08-05 18:15:37 +01:00 committed by Piotr Esden-Tempski
parent 6559c46ce9
commit 253d0cc1d9
1 changed files with 92 additions and 23 deletions

View File

@ -41,6 +41,7 @@
#include "target.h"
#include "target_internal.h"
#include "cortexm.h"
#include "sfdp.h"
#define RP_ID "Raspberry RP2040"
#define RP_MAX_TABLE_SIZE 0x80U
@ -58,9 +59,32 @@
#define RP_GPIO_QSPI_CS_DRIVE_HIGH (3U << 8U)
#define RP_GPIO_QSPI_CS_DRIVE_MASK 0x00000300U
#define RP_SSI_BASE_ADDR 0x18000000U
#define RP_SSI_CTRL0 (RP_SSI_BASE_ADDR + 0x00U)
#define RP_SSI_DR0 (RP_SSI_BASE_ADDR + 0x60U)
#define RP_SSI_BASE_ADDR 0x18000000U
#define RP_SSI_CTRL0 (RP_SSI_BASE_ADDR + 0x00U)
#define RP_SSI_CTRL1 (RP_SSI_BASE_ADDR + 0x04U)
#define RP_SSI_ENABLE (RP_SSI_BASE_ADDR + 0x08U)
#define RP_SSI_DR0 (RP_SSI_BASE_ADDR + 0x60U)
#define RP_SSI_XIP_SPI_CTRL0 (RP_SSI_BASE_ADDR + 0xf4U)
#define RP_SSI_CTRL0_FRF_MASK 0x00600000U
#define RP_SSI_CTRL0_FRF_SERIAL (0U << 21U)
#define RP_SSI_CTRL0_FRF_DUAL (1U << 21U)
#define RP_SSI_CTRL0_FRF_QUAD (2U << 21U)
#define RP_SSI_CTRL0_TMOD_MASK 0x00000300U
#define RP_SSI_CTRL0_TMOD_BIDI (0U << 8U)
#define RP_SSI_CTRL0_TMOD_TX_ONLY (1U << 8U)
#define RP_SSI_CTRL0_TMOD_RX_ONLY (2U << 8U)
#define RP_SSI_CTRL0_TMOD_EEPROM (3U << 8U)
#define RP_SSI_CTRL0_DATA_BIT_MASK 0x001f0000U
#define RP_SSI_CTRL0_DATA_BIT_SHIFT 16U
#define RP_SSI_CTRL0_DATA_BITS(x) (((x) - 1U) << RP_SSI_CTRL0_DATA_BIT_SHIFT)
#define RP_SSI_CTRL0_MASK (RP_SSI_CTRL0_FRF_MASK | RP_SSI_CTRL0_TMOD_MASK | RP_SSI_CTRL0_DATA_BIT_MASK)
#define RP_SSI_ENABLE_SSI (1U << 0U)
#define RP_SSI_XIP_SPI_CTRL0_FORMAT_STD_SPI (0U << 0U)
#define RP_SSI_XIP_SPI_CTRL0_FORMAT_SPLIT (1U << 0U)
#define RP_SSI_XIP_SPI_CTRL0_FORMAT_FRF (2U << 0U)
#define RP_SSI_XIP_SPI_CTRL0_ADDRESS_LENGTH(x) (((x) * 2U) << 2U)
#define RP_SSI_XIP_SPI_CTRL0_INSTR_LENGTH_8b (2U << 8U)
#define RP_SSI_XIP_SPI_CTRL0_WAIT_CYCLES(x) (((x) * 8U) << 11U)
#define BOOTROM_FUNC_TABLE_ADDR 0x00000014U
#define BOOTROM_FUNC_TABLE_TAG(x, y) ((uint8_t)(x) | ((uint8_t)(y) << 8U))
@ -71,6 +95,15 @@
#define FLASHSIZE_64K_BLOCK_MASK ~(FLASHSIZE_64K_BLOCK - 1U)
#define MAX_FLASH (16U * 1024U * 1024U)
#define RP_SPI_OPCODE(x) (x)
#define RP_SPI_OPCODE_MASK 0x00ffU
#define RP_SPI_INTER_SHIFT 8U
#define RP_SPI_INTER_LENGTH(x) (((x) & 7U) << RP_SPI_INTER_SHIFT)
#define RP_SPI_INTER_MASK 0x0700U
#define RP_SPI_FRAME_OPCODE_ONLY (1 << 11U)
#define RP_SPI_FRAME_OPCODE_3B_ADDR (2 << 11U)
#define RP_SPI_FRAME_MASK 0x1800U
/* Instruction codes taken from Winbond W25Q16JV datasheet, as used on the
* original Pico board from Raspberry Pi.
* https://www.winbond.com/resource-files/w25q16jv%20spi%20revd%2008122016.pdf
@ -83,7 +116,8 @@
#define FLASHCMD_BLOCK32K_ERASE 0x52
#define FLASHCMD_BLOCK64K_ERASE 0xd8
#define FLASHCMD_CHIP_ERASE 0x60
#define FLASHCMD_READ_JEDEC_ID 0x9F
#define SPI_FLASH_CMD_READ_JEDEC_ID (RP_SPI_OPCODE(0x9fU) | RP_SPI_INTER_LENGTH(0) | RP_SPI_FRAME_OPCODE_ONLY)
#define SPI_FLASH_CMD_READ_SFDP (RP_SPI_OPCODE(0x5aU) | RP_SPI_INTER_LENGTH(1) | RP_SPI_FRAME_OPCODE_3B_ADDR)
typedef struct rp_priv {
uint16_t rom_debug_trampoline_begin;
@ -440,26 +474,62 @@ static void rp_spi_chip_select(target *const t, const bool active)
target_mem_write32(t, RP_GPIO_QSPI_CS_CTRL, (value & ~RP_GPIO_QSPI_CS_DRIVE_MASK) | state);
}
static uint32_t rp_read_flash_chip(target *t, uint32_t cmd)
static void rp_spi_read(
target *const t, const uint16_t command, const target_addr address, void *const buffer, const size_t length)
{
uint32_t value = 0;
/* Ensure the controller is in the correct serial SPI mode and select the Flash */
const uint32_t ssi_enabled = target_mem_read32(t, RP_SSI_ENABLE);
target_mem_write32(t, RP_SSI_ENABLE, 0);
const uint32_t ctrl0 = target_mem_read32(t, RP_SSI_CTRL0);
const uint32_t ctrl1 = target_mem_read32(t, RP_SSI_CTRL1);
const uint32_t xpi_ctrl0 = target_mem_read32(t, RP_SSI_XIP_SPI_CTRL0);
target_mem_write32(t, RP_SSI_CTRL0,
(ctrl0 & RP_SSI_CTRL0_MASK) | RP_SSI_CTRL0_FRF_SERIAL | RP_SSI_CTRL0_TMOD_BIDI | RP_SSI_CTRL0_DATA_BITS(8));
target_mem_write32(t, RP_SSI_XIP_SPI_CTRL0,
RP_SSI_XIP_SPI_CTRL0_FORMAT_FRF | RP_SSI_XIP_SPI_CTRL0_ADDRESS_LENGTH(0) |
RP_SSI_XIP_SPI_CTRL0_INSTR_LENGTH_8b | RP_SSI_XIP_SPI_CTRL0_WAIT_CYCLES(0));
target_mem_write32(t, RP_SSI_CTRL1, length);
target_mem_write32(t, RP_SSI_ENABLE, RP_SSI_ENABLE_SSI);
rp_spi_chip_select(t, true);
/* write command into SPI peripheral's FIFO */
for (size_t i = 0; i < 4; i++)
target_mem_write32(t, RP_SSI_DR0, cmd);
/* Set up the instruction */
const uint8_t opcode = command & RP_SPI_OPCODE_MASK;
target_mem_write32(t, RP_SSI_DR0, opcode);
target_mem_read32(t, RP_SSI_DR0);
/* now we have an entry in the receive FIFO for each write */
for (size_t i = 0; i < 4; i++) {
uint32_t status = target_mem_read32(t, RP_SSI_DR0);
value |= (status & 0xFF) << 24;
value >>= 8;
const uint16_t addr_mode = command & RP_SPI_FRAME_MASK;
if (addr_mode == RP_SPI_FRAME_OPCODE_3B_ADDR) {
/* For each byte sent here, we have to manually clean up from the controller with a read */
target_mem_write32(t, RP_SSI_DR0, (address >> 16U) & 0xffU);
target_mem_read32(t, RP_SSI_DR0);
target_mem_write32(t, RP_SSI_DR0, (address >> 8U) & 0xffU);
target_mem_read32(t, RP_SSI_DR0);
target_mem_write32(t, RP_SSI_DR0, address & 0xffU);
target_mem_read32(t, RP_SSI_DR0);
}
rp_spi_chip_select(t, false);
const size_t inter_length = (command & RP_SPI_INTER_MASK) >> RP_SPI_INTER_SHIFT;
for (size_t i = 0; i < inter_length; ++i) {
/* For each byte sent here, we have to manually clean up from the controller with a read */
target_mem_write32(t, RP_SSI_DR0, 0);
target_mem_read32(t, RP_SSI_DR0);
}
return value;
/* Now read back the data that elicited */
uint8_t *const data = (uint8_t *const)buffer;
for (size_t i = 0; i < length; ++i) {
/* Do a write to read */
target_mem_write32(t, RP_SSI_DR0, 0);
data[i] = target_mem_read32(t, RP_SSI_DR0) & 0xffU;
}
/* Deselect the Flash and put things back to how they were */
rp_spi_chip_select(t, false);
target_mem_write32(t, RP_SSI_ENABLE, 0);
target_mem_write32(t, RP_SSI_CTRL1, ctrl1);
target_mem_write32(t, RP_SSI_CTRL0, ctrl0);
target_mem_write32(t, RP_SSI_XIP_SPI_CTRL0, xpi_ctrl0);
target_mem_write32(t, RP_SSI_ENABLE, ssi_enabled);
}
static uint32_t rp_get_flash_length(target *t)
@ -494,14 +564,13 @@ static uint32_t rp_get_flash_length(target *t)
size = MAX_FLASH;
rp_flash_prepare(t);
uint32_t flash_id = rp_read_flash_chip(t, FLASHCMD_READ_JEDEC_ID);
spi_flash_id_s flash_id;
rp_spi_read(t, SPI_FLASH_CMD_READ_JEDEC_ID, 0, &flash_id, sizeof(flash_id));
rp_flash_resume(t);
DEBUG_INFO("Flash device ID: %08" PRIx32 "\n", flash_id);
uint8_t size_log2 = (flash_id & 0xff0000) >> 16;
if (size_log2 >= 8 && size_log2 <= 34)
size = 1 << size_log2;
DEBUG_INFO("Flash device ID: %02x %02x %02x\n", flash_id.manufacturer, flash_id.type, flash_id.capacity);
if (flash_id.capacity >= 8 && flash_id.capacity <= 34)
size = 1 << flash_id.capacity;
return size;
}