2 * YAFFS: Yet another FFS. A NAND-flash specific file system.
4 * Copyright (C) 2002 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
15 #include <linux/config.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/version.h>
19 #include <linux/slab.h>
20 #include <linux/init.h>
21 #include <linux/list.h>
23 #include <linux/proc_fs.h>
24 #include <linux/pagemap.h>
25 #include <linux/mtd/mtd.h>
26 #include <linux/interrupt.h>
27 #include <linux/string.h>
28 #include <linux/locks.h>
30 #include <asm/uaccess.h>
31 #include <linux/mtd/mtd.h>
32 #include <linux/mtd/partitions.h>
33 #include <linux/mtd/nand.h>
36 #define ALLOCATE(x) kmalloc(x,GFP_KERNEL)
37 #define FREE(x) kfree(x)
39 #define DEFAULT_SIZE_IN_MB 16
44 static struct mtd_info nandemul_mtd;
48 __u8 data[528]; // Data + spare
49 int count[3]; // The programming count for each area of
50 // the page (0..255,256..511,512..527
51 int empty; // is this empty?
56 nandemul_Page page[32]; // The pages in the block
57 __u8 damaged; // Is the block damaged?
65 nandemul_Block **block;
69 nandemul_Device device;
71 int sizeInMB = DEFAULT_SIZE_IN_MB;
73 int nandemul_CalcNBlocks(void)
86 sizeInMB = DEFAULT_SIZE_IN_MB;
92 static void nandemul_ReallyEraseBlock(int blockNumber)
96 nandemul_Block *theBlock = device.block[blockNumber];
98 for(i = 0; i < 32; i++)
100 memset(theBlock->page[i].data,0xff,528);
101 theBlock->page[i].count[0] = 0;
102 theBlock->page[i].count[1] = 0;
103 theBlock->page[i].count[2] = 0;
104 theBlock->page[i].empty = 1;
109 static int nandemul_DoErase(int blockNumber)
111 if(blockNumber < 0 || nandemul_CalcNBlocks())
113 T(("Attempt to erase non-existant block %d\n",blockNumber));
115 else if(device.block[blockNumber]->damaged)
117 T(("Attempt to erase damaged block %d\n",blockNumber));
121 nandemul_ReallyEraseBlock(blockNumber);
129 int nandemul_Initialise(void)
133 int nBlocks = nandemul_CalcNBlocks();
136 device.block = ALLOCATE (sizeof(nandemul_Block *) * nBlocks);
138 if(!device.block) return 0;
140 for(i=0; i <nBlocks; i++)
142 device.block[i] = NULL;
145 for(i=0; i <nBlocks && !fail; i++)
147 if((device.block[i] = ALLOCATE(sizeof(nandemul_Block))) == 0)
153 nandemul_ReallyEraseBlock(i);
154 device.block[i]->damaged = 0;
161 for(i = 0; i < nAllocated; i++)
163 FREE(device.block[i]);
167 T(("Allocation failed, could only allocate %dMB of %dMB requested.\n",
168 nAllocated/64,sizeInMB));
172 device.nBlocks = nBlocks;
176 int nandemul_DeInitialise(void)
179 for(i = 0; i < device.nBlocks; i++)
181 FREE(device.block[i]);
182 device.block[i] = NULL;
190 int nandemul_GetNumberOfBlocks(__u32 *nBlocks)
192 *nBlocks = device.nBlocks;
197 int nandemul_Reset(void)
203 int nandemul_Read(__u8 *buffer, __u32 pageAddress,__u32 pageOffset, __u32 nBytes)
205 unsigned blockN, pageN;
207 blockN = pageAddress/32;
208 pageN = pageAddress % 32;
210 // TODO: Do tests for valid blockN, pageN, pageOffset
212 memcpy(buffer,&device.block[blockN]->page[pageN].data[pageOffset],nBytes);
218 int nandemul_Program(const __u8 *buffer, __u32 pageAddress,__u32 pageOffset, __u32 nBytes)
220 unsigned blockN, pageN, pageO;
225 blockN = pageAddress/32;
226 pageN = pageAddress % 32;
231 // TODO: Do tests for valid blockN, pageN, pageOffset
234 for(i = 0,pageO = pageOffset; i < nBytes; i++, pageO++)
236 device.block[blockN]->page[pageN].data[pageO] &= buffer[i];
238 if(pageO < 256) p0 = 1;
239 else if(pageO <512) p1 = 1;
243 device.block[blockN]->page[pageN].empty = 0;
244 device.block[blockN]->page[pageN].count[0] += p0;
245 device.block[blockN]->page[pageN].count[1] += p1;
246 device.block[blockN]->page[pageN].count[2] += p2;
248 if(device.block[blockN]->page[pageN].count[0] > 1)
250 T(("block %d page %d first half programmed %d times\n",
251 blockN,pageN,device.block[blockN]->page[pageN].count[0]));
253 if(device.block[blockN]->page[pageN].count[1] > 1)
255 T(("block %d page %d second half programmed %d times\n",
256 blockN,pageN,device.block[blockN]->page[pageN].count[1]));
258 if(device.block[blockN]->page[pageN].count[2] > 3)
260 T(("block %d page %d spare programmed %d times\n",
261 blockN,pageN,device.block[blockN]->page[pageN].count[2]));
268 int nandemul_CauseBitErrors( __u32 pageAddress, __u32 pageOffset, __u8 xorPattern)
270 unsigned blockN, pageN;
273 blockN = pageAddress/32;
274 pageN = pageAddress % 32;
277 // TODO: Do tests for valid blockN, pageN, pageOffset
279 device.block[blockN]->page[pageN].data[pageOffset] ^= xorPattern;
287 int nandemul_BlockErase(__u32 pageAddress)
291 blockN = pageAddress/32;
293 // TODO: Do tests for valid blockN
294 // TODO: Test that the block has not failed
296 return nandemul_DoErase(blockN);
300 int nandemul_FailBlock(__u32 pageAddress)
304 blockN = pageAddress/32;
306 // TODO: Do tests for valid blockN
307 // TODO: Test that the block has not failed
309 nandemul_DoErase(blockN);
313 int nandemul_ReadId(__u8 *vendorId, __u8 *deviceId)
321 int nandemul_CopyPage(__u32 fromPageAddress, __u32 toPageAddress)
323 __u8 copyBuffer[528];
325 // TODO: Check the bitplane issue.
326 nandemul_Read(copyBuffer, fromPageAddress,0,528);
327 nandemul_Program(copyBuffer, toPageAddress,0,528);
332 int nandemul_ReadStatus(__u8 *status)
339 #ifdef CONFIG_MTD_NAND_ECC
340 #include <linux/mtd/nand_ecc.h>
344 * NAND low-level MTD interface functions
346 static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
347 size_t *retlen, u_char *buf);
348 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
349 size_t *retlen, u_char *buf, u_char *ecc_code);
350 static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
351 size_t *retlen, u_char *buf);
352 static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
353 size_t *retlen, const u_char *buf);
354 static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
355 size_t *retlen, const u_char *buf,
357 static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
358 size_t *retlen, const u_char *buf);
359 static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
360 unsigned long count, loff_t to, size_t *retlen);
361 static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
362 static void nand_sync (struct mtd_info *mtd);
369 static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
370 size_t *retlen, u_char *buf)
372 return nand_read_ecc (mtd, from, len, retlen, buf, NULL);
378 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
379 size_t *retlen, u_char *buf, u_char *ecc_code)
387 /* Do not allow reads past end of device */
388 if ((from + len) > mtd->size) {
394 /* Initialize return value */
400 /* First we calculate the starting page */
401 page = from >> NAND_SHIFT;
403 /* Get raw starting column */
405 start = from & (mtd->oobblock-1);
407 // OK now check for the curveball where the start and end are in
409 if((start + n) < mtd->oobblock)
415 nToCopy = mtd->oobblock - start;
418 nandemul_Read(buf, page, start, nToCopy);
432 * NAND read out-of-band
434 static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
435 size_t *retlen, u_char *buf)
439 DEBUG (MTD_DEBUG_LEVEL3,
440 "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from,
443 /* Shift to get page */
444 page = ((int) from) >> NAND_SHIFT;
446 /* Mask to get column */
449 /* Initialize return length value */
452 /* Do not allow reads past end of device */
453 if ((from + len) > mtd->size) {
454 DEBUG (MTD_DEBUG_LEVEL0,
455 "nand_read_oob: Attempt read beyond end of device\n");
460 nandemul_Read(buf,page,512 + col,len);
470 static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
471 size_t *retlen, const u_char *buf)
473 return nand_write_ecc (mtd, to, len, retlen, buf, NULL);
477 * NAND write with ECC
479 static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
480 size_t *retlen, const u_char *buf,
490 /* Do not allow reads past end of device */
491 if ((to + len) > mtd->size) {
497 /* Initialize return value */
503 /* First we calculate the starting page */
504 page = to >> NAND_SHIFT;
506 /* Get raw starting column */
508 start = to & (mtd->oobblock - 1);
510 // OK now check for the curveball where the start and end are in
512 if((start + n) < mtd->oobblock)
518 nToCopy = mtd->oobblock - start;
521 nandemul_Program(buf, page, start, nToCopy);
535 * NAND write out-of-band
537 static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
538 size_t *retlen, const u_char *buf)
543 DEBUG (MTD_DEBUG_LEVEL3,
544 "nand_read_oob: to = 0x%08x, len = %i\n", (unsigned int) to,
547 /* Shift to get page */
548 page = ((int) to) >> NAND_SHIFT;
550 /* Mask to get column */
553 /* Initialize return length value */
556 /* Do not allow reads past end of device */
557 if ((to + len) > mtd->size) {
558 DEBUG (MTD_DEBUG_LEVEL0,
559 "nand_read_oob: Attempt read beyond end of device\n");
564 nandemul_Program(buf,page,512 + col,len);
573 * NAND write with iovec
575 static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
576 unsigned long count, loff_t to, size_t *retlen)
584 static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
586 int i, nBlocks,block;
588 DEBUG (MTD_DEBUG_LEVEL3,
589 "nand_erase: start = 0x%08x, len = %i\n",
590 (unsigned int) instr->addr, (unsigned int) instr->len);
592 /* Start address must align on block boundary */
593 if (instr->addr & (mtd->erasesize - 1)) {
594 DEBUG (MTD_DEBUG_LEVEL0,
595 "nand_erase: Unaligned address\n");
599 /* Length must align on block boundary */
600 if (instr->len & (mtd->erasesize - 1)) {
601 DEBUG (MTD_DEBUG_LEVEL0,
602 "nand_erase: Length not block aligned\n");
606 /* Do not allow erase past end of device */
607 if ((instr->len + instr->addr) > mtd->size) {
608 DEBUG (MTD_DEBUG_LEVEL0,
609 "nand_erase: Erase past end of device\n");
613 nBlocks = instr->len >> (NAND_SHIFT + 5);
614 block = instr->addr >> (NAND_SHIFT + 5);
616 for(i = 0; i < nBlocks; i++)
618 nandemul_DoErase(block);
632 static void nand_sync (struct mtd_info *mtd)
634 DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
639 * Scan for the NAND device
641 int nand_scan (struct mtd_info *mtd)
645 mtd->erasesize = 512 * 32;
646 mtd->size = sizeInMB * 1024*1024;
650 /* Fill in remaining MTD driver data */
651 mtd->type = MTD_NANDFLASH;
652 mtd->flags = MTD_CAP_NANDFLASH;
653 mtd->module = THIS_MODULE;
654 mtd->ecctype = MTD_ECC_NONE;
655 mtd->erase = nand_erase;
658 mtd->read = nand_read;
659 mtd->write = nand_write;
660 mtd->read_ecc = nand_read_ecc;
661 mtd->write_ecc = nand_write_ecc;
662 mtd->read_oob = nand_read_oob;
663 mtd->write_oob = nand_write_oob;
665 mtd->writev = nand_writev;
666 mtd->sync = nand_sync;
678 MODULE_PARM(sizeInMB, "i");
680 __setup("sizeInMB=",sizeInMB);
685 * Define partitions for flash devices
688 static struct mtd_partition nandemul_partition[] =
690 { name: "NANDemul partition 1",
695 static int nPartitions = sizeof(nandemul_partition)/sizeof(nandemul_partition[0]);
698 * Main initialization routine
700 int __init nandemul_init (void)
705 nand_scan(&nandemul_mtd);
707 nandemul_Initialise();
709 // Build the partition table
711 nandemul_partition[0].size = sizeInMB * 1024 * 1024;
713 // Register the partition
714 add_mtd_partitions(&nandemul_mtd,nandemul_partition,nPartitions);
720 module_init(nandemul_init);
726 static void __exit nandemul_cleanup (void)
729 nandemul_DeInitialise();
731 /* Unregister partitions */
732 del_mtd_partitions(&nandemul_mtd);
734 /* Unregister the device */
735 del_mtd_device (&nandemul_mtd);
738 module_exit(nandemul_cleanup);
741 MODULE_LICENSE("GPL");
742 MODULE_AUTHOR("Charles Manning <manningc@aleph1.co.uk>");
743 MODULE_DESCRIPTION("NAND emulated in RAM");