mirror of https://github.com/wolfSSL/wolfBoot.git
Fixes for QSPI read. Adds alternate byte support. Cleanup of simple QSPI read/write.
parent
c3cf21a81f
commit
8d7d4d4f74
|
@ -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_IMODE(1) | /* Instruction Mode - always single SPI */
|
||||
QUADSPI_CCR_ADMODE(addrMode) | /* Address Mode */
|
||||
QUADSPI_CCR_ADSIZE(adsz) | /* Address Size */
|
||||
QUADSPI_CCR_ABMODE(0) | /* Alternate byte (none) */
|
||||
QUADSPI_CCR_DMODE(mode) | /* Data Mode */
|
||||
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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
123
src/qspi_flash.c
123
src/qspi_flash.c
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue