ST25FL1 driver is code complete

This commit is contained in:
Gregory Nutt 2015-08-29 15:58:54 -06:00
parent bfc3c98e12
commit d6b0a8fe72
4 changed files with 212 additions and 27 deletions

View File

@ -10900,4 +10900,6 @@
locked down (2015-08-27).
* drivers/lcd and include/nuttx/lcd: Add SSD1351 OLED controller
support. Contributed by Paul Alexander Patience (2015-08-28).
* include/nuttx/mtd/mtd.h: Move MTD ioctl command definitions from
include/nuttx/fs/fs.h to include/nuttx/mtd.h. Add ioctl commands
to protect and unprotect memory (2015-08-29).

2
arch

@ -1 +1 @@
Subproject commit a26ed33fa4c164564b45b4f0905887fcf553f425
Subproject commit 7678d3b41e8c697ac6d59154ed48135f12a14208

View File

@ -330,7 +330,12 @@ static void st25fl1_write_enable(FAR struct qspi_dev_s *qspi);
static void st25fl1_write_disable(FAR struct qspi_dev_s *qspi);
static int st25fl1_readid(FAR struct st25fl1_dev_s *priv);
static void st25fl1_unprotect(FAR struct st25fl1_dev_s *priv);
static int st25fl1_protect(FAR struct st25fl1_dev_s *priv,
off_t startblock, size_t nblocks);
static int st25fl1_unprotect(FAR struct st25fl1_dev_s *priv,
off_t startblock, size_t nblocks);
static bool st25fl1_isprotected(FAR struct st25fl1_dev_s *priv,
uint8_t status, off_t address);
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_read_byte(FAR struct st25fl1_dev_s *priv, FAR uint8_t *buffer,
@ -629,13 +634,171 @@ static inline int st25fl1_readid(struct st25fl1_dev_s *priv)
return OK;
}
/************************************************************************************
* Name: st25fl1_protect
************************************************************************************/
static int st25fl1_protect(FAR struct st25fl1_dev_s *priv,
off_t startblock, size_t nblocks)
{
unsigned char status[3];
/* Get the status register value to check the current protection */
status[0] = sf25fl1_read_status1(priv->qspi);
status[1] = sf25fl1_read_status2(priv->qspi);
status[2] = sf25fl1_read_status3(priv->qspi);
if ((status[0] & STATUS1_BP_MASK) == STATUS1_BP_NONE)
{
/* Protection already disabled */
return 0;
}
/* Check if sector protection registers are locked */
if ((status[0] & STATUS1_SRP0_MASK) == STATUS1_SRP0_LOCKED)
{
/* Yes.. unprotect section protection registers */
status[0] &= ~STATUS1_SRP0_MASK;
st25fl1_write_status(priv->qspi, status);
}
/* Set the protection mask to zero.
* REVISIT: This logic should really just set the BP bits as
* necessary to protect the range of sectors.
*/
status[0] |= STATUS1_BP_MASK;
st25fl1_write_status(priv->qspi, status);
/* Check the new status */
status[0] = sf25fl1_read_status1(priv->qspi);
if ((status[0] & STATUS1_BP_MASK) != STATUS1_BP_MASK)
{
return -EACCES;
}
return OK;
}
/************************************************************************************
* Name: st25fl1_unprotect
************************************************************************************/
static void st25fl1_unprotect(FAR struct st25fl1_dev_s *priv)
static int st25fl1_unprotect(FAR struct st25fl1_dev_s *priv,
off_t startblock, size_t nblocks)
{
#warning Missing Logic
unsigned char status[3];
/* Get the status register value to check the current protection */
status[0] = sf25fl1_read_status1(priv->qspi);
status[1] = sf25fl1_read_status2(priv->qspi);
status[2] = sf25fl1_read_status3(priv->qspi);
if ((status[0] & STATUS1_BP_MASK) == STATUS1_BP_NONE)
{
/* Protection already disabled */
return 0;
}
/* Check if sector protection registers are locked */
if ((status[0] & STATUS1_SRP0_MASK) == STATUS1_SRP0_LOCKED)
{
/* Yes.. unprotect section protection registers */
status[0] &= ~STATUS1_SRP0_MASK;
st25fl1_write_status(priv->qspi, status);
}
/* Set the protection mask to zero.
* REVISIT: This logic should really just re-write the BP bits as
* necessary to unprotect the range of sectors.
*/
status[0] &= ~STATUS1_BP_MASK;
st25fl1_write_status(priv->qspi, status);
/* Check the new status */
status[0] = sf25fl1_read_status1(priv->qspi);
if ((status[0] & (STATUS1_SRP0_MASK | STATUS1_BP_MASK)) != 0)
{
return -EACCES;
}
return OK;
}
/************************************************************************************
* Name: st25fl1_isprotected
************************************************************************************/
static bool st25fl1_isprotected(FAR struct st25fl1_dev_s *priv, uint8_t status,
off_t address)
{
off_t protstart;
off_t protend;
off_t protsize;
unsigned int bp;
/* What is protected? 64 Kb blocks? Or 4Kb sectors? */
if ((status & STATUS1_SEC_MASK) == STATUS1_SEC_BLOCK)
{
/* 64 Kb block */
protsize = 0x00010000;
}
else
{
/* 4 Kb sector */
protsize = 0x00001000;
}
/* The BP field is the essentially a multiplier on this protection size */
bp = (status & STATUS1_BP_MASK) >> STATUS1_BP_SHIFT;
switch (bp)
{
case 0:
return false;
case 1:
break;
case 6:
case 7:
return true;
default:
protsize <<= (protsize << (bp - 1));
break;
}
/* The final protection range then depends on if the protection region is
* configured top-down or bottom up (assuming CMP=0).
*/
if ((status & STATUS1_TB_MASK) != 0)
{
protstart = 0x00000000;
protend = protstart + protsize;
}
else
{
protend = 0x00200000;
protstart = protend - protsize;
}
return (address >= protstart && address < protend);
}
/************************************************************************************
@ -645,13 +808,10 @@ static void st25fl1_unprotect(FAR struct st25fl1_dev_s *priv)
static int st25fl1_erase_sector(struct st25fl1_dev_s *priv, off_t sector)
{
off_t address;
#ifdef CONFIG_DEBUG
uint8_t status;
#endif
fvdbg("sector: %08lx\n", (unsigned long)sector);
#ifdef CONFIG_DEBUG
/* Check that the flash is ready and unprotected */
status = sf25fl1_read_status1(priv->qspi);
@ -661,18 +821,19 @@ static int st25fl1_erase_sector(struct st25fl1_dev_s *priv, off_t sector)
return -EBUSY;
}
if ((status & STATUS1_BP_MASK) != 0)
{
fdbg("ERROR: Flash protected: %02x", status);
/* REVISIT: Should check if this particular sector is protected */
//return -EACCES;
}
#endif
/* Send the sector erase command */
/* Get the address associated with the sector */
address = (off_t)sector << priv->sectorshift;
if ((status & STATUS1_BP_MASK) != 0 &&
st25fl1_isprotected(priv, status, address))
{
fdbg("ERROR: Flash protected: %02x", status);
return -EACCES;
}
/* Send the sector erase command */
st25fl1_write_enable(priv->qspi);
st25fl1_command_address(priv->qspi, ST25FL1_SECTOR_ERASE, address, 3);
@ -690,7 +851,6 @@ static int st25fl1_erase_chip(struct st25fl1_dev_s *priv)
{
uint8_t status;
#ifdef CONFIG_DEBUG
/* Check if the FLASH is protected */
status = sf25fl1_read_status1(priv->qspi);
@ -699,7 +859,6 @@ static int st25fl1_erase_chip(struct st25fl1_dev_s *priv)
fdbg("ERROR: FLASH is Protected: %02x", status);
return -EACCES;
}
#endif
/* Erase the whole chip */
@ -823,6 +982,8 @@ static int st25fl1_write_page(struct st25fl1_dev_s *priv, FAR const uint8_t *buf
#ifdef CONFIG_ST25FL1_SECTOR512
static int st25fl1_flush_cache(struct st25fl1_dev_s *priv)
{
int ret = OK;
/* 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
* the cached erase block to FLASH.
@ -831,7 +992,12 @@ static int st25fl1_flush_cache(struct st25fl1_dev_s *priv)
if (IS_DIRTY(priv) || IS_ERASED(priv))
{
/* Write entire erase block to FLASH */
#warning Missing Logic
ret = st25fl1_write_page(priv, priv->sector, 1 << priv->sectorshift);
if (ret < 0)
{
fdbg("ERROR: st25fl1_write_page failed: %d\n", ret);
}
/* The case is no long dirty and the FLASH is no longer erased */
@ -839,7 +1005,7 @@ static int st25fl1_flush_cache(struct st25fl1_dev_s *priv)
CLR_ERASED(priv);
}
return OK;
return ret;
}
#endif
@ -1198,9 +1364,28 @@ static int st25fl1_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
}
break;
case MTDIOC_XIPBASE:
case MTDIOC_PROTECT:
{
FAR const struct mtd_protect_s *prot =
(FAR const struct mtd_protect_s *)((uintptr_t)arg);
DEBUGASSERT(prot);
ret = st25fl1_protect(priv, prot->startblock, prot->nblocks);
}
break;
case MTDIOC_UNPROTECT:
{
FAR const struct mtd_protect_s *prot =
(FAR const struct mtd_protect_s *)((uintptr_t)arg);
DEBUGASSERT(prot);
ret = st25fl1_unprotect(priv, prot->startblock, prot->nblocks);
}
break;
default:
ret = -ENOTTY; /* Bad command */
ret = -ENOTTY; /* Bad/unsupported command */
break;
}
@ -1277,10 +1462,6 @@ FAR struct mtd_dev_s *st25fl1_initialize(FAR struct qspi_dev_s *qspi)
usleep(50*1000);
}
/* Make sure that the FLASH is unprotected so that we can write into it */
st25fl1_unprotect(priv);
#ifdef CONFIG_ST25FL1_SECTOR512 /* Simulate a 512 byte sector */
/* Allocate a buffer for the erase block cache */

View File

@ -46,6 +46,8 @@
#include <sys/types.h>
#include <stdint.h>
#include <nuttx/fs/ioctl.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/