mirror of
https://github.com/apache/nuttx.git
synced 2026-05-27 11:26:12 +08:00
ST25FL1 driver is code complete
This commit is contained in:
@@ -10900,4 +10900,6 @@
|
|||||||
locked down (2015-08-27).
|
locked down (2015-08-27).
|
||||||
* drivers/lcd and include/nuttx/lcd: Add SSD1351 OLED controller
|
* drivers/lcd and include/nuttx/lcd: Add SSD1351 OLED controller
|
||||||
support. Contributed by Paul Alexander Patience (2015-08-28).
|
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).
|
||||||
|
|||||||
+1
-1
Submodule arch updated: a26ed33fa4...7678d3b41e
+206
-25
@@ -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 void st25fl1_write_disable(FAR struct qspi_dev_s *qspi);
|
||||||
|
|
||||||
static int st25fl1_readid(FAR struct st25fl1_dev_s *priv);
|
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_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 int 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,
|
||||||
@@ -629,13 +634,171 @@ static inline int st25fl1_readid(struct st25fl1_dev_s *priv)
|
|||||||
return OK;
|
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
|
* 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)
|
static int st25fl1_erase_sector(struct st25fl1_dev_s *priv, off_t sector)
|
||||||
{
|
{
|
||||||
off_t address;
|
off_t address;
|
||||||
#ifdef CONFIG_DEBUG
|
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
#endif
|
|
||||||
|
|
||||||
fvdbg("sector: %08lx\n", (unsigned long)sector);
|
fvdbg("sector: %08lx\n", (unsigned long)sector);
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG
|
|
||||||
/* Check that the flash is ready and unprotected */
|
/* Check that the flash is ready and unprotected */
|
||||||
|
|
||||||
status = sf25fl1_read_status1(priv->qspi);
|
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;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((status & STATUS1_BP_MASK) != 0)
|
/* Get the address associated with the sector */
|
||||||
{
|
|
||||||
fdbg("ERROR: Flash protected: %02x", status);
|
|
||||||
/* REVISIT: Should check if this particular sector is protected */
|
|
||||||
//return -EACCES;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Send the sector erase command */
|
|
||||||
|
|
||||||
address = (off_t)sector << priv->sectorshift;
|
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_write_enable(priv->qspi);
|
||||||
st25fl1_command_address(priv->qspi, ST25FL1_SECTOR_ERASE, address, 3);
|
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;
|
uint8_t status;
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG
|
|
||||||
/* Check if the FLASH is protected */
|
/* Check if the FLASH is protected */
|
||||||
|
|
||||||
status = sf25fl1_read_status1(priv->qspi);
|
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);
|
fdbg("ERROR: FLASH is Protected: %02x", status);
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Erase the whole chip */
|
/* 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
|
#ifdef CONFIG_ST25FL1_SECTOR512
|
||||||
static int st25fl1_flush_cache(struct st25fl1_dev_s *priv)
|
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)
|
/* 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
|
||||||
* the cached erase block to FLASH.
|
* 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))
|
if (IS_DIRTY(priv) || IS_ERASED(priv))
|
||||||
{
|
{
|
||||||
/* Write entire erase block to FLASH */
|
/* 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 */
|
/* 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);
|
CLR_ERASED(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1198,9 +1364,28 @@ static int st25fl1_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
ret = -ENOTTY; /* Bad command */
|
ret = -ENOTTY; /* Bad/unsupported command */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1277,10 +1462,6 @@ FAR struct mtd_dev_s *st25fl1_initialize(FAR struct qspi_dev_s *qspi)
|
|||||||
usleep(50*1000);
|
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 */
|
#ifdef CONFIG_ST25FL1_SECTOR512 /* Simulate a 512 byte sector */
|
||||||
/* Allocate a buffer for the erase block cache */
|
/* Allocate a buffer for the erase block cache */
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,8 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <nuttx/fs/ioctl.h>
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
Reference in New Issue
Block a user