ST25FL1: Flesh out FLASH write logic

This commit is contained in:
Gregory Nutt
2015-08-28 12:01:08 -06:00
parent e392471dc2
commit 4a1951b192
2 changed files with 157 additions and 26 deletions
+11
View File
@@ -405,6 +405,17 @@ config ST25FL1_SECTOR512
bool "Simulate 512 byte Erase Blocks" bool "Simulate 512 byte Erase Blocks"
default n default n
config ST25FL1_SCRAMBLE
bool "Scramble data"
default n
---help---
Requires drviver support for data scrambling/descrambling.
config ST25FL1_SCRAMBLE_KEY
hex "Scramble key"
default 0x0baddead
depends on ST25FL1_SCRAMBLE
endif endif
config MTD_SMART config MTD_SMART
+146 -26
View File
@@ -333,15 +333,15 @@ static int st25fl1_readid(FAR struct st25fl1_dev_s *priv);
static void st25fl1_unprotect(FAR struct st25fl1_dev_s *priv); static void st25fl1_unprotect(FAR struct st25fl1_dev_s *priv);
static int st25fl1_erase_sector(FAR struct st25fl1_dev_s *priv, off_t offset); static int st25fl1_erase_sector(FAR struct st25fl1_dev_s *priv, off_t offset);
static int st25fl1_erase_chip(FAR struct st25fl1_dev_s *priv); static int st25fl1_erase_chip(FAR struct st25fl1_dev_s *priv);
static void st25fl1_read_byte(FAR struct st25fl1_dev_s *priv, FAR uint8_t *buffer, static int st25fl1_read_byte(FAR struct st25fl1_dev_s *priv, FAR uint8_t *buffer,
off_t address, size_t nbytes); off_t address, size_t nbytes);
static void st25fl1_write_page(FAR struct st25fl1_dev_s *priv, static int st25fl1_write_page(FAR struct st25fl1_dev_s *priv,
FAR const uint8_t *buffer, off_t address, size_t nbytes); FAR const uint8_t *buffer, off_t address, size_t nbytes);
#ifdef CONFIG_ST25FL1_SECTOR512 #ifdef CONFIG_ST25FL1_SECTOR512
static void st25fl1_flush_cache(struct st25fl1_dev_s *priv); static int st25fl1_flush_cache(struct st25fl1_dev_s *priv);
static FAR uint8_t *st25fl1_read_cache(struct st25fl1_dev_s *priv, off_t sector); static FAR uint8_t *st25fl1_read_cache(struct st25fl1_dev_s *priv, off_t sector);
static void st25fl1_erase_cache(struct st25fl1_dev_s *priv, off_t sector); static void st25fl1_erase_cache(struct st25fl1_dev_s *priv, off_t sector);
static void st25fl1_write_cache(FAR struct st25fl1_dev_s *priv, static int st25fl1_write_cache(FAR struct st25fl1_dev_s *priv,
FAR const uint8_t *buffer, off_t sector, size_t nsectors); FAR const uint8_t *buffer, off_t sector, size_t nsectors);
#endif #endif
@@ -722,22 +722,98 @@ static int st25fl1_erase_chip(struct st25fl1_dev_s *priv)
* Name: st25fl1_read_byte * Name: st25fl1_read_byte
************************************************************************************/ ************************************************************************************/
static void st25fl1_read_byte(FAR struct st25fl1_dev_s *priv, FAR uint8_t *buffer, static int st25fl1_read_byte(FAR struct st25fl1_dev_s *priv, FAR uint8_t *buffer,
off_t address, size_t nbytes) off_t address, size_t buflen)
{ {
struct qspi_meminfo_s meminfo;
fvdbg("address: %08lx nbytes: %d\n", (long)address, (int)nbytes); fvdbg("address: %08lx nbytes: %d\n", (long)address, (int)nbytes);
#warning Missing Logic
#ifdef CONFIG_ST25FL1_SCRAMBLE
meminfo.flags = QSPIMEM_READ | QSPIMEM_QUADIO | QSPIMEM_SCRAMBLE;
#else
meminfo.flags = QSPIMEM_READ | QSPIMEM_QUADIO;
#endif
meminfo.addrlen = 3;
meminfo.dummies = 6;
meminfo.buflen = buflen;
meminfo.cmd = ST25FL1_FAST_READ_QUADIO;
meminfo.addr = address;
#ifdef CONFIG_ST25FL1_SCRAMBLE
meminfo.key = CONFIG_ST25FL1_SCRAMBLE_KEY;
#endif
meminfo.buffer = buffer;
return QSPI_MEMORY(priv->qspi, &meminfo);
} }
/************************************************************************************ /************************************************************************************
* Name: st25fl1_write_page * Name: st25fl1_write_page
************************************************************************************/ ************************************************************************************/
static void st25fl1_write_page(struct st25fl1_dev_s *priv, FAR const uint8_t *buffer, static int st25fl1_write_page(struct st25fl1_dev_s *priv, FAR const uint8_t *buffer,
off_t address, size_t nbytes) off_t address, size_t buflen)
{ {
fvdbg("address: %08lx nwords: %d\n", (long)address, (int)nbytes); struct qspi_meminfo_s meminfo;
#warning Missing Logic unsigned int pagesize;
unsigned int npages;
int ret;
int i;
fvdbg("address: %08lx buflen: %u\n", (unsigned long)address, (unsigned)buflen);
npages = (buflen >> priv->pageshift);
pagesize = (1 << priv->pageshift);
/* Set up non-varying parts of transfer description */
#ifdef CONFIG_ST25FL1_SCRAMBLE
meminfo.flags = QSPIMEM_WRITE | QSPIMEM_SCRAMBLE;
#else
meminfo.flags = QSPIMEM_WRITE;
#endif
meminfo.cmd = ST25FL1_PAGE_PROGRAM;
meminfo.addrlen = 3;
meminfo.buflen = pagesize;
#ifdef CONFIG_ST25FL1_SCRAMBLE
meminfo.key = CONFIG_ST25FL1_SCRAMBLE_KEY;
#endif
meminfo.dummies = 0;
/* Then write each page */
for (i = 0; i < npages; i++)
{
/* Set up varying parts of the transfer description */
meminfo.addr = address;
meminfo.buffer = (void *)buffer;
/* Write one page */
st25fl1_write_enable(priv->qspi);
ret = QSPI_MEMORY(priv->qspi, &meminfo);
if (ret < 0)
{
fdbg("ERROR: QSPI_MEMORY failed writing address=%06x\n",
address)
return ret;
}
/* Update for the next time through the loop */
buffer += pagesize;
address += pagesize;
buflen -= pagesize;
}
/* The transfer should always be an even number of sectors and hence also
* pages. There should be no remainder.
*/
DEBUGASSERT(buflen == 0);
st25fl1_write_disable(priv->qspi);
return OK;
} }
/************************************************************************************ /************************************************************************************
@@ -745,7 +821,7 @@ static void st25fl1_write_page(struct st25fl1_dev_s *priv, FAR const uint8_t *bu
************************************************************************************/ ************************************************************************************/
#ifdef CONFIG_ST25FL1_SECTOR512 #ifdef CONFIG_ST25FL1_SECTOR512
static void st25fl1_flush_cache(struct st25fl1_dev_s *priv) static int st25fl1_flush_cache(struct st25fl1_dev_s *priv)
{ {
/* If the cached is dirty (meaning that it no longer matches the old FLASH contents) /* If the cached is dirty (meaning that it no longer matches the old FLASH contents)
* or was erased (with the cache containing the correct FLASH contents), then write * or was erased (with the cache containing the correct FLASH contents), then write
@@ -762,6 +838,8 @@ static void st25fl1_flush_cache(struct st25fl1_dev_s *priv)
CLR_DIRTY(priv); CLR_DIRTY(priv);
CLR_ERASED(priv); CLR_ERASED(priv);
} }
return OK;
} }
#endif #endif
@@ -775,6 +853,7 @@ static FAR uint8_t *st25fl1_read_cache(struct st25fl1_dev_s *priv, off_t sector)
off_t esectno; off_t esectno;
int shift; int shift;
int index; int index;
int ret;
/* Convert from the 512 byte sector to the erase sector size of the device. For /* Convert from the 512 byte sector to the erase sector size of the device. For
* exmample, if the actual erase sector size if 4Kb (1 << 12), then we first * exmample, if the actual erase sector size if 4Kb (1 << 12), then we first
@@ -791,12 +870,23 @@ static FAR uint8_t *st25fl1_read_cache(struct st25fl1_dev_s *priv, off_t sector)
{ {
/* No.. Flush any dirty erase block currently in the cache */ /* No.. Flush any dirty erase block currently in the cache */
st25fl1_flush_cache(priv); ret = st25fl1_flush_cache(priv);
if (ret < 0)
{
fdbg("ERROR: st25fl1_flush_cache failed: %d\n", ret);
return NULL;
}
/* Read the erase block into the cache */ /* Read the erase block into the cache */
st25fl1_read_byte(priv, priv->sector, (esectno << priv->sectorshift) ret = st25fl1_read_byte(priv, priv->sector,
(1 << priv->sectorshift)); (esectno << priv->sectorshift)
(1 << priv->sectorshift));
if (ret < 0)
{
fdbg("ERROR: st25fl1_read_byte failed: %d\n", ret);
return NULL;
}
/* Mark the sector as cached */ /* Mark the sector as cached */
@@ -861,10 +951,12 @@ static void st25fl1_erase_cache(struct st25fl1_dev_s *priv, off_t sector)
************************************************************************************/ ************************************************************************************/
#ifdef CONFIG_ST25FL1_SECTOR512 #ifdef CONFIG_ST25FL1_SECTOR512
static void st25fl1_write_cache(FAR struct st25fl1_dev_s *priv, FAR const uint8_t *buffer, static int st25fl1_write_cache(FAR struct st25fl1_dev_s *priv,
off_t sector, size_t nsectors) FAR const uint8_t *buffer, off_t sector,
size_t nsectors)
{ {
FAR uint8_t *dest; FAR uint8_t *dest;
int ret;
for (; nsectors > 0; nsectors--) for (; nsectors > 0; nsectors--)
{ {
@@ -884,7 +976,13 @@ static void st25fl1_write_cache(FAR struct st25fl1_dev_s *priv, FAR const uint8_
off_t esectno = sector >> (priv->sectorshift - ST25FL1_SECTOR512_SHIFT); off_t esectno = sector >> (priv->sectorshift - ST25FL1_SECTOR512_SHIFT);
fvdbg("sector: %ld esectno: %d\n", sector, esectno); fvdbg("sector: %ld esectno: %d\n", sector, esectno);
DEBUGVERIFY(st25fl1_erase_sector(priv, esectno)); ret = st25fl1_erase_sector(priv, esectno);
if (ret < 0)
{
fdbg("ERROR: st25fl1_erase_sector failed: %d\n", ret);
return ret;
}
SET_ERASED(priv); SET_ERASED(priv);
} }
@@ -901,7 +999,7 @@ static void st25fl1_write_cache(FAR struct st25fl1_dev_s *priv, FAR const uint8_
/* Flush the last erase block left in the cache */ /* Flush the last erase block left in the cache */
st25fl1_flush_cache(priv); return st25fl1_flush_cache(priv);
} }
#endif #endif
@@ -935,7 +1033,11 @@ static int st25fl1_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nbl
#ifdef CONFIG_S25FL1_SECTOR512 #ifdef CONFIG_S25FL1_SECTOR512
/* Flush the last erase block left in the cache */ /* Flush the last erase block left in the cache */
st25fl1_flush_cache(priv); ret = st25fl1_flush_cache(priv);
if (ret < 0)
{
nblocks = ret;
}
#endif #endif
st25fl1_unlock(priv->qspi); st25fl1_unlock(priv->qspi);
@@ -983,6 +1085,7 @@ static ssize_t st25fl1_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, FAR const uint8_t *buffer) size_t nblocks, FAR const uint8_t *buffer)
{ {
FAR struct st25fl1_dev_s *priv = (FAR struct st25fl1_dev_s *)dev; FAR struct st25fl1_dev_s *priv = (FAR struct st25fl1_dev_s *)dev;
int ret = (int)nblocks;
fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
@@ -991,14 +1094,24 @@ static ssize_t st25fl1_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
st25fl1_lock(priv->qspi); st25fl1_lock(priv->qspi);
#if defined(CONFIG_ST25FL1_SECTOR512) #if defined(CONFIG_ST25FL1_SECTOR512)
st25fl1_write_cache(priv, buffer, startblock, nblocks); ret = st25fl1_write_cache(priv, buffer, startblock, nblocks);
if (ret < 0)
{
fdbg("ERROR: st25fl1_write_cache failed: %d\n", ret);
}
#else #else
st25fl1_write_page(priv, buffer, startblock << priv->sectorshift, ret = st25fl1_write_page(priv, buffer, startblock << priv->sectorshift,
nblocks << priv->sectorshift); nblocks << priv->sectorshift);
if (ret < 0)
{
fdbg("ERROR: st25fl1_write_page failed: %d\n", ret);
}
#endif #endif
st25fl1_unlock(priv->qspi); st25fl1_unlock(priv->qspi);
return nblocks; return ret;
} }
/************************************************************************************ /************************************************************************************
@@ -1009,17 +1122,24 @@ static ssize_t st25fl1_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbyt
FAR uint8_t *buffer) FAR uint8_t *buffer)
{ {
FAR struct st25fl1_dev_s *priv = (FAR struct st25fl1_dev_s *)dev; FAR struct st25fl1_dev_s *priv = (FAR struct st25fl1_dev_s *)dev;
int ret;
fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes); fvdbg("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes);
/* Lock the QuadSPI bus and select this FLASH part */ /* Lock the QuadSPI bus and select this FLASH part */
st25fl1_lock(priv->qspi); st25fl1_lock(priv->qspi);
st25fl1_read_byte(priv, buffer, offset, nbytes); ret = st25fl1_read_byte(priv, buffer, offset, nbytes);
st25fl1_unlock(priv->qspi); st25fl1_unlock(priv->qspi);
if (ret < 0)
{
fdbg("ERROR: st25fl1_read_byte returned: %d\n", ret);
return (ssize_t)ret;
}
fvdbg("return nbytes: %d\n", (int)nbytes); fvdbg("return nbytes: %d\n", (int)nbytes);
return nbytes; return (ssize_t)nbytes;
} }
/************************************************************************************ /************************************************************************************