📄 nandsim.c
字号:
/* * NAND flash simulator. * * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org> * * Copyright (C) 2004 Nokia Corporation * * Note: NS means "NAND Simulator". * Note: Input means input TO flash chip, output means output FROM chip. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * * $Id: nandsim.c,v 1.11 2005/05/23 12:51:04 dedekind Exp $ */#include <linux/config.h>#include <linux/init.h>#include <linux/types.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/partitions.h>#include <linux/delay.h>#ifdef CONFIG_NS_ABS_POS#include <asm/io.h>#endif#define CONFIG_NANDSIM_FIRST_ID_BYTE CONFIG_MTD_NAND_NANDSIM_FIRST_ID#define CONFIG_NANDSIM_SECOND_ID_BYTE CONFIG_MTD_NAND_NANDSIM_SECOND_ID#define CONFIG_NANDSIM_THIRD_ID_BYTE CONFIG_MTD_NAND_NANDSIM_THIRD_ID#define CONFIG_NANDSIM_FOURTH_ID_BYTE CONFIG_MTD_NAND_NANDSIM_FOURTH_ID#ifndef CONFIG_MTD_NAND_NANDSIM_ACCESS_DELAY# define CONFIG_MTD_NAND_NANDSIM_ACCESS_DELAY 25#endif#ifndef CONFIG_MTD_NAND_NANDSIM_PROGRAM_DELAY# define CONFIG_MTD_NAND_NANDSIM_PROGRAM_DELAY 200#endif#ifndef CONFIG_MTD_NAND_NANDSIM_ERASE_DELAY# define CONFIG_MTD_NAND_NANDSIM_ERASE_DELAY 2#endif#ifndef CONFIG_MTD_NAND_NANDSIM_OUTPUT_CYCLE# define CONFIG_MTD_NAND_NANDSIM_OUTPUT_CYCLE 40#endif#ifndef CONFIG_MTD_NAND_NANDSIM_INPUT_CYCLE# define CONFIG_MTD_NAND_NANDSIM_INPUT_CYCLE 50#endif#ifdef CONFIG_MTD_NAND_NANDSIM_16BIT_BUS# define CONFIG_NANDSIM_BUS_WIDTH 16#else# define CONFIG_NANDSIM_BUS_WIDTH 8#endif#ifndef CONFIG_MTD_NAND_NANDSIM_DELAY# define CONFIG_MTD_NAND_NANDSIM_DELAY 0#else# undef CONFIG_MTD_NAND_NANDSIM_DELAY# define CONFIG_MTD_NAND_NANDSIM_DELAY 1#endif#ifndef CONFIG_MTD_NAND_NANDSIM_LOG# define CONFIG_MTD_NAND_NANDSIM_LOG 0#else# undef CONFIG_MTD_NAND_NANDSIM_LOG# define CONFIG_MTD_NAND_NANDSIM_LOG 1#endif#ifndef CONFIG_MTD_NAND_NANDSIM_DEBUG# define CONFIG_MTD_NAND_NANDSIM_DEBUG 0#else# undef CONFIG_MTD_NAND_NANDSIM_DEBUG# define CONFIG_MTD_NAND_NANDSIM_DEBUG 1#endifstatic uint first_id_byte = CONFIG_NANDSIM_FIRST_ID_BYTE;static uint second_id_byte = CONFIG_NANDSIM_SECOND_ID_BYTE;static uint third_id_byte = CONFIG_NANDSIM_THIRD_ID_BYTE;static uint fourth_id_byte = CONFIG_NANDSIM_FOURTH_ID_BYTE;static uint access_delay = CONFIG_MTD_NAND_NANDSIM_ACCESS_DELAY;static uint programm_delay = CONFIG_MTD_NAND_NANDSIM_PROGRAM_DELAY;static uint erase_delay = CONFIG_MTD_NAND_NANDSIM_ERASE_DELAY;static uint output_cycle = CONFIG_MTD_NAND_NANDSIM_OUTPUT_CYCLE;static uint input_cycle = CONFIG_MTD_NAND_NANDSIM_INPUT_CYCLE;static uint bus_width = CONFIG_NANDSIM_BUS_WIDTH;static uint do_delays = CONFIG_MTD_NAND_NANDSIM_DELAY;static uint log = CONFIG_MTD_NAND_NANDSIM_LOG;static uint dbg = CONFIG_MTD_NAND_NANDSIM_DEBUG;module_param(first_id_byte, uint, 0400);module_param(second_id_byte, uint, 0400);module_param(third_id_byte, uint, 0400);module_param(fourth_id_byte, uint, 0400);module_param(access_delay, uint, 0400);module_param(programm_delay, uint, 0400);module_param(erase_delay, uint, 0400);module_param(output_cycle, uint, 0400);module_param(input_cycle, uint, 0400);module_param(bus_width, uint, 0400);module_param(do_delays, uint, 0400);module_param(log, uint, 0400);module_param(dbg, uint, 0400);MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)");MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command");MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command");MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)");MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)");MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanoseconds)");MODULE_PARM_DESC(input_cycle, "Word input (to flash) time (nanoseconds)");MODULE_PARM_DESC(bus_width, "Chip's bus width (8- or 16-bit)");MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not zero");MODULE_PARM_DESC(log, "Perform logging if not zero");MODULE_PARM_DESC(dbg, "Output debug information if not zero");/* The largest possible page size */#define NS_LARGEST_PAGE_SIZE 2048 /* The prefix for simulator output */#define NS_OUTPUT_PREFIX "[nandsim]"/* Simulator's output macros (logging, debugging, warning, error) */#define NS_LOG(args...) \ do { if (log) printk(KERN_DEBUG NS_OUTPUT_PREFIX " log: " args); } while(0)#define NS_DBG(args...) \ do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0)#define NS_WARN(args...) \ do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warnig: " args); } while(0)#define NS_ERR(args...) \ do { printk(KERN_ERR NS_OUTPUT_PREFIX " errorr: " args); } while(0)/* Busy-wait delay macros (microseconds, milliseconds) */#define NS_UDELAY(us) \ do { if (do_delays) udelay(us); } while(0)#define NS_MDELAY(us) \ do { if (do_delays) mdelay(us); } while(0) /* Is the nandsim structure initialized ? */#define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0)/* Good operation completion status */#define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0)))/* Operation failed completion status */#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns)) /* Calculate the page offset in flash RAM image by (row, column) address */#define NS_RAW_OFFSET(ns) \ (((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column) /* Calculate the OOB offset in flash RAM image by (row, column) address */#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)/* After a command is input, the simulator goes to one of the following states */#define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */#define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */#define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */#define STATE_CMD_PAGEPROG 0x00000004 /* start page programm */#define STATE_CMD_READOOB 0x00000005 /* read OOB area */#define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */#define STATE_CMD_STATUS 0x00000007 /* read status */#define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */#define STATE_CMD_SEQIN 0x00000009 /* sequential data imput */#define STATE_CMD_READID 0x0000000A /* read ID */#define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */#define STATE_CMD_RESET 0x0000000C /* reset */#define STATE_CMD_MASK 0x0000000F /* command states mask *//* After an addres is input, the simulator goes to one of these states */#define STATE_ADDR_PAGE 0x00000010 /* full (row, column) address is accepted */#define STATE_ADDR_SEC 0x00000020 /* sector address was accepted */#define STATE_ADDR_ZERO 0x00000030 /* one byte zero address was accepted */#define STATE_ADDR_MASK 0x00000030 /* address states mask *//* Durind data input/output the simulator is in these states */#define STATE_DATAIN 0x00000100 /* waiting for data input */#define STATE_DATAIN_MASK 0x00000100 /* data input states mask */#define STATE_DATAOUT 0x00001000 /* waiting for page data output */#define STATE_DATAOUT_ID 0x00002000 /* waiting for ID bytes output */#define STATE_DATAOUT_STATUS 0x00003000 /* waiting for status output */#define STATE_DATAOUT_STATUS_M 0x00004000 /* waiting for multi-plane status output */#define STATE_DATAOUT_MASK 0x00007000 /* data output states mask *//* Previous operation is done, ready to accept new requests */#define STATE_READY 0x00000000/* This state is used to mark that the next state isn't known yet */#define STATE_UNKNOWN 0x10000000/* Simulator's actions bit masks */#define ACTION_CPY 0x00100000 /* copy page/OOB to the internal buffer */#define ACTION_PRGPAGE 0x00200000 /* programm the internal buffer to flash */#define ACTION_SECERASE 0x00300000 /* erase sector */#define ACTION_ZEROOFF 0x00400000 /* don't add any offset to address */#define ACTION_HALFOFF 0x00500000 /* add to address half of page */#define ACTION_OOBOFF 0x00600000 /* add to address OOB offset */#define ACTION_MASK 0x00700000 /* action mask */#define NS_OPER_NUM 12 /* Number of operations supported by the simulator */#define NS_OPER_STATES 6 /* Maximum number of states in operation */#define OPT_ANY 0xFFFFFFFF /* any chip supports this operation */#define OPT_PAGE256 0x00000001 /* 256-byte page chips */#define OPT_PAGE512 0x00000002 /* 512-byte page chips */#define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */#define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */#define OPT_AUTOINCR 0x00000020 /* page number auto inctimentation is possible */#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */#define OPT_LARGEPAGE (OPT_PAGE2048) /* 2048-byte page chips */#define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips *//* Remove action bits ftom state */#define NS_STATE(x) ((x) & ~ACTION_MASK) /* * Maximum previous states which need to be saved. Currently saving is * only needed for page programm operation with preceeded read command * (which is only valid for 512-byte pages). */#define NS_MAX_PREVSTATES 1/* * The structure which describes all the internal simulator data. */struct nandsim { struct mtd_partition part; uint busw; /* flash chip bus width (8 or 16) */ u_char ids[4]; /* chip's ID bytes */ uint32_t options; /* chip's characteristic bits */ uint32_t state; /* current chip state */ uint32_t nxstate; /* next expected state */ uint32_t *op; /* current operation, NULL operations isn't known yet */ uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */ uint16_t npstates; /* number of previous states saved */ uint16_t stateidx; /* current state index */ /* The simulated NAND flash image */ union flash_media { u_char *byte; uint16_t *word; } mem; /* Internal buffer of page + OOB size bytes */ union internal_buffer { u_char *byte; /* for byte access */ uint16_t *word; /* for 16-bit word access */ } buf; /* NAND flash "geometry" */ struct nandsin_geometry { uint32_t totsz; /* total flash size, bytes */ uint32_t secsz; /* flash sector (erase block) size, bytes */ uint pgsz; /* NAND flash page size, bytes */ uint oobsz; /* page OOB area size, bytes */ uint32_t totszoob; /* total flash size including OOB, bytes */ uint pgszoob; /* page size including OOB , bytes*/ uint secszoob; /* sector size including OOB, bytes */ uint pgnum; /* total number of pages */ uint pgsec; /* number of pages per sector */ uint secshift; /* bits number in sector size */ uint pgshift; /* bits number in page size */ uint oobshift; /* bits number in OOB size */ uint pgaddrbytes; /* bytes per page address */ uint secaddrbytes; /* bytes per sector address */ uint idbytes; /* the number ID bytes that this chip outputs */ } geom; /* NAND flash internal registers */ struct nandsim_regs { unsigned command; /* the command register */ u_char status; /* the status register */ uint row; /* the page number */ uint column; /* the offset within page */ uint count; /* internal counter */ uint num; /* number of bytes which must be processed */ uint off; /* fixed page offset */ } regs; /* NAND flash lines state */ struct ns_lines_status { int ce; /* chip Enable */ int cle; /* command Latch Enable */ int ale; /* address Latch Enable */ int wp; /* write Protect */ } lines;};/* * Operations array. To perform any operation the simulator must pass * through the correspondent states chain. */static struct nandsim_operations { uint32_t reqopts; /* options which are required to perform the operation */ uint32_t states[NS_OPER_STATES]; /* operation's states */} ops[NS_OPER_NUM] = { /* Read page + OOB from the beginning */ {OPT_SMALLPAGE, {STATE_CMD_READ0 | ACTION_ZEROOFF, STATE_ADDR_PAGE | ACTION_CPY, STATE_DATAOUT, STATE_READY}}, /* Read page + OOB from the second half */ {OPT_PAGE512_8BIT, {STATE_CMD_READ1 | ACTION_HALFOFF, STATE_ADDR_PAGE | ACTION_CPY, STATE_DATAOUT, STATE_READY}}, /* Read OOB */ {OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY, STATE_DATAOUT, STATE_READY}}, /* Programm page starting from the beginning */ {OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, /* Programm page starting from the beginning */ {OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, /* Programm page starting from the second half */ {OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, /* Programm OOB */ {OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, /* Erase sector */ {OPT_ANY, {STATE_CMD_ERASE1, STATE_ADDR_SEC, STATE_CMD_ERASE2 | ACTION_SECERASE, STATE_READY}}, /* Read status */ {OPT_ANY, {STATE_CMD_STATUS, STATE_DATAOUT_STATUS, STATE_READY}}, /* Read multi-plane status */ {OPT_SMARTMEDIA, {STATE_CMD_STATUS_M, STATE_DATAOUT_STATUS_M, STATE_READY}}, /* Read ID */ {OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}}, /* Large page devices read page */ {OPT_LARGEPAGE, {STATE_CMD_READ0, STATE_ADDR_PAGE, STATE_CMD_READSTART | ACTION_CPY, STATE_DATAOUT, STATE_READY}}};/* MTD structure for NAND controller */static struct mtd_info *nsmtd;static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];/* * Initialize the nandsim structure. * * RETURNS: 0 if success, -ERRNO if failure. */static intinit_nandsim(struct mtd_info *mtd){ struct nand_chip *chip = (struct nand_chip *)mtd->priv; struct nandsim *ns = (struct nandsim *)(chip->priv); int i; if (NS_IS_INITIALIZED(ns)) { NS_ERR("init_nandsim: nandsim is already initialized\n"); return -EIO; } /* Force mtd to not do delays */ chip->chip_delay = 0; /* Initialize the NAND flash parameters */ ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8; ns->geom.totsz = mtd->size; ns->geom.pgsz = mtd->oobblock; ns->geom.oobsz = mtd->oobsize; ns->geom.secsz = mtd->erasesize; ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz; ns->geom.pgnum = ns->geom.totsz / ns->geom.pgsz; ns->geom.totszoob = ns->geom.totsz + ns->geom.pgnum * ns->geom.oobsz; ns->geom.secshift = ffs(ns->geom.secsz) - 1; ns->geom.pgshift = chip->page_shift; ns->geom.oobshift = ffs(ns->geom.oobsz) - 1; ns->geom.pgsec = ns->geom.secsz / ns->geom.pgsz; ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec; ns->options = 0; if (ns->geom.pgsz == 256) { ns->options |= OPT_PAGE256; } else if (ns->geom.pgsz == 512) { ns->options |= (OPT_PAGE512 | OPT_AUTOINCR); if (ns->busw == 8)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -