You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/02/04 18:06:09 UTC
[incubator-nuttx] 01/02: drivers:mtd:w25qxxxjv.c: use different
protect bits and address lengths for different chips
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 9146878dad9e1346453a2a21ea1d841965e13811
Author: Alexander Vasiljev <al...@gmail.com>
AuthorDate: Wed Feb 3 12:36:13 2021 +0300
drivers:mtd:w25qxxxjv.c: use different protect bits and address lengths for different chips
---
drivers/mtd/w25qxxxjv.c | 80 +++++++++++++++++++++++++++++++++++++++----------
1 file changed, 64 insertions(+), 16 deletions(-)
diff --git a/drivers/mtd/w25qxxxjv.c b/drivers/mtd/w25qxxxjv.c
index 51c9d7f..81bb541 100644
--- a/drivers/mtd/w25qxxxjv.c
+++ b/drivers/mtd/w25qxxxjv.c
@@ -118,6 +118,8 @@
* 0xd8 | A23-A16 | A15-A8 | A7-A0 */
#define W25QXXXJV_CHIP_ERASE 0x60 /* Chip Erase: *
* 0xc7 or 0x60 */
+#define W25QXXXJV_ENTER_4BT_MODE 0xB7 /* Enter 4-byte address mode */
+#define W25QXXXJV_EXIT_4BT_MODE 0xE9 /* Exit 4-byte address mode */
/* Read Commands ************************************************************
* Command Value Description: *
@@ -139,7 +141,6 @@
* Command Value Description: *
* Data sequence *
*/
-
#define W25QXXXJV_JEDEC_ID 0x9f /* JEDEC ID: *
* 0x9f | Manufacturer | MemoryType | *
* Capacity */
@@ -177,7 +178,7 @@
#define STATUS_BP_SHIFT (2) /* Bits 2-4: Block protect bits */
#define STATUS_BP_MASK (7 << STATUS_BP_SHIFT)
#define STATUS_BP_NONE (0 << STATUS_BP_SHIFT)
-#define STATUS_BP_ALL (7 << STATUS_BP_SHIFT)
+#define STATUS_BP_ALL (15 << STATUS_BP_SHIFT)
#define STATUS_TB_MASK (1 << 5) /* Bit 5: Top / Bottom Protect */
#define STATUS_TB_TOP (0 << 5) /* 0 = BP2-BP0 protect Top down */
#define STATUS_TB_BOTTOM (1 << 5) /* 1 = BP2-BP0 protect Bottom up */
@@ -188,6 +189,13 @@
#define STATUS_SRP_UNLOCKED (0 << 7) /* see blow for details */
#define STATUS_SRP_LOCKED (1 << 7) /* see blow for details */
+/* Some chips have four protect bits */
+
+/* Bits 2-5: Block protect bits */
+#define STATUS_BP_4_MASK (15 << STATUS_BP_SHIFT)
+/* Some chips have top/bottom bit at sixth bit */
+#define STATUS_TB_6_MASK (1 << 6) /* Bit 6: Top / Bottom Protect */
+
/* Status Register Protect (SRP, SRL)
* SRL SRP /WP Status Register Description
* 0 0 X Software Protection [Factory Default] /WP pin has no
@@ -316,6 +324,9 @@ struct w25qxxxjv_dev_s
uint16_t nsectors; /* Number of erase sectors */
uint8_t sectorshift; /* Log2 of sector size */
uint8_t pageshift; /* Log2 of page size */
+ uint8_t addresslen; /* Length of address 3 or 4 bytes */
+ uint8_t protectmask; /* Mask for protect bits in status register */
+ uint8_t tbmask; /* Mask for top/bottom bit in status register */
FAR uint8_t *cmdbuf; /* Allocated command buffer */
FAR uint8_t *readbuf; /* Allocated status read buffer */
@@ -637,42 +648,63 @@ static inline int w25qxxxjv_readid(struct w25qxxxjv_dev_s *priv)
priv->sectorshift = W25Q016_SECTOR_SHIFT;
priv->pageshift = W25Q016_PAGE_SHIFT;
priv->nsectors = W25Q016_SECTOR_COUNT;
+ priv->addresslen = 3;
+ priv->protectmask = STATUS_BP_MASK;
+ priv->tbmask = STATUS_TB_MASK;
break;
case W25Q032_JEDEC_CAPACITY:
priv->sectorshift = W25Q032_SECTOR_SHIFT;
priv->pageshift = W25Q032_PAGE_SHIFT;
priv->nsectors = W25Q032_SECTOR_COUNT;
+ priv->addresslen = 3;
+ priv->protectmask = STATUS_BP_MASK;
+ priv->tbmask = STATUS_TB_MASK;
break;
case W25Q064_JEDEC_CAPACITY:
priv->sectorshift = W25Q064_SECTOR_SHIFT;
priv->pageshift = W25Q064_PAGE_SHIFT;
priv->nsectors = W25Q064_SECTOR_COUNT;
+ priv->addresslen = 3;
+ priv->protectmask = STATUS_BP_4_MASK;
+ priv->tbmask = STATUS_TB_6_MASK;
break;
case W25Q128_JEDEC_CAPACITY:
priv->sectorshift = W25Q128_SECTOR_SHIFT;
priv->pageshift = W25Q128_PAGE_SHIFT;
priv->nsectors = W25Q128_SECTOR_COUNT;
+ priv->addresslen = 3;
+ priv->protectmask = STATUS_BP_MASK;
+ priv->tbmask = STATUS_TB_MASK;
break;
case W25Q256_JEDEC_CAPACITY:
priv->sectorshift = W25Q256_SECTOR_SHIFT;
priv->pageshift = W25Q256_PAGE_SHIFT;
priv->nsectors = W25Q256_SECTOR_COUNT;
+ priv->addresslen = 4;
+ priv->protectmask = STATUS_BP_4_MASK;
+ priv->tbmask = STATUS_TB_6_MASK;
break;
case W25Q512_JEDEC_CAPACITY:
priv->sectorshift = W25Q512_SECTOR_SHIFT;
priv->pageshift = W25Q512_PAGE_SHIFT;
priv->nsectors = W25Q512_SECTOR_COUNT;
+ priv->addresslen = 4;
+ priv->protectmask = STATUS_BP_4_MASK;
+ priv->tbmask = STATUS_TB_6_MASK;
break;
case W25Q01_JEDEC_CAPACITY:
priv->sectorshift = W25Q01_SECTOR_SHIFT;
priv->pageshift = W25Q01_PAGE_SHIFT;
priv->nsectors = W25Q01_SECTOR_COUNT;
+ priv->addresslen = 4;
+ priv->protectmask = STATUS_BP_4_MASK;
+ priv->tbmask = STATUS_TB_6_MASK;
break;
/* Support for this part is not implemented yet */
@@ -696,7 +728,8 @@ static int w25qxxxjv_protect(FAR struct w25qxxxjv_dev_s *priv,
priv->cmdbuf[0] = w25qxxxjv_read_status(priv);
- if ((priv->cmdbuf[0] & STATUS_BP_MASK) == STATUS_BP_ALL)
+ if ((priv->cmdbuf[0] & priv->protectmask) ==
+ (STATUS_BP_ALL & priv->protectmask))
{
/* Protection already enabled */
@@ -705,13 +738,14 @@ static int w25qxxxjv_protect(FAR struct w25qxxxjv_dev_s *priv,
/* set the BP bits as necessary to protect the range of sectors. */
- priv->cmdbuf[0] |= STATUS_BP_ALL;
+ priv->cmdbuf[0] |= (STATUS_BP_ALL & priv->protectmask);
w25qxxxjv_write_status(priv);
/* Check the new status */
priv->cmdbuf[0] = w25qxxxjv_read_status(priv);
- if ((priv->cmdbuf[0] & STATUS_BP_MASK) != STATUS_BP_ALL)
+ if ((priv->cmdbuf[0] & priv->protectmask) !=
+ (STATUS_BP_ALL & priv->protectmask))
{
return -EACCES;
}
@@ -730,7 +764,7 @@ static int w25qxxxjv_unprotect(FAR struct w25qxxxjv_dev_s *priv,
priv->cmdbuf[0] = w25qxxxjv_read_status(priv);
- if ((priv->cmdbuf[0] & STATUS_BP_MASK) == STATUS_BP_NONE)
+ if ((priv->cmdbuf[0] & priv->protectmask) == STATUS_BP_NONE)
{
/* Protection already disabled */
@@ -742,13 +776,13 @@ static int w25qxxxjv_unprotect(FAR struct w25qxxxjv_dev_s *priv,
* necessary to unprotect the range of sectors.
*/
- priv->cmdbuf[0] &= ~STATUS_BP_MASK;
+ priv->cmdbuf[0] &= ~priv->protectmask;
w25qxxxjv_write_status(priv);
/* Check the new status */
priv->cmdbuf[0] = w25qxxxjv_read_status(priv);
- if ((priv->cmdbuf[0] & (STATUS_SRP_MASK | STATUS_BP_MASK)) != 0)
+ if ((priv->cmdbuf[0] & (STATUS_SRP_MASK | priv->protectmask)) != 0)
{
return -EACCES;
}
@@ -771,7 +805,7 @@ static bool w25qxxxjv_isprotected(FAR struct w25qxxxjv_dev_s *priv,
/* The BP field is spread across non-contiguous bits */
- bp = (status & STATUS_BP_MASK) >> STATUS_BP_SHIFT;
+ bp = (status & priv->protectmask) >> STATUS_BP_SHIFT;
/* the BP field is essentially the power-of-two of the number of 64k
* sectors, saturated to the device size.
@@ -794,7 +828,7 @@ static bool w25qxxxjv_isprotected(FAR struct w25qxxxjv_dev_s *priv,
* configured top-down or bottom up (assuming CMP=0).
*/
- if ((status & STATUS_TB_MASK) != 0)
+ if ((status & priv->tbmask) != 0)
{
protstart = 0x00000000;
protend = protstart + protsize;
@@ -834,7 +868,7 @@ static int w25qxxxjv_erase_sector(FAR struct w25qxxxjv_dev_s *priv,
address = (off_t)sector << priv->sectorshift;
- if ((status & STATUS_BP_MASK) != 0 &&
+ if ((status & priv->protectmask) != 0 &&
w25qxxxjv_isprotected(priv, status, address))
{
ferr("ERROR: Flash protected: %02x", status);
@@ -846,7 +880,7 @@ static int w25qxxxjv_erase_sector(FAR struct w25qxxxjv_dev_s *priv,
w25qxxxjv_write_enable(priv);
w25qxxxjv_command_address(priv->qspi,
W25QXXXJV_SECTOR_ERASE,
- address, 3);
+ address, priv->addresslen);
/* Wait for erasure to finish */
@@ -866,7 +900,7 @@ static int w25qxxxjv_erase_chip(FAR struct w25qxxxjv_dev_s *priv)
/* Check if the FLASH is protected */
status = w25qxxxjv_read_status(priv);
- if ((status & STATUS_BP_MASK) != 0)
+ if ((status & priv->protectmask) != 0)
{
ferr("ERROR: FLASH is Protected: %02x", status);
return -EACCES;
@@ -902,7 +936,7 @@ static int w25qxxxjv_read_byte(FAR struct w25qxxxjv_dev_s *priv,
finfo("address: %08lx nbytes: %d\n", (long)address, (int)buflen);
meminfo.flags = QSPIMEM_READ | QSPIMEM_QUADIO;
- meminfo.addrlen = 3;
+ meminfo.addrlen = priv->addresslen;
meminfo.dummies = CONFIG_W25QXXXJV_DUMMIES;
meminfo.buflen = buflen;
meminfo.cmd = W25QXXXJV_FAST_READ_QUADIO;
@@ -937,7 +971,7 @@ static int w25qxxxjv_write_page(struct w25qxxxjv_dev_s *priv,
meminfo.flags = QSPIMEM_WRITE;
meminfo.cmd = W25QXXXJV_PAGE_PROGRAM;
- meminfo.addrlen = 3;
+ meminfo.addrlen = priv->addresslen;
meminfo.buflen = pagesize;
meminfo.dummies = 0;
@@ -1383,7 +1417,7 @@ static int w25qxxxjv_ioctl(FAR struct mtd_dev_s *dev,
#endif
ret = OK;
- finfo("blocksize: %d erasesize: %d neraseblocks: %d\n",
+ finfo("blocksize: %lu erasesize: %lu neraseblocks: %lu\n",
geo->blocksize, geo->erasesize, geo->neraseblocks);
}
}
@@ -1509,6 +1543,20 @@ FAR struct mtd_dev_s *w25qxxxjv_initialize(FAR struct qspi_dev_s *qspi,
goto errout_with_readbuf;
}
+ /* Enter 4-byte address mode if chip is 4-byte addressable */
+
+ if (priv->addresslen == 4)
+ {
+ w25qxxxjv_lock(priv->qspi);
+ ret = w25qxxxjv_command(priv->qspi, W25QXXXJV_ENTER_4BT_MODE);
+ if (ret != OK)
+ {
+ ferr("ERROR: Failed to enter 4 byte mode\n");
+ }
+
+ w25qxxxjv_unlock(priv->qspi);
+ }
+
/* Unprotect FLASH sectors if so requested. */
if (unprotect)