diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2013-11-17 12:22:09 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2013-11-17 12:22:09 -0600 |
commit | dd05b6c29749b2cc98f045cb057a1836a93cf4ca (patch) | |
tree | 0bd5c767821cf9f40d532b6f57aa10c720a02268 /nuttx/drivers/mtd | |
parent | c871a0b7e2edcfb6957ed431e5ad84f43a28aa3d (diff) | |
download | px4-nuttx-dd05b6c29749b2cc98f045cb057a1836a93cf4ca.tar.gz px4-nuttx-dd05b6c29749b2cc98f045cb057a1836a93cf4ca.tar.bz2 px4-nuttx-dd05b6c29749b2cc98f045cb057a1836a93cf4ca.zip |
More NAND stuff
Diffstat (limited to 'nuttx/drivers/mtd')
-rw-r--r-- | nuttx/drivers/mtd/Kconfig | 6 | ||||
-rw-r--r-- | nuttx/drivers/mtd/Make.defs | 3 | ||||
-rwxr-xr-x | nuttx/drivers/mtd/mtd_nand.c | 179 | ||||
-rwxr-xr-x | nuttx/drivers/mtd/mtd_nandraw.c (renamed from nuttx/drivers/mtd/mtd_rawnand.c) | 2 | ||||
-rw-r--r-- | nuttx/drivers/mtd/mtd_nandscheme.c | 384 |
5 files changed, 558 insertions, 16 deletions
diff --git a/nuttx/drivers/mtd/Kconfig b/nuttx/drivers/mtd/Kconfig index 1097897f0..687456972 100644 --- a/nuttx/drivers/mtd/Kconfig +++ b/nuttx/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/nuttx/drivers/mtd/Make.defs b/nuttx/drivers/mtd/Make.defs index 1d83cf5f9..feabf468f 100644 --- a/nuttx/drivers/mtd/Make.defs +++ b/nuttx/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/nuttx/drivers/mtd/mtd_nand.c b/nuttx/drivers/mtd/mtd_nand.c index b0bf9826d..ada091b86 100755 --- a/nuttx/drivers/mtd/mtd_nand.c +++ b/nuttx/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 */ @@ -95,6 +108,136 @@ static int nand_ioctl(struct mtd_dev_s *dev, int cmd, ****************************************************************************/ /**************************************************************************** + * 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 * * Description: @@ -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/nuttx/drivers/mtd/mtd_rawnand.c b/nuttx/drivers/mtd/mtd_nandraw.c index 92e4d82b6..012e470cc 100755 --- a/nuttx/drivers/mtd/mtd_rawnand.c +++ b/nuttx/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 <gnutt@nuttx.org> diff --git a/nuttx/drivers/mtd/mtd_nandscheme.c b/nuttx/drivers/mtd/mtd_nandscheme.c new file mode 100644 index 000000000..13df5d584 --- /dev/null +++ b/nuttx/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 <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; +}; |