From af6c99049872785fb8ad74bfc88bd444235a5f68 Mon Sep 17 00:00:00 2001 From: Sebastien Lorquet Date: Thu, 5 Jan 2023 17:44:30 +0100 Subject: [PATCH] add support for more is25 mtd devices --- drivers/mtd/is25xp.c | 141 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 124 insertions(+), 17 deletions(-) diff --git a/drivers/mtd/is25xp.c b/drivers/mtd/is25xp.c index 4b2ecd3b38..6dd1a70d08 100644 --- a/drivers/mtd/is25xp.c +++ b/drivers/mtd/is25xp.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -77,6 +78,7 @@ #define IS25_IS25LP064_NSECTORS 2048 #define IS25_IS25LP064_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ #define IS25_IS25LP064_NPAGES 32768 +#define IS25_IS25LP064_ADDRLEN 3 /* IS25LP128 capacity is 16,777,216 bytes: * (4,096 sectors) * (4,096 bytes per sector) @@ -88,30 +90,60 @@ #define IS25_IS25LP128_NSECTORS 4096 #define IS25_IS25LP128_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ #define IS25_IS25LP128_NPAGES 65536 +#define IS25_IS25LP128_ADDRLEN 3 + +/* IS25LP256 capacity is 33,554,432 bytes: + * (8,192 sectors) * (4,096 bytes per sector) + * (131,072 pages) * (256 bytes per page) + */ + +#define IS25_IS25LP256_CAPACITY 0x19 +#define IS25_IS25LP256_SECTOR_SHIFT 12 /* Sector size 1 << 12 = 4,096 */ +#define IS25_IS25LP256_NSECTORS 8192 +#define IS25_IS25LP256_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define IS25_IS25LP256_NPAGES 131072 +#define IS25_IS25LP256_ADDRLEN 4 /* This chip requires long addresses */ + +/* IS25LP512 capacity is 67,108,864 bytes: + * (16,364 sectors) * (4,096 bytes per sector) + * (262,144 pages) * (256 bytes per page) + */ + +#define IS25_IS25LP512_CAPACITY 0x1A +#define IS25_IS25LP512_SECTOR_SHIFT 12 /* Sector size 1 << 12 = 4,096 */ +#define IS25_IS25LP512_NSECTORS 16384 +#define IS25_IS25LP512_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define IS25_IS25LP512_NPAGES 262144 +#define IS25_IS25LP512_ADDRLEN 4 /* This chip requires long addresses */ /* Instructions */ /* Command Value N Description Addr Dummy Data */ -#define IS25_WREN 0x06 /* 1 Write Enable 0 0 0 */ -#define IS25_WRDI 0x04 /* 1 Write Disable 0 0 0 */ -#define IS25_RDID 0x9f /* 1 Read Identification 0 0 1-3 */ -#define IS25_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */ +#define IS25_WREN 0x06 /* 1 Write Enable 0 0 0 */ +#define IS25_WRDI 0x04 /* 1 Write Disable 0 0 0 */ +#define IS25_RDID 0x9f /* 1 Read Identification 0 0 1-3 */ +#define IS25_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */ -/* #define IS25_EWSR 0x50 1 Write enable status 0 0 0 */ -#define IS25_WRSR 0x01 /* 1 Write Status Register 0 0 1 */ -#define IS25_READ 0x03 /* 1 Read Data Bytes 3 0 >=1 */ -#define IS25_FAST_READ 0x0b /* 1 Higher speed read 3 1 >=1 */ -#define IS25_PP 0x02 /* 1 Page Program 3 0 1-256 */ -#define IS25_SE 0x20 /* 1 Sector Erase 3 0 0 */ -#define IS25_BE32 0x52 /* 2 32K Block Erase 3 0 0 */ -#define IS25_BE64 0xD8 /* 2 64K Block Erase 3 0 0 */ -#define IS25_CER 0xC7 /* 1 Chip Erase 0 0 0 */ +#define IS25_EWSR 0x50 /* 1 Write enable status 0 0 0 */ +#define IS25_WRSR 0x01 /* 1 Write Status Register 0 0 1 */ +#define IS25_READ 0x03 /* 1 Read Data Bytes 3 0 >=1 */ +#define IS25_FAST_READ 0x0b /* 1 Higher speed read 3 1 >=1 */ +#define IS25_PP 0x02 /* 1 Page Program 3 0 1-256 */ +#define IS25_SE 0x20 /* 1 Sector Erase 3 0 0 */ +#define IS25_BE32 0x52 /* 2 32K Block Erase 3 0 0 */ +#define IS25_BE64 0xD8 /* 2 64K Block Erase 3 0 0 */ +#define IS25_CER 0xC7 /* 1 Chip Erase 0 0 0 */ +#define IS25_EN4B 0xB7 /* 1 Enter 4-byte Address Mode 0 0 0 */ /* NOTE 1: All parts. * NOTE 2: In IS25XP terminology, 0x52 and 0xd8 are block erase and 0x20 * is a sector erase. Block erase provides a faster way to erase * multiple 4K sectors at once. + * NOTE 3: The larger chips (256/512Mbit) requires more than 24 address bits. + * To enable this, the EN4B command changes the address length of all + * commands that take a 3-byte address to 4 bytes. For information, + * other commands with a fixed 4-byte address are available. */ /* Status register bit definitions */ @@ -149,9 +181,10 @@ struct is25xp_dev_s FAR struct spi_dev_s *dev; /* Saved SPI interface instance */ uint8_t sectorshift; /* 12 */ uint8_t pageshift; /* 8 */ - uint16_t nsectors; /* 2,048 or 4,096 */ - uint32_t npages; /* 32,768 or 65,536 */ + uint16_t nsectors; /* 2,048 or 4,096 or 8,192 or 16,384 */ + uint32_t npages; /* 32,768 or 65,536 or 131,072 or 262,144 */ uint8_t lastwaswrite; /* Indicates if last operation was write */ + uint8_t addrlen; /* Address length, 3 or 4 bytes */ }; /**************************************************************************** @@ -163,6 +196,7 @@ struct is25xp_dev_s static void is25xp_lock(FAR struct spi_dev_s *dev); static inline void is25xp_unlock(FAR struct spi_dev_s *dev); static inline int is25xp_readid(struct is25xp_dev_s *priv); +static void is25xp_enable4byteaddr(struct is25xp_dev_s *priv); static void is25xp_waitwritecomplete(struct is25xp_dev_s *priv); static void is25xp_writeenable(struct is25xp_dev_s *priv); static inline void is25xp_sectorerase(struct is25xp_dev_s *priv, @@ -283,6 +317,7 @@ static inline int is25xp_readid(struct is25xp_dev_s *priv) priv->nsectors = IS25_IS25LP064_NSECTORS; priv->pageshift = IS25_IS25LP064_PAGE_SHIFT; priv->npages = IS25_IS25LP064_NPAGES; + priv->addrlen = IS25_IS25LP064_ADDRLEN; return OK; } else if (capacity == IS25_IS25LP128_CAPACITY) @@ -293,6 +328,29 @@ static inline int is25xp_readid(struct is25xp_dev_s *priv) priv->nsectors = IS25_IS25LP128_NSECTORS; priv->pageshift = IS25_IS25LP128_PAGE_SHIFT; priv->npages = IS25_IS25LP128_NPAGES; + priv->addrlen = IS25_IS25LP128_ADDRLEN; + return OK; + } + else if (capacity == IS25_IS25LP256_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->sectorshift = IS25_IS25LP256_SECTOR_SHIFT; + priv->nsectors = IS25_IS25LP256_NSECTORS; + priv->pageshift = IS25_IS25LP256_PAGE_SHIFT; + priv->npages = IS25_IS25LP256_NPAGES; + priv->addrlen = IS25_IS25LP256_ADDRLEN; + return OK; + } + else if (capacity == IS25_IS25LP512_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->sectorshift = IS25_IS25LP512_SECTOR_SHIFT; + priv->nsectors = IS25_IS25LP512_NSECTORS; + priv->pageshift = IS25_IS25LP512_PAGE_SHIFT; + priv->npages = IS25_IS25LP512_NPAGES; + priv->addrlen = IS25_IS25LP512_ADDRLEN; return OK; } } @@ -300,6 +358,27 @@ static inline int is25xp_readid(struct is25xp_dev_s *priv) return -ENODEV; } +/**************************************************************************** + * Name: is25xp_enable4byteaddr + ****************************************************************************/ + +static void is25xp_enable4byteaddr(struct is25xp_dev_s *priv) +{ + /* Lock the SPI bus, configure the bus, and select this FLASH part. */ + + is25xp_lock(priv->dev); + SPI_SELECT(priv->dev, SPIDEV_FLASH(0), true); + + /* Send the "Enter 4-byte Address Mode (EN4B)" command */ + + SPI_SEND(priv->dev, IS25_EN4B); + + /* Deselect the FLASH and unlock the bus */ + + SPI_SELECT(priv->dev, SPIDEV_FLASH(0), false); + is25xp_unlock(priv->dev); +} + /**************************************************************************** * Name: is25xp_waitwritecomplete ****************************************************************************/ @@ -472,6 +551,11 @@ static void is25xp_sectorerase(struct is25xp_dev_s *priv, * and the values used in the following two bytes don't really matter. */ + if (priv->addrlen == 4) + { + SPI_SEND(priv->dev, (offset >> 24) & 0xff); + } + SPI_SEND(priv->dev, (offset >> 16) & 0xff); SPI_SEND(priv->dev, (offset >> 8) & 0xff); SPI_SEND(priv->dev, offset & 0xff); @@ -554,6 +638,11 @@ static inline void is25xp_pagewrite(struct is25xp_dev_s *priv, /* Send the page offset high byte first. */ + if (priv->addrlen == 4) + { + SPI_SEND(priv->dev, (offset >> 24) & 0xff); + } + SPI_SEND(priv->dev, (offset >> 16) & 0xff); SPI_SEND(priv->dev, (offset >> 8) & 0xff); SPI_SEND(priv->dev, offset & 0xff); @@ -602,6 +691,11 @@ static inline void is25xp_bytewrite(struct is25xp_dev_s *priv, /* Send the page offset high byte first. */ + if (priv->addrlen == 4) + { + SPI_SEND(priv->dev, (offset >> 24) & 0xff); + } + SPI_SEND(priv->dev, (offset >> 16) & 0xff); SPI_SEND(priv->dev, (offset >> 8) & 0xff); SPI_SEND(priv->dev, offset & 0xff); @@ -795,6 +889,11 @@ static ssize_t is25xp_read(FAR struct mtd_dev_s *dev, /* Send the page offset high byte first. */ + if (priv->addrlen == 4) + { + SPI_SEND(priv->dev, (offset >> 24) & 0xff); + } + SPI_SEND(priv->dev, (offset >> 16) & 0xff); SPI_SEND(priv->dev, (offset >> 8) & 0xff); SPI_SEND(priv->dev, offset & 0xff); @@ -927,8 +1026,9 @@ static int is25xp_ioctl(FAR struct mtd_dev_s *dev, ret = OK; - finfo("blocksize: %d erasesize: %d neraseblocks: %d\n", - geo->blocksize, geo->erasesize, geo->neraseblocks); + finfo("blocksize: %"PRIu32" erasesize: %"PRIu32 + " neraseblocks: %"PRIu32"\n", geo->blocksize, + geo->erasesize, geo->neraseblocks); } } break; @@ -1034,6 +1134,13 @@ FAR struct mtd_dev_s *is25xp_initialize(FAR struct spi_dev_s *dev) } else { + /* For the large capacity chip, enable 4-byte address mode. */ + + if (priv->addrlen == 4) + { + is25xp_enable4byteaddr(priv); + } + /* Make sure that the FLASH is unprotected so that we can * write into it */