diff --git a/hal/spi/spi_drv_stm32.c b/hal/spi/spi_drv_stm32.c index 31966a59..bef8de92 100644 --- a/hal/spi/spi_drv_stm32.c +++ b/hal/spi/spi_drv_stm32.c @@ -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 */ diff --git a/include/spi_drv.h b/include/spi_drv.h index d6e453e6..50d5aeae 100644 --- a/include/spi_drv.h +++ b/include/spi_drv.h @@ -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 */ diff --git a/src/qspi_flash.c b/src/qspi_flash.c index c209f54a..b004fd82 100644 --- a/src/qspi_flash.c +++ b/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;