More NAND stuff

This commit is contained in:
Gregory Nutt 2013-11-17 12:22:09 -06:00
parent 0e7a8668a5
commit d54832a942
10 changed files with 845 additions and 150 deletions

View File

@ -6079,4 +6079,5 @@
(2013-11-16).
* drivers/mtd/mtd_rawnand.c and include/nuttx/mtd/nand_raw.h: More
NAND support (2013-11-17).
* drivers/mtd/mtd_nandscheme.c: More NAND support (2013-11-17).

View File

@ -76,8 +76,7 @@
/* This type represents the state of the raw NAND MTD device. The struct
* nand_raw_s must appear at the beginning of the definition so that you can
* freely cast between pointers to struct mtd_dev_s, struct nand_raw_s, and
* struct sam_rawnand_s.
* freely cast between pointers to struct nand_raw_s and struct sam_rawnand_s.
*/
struct sam_rawnand_s
@ -92,14 +91,11 @@ struct sam_rawnand_s
/* MTD driver methods */
static int nand_erase(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks);
static ssize_t nand_bread(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, uint8_t *buf);
static ssize_t nand_bwrite(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, const uint8_t *buf);
static int nand_ioctl(struct mtd_dev_s *dev, int cmd,
unsigned long arg);
static int nand_eraseblock(struct nand_raw_s *raw, off_t block);
static int nand_readpage(struct nand_raw_s *raw, off_t block,
unsigned int page, void *data, void *spare);
static int nand_writepage(struct nand_raw_s *raw, off_t block,
unsigned int page, const void *data, const void *spare);
/****************************************************************************
* Private Data
@ -126,129 +122,82 @@ static struct sam_rawnand_s g_cs3nand;
****************************************************************************/
/****************************************************************************
* Name: nand_erase
* Name: nand_eraseblock
*
* Description:
* Erase several blocks, each of the size previously reported.
* Erases the specified block of the device.
*
* Input parameters:
* raw - Lower-half, raw NAND FLASH interface
* block - Number of the physical block to erase.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
*
****************************************************************************/
static int nand_erase(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks)
static int nand_eraseblock(struct nand_raw_s *raw, off_t block)
{
struct sam_rawnand_s *priv = (struct sam_rawnand_s *)dev;
/* The interface definition assumes that all erase blocks are the same size.
* If that is not true for this particular device, then transform the
* start block and nblocks as necessary.
*/
struct sam_rawnand_s *priv = (struct sam_rawnand_s *)raw;
DEBUGASSERT(raw);
#warning Missing logic
/* Erase the specified blocks and return status (OK or a negated errno) */
return OK;
return -ENOSYS;
}
/****************************************************************************
* Name: nand_bread
* Name: nand_readpage
*
* Description:
* Read the specified number of blocks into the user provided buffer.
* Reads the data and/or the spare areas of a page of a NAND FLASH into the
* provided buffers.
*
* Input parameters:
* raw - Lower-half, raw NAND FLASH interface
* block - Number of the block where the page to read resides.
* page - Number of the page to read inside the given block.
* data - Buffer where the data area will be stored.
* spare - Buffer where the spare area will be stored.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
*
****************************************************************************/
static ssize_t nand_bread(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, uint8_t *buf)
static int nand_readpage(struct nand_raw_s *raw, off_t block,
unsigned int page, void *data, void *spare)
{
struct sam_rawnand_s *priv = (struct sam_rawnand_s *)dev;
/* The interface definition assumes that all read/write blocks are the same size.
* If that is not true for this particular device, then transform the
* start block and nblocks as necessary.
*/
/* Read the specified blocks into the provided user buffer and return status
* (The positive, number of blocks actually read or a negated errno).
*/
struct sam_rawnand_s *priv = (struct sam_rawnand_s *)raw;
DEBUGASSERT(raw);
#warning Missing logic
return 0;
return -ENOSYS;
}
/****************************************************************************
* Name: nand_bwrite
* Name: nand_writepage
*
* Description:
* Write the specified number of blocks from the user provided buffer.
* Writes the data and/or the spare area of a page on a NAND FLASH chip.
*
* Input parameters:
* raw - Lower-half, raw NAND FLASH interface
* block - Number of the block where the page to write resides.
* page - Number of the page to write inside the given block.
* data - Buffer containing the data to be writting
* spare - Buffer conatining the spare data to be written.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
*
****************************************************************************/
static ssize_t nand_bwrite(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, const uint8_t *buf)
static int nand_writepage(struct nand_raw_s *raw, off_t block,
unsigned int page, const void *data,
const void *spare)
{
struct sam_rawnand_s *priv = (struct sam_rawnand_s *)dev;
/* The interface definition assumes that all read/write blocks are the same size.
* If that is not true for this particular device, then transform the
* start block and nblocks as necessary.
*/
/* Write the specified blocks from the provided user buffer and return status
* (The positive, number of blocks actually written or a negated errno)
*/
struct sam_rawnand_s *priv = (struct sam_rawnand_s *)raw;
DEBUGASSERT(raw);
#warning Missing logic
return 0;
}
/****************************************************************************
* Name: nand_ioctl
****************************************************************************/
static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
struct sam_rawnand_s *priv = (struct sam_rawnand_s *)dev;
int ret = -EINVAL; /* Assume good command with bad parameters */
switch (cmd)
{
case MTDIOC_GEOMETRY:
{
struct mtd_geometry_s *geo = (struct mtd_geometry_s *)arg;
if (geo)
{
/* Populate the geometry structure with information needed to know
* the capacity and how to access the device.
*
* NOTE: that the device is treated as though it where just an array
* of fixed size blocks. That is most likely not true, but the client
* will expect the device logic to do whatever is necessary to make it
* appear so.
*/
geo->blocksize = 512; /* Size of one read/write block */
geo->erasesize = 4096; /* Size of one erase block */
geo->neraseblocks = 1024; /* Number of erase blocks */
ret = OK;
}
}
break;
case MTDIOC_BULKERASE:
{
/* Erase the entire device */
ret = OK;
}
break;
case MTDIOC_XIPBASE:
default:
ret = -ENOTTY; /* Bad command */
break;
}
return ret;
return -ENOSYS;
}
/****************************************************************************
@ -259,14 +208,10 @@ static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg)
* Name: sam_nand_initialize
*
* Description:
* Create and initialize an NAND MTD device instance. MTD devices are
* not registered in the file system, but are created as instances that can
* be bound to other functions (such as a block or character driver front
* end).
*
* This MTD devices implements a RAW NAND interface: No ECC or sparing is
* Create and initialize an raw NAND device instance. This driver
* implements the RAW NAND interface: No software ECC or sparing is
* performed here. Those necessary NAND features are provided by common,
* higher level MTD layers found in drivers/mtd.
* higher level NAND MTD layers found in drivers/mtd.
*
* Input parameters:
* cs - Chip select number (in the event that multiple NAND devices
@ -366,13 +311,12 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
/* Initialize the device structure */
memset(priv, 0, sizeof(struct sam_rawnand_s));
priv->raw.mtd.erase = nand_erase;
priv->raw.mtd.bread = nand_bread;
priv->raw.mtd.bwrite = nand_bwrite;
priv->raw.mtd.ioctl = nand_ioctl;
priv->raw.cmdaddr = cmdaddr;
priv->raw.addraddr = addraddr;
priv->raw.dataaddr = dataaddr;
priv->raw.eraseblock = nand_eraseblock;
priv->raw.readpage = nand_readpage;
priv->raw.writepage = nand_writepage;
priv->cs = cs;
/* Initialize the NAND hardware */

View File

@ -67,19 +67,15 @@ extern "C" {
* Name: sam_nand_initialize
*
* Description:
* Create and initialize a raw NAND MTD device instance. MTD devices are
* not registered in the file system, but are created as instances that can
* be bound to other functions (such as a block or character driver front
* end).
*
* This MTD devices implements a RAW NAND interface: No ECC or sparing is
* Create and initialize an raw NAND device instance. This driver
* implements the RAW NAND interface: No software ECC or sparing is
* performed here. Those necessary NAND features are provided by common,
* higher level MTD layers found in drivers/mtd.
*
* higher level NAND MTD layers found in drivers/mtd.
*
* Input parameters:
* cs - Chip select number (in the event that multiple NAND devices
* are connected on-board).
*
*
* Returned value.
* On success a non-NULL pointer to an MTD device structure is returned;
* NULL is returned on a failure.

View File

@ -87,6 +87,12 @@ config ARCH_NAND_HWECC
if MTD_NAND
config MTD_NAND_BLOCKCHECK
bool "Block check"
default y
---help---
Enable support for bad block checking.
config MTD_NAND_MAXNUMBLOCKS
int "Max blocks"
default 1024

View File

@ -46,7 +46,8 @@ CSRCS += mtd_partition.c
endif
ifeq ($(CONFIG_MTD_NAND),y)
CSRCS += mtd_nand.c mtd_onfi.c mtd_rawnand.c mtd_nandmodel.c mtd_modeltab.c
CSRCS += mtd_nand.c mtd_onfi.c mtd_nandscheme.c mtd_nandraw.c
CSRCS += mtd_nandmodel.c mtd_modeltab.c
endif
ifeq ($(CONFIG_RAMMTD),y)

View File

@ -66,6 +66,10 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Success Values returned by the nand_checkblock function */
#define BADBLOCK 255
#define GOODBLOCK 254
/****************************************************************************
* Private Types
@ -74,6 +78,15 @@
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Sparing logic */
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
static int nand_checkblock(FAR struct nand_dev_s *nand, off_t block);
static int nand_devscan(FAR struct nand_dev_s *nand);
#else
# define nand_checkblock(n,b) (GOODBLOCK)
# define nand_devscan(n)
#endif
/* MTD driver methods */
@ -94,6 +107,136 @@ static int nand_ioctl(struct mtd_dev_s *dev, int cmd,
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: nand_checkblock
*
* Description:
* Read and check for a bad block.
*
* Input Parameters:
* nand - Pointer to a struct nand_dev_s instance.
* block - Number of block to check.
*
* Returned Value:
* Returns BADBLOCK if the given block of a nandflash device is bad;
* returns GOODBLOCK if the block is good; or returns negated errno
* value on any failure.
*
****************************************************************************/
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
static int nand_checkblock(FAR struct nand_dev_s *nand, off_t block)
{
uint8_t spare[CONFIG_MTD_NAND_MAXPAGESPARESIZE];
const struct nand_raw_s *raw;
const struct nand_model_s *model;
const struct nand_scheme_s *scheme;
uint8_t marker;
int ret;
DEBUGASSERT(nand && nand->raw);
/* Retrieve model scheme */
raw = nand->raw;
model = &raw->model;
scheme = nandmodel_getscheme(model);
/* Read spare area of first page of block */
ret = NAND_READPAGE(raw, block, 0, 0, spare);
if (ret < 0)
{
fdbg("ERROR: Cannot read page #0 of block #%d\n", block);
return ret;
}
nandscheme_readbadblockmarker(scheme, spare, &marker);
if (marker != 0xff)
{
return BADBLOCK;
}
/* Read spare area of second page of block */
ret = NAND_READPAGE(raw, block, 1, 0, spare);
if (ret < 0)
{
fdbg("ERROR: Cannot read page #1 of block #%d\n", block);
return ret;
}
nandscheme_readbadblockmarker(scheme, spare, &marker);
if (marker != 0xFF)
{
return BADBLOCK;
}
return GOODBLOCK;
}
#endif /* CONFIG_MTD_NAND_BLOCKCHECK */
/****************************************************************************
* Name: nand_devscan
*
* Description:
* Scans the device to retrieve or create block status information.
*
* Input Parameters:
* nand - Pointer to a struct nand_dev_s instance.
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
static int nand_devscan(FAR struct nand_dev_s *nand)
{
FAR const struct nand_raw_s *raw;
FAR const struct nand_model_s *model;
off_t numBlocks;
off_t block;
int ret;
DEBUGASSERT(nand && nand->raw);
/* Retrieve model information */
raw = nand->raw;
model = &raw->model;
numBlocks = nandmodel_getdevblocksize(model);
/* Initialize block statuses */
fvdbg("Retrieving bad block information ...\n");
/* Retrieve block status from their first page spare area */
for (block = 0; block < numBlocks; block++)
{
/* Read spare of first page */
ret = nand_checkblock(nand, block);
if (ret != GOODBLOCK)
{
if (ret == BADBLOCK)
{
fvdbg("Block %u is bad\n", (unsigned int)block);
}
else
{
fdbg("ERROR: Cannot retrieve info from block %u: %d\n",
(unsigned int)block, ret);
}
}
}
return OK;
}
#endif /* CONFIG_MTD_NAND_BLOCKCHECK */
/****************************************************************************
* Name: nand_erase
*
@ -105,7 +248,7 @@ static int nand_ioctl(struct mtd_dev_s *dev, int cmd,
static int nand_erase(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks)
{
struct nand_raw_s *priv = (struct nand_raw_s *)dev;
struct nand_raw_s *nand = (struct nand_raw_s *)dev;
/* The interface definition assumes that all erase blocks are the same size.
* If that is not true for this particular device, then transform the
@ -129,7 +272,7 @@ static int nand_erase(struct mtd_dev_s *dev, off_t startblock,
static ssize_t nand_bread(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, uint8_t *buf)
{
struct nand_raw_s *priv = (struct nand_raw_s *)dev;
struct nand_raw_s *nand = (struct nand_raw_s *)dev;
/* The interface definition assumes that all read/write blocks are the same size.
* If that is not true for this particular device, then transform the
@ -155,7 +298,7 @@ static ssize_t nand_bread(struct mtd_dev_s *dev, off_t startblock,
static ssize_t nand_bwrite(struct mtd_dev_s *dev, off_t startblock,
size_t nblocks, const uint8_t *buf)
{
struct nand_raw_s *priv = (struct nand_raw_s *)dev;
struct nand_raw_s *nand = (struct nand_raw_s *)dev;
/* The interface definition assumes that all read/write blocks are the same size.
* If that is not true for this particular device, then transform the
@ -176,7 +319,7 @@ static ssize_t nand_bwrite(struct mtd_dev_s *dev, off_t startblock,
static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
struct nand_raw_s *priv = (struct nand_raw_s *)dev;
struct nand_raw_s *nand = (struct nand_raw_s *)dev;
int ret = -EINVAL; /* Assume good command with bad parameters */
switch (cmd)
@ -246,7 +389,7 @@ static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg)
FAR struct mtd_dev_s *nand_initialize(FAR struct nand_raw_s *raw)
{
FAR struct nand_dev_s *priv;
FAR struct nand_dev_s *nand;
struct onfi_pgparam_s onfi;
int ret;
@ -338,8 +481,8 @@ FAR struct mtd_dev_s *nand_initialize(FAR struct nand_raw_s *raw)
/* Allocate an NAND MTD device structure */
priv = (FAR struct nand_dev_s *)kzalloc(sizeof(struct nand_dev_s));
if (!priv)
nand = (FAR struct nand_dev_s *)kzalloc(sizeof(struct nand_dev_s));
if (!nand)
{
fdbg("ERROR: Failed to allocate the NAND MTD device structure\n");
return NULL;
@ -347,15 +490,23 @@ FAR struct mtd_dev_s *nand_initialize(FAR struct nand_raw_s *raw)
/* Initialize the NAND MTD device structure */
priv->mtd.erase = nand_erase;
priv->mtd.bread = nand_bread;
priv->mtd.bwrite = nand_bwrite;
priv->mtd.ioctl = nand_ioctl;
priv->raw = raw;
nand->mtd.erase = nand_erase;
nand->mtd.bread = nand_bread;
nand->mtd.bwrite = nand_bwrite;
nand->mtd.ioctl = nand_ioctl;
nand->raw = raw;
#warning Missing logic
/* Scan the device for bad blocks */
ret = nand_devscan(nand);
if (ret < 0)
{
fdbg("ERROR: nandspare_intialize failed\n", ret);
kfree(nand);
return NULL;
}
/* Return the implementation-specific state structure as the MTD device */
return OK;
return &nand->mtd;
}

View File

@ -1,5 +1,5 @@
/****************************************************************************
* drivers/mtd/mtd_rawnand.c
* drivers/mtd/mtd_nandraw.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>

View File

@ -0,0 +1,384 @@
/****************************************************************************
* include/nuttx/mtd/nand_scheme.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* This logic was based largely on Atmel sample code with modifications for
* better integration with NuttX. The Atmel sample code has a BSD
* compatibile license that requires this copyright notice:
*
* Copyright (c) 2012, Atmel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the names NuttX nor Atmel nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/mtd/nand_config.h>
#include <sys/types.h>
#include <errno.h>
#include <assert.h>
#include <nuttx/mtd/nand_scheme.h>
/****************************************************************************
* Private Data
****************************************************************************/
/* Spare area placement scheme for 256 byte pages */
const struct nand_scheme_s g_nand_sparescheme256 =
{
/* Bad block marker is at position #5 */
5,
/* 3 ecc bytes */
3,
/* 4 extra bytes */
4,
/* Ecc bytes positions */
{0, 1, 2},
/* Extra bytes positions */
{3, 4, 6, 7}
};
/* Spare area placement scheme for 512 byte pages */
const struct nand_scheme_s g_nand_sparescheme512 =
{
/* Bad block marker is at position #5 */
5,
/* 6 ecc bytes */
6,
/* 8 extra bytes */
8,
/* Ecc bytes positions */
{0, 1, 2, 3, 6, 7},
/* Extra bytes positions */
{8, 9, 10, 11, 12, 13, 14, 15}
};
/* Spare area placement scheme for 2048 byte pages */
const struct nand_scheme_s g_nand_sparescheme2048 =
{
/* Bad block marker is at position #0 */
0,
/* 24 ecc bytes */
24,
/* 38 extra bytes */
38,
/* Ecc bytes positions */
{40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63},
/* Extra bytes positions */
{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39}
};
/* Spare area placement scheme for 4096 byte pages. */
const struct nand_scheme_s g_nand_sparescheme4096 =
{
/* Bad block marker is at position #0 */
0,
/* 48 ecc bytes */
48,
/* 78 extra bytes */
78,
/* Ecc bytes positions */
{ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
122, 123, 124, 125, 126, 127},
/* Extra bytes positions */
{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76, 77, 78, 79}
};
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nandscheme_readbadblockmarker
*
* Description:
* Reads the bad block marker inside a spare area buffer using the provided
* scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* marker Pointer to the variable to store the bad block marker.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_readbadblockmarker(FAR const struct nand_scheme_s *scheme,
FAR const uint8_t *spare,
FAR uint8_t *marker)
{
*marker = spare[scheme->bbpos];
}
/****************************************************************************
* Name: nandscheme_readbadblockmarker
*
* Description:
* Modifies the bad block marker inside a spare area, using the given
* scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* marker Bad block marker to write.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_writebadblockmarker(FAR const struct nand_scheme_s *scheme,
FAR uint8_t *spare, uint8_t marker)
{
spare[scheme->bbpos] = marker;
}
/****************************************************************************
* Name: nandscheme_readecc
*
* Description:
* Reads ECC information from a spare area using the provided scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* ecc ECC buffer.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_readecc(FAR const struct nand_scheme_s *scheme,
FAR const uint8_t *spare, FAR uint8_t *ecc)
{
int i;
for (i = 0; i < scheme->eccsize; i++)
{
ecc[i] = spare[scheme->eccbytepos[i]];
}
}
/****************************************************************************
* Name: nandscheme_writeecc
*
* Description:
* Writes ECC information in a spare area, using a particular scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* ecc ECC buffer.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_writeecc(FAR const struct nand_scheme_s *scheme,
FAR uint8_t *spare, FAR const uint8_t *ecc)
{
int i;
for (i = 0; i < scheme->eccsize; i++)
{
spare[scheme->eccbytepos[i]] = ecc[i];
}
}
/****************************************************************************
* Name: nandscheme_readextra
*
* Description:
* Reads extra bytes of information from a spare area, using the provided
* scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* extra Extra bytes buffer.
* size Number of extra bytes to read.
* offset Index where to read the first extra byte.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_readextra(FAR const struct nand_scheme_s *scheme,
FAR const uint8_t *spare, FAR void *extra,
unsigned int size, unsigned int offset)
{
DEBUGASSERT((size + offset) < scheme->nxbytes);
int i;
for (i = 0; i < size; i++)
{
((uint8_t *)extra)[i] = spare[scheme->xbytepos[i+offset]];
}
}
/****************************************************************************
* Name: nandscheme_readextra
*
* Description:
* Write extra bytes of information inside a spare area, using the provided
* scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* extra Extra bytes buffer.
* size Number of extra bytes to write.
* offset Index where to write the first extra byte.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_writeextra(FAR const struct nand_scheme_s *scheme,
FAR uint8_t *spare, FAR const void *extra,
unsigned int size, unsigned int offset)
{
DEBUGASSERT((size + offset) < scheme->nxbytes);
uint32_t i;
for (i = 0; i < size; i++) {
spare[scheme->xbytepos[i+offset]] = ((uint8_t *) extra)[i];
}
}
/****************************************************************************
* Name: nandscheme_readextra
*
* Description:
* Build a scheme instance for 4096 page size nand flash
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spareSize Size of spare area.
* offset Index where to write the first extra byte.
* size Number of extra bytes to write.
* offset Index where to write the first extra byte.
*
* Returned Values:
* OK on success; a negated errno value on failure.
*
****************************************************************************/
int nandscheme_build4086(FAR struct nand_scheme_s *scheme,
unsigned int spareSize, unsigned int eccOffset)
{
uint8_t eccsize = g_nand_sparescheme4096.eccsize;
int i;
if ((eccOffset + eccsize) > spareSize)
{
return -E2BIG;
}
scheme->bbpos = g_nand_sparescheme4096.bbpos;
scheme->eccsize = eccsize;
for (i = 0; i < eccsize; i++)
{
scheme->eccbytepos[i] = eccOffset + i;
}
scheme->nxbytes = spareSize - eccsize - 2;
for (i = 0; i < scheme->nxbytes; i++)
{
scheme->xbytepos[i] = 2 + i;
}
return OK;
};

View File

@ -100,26 +100,92 @@
#define READ_DATA16(raw) \
(*((volatile uint16_t *)raw->dataaddr))
/* struct nand_raw_s operations */
/****************************************************************************
* Name: NAND_ERASEBLOCK
*
* Description:
* Erases the specified block of the device.
*
* Input parameters:
* raw - Lower-half, raw NAND FLASH interface
* block - Number of the physical block to erase.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
*
****************************************************************************/
#define NAND_ERASEBLOCK(r,b) ((r)->eraseblock(r,b))
/****************************************************************************
* Name: NAND_READPAGE
*
* Description:
* Reads the data and/or the spare areas of a page of a NAND FLASH into the
* provided buffers.
*
* Input parameters:
* raw - Lower-half, raw NAND FLASH interface
* block - Number of the block where the page to read resides.
* page - Number of the page to read inside the given block.
* data - Buffer where the data area will be stored.
* spare - Buffer where the spare area will be stored.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
*
****************************************************************************/
#define NAND_READPAGE(r,b,p,d,s) ((r)->readpage(r,b,p,d,s))
/****************************************************************************
* Name: NAND_WRITEPAGE
*
* Description:
* Writes the data and/or the spare area of a page on a NAND FLASH chip.
*
* Input parameters:
* raw - Lower-half, raw NAND FLASH interface
* block - Number of the block where the page to write resides.
* page - Number of the page to write inside the given block.
* data - Buffer containing the data to be writting
* spare - Buffer conatining the spare data to be written.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
*
****************************************************************************/
#define NAND_WRITEPAGE(r,b,p,d,s) ((r)->writepage(r,b,p,d,s))
/****************************************************************************
* Public Types
****************************************************************************/
/* This type represents the visible portion of the lower-half, raw NAND MTD
* device. Rules:
*
* 1. The struct mtd_dev_s must appear at the beginning of the definition so
* that you can freely cast between pointers to struct mtd_dev_s and struct
* nand_raw_s.
* 2. The lower-half driver may freely append additional information after
* this required header information.
* device. The lower-half driver may freely append additional information
* after this required header information.
*/
struct nand_raw_s
{
struct mtd_dev_s mtd; /* Externally visible part of the driver */
/* NAND data */
struct nand_model_s model; /* The NAND model storage */
uintptr_t cmdaddr; /* NAND command address base */
uintptr_t addraddr; /* NAND address address base */
uintptr_t dataaddr; /* NAND data address */
/* NAND operations */
CODE int (*eraseblock)(FAR struct nand_raw_s *raw, off_t block);
CODE int (*readpage)(FAR struct nand_raw_s *raw, off_t block,
unsigned int page, FAR void *data, FAR void *spare);
CODE int (*writepage)(FAR struct nand_raw_s *raw, off_t block,
unsigned int page, FAR const void *data,
FAR const void *spare);
};
/****************************************************************************

View File

@ -97,6 +97,152 @@ EXTERN const struct nand_scheme_s g_nand_sparescheme4096;
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: nandscheme_readbadblockmarker
*
* Description:
* Reads the bad block marker inside a spare area buffer using the provided
* scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* marker Pointer to the variable to store the bad block marker.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_readbadblockmarker(FAR const struct nand_scheme_s *scheme,
FAR const uint8_t *spare,
FAR uint8_t *marker);
/****************************************************************************
* Name: nandscheme_readbadblockmarker
*
* Description:
* Modifies the bad block marker inside a spare area, using the given
* scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* marker Bad block marker to write.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_writebadblockmarker(FAR const struct nand_scheme_s *scheme,
FAR uint8_t *spare, uint8_t marker);
/****************************************************************************
* Name: nandscheme_readecc
*
* Description:
* Reads ECC information from a spare area using the provided scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* ecc ECC buffer.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_readecc(FAR const struct nand_scheme_s *scheme,
FAR const uint8_t *spare, FAR uint8_t *ecc);
/****************************************************************************
* Name: nandschem_writeecc
*
* Description:
* Writes ECC information in a spare area, using a particular scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* ecc ECC buffer.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_writeecc(FAR const struct nand_scheme_s *scheme,
FAR uint8_t *spare, FAR const uint8_t *ecc);
/****************************************************************************
* Name: nandscheme_readextra
*
* Description:
* Reads extra bytes of information from a spare area, using the provided
* scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* extra Extra bytes buffer.
* size Number of extra bytes to read.
* offset Index where to read the first extra byte.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_readextra(FAR const struct nand_scheme_s *scheme,
FAR const uint8_t *spare, FAR void *extra,
unsigned int size, unsigned int offset);
/****************************************************************************
* Name: nandscheme_readextra
*
* Description:
* Write extra bytes of information inside a spare area, using the provided
* scheme.
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spare Spare area buffer.
* extra Extra bytes buffer.
* size Number of extra bytes to write.
* offset Index where to write the first extra byte.
*
* Returned Values:
* None
*
****************************************************************************/
void nandscheme_writeextra(FAR const struct nand_scheme_s *scheme,
FAR uint8_t *spare, FAR const void *extra,
unsigned int size, unsigned int offset);
/****************************************************************************
* Name: nandscheme_readextra
*
* Description:
* Build a scheme instance for 4096 page size nand flash
*
* Input Parameters:
* scheme Pointer to a nand_scheme_s instance.
* spareSize Size of spare area.
* offset Index where to write the first extra byte.
* size Number of extra bytes to write.
* offset Index where to write the first extra byte.
*
* Returned Values:
* OK on success; a negated errno value on failure.
*
****************************************************************************/
int nandscheme_build4086(FAR struct nand_scheme_s *scheme,
unsigned int spareSize, unsigned int eccOffset);
#undef EXTERN
#ifdef __cplusplus
}