From 7936819fccc5bca455ba0fcc45cde3fcb36fe1ea Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 26 Aug 2015 14:16:45 -0600 Subject: [PATCH] ST25FL1: Flesh out more initialization logic --- arch | 2 +- drivers/mtd/st25fl1.c | 504 +++++++++++++++++++++++++++++++----------- 2 files changed, 381 insertions(+), 125 deletions(-) diff --git a/arch b/arch index 5336c64638..5f3f8a53bb 160000 --- a/arch +++ b/arch @@ -1 +1 @@ -Subproject commit 5336c646386607424e3426fb488d73241abb5f08 +Subproject commit 5f3f8a53bbcc0fd201bed99de4f69a6fa97597eb diff --git a/drivers/mtd/st25fl1.c b/drivers/mtd/st25fl1.c index 18a67eef24..4694320d08 100644 --- a/drivers/mtd/st25fl1.c +++ b/drivers/mtd/st25fl1.c @@ -174,12 +174,20 @@ /* Flash Manufacturer JEDEC IDs */ +#define ST25FL1_JEDEC_ID_SPANSION 0x01 #define ST25FL1_JEDEC_ID_ATMEL 0x1f #define ST25FL1_JEDEC_ID_ST 0x20 #define ST25FL1_JEDEC_ID_SST 0xbf #define ST25FL1_JEDEC_ID_MACRONIX 0xc2 #define ST25FL1_JEDEC_ID_WINBOND 0xef +/* ST25FL1 JEDIC IDs */ + +#define ST25FL1_JEDEC_DEVICE_TYPE 0x40 /* ST25FL1 memory devuce type */ +#define S25FL116K_JEDEC_CAPACITY 0x15 /* S25FL116K memory capacity */ +#define S25FL132K_JEDEC_CAPACITY 0x16 /* S25FL132K memory capacity */ +#define S25FL164K_JEDEC_CAPACITY 0x17 /* S25FL164K memory capacity */ + /* ST25FL1 Registers ****************************************************************/ /* Status register bit definitions */ @@ -198,7 +206,7 @@ # define STATUS1_TB_BOTTOM (1 << 5) /* 1 = BP2-BP0 protect Bottom up */ #define STATUS1_SEC_MASK (1 << 6) /* Bit 6: Sector / Block Protect */ # define STATUS1_SEC_BLOCK (0 << 6) /* 0 = BP2-BP0 protect 64-kB blocks */ -# define STATUS1_SEC_BLOCK (1 << 6) /* 1 = BP2-BP0 protect 4-kB sectors */ +# define STATUS1_SEC_SECTOR (1 << 6) /* 1 = BP2-BP0 protect 4-kB sectors */ #define STATUS1_SRP0_MASK (1 << 7) /* Bit 7: Status register protect 0 */ # define STATUS1_SRP0_UNLOCKED (0 << 7) /* 0 = WP# no effect / PS Lock Down */ # define STATUS1_SRP0_LOCKED (1 << 7) /* 1 = WP# protect / OTP Lock Down */ @@ -238,12 +246,15 @@ /* All members of the family support uniform 4K-byte sectors */ #define S25FL116K_SECTOR_SIZE (4*1024) +#define S25FL116K_SECTOR_SHIFT (12) #define S25FL116K_SECTOR_COUNT (512) #define S25FL132K_SECTOR_SIZE (4*1024) +#define S25FL163K_SECTOR_SHIFT (12) #define S25FL132K_SECTOR_COUNT (1024) #define S25FL164K_SECTOR_SIZE (4*1024) +#define S25FL164K_SECTOR_SHIFT (12) #define S25FL164K_SECTOR_COUNT (2048) /* Cache flags **********************************************************************/ @@ -276,8 +287,9 @@ struct st25fl1_dev_s { struct mtd_dev_s mtd; /* MTD interface */ - FAR struct spi_dev_s *qspi; /* Saved QuadSPI interface instance */ + FAR struct qspi_dev_s *qspi; /* Saved QuadSPI interface instance */ uint16_t nsectors; /* Number of erase sectors */ + uint8_t sectorshift; /* Log2 of sector size */ #ifdef CONFIG_ST25FL1_SECTOR512 uint8_t flags; /* Buffered sector flags */ @@ -290,39 +302,54 @@ struct st25fl1_dev_s * Private Function Prototypes ************************************************************************************/ -/* Helpers */ +/* Locking */ -static void st25fl1_lock(FAR struct spi_dev_s *qspi); -static inline void st25fl1_unlock(FAR struct spi_dev_s *qspi); -static inline int st25fl1_readid(FAR struct st25fl1_dev_s *priv); +static void st25fl1_lock(FAR struct qspi_dev_s *qspi); +static inline void st25fl1_unlock(FAR struct qspi_dev_s *qspi); + +/* Low-level message helpers */ + +static int st25fl1_command(FAR struct qspi_dev_s *qspi, uint8_t cmd); +static int st25fl1_command_address(FAR struct qspi_dev_s *qspi, uint8_t cmd, + off_t address); +static int st25fl1_command_read(FAR struct qspi_dev_s *qspi, uint8_t cmd, + FAR void *buffer, size_t buflen); +static int st25fl1_command_write(FAR struct qspi_dev_s *qspi, uint8_t cmd, + FAR const void *buffer, size_t buflen); +static uint8_t sf25fl1_read_status1(FAR struct qspi_dev_s *qspi); +static uint8_t sf25fl1_read_status2(FAR struct qspi_dev_s *qspi); +static uint8_t sf25fl1_read_status3(FAR struct qspi_dev_s *qspi); +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 uint8_t st25fl1_waitwritecomplete(FAR struct st25fl1_dev_s *priv); -static inline void st25fl1_wren(FAR struct st25fl1_dev_s *priv); -static inline void st25fl1_wrdi(FAR struct st25fl1_dev_s *priv); -static void st25fl1_sectorerase(FAR struct st25fl1_dev_s *priv, off_t offset); -static inline int st25fl1_chiperase(FAR struct st25fl1_dev_s *priv); -static void st25fl1_byteread(FAR struct st25fl1_dev_s *priv, FAR uint8_t *buffer, - off_t address, size_t nbytes); -static void st25fl1_pagewrite(FAR struct st25fl1_dev_s *priv, FAR const uint8_t *buffer, - off_t address, size_t nbytes); +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 void st25fl1_read_byte(FAR struct st25fl1_dev_s *priv, FAR uint8_t *buffer, + off_t address, size_t nbytes); +static void st25fl1_write_page(FAR struct st25fl1_dev_s *priv, + FAR const uint8_t *buffer, off_t address, size_t nbytes); #ifdef CONFIG_ST25FL1_SECTOR512 -static void st25fl1_cacheflush(struct st25fl1_dev_s *priv); -static FAR uint8_t *st25fl1_cacheread(struct st25fl1_dev_s *priv, off_t sector); -static void st25fl1_cacheerase(struct st25fl1_dev_s *priv, off_t sector); -static void st25fl1_cachewrite(FAR struct st25fl1_dev_s *priv, FAR const uint8_t *buffer, - off_t sector, size_t nsectors); +static void st25fl1_flush_cache(struct st25fl1_dev_s *priv); +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_write_cache(FAR struct st25fl1_dev_s *priv, + FAR const uint8_t *buffer, off_t sector, size_t nsectors); #endif /* MTD driver methods */ -static int st25fl1_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks); +static int st25fl1_erase(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks); static ssize_t st25fl1_bread(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR uint8_t *buf); + size_t nblocks, FAR uint8_t *buf); static ssize_t st25fl1_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, - size_t nblocks, FAR const uint8_t *buf); + size_t nblocks, FAR const uint8_t *buf); static ssize_t st25fl1_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbytes, - FAR uint8_t *buffer); -static int st25fl1_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); + FAR uint8_t *buffer); +static int st25fl1_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); /************************************************************************************ * Private Data @@ -336,7 +363,7 @@ static int st25fl1_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg); * Name: st25fl1_lock ************************************************************************************/ -static void st25fl1_lock(FAR struct spi_dev_s *qspi) +static void st25fl1_lock(FAR struct qspi_dev_s *qspi) { /* On QuadSPI busses where there are multiple devices, it will be necessary to * lock QuadSPI to have exclusive access to the busses for a sequence of @@ -363,42 +390,189 @@ static void st25fl1_lock(FAR struct spi_dev_s *qspi) * Name: st25fl1_unlock ************************************************************************************/ -static inline void st25fl1_unlock(FAR struct spi_dev_s *qspi) +static inline void st25fl1_unlock(FAR struct qspi_dev_s *qspi) { (void)QSPI_LOCK(qspi, false); } +/************************************************************************************ + * Name: st25fl1_command + ************************************************************************************/ + +static int st25fl1_command(FAR struct qspi_dev_s *qspi, uint8_t cmd) +{ + /* This function just allows us to insert debug output */ + + fvdbg("CMD: %02x\n", cmd); + return QSPI_COMMAND(qspi, (uint16_t)cmd); +} + +/************************************************************************************ + * Name: st25fl1_command_read + ************************************************************************************/ + +static int st25fl1_command_read(FAR struct qspi_dev_s *qspi, uint8_t cmd, + FAR void *buffer, size_t buflen) +{ + /* This function just allows us to insert debug output */ + + fvdbg("CMD: %02x buflen: %lu\n", cmd, (unsigned long)buflen); + return QSPI_COMMAND_READ(qspi, (uint16_t)cmd, buffer, buflen); +} + +/************************************************************************************ + * Name: st25fl1_command_write + ************************************************************************************/ + +static int st25fl1_command_write(FAR struct qspi_dev_s *qspi, uint8_t cmd, + FAR const void *buffer, size_t buflen) +{ + /* This function just allows us to insert debug output */ + + fvdbg("CMD: %02x buflen: %lu\n", cmd, (unsigned long)buflen); + return QSPI_COMMAND_WRITE(qspi, (uint16_t)cmd, buffer, buflen); +} + +/************************************************************************************ + * Name: sf25fl1_read_status1 + ************************************************************************************/ + +static uint8_t sf25fl1_read_status1(FAR struct qspi_dev_s *qspi) +{ + uint8_t status; + + DEBUGVERIFY(st25fl1_command_read(qspi, ST25FL1_READ_STATUS1, + (FAR void *)&status, 1)); + return status; +} + +/************************************************************************************ + * Name: sf25fl1_read_status2 + ************************************************************************************/ + +static uint8_t sf25fl1_read_status2(FAR struct qspi_dev_s *qspi) +{ + uint8_t status; + + DEBUGVERIFY(st25fl1_command_read(qspi, ST25FL1_READ_STATUS2, + (FAR void *)&status, 1)); + return status; +} + +/************************************************************************************ + * Name: sf25fl1_read_status3 + ************************************************************************************/ + +static uint8_t sf25fl1_read_status3(FAR struct qspi_dev_s *qspi) +{ + uint8_t status; + + DEBUGVERIFY(st25fl1_command_read(qspi, ST25FL1_READ_STATUS3, + (FAR void *)&status, 1)); + return status; +} + +/************************************************************************************ + * Name: st25fl1_write_enable + ************************************************************************************/ + +static void st25fl1_write_enable(FAR struct qspi_dev_s *qspi) +{ + uint8_t status; + + do + { + st25fl1_command(qspi, ST25FL1_WRITE_ENABLE); + status = sf25fl1_read_status1(qspi); + } + while ((status & STATUS1_WEL_MASK) != STATUS1_WEL_ENABLED); +} + +/************************************************************************************ + * Name: st25fl1_write_disable + ************************************************************************************/ + +static void st25fl1_write_disable(FAR struct qspi_dev_s *qspi) +{ + uint8_t status; + + do + { + st25fl1_command(qspi, ST25FL1_WRITE_DISABLE); + status = sf25fl1_read_status1(qspi); + } + while ((status & STATUS1_WEL_MASK) != STATUS1_WEL_DISABLED); +} + +/************************************************************************************ + * Name: st25fl1_write_status + ************************************************************************************/ + +static void st25fl1_write_status(FAR struct qspi_dev_s *qspi, uint8_t status[3]) +{ + st25fl1_write_enable(qspi); + st25fl1_command_write(qspi, ST25FL1_WRITE_STATUS, (FAR const void *)status, 3); + st25fl1_write_disable(qspi); +} + /************************************************************************************ * Name: st25fl1_readid ************************************************************************************/ static inline int st25fl1_readid(struct st25fl1_dev_s *priv) { - uint16_t manufacturer; - uint16_t memory; - uint16_t capacity; - - fvdbg("priv: %p\n", priv); + uint8_t jedecid[3]; /* Lock the QuadSPI bus and configure the bus. */ st25fl1_lock(priv->qspi); -#warning Missing Logic + /* Read the JEDEC ID */ + + st25fl1_command_read(priv->qspi, ST25FL1_JEDEC_ID, jedecid, 3); /* Unlock the bus */ st25fl1_unlock(priv->qspi); - fvdbg("manufacturer: %02x memory: %02x capacity: %02x\n", - manufacturer, memory, capacity); + fvdbg("Manufacturer: %02x Device Type %02x, Capacity: %02x", + jedecid[0], jedecid[1], jedecid[2]); - /* Check for a valid manufacturer and memory type */ -#warning Missing Logic + /* Check for a recognized memory device type */ - /* We don't understand the manufacturer or the memory type */ + if (jedecid[1] != ST25FL1_JEDEC_DEVICE_TYPE) + { + fdbg("ERROR: Unrecognized device type: %02x\n", jedecid[1]); + return -ENODEV; + } - return -ENODEV; + /* Check for a supported capacity */ + + switch (jedecid[2]) + { + case S25FL116K_JEDEC_CAPACITY: + priv->sectorshift = S25FL116K_SECTOR_SHIFT; + priv->nsectors = S25FL116K_SECTOR_COUNT; + break; + + case S25FL132K_JEDEC_CAPACITY: + priv->sectorshift = S25FL163K_SECTOR_SHIFT; + priv->nsectors = S25FL132K_SECTOR_COUNT; + break; + + case S25FL164K_JEDEC_CAPACITY: + priv->sectorshift = S25FL164K_SECTOR_SHIFT; + priv->nsectors = S25FL164K_SECTOR_COUNT; + break; + + /* Support for this part is not implemented yet */ + + default: + fdbg("ERROR: Unsupported memory capacity: %02x\n", jedecid[2]); + return -ENODEV; + } + + return OK; } /************************************************************************************ @@ -424,54 +598,93 @@ static uint8_t st25fl1_waitwritecomplete(struct st25fl1_dev_s *priv) { #warning Missing Logic } - while ((status & ST25FL1_SR_BUSY) != 0); + while ((status & STATUS1_BUSY_MASK) == STATUS1_BUSY); return status; } /************************************************************************************ - * Name: st25fl1_wren + * Name: st25fl1_erase_sector ************************************************************************************/ -static inline void st25fl1_wren(struct st25fl1_dev_s *priv) +static int st25fl1_erase_sector(struct st25fl1_dev_s *priv, off_t sector) { -#warning Missing Logic +#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); + if ((status & STATUS1_BUSY_MASK) != STATUS1_READY) + { + fdbg("ERROR: Flash busy: %02x", status); + 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 */ + + st25fl1_write_enable(priv->qspi); + st25fl1_command_address(priv->qspi, ST25FL1_SECTOR_ERASE, sector); + + /* Wait for erasure to finish */ + + while ((sf25fl1_read_status1(priv->qspi) & STATUS1_BUSY_MASK) != 0); + return OK; } /************************************************************************************ - * Name: st25fl1_wrdi + * Name: st25fl1_erase_chip ************************************************************************************/ -static inline void st25fl1_wrdi(struct st25fl1_dev_s *priv) +static int st25fl1_erase_chip(struct st25fl1_dev_s *priv) { -#warning Missing Logic + uint8_t status; + +#ifdef CONFIG_DEBUG + /* Check if the FLASH is protected */ + + status = sf25fl1_read_status1(priv->qspi); + if ((status & STATUS1_BP_MASK) != 0) + { + fdbg("ERROR: FLASH is Protected: %02x", status); + return -EACCES; + } +#endif + + /* Erase the whole chip */ + + st25fl1_write_enable(priv->qspi); + st25fl1_command(priv->qspi, ST25FL1_CHIP_ERASE_2); + + /* Wait for the erasure to complete */ + + status = sf25fl1_read_status1(priv->qspi); + while ((status & STATUS1_BUSY_MASK) != 0) + { + usleep(200*1000); + status = sf25fl1_read_status1(priv->qspi); + } + + return OK; } /************************************************************************************ - * Name: st25fl1_sectorerase + * Name: st25fl1_read_byte ************************************************************************************/ -static void st25fl1_sectorerase(struct st25fl1_dev_s *priv, off_t sector) -{ - fvdbg("sector: %08lx\n", (long)sector); -#warning Missing Logic -} - -/************************************************************************************ - * Name: st25fl1_chiperase - ************************************************************************************/ - -static inline int st25fl1_chiperase(struct st25fl1_dev_s *priv) -{ - fvdbg("priv: %p\n", priv); -#warning Missing Logic -} - -/************************************************************************************ - * Name: st25fl1_byteread - ************************************************************************************/ - -static void st25fl1_byteread(FAR struct st25fl1_dev_s *priv, FAR uint8_t *buffer, +static void st25fl1_read_byte(FAR struct st25fl1_dev_s *priv, FAR uint8_t *buffer, off_t address, size_t nbytes) { fvdbg("address: %08lx nbytes: %d\n", (long)address, (int)nbytes); @@ -479,10 +692,10 @@ static void st25fl1_byteread(FAR struct st25fl1_dev_s *priv, FAR uint8_t *buffer } /************************************************************************************ - * Name: st25fl1_pagewrite + * Name: st25fl1_write_page ************************************************************************************/ -static void st25fl1_pagewrite(struct st25fl1_dev_s *priv, FAR const uint8_t *buffer, +static void st25fl1_write_page(struct st25fl1_dev_s *priv, FAR const uint8_t *buffer, off_t address, size_t nbytes) { fvdbg("address: %08lx nwords: %d\n", (long)address, (int)nbytes); @@ -490,11 +703,11 @@ static void st25fl1_pagewrite(struct st25fl1_dev_s *priv, FAR const uint8_t *buf } /************************************************************************************ - * Name: st25fl1_cacheflush + * Name: st25fl1_flush_cache ************************************************************************************/ #ifdef CONFIG_ST25FL1_SECTOR512 -static void st25fl1_cacheflush(struct st25fl1_dev_s *priv) +static void st25fl1_flush_cache(struct st25fl1_dev_s *priv) { /* 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 @@ -515,11 +728,11 @@ static void st25fl1_cacheflush(struct st25fl1_dev_s *priv) #endif /************************************************************************************ - * Name: st25fl1_cacheread + * Name: st25fl1_read_cache ************************************************************************************/ #ifdef CONFIG_ST25FL1_SECTOR512 -static FAR uint8_t *st25fl1_cacheread(struct st25fl1_dev_s *priv, off_t sector) +static FAR uint8_t *st25fl1_read_cache(struct st25fl1_dev_s *priv, off_t sector) { off_t esectno; int shift; @@ -530,7 +743,7 @@ static FAR uint8_t *st25fl1_cacheread(struct st25fl1_dev_s *priv, off_t sector) * shift to the right by 3 to get the sector number in 4096 increments. */ - shift = ST25FL1_SECTOR_SHIFT - ST25FL1_SECTOR512_SHIFT; + shift = priv->sectorshift - ST25FL1_SECTOR512_SHIFT; esectno = sector >> shift; fvdbg("sector: %ld esectno: %d shift=%d\n", sector, esectno, shift); @@ -540,11 +753,12 @@ static FAR uint8_t *st25fl1_cacheread(struct st25fl1_dev_s *priv, off_t sector) { /* No.. Flush any dirty erase block currently in the cache */ - st25fl1_cacheflush(priv); + st25fl1_flush_cache(priv); /* Read the erase block into the cache */ - st25fl1_byteread(priv, priv->sector, (esectno << ST25FL1_SECTOR_SHIFT), ST25FL1_SECTOR_SIZE); + st25fl1_read_byte(priv, priv->sector, (esectno << priv->sectorshift) + (1 << priv->sectorshift)); /* Mark the sector as cached */ @@ -566,11 +780,11 @@ static FAR uint8_t *st25fl1_cacheread(struct st25fl1_dev_s *priv, off_t sector) #endif /************************************************************************************ - * Name: st25fl1_cacheerase + * Name: st25fl1_erase_cache ************************************************************************************/ #ifdef CONFIG_ST25FL1_SECTOR512 -static void st25fl1_cacheerase(struct st25fl1_dev_s *priv, off_t sector) +static void st25fl1_erase_cache(struct st25fl1_dev_s *priv, off_t sector) { FAR uint8_t *dest; @@ -578,7 +792,7 @@ static void st25fl1_cacheerase(struct st25fl1_dev_s *priv, off_t sector) * the cache. */ - dest = st25fl1_cacheread(priv, sector); + dest = st25fl1_read_cache(priv, sector); /* Erase the block containing this sector if it is not already erased. * The erased indicated will be cleared when the data from the erase sector @@ -587,10 +801,10 @@ static void st25fl1_cacheerase(struct st25fl1_dev_s *priv, off_t sector) if (!IS_ERASED(priv)) { - off_t esectno = sector >> (ST25FL1_SECTOR_SHIFT - ST25FL1_SECTOR512_SHIFT); + off_t esectno = sector >> (priv->sectorshift - ST25FL1_SECTOR512_SHIFT); fvdbg("sector: %ld esectno: %d\n", sector, esectno); - st25fl1_sectorerase(priv, esectno); + DEBUGVERIFY(st25fl1_erase_sector(priv, esectno)); SET_ERASED(priv); } @@ -605,11 +819,11 @@ static void st25fl1_cacheerase(struct st25fl1_dev_s *priv, off_t sector) #endif /************************************************************************************ - * Name: st25fl1_cachewrite + * Name: st25fl1_write_cache ************************************************************************************/ #ifdef CONFIG_ST25FL1_SECTOR512 -static void st25fl1_cachewrite(FAR struct st25fl1_dev_s *priv, FAR const uint8_t *buffer, +static void st25fl1_write_cache(FAR struct st25fl1_dev_s *priv, FAR const uint8_t *buffer, off_t sector, size_t nsectors) { FAR uint8_t *dest; @@ -620,7 +834,7 @@ static void st25fl1_cachewrite(FAR struct st25fl1_dev_s *priv, FAR const uint8_t * memory. */ - dest = st25fl1_cacheread(priv, sector); + dest = st25fl1_read_cache(priv, sector); /* Erase the block containing this sector if it is not already erased. * The erased indicated will be cleared when the data from the erase sector @@ -629,10 +843,10 @@ static void st25fl1_cachewrite(FAR struct st25fl1_dev_s *priv, FAR const uint8_t if (!IS_ERASED(priv)) { - off_t esectno = sector >> (ST25FL1_SECTOR_SHIFT - ST25FL1_SECTOR512_SHIFT); + off_t esectno = sector >> (priv->sectorshift - ST25FL1_SECTOR512_SHIFT); fvdbg("sector: %ld esectno: %d\n", sector, esectno); - st25fl1_sectorerase(priv, esectno); + DEBUGVERIFY(st25fl1_erase_sector(priv, esectno)); SET_ERASED(priv); } @@ -649,7 +863,7 @@ static void st25fl1_cachewrite(FAR struct st25fl1_dev_s *priv, FAR const uint8_t /* Flush the last erase block left in the cache */ - st25fl1_cacheflush(priv); + st25fl1_flush_cache(priv); } #endif @@ -660,19 +874,44 @@ static void st25fl1_cachewrite(FAR struct st25fl1_dev_s *priv, FAR const uint8_t static int st25fl1_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks) { FAR struct st25fl1_dev_s *priv = (FAR struct st25fl1_dev_s *)dev; + size_t blocksleft = nblocks; fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); -#warning Missing Logic + /* Lock access to the SPI bus until we complete the erase */ + + st25fl1_lock(priv->qspi); + + while (blocksleft-- > 0) + { + /* Erase each sector */ + +#ifdef CONFIG_S25FL1_SECTOR512 + st25fl1_erase_cache(priv, startblock); +#else + st25fl1_erase_sector(priv, startblock); +#endif + startblock++; + } + +#ifdef CONFIG_S25FL1_SECTOR512 + /* Flush the last erase block left in the cache */ + + st25fl1_flush_cache(priv); +#endif + + st25fl1_unlock(priv->qspi); + return (int)nblocks; } /************************************************************************************ * Name: st25fl1_bread ************************************************************************************/ -static ssize_t st25fl1_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR uint8_t *buffer) +static ssize_t st25fl1_bread(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR uint8_t *buffer) { + FAR struct st25fl1_dev_s *priv = (FAR struct st25fl1_dev_s *)dev; ssize_t nbytes; fvdbg("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); @@ -680,16 +919,18 @@ static ssize_t st25fl1_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t /* On this device, we can handle the block read just like the byte-oriented read */ #ifdef CONFIG_ST25FL1_SECTOR512 - nbytes = st25fl1_read(dev, startblock << ST25FL1_SECTOR512_SHIFT, nblocks << ST25FL1_SECTOR512_SHIFT, buffer); + nbytes = st25fl1_read(dev, startblock << ST25FL1_SECTOR512_SHIFT, + nblocks << ST25FL1_SECTOR512_SHIFT, buffer); if (nbytes > 0) { nbytes >>= ST25FL1_SECTOR512_SHIFT; } #else - nbytes = st25fl1_read(dev, startblock << ST25FL1_SECTOR_SHIFT, nblocks << ST25FL1_SECTOR_SHIFT, buffer); + nbytes = st25fl1_read(dev, startblock << priv->sectorshift, + nblocks << priv->sectorshift, buffer); if (nbytes > 0) { - nbytes >>= ST25FL1_SECTOR_SHIFT; + nbytes >>= priv->sectorshift; } #endif @@ -700,8 +941,8 @@ static ssize_t st25fl1_bread(FAR struct mtd_dev_s *dev, off_t startblock, size_t * Name: st25fl1_bwrite ************************************************************************************/ -static ssize_t st25fl1_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks, - FAR const uint8_t *buffer) +static ssize_t st25fl1_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, + size_t nblocks, FAR const uint8_t *buffer) { FAR struct st25fl1_dev_s *priv = (FAR struct st25fl1_dev_s *)dev; @@ -712,10 +953,10 @@ static ssize_t st25fl1_bwrite(FAR struct mtd_dev_s *dev, off_t startblock, size_ st25fl1_lock(priv->qspi); #if defined(CONFIG_ST25FL1_SECTOR512) - st25fl1_cachewrite(priv, buffer, startblock, nblocks); + st25fl1_write_cache(priv, buffer, startblock, nblocks); #else - st25fl1_pagewrite(priv, buffer, startblock << ST25FL1_SECTOR_SHIFT, - nblocks << ST25FL1_SECTOR_SHIFT); + st25fl1_write_page(priv, buffer, startblock << priv->sectorshift, + nblocks << priv->sectorshift); #endif st25fl1_unlock(priv->qspi); @@ -736,7 +977,7 @@ static ssize_t st25fl1_read(FAR struct mtd_dev_s *dev, off_t offset, size_t nbyt /* Lock the QuadSPI bus and select this FLASH part */ st25fl1_lock(priv->qspi); - st25fl1_byteread(priv, buffer, offset, nbytes); + st25fl1_read_byte(priv, buffer, offset, nbytes); st25fl1_unlock(priv->qspi); fvdbg("return nbytes: %d\n", (int)nbytes); @@ -758,7 +999,9 @@ static int st25fl1_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) { case MTDIOC_GEOMETRY: { - FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg); + FAR struct mtd_geometry_s *geo = + (FAR struct mtd_geometry_s *)((uintptr_t)arg); + if (geo) { /* Populate the geometry structure with information need to know @@ -773,10 +1016,10 @@ static int st25fl1_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) #ifdef CONFIG_ST25FL1_SECTOR512 geo->blocksize = (1 << ST25FL1_SECTOR512_SHIFT); geo->erasesize = (1 << ST25FL1_SECTOR512_SHIFT); - geo->neraseblocks = priv->nsectors << (ST25FL1_SECTOR_SHIFT - ST25FL1_SECTOR512_SHIFT); + geo->neraseblocks = priv->nsectors << (priv->sectorshift - ST25FL1_SECTOR512_SHIFT); #else - geo->blocksize = ST25FL1_SECTOR_SIZE; - geo->erasesize = ST25FL1_SECTOR_SIZE; + geo->blocksize = (1 << priv->sectorshift); + geo->erasesize = (1 << priv->sectorshift); geo->neraseblocks = priv->nsectors; #endif ret = OK; @@ -789,11 +1032,11 @@ static int st25fl1_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) case MTDIOC_BULKERASE: { - /* Erase the entire device */ + /* Erase the entire device */ - st25fl1_lock(priv->qspi); - ret = st25fl1_chiperase(priv); - st25fl1_unlock(priv->qspi); + st25fl1_lock(priv->qspi); + ret = st25fl1_erase_chip(priv); + st25fl1_unlock(priv->qspi); } break; @@ -821,9 +1064,10 @@ static int st25fl1_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg) * ************************************************************************************/ -FAR struct mtd_dev_s *st25fl1_initialize(FAR struct spi_dev_s *qspi) +FAR struct mtd_dev_s *st25fl1_initialize(FAR struct qspi_dev_s *qspi) { FAR struct st25fl1_dev_s *priv; + uint8_t status[3]; int ret; fvdbg("qspi: %p\n", qspi); @@ -856,30 +1100,42 @@ FAR struct mtd_dev_s *st25fl1_initialize(FAR struct spi_dev_s *qspi) { /* Unrecognized! Discard all of that work we just did and return NULL */ - fdbg("Unrecognized\n"); + fdbg("ERROR Unrecognized QSPI device\n"); kmm_free(priv); - priv = NULL; + return NULL; } - else - { - /* Make sure that the FLASH is unprotected so that we can write into it */ - st25fl1_unprotect(priv); + /* Enable quad mode */ + + status[0] = sf25fl1_read_status1(priv->qspi); + status[1] = sf25fl1_read_status2(priv->qspi); + status[2] = sf25fl1_read_status3(priv->qspi); + + while ((status[1] & STATUS2_QUAD_ENABLE_MASK) == 0) + { + status[1] |= STATUS2_QUAD_ENABLE; + st25fl1_write_status(priv->qspi, status); + status[1] = sf25fl1_read_status2(priv->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 */ + /* Allocate a buffer for the erase block cache */ - priv->sector = (FAR uint8_t *)kmm_malloc(ST25FL1_SECTOR_SIZE); - if (!priv->sector) - { - /* Allocation failed! Discard all of that work we just did and return NULL */ + priv->sector = (FAR uint8_t *)kmm_malloc((1 << priv->sectorshift)); + if (!priv->sector) + { + /* Allocation failed! Discard all of that work we just did and return NULL */ - fdbg("Allocation failed\n"); - kmm_free(priv); - priv = NULL; - } -#endif + fdbg("ERROR: Allocation failed\n"); + kmm_free(priv); + return NULL; } +#endif } #ifdef CONFIG_MTD_REGISTRATION