| /**************************************************************************** |
| * drivers/mtd/mtd_nandmodel.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) 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 <nuttx/config.h> |
| #include <nuttx/mtd/nand_config.h> |
| |
| #include <sys/types.h> |
| #include <stdint.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <debug.h> |
| |
| #include <nuttx/mtd/nand.h> |
| #include <nuttx/mtd/nand_model.h> |
| |
| /**************************************************************************** |
| * 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 (MB)\n", model->devsize); |
| fvdbg(" blocksize: %d (KB)\n", model->blocksize); |
| fvdbg(" pagesize: %d (B)\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_getbyteblocksize(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_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 */ |
| } |
| } |