diff --git a/ChangeLog b/ChangeLog index 72b68adf5a..13d95bb900 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6075,4 +6075,6 @@ (2013-11-16). * drivers/mtd/mtd_modeltab.c: Further NAND support (still incomplete). (2013-11-16). + * drivers/mtd/mtd_nandmodel.c: More NAND support (same story). + (2013-11-16). diff --git a/arch/arm/src/sama5/sam_nand.c b/arch/arm/src/sama5/sam_nand.c index 2aca6ad8f2..03b8b8d184 100644 --- a/arch/arm/src/sama5/sam_nand.c +++ b/arch/arm/src/sama5/sam_nand.c @@ -58,6 +58,7 @@ #include #include #include +#include #include @@ -71,18 +72,19 @@ * Private Types ****************************************************************************/ -/* This type represents the state of the NAND MTD device. The struct +/* This type represents the state of the raw NAND MTD device. 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_dev_s. + * freely cast between pointers to struct mtd_dev_s and struct nand_raw_s. */ -struct nand_dev_s +struct nand_raw_s { - struct mtd_dev_s mtd; /* Externally visible part of the driver */ - uint8_t cs; /* Chip select number (0..3) */ - uintptr_t cmdaddr; /* NAND command address base */ - uintptr_t addraddr; /* NAND address address base */ - uintptr_t dataaddr; /* NAND data address */ + struct mtd_dev_s mtd; /* Externally visible part of the driver */ + uint8_t cs; /* Chip select number (0..3) */ + struct nand_model_s model; /* The NAND model */ + uintptr_t cmdaddr; /* NAND command address base */ + uintptr_t addraddr; /* NAND address address base */ + uintptr_t dataaddr; /* NAND data address */ }; /**************************************************************************** @@ -108,16 +110,16 @@ static int nand_ioctl(struct mtd_dev_s *dev, int cmd, */ #ifdef CONFIG_SAMA5_EBICS0_NAND -static struct nand_dev_s g_cs0nand; +static struct nand_raw_s g_cs0nand; #endif #ifdef CONFIG_SAMA5_EBICS1_NAND -static struct nand_dev_s g_cs1nand; +static struct nand_raw_s g_cs1nand; #endif #ifdef CONFIG_SAMA5_EBICS2_NAND -static struct nand_dev_s g_cs2nand; +static struct nand_raw_s g_cs2nand; #endif #ifdef CONFIG_SAMA5_EBICS3_NAND -static struct nand_dev_s g_cs3nand; +static struct nand_raw_s g_cs3nand; #endif /**************************************************************************** @@ -135,7 +137,7 @@ static struct nand_dev_s g_cs3nand; static int nand_erase(struct mtd_dev_s *dev, off_t startblock, size_t nblocks) { - struct nand_dev_s *priv = (struct nand_dev_s *)dev; + struct nand_raw_s *priv = (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 @@ -159,7 +161,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_dev_s *priv = (struct nand_dev_s *)dev; + struct nand_raw_s *priv = (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 @@ -185,7 +187,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_dev_s *priv = (struct nand_dev_s *)dev; + struct nand_raw_s *priv = (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 @@ -206,7 +208,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_dev_s *priv = (struct nand_dev_s *)dev; + struct nand_raw_s *priv = (struct nand_raw_s *)dev; int ret = -EINVAL; /* Assume good command with bad parameters */ switch (cmd) @@ -279,7 +281,8 @@ static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg) struct mtd_dev_s *sam_nand_initialize(int cs) { - struct nand_dev_s *priv; + struct nand_raw_s *priv; + struct mtd_s *mtd; uintptr_t cmdaddr; uintptr_t addraddr; uintptr_t dataaddr; @@ -363,7 +366,7 @@ struct mtd_dev_s *sam_nand_initialize(int cs) /* Initialize the device structure */ - memset(priv, 0, sizeof(struct nand_dev_s)); + memset(priv, 0, sizeof(struct nand_raw_s)); priv->mtd.erase = nand_erase; priv->mtd.bread = nand_bread; priv->mtd.bwrite = nand_bwrite; @@ -384,20 +387,21 @@ struct mtd_dev_s *sam_nand_initialize(int cs) return NULL; } - /* Probe the NAND part */ + /* Probe the NAND part. On success, an MTD interface that wraps + * our raw NAND interface is returned. + */ - ret = nand_initialize(&priv->mtd, cmdaddr, addraddr, dataaddr); - if (ret < 0) + mtd = nand_initialize(&priv->mtd, cmdaddr, addraddr, dataaddr, &priv->model); + if (!mtd) { fdbg("ERROR: CS%d nand_initialize failed: %d at (%p, %p, %p)\n", - cs, ret, - (FAR void *)cmdaddr, (FAR void *)addraddr, (FAR void *)dataaddr); + cs, (FAR void *)cmdaddr, (FAR void *)addraddr, (FAR void *)dataaddr); return NULL; } #warning Missing logic - /* Return the implementation-specific state structure as the MTD device */ + /* Return the MTD wrapper interface as the MTD device */ - return &priv->mtd; + return mtd; } diff --git a/drivers/mtd/Make.defs b/drivers/mtd/Make.defs index 359516641a..e5e4a3e6c5 100644 --- a/drivers/mtd/Make.defs +++ b/drivers/mtd/Make.defs @@ -46,7 +46,7 @@ CSRCS += mtd_partition.c endif ifeq ($(CONFIG_MTD_NAND),y) -CSRCS += mtd_nand.c mtd_onfi.c mtd_modeltab.c +CSRCS += mtd_nand.c mtd_onfi.c 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 2df0a0d800..f94b0bae80 100755 --- a/drivers/mtd/mtd_nand.c +++ b/drivers/mtd/mtd_nand.c @@ -51,8 +51,12 @@ #include #include #include +#include #include +#include +#include +#include #include #include #include @@ -70,6 +74,17 @@ * Private Function Prototypes ****************************************************************************/ +/* 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); + /**************************************************************************** * Private Data ****************************************************************************/ @@ -78,6 +93,132 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: nand_erase + * + * Description: + * Erase several blocks, each of the size previously reported. + * + ****************************************************************************/ + +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; + + /* 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. + */ +#warning Missing logic + + /* Erase the specified blocks and return status (OK or a negated errno) */ + + return OK; +} + +/**************************************************************************** + * Name: nand_bread + * + * Description: + * Read the specified number of blocks into the user provided buffer. + * + ****************************************************************************/ + +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; + + /* 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). + */ +#warning Missing logic + + return 0; +} + +/**************************************************************************** + * Name: nand_bwrite + * + * Description: + * Write the specified number of blocks from the user provided buffer. + * + ****************************************************************************/ + +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; + + /* 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) + */ +#warning Missing logic + + return 0; +} + +/**************************************************************************** + * Name: nand_ioctl + ****************************************************************************/ + +static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg) +{ + struct nand_raw_s *priv = (struct nand_raw_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; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -93,18 +234,24 @@ * cmdaddr - NAND command address base * addraddr - NAND address address base * dataaddr - NAND data address + * model - A pointer to the model data (probably in the raw MTD + * driver instance. * * Returned value. - * OK is returned on success; A negated errno value is returned on failure. + * A non-NULL MTD driver intstance is returned on success. NULL is + * returned on any failaure. * ****************************************************************************/ -int nand_initialize(FAR struct mtd_dev_s *raw, - uintptr_t cmdaddr, uintptr_t addraddr, uintptr_t dataaddr) +FAR struct mtd_dev_s *nand_initialize(FAR struct mtd_dev_s *raw, + uintptr_t cmdaddr, uintptr_t addraddr, + uintptr_t dataaddr, + FAR struct nand_model_s *model) { + FAR struct nand_dev_s *priv; struct onfi_pgparam_s onfi; - struct nand_model_s model; bool compatible; + bool havemodel = false; int ret; fvdbg("cmdaddr=%p addraddr=%p dataaddr=%p\n", @@ -116,7 +263,7 @@ int nand_initialize(FAR struct mtd_dev_s *raw, { fdbg("ERROR: No NAND device detected at: %p %p %p\n", (FAR void *)cmdaddr, (FAR void *)addraddr, (FAR void *)dataaddr); - return -ENODEV; + return NULL; } /* Read the ONFI page parameters from the NAND device */ @@ -136,49 +283,69 @@ int nand_initialize(FAR struct mtd_dev_s *raw, /* Construct the NAND model structure */ - model.devid = onfi.manufacturer; - model.options = onfi.buswidth ? NANDMODEL_DATAWIDTH16 : NANDMODEL_DATAWIDTH8; - model.pagesize = onfi.pagesize; - model.sparesize = onfi.sparesize; + model->devid = onfi.manufacturer; + model->options = onfi.buswidth ? NANDMODEL_DATAWIDTH16 : NANDMODEL_DATAWIDTH8; + model->pagesize = onfi.pagesize; + model->sparesize = onfi.sparesize; - size = (uint64_t)onfi.pagesperblock * - (uint64_t)onfi.blocksperlun * - (uint64_t)onfi.pagesize; + size = (uint64_t)onfi.pagesperblock * + (uint64_t)onfi.blocksperlun * + (uint64_t)onfi.pagesize; DEBUGASSERT(size < (uint64_t)(1 << 21)); - model.devsize = (uint16_t)(size >> 20); + model->devsize = (uint16_t)(size >> 20); - size = (uint64_t)onfi.pagesperblock * - (uint64_t)onfi.pagesize; + size = (uint64_t)onfi.pagesperblock * + (uint64_t)onfi.pagesize; DEBUGASSERT(size < (uint64_t)(1 << 11)); - model.blocksize = (uint16_t)(size >> 10); + model->blocksize = (uint16_t)(size >> 10); switch (onfi.pagesize) { case 256: - model.scheme = &g_nand_sparescheme256; + model->scheme = &g_nand_sparescheme256; break; case 512: - model.scheme = &g_nand_sparescheme512; + model->scheme = &g_nand_sparescheme512; break; case 2048: - model.scheme = &g_nand_sparescheme2048; + model->scheme = &g_nand_sparescheme2048; break; case 4096: - model.scheme = &g_nand_sparescheme4096; + model->scheme = &g_nand_sparescheme4096; break; } + havemodel = true; + /* Disable any internal, embedded ECC function */ (void)onfi_embeddedecc(&onfi, cmdaddr, addraddr, dataaddr, false); } -#warning Missing logic + /* Allocate an NAND MTD device structure */ + + priv = (FAR struct nand_dev_s *)kzalloc(sizeof(struct nand_dev_s)); + if (!priv) + { + fdbg("ERROR: Failed to allocate the NAND MTD device structure\n"); + return NULL; + } + + /* 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; + priv->model = model; + + #warning Missing logic /* Return the implementation-specific state structure as the MTD device */ diff --git a/drivers/mtd/mtd_nandmodel.c b/drivers/mtd/mtd_nandmodel.c new file mode 100644 index 0000000000..643804fa47 --- /dev/null +++ b/drivers/mtd/mtd_nandmodel.c @@ -0,0 +1,510 @@ +/**************************************************************************** + * drivers/mtd/mtd_nand.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) 2011, 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 +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nandmodel_find + * + * Description: + * Looks for a nand_model_s corresponding to the given ID inside a list of + * model. If found, the model variable is filled with the correct values. + * + * Input Parameters: + * modeltab List of nand_model_s instances. + * size Number of models in list. + * chipid Identifier returned by the Nand(id1|(id2<<8)|(id3<<16)|(id4<<24)). + * model nand_model_s instance to update with the model parameters. + * + * Returned Values: + * OK is returned on success; -ENODEV is returned on failure. + * + ****************************************************************************/ + +int nandmodel_find(FAR const struct nand_model_s *modeltab, size_t size, + uint32_t chipid, FAR struct nand_model_s *model) +{ + uint8_t id2; + uint8_t id4; + bool found = false; + int i; + + id2 = (uint8_t)(chipid>>8); + id4 = (uint8_t)(chipid>>24); + + fvdbg("NAND ID is 0x%08x\n", (int)chipid); + + for (i = 0; i < size; i++) + { + if (modeltab[i].devid == id2) + { + found = true; + + if (model) + { + memcpy(model, &modeltab[i], sizeof(struct nand_model_s)); + + if (model->blocksize == 0 || model->pagesize == 0) + { + fvdbg("Fetch from ID4(0x%.2x):\n", id4); + + /* Fetch from the extended ID4 + * ID4 D5 D4 BlockSize || D1 D0 PageSize + * 0 0 64K || 0 0 1K + * 0 1 128K || 0 1 2K + * 1 0 256K || 1 0 4K + * 1 1 512K || 1 1 8k + */ + + switch (id4 & 0x03) + { + case 0x00: + model->pagesize = 1024; + break; + + case 0x01: + model->pagesize = 2048; + break; + + case 0x02: + model->pagesize = 4096; + break; + + case 0x03: + model->pagesize = 8192; + break; + } + + switch (id4 & 0x30) + { + case 0x00: + model->blocksize = 64; + break; + + case 0x10: + model->blocksize = 128; + break; + + case 0x20: + model->blocksize = 256; + break; + + case 0x30: + model->blocksize = 512; + break; + } + } + } + + fvdbg("NAND Model found:\n"); + fvdbg(" devid: 0x%02x\n", model->devid); + fvdbg(" devsize: %d\n", model->devsize); + fvdbg(" blocksize: %d\n", model->blocksize); + fvdbg(" pagesize: %d\n", model->pagesize); + fvdbg(" options: 0x%02x\n", model->options); + break; + } + } + + /* Check if chip has been detected */ + + return found ? OK : -ENODEV; +} + +/**************************************************************************** + * Name: nandmodel_translate + * + * Description: + * Translates address/size access of a nand_model_s to block, page and + * offset values. The values are stored in the provided variables if their + * pointer is not 0. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * address Access address. + * size Access size in bytes. + * block Stores the first accessed block number. + * page Stores the first accessed page number inside the first block. + * offset Stores the byte offset inside the first accessed page. + * + * Returned Values: + * OK on success; -EPIPE on failure. + * + ****************************************************************************/ + +int nandmodel_translate(FAR const struct nand_model_s *model, off_t address, + size_t size, FAR off_t *block, off_t *page, + off_t *offset) +{ + size_t blocksize; + size_t pagesize; + off_t tmpblock; + off_t tmppage; + off_t tmpoffset; + + /* Check that access is not too big */ + + if ((address + size) > nandmodel_getdevbytesize(model)) + { + + fvdbg("nandmodel_translate: out-of-bounds access.\n"); + return -ESPIPE; + } + + /* Get Nand info */ + + blocksize = nandmodel_getblocksize(model); + pagesize = nandmodel_getpagesize(model); + + /* Translate address */ + + tmpblock = address / blocksize; + address -= tmpblock * blocksize; + + tmppage = address / pagesize; + address -= tmppage * pagesize; + tmpoffset = address; + + /* Save results */ + + if (block) + { + *block = tmpblock; + } + + if (page) + { + *page = tmppage; + } + + if (offset) + { + *offset = tmpoffset; + } + + return OK; +} + +/**************************************************************************** + * Name: nandmodel_getscheme + * + * Description: + * Returns the spare area placement scheme used by a particular nandflash + * model. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Spare placement scheme + * + ****************************************************************************/ + +FAR const struct nand_dev_scheme_s * +nandmodel_getscheme(FAR const struct nand_model_s *model) +{ + return model->scheme; +} + +/**************************************************************************** + * Name: nandmodel_getdevid + * + * Description: + * Returns the device ID of a particular NAND FLASH model. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Device ID + * + ****************************************************************************/ + +uint8_t nandmodel_getdevid(FAR const struct nand_model_s *model) +{ + return model->devid; +} + +/**************************************************************************** + * Name: nandmodel_getdevblocksize + * + * Description: + * Returns the number of blocks in the entire device. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Number of blocks in the device + * + ****************************************************************************/ + +off_t nandmodel_getdevblocksize(FAR const struct nand_model_s *model) +{ + return (1024 * model->devsize) / model->blocksize; +} + +/**************************************************************************** + * Name: nandmodel_getdevpagesize + * + * Description: + * Returns the number of pages in the entire device. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Number of pages in the device + * + ****************************************************************************/ + +size_t nandmodel_getdevpagesize(FAR const struct nand_model_s *model) +{ + return (uint32_t)nandmodel_getdevblocksize(model) //* 8 // HACK + * nandmodel_getblocksize(model); +} + +/**************************************************************************** + * Name: nandmodel_getdevbytesize + * + * Description: + * Returns the size of the whole device in bytes (this does not include + * the size of the spare zones). + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Size of the device in bytes + * + ****************************************************************************/ + +uint64_t nandmodel_getdevbytesize(FAR const struct nand_model_s *model) +{ + return ((uint64_t)model->devsize) << 20; +} + +/**************************************************************************** + * Name: nandmodel_getdevmbsize + * + * Description: + * Returns the size of the whole device in Mega bytes (this does not + * include the size of the spare zones). + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * size of the device in MB. + * + ****************************************************************************/ + +uint32_t nandmodel_getdevmbsize(FAR const struct nand_model_s *model) +{ + return ((uint32_t)model->devsize); +} + +/**************************************************************************** + * Name: nandmodel_getblockpagesize + * + * Description: + * Returns the number of pages in one single block of a device. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Block size in pages + * + ****************************************************************************/ + +unsigned int nandmodel_getblockpagesize(FAR const struct nand_model_s *model) +{ + return model->blocksize * 1024 / model->pagesize; +} + +/**************************************************************************** + * Name: nandmodel_getblockbytesize + * + * Description: + * Returns the size in bytes of one single block of a device. This does not + * take into account the spare zones size. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Block size in bytes + * + ****************************************************************************/ + +unsigned int nandmodel_getblockbytesize(FAR const struct nand_model_s *model) +{ + return model->blocksize * 1024; +} + +/**************************************************************************** + * Name: nandmodel_getpagesize + * + * Description: + * Returns the size of the data area of a page in bytes. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Size of data area in bytes + * + ****************************************************************************/ + +unsigned int nandmodel_getpagesize(FAR const struct nand_model_s *model) +{ + return model->pagesize; +} + +/**************************************************************************** + * Name: nandmodel_getsparesize + * + * Description: + * Returns the size of the spare area of a page in bytes. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * size of spare area in bytes + * + ****************************************************************************/ + +unsigned int nandmodel_getsparesize(FAR const struct nand_model_s *model) +{ + if (model->sparesize) + { + return model->sparesize; + } + else + { + return (model->pagesize >> 5); /* Spare size is 16/512 of data size */ + } +} + +/**************************************************************************** + * Name: nandmodel_getbuswidth + * + * Description: + * Returns the number of bits used by the data bus of a NAND FLASH device. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * data width + * + ****************************************************************************/ + +unsigned int nandmodel_getbuswidth(FAR const struct nand_model_s *model) +{ + return (model->options & NANDMODEL_DATAWIDTH16)? 16 : 8; +} + +/**************************************************************************** + * Name: nandmodel_havesmallblocks + * + * Description: + * Returns true if the given NAND FLASH model uses the "small blocks/pages" + * command set; otherwise returns false. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Returns true if the given NAND FLASH model uses the "small blocks/pages" + * command set; otherwise returns false. + * + ****************************************************************************/ + +bool nandmodel_havesmallblocks(FAR const struct nand_model_s *model) +{ + return (model->pagesize <= 512 )? 1: 0; +} + +/**************************************************************************** + * Name: nandmodel_havecopyback + * + * Description: + * Returns true if the device supports the copy-back operation. Otherwise + * returns false. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Returns true if the device supports the copy-back operation. Otherwise + * returns false. + * + ****************************************************************************/ + +bool nandmodel_havecopyback(FAR const struct nand_model_s *model) +{ + return ((model->options & NANDMODEL_COPYBACK) != 0); +} diff --git a/include/nuttx/mtd/nand.h b/include/nuttx/mtd/nand.h index f047fb7427..4554841d96 100644 --- a/include/nuttx/mtd/nand.h +++ b/include/nuttx/mtd/nand.h @@ -52,6 +52,7 @@ #include #include +#include /**************************************************************************** * Pre-Processor Definitions @@ -61,6 +62,18 @@ * Public Types ****************************************************************************/ +/* This type represents the state of the NAND MTD device. 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_dev_s. + */ + +struct nand_dev_s +{ + struct mtd_dev_s mtd; /* Externally visible part of the driver */ + struct mtd_dev_s *raw; /* The lower-half, "raw" nand MTD driver */ + struct nand_model_s *model; /* Reference to the model (in the raw data structure) */ +}; + /**************************************************************************** * Public Data ****************************************************************************/ @@ -90,14 +103,18 @@ extern "C" * cmdaddr - NAND command address base * addraddr - NAND address address base * dataaddr - NAND data address + * model - A pointer to the model data (probably in the raw MTD + * driver instance. * * Returned value. - * OK is returned on success; A negated errno value is returned on failure. + * A non-NULL MTD driver intstance is returned on success. NULL is + * returned on any failaure. * ****************************************************************************/ -int nand_initialize(FAR struct mtd_dev_s *raw, - uintptr_t cmdaddr, uintptr_t addraddr, uintptr_t dataaddr); +FAR struct mtd_dev_s *nand_initialize(FAR struct mtd_dev_s *raw, + uintptr_t cmdaddr, uintptr_t addraddr, + uintptr_t dataaddr, FAR struct nand_model_s *model); #undef EXTERN #ifdef __cplusplus diff --git a/include/nuttx/mtd/nand_model.h b/include/nuttx/mtd/nand_model.h index b2130ad6bb..32268f44d3 100644 --- a/include/nuttx/mtd/nand_model.h +++ b/include/nuttx/mtd/nand_model.h @@ -113,6 +113,285 @@ EXTERN const struct nand_model_s g_nandmodels[NAND_NMODELS]; * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: nandmodel_find + * + * Description: + * Looks for a nand_model_s corresponding to the given ID inside a list of + * model. If found, the model variable is filled with the correct values. + * + * Input Parameters: + * modeltab List of nand_model_s instances. + * size Number of models in list. + * chipid Identifier returned by the Nand(id1|(id2<<8)|(id3<<16)|(id4<<24)). + * model nand_model_s instance to update with the model parameters. + * + * Returned Values: + * OK is returned on success; -ENODEV is returned on failure. + * + ****************************************************************************/ + +int nandmodel_find(FAR const struct nand_model_s *modeltab, size_t size, + uint32_t chipid, FAR struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_translate + * + * Description: + * Translates address/size access of a nand_model_s to block, page and + * offset values. The values are stored in the provided variables if their + * pointer is not 0. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * address Access address. + * size Access size in bytes. + * block Stores the first accessed block number. + * page Stores the first accessed page number inside the first block. + * offset Stores the byte offset inside the first accessed page. + * + * Returned Values: + * OK on success; -EPIPE on failure. + * + ****************************************************************************/ + +int nandmodel_translate(FAR const struct nand_model_s *model, off_t address, + size_t size, FAR off_t *block, off_t *page, + off_t *offset); + +/**************************************************************************** + * Name: nandmodel_getscheme + * + * Description: + * Returns the spare area placement scheme used by a particular nandflash + * model. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Spare placement scheme + * + ****************************************************************************/ + +FAR const struct nand_dev_scheme_s * +nandmodel_getscheme(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_getdevid + * + * Description: + * Returns the device ID of a particular NAND FLASH model. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Device ID + * + ****************************************************************************/ + +uint8_t nandmodel_getdevid(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_getdevblocksize + * + * Description: + * Returns the number of blocks in the entire device. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Number of blocks in the device + * + ****************************************************************************/ + +off_t nandmodel_getdevblocksize(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_getdevpagesize + * + * Description: + * Returns the number of pages in the entire device. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Number of pages in the device + * + ****************************************************************************/ + +size_t nandmodel_getdevpagesize(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_getdevbytesize + * + * Description: + * Returns the size of the whole device in bytes (this does not include + * the size of the spare zones). + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Size of the device in bytes + * + ****************************************************************************/ + +uint64_t nandmodel_getdevbytesize(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_getdevmbsize + * + * Description: + * Returns the size of the whole device in Mega bytes (this does not + * include the size of the spare zones). + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * size of the device in MB. + * + ****************************************************************************/ + +uint32_t nandmodel_getdevmbsize(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_getblocksize + * + * Description: + * Returns the number of pages in one single block of a device. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * + * + ****************************************************************************/ + +unsigned int nandmodel_getblocksize(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_getblockpagesize + * + * Description: + * Returns the number of pages in one single block of a device. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Block size in pages + * + ****************************************************************************/ + +unsigned int nandmodel_getblockpagesize(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_getblockbytesize + * + * Description: + * Returns the size in bytes of one single block of a device. This does not + * take into account the spare zones size. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Block size in bytes + * + ****************************************************************************/ + +unsigned int nandmodel_getblockbytesize(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_getpagesize + * + * Description: + * Returns the size of the data area of a page in bytes. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Size of data area in bytes + * + ****************************************************************************/ + +unsigned int nandmodel_getpagesize(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_getsparesize + * + * Description: + * Returns the size of the spare area of a page in bytes. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * size of spare area in bytes + * + ****************************************************************************/ + +unsigned int nandmodel_getsparesize(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_getbuswidth + * + * Description: + * Returns the number of bits used by the data bus of a NAND FLASH device. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * data width + * + ****************************************************************************/ + +unsigned int nandmodel_getbuswidth(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_havesmallblocks + * + * Description: + * Returns true if the given NAND FLASH model uses the "small blocks/pages" + * command set; otherwise returns false. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Returns true if the given NAND FLASH model uses the "small blocks/pages" + * command set; otherwise returns false. + * + ****************************************************************************/ + +bool nandmodel_havesmallblocks(FAR const struct nand_model_s *model); + +/**************************************************************************** + * Name: nandmodel_havecopyback + * + * Description: + * Returns true if the device supports the copy-back operation. Otherwise + * returns false. + * + * Input Parameters: + * model Pointer to a nand_model_s instance. + * + * Returned Values: + * Returns true if the device supports the copy-back operation. Otherwise + * returns false. + * + ****************************************************************************/ + +bool nandmodel_havecopyback(FAR const struct nand_model_s *model); + #undef EXTERN #ifdef __cplusplus }