drivers/mtd/mx25rxx.c: add support for 512B sectors
- Fix for mx25rxx driver as it does not work properly - Add mx25rxx memory chip & smartfs support in b-l475e-iot01a/nsh config - Update smartfs smart_scan() function
This commit is contained in:
parent
08460ba5b1
commit
780d4d41e8
@ -1182,7 +1182,7 @@ if STM32L4_QSPI
|
||||
config STM32L4_QSPI_FLASH_SIZE
|
||||
int "Size of attached serial flash, bytes"
|
||||
default 16777216
|
||||
range 1 2147483648
|
||||
range 1 2147483647
|
||||
---help---
|
||||
The STM32L4 QSPI peripheral requires the size of the Flash be specified
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
if ARCH_BOARD_B_L475E_IOT01A
|
||||
|
||||
config B_L475E_IOT01A_MTD_FLASH
|
||||
bool "MTD driver for external 64Mbytes flash memory"
|
||||
bool "MTD driver for external 64Mbits flash memory"
|
||||
default n
|
||||
select STM32L4_DMA1
|
||||
select STM32L4_QSPI
|
||||
|
@ -16,6 +16,9 @@ CONFIG_ARCH_CHIP_STM32L4=y
|
||||
CONFIG_ARCH_STACKDUMP=y
|
||||
CONFIG_BOARD_LOOPSPERMSEC=8025
|
||||
CONFIG_BUILTIN=y
|
||||
CONFIG_B_L475E_IOT01A_MTD_FLASH=y
|
||||
CONFIG_B_L475E_IOT01A_MTD_PART=y
|
||||
CONFIG_B_L475E_IOT01A_MTD_PART_LIST="16,64,128,128"
|
||||
CONFIG_FS_PROCFS=y
|
||||
CONFIG_HAVE_CXX=y
|
||||
CONFIG_HAVE_CXXINITIALIZE=y
|
||||
@ -23,10 +26,13 @@ CONFIG_INTELHEX_BINARY=y
|
||||
CONFIG_MAX_TASKS=16
|
||||
CONFIG_MAX_WDOGPARMS=2
|
||||
CONFIG_MM_REGIONS=2
|
||||
CONFIG_MTD_SMART_SECTOR_SIZE=512
|
||||
CONFIG_MX25RXX_SECTOR512=y
|
||||
CONFIG_NFILE_DESCRIPTORS=8
|
||||
CONFIG_NFILE_STREAMS=8
|
||||
CONFIG_NSH_ARCHINIT=y
|
||||
CONFIG_NSH_BUILTIN_APPS=y
|
||||
CONFIG_NSH_DISABLE_LOSMART=y
|
||||
CONFIG_NSH_FILEIOSIZE=512
|
||||
CONFIG_NSH_LINELEN=64
|
||||
CONFIG_NSH_READLINE=y
|
||||
@ -42,6 +48,7 @@ CONFIG_SDCLONE_DISABLE=y
|
||||
CONFIG_START_DAY=6
|
||||
CONFIG_START_MONTH=12
|
||||
CONFIG_START_YEAR=2011
|
||||
CONFIG_STM32L4_QSPI_FLASH_SIZE=8388608
|
||||
CONFIG_STM32L4_USART1=y
|
||||
CONFIG_SYSTEM_NSH=y
|
||||
CONFIG_USART1_SERIAL_CONSOLE=y
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* config/b-l475e-iot01a/src/stm32_bringup.c
|
||||
*
|
||||
* Copyright (C) 2017-2018 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2017-2019 Gregory Nutt. All rights reserved.
|
||||
* Author: Simon Piriou <spiriou31@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -182,8 +182,15 @@ int stm32l4_bringup(void)
|
||||
}
|
||||
|
||||
mtd_part = mtd_partition(g_mtd_fs, partoffset,
|
||||
partszbytes / erasesize);
|
||||
partoffset += partszbytes / erasesize;
|
||||
partszbytes / geo.blocksize);
|
||||
partoffset += partszbytes / geo.blocksize;
|
||||
|
||||
if (!mtd_part)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to create part %d, size=%d\n",
|
||||
partno, partsize);
|
||||
goto process_next_part;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MTD_SMART) && defined(CONFIG_FS_SMARTFS)
|
||||
/* Now initialize a SMART Flash block device and bind it to the MTD
|
||||
|
@ -641,6 +641,10 @@ config MX25RXX_QSPI_READ_FREQUENCY
|
||||
Clock frequency for read data command.
|
||||
Only Quad read is supported in this driver.
|
||||
|
||||
config MX25RXX_SECTOR512
|
||||
bool "Simulate 512 byte Erase Blocks"
|
||||
default n
|
||||
|
||||
endif # MTD_MX25RXX
|
||||
|
||||
config MTD_SMART
|
||||
|
@ -1,7 +1,7 @@
|
||||
/************************************************************************************
|
||||
* drivers/mtd/mx25rxx.c
|
||||
*
|
||||
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 201, 2019 Gregory Nutt. All rights reserved.
|
||||
* Author: Simon Piriou <spiriou31@gmail.com>
|
||||
|
||||
* Derived from QuadSPI-based N25QxxxA driver (drivers/mtd/n25qxxx.c)
|
||||
@ -46,6 +46,11 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/signal.h>
|
||||
#include <nuttx/signal.h>
|
||||
@ -121,7 +126,7 @@
|
||||
|
||||
#define MX25R6435F_SECTOR_SIZE (4*1024)
|
||||
#define MX25R6435F_SECTOR_SHIFT (12)
|
||||
#define MX25R6435F_SECTOR_COUNT (16384)
|
||||
#define MX25R6435F_SECTOR_COUNT (2048)
|
||||
#define MX25R6435F_PAGE_SIZE (256)
|
||||
#define MX25R6435F_PAGE_SHIFT (8)
|
||||
|
||||
@ -140,6 +145,30 @@
|
||||
#define MX25R_CR_TB (1 << 3) /* Bit 3: Top/bottom selected */
|
||||
#define MX25R_CR_DC (1 << 6) /* Bit 6: Dummy cycle */
|
||||
|
||||
/* Cache flags **********************************************************************/
|
||||
|
||||
#define MX25RXX_CACHE_VALID (1 << 0) /* 1=Cache has valid data */
|
||||
#define MX25RXX_CACHE_DIRTY (1 << 1) /* 1=Cache is dirty */
|
||||
#define MX25RXX_CACHE_ERASED (1 << 2) /* 1=Backing FLASH is erased */
|
||||
|
||||
#define IS_VALID(p) ((((p)->flags) & MX25RXX_CACHE_VALID) != 0)
|
||||
#define IS_DIRTY(p) ((((p)->flags) & MX25RXX_CACHE_DIRTY) != 0)
|
||||
#define IS_ERASED(p) ((((p)->flags) & MX25RXX_CACHE_ERASED) != 0)
|
||||
|
||||
#define SET_VALID(p) do { (p)->flags |= MX25RXX_CACHE_VALID; } while (0)
|
||||
#define SET_DIRTY(p) do { (p)->flags |= MX25RXX_CACHE_DIRTY; } while (0)
|
||||
#define SET_ERASED(p) do { (p)->flags |= MX25RXX_CACHE_ERASED; } while (0)
|
||||
|
||||
#define CLR_VALID(p) do { (p)->flags &= ~MX25RXX_CACHE_VALID; } while (0)
|
||||
#define CLR_DIRTY(p) do { (p)->flags &= ~MX25RXX_CACHE_DIRTY; } while (0)
|
||||
#define CLR_ERASED(p) do { (p)->flags &= ~MX25RXX_CACHE_ERASED; } while (0)
|
||||
|
||||
/* 512 byte sector support **********************************************************/
|
||||
|
||||
#define MX25RXX_SECTOR512_SHIFT 9
|
||||
#define MX25RXX_SECTOR512_SIZE (1 << 9)
|
||||
#define MX25RXX_ERASED_STATE 0xff
|
||||
|
||||
/************************************************************************************
|
||||
* Private Types
|
||||
************************************************************************************/
|
||||
@ -153,9 +182,15 @@ struct mx25rxx_dev_s
|
||||
|
||||
FAR uint8_t *cmdbuf; /* Allocated command buffer */
|
||||
|
||||
uint8_t sectorshift; /* 16 or 18 */
|
||||
uint8_t pageshift; /* 8 */
|
||||
uint16_t nsectors; /* 128 or 64 */
|
||||
uint8_t sectorshift; /* Log2 of sector size */
|
||||
uint8_t pageshift; /* Log2 of page size */
|
||||
uint16_t nsectors; /* Number of erase sectors */
|
||||
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
uint8_t flags; /* Buffered sector flags */
|
||||
uint16_t esectno; /* Erase sector number in the cache */
|
||||
FAR uint8_t *sector; /* Allocated sector data */
|
||||
#endif
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
@ -201,6 +236,14 @@ static int mx25rxx_erase_sector(struct mx25rxx_dev_s *priv, off_t sector);
|
||||
static int mx25rxx_erase_block(struct mx25rxx_dev_s *priv, off_t block);
|
||||
static int mx25rxx_erase_chip(struct mx25rxx_dev_s *priv);
|
||||
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
static int mx25rxx_flush_cache(struct mx25rxx_dev_s *priv);
|
||||
static FAR uint8_t *mx25rxx_read_cache(struct mx25rxx_dev_s *priv, off_t sector);
|
||||
static void mx25rxx_erase_cache(struct mx25rxx_dev_s *priv, off_t sector);
|
||||
static int mx25rxx_write_cache(FAR struct mx25rxx_dev_s *priv,
|
||||
FAR const uint8_t *buffer, off_t sector, size_t nsectors);
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* Private Functions
|
||||
******************************************************************************/
|
||||
@ -258,7 +301,7 @@ int mx25rxx_command_write(FAR struct qspi_dev_s *qspi, uint8_t cmd,
|
||||
struct qspi_cmdinfo_s cmdinfo;
|
||||
|
||||
finfo("CMD: %02x buflen: %lu 0x%x\n",
|
||||
cmd, (unsigned long)buflen, *(uint32_t*)buffer);
|
||||
cmd, (unsigned long)buflen, *(FAR uint32_t *)buffer);
|
||||
|
||||
cmdinfo.flags = QSPICMD_WRITEDATA;
|
||||
cmdinfo.addrlen = 0;
|
||||
@ -376,6 +419,15 @@ int mx25rxx_write_page(struct mx25rxx_dev_s *priv, FAR const uint8_t *buffer,
|
||||
address += pagesize;
|
||||
}
|
||||
|
||||
/* Wait for write operation to finish */
|
||||
|
||||
do
|
||||
{
|
||||
mx25rxx_read_status(priv);
|
||||
ret = priv->cmdbuf[0];
|
||||
}
|
||||
while ((ret & MX25R_SR_WIP) != 0);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -399,7 +451,7 @@ int mx25rxx_erase_sector(struct mx25rxx_dev_s *priv, off_t sector)
|
||||
|
||||
do
|
||||
{
|
||||
nxsig_usleep(50*1000);
|
||||
nxsig_usleep(50 * 1000);
|
||||
mx25rxx_read_status(priv);
|
||||
status = priv->cmdbuf[0];
|
||||
}
|
||||
@ -423,7 +475,7 @@ int mx25rxx_erase_block(struct mx25rxx_dev_s *priv, off_t block)
|
||||
|
||||
do
|
||||
{
|
||||
nxsig_usleep(300*1000);
|
||||
nxsig_usleep(300 * 1000);
|
||||
mx25rxx_read_status(priv);
|
||||
status = priv->cmdbuf[0];
|
||||
}
|
||||
@ -500,7 +552,9 @@ int mx25rxx_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
|
||||
{
|
||||
FAR struct mx25rxx_dev_s *priv = (FAR struct mx25rxx_dev_s *)dev;
|
||||
size_t blocksleft = nblocks;
|
||||
unsigned int sectorsPerBlock = (64*1024)>>priv->sectorshift;
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
|
||||
|
||||
@ -508,18 +562,46 @@ int mx25rxx_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
|
||||
|
||||
mx25rxx_lock(priv->qspi, false);
|
||||
|
||||
while (blocksleft-- > 0)
|
||||
{
|
||||
/* Erase each sector */
|
||||
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
mx25rxx_erase_cache(priv, startblock);
|
||||
#else
|
||||
mx25rxx_erase_sector(priv, startblock);
|
||||
#endif
|
||||
startblock++;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
/* Flush the last erase block left in the cache */
|
||||
|
||||
ret = mx25rxx_flush_cache(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
nblocks = ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* FIXME: use mx25rxx_erase_block in case CONFIG_MX25RXX_SECTOR512 is not configured
|
||||
* to speed up block erase.
|
||||
*/
|
||||
|
||||
unsigned int sectorsperblock = (64 * 1024) >> priv->sectorshift;
|
||||
while (blocksleft > 0)
|
||||
{
|
||||
/* Check if current block is aligned on 64k block to speed up erase */
|
||||
|
||||
if (((startblock & (sectorsPerBlock-1)) == 0) &&
|
||||
(blocksleft >= sectorsPerBlock))
|
||||
if (((startblock & (sectorsperblock - 1)) == 0) &&
|
||||
(blocksleft >= sectorsperblock))
|
||||
{
|
||||
/* Erase 64k block */
|
||||
|
||||
mx25rxx_erase_block(priv, startblock>>(16-priv->sectorshift));
|
||||
startblock += sectorsPerBlock;
|
||||
blocksleft -= sectorsPerBlock;
|
||||
mx25rxx_erase_block(priv, startblock >> (16 - priv->sectorshift));
|
||||
startblock += sectorsperblock;
|
||||
blocksleft -= sectorsperblock;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -530,6 +612,7 @@ int mx25rxx_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
|
||||
blocksleft --;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
mx25rxx_unlock(priv->qspi);
|
||||
|
||||
@ -539,17 +622,30 @@ int mx25rxx_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
|
||||
ssize_t mx25rxx_bread(FAR struct mtd_dev_s *dev, off_t startblock,
|
||||
size_t nblocks, FAR uint8_t *buf)
|
||||
{
|
||||
FAR struct mx25rxx_dev_s *mx_dev = (FAR struct mx25rxx_dev_s*)dev;
|
||||
#ifndef CONFIG_MX25RXX_SECTOR512
|
||||
FAR struct mx25rxx_dev_s *priv = (FAR struct mx25rxx_dev_s *)dev;
|
||||
#endif
|
||||
ssize_t nbytes;
|
||||
|
||||
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
|
||||
|
||||
nbytes = mx25rxx_read(dev, startblock << mx_dev->pageshift,
|
||||
nblocks << mx_dev->pageshift, buf);
|
||||
/* On this device, we can handle the block read just like the byte-oriented read */
|
||||
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
nbytes = mx25rxx_read(dev, startblock << MX25RXX_SECTOR512_SHIFT,
|
||||
nblocks << MX25RXX_SECTOR512_SHIFT, buf);
|
||||
if (nbytes > 0)
|
||||
{
|
||||
nbytes >>= mx_dev->pageshift;
|
||||
nbytes >>= MX25RXX_SECTOR512_SHIFT;
|
||||
}
|
||||
#else
|
||||
nbytes = mx25rxx_read(dev, startblock << priv->pageshift,
|
||||
nblocks << priv->pageshift, buf);
|
||||
if (nbytes > 0)
|
||||
{
|
||||
nbytes >>= priv->pageshift;
|
||||
}
|
||||
#endif
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
@ -558,7 +654,7 @@ ssize_t mx25rxx_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
|
||||
size_t nblocks, FAR const uint8_t *buf)
|
||||
{
|
||||
FAR struct mx25rxx_dev_s *priv = (FAR struct mx25rxx_dev_s *)dev;
|
||||
int ret = (int)nblocks;
|
||||
int ret;
|
||||
|
||||
finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks);
|
||||
|
||||
@ -566,12 +662,21 @@ ssize_t mx25rxx_bwrite(FAR struct mtd_dev_s *dev, off_t startblock,
|
||||
|
||||
mx25rxx_lock(priv->qspi, false);
|
||||
|
||||
#if defined(CONFIG_MX25RXX_SECTOR512)
|
||||
ret = mx25rxx_write_cache(priv, buf, startblock, nblocks);
|
||||
if (ret < 0)
|
||||
{
|
||||
ferr("ERROR: mx25rxx_write_cache failed: %d\n", ret);
|
||||
}
|
||||
|
||||
#else
|
||||
ret = mx25rxx_write_page(priv, buf, startblock << priv->pageshift,
|
||||
nblocks << priv->pageshift);
|
||||
if (ret < 0)
|
||||
{
|
||||
ferr("ERROR: mx25rxx_write_page failed: %d\n", ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
mx25rxx_unlock(priv->qspi);
|
||||
|
||||
@ -627,9 +732,16 @@ int mx25rxx_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
|
||||
* appear so.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
geo->blocksize = (1 << MX25RXX_SECTOR512_SHIFT);
|
||||
geo->erasesize = (1 << MX25RXX_SECTOR512_SHIFT);
|
||||
geo->neraseblocks = priv->nsectors <<
|
||||
(priv->sectorshift - MX25RXX_SECTOR512_SHIFT);
|
||||
#else
|
||||
geo->blocksize = (1 << priv->pageshift);
|
||||
geo->erasesize = (1 << priv->sectorshift);
|
||||
geo->neraseblocks = priv->nsectors;
|
||||
#endif
|
||||
ret = OK;
|
||||
|
||||
finfo("blocksize: %d erasesize: %d neraseblocks: %d\n",
|
||||
@ -702,11 +814,215 @@ int mx25rxx_readid(struct mx25rxx_dev_s *dev)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Public Functions
|
||||
******************************************************************************/
|
||||
/************************************************************************************
|
||||
* Name: mx25rxx_flush_cache
|
||||
************************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
static int mx25rxx_flush_cache(struct mx25rxx_dev_s *priv)
|
||||
{
|
||||
int ret = OK;
|
||||
|
||||
/* If the cache 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.
|
||||
*/
|
||||
|
||||
if (IS_DIRTY(priv) || IS_ERASED(priv))
|
||||
{
|
||||
off_t address;
|
||||
|
||||
/* Convert the erase sector number into a FLASH address */
|
||||
|
||||
address = (off_t)priv->esectno << priv->sectorshift;
|
||||
|
||||
/* Write entire erase block to FLASH */
|
||||
|
||||
ret = mx25rxx_write_page(priv, priv->sector, address, 1 << priv->sectorshift);
|
||||
if (ret < 0)
|
||||
{
|
||||
ferr("ERROR: mx25rxx_write_page failed: %d\n", ret);
|
||||
}
|
||||
|
||||
/* The cache is no long dirty and the FLASH is no longer erased */
|
||||
|
||||
CLR_DIRTY(priv);
|
||||
CLR_ERASED(priv);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_MX25RXX_SECTOR512 */
|
||||
|
||||
/************************************************************************************
|
||||
* Name: mx25rxx_read_cache
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
static FAR uint8_t *mx25rxx_read_cache(struct mx25rxx_dev_s *priv, off_t sector)
|
||||
{
|
||||
off_t esectno;
|
||||
int shift;
|
||||
int index;
|
||||
int ret;
|
||||
|
||||
/* Convert from the 512 byte sector to the erase sector size of the device. For
|
||||
* example, if the actual erase sector size is 4Kb (1 << 12), then we first
|
||||
* shift to the right by 3 to get the sector number in 4096 increments.
|
||||
*/
|
||||
|
||||
shift = priv->sectorshift - MX25RXX_SECTOR512_SHIFT;
|
||||
esectno = sector >> shift;
|
||||
finfo("sector: %ld esectno: %d (%d) shift=%d\n",
|
||||
sector, esectno, priv->esectno, shift);
|
||||
|
||||
/* Check if the requested erase block is already in the cache */
|
||||
|
||||
if (!IS_VALID(priv) || esectno != priv->esectno)
|
||||
{
|
||||
/* No.. Flush any dirty erase block currently in the cache */
|
||||
|
||||
ret = mx25rxx_flush_cache(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
ferr("ERROR: mx25rxx_flush_cache failed: %d\n", ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read the erase block into the cache */
|
||||
|
||||
ret = mx25rxx_read_byte(priv, priv->sector,
|
||||
(esectno << priv->sectorshift),
|
||||
(1 << priv->sectorshift));
|
||||
if (ret < 0)
|
||||
{
|
||||
ferr("ERROR: mx25rxx_read_byte failed: %d\n", ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Mark the sector as cached */
|
||||
|
||||
priv->esectno = esectno;
|
||||
|
||||
SET_VALID(priv); /* The data in the cache is valid */
|
||||
CLR_DIRTY(priv); /* It should match the FLASH contents */
|
||||
CLR_ERASED(priv); /* The underlying FLASH has not been erased */
|
||||
}
|
||||
|
||||
/* Get the index to the 512 sector in the erase block that holds the argument */
|
||||
|
||||
index = sector & ((1 << shift) - 1);
|
||||
|
||||
/* Return the address in the cache that holds this sector */
|
||||
|
||||
return &priv->sector[index << MX25RXX_SECTOR512_SHIFT];
|
||||
}
|
||||
#endif /* CONFIG_MX25RXX_SECTOR512 */
|
||||
|
||||
/************************************************************************************
|
||||
* Name: mx25rxx_erase_cache
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
static void mx25rxx_erase_cache(struct mx25rxx_dev_s *priv, off_t sector)
|
||||
{
|
||||
FAR uint8_t *dest;
|
||||
|
||||
/* First, make sure that the erase block containing the 512 byte sector is in
|
||||
* the cache.
|
||||
*/
|
||||
|
||||
dest = mx25rxx_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
|
||||
* is read into the cache and set here when we erase the block.
|
||||
*/
|
||||
|
||||
if (!IS_ERASED(priv))
|
||||
{
|
||||
off_t esectno = sector >> (priv->sectorshift - MX25RXX_SECTOR512_SHIFT);
|
||||
finfo("sector: %ld esectno: %d\n", sector, esectno);
|
||||
|
||||
DEBUGVERIFY(mx25rxx_erase_sector(priv, esectno));
|
||||
SET_ERASED(priv);
|
||||
}
|
||||
|
||||
/* Put the cached sector data into the erase state and mark the cache as dirty
|
||||
* (but don't update the FLASH yet. The caller will do that at a more optimal
|
||||
* time).
|
||||
*/
|
||||
|
||||
memset(dest, MX25RXX_ERASED_STATE, MX25RXX_SECTOR512_SIZE);
|
||||
SET_DIRTY(priv);
|
||||
}
|
||||
#endif /* CONFIG_MX25RXX_SECTOR512 */
|
||||
|
||||
/************************************************************************************
|
||||
* Name: mx25rxx_write_cache
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512
|
||||
static int mx25rxx_write_cache(FAR struct mx25rxx_dev_s *priv,
|
||||
FAR const uint8_t *buffer, off_t sector,
|
||||
size_t nsectors)
|
||||
{
|
||||
FAR uint8_t *dest;
|
||||
int ret;
|
||||
|
||||
for (; nsectors > 0; nsectors--)
|
||||
{
|
||||
/* First, make sure that the erase block containing 512 byte sector is in
|
||||
* memory.
|
||||
*/
|
||||
|
||||
dest = mx25rxx_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
|
||||
* is read into the cache and set here when we erase the sector.
|
||||
*/
|
||||
|
||||
if (!IS_ERASED(priv))
|
||||
{
|
||||
off_t esectno = sector >> (priv->sectorshift - MX25RXX_SECTOR512_SHIFT);
|
||||
finfo("sector: %ld esectno: %d\n", sector, esectno);
|
||||
|
||||
ret = mx25rxx_erase_sector(priv, esectno);
|
||||
if (ret < 0)
|
||||
{
|
||||
ferr("ERROR: mx25rxx_erase_sector failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SET_ERASED(priv);
|
||||
}
|
||||
|
||||
/* Copy the new sector data into cached erase block */
|
||||
|
||||
memcpy(dest, buffer, MX25RXX_SECTOR512_SIZE);
|
||||
SET_DIRTY(priv);
|
||||
|
||||
/* Set up for the next 512 byte sector */
|
||||
|
||||
finfo("address: %08x nbytes: %d 0x%04x\n",
|
||||
sector << MX25RXX_SECTOR512_SHIFT, MX25RXX_SECTOR512_SIZE,
|
||||
*(FAR uint32_t *)buffer);
|
||||
buffer += MX25RXX_SECTOR512_SIZE;
|
||||
sector++;
|
||||
}
|
||||
|
||||
/* Flush the last erase block left in the cache */
|
||||
|
||||
return mx25rxx_flush_cache(priv);
|
||||
}
|
||||
#endif /* CONFIG_MX25RXX_SECTOR512 */
|
||||
|
||||
/************************************************************************************
|
||||
* Public Functions
|
||||
************************************************************************************/
|
||||
|
||||
/************************************************************************************
|
||||
* Name: mx25rxx_initialize
|
||||
*
|
||||
* Description:
|
||||
@ -716,7 +1032,7 @@ int mx25rxx_readid(struct mx25rxx_dev_s *dev)
|
||||
* instances that can be bound to other functions (such as a block or
|
||||
* character driver front end).
|
||||
*
|
||||
******************************************************************************/
|
||||
************************************************************************************/
|
||||
|
||||
FAR struct mtd_dev_s *mx25rxx_initialize(FAR struct qspi_dev_s *qspi, bool unprotect)
|
||||
{
|
||||
@ -770,6 +1086,19 @@ FAR struct mtd_dev_s *mx25rxx_initialize(FAR struct qspi_dev_s *qspi, bool unpro
|
||||
goto exit_free_cmdbuf;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MX25RXX_SECTOR512 /* Simulate a 512 byte sector */
|
||||
/* Allocate a buffer for the erase block cache */
|
||||
|
||||
dev->sector = (FAR uint8_t *)QSPI_ALLOC(qspi, 1 << dev->sectorshift);
|
||||
if (dev->sector == NULL)
|
||||
{
|
||||
/* Allocation failed! Discard all of that work we just did and return NULL */
|
||||
|
||||
ferr("ERROR: Sector allocation failed\n");
|
||||
goto exit_free_cmdbuf;
|
||||
}
|
||||
#endif
|
||||
|
||||
mx25rxx_lock(dev->qspi, false);
|
||||
|
||||
/* Set MTD device in low power mode, with minimum dummy cycles */
|
||||
@ -779,11 +1108,12 @@ FAR struct mtd_dev_s *mx25rxx_initialize(FAR struct qspi_dev_s *qspi, bool unpro
|
||||
mx25rxx_read_status(dev);
|
||||
status = dev->cmdbuf[0];
|
||||
mx25rxx_read_configuration(dev);
|
||||
config = *(uint16_t*)(dev->cmdbuf);
|
||||
config = *(FAR uint16_t *)(dev->cmdbuf);
|
||||
|
||||
/* FIXME avoid compiler warnings in case info logs are disabled */
|
||||
(void)status;
|
||||
(void)config;
|
||||
/* Avoid compiler warnings in case info logs are disabled */
|
||||
|
||||
UNUSED(status);
|
||||
UNUSED(config);
|
||||
|
||||
finfo("device ready 0x%02x 0x%04x\n", status, config);
|
||||
|
||||
|
@ -1879,7 +1879,7 @@ static int smart_scan(FAR struct smart_struct_s *dev)
|
||||
{
|
||||
/* Read the next sector from the device */
|
||||
|
||||
ret = MTD_READ(dev->mtd, 0, sizeof(struct smart_sect_header_s),
|
||||
ret = MTD_READ(dev->mtd, readaddress, sizeof(struct smart_sect_header_s),
|
||||
(FAR uint8_t *) &header);
|
||||
if (ret != sizeof(struct smart_sect_header_s))
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user