mirror of https://github.com/wolfSSL/wolfBoot.git
QSPI Flash tests passing in single SPI mode (working on Quad mode).
``` wolfBoot Init Flash ID (ret 0): 0x1870EF, status 0 Erase Sector: Ret 0 Flash Write: Ret 0, Address 0x200000, Page 0, Len 256 Write Page: Ret 0 Flash Read: Ret 0, Address 0x200000, Len 256, Cmd 0xB Read Page: Ret 0 Checking... Flash Test Passed ```pull/264/head
parent
26bed3e893
commit
5331f5ee23
|
@ -248,7 +248,7 @@ int qspi_transfer(
|
|||
|
||||
while (dsz > 0U) {
|
||||
if (fmode == 0) {
|
||||
while ((QUADSPI_SR & QUADSPI_SR_FTF));
|
||||
while ((QUADSPI_SR & QUADSPI_SR_FTF) == 0);
|
||||
QUADSPI_DR = *dptr;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -60,11 +60,11 @@ uint8_t spi_read(void);
|
|||
|
||||
|
||||
#ifdef QSPI_FLASH
|
||||
enum QSPIMode {
|
||||
QSPI_ADDR_MODE_SPI = 1,
|
||||
QSPI_ADDR_MODE_DSPI = 2,
|
||||
QSPI_ADDR_MODE_QSPI = 3,
|
||||
};
|
||||
|
||||
/* 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
|
||||
|
||||
int qspi_transfer(
|
||||
const uint8_t cmd, uint32_t addr, uint32_t addrSz,
|
||||
|
|
125
src/qspi_flash.c
125
src/qspi_flash.c
|
@ -32,7 +32,7 @@
|
|||
#include "printf.h"
|
||||
|
||||
#ifdef DEBUG_UART
|
||||
#define DEBUG_QSPI
|
||||
#define DEBUG_QSPI 1
|
||||
#endif
|
||||
|
||||
/* Flash Parameters:
|
||||
|
@ -42,19 +42,19 @@
|
|||
#define FLASH_DEVICE_SIZE (16 * 1024 * 1024)
|
||||
#endif
|
||||
#ifndef FLASH_PAGE_SIZE
|
||||
#define FLASH_PAGE_SIZE 256
|
||||
#define FLASH_PAGE_SIZE SPI_FLASH_PAGE_SIZE
|
||||
#endif
|
||||
#ifndef FLASH_NUM_PAGES
|
||||
#define FLASH_NUM_PAGES 0x10000
|
||||
#define FLASH_NUM_PAGES (FLASH_DEVICE_SIZE/FLASH_PAGE_SIZE)
|
||||
#endif
|
||||
#ifndef FLASH_SECTOR_SIZE
|
||||
#define FLASH_SECTOR_SIZE WOLFBOOT_SECTOR_SIZE
|
||||
#define FLASH_SECTOR_SIZE SPI_FLASH_SECTOR_SIZE
|
||||
#endif
|
||||
#define FLASH_NUM_SECTORS (FLASH_DEVICE_SIZE/FLASH_SECTOR_SIZE)
|
||||
|
||||
/* QSPI Configuration */
|
||||
#ifndef QSPI_ADDR_MODE
|
||||
#define QSPI_ADDR_MODE QSPI_ADDR_MODE_QSPI
|
||||
#define QSPI_ADDR_MODE QSPI_ADDR_MODE_SPI
|
||||
#endif
|
||||
#ifndef QSPI_ADDR_SZ
|
||||
#define QSPI_ADDR_SZ 3
|
||||
|
@ -70,6 +70,9 @@
|
|||
/* Flash Commands */
|
||||
#define WRITE_ENABLE_CMD 0x06U
|
||||
#define READ_SR_CMD 0x05U
|
||||
#define READ_SR2_CMD 0x35U
|
||||
#define WRITE_SR_CMD 0x01U
|
||||
#define WRITE_SR2_CMD 0x31U
|
||||
#define WRITE_DISABLE_CMD 0x04U
|
||||
#define READ_ID_CMD 0x9FU
|
||||
|
||||
|
@ -81,14 +84,15 @@
|
|||
|
||||
#define FAST_READ_CMD 0x0BU
|
||||
#define DUAL_READ_CMD 0x3BU
|
||||
#define QUAD_READ_CMD 0xEBU
|
||||
#define QUAD_READ_CMD 0x6BU
|
||||
#define FAST_READ_4B_CMD 0x0CU
|
||||
#define DUAL_READ_4B_CMD 0x3CU
|
||||
#define QUAD_READ_4B_CMD 0x6CU
|
||||
|
||||
#define PAGE_PROG_CMD 0x02U
|
||||
#define DUAL_PROG_CMD 0xA2U
|
||||
#define QUAD_PROG_CMD 0x22U
|
||||
#define QUAD_PROG_CMD 0x32U
|
||||
|
||||
#define PAGE_PROG_4B_CMD 0x12U
|
||||
#define DUAL_PROG_4B_CMD 0x12U
|
||||
#define QUAD_PROG_4B_CMD 0x34U
|
||||
|
@ -101,8 +105,11 @@
|
|||
#define FLASH_SR_WRITE_EN 0x02 /* 1=Write Enabled, 0=Write Disabled */
|
||||
#define FLASH_SR_BUSY 0x01 /* 1=Busy, 0=Ready */
|
||||
|
||||
#define FLASH_SR2_QE 0x02 /* 1=Quad Enable (QE) */
|
||||
|
||||
/* Read Command */
|
||||
#if QSPI_ADDR_MODE == QSPI_ADDR_MODE_QSPI && QSPI_ADDR_SZ == 4
|
||||
#define FLASH_READ_CMD QUAD_READ_4B_CMD
|
||||
#define FLASH_READ_CMD QUAD_READ_4B_CMD
|
||||
#elif QSPI_ADDR_MODE == QSPI_ADDR_MODE_DSPI && QSPI_ADDR_SZ == 4
|
||||
#define FLASH_READ_CMD DUAL_READ_4B_CMD
|
||||
#elif QSPI_ADDR_SZ == 4
|
||||
|
@ -115,6 +122,15 @@
|
|||
#define FLASH_READ_CMD FAST_READ_CMD
|
||||
#endif
|
||||
|
||||
/* Write Command */
|
||||
#if QSPI_ADDR_MODE == QSPI_ADDR_MODE_QSPI
|
||||
#define FLASH_WRITE_CMD QUAD_PROG_CMD
|
||||
#elif QSPI_ADDR_MODE == QSPI_ADDR_MODE_DSPI
|
||||
#define FLASH_WRITE_CMD DUAL_PROG_CMD
|
||||
#else
|
||||
#define FLASH_WRITE_CMD PAGE_PROG_CMD
|
||||
#endif
|
||||
|
||||
|
||||
/* forward declarations */
|
||||
static int qspi_wait_ready(void);
|
||||
|
@ -135,8 +151,8 @@ static int qspi_flash_read_id(uint8_t* id, uint32_t idSz)
|
|||
QSPI_ADDR_MODE_SPI);
|
||||
qspi_status((uint8_t*)&status);
|
||||
#ifdef DEBUG_QSPI
|
||||
wolfBoot_printf("Flash: Ret %d: ID: %x, Cmd %x, status %x\n",
|
||||
ret, *((uint32_t*)data), READ_ID_CMD, status);
|
||||
wolfBoot_printf("Flash ID (ret %d): 0x%x, status %x\n",
|
||||
ret, *((uint32_t*)data), status);
|
||||
#endif
|
||||
|
||||
/* optionally return id data */
|
||||
|
@ -155,14 +171,14 @@ static int qspi_write_enable(void)
|
|||
|
||||
ret = qspi_transfer(WRITE_ENABLE_CMD, 0, 0, NULL, 0, NULL, 0, 0,
|
||||
QSPI_ADDR_MODE_SPI);
|
||||
#ifdef DEBUG_QSPI
|
||||
#if defined(DEBUG_QSPI) && DEBUG_QSPI > 1
|
||||
wolfBoot_printf("Write Enable: Ret %d\n", ret);
|
||||
#endif
|
||||
|
||||
qspi_wait_ready();
|
||||
|
||||
ret = qspi_wait_we();
|
||||
#ifdef DEBUG_QSPI
|
||||
#if defined(DEBUG_QSPI) && DEBUG_QSPI > 1
|
||||
wolfBoot_printf("Write Enabled: %s\n", ret == 0 ? "yes" : "no");
|
||||
#endif
|
||||
|
||||
|
@ -173,7 +189,7 @@ static int qspi_write_disable(void)
|
|||
{
|
||||
int ret = qspi_transfer(WRITE_DISABLE_CMD, 0, 0, NULL, 0, NULL, 0, 0,
|
||||
QSPI_ADDR_MODE_SPI);
|
||||
#ifdef DEBUG_QSPI
|
||||
#if defined(DEBUG_QSPI) && DEBUG_QSPI > 1
|
||||
wolfBoot_printf("Write Disable: Ret %d\n", ret);
|
||||
#endif
|
||||
return ret;
|
||||
|
@ -183,12 +199,19 @@ static int qspi_status(uint8_t* status)
|
|||
{
|
||||
int ret;
|
||||
uint8_t data[4]; /* size multiple of uint32_t */
|
||||
#if defined(DEBUG_QSPI) && DEBUG_QSPI > 1
|
||||
static uint8_t last_status = 0;
|
||||
#endif
|
||||
|
||||
memset(data, 0, sizeof(data));
|
||||
ret = qspi_transfer(READ_SR_CMD, 0, 0, NULL, 0, data, 1, 0,
|
||||
QSPI_ADDR_MODE_SPI);
|
||||
#ifdef DEBUG_QSPI
|
||||
wolfBoot_printf("Status (ret %d): %02x\n", ret, data[0]);
|
||||
#if defined(DEBUG_QSPI) && DEBUG_QSPI > 1
|
||||
if (status == NULL || last_status != data[0]) {
|
||||
wolfBoot_printf("Status (ret %d): %02x -> %02x\n",
|
||||
ret, last_status, data[0]);
|
||||
}
|
||||
last_status = data[0];
|
||||
#endif
|
||||
if (ret == 0 && status) {
|
||||
*status = data[0];
|
||||
|
@ -236,6 +259,37 @@ static int qspi_wait_we(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if QSPI_ADDR_MODE == QSPI_ADDR_MODE_QSPI
|
||||
static int qspi_quad_enable(void)
|
||||
{
|
||||
int ret;
|
||||
uint8_t data[4]; /* size multiple of uint32_t */
|
||||
|
||||
ret = qspi_write_enable();
|
||||
if (ret == 0) {
|
||||
memset(data, 0, sizeof(data));
|
||||
ret = qspi_transfer(READ_SR2_CMD, 0, 0, NULL, 0, data, 1, 0,
|
||||
QSPI_ADDR_MODE_SPI);
|
||||
#ifdef DEBUG_QSPI
|
||||
wolfBoot_printf("Status Reg 2: Ret %d, 0x%x\n", ret, data[0]);
|
||||
#endif
|
||||
if (ret == 0) {
|
||||
if ((data[0] & FLASH_SR2_QE) == 0) {
|
||||
data[0] |= FLASH_SR2_QE;
|
||||
ret = qspi_transfer(WRITE_SR2_CMD, 0, 0, data, 1, NULL, 0, 0,
|
||||
QSPI_ADDR_MODE_SPI);
|
||||
#ifdef DEBUG_QSPI
|
||||
wolfBoot_printf("Setting Quad Enable: Ret %d, SR2 0x%x\n",
|
||||
ret, data[0]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
qspi_write_disable();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if QSPI_ADDR_SZ == 4
|
||||
static int qspi_enter_4byte_addr(void)
|
||||
{
|
||||
|
@ -279,6 +333,9 @@ uint16_t spi_flash_probe(void)
|
|||
spi_init(0,0);
|
||||
qspi_flash_read_id(NULL, 0);
|
||||
|
||||
#if QSPI_ADDR_MODE == QSPI_ADDR_MODE_QSPI
|
||||
qspi_quad_enable();
|
||||
#endif
|
||||
#if QSPI_ADDR_SZ == 4
|
||||
qspi_enter_4byte_addr();
|
||||
#endif
|
||||
|
@ -289,6 +346,8 @@ uint16_t spi_flash_probe(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Called for each sector from hal.h inline ext_flash_erase function
|
||||
* Use SPI_FLASH_SECTOR_SIZE to adjust for QSPI sector size */
|
||||
int spi_flash_sector_erase(uint32_t address)
|
||||
{
|
||||
int ret;
|
||||
|
@ -301,7 +360,7 @@ int spi_flash_sector_erase(uint32_t address)
|
|||
NULL, 0, NULL, 0,
|
||||
0, QSPI_ADDR_MODE_SPI);
|
||||
#ifdef DEBUG_QSPI
|
||||
wolfBoot_printf("Flash Erase: Ret %d\n", ret);
|
||||
wolfBoot_printf("Flash Erase: Ret %d, Address 0x%x\n", ret, address);
|
||||
#endif
|
||||
if (ret == 0) {
|
||||
ret = qspi_wait_ready(); /* Wait for not busy */
|
||||
|
@ -315,12 +374,21 @@ int spi_flash_read(uint32_t address, void *data, int len)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (address > FLASH_DEVICE_SIZE) {
|
||||
#ifdef DEBUG_QSPI
|
||||
wolfBoot_printf("Flash Read: Invalid address (0x%x > 0x%x max)\n",
|
||||
address, FLASH_DEVICE_SIZE);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ------ Read Flash ------ */
|
||||
ret = qspi_transfer(FLASH_READ_CMD, address, QSPI_ADDR_SZ,
|
||||
NULL, 0, data, len,
|
||||
QSPI_DUMMY_READ, QSPI_ADDR_MODE);
|
||||
#ifdef DEBUG_QSPI
|
||||
wolfBoot_printf("Flash Read: Ret %d\r\n", ret);
|
||||
wolfBoot_printf("Flash Read: Ret %d, Address 0x%x, Len %d, Cmd 0x%x\n",
|
||||
ret, address, len, FLASH_READ_CMD);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
|
@ -329,7 +397,6 @@ int spi_flash_read(uint32_t address, void *data, int len)
|
|||
int spi_flash_write(uint32_t address, const void *data, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t cmd[8]; /* size multiple of uint32_t */
|
||||
uint32_t xferSz, page, pages, idx = 0;
|
||||
uintptr_t addr;
|
||||
|
||||
|
@ -345,11 +412,12 @@ 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(PAGE_PROG_CMD, addr, QSPI_ADDR_SZ,
|
||||
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_SPI);
|
||||
NULL, 0, 0, QSPI_ADDR_MODE);
|
||||
#ifdef DEBUG_QSPI
|
||||
wolfBoot_printf("Flash Page %d Write: Ret %d\n", page, ret);
|
||||
wolfBoot_printf("Flash Write: Ret %d, Address 0x%x, Len %d, Cmd 0x%x\n",
|
||||
ret, addr, xferSz, FLASH_WRITE_CMD);
|
||||
#endif
|
||||
if (ret != 0)
|
||||
break;
|
||||
|
@ -388,31 +456,30 @@ static int test_flash(void)
|
|||
uint8_t pageData[FLASH_PAGE_SIZE];
|
||||
uint32_t wait = 0;
|
||||
|
||||
/* long wait */
|
||||
while (++wait < 1000000);
|
||||
|
||||
#ifndef TEST_FLASH_READONLY
|
||||
/* Erase sector */
|
||||
ret = ext_flash_erase(TEST_ADDRESS, WOLFBOOT_SECTOR_SIZE);
|
||||
wolfBoot_printf("Erase Sector: Ret %d\n", ret);
|
||||
ret = ext_flash_erase(TEST_ADDRESS, FLASH_SECTOR_SIZE);
|
||||
wolfBoot_printf("Sector Erase: Ret %d\n", ret);
|
||||
|
||||
/* Write Pages */
|
||||
/* Write Page */
|
||||
for (i=0; i<sizeof(pageData); i++) {
|
||||
pageData[i] = (i & 0xff);
|
||||
}
|
||||
ret = ext_flash_write(TEST_ADDRESS, pageData, sizeof(pageData));
|
||||
wolfBoot_printf("Write Page: Ret %d\n", ret);
|
||||
wolfBoot_printf("Page Write: Ret %d\n", ret);
|
||||
#endif /* !TEST_FLASH_READONLY */
|
||||
|
||||
/* Read page */
|
||||
memset(pageData, 0, sizeof(pageData));
|
||||
ret = ext_flash_read(TEST_ADDRESS, pageData, sizeof(pageData));
|
||||
wolfBoot_printf("Read Page: Ret %d\n", ret);
|
||||
wolfBoot_printf("Page Read: Ret %d\n", ret);
|
||||
|
||||
wolfBoot_printf("Checking...\n");
|
||||
/* Check data */
|
||||
for (i=0; i<sizeof(pageData); i++) {
|
||||
#if defined(DEBUG_QSPI) && DEBUG_QSPI > 1
|
||||
wolfBoot_printf("check[%3d] %02x\n", i, pageData[i]);
|
||||
#endif
|
||||
if (pageData[i] != (i & 0xff)) {
|
||||
wolfBoot_printf("Check Data @ %d failed\n", i);
|
||||
return -1;
|
||||
|
|
Loading…
Reference in New Issue