Fixes for QSPI read. Adds alternate byte support. Cleanup of simple QSPI read/write.

pull/264/head
David Garske 2022-12-21 17:45:27 -08:00
parent c3cf21a81f
commit 8d7d4d4f74
3 changed files with 127 additions and 89 deletions

View File

@ -194,69 +194,61 @@ static void RAMFUNCTION spi_reset(void)
}
#ifdef QSPI_FLASH
int qspi_transfer(
const uint8_t cmd, uint32_t addr, uint32_t addrSz,
const uint8_t* txData, uint32_t txSz,
uint8_t* rxData, uint32_t rxSz, uint32_t dummySz,
uint32_t mode)
int qspi_transfer(uint8_t fmode, const uint8_t cmd,
uint32_t addr, uint32_t addrSz, uint32_t addrMode,
uint32_t alt, uint32_t altSz, uint32_t altMode,
uint32_t dummySz,
uint8_t* data, uint32_t dataSz, uint32_t dataMode)
{
uint32_t fmode = 0, amode = 0;
uint32_t adsz = 0, dsz = 0;
uint8_t* dptr = NULL;
uint32_t adsz = 0, absz = 0;
if (txData != NULL && txSz > 0) {
fmode = 0; /* indirect write */
dsz = txSz;
dptr = (uint8_t*)txData;
if (addrSz > 0) {
adsz = addrSz-1;
}
else if (rxData != NULL && rxSz > 0) {
fmode = 1; /* indirect read */
dsz = rxSz;
dptr = rxData;
}
else {
mode = 0; /* no data */
if (altSz > 0) {
absz = altSz-1;
}
/* Enable the QSPI peripheral */
QUADSPI_CR |= QUADSPI_CR_EN;
if (dsz > 0) {
QUADSPI_DLR = dsz-1;
}
if (addrSz > 0) {
amode = 1;
adsz = addrSz-1;
if (dataSz > 0) {
QUADSPI_DLR = dataSz-1;
}
/* Configure QSPI: CCR register with all communications parameters */
/* mode 1=1SPI, 2=2SPI, 3=4SPI */
QUADSPI_CCR = (
QUADSPI_CCR_FMODE(fmode) | /* Functional Mode */
QUADSPI_CCR_IMODE(1) | /* Instruction Mode */
QUADSPI_CCR_ADMODE(amode) | /* Address Mode */
QUADSPI_CCR_ADSIZE(adsz) | /* Address Size */
QUADSPI_CCR_ABMODE(0) | /* Alternate byte (none) */
QUADSPI_CCR_DMODE(mode) | /* Data Mode */
QUADSPI_CCR_DCYC(dummySz) | /* Dummy Cycles (between instruction and read) */
cmd /* Instruction / Command byte */
QUADSPI_CCR_FMODE(fmode) | /* Functional Mode */
QUADSPI_CCR_IMODE(1) | /* Instruction Mode - always single SPI */
QUADSPI_CCR_ADMODE(addrMode) | /* Address Mode */
QUADSPI_CCR_ADSIZE(adsz) | /* Address Size */
QUADSPI_CCR_ABMODE(altMode) | /* Alternate byte mode */
QUADSPI_CCR_ABSIZE(absz ) | /* Alternate byte size */
QUADSPI_CCR_DMODE(dataMode) | /* Data Mode */
QUADSPI_CCR_DCYC(dummySz) | /* Dummy Cycles (between instruction and read) */
cmd /* Instruction / Command byte */
);
/* Set optional alternate bytes */
if (altSz > 0) {
QUADSPI_ABR = alt;
}
/* Set command address 4 or 3 byte */
QUADSPI_AR = addr;
while (dsz > 0U) {
while (dataSz > 0U) {
if (fmode == 0) {
while ((QUADSPI_SR & QUADSPI_SR_FTF) == 0);
QUADSPI_DR = *dptr;
QUADSPI_DR = *data;
}
else {
while ((QUADSPI_SR & (QUADSPI_SR_FTF | QUADSPI_SR_TCF)) == 0);
*dptr = QUADSPI_DR;
*data = QUADSPI_DR;
}
dsz--;
dptr++;
dataSz--;
data++;
}
/* wait for transfer complete */

View File

@ -61,16 +61,21 @@ uint8_t spi_read(void);
#ifdef QSPI_FLASH
/* these are used in macro logic, so must be defines */
#define QSPI_ADDR_MODE_SPI 1
#define QSPI_ADDR_MODE_DSPI 2
#define QSPI_ADDR_MODE_QSPI 3
#define QSPI_MODE_WRITE 0
#define QSPI_MODE_READ 1
int qspi_transfer(
const uint8_t cmd, uint32_t addr, uint32_t addrSz,
const uint8_t* txData, uint32_t txSz,
uint8_t* rxData, uint32_t rxSz, uint32_t dummySz,
uint32_t mode);
/* these are used in macro logic, so must be defines */
#define QSPI_DATA_MODE_NONE 0
#define QSPI_DATA_MODE_SPI 1
#define QSPI_DATA_MODE_DSPI 2
#define QSPI_DATA_MODE_QSPI 3
int qspi_transfer(uint8_t fmode, const uint8_t cmd,
uint32_t addr, uint32_t addrSz, uint32_t addrMode,
uint32_t alt, uint32_t altSz, uint32_t altMode,
uint32_t dummySz,
uint8_t* data, uint32_t dataSz, uint32_t dataMode
);
#endif /* QSPI_FLASH */
#endif /* SPI_FLASH || QSPI_FLASH */

View File

@ -52,9 +52,10 @@
#endif
#define FLASH_NUM_SECTORS (FLASH_DEVICE_SIZE/FLASH_SECTOR_SIZE)
/* QSPI Configuration - Use single/dual/quad mode for data transfers */
#ifndef QSPI_ADDR_MODE
#define QSPI_ADDR_MODE QSPI_ADDR_MODE_SPI
#ifndef QSPI_DATA_MODE
#define QSPI_DATA_MODE QSPI_DATA_MODE_SPI
#endif
#ifndef QSPI_ADDR_SZ
#define QSPI_ADDR_SZ 3
@ -63,7 +64,7 @@
#define QSPI_DUMMY_READ 8 /* Number of dummy clock cycles for reads */
#endif
#ifndef QSPI_FLASH_READY_TRIES
#define QSPI_FLASH_READY_TRIES 1000
#define QSPI_FLASH_READY_TRIES 5000
#endif
@ -84,7 +85,7 @@
#define FAST_READ_CMD 0x0BU
#define DUAL_READ_CMD 0x3BU
#define QUAD_READ_CMD 0x6BU
#define QUAD_READ_CMD 0xEBU
#define FAST_READ_4B_CMD 0x0CU
#define DUAL_READ_4B_CMD 0x3CU
#define QUAD_READ_4B_CMD 0x6CU
@ -108,29 +109,37 @@
#define FLASH_SR2_QE 0x02 /* 1=Quad Enable (QE) */
/* Read Command */
#if QSPI_ADDR_MODE == QSPI_ADDR_MODE_QSPI && QSPI_ADDR_SZ == 4
#if QSPI_DATA_MODE == QSPI_DATA_MODE_QSPI && QSPI_ADDR_SZ == 4
#define FLASH_READ_CMD QUAD_READ_4B_CMD
#elif QSPI_ADDR_MODE == QSPI_ADDR_MODE_DSPI && QSPI_ADDR_SZ == 4
#elif QSPI_DATA_MODE == QSPI_DATA_MODE_DSPI && QSPI_ADDR_SZ == 4
#define FLASH_READ_CMD DUAL_READ_4B_CMD
#elif QSPI_ADDR_SZ == 4
#define FLASH_READ_CMD FAST_READ_4B_CMD
#elif QSPI_ADDR_MODE == QSPI_ADDR_MODE_QSPI
#elif QSPI_DATA_MODE == QSPI_DATA_MODE_QSPI
#define FLASH_READ_CMD QUAD_READ_CMD
#elif QSPI_ADDR_MODE == QSPI_ADDR_MODE_DSPI
#undef QSPI_DUMMY_READ
#define QSPI_DUMMY_READ 4
#define QSPI_ADDR_MODE QSPI_DATA_MODE_QSPI
#elif QSPI_DATA_MODE == QSPI_DATA_MODE_DSPI
#define FLASH_READ_CMD DUAL_READ_CMD
#else
#define FLASH_READ_CMD FAST_READ_CMD
#endif
/* Write Command */
#if QSPI_ADDR_MODE == QSPI_ADDR_MODE_QSPI
#if QSPI_DATA_MODE == QSPI_DATA_MODE_QSPI
#define FLASH_WRITE_CMD QUAD_PROG_CMD
#elif QSPI_ADDR_MODE == QSPI_ADDR_MODE_DSPI
#elif QSPI_DATA_MODE == QSPI_DATA_MODE_DSPI
#define FLASH_WRITE_CMD DUAL_PROG_CMD
#else
#define FLASH_WRITE_CMD PAGE_PROG_CMD
#endif
/* default to single SPI mode for address */
#ifndef QSPI_ADDR_MODE
#define QSPI_ADDR_MODE QSPI_DATA_MODE_SPI
#endif
/* forward declarations */
static int qspi_wait_ready(void);
@ -139,6 +148,21 @@ static int qspi_status(uint8_t* status);
static int test_flash(void);
#endif
static inline int qspi_command_simple(uint8_t fmode, uint8_t cmd,
uint8_t* data, uint32_t dataSz)
{
uint32_t dmode = QSPI_DATA_MODE_NONE;
if (dataSz > 0) {
dmode = QSPI_DATA_MODE_SPI;
}
return qspi_transfer(fmode, cmd,
0, 0, QSPI_DATA_MODE_NONE, /* Address */
0, 0, QSPI_DATA_MODE_NONE, /* Alternate Bytes */
0, /* Dummy Cycles */
data, dataSz, dmode /* Data */
);
}
static int qspi_flash_read_id(uint8_t* id, uint32_t idSz)
{
int ret;
@ -146,12 +170,11 @@ static int qspi_flash_read_id(uint8_t* id, uint32_t idSz)
uint32_t status = 0;
memset(data, 0, sizeof(data));
ret = qspi_transfer(READ_ID_CMD, 0, 0, NULL, 0, data, 3, 0,
QSPI_ADDR_MODE_SPI);
qspi_status((uint8_t*)&status);
ret = qspi_command_simple(QSPI_MODE_READ, READ_ID_CMD, data, 3);
#ifdef DEBUG_QSPI
wolfBoot_printf("Flash ID (ret %d): 0x%x, status %x\n",
ret, *((uint32_t*)data), status);
wolfBoot_printf("Flash ID (ret %d): 0x%x\n",
ret, *((uint32_t*)data));
#endif
/* optionally return id data */
@ -171,8 +194,7 @@ static int qspi_write_enable(void)
uint8_t status = 0;
/* send write enable */
ret = qspi_transfer(WRITE_ENABLE_CMD, 0, 0, NULL, 0, NULL, 0, 0,
QSPI_ADDR_MODE_SPI);
ret = qspi_command_simple(QSPI_MODE_WRITE, WRITE_ENABLE_CMD, NULL, 0);
#if defined(DEBUG_QSPI) && DEBUG_QSPI > 1
wolfBoot_printf("Write Enable: Ret %d\n", ret);
#endif
@ -203,8 +225,7 @@ static int qspi_write_enable(void)
static int qspi_write_disable(void)
{
int ret = qspi_transfer(WRITE_DISABLE_CMD, 0, 0, NULL, 0, NULL, 0, 0,
QSPI_ADDR_MODE_SPI);
int ret = qspi_command_simple(QSPI_MODE_WRITE, WRITE_DISABLE_CMD, NULL, 0);
#if defined(DEBUG_QSPI) && DEBUG_QSPI > 1
wolfBoot_printf("Write Disable: Ret %d\n", ret);
#endif
@ -220,8 +241,7 @@ static int qspi_status(uint8_t* status)
#endif
memset(data, 0, sizeof(data));
ret = qspi_transfer(READ_SR_CMD, 0, 0, NULL, 0, data, 1, 0,
QSPI_ADDR_MODE_SPI);
ret = qspi_command_simple(QSPI_MODE_READ, READ_SR_CMD, data, 1);
#if defined(DEBUG_QSPI) && DEBUG_QSPI > 1
if (status == NULL || last_status != data[0]) {
wolfBoot_printf("Status (ret %d): %02x -> %02x\n",
@ -255,25 +275,24 @@ static int qspi_wait_ready(void)
return -1;
}
#if QSPI_ADDR_MODE == QSPI_ADDR_MODE_QSPI
#if QSPI_DATA_MODE == QSPI_DATA_MODE_QSPI
static int qspi_quad_enable(void)
{
int ret;
uint8_t data[4]; /* size multiple of uint32_t */
memset(data, 0, sizeof(data));
ret = qspi_transfer(READ_SR2_CMD, 0, 0, NULL, 0, data, 1, 0,
QSPI_ADDR_MODE_SPI);
ret = qspi_command_simple(QSPI_MODE_READ, READ_SR2_CMD, data, 1);
#ifdef DEBUG_QSPI
wolfBoot_printf("Status Reg 2: Ret %d, 0x%x\n", ret, data[0]);
wolfBoot_printf("Status Reg 2: Ret %d, 0x%x (Quad Enabled: %s)\n",
ret, data[0], (data[0] & FLASH_SR2_QE) ? "Yes" : "No");
#endif
if (ret == 0 && (data[0] & FLASH_SR2_QE) == 0) {
ret = qspi_write_enable();
if (ret == 0) {
memset(data, 0, sizeof(data));
data[0] |= FLASH_SR2_QE;
ret = qspi_transfer(WRITE_SR2_CMD, 0, 0, data, 1, NULL, 0, 0,
QSPI_ADDR_MODE_SPI);
ret = qspi_command_simple(QSPI_MODE_WRITE, WRITE_SR2_CMD, data, 1);
#ifdef DEBUG_QSPI
wolfBoot_printf("Setting Quad Enable: Ret %d, SR2 0x%x\n",
ret, data[0]);
@ -292,8 +311,7 @@ static int qspi_enter_4byte_addr(void)
{
int ret = qspi_write_enable();
if (ret == 0) {
ret = qspi_transfer(ENTER_4B_ADDR_MODE_CMD, 0, 0,
NULL, 0, NULL, 0, 0, QSPI_ADDR_MODE_SPI);
ret = qspi_command_simple(QSPI_MODE_WRITE, ENTER_4B_ADDR_MODE_CMD, NULL, 0);
#ifdef DEBUG_QSPI
wolfBoot_printf("Enter 4-byte address mode: Ret %d\n", ret);
#endif
@ -308,8 +326,7 @@ static int qspi_exit_4byte_addr(void)
{
int ret = qspi_write_enable();
if (ret == 0) {
ret = qspi_transfer(EXIT_4B_ADDR_MODE_CMD, 0, 0,
NULL, 0, NULL, 0, 0, QSPI_ADDR_MODE_SPI);
ret = qspi_command_simple(QSPI_MODE_WRITE, EXIT_4B_ADDR_MODE_CMD, NULL, 0);
#ifdef DEBUG_QSPI
wolfBoot_printf("Enter 4-byte address mode: Ret %d\n", ret);
#endif
@ -328,7 +345,7 @@ uint16_t spi_flash_probe(void)
spi_init(0,0);
qspi_flash_read_id(NULL, 0);
#if QSPI_ADDR_MODE == QSPI_ADDR_MODE_QSPI
#if QSPI_DATA_MODE == QSPI_DATA_MODE_QSPI
qspi_quad_enable();
#endif
#if QSPI_ADDR_SZ == 4
@ -351,8 +368,12 @@ int spi_flash_sector_erase(uint32_t address)
ret = qspi_write_enable();
if (ret == 0) {
/* ------ Erase Flash ------ */
ret = qspi_transfer(SEC_ERASE_CMD, address, QSPI_ADDR_SZ,
NULL, 0, NULL, 0, 0, QSPI_ADDR_MODE_SPI);
ret = qspi_transfer(QSPI_MODE_WRITE, SEC_ERASE_CMD,
address, QSPI_ADDR_SZ, QSPI_DATA_MODE_SPI, /* Address */
0, 0, QSPI_DATA_MODE_NONE, /* Alternate Bytes */
0, /* Dummy */
NULL, 0, QSPI_DATA_MODE_NONE /* Data */
);
#ifdef DEBUG_QSPI
wolfBoot_printf("Flash Erase: Ret %d, Address 0x%x\n", ret, address);
#endif
@ -367,6 +388,15 @@ int spi_flash_sector_erase(uint32_t address)
int spi_flash_read(uint32_t address, void *data, int len)
{
int ret;
#if QSPI_DATA_MODE == QSPI_DATA_MODE_QSPI
const uint32_t altByte = 0xF0; /* enable continuous read */
uint32_t altSz = 1;
uint32_t altMode = QSPI_ADDR_MODE;
#else
const uint32_t altByte = 0x00;
uint32_t altSz = 0;
uint32_t altMode = QSPI_DATA_MODE_NONE;
#endif
if (address > FLASH_DEVICE_SIZE) {
#ifdef DEBUG_QSPI
@ -377,8 +407,13 @@ int spi_flash_read(uint32_t address, void *data, int len)
}
/* ------ Read Flash ------ */
ret = qspi_transfer(FLASH_READ_CMD, address, QSPI_ADDR_SZ,
NULL, 0, data, len, QSPI_DUMMY_READ, QSPI_ADDR_MODE);
ret = qspi_transfer(QSPI_MODE_READ, FLASH_READ_CMD,
address, QSPI_ADDR_SZ, QSPI_ADDR_MODE, /* Address */
altByte, altSz, altMode, /* Alternate Bytes */
QSPI_DUMMY_READ, /* Dummy */
data, len, QSPI_DATA_MODE /* Data */
);
#ifdef DEBUG_QSPI
wolfBoot_printf("Flash Read: Ret %d, Address 0x%x, Len %d, Cmd 0x%x\n",
ret, address, len, FLASH_READ_CMD);
@ -405,11 +440,15 @@ int spi_flash_write(uint32_t address, const void *data, int len)
addr = address + (page * FLASH_PAGE_SIZE);
/* ------ Write Flash (page at a time) ------ */
ret = qspi_transfer(FLASH_WRITE_CMD, addr, QSPI_ADDR_SZ,
(const uint8_t*)(data + (page * FLASH_PAGE_SIZE)), xferSz,
NULL, 0, 0, QSPI_ADDR_MODE);
ret = qspi_transfer(QSPI_MODE_WRITE, FLASH_WRITE_CMD,
addr, QSPI_ADDR_SZ, QSPI_DATA_MODE_SPI, /* Address */
0, 0, QSPI_DATA_MODE_NONE, /* Alternate Bytes */
0, /* Dummy */
(uint8_t*)(data + (page * FLASH_PAGE_SIZE)),
xferSz, QSPI_DATA_MODE /* Data */
);
#ifdef DEBUG_QSPI
wolfBoot_printf("Flash Write: Ret %d, Address 0x%x, Len %d, Cmd 0x%x\n",
wolfBoot_printf("Flash Write: Ret %d, Addr 0x%x, Len %d, Cmd 0x%x\n",
ret, addr, xferSz, FLASH_WRITE_CMD);
#endif
if (ret != 0)
@ -441,7 +480,9 @@ void spi_flash_release(void)
#ifdef TEST_FLASH
#define TEST_ADDRESS (2 * 1024 * 1024) /* 2MB */
/* Start Address for test - 2MB */
#define TEST_ADDRESS (2 * 1024 * 1024)
static int test_flash(void)
{
int ret;