diff --git a/ChangeLog b/ChangeLog index fc411dfaf9a..4a414666d39 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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). diff --git a/arch/arm/src/sama5/sam_nand.c b/arch/arm/src/sama5/sam_nand.c index d62741b8951..00e61767bec 100644 --- a/arch/arm/src/sama5/sam_nand.c +++ b/arch/arm/src/sama5/sam_nand.c @@ -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 */ diff --git a/arch/arm/src/sama5/sam_nand.h b/arch/arm/src/sama5/sam_nand.h index b2ef62a8aae..2bef90554fb 100644 --- a/arch/arm/src/sama5/sam_nand.h +++ b/arch/arm/src/sama5/sam_nand.h @@ -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. diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 1097897f085..6874569722c 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -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 diff --git a/drivers/mtd/Make.defs b/drivers/mtd/Make.defs index 1d83cf5f98b..feabf468f59 100644 --- a/drivers/mtd/Make.defs +++ b/drivers/mtd/Make.defs @@ -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) diff --git a/drivers/mtd/mtd_nand.c b/drivers/mtd/mtd_nand.c index b0bf9826d45..ada091b86b9 100755 --- a/drivers/mtd/mtd_nand.c +++ b/drivers/mtd/mtd_nand.c @@ -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; } diff --git a/drivers/mtd/mtd_rawnand.c b/drivers/mtd/mtd_nandraw.c similarity index 99% rename from drivers/mtd/mtd_rawnand.c rename to drivers/mtd/mtd_nandraw.c index 92e4d82b63c..012e470cc81 100755 --- a/drivers/mtd/mtd_rawnand.c +++ b/drivers/mtd/mtd_nandraw.c @@ -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 diff --git a/drivers/mtd/mtd_nandscheme.c b/drivers/mtd/mtd_nandscheme.c new file mode 100644 index 00000000000..13df5d584b1 --- /dev/null +++ b/drivers/mtd/mtd_nandscheme.c @@ -0,0 +1,384 @@ +/**************************************************************************** + * include/nuttx/mtd/nand_scheme.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 +#include + +#include +#include +#include + +#include + +/**************************************************************************** + * 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; +}; diff --git a/include/nuttx/mtd/nand_raw.h b/include/nuttx/mtd/nand_raw.h index f8ff3dd9a69..193459af7c5 100644 --- a/include/nuttx/mtd/nand_raw.h +++ b/include/nuttx/mtd/nand_raw.h @@ -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); }; /**************************************************************************** diff --git a/include/nuttx/mtd/nand_scheme.h b/include/nuttx/mtd/nand_scheme.h index 9c7ad069ad1..5bbd788f318 100644 --- a/include/nuttx/mtd/nand_scheme.h +++ b/include/nuttx/mtd/nand_scheme.h @@ -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 }