diff options
Diffstat (limited to 'target/linux/storm/patches/007-mtd.patch')
-rw-r--r-- | target/linux/storm/patches/007-mtd.patch | 4948 |
1 files changed, 0 insertions, 4948 deletions
diff --git a/target/linux/storm/patches/007-mtd.patch b/target/linux/storm/patches/007-mtd.patch deleted file mode 100644 index a907de32cb..0000000000 --- a/target/linux/storm/patches/007-mtd.patch +++ /dev/null @@ -1,4948 +0,0 @@ ---- a/drivers/mtd/chips/Kconfig -+++ b/drivers/mtd/chips/Kconfig -@@ -220,6 +220,13 @@ config MTD_ROM - This option enables basic support for ROM chips accessed through - a bus mapping driver. - -+config MTD_SERIAL -+ tristate "Support for Serial chips in bus mapping" -+ depends on MTD -+ help -+ This option enables basic support for Serial chips accessed through -+ a bus mapping driver. -+ - config MTD_ABSENT - tristate "Support for absent chips in bus mapping" - help ---- a/drivers/mtd/chips/cfi_cmdset_0002.c -+++ b/drivers/mtd/chips/cfi_cmdset_0002.c -@@ -39,10 +39,15 @@ - #include <linux/mtd/cfi.h> - #include <linux/mtd/xip.h> - -+//****** Storlink SoC ****** - #define AMD_BOOTLOC_BUG --#define FORCE_WORD_WRITE 0 -- --#define MAX_WORD_RETRIES 3 -+//#define FORCE_WORD_WRITE 0 -+#define FORCE_WORD_WRITE 1 -+#define FORCE_FAST_PROG 0 -+ -+//#define MAX_WORD_RETRIES 3 -+#define MAX_WORD_RETRIES 3 // CONFIG_MTD_CFI_AMDSTD_RETRY -+//************************** - - #define MANUFACTURER_AMD 0x0001 - #define MANUFACTURER_ATMEL 0x001F -@@ -322,6 +327,13 @@ struct mtd_info *cfi_cmdset_0002(struct - #endif - - bootloc = extp->TopBottom; -+//****** Storlink SoC ****** -+ if(bootloc == 5) -+ { -+ bootloc = 3; -+ extp->TopBottom = 3; -+ } -+//************************** - if ((bootloc != 2) && (bootloc != 3)) { - printk(KERN_WARNING "%s: CFI does not contain boot " - "bank location. Assuming top.\n", map->name); -@@ -340,6 +352,9 @@ struct mtd_info *cfi_cmdset_0002(struct - cfi->cfiq->EraseRegionInfo[j] = swap; - } - } -+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1 -+ cfi->device_type = CFI_DEVICETYPE_X8; -+#endif - /* Set the default CFI lock/unlock addresses */ - cfi->addr_unlock1 = 0x555; - cfi->addr_unlock2 = 0x2aa; -@@ -461,6 +476,7 @@ static int __xipram chip_ready(struct ma - map_word d, t; - - d = map_read(map, addr); -+ udelay(20); //Storlink SoC - t = map_read(map, addr); - - return map_word_equal(map, d, t); -@@ -626,7 +642,9 @@ static void put_chip(struct map_info *ma - default: - printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate); - } -+//****** Storlink SoC ****** - wake_up(&chip->wq); -+//************************** - } - - #ifdef CONFIG_MTD_XIP -@@ -940,7 +958,9 @@ static inline int do_read_secsi_onechip( - cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); - -+//****** Storlink SoC ****** - wake_up(&chip->wq); -+//************************** - spin_unlock(chip->mutex); - - return 0; -@@ -1005,7 +1025,10 @@ static int __xipram do_write_oneword(str - */ - unsigned long uWriteTimeout = ( HZ / 1000 ) + 1; - int ret = 0; -- map_word oldd; -+//****** Storlink SoC ****** -+// map_word oldd; -+ map_word oldd, tmp; -+//************************** - int retry_cnt = 0; - - adr += chip->start; -@@ -1037,9 +1060,15 @@ static int __xipram do_write_oneword(str - ENABLE_VPP(map); - xip_disable(map, chip, adr); - retry: -+//****** Storlink SoC ****** -+#if FORCE_FAST_PROG /* Unlock bypass */ -+ cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); -+#else - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); -+#endif -+//************************** - map_write(map, datum, adr); - chip->state = FL_WRITING; - -@@ -1072,7 +1101,13 @@ static int __xipram do_write_oneword(str - } - - if (chip_ready(map, adr)) -- break; -+ { -+ tmp = map_read(map, adr); -+ if(map_word_equal(map, tmp, datum)) -+// goto op_done; -+ break; -+ -+ } - - /* Latency issues. Drop the lock, wait a while and retry */ - UDELAY(map, chip, adr, 1); -@@ -1084,8 +1119,17 @@ static int __xipram do_write_oneword(str - /* FIXME - should have reset delay before continuing */ - - if (++retry_cnt <= MAX_WORD_RETRIES) -+ { -+//****** Storlink SoC ****** -+#if FORCE_FAST_PROG -+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); -+ //udelay(1); -+#endif -+ udelay(1); - goto retry; -- -+ } - ret = -EIO; - } - xip_enable(map, chip, adr); -@@ -1171,7 +1215,14 @@ static int cfi_amdstd_write_words(struct - return 0; - } - } -- -+//****** Storlink SoC ****** -+ map_write( map, CMD(0xF0), chipstart ); -+#if FORCE_FAST_PROG -+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL); -+#endif -+//************************** - /* We are now aligned, write as much as possible */ - while(len >= map_bankwidth(map)) { - map_word datum; -@@ -1181,7 +1232,15 @@ static int cfi_amdstd_write_words(struct - ret = do_write_oneword(map, &cfi->chips[chipnum], - ofs, datum); - if (ret) -+ { -+//****** Storlink SoC ****** -+#if FORCE_FAST_PROG -+ /* Get out of unlock bypass mode */ -+ cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL); -+#endif - return ret; -+ } - - ofs += map_bankwidth(map); - buf += map_bankwidth(map); -@@ -1189,19 +1248,38 @@ static int cfi_amdstd_write_words(struct - len -= map_bankwidth(map); - - if (ofs >> cfi->chipshift) { -+//****** Storlink SoC ****** -+#if FORCE_FAST_PROG -+ /* Get out of unlock bypass mode */ -+ cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL); -+#endif - chipnum ++; - ofs = 0; - if (chipnum == cfi->numchips) - return 0; - chipstart = cfi->chips[chipnum].start; -+#if FORCE_FAST_PROG -+ /* Go into unlock bypass mode for next set of chips */ -+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL); -+#endif - } - } - -+#if FORCE_FAST_PROG -+ /* Get out of unlock bypass mode */ -+ cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL); -+#endif -+ - /* Write the trailing bytes if any */ - if (len & (map_bankwidth(map)-1)) { - map_word tmp_buf; - - retry1: -+ - spin_lock(cfi->chips[chipnum].mutex); - - if (cfi->chips[chipnum].state != FL_READY) { -@@ -1221,7 +1299,11 @@ static int cfi_amdstd_write_words(struct - #endif - goto retry1; - } -- -+#if FORCE_FAST_PROG -+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, cfi->device_type, NULL); -+#endif - tmp_buf = map_read(map, ofs + chipstart); - - spin_unlock(cfi->chips[chipnum].mutex); -@@ -1231,11 +1313,23 @@ static int cfi_amdstd_write_words(struct - ret = do_write_oneword(map, &cfi->chips[chipnum], - ofs, tmp_buf); - if (ret) -+ { -+#if FORCE_FAST_PROG -+ /* Get out of unlock bypass mode */ -+ cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL); -+#endif - return ret; -- -+ } -+#if FORCE_FAST_PROG -+ /* Get out of unlock bypass mode */ -+ cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL); -+#endif - (*retlen) += len; - } - -+ map_write( map, CMD(0xF0), chipstart ); - return 0; - } - -@@ -1275,6 +1369,7 @@ static int __xipram do_write_buffer(stru - ENABLE_VPP(map); - xip_disable(map, chip, cmd_adr); - -+ map_write( map, CMD(0xF0), chip->start ); //Storlink - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); - //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); -@@ -1535,6 +1630,9 @@ static int __xipram do_erase_oneblock(st - DECLARE_WAITQUEUE(wait, current); - int ret = 0; - -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_lock(); // sl2312 share pin lock -+#endif - adr += chip->start; - - spin_lock(chip->mutex); -@@ -1613,6 +1711,9 @@ static int __xipram do_erase_oneblock(st - chip->state = FL_READY; - put_chip(map, chip, adr); - spin_unlock(chip->mutex); -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return ret; - } - ---- /dev/null -+++ b/drivers/mtd/chips/map_serial.c -@@ -0,0 +1,188 @@ -+/* -+ * Common code to handle map devices which are simple ROM -+ * (C) 2000 Red Hat. GPL'd. -+ * $Id: map_serial.c,v 1.3 2006/06/05 02:34:54 middle Exp $ -+ */ -+ -+#include <linux/version.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <asm/io.h> -+ -+#include <asm/byteorder.h> -+#include <linux/errno.h> -+#include <linux/slab.h> -+ -+#include <asm/hardware.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> -+#include <linux/init.h> //add -+#include <asm/arch/sl2312.h> -+#include <asm/arch/flash.h> -+ -+static int mapserial_erase(struct mtd_info *mtd, struct erase_info *instr); -+static int mapserial_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); -+static int mapserial_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); -+static void mapserial_nop (struct mtd_info *); -+struct mtd_info *map_serial_probe(struct map_info *map); -+ -+extern int m25p80_sector_erase(__u32 address, __u32 schip_en); -+ -+static struct mtd_chip_driver mapserial_chipdrv = { -+ probe: map_serial_probe, -+ name: "map_serial", -+ module: THIS_MODULE -+}; -+ -+struct mtd_info *map_serial_probe(struct map_info *map) -+{ -+ struct mtd_info *mtd; -+ -+ mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); -+ if (!mtd) -+ return NULL; -+ -+ memset(mtd, 0, sizeof(*mtd)); -+ -+ map->fldrv = &mapserial_chipdrv; -+ mtd->priv = map; -+ mtd->name = map->name; -+ mtd->type = MTD_OTHER; -+ mtd->erase = mapserial_erase; -+ mtd->size = map->size; -+ mtd->read = mapserial_read; -+ mtd->write = mapserial_write; -+ mtd->sync = mapserial_nop; -+ mtd->flags = (MTD_WRITEABLE|MTD_ERASEABLE); -+// mtd->erasesize = 512; // page size; -+#ifdef CONFIG_MTD_SL2312_SERIAL_ST -+ mtd->erasesize = M25P80_SECTOR_SIZE; // block size; -+#else -+ mtd->erasesize = 0x1000; // block size; -+#endif -+ -+ __module_get(THIS_MODULE); -+ //MOD_INC_USE_COUNT; -+ return mtd; -+} -+ -+#define FLASH_ACCESS_OFFSET 0x00000010 -+#define FLASH_ADDRESS_OFFSET 0x00000014 -+#define FLASH_WRITE_DATA_OFFSET 0x00000018 -+#define FLASH_READ_DATA_OFFSET 0x00000018 -+ -+static __u32 readflash_ctrl_reg(__u32 ofs) -+{ -+ __u32 *base; -+ -+ base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs)); -+ return __raw_readl(base); -+} -+ -+static void writeflash_ctrl_reg(__u32 data, __u32 ofs) -+{ -+ __u32 *base; -+ -+ base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs)); -+ __raw_writel(data, base); -+} -+ -+static int mapserial_erase_block(struct map_info *map,unsigned int block) -+{ -+ -+ __u32 address; -+#ifdef CONFIG_MTD_SL2312_SERIAL_ST -+ -+ if(!m25p80_sector_erase(block, 0)) -+ return (MTD_ERASE_DONE); -+#else -+ __u32 opcode; -+ __u32 count=0; -+// __u8 status; -+ -+ // printk("mapserial_erase_block : erase block %d \n",block); -+// opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | cmd; -+ opcode = 0x80000000 | 0x0200 | 0x50; -+ address = (block << 13); -+ writeflash_ctrl_reg(address,FLASH_ADDRESS_OFFSET); -+ writeflash_ctrl_reg(opcode,FLASH_ACCESS_OFFSET); -+ opcode=readflash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(opcode&0x80000000) -+ { -+ opcode = readflash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ count++; -+ if (count > 10000) -+ { -+ return (MTD_ERASE_FAILED); -+ } -+ } -+ return (MTD_ERASE_DONE); -+#endif -+} -+ -+static int mapserial_erase(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ struct map_info *map = (struct map_info *)mtd->priv; -+ unsigned int addr; -+ int len; -+ unsigned int block; -+ unsigned int ret=0; -+ -+ addr = instr->addr; -+ len = instr->len; -+ while (len > 0) -+ { -+ block = addr / mtd->erasesize; -+#ifdef CONFIG_MTD_SL2312_SERIAL_ST -+ ret = mapserial_erase_block(map,addr); -+#else -+ ret = mapserial_erase_block(map,block); -+#endif -+ addr = addr + mtd->erasesize; -+ len = len - mtd->erasesize; -+ } -+ return (ret); -+} -+ -+static int mapserial_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -+{ -+ struct map_info *map = (struct map_info *)mtd->priv; -+// printk("mapserial_read : \n"); -+ map->copy_from(map, buf, from, len); -+ *retlen = len; -+ return 0; -+} -+ -+static void mapserial_nop(struct mtd_info *mtd) -+{ -+ /* Nothing to see here */ -+} -+ -+static int mapserial_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) -+{ -+ struct map_info *map = (struct map_info *)mtd->priv; -+// printk("mapserial_write : buf %x to %x len %x \n",(int)buf, (int)to, (int)len); -+ //map->copy_to(map, buf, to, len); -+ map->copy_to(map, to, buf, len); -+ *retlen = len; -+ return 0; -+} -+ -+int __init map_serial_init(void) -+{ -+ register_mtd_chip_driver(&mapserial_chipdrv); -+ return 0; -+} -+ -+static void __exit map_serial_exit(void) -+{ -+ unregister_mtd_chip_driver(&mapserial_chipdrv); -+} -+ -+module_init(map_serial_init); -+module_exit(map_serial_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); -+MODULE_DESCRIPTION("MTD chip driver for ROM chips"); ---- a/drivers/mtd/maps/Kconfig -+++ b/drivers/mtd/maps/Kconfig -@@ -614,5 +614,30 @@ config MTD_PLATRAM - - This selection automatically selects the map_ram driver. - -+#*************************************************************************************** -+# Storlink parallel/Serial Flash configuration -+#*************************************************************************************** -+config MTD_SL2312_CFI -+ tristate "CFI Flash device mapped on SL2312" -+ depends on MTD_CFI -+ help -+ Map driver for SL2312 demo board. -+ -+config MTD_SL2312_SERIAL_ATMEL -+ tristate "ATMEL Serial Flash device mapped on SL2312" -+ depends on MTD_PARTITIONS && ARCH_SL2312 -+ help -+ Map driver for SL2312 demo board. -+ -+config MTD_SL2312_SERIAL_ST -+ tristate "ST Serial Flash device mapped on SL2312" -+ depends on MTD_PARTITIONS && ARCH_SL2312 -+ help -+ Map driver for SL2312 demo board. -+ -+config SL2312_SHARE_PIN -+ tristate "Parallel Flash share pin on SL2312 ASIC" -+ depends on SL3516_ASIC -+ - endmenu - ---- /dev/null -+++ b/drivers/mtd/maps/sl2312-flash-atmel.c -@@ -0,0 +1,554 @@ -+/* -+ * $Id: sl2312-flash-atmel.c,v 1.2 2006/06/05 02:35:57 middle Exp $ -+ * -+ * Flash and EPROM on Hitachi Solution Engine and similar boards. -+ * -+ * (C) 2001 Red Hat, Inc. -+ * -+ * GPL'd -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+ -+#include <asm/io.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+#include <asm/hardware.h> -+ -+#include <asm/arch/sl2312.h> -+#include <asm/arch/flash.h> -+#include <linux/init.h> //add -+ -+ -+#define g_page_addr AT45DB321_PAGE_SHIFT //321 : shift 10 ; 642 : shift 11 -+#define g_chipen SERIAL_FLASH_CHIP0_EN //atmel -+ -+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -+ -+void address_to_page(__u32 address, __u16 *page, __u16 *offset) -+{ -+ *page = address / SPAGE_SIZE; -+ *offset = address % SPAGE_SIZE; -+} -+ -+static __u32 read_flash_ctrl_reg(__u32 ofs) -+{ -+ __u32 *base; -+ -+ base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs)); -+ return __raw_readl(base); -+} -+ -+static void write_flash_ctrl_reg(__u32 ofs,__u32 data) -+{ -+ __u32 *base; -+ -+ base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs)); -+ __raw_writel(data, base); -+} -+ -+void atmel_read_status(__u8 cmd, __u8 *data) -+{ -+ __u32 opcode; -+ __u32 value; -+ -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | cmd | g_chipen; -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(opcode&0x80000000) -+ { -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ -+ value=read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ *data = value & 0xff; -+} -+ -+void main_memory_page_read(__u8 cmd, __u16 page, __u16 offset, __u8 *data) -+{ -+ __u32 opcode; -+ __u32 address; -+ __u32 value; -+ -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS_4X_DATA | cmd | g_chipen; -+ address = (page << g_page_addr) + offset; -+ write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address); -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(opcode&0x80000000) -+ { -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ -+ value=read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ *data = value & 0xff; -+} -+ -+void buffer_to_main_memory(__u8 cmd, __u16 page) -+{ -+ __u32 opcode; -+ __u32 address; -+ __u8 status; -+ -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | cmd | g_chipen; -+ address = (page << g_page_addr); -+ write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address); -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(opcode&0x80000000) -+ { -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ atmel_read_status(READ_STATUS_SPI, &status); -+ while(!(status&0x80)) -+ { -+ atmel_read_status(READ_STATUS_SPI, &status); -+ flash_delay(); -+ schedule(); -+ } -+ -+} -+ -+ -+void atmel_flash_read_page(__u32 address, __u8 *buffer, __u32 len) -+{ -+ __u8 byte; -+ __u16 page, offset; -+ __u16 i; -+ -+ address_to_page(address, &page, &offset); -+ -+ for(i=0; i<len; i++,offset++) -+ { -+ main_memory_page_read(MAIN_MEMORY_PAGE_READ_SPI , page, offset, &byte); -+ buffer [i]= byte; -+ } -+} -+ -+void atmel_flash_program_page(__u32 address, __u8 *buffer, __u32 len) -+{ -+ __u8 pattern; -+ __u16 page, offset; -+ __u32 i; -+ -+ address_to_page(address, &page, &offset); -+ // printk("atmel_flash_program_page: offset %x len %x page %x \n", offset, len, page); -+ -+ if(offset) -+ main_memory_to_buffer(MAIN_MEMORY_TO_BUFFER1,page); -+ -+ for(i=0; i<len; i++,offset++) -+ { -+ pattern = buffer[i]; -+ atmel_buffer_write(BUFFER1_WRITE,offset,pattern); -+ } -+ -+ // printk("atmel_flash_program_page: offset %x \n", offset); -+ buffer_to_main_memory(BUFFER1_TO_MAIN_MEMORY, page); -+ // printk("atmel_flash_program_page: buffer_to_main_memory %x page\n", page); -+ -+} -+ -+ -+void main_memory_to_buffer(__u8 cmd, __u16 page) -+{ -+ __u32 opcode; -+ __u32 address; -+ __u8 status; -+ -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | cmd | g_chipen; -+ address = (page << g_page_addr); -+ write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address); -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(opcode&0x80000000) -+ { -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ atmel_read_status(READ_STATUS_SPI, &status); -+ while(!(status&0x80)) -+ { -+ atmel_read_status(READ_STATUS_SPI, &status); -+ flash_delay(); -+ schedule(); -+ } -+ -+} -+ -+void main_memory_page_program(__u8 cmd, __u16 page, __u16 offset, __u8 data) -+{ -+ __u32 opcode; -+ __u32 address; -+ __u8 status; -+ -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS_DATA | cmd | g_chipen; -+ address = (page << g_page_addr) + offset; -+ write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address); -+ write_flash_ctrl_reg(FLASH_WRITE_DATA_OFFSET, data); -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(opcode&0x80000000) -+ { -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ atmel_read_status(READ_STATUS_SPI, &status); -+ while(!(status&0x80)) -+ { -+ atmel_read_status(READ_STATUS_SPI, &status); -+ flash_delay(); -+ schedule(); -+ } -+} -+ -+void atmel_buffer_write(__u8 cmd, __u16 offset, __u8 data) -+{ -+ __u32 opcode; -+ __u32 address; -+ -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS_DATA | cmd | g_chipen; -+ address = offset; -+ write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address); -+ write_flash_ctrl_reg(FLASH_WRITE_DATA_OFFSET, data); -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(opcode&0x80000000) -+ { -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ -+} -+ -+void atmel_erase_page(__u8 cmd, __u16 page) -+{ -+ __u32 opcode; -+ __u32 address; -+ __u8 status; -+ -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | cmd | g_chipen; -+ address = (page << g_page_addr); -+ write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address); -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(opcode&0x80000000) -+ { -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ atmel_read_status(READ_STATUS_SPI, &status); -+ while(!(status&0x80)) -+ { -+ atmel_read_status(READ_STATUS_SPI, &status); -+ flash_delay(); -+ schedule(); -+ } -+ -+} -+ -+void atmel_erase_block(__u8 cmd, __u16 block) -+{ -+ __u32 opcode; -+ __u32 address; -+ __u8 status; -+ -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | cmd | g_chipen; -+ address = (block << 13); -+ write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address); -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(opcode&0x80000000) -+ { -+ opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ atmel_read_status(READ_STATUS_SPI, &status); -+ while(!(status&0x80)) -+ { -+ atmel_read_status(READ_STATUS_SPI, &status); -+ flash_delay(); -+ schedule(); -+ } -+ -+} -+ -+void flash_delay(void) -+{ -+ int i; -+ -+ for(i=0; i<50; i++) -+ i=i; -+} -+ -+ -+ -+ -+__u32 sl2312_read32(struct map_info *map, unsigned long ofs) -+{ -+ -+#if 0 -+ __u16 page, offset; -+ __u32 pattern; -+ __u8 byte, i; -+ -+ pattern = 0; -+ address_to_page(ofs, &page, &offset); -+ for(i=0; i<4; i++, offset++) -+ { -+ pattern = pattern << 8; -+ main_memory_page_read(MAIN_MEMORY_PAGE_READ_SPI , page, offset, &byte); -+//printk("sl2312_read32:: address = %08x data = %c \n",ofs,byte); -+ pattern += byte; -+ } -+ return pattern; -+#else -+ return read_flash_ctrl_reg(ofs); -+#endif -+ -+} -+ -+__u8 sl2312_read8(struct map_info *map, unsigned long ofs) -+{ -+ __u16 page, offset; -+ __u8 byte; -+ -+ address_to_page(ofs, &page, &offset); -+ main_memory_page_read(MAIN_MEMORY_PAGE_READ_SPI , page, offset, &byte); -+ //printk("sl2312_read8:: address = %08x data = %c \n",ofs,byte); -+ return byte; -+ -+} -+ -+void sl2312_write32(struct map_info *map, __u32 d, unsigned long ofs) -+{ -+#if 0 -+ __u16 page, offset; -+ __u8 byte, i; -+ -+ address_to_page(ofs, &page, &offset); -+ for(i=0; i<4; i++, offset++) -+ { -+ byte = d & 0xff; -+ main_memory_page_program(MAIN_MEMORY_PROGRAM_BUFFER1, page, offset, byte); -+ d = d >> 8; -+//printk("sl2312_write32:: address = %08x data = %c \n",ofs,byte); -+ } -+#else -+ write_flash_ctrl_reg(ofs, d); -+#endif -+} -+ -+void sl2312_write8(struct map_info *map, __u8 d, unsigned long ofs) -+{ -+ __u16 page, offset; -+ -+ address_to_page(ofs, &page, &offset); -+ main_memory_page_program(MAIN_MEMORY_PROGRAM_BUFFER1, page, offset, d); -+//printk("sl2312_write8:: address = %08x data = %c \n",ofs,d); -+ -+} -+ -+void sl2312_copy_from(struct map_info *map, void *buf, unsigned long ofs, ssize_t len) -+{ -+ __u32 size; -+ __u8 *buffer; -+ __u32 length;//i, j, -+ -+ //printk("sl2312_copy_from:: address = %08x datalen = %d \n",ofs,len); -+ -+ length = len; -+ buffer = (__u8 *)buf; -+ while(len) -+ { -+ size = SPAGE_SIZE - (ofs%SPAGE_SIZE); -+ if(size > len) -+ size = len; -+ atmel_flash_read_page(ofs, buffer, size); -+ buffer+=size; -+ ofs+=size; -+ len -= size; -+ } -+ -+#if 0 -+ buffer = (__u8 *)buf; -+ for(i=0; i<length; i+=16) -+ { -+ for(j=0; j<16; j++,buffer++) -+ { -+ if((i*16+j)<length) -+ printk("%x ",(int)*buffer); -+ } -+ printk("\n"); -+ } -+ -+ printk("\n"); -+#endif -+ -+} -+ -+ -+void sl2312_copy_to(struct map_info *map, unsigned long ofs, void *buf, ssize_t len) -+{ -+ __u32 size; -+ __u8 *buffer; -+ -+ buffer = (__u8 *)buf; -+ //printk("sl2312_copy_to:offset %x len %x \n", ofs, len); -+// printk("sl2312_copy_to:buf is %x \n", (int)buf); -+ -+ while(len) -+ { -+ size = SPAGE_SIZE - (ofs%SPAGE_SIZE); -+ if(size > len) -+ size = len; -+ atmel_flash_program_page(ofs, buffer, size); -+ buffer+=size; -+ ofs+=size; -+ len-=size; -+ } -+ -+ -+} -+ -+ -+static struct mtd_info *serial_mtd; -+ -+static struct mtd_partition *parsed_parts; -+ -+static struct map_info sl2312_serial_map = { -+// name: "SL2312 serial flash", -+// size: 4194304, //0x400000, -+// //buswidth: 4, -+// bankwidth: 4, -+// phys: SL2312_FLASH_BASE, -+//#ifdef CONFIG_MTD_COMPLEX_MAPPINGS -+// //read32: sl2312_read32, -+// //read8: sl2312_read8, -+// copy_from: sl2312_copy_from, -+// //write8: sl2312_write8, -+// //write32: sl2312_write32, -+// read: sl2312_read32, -+// write: sl2312_write32, -+// copy_to: sl2312_copy_to -+//#endif -+ .name = "SL2312 serial flash", -+ .size = 4194304, //0x400000, -+ //buswidth: 4, -+ .bankwidth = 4, -+ .phys = SL2312_FLASH_BASE, -+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS -+ //read32: sl2312_read32, -+ //read8: sl2312_read8, -+ .copy_from = sl2312_copy_from, -+ //write8: sl2312_write8, -+ //write32: sl2312_write32, -+ .read = sl2312_read32, -+ .write = sl2312_write32, -+ .copy_to = sl2312_copy_to -+#endif -+}; -+ -+ -+ -+static struct mtd_partition sl2312_partitions[] = { -+ -+ -+ ///* boot code */ -+ //{ name: "bootloader", offset: 0x00000000, size: 0x20000, }, -+ ///* kernel image */ -+ //{ name: "kerel image", offset: 0x000020000, size: 0x2E0000 }, -+ ///* All else is writable (e.g. JFFS) */ -+ //{ name: "user data", offset: 0x00300000, size: 0x00100000, }, -+ /* boot code */ -+ { .name = "bootloader", .offset = 0x00000000, .size = 0x20000, }, -+ /* kernel image */ -+ { .name = "kerel image", .offset = 0x000020000, .size = 0xE0000 }, -+ /* All else is writable (e.g. JFFS) */ -+ { .name = "user data", .offset = 0x00100000, .size = 0x00300000, }, -+ -+ -+}; -+ -+ -+ -+static int __init init_sl2312_maps(void) -+{ -+ int nr_parts = 0; -+ struct mtd_partition *parts; -+ -+ serial_mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); -+ if (!serial_mtd) -+ return NULL; -+ -+ memset(serial_mtd, 0, sizeof(struct mtd_info)); -+ //sl2312flash_map.virt = (unsigned long)ioremap(SL2312_FLASH_BASE, FLASH_SIZE); -+ //sl2312_serial_map.map_priv_1 = (unsigned long)ioremap(SL2312_FLASH_BASE, SFLASH_SIZE);//(unsigned long)FLASH_VBASE; -+ sl2312_serial_map.virt = (unsigned long)ioremap(SL2312_FLASH_BASE, SFLASH_SIZE);//(unsigned long)ioremap(FLASH_START, SFLASH_SIZE); -+ if (!sl2312_serial_map.virt) { -+ printk(" failed to ioremap \n"); -+ return -EIO; -+ } -+ serial_mtd = do_map_probe("map_serial", &sl2312_serial_map); -+ if (serial_mtd) { -+ //serial_mtd->module = THIS_MODULE; -+ serial_mtd->owner = THIS_MODULE; -+ -+ } -+ -+#ifdef CONFIG_MTD_REDBOOT_PARTS -+ nr_parts = parse_redboot_partitions(serial_mtd, &parsed_parts); -+ if (nr_parts > 0) -+ printk(KERN_NOTICE "Found RedBoot partition table.\n"); -+ else if (nr_parts < 0) -+ printk(KERN_NOTICE "Error looking for RedBoot partitions.\n"); -+#else -+ parsed_parts = sl2312_partitions; -+ parts = sl2312_partitions; -+ nr_parts = sizeof(sl2312_partitions)/sizeof(*parts); -+ nr_parts = sizeof(sl2312_partitions)/sizeof(*parsed_parts); -+#endif /* CONFIG_MTD_REDBOOT_PARTS */ -+ -+ if (nr_parts > 0) -+ add_mtd_partitions(serial_mtd, parsed_parts, nr_parts); -+ else -+ add_mtd_device(serial_mtd); -+ -+ return 0; -+} -+ -+static void __exit cleanup_sl2312_maps(void) -+{ -+ if (parsed_parts) -+ del_mtd_partitions(serial_mtd); -+ else -+ del_mtd_device(serial_mtd); -+ -+ map_destroy(serial_mtd); -+ -+ -+} -+ -+module_init(init_sl2312_maps); -+module_exit(cleanup_sl2312_maps); -+ -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Plus Chen <plus@storlink.com.tw>"); -+MODULE_DESCRIPTION("MTD map driver for Storlink Sword boards"); -+ ---- /dev/null -+++ b/drivers/mtd/maps/sl2312-flash-cfi.c -@@ -0,0 +1,370 @@ -+/*====================================================================== -+ -+ 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 of the License, 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 -+======================================================================*/ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/ioport.h> -+#include <linux/init.h> -+#include <linux/string.h> -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+ -+#include <asm/hardware.h> -+#include <asm/io.h> -+#include <asm/system.h> -+#include <asm/arch/sl2312.h> -+#include <linux/mtd/kvctl.h> -+#include "sl2312_flashmap.h" -+ -+ -+//extern int parse_afs_partitions(struct mtd_info *, struct mtd_partition **); -+ -+/* the base address of FLASH control register */ -+#define FLASH_CONTROL_BASE_ADDR (IO_ADDRESS(SL2312_FLASH_CTRL_BASE)) -+#define SL2312_GLOBAL_BASE_ADDR (IO_ADDRESS(SL2312_GLOBAL_BASE)) -+ -+/* define read/write register utility */ -+#define FLASH_READ_REG(offset) (__raw_readl(offset+FLASH_CONTROL_BASE_ADDR)) -+#define FLASH_WRITE_REG(offset,val) (__raw_writel(val,offset+FLASH_CONTROL_BASE_ADDR)) -+ -+/* the offset of FLASH control register */ -+enum EMAC_REGISTER { -+ FLASH_ID = 0x0000, -+ FLASH_STATUS = 0x0008, -+ FLASH_TYPE = 0x000c, -+ FLASH_ACCESS = 0x0020, -+ FLASH_ADDRESS = 0x0024, -+ FLASH_DATA = 0x0028, -+ FLASH_TIMING = 0x002c, -+}; -+ -+//#define FLASH_BASE FLASH_CONTROL_BASE_ADDR -+//#define FLASH_SIZE 0x00800000 //INTEGRATOR_FLASH_SIZE -+ -+//#define FLASH_PART_SIZE 8388608 -+ -+static unsigned int flash_indirect_access = 0; -+ -+#ifdef CONFIG_SL2312_SHARE_PIN -+static unsigned int chip_en = 0x00000000; -+ -+void sl2312flash_enable_parallel_flash(void) -+{ -+ unsigned int reg_val; -+ -+ reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30); -+ reg_val = reg_val & 0xfffffffd; -+ writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30); -+ return; -+} -+ -+void sl2312flash_disable_parallel_flash(void) -+{ -+ unsigned int reg_val; -+ -+ reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30); -+ reg_val = reg_val | 0x00000002; -+ writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30); -+ return; -+} -+#endif -+ -+ -+static struct map_info sl2312flash_map = -+{ -+ name: "SL2312 CFI Flash", -+ size: FLASH_SIZE, -+ bankwidth: 2, -+ //bankwidth: 1, //for 8 bits width -+ phys: SL2312_FLASH_BASE, -+}; -+ -+static struct mtd_info *mtd; -+#if 0 -+static struct mtd_partition sl2312_partitions[] = { -+ /* boot code */ -+ { -+ name: "bootloader", -+ offset: 0x00000000, -+ size: 0x20000, -+// mask_flags: MTD_WRITEABLE, -+ }, -+ /* kernel image */ -+ { -+ name: "kerel image", -+ offset: 0x00020000, -+ size: 0x2E0000 -+ }, -+ /* All else is writable (e.g. JFFS) */ -+ { -+ name: "user data", -+ offset: 0x00300000, -+ size: 0x00100000, -+ } -+}; -+#endif -+ -+ -+ -+static int __init sl2312flash_init(void) -+{ -+ struct mtd_partition *parts; -+ int nr_parts = 0; -+ int ret; -+#ifndef CONFIG_SL2312_SHARE_PIN -+ unsigned int reg_val; -+#endif -+ -+ printk("SL2312 MTD Driver Init.......\n"); -+ -+#ifndef CONFIG_SL2312_SHARE_PIN -+ /* enable flash */ -+ reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30); -+ reg_val = reg_val & 0xfffffffd; -+ writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30); -+#else -+ sl2312flash_enable_parallel_flash(); /* enable Parallel FLASH */ -+#endif -+ FLASH_WRITE_REG(FLASH_ACCESS,0x00004000); /* parallel flash direct access mode */ -+ ret = FLASH_READ_REG(FLASH_ACCESS); -+ if (ret == 0x00004000) -+ { -+ flash_indirect_access = 0; /* parallel flash direct access */ -+ } -+ else -+ { -+ flash_indirect_access = 1; /* parallel flash indirect access */ -+ } -+ -+ /* -+ * Also, the CFI layer automatically works out what size -+ * of chips we have, and does the necessary identification -+ * for us automatically. -+ */ -+#ifdef CONFIG_GEMINI_IPI -+ sl2312flash_map.virt = FLASH_VBASE;//(unsigned int *)ioremap(SL2312_FLASH_BASE, FLASH_SIZE); -+#else -+ sl2312flash_map.virt = (unsigned int *)ioremap(SL2312_FLASH_BASE, FLASH_SIZE); -+#endif -+ //printk("sl2312flash_map.virt = %08x\n",(unsigned int)sl2312flash_map.virt); -+ -+// simple_map_init(&sl2312flash_map); -+ -+ mtd = do_map_probe("cfi_probe", &sl2312flash_map); -+ if (!mtd) -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ sl2312flash_disable_parallel_flash(); /* disable Parallel FLASH */ -+#endif -+ return -ENXIO; -+ } -+ mtd->owner = THIS_MODULE; -+// mtd->erase = flash_erase; -+// mtd->read = flash_read; -+// mtd->write = flash_write; -+ -+ parts = sl2312_partitions; -+ nr_parts = sizeof(sl2312_partitions)/sizeof(*parts); -+ ret = add_mtd_partitions(mtd, parts, nr_parts); -+ /*If we got an error, free all resources.*/ -+ if (ret < 0) { -+ del_mtd_partitions(mtd); -+ map_destroy(mtd); -+ } -+#ifdef CONFIG_SL2312_SHARE_PIN -+ sl2312flash_disable_parallel_flash(); /* disable Parallel FLASH */ -+#endif -+ printk("SL2312 MTD Driver Init Success ......\n"); -+ return ret; -+} -+ -+static void __exit sl2312flash_exit(void) -+{ -+ if (mtd) { -+ del_mtd_partitions(mtd); -+ map_destroy(mtd); -+ } -+ -+ if (sl2312flash_map.virt) { -+ iounmap((void *)sl2312flash_map.virt); -+ sl2312flash_map.virt = 0; -+ } -+} -+ -+char chrtohex(char c) -+{ -+ char val; -+ if ((c >= '0') && (c <= '9')) -+ { -+ val = c - '0'; -+ return val; -+ } -+ else if ((c >= 'a') && (c <= 'f')) -+ { -+ val = 10 + (c - 'a'); -+ return val; -+ } -+ else if ((c >= 'A') && (c <= 'F')) -+ { -+ val = 10 + (c - 'A'); -+ return val; -+ } -+ printk("<1>Error number\n"); -+ return 0; -+} -+ -+ -+int get_vlaninfo(vlaninfo* vlan) -+{ -+ vctl_mheader head; -+ vctl_entry entry; -+ struct mtd_info *mymtd=NULL; -+ int i, j, loc = 0; -+ char *payload=0, *tmp1, *tmp2, tmp3[9]; -+ size_t retlen; -+ -+ #ifdef CONFIG_SL2312_SHARE_PIN -+ sl2312flash_enable_parallel_flash(); -+ #endif -+ for(i=0;i<MAX_MTD_DEVICES;i++) -+ { -+ mymtd=get_mtd_device(NULL,i); -+ // printk("mymtd->name: %s\n", mymtd->name); -+ if(mymtd && !strcmp(mymtd->name,"VCTL")) -+ { -+ // printk("%s\n", mymtd->name); -+ break; -+ } -+ } -+ if( i >= MAX_MTD_DEVICES) -+ { -+ printk("Can't find version control\n"); -+ #ifdef CONFIG_SL2312_SHARE_PIN -+ sl2312flash_disable_parallel_flash(); -+ #endif -+ return 0; -+ } -+ -+ if (!mymtd | !mymtd->read) -+ { -+ printk("<1>Can't read Version Configuration\n"); -+ #ifdef CONFIG_SL2312_SHARE_PIN -+ sl2312flash_disable_parallel_flash(); -+ #endif -+ return 0; -+ } -+ -+ mymtd->read(mymtd, 0, VCTL_HEAD_SIZE, &retlen, (u_char*)&head); -+ // printk("entry header: %c%c%c%c\n", head.header[0], head.header[1], head.header[2], head.header[3]); -+ // printk("entry number: %x\n", head.entry_num); -+ if ( strncmp(head.header, "FLFM", 4) ) -+ { -+ printk("VCTL is a erase block\n"); -+ #ifdef CONFIG_SL2312_SHARE_PIN -+ sl2312flash_disable_parallel_flash(); -+ #endif -+ return 0; -+ } -+ loc += retlen; -+ for (i = 0; i < head.entry_num; i++) -+ { -+ mymtd->read(mymtd, loc, VCTL_ENTRY_LEN, &retlen, (u_char*)&entry); -+ // printk("type: %x\n", entry.type); -+ // printk("size: %x\n", entry.size); -+ strncpy(tmp3, entry.header, 4); -+ if (entry.type == VCT_VLAN) -+ { -+ for (j = 0; j < 6 ; j++) -+ { -+ vlan[0].mac[j] = 0; -+ vlan[1].mac[j] = 0; -+ } -+ vlan[0].vlanid = 1; -+ vlan[1].vlanid = 2; -+ vlan[0].vlanmap = 0x7F; -+ vlan[1].vlanmap = 0x80; -+ -+ payload = (char *)kmalloc(entry.size - VCTL_ENTRY_LEN, GFP_KERNEL); -+ loc += VCTL_ENTRY_LEN; -+ mymtd->read(mymtd, loc, entry.size - VCTL_ENTRY_LEN, &retlen, payload); -+ // printk("%s\n", payload); -+ tmp1 = strstr(payload, "MAC1:"); -+ tmp2 = strstr(payload, "MAC2:"); -+ if(!tmp1||!tmp2){ -+ kfree(payload); -+ #ifdef CONFIG_SL2312_SHARE_PIN -+ sl2312flash_disable_parallel_flash(); -+ #endif -+ printk("Error VCTL format!!\n"); -+ return 0; -+ } -+ tmp1 += 7; -+ tmp2 += 7; -+ -+ -+ for (j = 0; j < 6; j++) -+ { -+ vlan[0].mac[j] = chrtohex(tmp1[2*j])*16 + chrtohex(tmp1[(2*j)+1]); -+ vlan[1].mac[j] = chrtohex(tmp2[2*j])*16 + chrtohex(tmp2[(2*j)+1]); -+ } -+ tmp1 = strstr(payload, "ID1:"); -+ tmp2 = strstr(payload, "ID2:"); -+ tmp1 += 4; -+ tmp2 += 4; -+ vlan[0].vlanid = tmp1[0] - '0'; -+ vlan[1].vlanid = tmp2[0] - '0'; -+ tmp1 = strstr(payload, "MAP1:"); -+ tmp2 = strstr(payload, "MAP2:"); -+ tmp1 += 7; -+ tmp2 += 7; -+ vlan[0].vlanmap = chrtohex(tmp1[0]) * 16 + chrtohex(tmp1[1]); -+ vlan[1].vlanmap = chrtohex(tmp2[0]) * 16 + chrtohex(tmp2[1]); -+ // printk("Vlan1 id:%x map:%02x mac:%x%x%x%x%x%x\n", vlan[0].vlanid, vlan[0].vlanmap, vlan[0].mac[0], vlan[0].mac[1], vlan[0].mac[2], vlan[0].mac[3], vlan[0].mac[4], vlan[0].mac[5]); -+ // printk("Vlan2 id:%x map:%02x mac:%x%x%x%x%x%x\n", vlan[1].vlanid, vlan[1].vlanmap, vlan[1].mac[0], vlan[1].mac[1], vlan[1].mac[2], vlan[1].mac[3], vlan[1].mac[4], vlan[1].mac[5]); -+ break; -+ } -+ loc += entry.size; -+ } -+ if ( entry.type == VCT_VLAN ) -+ { -+ #ifdef CONFIG_SL2312_SHARE_PIN -+ sl2312flash_disable_parallel_flash(); -+ #endif -+ kfree(payload); -+ return 1; -+ } -+ if (i >= head.entry_num) -+ printk("Can't find vlan information\n"); -+ #ifdef CONFIG_SL2312_SHARE_PIN -+ sl2312flash_disable_parallel_flash(); -+ #endif -+ return 0; -+} -+ -+EXPORT_SYMBOL(get_vlaninfo); -+ -+ -+module_init(sl2312flash_init); -+module_exit(sl2312flash_exit); -+ -+MODULE_AUTHOR("Storlink Ltd"); -+MODULE_DESCRIPTION("CFI map driver"); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/drivers/mtd/maps/sl2312-flash-m25p80.c -@@ -0,0 +1,498 @@ -+/* -+ * $Id: sl2312-flash-m25p80.c,v 1.2 2006/06/02 08:46:02 middle Exp $ -+ * -+ * Flash and EPROM on Hitachi Solution Engine and similar boards. -+ * -+ * (C) 2001 Red Hat, Inc. -+ * -+ * GPL'd -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+ -+#include <asm/io.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+#include <asm/hardware.h> -+ -+#include <asm/arch/sl2312.h> -+#include <asm/arch/flash.h> -+#include <linux/init.h> //add -+#define g_chipen SERIAL_FLASH_CHIP0_EN //ST -+ -+//static int m25p80_page_program(__u32 address, __u8 data, __u32 schip_en); -+static void m25p80_write_cmd(__u8 cmd, __u32 schip_en); -+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -+ -+ -+static __u32 read_flash_ctrl_reg(__u32 ofs) -+{ -+ __u32 *base; -+ -+ base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs)); -+ return __raw_readl(base); -+} -+ -+static void write_flash_ctrl_reg(__u32 ofs,__u32 data) -+{ -+ __u32 *base; -+ -+ base = (__u32 *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE + ofs)); -+ __raw_writel(data, base); -+} -+ -+static void m25p80_read(__u32 address, __u8 *data, __u32 schip_en) -+{ -+ __u32 opcode,status; -+ __u32 value; -+ -+ //opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | M25P80_READ; -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS_DATA | M25P80_READ; -+ write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address); -+ -+ opcode|=g_chipen; -+ -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ status=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(status&0x80000000) -+ { -+ status=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ -+ value=read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ *data = value & 0xff; -+} -+ -+static int m25p80_page_program(__u32 address, __u8 *data, __u32 schip_en) -+{ -+ __u32 opcode; -+ __u32 status; -+ __u32 tmp; -+ int res = FLASH_ERR_OK; -+ //volatile FLASH_DATA_T* data_ptr = (volatile FLASH_DATA_T*) data; -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | M25P80_READ_STATUS; -+ -+ opcode|=g_chipen; -+ -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ //middle delay_ms(130); -+ status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ if((status&0x02)==0x02) -+ { -+ //middle delay_ms(100); -+ m25p80_write_cmd(M25P80_WRITE_DISABLE, schip_en); -+ } -+ -+ -+ m25p80_write_cmd(M25P80_WRITE_ENABLE, schip_en); -+ ////middle delay_ms(10); -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS_DATA | M25P80_PAGE_PROGRAM; -+ write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address); -+ write_flash_ctrl_reg(FLASH_WRITE_DATA_OFFSET, *data); -+ -+ //status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ //while(status!=data) -+ //{ -+ // status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ // //middle delay_ms(10); -+ //} -+ -+ opcode|=g_chipen; -+ -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ //opcode=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | M25P80_READ_STATUS; -+ -+ opcode|=g_chipen; -+ -+ -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ //while(status&0xfd) -+ while(status&0x01) -+ { -+ //if((status&0x9c)!=0) -+ // printf(" m25p80_page_program Protect Status = %x\n",status); -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ flash_delay(); -+ schedule(); -+ //middle delay_ms(50); -+ } -+ //printf("status = %x, data = %x\n",status,data); -+ if((status&0x02)==0x02) -+ { -+ //middle delay_ms(100); -+ m25p80_write_cmd(M25P80_WRITE_DISABLE, schip_en); -+ } -+ //};//while (len > 0) -+ return res; -+} -+ -+void m25p80_copy_from(struct map_info *map, void *buf, unsigned long ofs, ssize_t len) -+{ -+// __u32 size; -+ __u8 *buffer; -+ __u32 length;//i, j, -+ -+ length = len; -+ buffer = (__u8 *)buf; -+ while(len) -+ { -+ m25p80_read(ofs, buffer, g_chipen); -+ buffer++; -+ ofs++; -+ len --; -+ } ; -+ -+} -+ -+__u32 m25p80_read32(struct map_info *map, unsigned long ofs) -+{ -+ -+ return read_flash_ctrl_reg(ofs); -+ -+ -+} -+ -+void m25p80_write32(struct map_info *map, __u32 d, unsigned long ofs) -+{ -+ -+ write_flash_ctrl_reg(ofs, d); -+ -+} -+ -+void m25p80_copy_to(struct map_info *map, unsigned long ofs, void *buf, ssize_t len) -+{ -+ __u32 size, i, ret; -+ -+ while(len > 0) -+ { -+ if(len >= M25P80_PAGE_SIZE) -+ size = M25P80_PAGE_SIZE; -+ else -+ size = len; -+ -+ for(i=0;i<size;i++) -+ { -+ ret = m25p80_page_program( (ofs+i), (buf+i), g_chipen); -+ } -+ buf+=M25P80_PAGE_SIZE; -+ ofs+=M25P80_PAGE_SIZE; -+ len-=M25P80_PAGE_SIZE; -+ -+ }; -+ -+ -+} -+ -+static struct mtd_info *serial_mtd; -+ -+static struct mtd_partition *parsed_parts; -+ -+static struct map_info m25p80_map = { -+ -+ .name = "SL2312 serial flash m25p80", -+ .size = 1048576, //0x100000, -+ //buswidth: 4, -+ .bankwidth = 4, -+ .phys = SL2312_FLASH_BASE, -+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS -+ .copy_from = m25p80_copy_from, -+ .read = m25p80_read32, -+ .write = m25p80_write32, -+ .copy_to = m25p80_copy_to -+#endif -+}; -+ -+ -+ -+static struct mtd_partition m25p80_partitions[] = { -+ -+ /* boot code */ -+ { .name = "bootloader", .offset = 0x00000000, .size = 0x20000, }, -+ /* kernel image */ -+ { .name = "kerel image", .offset = 0x000020000, .size = 0xC0000 }, -+ /* All else is writable (e.g. JFFS) */ -+ { .name = "user data", .offset = 0x000E0000, .size = 0x00010000, }, -+ -+ -+}; -+ -+void flash_delay() -+{ -+ int i,j; -+ for(i=0;i<0x100;i++) -+ j=i*3+5; -+} -+ -+int m25p80_sector_erase(__u32 address, __u32 schip_en) -+{ -+ __u32 opcode; -+ __u32 status; -+ __u32 tmp; -+ int res = FLASH_ERR_OK; -+ //printf("\n-->m25p80_sector_erase"); -+ if(address >= FLASH_START) -+ address-=FLASH_START; -+ -+ m25p80_write_cmd(M25P80_WRITE_ENABLE, schip_en); -+ //printf("\n m25p80_sector_erase : after we-en"); -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_SHIFT_ADDRESS | M25P80_SECTOR_ERASE; -+ write_flash_ctrl_reg(FLASH_ADDRESS_OFFSET, address); -+ #ifdef MIDWAY_DIAG -+ opcode|=schip_en; -+ #endif -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | M25P80_READ_STATUS; -+ #ifdef MIDWAY_DIAG -+ opcode|=schip_en; -+ #endif -+ -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ //while(status&0xfd) -+ while(status&0x01) -+ { -+ //if((status&0x9c)!=0) -+ // printf(" m25p80_sector_erase Protect Status = %x\n",status); -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ flash_delay(); -+ schedule(); -+ //middle delay_ms(50); -+ } -+ if((status&0x02)==0x02) -+ { -+ //middle delay_ms(100); -+ m25p80_write_cmd(M25P80_WRITE_DISABLE, schip_en); -+ } -+ //printf("\n<--m25p80_sector_erase"); -+ return res; -+} -+ -+static void m25p80_write_cmd(__u8 cmd, __u32 schip_en) -+{ -+ __u32 opcode,tmp; -+ __u32 status; -+ -+ -+ -+ -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE | cmd; -+ -+ opcode|=g_chipen; -+ -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ ////// -+ opcode = 0x80000000 | FLASH_ACCESS_ACTION_OPCODE_DATA | M25P80_READ_STATUS; -+ -+ opcode|=g_chipen; -+ -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ //middle delay_ms(130); -+ status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ //printf("\ncmd =%x status = %x",cmd,status); -+ if(cmd==M25P80_WRITE_ENABLE) -+ { -+ //printf("\n**-->enable** status = %x",status); -+ //middle delay_ms(100); -+ while((status&0x03) != 2) -+ { -+ //if((status&0x9c)!=0) -+ // printf(" M25P80_WRITE_ENABLE Protect Status = %x\n",status); -+ -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ //flash_delay(); -+ } -+ status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ //printf("\n**enable** status = %x",status); -+ flash_delay(); -+ schedule(); -+ //middle delay_ms(100); -+ } -+ } -+ else if(cmd==M25P80_WRITE_DISABLE) -+ { -+ //while((status&0x03) == 2) -+ // printf("\n**disable** status = %x",status); -+ //middle delay_ms(100); -+ while((status&0x03) != 0) -+ { -+ //m25p80_write_status((status&0xfd),schip_en); -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ //printf("\n**disable** status = %x",status); -+ flash_delay(); -+ schedule(); -+ //middle delay_ms(50); -+ } -+ } -+ else -+ { -+ //while((status&0x01) !=0) -+ while((status&0x01) !=0) -+ { -+ write_flash_ctrl_reg(FLASH_ACCESS_OFFSET, opcode); -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ while(tmp&0x80000000) -+ { -+ tmp=read_flash_ctrl_reg(FLASH_ACCESS_OFFSET); -+ flash_delay(); -+ schedule(); -+ } -+ status = read_flash_ctrl_reg(FLASH_READ_DATA_OFFSET); -+ flash_delay(); -+ schedule(); -+ //middle delay_ms(50); -+ } -+ } -+ ////// -+ -+ //printf("\n<-- status = %x",status); -+} -+ -+static int __init init_sl2312_m25p80(void) -+{ -+ int nr_parts = 0; -+ struct mtd_partition *parts; -+ -+ serial_mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); -+ if (!serial_mtd) -+ return NULL; -+ -+ memset(serial_mtd, 0, sizeof(struct mtd_info)); -+ m25p80_map.virt = (unsigned long)ioremap(SL2312_FLASH_BASE, SFLASH_SIZE);//(unsigned long)ioremap(FLASH_START, SFLASH_SIZE); -+ if (!m25p80_map.virt) { -+ printk(" failed to ioremap \n"); -+ return -EIO; -+ } -+ serial_mtd = do_map_probe("map_serial", &m25p80_map); -+ if (serial_mtd) { -+ serial_mtd->owner = THIS_MODULE; -+ -+ } -+ -+#ifdef CONFIG_MTD_REDBOOT_PARTS -+ nr_parts = parse_redboot_partitions(serial_mtd, &parsed_parts); -+ if (nr_parts > 0) -+ printk(KERN_NOTICE "Found RedBoot partition table.\n"); -+ else if (nr_parts < 0) -+ printk(KERN_NOTICE "Error looking for RedBoot partitions.\n"); -+#else -+ parsed_parts = m25p80_partitions; -+ parts = m25p80_partitions; -+ nr_parts = sizeof(m25p80_partitions)/sizeof(*parts); -+ nr_parts = sizeof(m25p80_partitions)/sizeof(*parsed_parts); -+#endif /* CONFIG_MTD_REDBOOT_PARTS */ -+ -+ if (nr_parts > 0) -+ add_mtd_partitions(serial_mtd, parsed_parts, nr_parts); -+ else -+ add_mtd_device(serial_mtd); -+ -+ return 0; -+} -+ -+static void __exit cleanup_sl2312_m25p80(void) -+{ -+ if (parsed_parts) -+ del_mtd_partitions(serial_mtd); -+ else -+ del_mtd_device(serial_mtd); -+ -+ map_destroy(serial_mtd); -+ -+ -+} -+ -+module_init(init_sl2312_m25p80); -+module_exit(cleanup_sl2312_m25p80); -+ -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Plus Chen <plus@storlink.com.tw>"); -+MODULE_DESCRIPTION("MTD map driver for Storlink Sword boards"); -+ ---- /dev/null -+++ b/drivers/mtd/maps/sl2312_flashmap.h -@@ -0,0 +1,20 @@ -+/* -+ * Please note that the name are used in mkflash script. Therefore -+ * don't change them. If you want to add different partitions, you -+ * will need to modify mkflash script as well so that the end image -+ * is what you include here! -+ * -+ * Also, the 7th item is always the size, so please don't add extra -+ * spaces in the name or other items. -+ * -+ * - Alan -+ */ -+ -+static struct mtd_partition sl2312_partitions[] = { -+ { name: "RedBoot", offset: 0x00000000, size: 0x00020000, }, -+ { name: "kernel", offset: 0x00020000, size: 0x00100000, }, -+ { name: "rootfs", offset: 0x00120000, size: 0x006A0000, }, -+ { name: "VCTL", offset: 0x007C0000, size: 0x00010000, }, -+ { name: "cfg", offset: 0x007D0000, size: 0x00020000, }, -+ { name: "FIS directory", offset: 0x007F0000, size: 0x00010000, } -+}; ---- /dev/null -+++ b/drivers/mtd/maps/sl2312_flashmap.h.16MB -@@ -0,0 +1,21 @@ -+/* -+ * Please note that the name are used in mkflash script. Therefore -+ * don't change them. If you want to add different partitions, you -+ * will need to modify mkflash script as well so that the end image -+ * is what you include here! -+ * -+ * Also, the 7th item is always the size, so please don't add extra -+ * spaces in the name or other items. -+ * -+ * - Alan -+ */ -+ -+static struct mtd_partition sl2312_partitions[] = { -+ { name: "RedBoot", offset: 0x00000000, size: 0x00020000, }, -+ { name: "Kernel", offset: 0x00020000, size: 0x00300000, }, -+ { name: "Ramdisk", offset: 0x00320000, size: 0x00600000, }, -+ { name: "Application", offset: 0x00920000, size: 0x00600000, }, -+ { name: "VCTL", offset: 0x00F20000, size: 0x00020000, }, -+ { name: "CurConf", offset: 0x00F40000, size: 0x000A0000, }, -+ { name: "FIS directory", offset: 0x00FE0000, size: 0x00020000, } -+}; ---- /dev/null -+++ b/drivers/mtd/maps/sl2312_flashmap.h.8MB -@@ -0,0 +1,21 @@ -+/* -+ * Please note that the name are used in mkflash script. Therefore -+ * don't change them. If you want to add different partitions, you -+ * will need to modify mkflash script as well so that the end image -+ * is what you include here! -+ * -+ * Also, the 7th item is always the size, so please don't add extra -+ * spaces in the name or other items. -+ * -+ * - Alan -+ */ -+ -+static struct mtd_partition sl2312_partitions[] = { -+ { name: "RedBoot", offset: 0x00000000, size: 0x00020000, }, -+ { name: "Kernel", offset: 0x00020000, size: 0x00200000, }, -+ { name: "Ramdisk", offset: 0x00220000, size: 0x00280000, }, -+ { name: "Application", offset: 0x004A0000, size: 0x00300000, }, -+ { name: "VCTL", offset: 0x007A0000, size: 0x00020000, }, -+ { name: "CurConf", offset: 0x007C0000, size: 0x00020000, }, -+ { name: "FIS directory", offset: 0x007E0000, size: 0x00020000, } -+}; ---- a/drivers/mtd/mtdchar.c -+++ b/drivers/mtd/mtdchar.c -@@ -59,6 +59,77 @@ struct mtd_file_info { - enum mtd_file_modes mode; - }; - -+/*********************************************************************** -+/* Storlink SoC -- flash -+/***********************************************************************/ -+#ifdef CONFIG_SL2312_SHARE_PIN -+unsigned int share_pin_flag=0; // bit0:FLASH, bit1:UART, bit2:EMAC, bit3-4:IDE -+unsigned int check_sleep_flag=0; // bit0:FLASH, bit1:IDE -+static spinlock_t sl2312_flash_lock = SPIN_LOCK_UNLOCKED; -+EXPORT_SYMBOL(share_pin_flag); -+int dbg=0; -+DECLARE_WAIT_QUEUE_HEAD(wq); -+extern struct wait_queue_head_t *flash_wait; -+unsigned int flash_req=0; -+void mtd_lock() -+{ -+ struct task_struct *tsk = current; -+ unsigned int value ; -+ unsigned long flags; -+ flash_req = 1; -+ DECLARE_WAITQUEUE(wait, tsk); -+ add_wait_queue(&wq, &wait); -+ for(;;) -+ { -+ set_task_state(tsk, TASK_INTERRUPTIBLE); -+ spin_lock_irqsave(&sl2312_flash_lock,flags); -+ if((share_pin_flag&0x1E)){//||(check_sleep_flag&0x00000002)) { -+ spin_unlock_irqrestore(&sl2312_flash_lock, flags); -+ check_sleep_flag |= 0x00000001; -+ if(dbg) -+ printk("mtd yield %x %x\n",share_pin_flag,check_sleep_flag); -+ wake_up_interruptible(&flash_wait); -+ schedule(); -+ } -+ else { -+ check_sleep_flag &= ~0x01; -+ share_pin_flag |= 0x00000001 ; // set share pin flag -+ spin_unlock_irqrestore(&sl2312_flash_lock, flags); -+ value = readl(IO_ADDRESS((SL2312_GLOBAL_BASE+GLOBAL_MISC_REG))); -+ value = value & (~PFLASH_SHARE_BIT) ; -+ writel(value,IO_ADDRESS((SL2312_GLOBAL_BASE+GLOBAL_MISC_REG))); -+ if(dbg) -+ printk("mtd Go %x %x\n",share_pin_flag,check_sleep_flag); -+ tsk->state = TASK_RUNNING; -+ remove_wait_queue(&wq, &wait); -+ return ; -+ } -+ } -+} -+ -+void mtd_unlock() -+{ -+ unsigned int value ; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&sl2312_flash_lock,flags); // Disable IRQ -+ value = readl(IO_ADDRESS((SL2312_GLOBAL_BASE+GLOBAL_MISC_REG))); -+ value = value | PFLASH_SHARE_BIT ; // Disable Flash PADs -+ writel(value,IO_ADDRESS((SL2312_GLOBAL_BASE+GLOBAL_MISC_REG))); -+ share_pin_flag &= ~(0x00000001); // clear share pin flag -+ check_sleep_flag &= ~0x00000001; -+ spin_unlock_irqrestore(&sl2312_flash_lock, flags); // Restore IRQ -+ if (check_sleep_flag & 0x00000002) -+ { -+ check_sleep_flag &= ~(0x00000002); -+ wake_up_interruptible(&flash_wait); -+ } -+ DEBUG(MTD_DEBUG_LEVEL0, "Flash Unlock...\n"); -+ flash_req = 0; -+} -+#endif -+/***********************************************************************/ -+ - static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) - { - struct mtd_file_info *mfi = file->private_data; -@@ -162,13 +233,21 @@ static ssize_t mtd_read(struct file *fil - int len; - char *kbuf; - -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_lock(); // sl2312 share pin lock -+#endif -+ - DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); - - if (*ppos + count > mtd->size) - count = mtd->size - *ppos; - -- if (!count) -+ if (!count){ -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return 0; -+ } - - /* FIXME: Use kiovec in 2.5 to lock down the user's buffers - and pass them directly to the MTD functions */ -@@ -178,8 +257,12 @@ static ssize_t mtd_read(struct file *fil - else - kbuf=kmalloc(count, GFP_KERNEL); - -- if (!kbuf) -+ if (!kbuf) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -ENOMEM; -+ } - - while (count) { - -@@ -224,6 +307,9 @@ static ssize_t mtd_read(struct file *fil - *ppos += retlen; - if (copy_to_user(buf, kbuf, retlen)) { - kfree(kbuf); -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; - } - else -@@ -235,13 +321,19 @@ static ssize_t mtd_read(struct file *fil - count = 0; - } - else { -- kfree(kbuf); -+ kfree(kbuf); -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return ret; - } - - } - - kfree(kbuf); -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return total_retlen; - } /* mtd_read */ - -@@ -255,24 +347,40 @@ static ssize_t mtd_write(struct file *fi - int ret=0; - int len; - -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_lock(); // sl2312 share pin lock -+#endif -+ - DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); - -- if (*ppos == mtd->size) -+ if (*ppos == mtd->size){ -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -ENOSPC; -+ } - - if (*ppos + count > mtd->size) - count = mtd->size - *ppos; - -- if (!count) -+ if (!count){ -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return 0; -+ } - - if (count > MAX_KMALLOC_SIZE) - kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL); - else - kbuf=kmalloc(count, GFP_KERNEL); - -- if (!kbuf) -+ if (!kbuf) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -ENOMEM; -+ } - - while (count) { - -@@ -283,6 +391,9 @@ static ssize_t mtd_write(struct file *fi - - if (copy_from_user(kbuf, buf, len)) { - kfree(kbuf); -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; - } - -@@ -323,11 +434,17 @@ static ssize_t mtd_write(struct file *fi - } - else { - kfree(kbuf); -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return ret; - } - } - - kfree(kbuf); -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return total_retlen; - } /* mtd_write */ - -@@ -381,36 +498,67 @@ static int mtd_ioctl(struct inode *inode - u_long size; - struct mtd_info_user info; - -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_lock(); // sl2312 share pin lock -+#endif -+ - DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); - - size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; - if (cmd & IOC_IN) { - if (!access_ok(VERIFY_READ, argp, size)) -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - } - if (cmd & IOC_OUT) { - if (!access_ok(VERIFY_WRITE, argp, size)) -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - } - - switch (cmd) { - case MEMGETREGIONCOUNT: - if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - break; - - case MEMGETREGIONINFO: - { - struct region_info_user ur; - -- if (copy_from_user(&ur, argp, sizeof(struct region_info_user))) -+ if (copy_from_user(&ur, argp, sizeof(struct region_info_user))) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - -- if (ur.regionindex >= mtd->numeraseregions) -+ if (ur.regionindex >= mtd->numeraseregions) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EINVAL; -+ } - if (copy_to_user(argp, &(mtd->eraseregions[ur.regionindex]), -- sizeof(struct mtd_erase_region_info))) -+ sizeof(struct mtd_erase_region_info))) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - break; - } - -@@ -433,7 +581,12 @@ static int mtd_ioctl(struct inode *inode - struct erase_info *erase; - - if(!(file->f_mode & 2)) -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EPERM; -+ } - - erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL); - if (!erase) -@@ -447,6 +600,9 @@ static int mtd_ioctl(struct inode *inode - if (copy_from_user(&erase->addr, argp, - sizeof(struct erase_info_user))) { - kfree(erase); -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; - } - erase->mtd = mtd; -@@ -484,14 +640,26 @@ static int mtd_ioctl(struct inode *inode - struct mtd_oob_buf buf; - struct mtd_oob_ops ops; - -- if(!(file->f_mode & 2)) -+ if(!(file->f_mode & 2)) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EPERM; -+ } - -- if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) -+ if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - -- if (buf.length > 4096) -+ if (buf.length > 4096) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EINVAL; -+ } - - if (!mtd->write_oob) - ret = -EOPNOTSUPP; -@@ -499,8 +667,12 @@ static int mtd_ioctl(struct inode *inode - ret = access_ok(VERIFY_READ, buf.ptr, - buf.length) ? 0 : EFAULT; - -- if (ret) -+ if (ret) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return ret; -+ } - - ops.ooblen = buf.length; - ops.ooboffs = buf.start & (mtd->oobsize - 1); -@@ -536,19 +708,35 @@ static int mtd_ioctl(struct inode *inode - struct mtd_oob_buf buf; - struct mtd_oob_ops ops; - -- if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) -+ if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - -- if (buf.length > 4096) -+ if (buf.length > 4096) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EINVAL; -+ } - -- if (!mtd->read_oob) -+ if (!mtd->read_oob) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - ret = -EOPNOTSUPP; -+ } - else - ret = access_ok(VERIFY_WRITE, buf.ptr, - buf.length) ? 0 : -EFAULT; -- if (ret) -+ if (ret) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return ret; -+ } - - ops.ooblen = buf.length; - ops.ooboffs = buf.start & (mtd->oobsize - 1); -@@ -580,7 +768,12 @@ static int mtd_ioctl(struct inode *inode - struct erase_info_user info; - - if (copy_from_user(&info, argp, sizeof(info))) -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - - if (!mtd->lock) - ret = -EOPNOTSUPP; -@@ -594,7 +787,12 @@ static int mtd_ioctl(struct inode *inode - struct erase_info_user info; - - if (copy_from_user(&info, argp, sizeof(info))) -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - - if (!mtd->unlock) - ret = -EOPNOTSUPP; -@@ -629,11 +827,21 @@ static int mtd_ioctl(struct inode *inode - loff_t offs; - - if (copy_from_user(&offs, argp, sizeof(loff_t))) -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - if (!mtd->block_isbad) - ret = -EOPNOTSUPP; - else -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return mtd->block_isbad(mtd, offs); -+ } - break; - } - -@@ -642,11 +850,21 @@ static int mtd_ioctl(struct inode *inode - loff_t offs; - - if (copy_from_user(&offs, argp, sizeof(loff_t))) -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - if (!mtd->block_markbad) - ret = -EOPNOTSUPP; - else -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return mtd->block_markbad(mtd, offs); -+ } - break; - } - -@@ -654,8 +872,12 @@ static int mtd_ioctl(struct inode *inode - case OTPSELECT: - { - int mode; -- if (copy_from_user(&mode, argp, sizeof(int))) -+ if (copy_from_user(&mode, argp, sizeof(int))) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -+ } - - mfi->mode = MTD_MODE_NORMAL; - -@@ -670,7 +892,12 @@ static int mtd_ioctl(struct inode *inode - { - struct otp_info *buf = kmalloc(4096, GFP_KERNEL); - if (!buf) -+ { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -ENOMEM; -+ } - ret = -EOPNOTSUPP; - switch (mfi->mode) { - case MTD_MODE_OTP_FACTORY: -@@ -701,12 +928,24 @@ static int mtd_ioctl(struct inode *inode - { - struct otp_info info; - -- if (mfi->mode != MTD_MODE_OTP_USER) -+ if (mfi->mode != MTD_MODE_OTP_USER) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EINVAL; -- if (copy_from_user(&info, argp, sizeof(info))) -+ } -+ if (copy_from_user(&info, argp, sizeof(info))) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EFAULT; -- if (!mtd->lock_user_prot_reg) -+ } -+ if (!mtd->lock_user_prot_reg) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EOPNOTSUPP; -+ } - ret = mtd->lock_user_prot_reg(mtd, info.start, info.length); - break; - } -@@ -742,8 +981,12 @@ static int mtd_ioctl(struct inode *inode - break; - - case MTD_MODE_RAW: -- if (!mtd->read_oob || !mtd->write_oob) -+ if (!mtd->read_oob || !mtd->write_oob) { -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif - return -EOPNOTSUPP; -+ } - mfi->mode = arg; - - case MTD_MODE_NORMAL: -@@ -766,6 +1009,10 @@ static int mtd_ioctl(struct inode *inode - ret = -ENOTTY; - } - -+#ifdef CONFIG_SL2312_SHARE_PIN -+ mtd_unlock(); // sl2312 share pin lock -+#endif -+ - return ret; - } /* memory_ioctl */ - ---- a/drivers/mtd/nand/Kconfig -+++ b/drivers/mtd/nand/Kconfig -@@ -44,6 +44,13 @@ config MTD_NAND_AUTCPU12 - This enables the driver for the autronix autcpu12 board to - access the SmartMediaCard. - -+config MTD_NAND_SL2312 -+ tristate "NAND Flash device on Storlink board" -+ depends on ARM && MTD_NAND && ARCH_SL2312 -+ help -+ This enables the driver for the Storlink board to -+ access the nand device. -+ - config MTD_NAND_EDB7312 - tristate "Support for Cirrus Logic EBD7312 evaluation board" - depends on ARCH_EDB7312 ---- /dev/null -+++ b/drivers/mtd/nand/sl2312-flash-nand.c -@@ -0,0 +1,2287 @@ -+/* -+ * drivers/mtd/sl2312.c -+ * -+ * $Id: sl2312-flash-nand.c,v 1.5 2006/06/15 07:02:29 middle Exp $ -+ * -+ * Copyright (C) 2001 Toshiba Corporation -+ * -+ * 2003 (c) MontaVista Software, Inc. This file is licensed under -+ * the terms of the GNU General Public License version 2. This program -+ * is licensed "as is" without any warranty of any kind, whether express -+ * or implied. -+ * -+ */ -+ -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/nand.h> -+#include <linux/mtd/nand_ecc.h> -+#include <linux/mtd/partitions.h> -+#include <linux/delay.h> -+#include <asm/io.h> -+#include <asm/hardware.h> -+#include <asm/arch/sl2312.h> -+#include "sl2312-flash-nand.h" -+ -+ -+#include <linux/errno.h> -+#include <linux/sched.h> -+#include <linux/types.h> -+#include <linux/mtd/compatmac.h> -+#include <linux/interrupt.h> -+#include <linux/bitops.h> -+ -+ -+/* -+ * NAND low-level MTD interface functions -+ */ -+static void sl2312_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len); -+static void sl2312_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len); -+static int sl2312_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len); -+ -+static int sl2312_nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); -+static int sl2312_nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); -+static int sl2312_nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); -+static int sl2312_nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf); -+static int sl2312_nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, -+ size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); -+static int sl2312_nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf); -+static int sl2312_nand_writev (struct mtd_info *mtd, const struct kvec *vecs, -+ unsigned long count, loff_t to, size_t * retlen); -+static int sl2312_nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, -+ unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); -+static int sl2312_nand_erase (struct mtd_info *mtd, struct erase_info *instr, int allowbbt); -+static void sl2312_nand_sync (struct mtd_info *mtd); -+static int sl2312_nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel); -+static int sl2312_nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt); -+static int sl2312_nand_erase_block(struct mtd_info *mtd, int page); -+ -+/* -+ * MTD structure for sl2312 NDFMC -+ */ -+static struct mtd_info *sl2312_mtd = NULL; -+static int nand_page=0,nand_col=0; -+ -+/* Define default oob placement schemes for large and small page devices */ -+static struct nand_oobinfo nand_oob_8 = { -+ .useecc = MTD_NANDECC_AUTOPLACE, -+ .eccbytes = 3, -+ .eccpos = {0, 1, 2}, -+ .oobfree = { {3, 2}, {6, 2} } -+}; -+ -+static struct nand_oobinfo nand_oob_16 = { -+ .useecc = MTD_NANDECC_AUTOPLACE, -+ .eccbytes = 6, -+ .eccpos = {0, 1, 2, 3, 6, 7}, -+ .oobfree = { {8, 8} } -+}; -+ -+static struct nand_oobinfo nand_oob_64 = { -+ .useecc = MTD_NANDECC_AUTOPLACE, -+ .eccbytes = 24, -+ .eccpos = { -+ 40, 41, 42, 43, 44, 45, 46, 47, -+ 48, 49, 50, 51, 52, 53, 54, 55, -+ 56, 57, 58, 59, 60, 61, 62, 63}, -+ .oobfree = { {2, 38} } -+}; -+ -+ -+/* -+ * Define partitions for flash device -+ */ -+/* the base address of FLASH control register */ -+#define FLASH_CONTROL_BASE_ADDR (IO_ADDRESS(SL2312_FLASH_CTRL_BASE)) -+#define SL2312_GLOBAL_BASE_ADDR (IO_ADDRESS(SL2312_GLOBAL_BASE)) -+//#define SL2312_FLASH_BASE_ADDR (IO_ADDRESS(SL2312_FLASH_BASE)) -+#define SL2312_FLASH_BASE_ADDR FLASH_VADDR(SL2312_FLASH_BASE) -+static unsigned int CHIP_EN; -+/* define read/write register utility */ -+//#define FLASH_READ_REG(offset) (__raw_readl(offset+FLASH_CONTROL_BASE_ADDR)) -+//#define FLASH_WRITE_REG(offset,val) (__raw_writel(val,offset+FLASH_CONTROL_BASE_ADDR)) -+//#define FLASH_READ_DATA(offset) (__raw_readb(offset+SL2312_FLASH_BASE_ADDR)) -+//#define FLASH_WRITE_DATA(offset,val) (__raw_writeb(val,offset+SL2312_FLASH_BASE_ADDR)) -+ -+unsigned int FLASH_READ_REG(unsigned int addr) -+{ -+ unsigned int *base; -+ unsigned int data; -+ -+ base = (unsigned int *)(FLASH_CONTROL_BASE_ADDR + addr); -+ data = *base; -+ return (data); -+} -+ -+void FLASH_WRITE_REG(unsigned int addr,unsigned int data) -+{ -+ unsigned int *base; -+ -+ base = (unsigned int *)(FLASH_CONTROL_BASE_ADDR + addr); -+ *base = data; -+ return; -+} -+ -+unsigned int FLASH_READ_DATA(unsigned int addr) -+{ -+ unsigned char *base; -+ unsigned int data; -+ -+ base = (unsigned char *)(SL2312_FLASH_BASE_ADDR + addr); -+ data = *base; -+ return (data); -+} -+ -+void FLASH_WRITE_DATA(unsigned int addr,unsigned int data) -+{ -+ unsigned char *base; -+ -+ base = (unsigned char *)(SL2312_FLASH_BASE_ADDR + addr); -+ *base = data; -+ return; -+} -+ -+/* the offset of FLASH control register */ -+enum NFLASH_REGISTER { -+ NFLASH_ID = 0x0000, -+ NFLASH_STATUS = 0x0008, -+ NFLASH_TYPE = 0x000c, -+ NFLASH_ACCESS = 0x0030, -+ NFLASH_COUNT = 0x0034, -+ NFLASH_CMD_ADDR = 0x0038, -+ NFLASH_ADDRESS = 0x003C, -+ NFLASH_DATA = 0x0040, -+ NFLASH_TIMING = 0x004C, -+ NFLASH_ECC_STATUS = 0x0050, -+ NFLASH_ECC_CONTROL = 0x0054, -+ NFLASH_ECC_OOB = 0x005c, -+ NFLASH_ECC_CODE_GEN0 = 0x0060, -+ NFLASH_ECC_CODE_GEN1 = 0x0064, -+ NFLASH_ECC_CODE_GEN2 = 0x0068, -+ NFLASH_ECC_CODE_GEN3 = 0x006C, -+ NFLASH_FIFO_CONTROL = 0x0070, -+ NFLASH_FIFO_STATUS = 0x0074, -+ NFLASH_FIFO_ADDRESS = 0x0078, -+ NFLASH_FIFO_DATA = 0x007c, -+}; -+ -+ -+ -+//#define FLASH_BASE FLASH_CONTROL_BASE_ADDR -+//#define FLASH_SIZE 0x00800000 //INTEGRATOR_FLASH_SIZE -+ -+//#define FLASH_PART_SIZE 8388608 -+ -+//static unsigned int flash_indirect_access = 0; -+ -+ -+#ifdef CONFIG_SL2312_SHARE_PIN -+void sl2312flash_enable_nand_flash(void) -+{ -+ unsigned int reg_val; -+ -+ reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30); -+ reg_val = reg_val & 0xfffffffb; -+ writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30); -+ return; -+} -+ -+void sl2312flash_disable_nand_flash(void) -+{ -+ unsigned int reg_val; -+ -+ reg_val = readl(SL2312_GLOBAL_BASE_ADDR + 0x30); -+ reg_val = reg_val | 0x00000004; -+ writel(reg_val,SL2312_GLOBAL_BASE_ADDR + 0x30); -+ return; -+} -+#endif -+ -+extern struct nand_oobinfo jffs2_oobinfo; -+/* -+ * Define partitions for flash devices -+ */ -+ -+static struct mtd_partition sl2312_partitions[] = { -+ { name: "RedBoot", offset: 0x00000000, size: 0x0020000, }, -+ { name: "Kernel", offset: 0x00020000, size: 0x00200000, }, -+ { name: "Ramdisk", offset: 0x00220000, size: 0x00280000, }, -+ { name: "Application", offset: 0x004A0000, size: 0x00320000, }, -+ { name: "VCTL", offset: 0x007C0000, size: 0x20000, }, -+ { name: "CurConf", offset: 0x007E0000, size: 0x20000, }, -+ { name: "FIS directory", offset: 0x007e0000, size: 0x00020000, } -+ -+}; -+ -+ -+/* -+ * hardware specific access to control-lines -+*/ -+static void sl2312_hwcontrol(struct mtd_info *mtd, int cmd) -+{ -+ -+ return ; -+} -+ -+static int sl2312_nand_scan_bbt(struct mtd_info *mtd) -+{ -+ return 0; -+} -+ -+/** -+ * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad -+ * @mtd: MTD device structure -+ * @ofs: offset relative to mtd start -+ */ -+static int sl2312_nand_block_isbad (struct mtd_info *mtd, loff_t ofs) -+{ -+ /* Check for invalid offset */ -+ if (ofs > mtd->size) -+ return -EINVAL; -+ -+ return sl2312_nand_block_checkbad (mtd, ofs, 1, 0); -+} -+ -+/** -+ * nand_block_checkbad - [GENERIC] Check if a block is marked bad -+ * @mtd: MTD device structure -+ * @ofs: offset from device start -+ * @getchip: 0, if the chip is already selected -+ * @allowbbt: 1, if its allowed to access the bbt area -+ * -+ * Check, if the block is bad. Either by reading the bad block table or -+ * calling of the scan function. -+ */ -+ -+static int sl2312_nand_erase_block(struct mtd_info *mtd, int page) -+{ -+ int opcode; -+ /* Send commands to erase a page */ -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0 -+ -+ if(mtd->oobblock > 528) -+ FLASH_WRITE_REG(NFLASH_COUNT, 0x7f0fff21); // 3 address & 2 command -+ else -+ FLASH_WRITE_REG(NFLASH_COUNT, 0x7f0fff11); // 2 address & 2 command -+ -+ FLASH_WRITE_REG(NFLASH_CMD_ADDR, 0x0000d060); // write read id command -+ FLASH_WRITE_REG(NFLASH_ADDRESS, page); //write address 0x00 -+ -+ -+ -+ /* read maker code */ -+ opcode = 0x80003000|DWIDTH|CHIP_EN; //set start bit & 8bits write command -+ FLASH_WRITE_REG(NFLASH_ACCESS, opcode); -+ -+ while(opcode&0x80000000) //polling flash access 31b -+ { -+ opcode=FLASH_READ_REG(NFLASH_ACCESS); -+ //sl2312_flash_delay(); -+ schedule(); -+ //cond_resched(); -+ } -+} -+ -+void sl2312_flash_delay(void) -+{ -+ int i; -+ -+ for(i=0; i<50; i++) -+ i=i; -+} -+ -+static int sl2312_nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) -+{ -+ struct nand_chip *this = mtd->priv; -+ -+ if (!this->bbt) -+ return this->block_bad(mtd, ofs, getchip); -+ -+ /* Return info from the table */ -+ return nand_isbad_bbt (mtd, ofs, allowbbt); -+} -+ -+/** -+ * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad -+ * @mtd: MTD device structure -+ * @ofs: offset relative to mtd start -+ */ -+static int sl2312_nand_block_markbad (struct mtd_info *mtd, loff_t ofs) -+{ -+ struct nand_chip *this = mtd->priv; -+ int ret; -+ -+ if ((ret = sl2312_nand_block_isbad(mtd, ofs))) { -+ /* If it was bad already, return success and do nothing. */ -+ if (ret > 0) -+ return 0; -+ return ret; -+ } -+ -+ return this->block_markbad(mtd, ofs); -+} -+ -+/* -+ * Get chip for selected access -+ */ -+static inline void sl2312_nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state) -+{ -+ -+ DECLARE_WAITQUEUE (wait, current); -+ -+ /* -+ * Grab the lock and see if the device is available -+ * For erasing, we keep the spinlock until the -+ * erase command is written. -+ */ -+retry: -+ spin_lock_bh (&this->chip_lock); -+ -+ if (this->state == FL_READY) { -+ this->state = new_state; -+ if (new_state != FL_ERASING) -+ spin_unlock_bh (&this->chip_lock); -+ return; -+ } -+ -+ if (this->state == FL_ERASING) { -+ if (new_state != FL_ERASING) { -+ this->state = new_state; -+ spin_unlock_bh (&this->chip_lock); -+ this->select_chip(mtd, 0); /* select in any case */ -+ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); -+ return; -+ } -+ } -+ -+ set_current_state (TASK_UNINTERRUPTIBLE); -+ add_wait_queue (&this->wq, &wait); -+ spin_unlock_bh (&this->chip_lock); -+ schedule (); -+ remove_wait_queue (&this->wq, &wait); -+ goto retry; -+} -+ -+/* -+* read device ready pin -+*/ -+static int sl2312_device_ready(struct mtd_info *mtd) -+{ -+ int ready; -+ -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0 -+ FLASH_WRITE_REG(NFLASH_COUNT, 0x7f000070); //set only command no address and two data -+ -+ FLASH_WRITE_REG(NFLASH_CMD_ADDR, 0x00000070); //write read status command -+ -+ -+ ready = 0x80002000|DWIDTH|CHIP_EN; //set start bit & 8bits read command -+ FLASH_WRITE_REG(NFLASH_ACCESS, ready); -+ -+ while(ready&0x80000000) //polling flash access 31b -+ { -+ ready=FLASH_READ_REG(NFLASH_ACCESS); -+ //sl2312_flash_delay(); -+ schedule(); -+ } -+ FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT); -+ ready=FLASH_READ_REG(NFLASH_DATA)&0xff; -+ return ready; -+} -+void sl2312_enable_hwecc(struct mtd_info *mtd, int mode) -+{ -+ /* reset first */ -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x80000001); //set 31b = 0 -+ -+} -+ -+ -+void sl2312_device_setup(void) -+{ -+ -+} -+static u_char sl2312_nand_read_byte(struct mtd_info *mtd) -+{ -+ -+ unsigned int data=0, page=0, col=0, tmp, i; -+ -+ printk ("**************************sl2312_nand_read_byte !! \n"); -+ //page = FLASH_READ_REG(NFLASH_ADDRESS)&0xffffff00; -+ //col = FLASH_READ_REG(NFLASH_ADDRESS)&0x000000ff; -+ page = nand_page; -+ col = nand_col; -+ for(i=0;i<(mtd->oobblock+mtd->oobsize);i++) -+ { -+ if(i==col) -+ data = FLASH_READ_DATA(page*mtd->oobblock +i); -+ else -+ tmp = FLASH_READ_DATA(page*mtd->oobblock +i); -+ } -+ return data&0xff; -+} -+ -+static void sl2312_nand_write_byte(struct mtd_info *mtd, u_char byte) -+{ -+ //struct nand_chip *this = mtd->priv; -+ unsigned int page=0, col=0, i; -+ u_char *databuf,oobbuf[mtd->oobsize]; -+ size_t retlen; -+ retlen=0; -+ printk ("********************sl2312_nand_write_byte !! \n"); -+ page = nand_page; -+ col = nand_col; -+ databuf = kmalloc (mtd->oobsize+mtd->oobblock,GFP_KERNEL); -+ -+ if (!databuf) { -+ printk ("sl2312_nand_write_byte : Unable to allocate SL2312 NAND MTD device structure.\n"); -+ -+ } -+ -+ for(i=0;i<(mtd->oobblock+mtd->oobsize);i++) -+ databuf[i] = FLASH_READ_DATA(page*mtd->oobblock +i); -+ -+ databuf[col] = byte; -+ sl2312_nand_write_ecc (mtd, page, mtd->oobblock, &retlen, databuf, oobbuf, NULL); -+ -+} -+ -+static void sl2312_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -+{ -+ int i, page=0,col=0; -+ struct nand_chip *this = mtd->priv; -+ u_char *databuf, *oobbuf; -+ size_t retlen; -+ retlen=0; -+ -+ -+ printk ("***********************sl2312_nand_write_buf !! \n"); -+ databuf = &(this->data_buf[0]); -+ oobbuf = &(this->data_buf[mtd->oobblock]); -+ for (i = 0; i < mtd->oobsize; i++) -+ oobbuf[i] = 0xff; -+ -+ if(len < mtd->oobblock) -+ { -+ //addr = FLASH_READ_REG(NFLASH_ADDRESS); -+ //page = FLASH_READ_REG(NFLASH_ADDRESS)&0xffffff00; -+ //col = FLASH_READ_REG(NFLASH_ADDRESS)&0x000000ff; -+ page = nand_page; -+ col = nand_col; -+ -+ sl2312_nand_read_ecc (mtd, page, mtd->oobblock , &retlen, databuf, oobbuf, NULL); -+ -+ for(i=col;i<len;i++) -+ databuf[col+i] = buf[i]; -+ -+ sl2312_nand_write_ecc (mtd, page, mtd->oobblock, &retlen, databuf, oobbuf, NULL); -+ -+ } -+ -+} -+ -+static void sl2312_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -+{ -+ int i, page=0,col=0,addr=0,tmp=0; -+ //struct nand_chip *this = mtd->priv; -+ printk ("********************sl2312_nand_read_buf !! \n"); -+ if(len < mtd->oobblock) -+ { -+ //addr = FLASH_READ_REG(NFLASH_ADDRESS); -+ //page = FLASH_READ_REG(NFLASH_ADDRESS)&0xffffff00; -+ //col = FLASH_READ_REG(NFLASH_ADDRESS)&0x000000ff; -+ page = nand_page; -+ col = nand_col; -+ for (i=col; i<((mtd->oobblock+mtd->oobsize)-col); i++) -+ { -+ if(i<len) -+ buf[i] = FLASH_READ_DATA(addr+i); -+ else -+ tmp = FLASH_READ_DATA(addr+i); -+ } -+ } -+} -+ -+static int sl2312_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) -+{ -+ int i; -+ //struct nand_chip *this = mtd->priv; -+ u_char *datatmp, *oobtmp; -+ size_t retlen; -+ retlen=0; -+ -+ datatmp = kmalloc (mtd->oobblock,GFP_KERNEL); -+ oobtmp = kmalloc (mtd->oobsize,GFP_KERNEL); -+ -+ if ((!datatmp)||(!oobtmp)) { -+ printk ("sl2312_nand_verify_buf : Unable to allocate SL2312 NAND MTD device structure.\n"); -+ -+ } -+ //page = nand_page; -+ for(i=0;i<mtd->oobblock;i++) -+ datatmp[i] = FLASH_READ_DATA(nand_page*mtd->oobblock +i); -+ /* read oobdata */ -+ for (i = 0; i < mtd->oobsize; i++) -+ oobtmp[i] = FLASH_READ_DATA(nand_page*mtd->oobblock + mtd->oobblock + i); -+ -+ if(len==mtd->oobblock) -+ { -+ for (i=0; i<len; i++) -+ { -+ if (buf[i] != datatmp[i]) -+ { -+ kfree(datatmp); -+ kfree(oobtmp); -+ printk("Data verify error -> page: %x, byte: %x \n",nand_page,i); -+ return i; -+ } -+ } -+ } -+ else if(len == mtd->oobsize) -+ { -+ for (i=0; i<len; i++) -+ { -+ if (buf[i] != oobtmp[i]) -+ { -+ kfree(datatmp); -+ kfree(oobtmp); -+ printk("OOB verify error -> page: %x, byte: %x \n",nand_page,i); -+ return i; -+ } -+ } -+ } -+ else -+ { -+ printk (KERN_WARNING "sl2312_nand_verify_buf : verify length not match 0x%08x\n", len); -+ kfree(datatmp); -+ kfree(oobtmp); -+ return -1; -+ } -+ -+ kfree(datatmp); -+ kfree(oobtmp); -+ return 0; -+} -+ -+/* -+ * Send command to NAND device -+ */ -+static void sl2312_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) -+{ -+ register struct nand_chip *this = mtd->priv; -+ int opcode; -+ -+ -+ /* -+ * program and erase have their own busy handlers -+ * status and sequential in needs no delay -+ */ -+ switch (command) { -+ -+ case NAND_CMD_PAGEPROG: -+ case NAND_CMD_ERASE1: -+ case NAND_CMD_ERASE2: -+ case NAND_CMD_SEQIN: -+ case NAND_CMD_STATUS: -+ case NAND_CMD_READ0: -+ -+ /* -+ * Write out the command to the device. -+ */ -+ if (column != -1 || page_addr != -1) { -+ -+ /* Serially input address */ -+ if (column != -1) -+ //FLASH_WRITE_REG(NFLASH_ADDRESS,column); -+ nand_col=column; -+ -+ opcode = FLASH_READ_REG(NFLASH_ADDRESS); -+ -+ if (page_addr != -1) -+ //FLASH_WRITE_REG(NFLASH_ADDRESS,opcode|(page_addr<<8)); -+ nand_page = page_addr; -+ -+ } -+ return; -+ -+ case NAND_CMD_RESET: -+ if (this->dev_ready) -+ break; -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0 -+ FLASH_WRITE_REG(NFLASH_COUNT, 0x7f0fff70); //set only command and no other data -+ FLASH_WRITE_REG(NFLASH_CMD_ADDR, NAND_CMD_RESET); //write reset command -+ -+ opcode = 0x80002000|DWIDTH|CHIP_EN; //set start bit & 8bits read command -+ FLASH_WRITE_REG(NFLASH_ACCESS, opcode); -+ -+ while(opcode&0x80000000) //polling flash access 31b -+ { -+ opcode=FLASH_READ_REG(NFLASH_ACCESS); -+ //sl2312_flash_delay(); -+ schedule(); -+ } -+ while ( !(sl2312_device_ready(mtd) & 0x40)); -+ { -+ FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT); -+ //sl2312_flash_delay(); -+ schedule(); -+ return; -+ } -+ /* This applies to read commands */ -+ default: -+ /* -+ * If we don't have access to the busy pin, we apply the given -+ * command delay -+ */ -+ if (!this->dev_ready) { -+ udelay (this->chip_delay); -+ FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT); -+ return; -+ } -+ } -+ -+ /* wait until command is processed */ -+ while (!this->dev_ready(mtd)); -+ -+} -+/*Add function*/ -+static void nand_read_id(int chip_no, unsigned char *id) -+{ -+ unsigned int opcode, i; -+ -+ if(chip_no==0) -+ CHIP_EN = NFLASH_CHIP0_EN; -+ else -+ CHIP_EN = NFLASH_CHIP1_EN; -+ -+ opcode = FLASH_READ_REG(NFLASH_TYPE); -+ -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0 -+ if((opcode&0x00000300)<=0x00000100) -+ FLASH_WRITE_REG(NFLASH_COUNT, 0x7f000100); //set only command & address and two data -+ else -+ FLASH_WRITE_REG(NFLASH_COUNT, 0x7f000300); //set only command & address and 4 data -+ -+ FLASH_WRITE_REG(NFLASH_CMD_ADDR, 0x00000090); //write read id command -+ FLASH_WRITE_REG(NFLASH_ADDRESS, 0x00000000); //write address 0x00 -+ -+ /* read maker code */ -+ opcode = 0x80002000|DWIDTH|CHIP_EN;//|chip0_en; //set start bit & 8bits read command -+ FLASH_WRITE_REG(NFLASH_ACCESS, opcode); -+ opcode=FLASH_READ_REG(NFLASH_ACCESS); -+ while(opcode&0x80000000) //polling flash access 31b -+ { -+ opcode=FLASH_READ_REG(NFLASH_ACCESS); -+ //sl2312_flash_delay(); -+ schedule(); -+ } -+ -+ opcode = FLASH_READ_REG(NFLASH_DATA); -+ if(DWIDTH==NFLASH_WiDTH16) -+ { -+ id[0] = opcode&0xff; -+ id[1] = (opcode&0xff00)>>8; -+ } -+ else -+ { -+ id[0] = opcode&0xff; -+ opcode = 0x80002000|DWIDTH|CHIP_EN;//|chip0_en; //set start bit & 8bits read command -+ FLASH_WRITE_REG(NFLASH_ACCESS, opcode); -+ opcode=FLASH_READ_REG(NFLASH_ACCESS); -+ while(opcode&0x80000000) //polling flash access 31b -+ { -+ opcode=FLASH_READ_REG(NFLASH_ACCESS); -+ //sl2312_flash_delay(); -+ schedule(); -+ } -+ opcode = FLASH_READ_REG(NFLASH_DATA); -+ id[1] = (opcode&0xff00)>>8; -+ -+ opcode=FLASH_READ_REG(NFLASH_TYPE); -+ if((opcode&0x300)>0x100) -+ { -+ for(i=0;i<2;i++) -+ { -+ //data cycle 3 & 4 ->not use -+ opcode = 0x80002000|DWIDTH|CHIP_EN;//set start bit & 8bits read command -+ FLASH_WRITE_REG(NFLASH_ACCESS, opcode); -+ opcode=FLASH_READ_REG(NFLASH_ACCESS); -+ while(opcode&0x80000000) //polling flash access 31b -+ { -+ opcode=FLASH_READ_REG(NFLASH_ACCESS); -+ //sl2312_flash_delay(); -+ schedule(); -+ } -+ -+ opcode=FLASH_READ_REG(NFLASH_DATA); -+ id[2+i] = (opcode&(0xff0000<<i*8))>>(8*(2+i)); -+ } -+ } -+ } -+ FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT); -+} -+ -+/* -+ * NAND erase a block -+ */ -+static int sl2312_nand_erase (struct mtd_info *mtd, struct erase_info *instr, int allowbbt) -+{ -+ int page, len, status, pages_per_block, ret, chipnr; -+ struct nand_chip *this = mtd->priv; -+ -+ DEBUG (MTD_DEBUG_LEVEL3, -+ "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); -+ -+ /* Start address must align on block boundary */ -+ if (instr->addr & ((1 << this->phys_erase_shift) - 1)) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n"); -+ return -EINVAL; -+ } -+ -+ /* Length must align on block boundary */ -+ if (instr->len & ((1 << this->phys_erase_shift) - 1)) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n"); -+ return -EINVAL; -+ } -+ -+ /* Do not allow erase past end of device */ -+ if ((instr->len + instr->addr) > mtd->size) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n"); -+ return -EINVAL; -+ } -+ -+ instr->fail_addr = 0xffffffff; -+ -+ /* Grab the lock and see if the device is available */ -+ sl2312_nand_get_chip (this, mtd, FL_ERASING, NULL); -+ -+ /* Shift to get first page */ -+ page = (int) (instr->addr >> this->page_shift); -+ chipnr = (int) (instr->addr >> this->chip_shift); -+ -+ /* Calculate pages in each block */ -+ pages_per_block = 1 << (this->phys_erase_shift - this->page_shift); -+ -+ /* Select the NAND device */ -+ //this->select_chip(mtd, chipnr); -+ this->select_chip(mtd, 0); -+ -+ /* Check the WP bit */ -+ /* Check, if it is write protected */ -+ status = sl2312_device_ready(mtd); -+ if (!(status & 0x80)) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n"); -+ instr->state = MTD_ERASE_FAILED; -+ goto erase_exit; -+ } -+ -+ /* Loop through the pages */ -+ len = instr->len; -+ -+ instr->state = MTD_ERASING; -+ -+ while (len) { -+ /* Check if we have a bad block, we do not erase bad blocks ! */ -+ if (this->block_bad(mtd, ((loff_t) page) << this->page_shift, 0)) { -+ printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page); -+ //instr->state = MTD_ERASE_FAILED; -+ //goto erase_exit; -+ } -+ -+ /* Invalidate the page cache, if we erase the block which contains -+ the current cached page */ -+ if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block)) -+ this->pagebuf = -1; -+ ///////// -+ -+ ///* Send commands to erase a page */ -+ //FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0 -+ // -+ //if(mtd->oobblock > 528) -+ // FLASH_WRITE_REG(NFLASH_COUNT, 0x7f0fff21); // 3 address & 2 command -+ //else -+ // FLASH_WRITE_REG(NFLASH_COUNT, 0x7f0fff11); // 2 address & 2 command -+ // -+ //FLASH_WRITE_REG(NFLASH_CMD_ADDR, 0x0000d060); // write read id command -+ //FLASH_WRITE_REG(NFLASH_ADDRESS, page); //write address 0x00 -+ // -+ // -+ // -+ ///* read maker code */ -+ //opcode = 0x80003000|DWIDTH|CHIP_EN; //set start bit & 8bits write command -+ //FLASH_WRITE_REG(NFLASH_ACCESS, opcode); -+ // -+ //while(opcode&0x80000000) //polling flash access 31b -+ //{ -+ // opcode=FLASH_READ_REG(NFLASH_ACCESS); -+ // //sl2312_flash_delay(); -+ // schedule(); -+ // //cond_resched(); -+ //} -+ sl2312_nand_erase_block(mtd, page); -+ ////////////// -+ status = this->waitfunc (mtd, this, FL_ERASING); -+ /* See if block erase succeeded */ -+ if (status & 0x01) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); -+ instr->state = MTD_ERASE_FAILED; -+ instr->fail_addr = (page << this->page_shift); -+ goto erase_exit; -+ } -+ -+ /* Increment page address and decrement length */ -+ len -= (1 << this->phys_erase_shift); -+ page += pages_per_block; -+ -+ /* Check, if we cross a chip boundary */ -+ if (len && !(page & this->pagemask)) { -+ chipnr++; -+ this->select_chip(mtd, 0); -+ this->select_chip(mtd, 0); -+ } -+ //sl2312_flash_delay(); -+ schedule(); -+ //cond_resched(); -+ } -+ instr->state = MTD_ERASE_DONE; -+ -+erase_exit: -+ /* De-select the NAND device */ -+ this->select_chip(mtd, 0); -+ spin_unlock_bh (&this->chip_lock); -+ -+ ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;; -+ /* Do call back function */ -+ if (!ret && instr->callback) -+ instr->callback (instr); -+ -+ /* The device is ready */ -+ spin_lock_bh (&this->chip_lock); -+ this->state = FL_READY; -+ spin_unlock_bh (&this->chip_lock); -+ FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT); -+ /* Return more or less happy */ -+ return ret; -+} -+ -+static void sl2312_nand_select_chip(struct mtd_info *mtd, int chip) -+{ -+ //struct nand_chip *this = mtd->priv; -+ -+ switch(chip) { -+ case -1: -+ CHIP_EN = NFLASH_CHIP0_EN; -+ break; -+ case 0: -+ CHIP_EN = NFLASH_CHIP0_EN; -+ break; -+ case 1: -+ CHIP_EN = NFLASH_CHIP1_EN; -+ break; -+ default: -+ CHIP_EN = NFLASH_CHIP0_EN; -+ break; -+ } -+} -+ -+/** -+ * nand_default_block_markbad - [DEFAULT] mark a block bad -+ * @mtd: MTD device structure -+ * @ofs: offset from device start -+ * -+ * This is the default implementation, which can be overridden by -+ * a hardware specific driver. -+*/ -+static int sl2312_nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) -+{ -+ struct nand_chip *this = mtd->priv; -+ u_char buf[2] = {0, 0}; -+ size_t retlen; -+ int block; -+ -+ /* Get block number */ -+ block = ((int) ofs) >> this->bbt_erase_shift; -+ this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); -+ -+ /* Do we have a flash based bad block table ? */ -+ if (this->options & NAND_USE_FLASH_BBT) -+ return nand_update_bbt (mtd, ofs); -+ -+ /* We write two bytes, so we dont have to mess with 16 bit access */ -+ ofs += mtd->oobsize + (this->badblockpos & ~0x01); -+ return sl2312_nand_write_oob (mtd, ofs , 2, &retlen, buf); -+} -+ -+/* Appropriate chip should already be selected */ -+static int sl2312_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)//(struct mtd_info *mtd, unsigned long page, ) -+{ -+ u_char *buf, *oobbuf; -+ size_t retlen; -+ unsigned long page, chipnr; -+ struct nand_chip *this = mtd->priv; -+ -+ if (getchip) { -+ page = (int)(ofs >> this->page_shift); -+ chipnr = (int)(ofs >> this->chip_shift); -+ -+ /* Grab the lock and see if the device is available */ -+ sl2312_nand_get_chip (this, mtd, FL_READING, NULL); -+ /* Select the NAND device */ -+ this->select_chip(mtd, chipnr); -+ } else -+ page = (int) ofs; -+ -+ buf = kmalloc (mtd->oobblock,GFP_KERNEL); -+ oobbuf = kmalloc (mtd->oobsize,GFP_KERNEL); -+ -+ if ((!buf)||(!oobbuf)) { -+ printk ("sl2312_nand_block_bad : Unable to allocate SL2312 NAND MTD device structure.\n"); -+ -+ } -+ -+ sl2312_nand_read_ecc (mtd, page, mtd->oobblock , &retlen, buf, oobbuf, NULL); -+ -+ -+ if(((mtd->oobblock < 528)&&(oobbuf[5] != 0xff))||((mtd->oobblock > 528)&&(oobbuf[0] != 0xff))) -+ { -+ kfree(buf); -+ kfree(oobbuf); -+ return 1; -+ } -+ -+ kfree(buf); -+ kfree(oobbuf); -+ return 0; -+} -+ -+/* -+* Use NAND read ECC -+*/ -+static int sl2312_nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) -+{ -+ return sl2312_nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); -+} -+ -+/* -+ * NAND read with ECC -+ */ -+static int sl2312_nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, -+ size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) -+{ -+ int j, col, page, opcode, i; -+ int end=0;//, ecc=0;//, end_page=0; -+ int erase_state = 0; -+ int read = 0, oob = 0, ecc_failed = 0;//, ecc_status = 0 -+ struct nand_chip *this = mtd->priv; -+ u_char *data_poi, *oob_data = oob_buf; -+ //u_char ecc_calc[6]; -+ //u_char ecc_code[6]; -+ int eccmode; -+ int *oob_config; -+ -+ -+ -+ // use chip default if zero -+ if (oobsel == NULL) -+ oobsel = &mtd->oobinfo; -+ -+ eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; -+ oob_config = oobsel->eccpos; -+ -+ DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); -+ -+ /* Do not allow reads past end of device */ -+ if ((from + len) > mtd->size) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n"); -+ *retlen = 0; -+ return -EINVAL; -+ } -+ -+ /* Grab the lock and see if the device is available */ -+ sl2312_nand_get_chip (this, mtd ,FL_READING, &erase_state); -+ -+ /* Select the NAND device */ -+ this->select_chip(mtd, 0); -+ -+ /* First we calculate the starting page */ -+ page = from >> this->page_shift; -+ -+ //end_page = mtd->oobblock + mtd->oobsize; -+ end = mtd->oobblock; -+ //ecc = mtd->eccsize; -+ /* Get raw starting column */ -+ col = (from & (mtd->oobblock - 1)); -+ -+ -+ /* Send the read command */ -+ //this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); -+ -+ /* Loop until all data read */ -+ FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT); -+ while (read < len) { -+ -+ //udelay(1200); -+ /* If we have consequent page reads, apply delay or wait for ready/busy pin */ -+ if (read) { -+ if (!this->dev_ready) -+ udelay (this->chip_delay); -+ else -+ while (!this->dev_ready(mtd)); -+ } -+ -+ /* -+ * If the read is not page aligned, we have to read into data buffer -+ * due to ecc, else we read into return buffer direct -+ */ -+ if (!col && (len - read) >= end) -+ data_poi = &buf[read]; -+ else -+ data_poi = this->data_buf; -+ -+ /* get oob area, if we have no oob buffer from fs-driver */ -+ if (!oob_buf) { -+ oob_data = &this->data_buf[end]; -+ oob = 0; -+ } -+ -+ j = 0; -+ switch (eccmode) { -+ case NAND_ECC_NONE: { /* No ECC, Read in a page */ -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0 -+ break; -+ } -+ -+ case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ -+ break; -+ -+ case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */ -+ break; -+ -+ case NAND_ECC_HW3_512: -+ case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page */ -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x80000001); //set 31b = 0 -+ break; -+ -+ default: -+ printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); -+ //BUG(); -+ }//end switch -+ -+ for(i=0;i<end;i++) -+ { -+ //udelay(7); -+ data_poi[i] = FLASH_READ_DATA(page*mtd->oobblock +i); -+ } -+ /* read oobdata */ -+ for (i = 0; i < mtd->oobsize; i++) -+ { -+ //udelay(7); -+ oob_data[oob + i] = FLASH_READ_DATA(page*mtd->oobblock +end+i); -+ } -+ -+ /* Skip ECC, if not active */ -+ if (eccmode == NAND_ECC_NONE) -+ goto readdata; -+ -+ // compare ecc and correct data -+ -+ opcode=FLASH_READ_REG(NFLASH_ECC_STATUS); -+ while(!(opcode&0x80000000)) //polling flash access 31b -+ { -+ opcode=FLASH_READ_REG(NFLASH_ECC_STATUS); -+ //sl2312_flash_delay(); -+ schedule(); -+ } -+ for(j=0;j<(end/512);j++) -+ {//for 2k page -+ -+ opcode = 0x00000000|oob_data[mtd->oobsize-3-4*j]<<16|oob_data[mtd->oobsize-2-4*j]<<8|oob_data[mtd->oobsize-1-4*j]; -+ -+ //opcode=FLASH_READ_REG(NFLASH_ECC_CODE_GEN0+(j*4)); -+ -+ FLASH_WRITE_REG(NFLASH_ECC_OOB, opcode); -+ opcode = 0x00000000|(j<<8); //select ECC code generation 0 -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, opcode); //??? -+ -+ opcode=FLASH_READ_REG(NFLASH_ECC_STATUS); -+ if((opcode&0x00000003)==0x03) -+ { -+ printk (KERN_WARNING "\nPageRead Uncorrectable error !!\n"); -+ ecc_failed++; -+ } -+ else if((opcode&0x00000003)==0x01) -+ { -+ printk (KERN_WARNING "\nPageRead One bit data error !!"); -+ // correct data -+ if((data_poi[(opcode&0xff80)>>7]>>((opcode&0x38)>>3))%1) -+ data_poi[(opcode&0xff80)>>7] &= ~(1<<((opcode&0x38)>>3)); -+ else -+ data_poi[(opcode&0xff80)>>7] |= (1<<((opcode&0x38)>>3)); -+ -+ } -+ else if((opcode&0x00000003)==0x02) -+ { -+ printk (KERN_WARNING "\nPageRead One bit ECC error !!\n"); -+ } -+ else if((opcode&0x00000003)==0x00) -+ { -+ -+ } -+ -+ }//for 2k page -+readdata: -+ if (col || (len - read) < end) { -+ for (j = col; j < end && read < len; j++) -+ buf[read++] = data_poi[j]; -+ } else -+ read += mtd->oobblock; -+ /* For subsequent reads align to page boundary. */ -+ col = 0; -+ /* Increment page address */ -+ page++; -+ schedule(); -+ } -+ /* De-select the NAND device */ -+ //this->select_chip(mtd, -1); -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0 -+ FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_INDIRECT); -+ /* Wake up anyone waiting on the device */ -+ spin_lock_bh (&this->chip_lock); -+ this->state = FL_READY; -+ wake_up (&this->wq); -+ spin_unlock_bh (&this->chip_lock); -+ -+ /* -+ * Return success, if no ECC failures, else -EIO -+ * fs driver will take care of that, because -+ * retlen == desired len and result == -EIO -+ */ -+ *retlen = read; -+ return ecc_failed ? -EIO : 0; -+} -+ -+/* -+ * Wait for command done. This applies to erase and program only -+ * Erase can take up to 400ms and program up to 20ms according to -+ * general NAND and SmartMedia specs -+ * -+*/ -+static int sl2312_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this, int state) -+{ -+ unsigned long timeo = jiffies; -+ int status, opcode; -+ -+ if (state == FL_ERASING) -+ timeo += (HZ * 400) / 1000; -+ else -+ timeo += (HZ * 20) / 1000; -+ -+ spin_lock_bh (&this->chip_lock); -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); //set 31b = 0 -+ FLASH_WRITE_REG(NFLASH_COUNT, 0x007f000070); //set only command no address and two data -+ -+ FLASH_WRITE_REG(NFLASH_CMD_ADDR, 0x00000070); //write read status command -+ -+ -+ opcode = 0x80002000|DWIDTH|CHIP_EN; //set start bit & 8bits read command -+ FLASH_WRITE_REG(NFLASH_ACCESS, opcode); -+ -+ while(opcode&0x80000000) //polling flash access 31b -+ { -+ opcode=FLASH_READ_REG(NFLASH_ACCESS); -+ //sl2312_flash_delay(); -+ schedule(); -+ } -+ -+ while (time_before(jiffies, timeo)) { -+ /* Check, if we were interrupted */ -+ if (this->state != state) { -+ spin_unlock_bh (&this->chip_lock); -+ FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT); -+ return 0; -+ } -+ if (this->dev_ready) { -+ if (this->dev_ready(mtd)) -+ break; -+ } -+ if (FLASH_READ_REG(NFLASH_DATA) & 0x40) -+ break; -+ -+ spin_unlock_bh (&this->chip_lock); -+ yield (); -+ spin_lock_bh (&this->chip_lock); -+ } -+ status = FLASH_READ_REG(NFLASH_DATA)&0xff; -+ spin_unlock_bh (&this->chip_lock); -+ FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT); -+ return status; -+} -+ -+static int sl2312_nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) -+{ -+ int i, col, page, j=0; -+ //int erase_state = 0; -+ struct nand_chip *this = mtd->priv; -+ u_char *databuf, *oobbuf; -+ -+ databuf = &this->data_buf[0]; -+ oobbuf = &this->data_buf[mtd->oobblock]; -+ for (i = 0; i < mtd->oobsize; i++) -+ oobbuf[i] = 0xff; -+ -+ DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); -+ -+ /* Shift to get page */ -+ page = ((int) from) >> this->page_shift; -+ -+ /* Mask to get column */ -+ col = from & (mtd->oobsize-1); //0x0f; -+ -+ /* Initialize return length value */ -+ *retlen = 0; -+ sl2312_nand_read_ecc (mtd, page, mtd->oobblock , retlen, databuf, oobbuf, NULL); -+ for(i=col,j=0;i<mtd->oobsize||i<(col+len);i++,j++) -+ buf[j] = oobbuf[i]; -+ -+ *retlen = j ; -+ return 0; -+} -+ -+#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0 -+/* -+* Use NAND write ECC -+*/ -+static int sl2312_nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) -+{ -+ return (sl2312_nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); -+} -+ -+/* -+ * NAND write with ECC -+ */ -+static int sl2312_nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, -+ size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel) -+{ -+ int page, ret = 0, oob = 0, written = 0; -+ struct nand_chip *this = mtd->priv; -+ -+ DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); -+ -+ -+ /* Do not allow write past end of device */ -+ if ((to + len) > mtd->size) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); -+ return -EINVAL; -+ } -+ -+ /* reject writes, which are not page aligned */ -+ if (NOTALIGNED (to) || NOTALIGNED(len)) { -+ printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); -+ return -EINVAL; -+ } -+ -+ // if oobsel is NULL, use chip defaults -+ if (oobsel == NULL) -+ oobsel = &mtd->oobinfo; -+ -+ /* Shift to get page */ -+ page = ((int) to) >> this->page_shift; -+ -+ /* Grab the lock and see if the device is available */ -+ sl2312_nand_get_chip (this, mtd, FL_WRITING, NULL); -+ -+ /* Select the NAND device */ -+ this->select_chip(mtd, 0); -+ -+ /* Check the WP bit */ -+ if (!(sl2312_device_ready(mtd) & 0x80)) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n"); -+ ret = -EIO; -+ goto out; -+ } -+ -+ /* Loop until all data is written */ -+ while (written < len) { -+ //udelay(100); -+ int cnt = mtd->oobblock; -+ this->data_poi = (u_char*) &buf[written]; -+ /* We use the same function for write and writev */ -+ if (eccbuf) { -+ ret = sl2312_nand_write_page (mtd, this, page, &eccbuf[oob], oobsel); -+ oob += mtd->oobsize; -+ } else -+ ret = sl2312_nand_write_page (mtd, this, page, NULL, oobsel); -+ -+ if (ret) -+ goto out; -+ -+ /* Update written bytes count */ -+ written += cnt; -+ /* Increment page address */ -+ page++; -+ } -+ -+out: -+ /* De-select the NAND device */ -+ //this->select_chip(mtd, -1); -+ -+ /* Wake up anyone waiting on the device */ -+ spin_lock_bh (&this->chip_lock); -+ this->state = FL_READY; -+ wake_up (&this->wq); -+ spin_unlock_bh (&this->chip_lock); -+ -+ *retlen = written; -+ return ret; -+} -+ -+/* -+ * Nand_page_program function is used for write and writev ! -+ * This function will always program a full page of data -+ * If you call it with a non page aligned buffer, you're lost :) -+ */ -+static int sl2312_nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel) -+{ -+ int i, j, status, opcode; -+ u_char ecc_code[16], *oob_data; -+ int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; -+ //int *oob_config = oobsel->eccpos; -+ -+ /* pad oob area, if we have no oob buffer from fs-driver */ -+ if (!oob_buf) { -+ oob_data = &this->data_buf[mtd->oobblock]; -+ for (i = 0; i < mtd->oobsize; i++) -+ oob_data[i] = 0xff; -+ } else -+ oob_data = oob_buf; -+ -+ /* Send command to begin auto page programming */ -+ -+ memset(oob_data,0xff,mtd->oobsize); -+ /* Write out complete page of data, take care of eccmode */ -+ switch (eccmode) { -+ /* No ecc and software ecc 3/256, write all */ -+ case NAND_ECC_NONE: -+ printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0 -+ break; -+ case NAND_ECC_SOFT: -+ break; -+ -+ /* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */ -+ case NAND_ECC_HW3_256: -+ break; -+ -+ /* Hardware ecc 3 byte / 512 byte data, write full page */ -+ case NAND_ECC_HW3_512: -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x80000001); //set 31b = 0 -+ -+ /* Hardware ecc 6 byte / 512 byte data, write full page */ -+ case NAND_ECC_HW6_512: -+ break; -+ -+ default: -+ printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0 -+ //BUG(); -+ } -+ -+ FLASH_WRITE_REG(NFLASH_ACCESS, NFLASH_DIRECT); -+ -+ for(i=0;i<mtd->oobblock;i++) -+ { -+ //udelay(5); -+ FLASH_WRITE_DATA((page*mtd->oobblock)+i,this->data_poi[i]); -+ } -+ /////////////// -+ if(eccmode!=NAND_ECC_NONE) -+ { -+ opcode=FLASH_READ_REG(NFLASH_ECC_STATUS); -+ while(!(opcode&0x80000000)) //polling flash access 31b -+ { -+ opcode=FLASH_READ_REG(NFLASH_ECC_STATUS); -+ //sl2312_flash_delay(); -+ schedule(); -+ } -+ -+ -+ for(i=0;i<(mtd->oobblock/512);i++) -+ { -+ opcode=FLASH_READ_REG(NFLASH_ECC_CODE_GEN0+(i*4)); -+ -+ for(j=3;j>0;j--) -+ oob_data[(mtd->oobsize-j-(i*4))] = (opcode<<((4-j)*8)) >>24; -+ -+ for(j=0;j<4;j++) -+ { -+ ecc_code[15-i*4] = opcode; -+ ecc_code[15-i*4-1] = opcode>>8; -+ ecc_code[15-i*4-2] = opcode>>16; -+ } -+ } -+ -+ //disable ecc -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x00000000); -+ -+ /* Write out OOB data */ -+ for(i=0;i<mtd->oobsize;i++) -+ { -+ //udelay(5); -+ FLASH_WRITE_DATA((page*mtd->oobblock)+mtd->oobblock+i,oob_data[i]); -+ } -+ } -+ else -+ { -+ for(i=0;i<mtd->oobsize;i++) -+ { -+ //udelay(5); -+ FLASH_WRITE_DATA((page*mtd->oobblock)+mtd->oobblock+i,0xff); -+ } -+ } -+ -+ -+ /* call wait ready function */ -+ status = this->waitfunc (mtd, this, FL_WRITING); -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0 -+ /* See if device thinks it succeeded */ -+ if (status & 0x01) { -+ DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); -+ FLASH_WRITE_REG(NFLASH_ECC_CONTROL, 0x0); //set 31b = 0 -+ return -EIO; -+ } -+ -+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE -+ /* -+ * The NAND device assumes that it is always writing to -+ * a cleanly erased page. Hence, it performs its internal -+ * write verification only on bits that transitioned from -+ * 1 to 0. The device does NOT verify the whole page on a -+ * byte by byte basis. It is possible that the page was -+ * not completely erased or the page is becoming unusable -+ * due to wear. The read with ECC would catch the error -+ * later when the ECC page check fails, but we would rather -+ * catch it early in the page write stage. Better to write -+ * no data than invalid data. -+ */ -+ -+ /* Send command to read back the page */ -+ this->cmdfunc (mtd, NAND_CMD_READ0, 0, page); -+ /* Loop through and verify the data */ -+ if (this->verify_buf(mtd, this->data_poi, mtd->oobblock)) { -+ DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); -+ return -EIO; -+ } -+ -+ /* check, if we have a fs-supplied oob-buffer */ -+ if (oob_buf) { -+ if (this->verify_buf(mtd, oob_data, mtd->oobsize)) { -+ DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); -+ return -EIO; -+ } -+ } else { -+ if (eccmode != NAND_ECC_NONE) { -+ int ecc_bytes = 0; -+ -+ switch (this->eccmode) { -+ case NAND_ECC_SOFT: -+ case NAND_ECC_HW3_256: ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; break; -+ case NAND_ECC_HW3_512: ecc_bytes = 3; break; -+ case NAND_ECC_HW6_512: ecc_bytes = 6; break; -+ } -+ -+ -+ -+ for(i=0;i < (mtd->oobblock+mtd->oobsize);i++) -+ { -+ if(i>=mtd->oobblock) -+ oob_data[i-mtd->oobblock] = FLASH_READ_DATA((page*mtd->oobblock) +i); -+ else -+ oob_data[0] = FLASH_READ_DATA((page*mtd->oobblock) +i); -+ } -+ -+ if(this->eccmode == NAND_ECC_HW3_512) -+ { -+ for(i=0;i<(mtd->oobblock/512);i++) -+ { -+ for(j=0;j<3;j++) -+ { -+ if (oob_data[mtd->oobsize-1-j-4*i] != ecc_code[15-j-4*i]) { -+ DEBUG (MTD_DEBUG_LEVEL0, -+ "%s: Failed ECC write " -+ "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i); -+ return -EIO; -+ } -+ } -+ } -+ } -+ }//eccmode != NAND_ECC_NONE -+ } -+ /* -+ * Terminate the read command. This is faster than sending a reset command or -+ * applying a 20us delay before issuing the next programm sequence. -+ * This is not a problem for all chips, but I have found a bunch of them. -+ */ -+ //this->select_chip(mtd, -1); -+ //this->select_chip(mtd, 0); -+#endif -+ -+ return 0; -+} -+ -+/* -+ * NAND write with iovec -+ */ -+static int sl2312_nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, -+ loff_t to, size_t * retlen) -+{ -+ return (sl2312_nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, 0)); -+} -+ -+static int sl2312_nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, -+ loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) -+{ -+ int i, page, len, total_len, ret = 0, written = 0; -+ struct nand_chip *this = mtd->priv; -+ -+ /* Calculate total length of data */ -+ total_len = 0; -+ for (i = 0; i < count; i++) -+ total_len += (int) vecs[i].iov_len; -+ -+ DEBUG (MTD_DEBUG_LEVEL3, -+ "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); -+ -+ /* Do not allow write past end of page */ -+ if ((to + total_len) > mtd->size) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n"); -+ return -EINVAL; -+ } -+ -+ /* reject writes, which are not page aligned */ -+ if (NOTALIGNED (to) || NOTALIGNED(total_len)) { -+ printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); -+ return -EINVAL; -+ } -+ -+ // if oobsel is NULL, use chip defaults -+ if (oobsel == NULL) -+ oobsel = &mtd->oobinfo; -+ -+ /* Shift to get page */ -+ page = ((int) to) >> this->page_shift; -+ -+ /* Grab the lock and see if the device is available */ -+ sl2312_nand_get_chip (this, mtd, FL_WRITING, NULL); -+ -+ /* Select the NAND device */ -+ this->select_chip(mtd, 0); -+ -+ /* Check the WP bit */ -+ if (!(sl2312_device_ready(mtd) & 0x80)) { -+ DEBUG (MTD_DEBUG_LEVEL0, "sl2312_nand_writev_ecc: Device is write protected!!!\n"); -+ ret = -EIO; -+ goto out; -+ } -+ -+ /* Loop until all iovecs' data has been written */ -+ len = 0; -+ while (count) { -+ /* -+ * Check, if the tuple gives us not enough data for a -+ * full page write. Then we can use the iov direct, -+ * else we have to copy into data_buf. -+ */ -+ if ((vecs->iov_len - len) >= mtd->oobblock) { -+ this->data_poi = (u_char *) vecs->iov_base; -+ this->data_poi += len; -+ len += mtd->oobblock; -+ /* Check, if we have to switch to the next tuple */ -+ if (len >= (int) vecs->iov_len) { -+ vecs++; -+ len = 0; -+ count--; -+ } -+ } else { -+ /* -+ * Read data out of each tuple until we have a full page -+ * to write or we've read all the tuples. -+ */ -+ int cnt = 0; -+ while ((cnt < mtd->oobblock) && count) { -+ if (vecs->iov_base != NULL && vecs->iov_len) { -+ this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; -+ } -+ /* Check, if we have to switch to the next tuple */ -+ if (len >= (int) vecs->iov_len) { -+ vecs++; -+ len = 0; -+ count--; -+ } -+ } -+ this->data_poi = this->data_buf; -+ } -+ -+ /* We use the same function for write and writev !) */ -+ ret = sl2312_nand_write_page (mtd, this, page, NULL, oobsel); -+ if (ret) -+ goto out; -+ -+ /* Update written bytes count */ -+ written += mtd->oobblock;; -+ -+ /* Increment page address */ -+ page++; -+ } -+ -+out: -+ /* De-select the NAND device */ -+ //this->select_chip(mtd, -1); -+ -+ /* Wake up anyone waiting on the device */ -+ spin_lock_bh (&this->chip_lock); -+ this->state = FL_READY; -+ wake_up (&this->wq); -+ spin_unlock_bh (&this->chip_lock); -+ -+ *retlen = written; -+ return ret; -+} -+ -+/* -+static u_char ffchars[] = { -+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -+}; -+*/ -+/* -+ * NAND write out-of-band -+ */ -+static int sl2312_nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) -+{ -+ int column, page, status, ret = 0, j=0; -+ struct nand_chip *this = mtd->priv; -+ u_char *databuf, *oobbuf; -+ -+ -+ databuf = &this->data_buf[0]; -+ oobbuf = &this->data_buf[mtd->oobblock]; -+ for (j = 0; j < mtd->oobsize; j++) -+ oobbuf[j] = 0xff; -+//#ifdef CONFIG_MTD_NAND_VERIFY_WRITE -+// int i; -+//#endif -+ -+ DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); -+ -+ /* Shift to get page */ -+ page = ((int) to) >> this->page_shift; -+ -+ /* Mask to get column */ -+ column = to & 0x1f; -+ -+ /* Initialize return length value */ -+ *retlen = 0; -+ -+ /* Do not allow write past end of page */ -+ if ((column + len) > mtd->oobsize) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); -+ return -EINVAL; -+ } -+ -+ /* Grab the lock and see if the device is available */ -+ sl2312_nand_get_chip (this, mtd, FL_WRITING, NULL); -+ -+ /* Select the NAND device */ -+ this->select_chip(mtd, 0); -+ -+ /* Reset the chip. Some chips (like the Toshiba TC5832DC found -+ in one of my DiskOnChip 2000 test units) will clear the whole -+ data page too if we don't do this. I have no clue why, but -+ I seem to have 'fixed' it in the doc2000 driver in -+ August 1999. dwmw2. */ -+ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); -+ -+ /* Check the WP bit */ -+ if (!(sl2312_device_ready(mtd) & 0x80)) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n"); -+ ret = -EIO; -+ goto out; -+ } -+ /* Write out desired data */ -+ this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page); -+ -+ sl2312_nand_read_ecc (mtd, page, mtd->oobblock , retlen, databuf, oobbuf, NULL); -+ -+ for(j=column;j<(column+len);j++) -+ oobbuf[j] = buf[j-column]; -+ sl2312_nand_write_ecc (mtd, page, mtd->oobblock, retlen, databuf, oobbuf, NULL); -+ -+ status = this->waitfunc (mtd, this, FL_WRITING); -+ -+ /* See if device thinks it succeeded */ -+ if (status & 0x01) { -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); -+ ret = -EIO; -+ goto out; -+ } -+ /* Return happy */ -+ *retlen = len; -+ -+ -+out: -+ /* De-select the NAND device */ -+ //this->select_chip(mtd, -1); -+ -+ /* Wake up anyone waiting on the device */ -+ spin_lock_bh (&this->chip_lock); -+ this->state = FL_READY; -+ wake_up (&this->wq); -+ spin_unlock_bh (&this->chip_lock); -+ -+ return ret; -+} -+ -+/* -+ * NAND sync -+ */ -+static void sl2312_nand_sync (struct mtd_info *mtd) -+{ -+ struct nand_chip *this = mtd->priv; -+ DECLARE_WAITQUEUE (wait, current); -+ -+ DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n"); -+ -+retry: -+ /* Grab the spinlock */ -+ spin_lock_bh (&this->chip_lock); -+ -+ /* See what's going on */ -+ switch (this->state) { -+ case FL_READY: -+ case FL_SYNCING: -+ this->state = FL_SYNCING; -+ spin_unlock_bh (&this->chip_lock); -+ break; -+ -+ default: -+ /* Not an idle state */ -+ add_wait_queue (&this->wq, &wait); -+ spin_unlock_bh (&this->chip_lock); -+ schedule (); -+ -+ remove_wait_queue (&this->wq, &wait); -+ goto retry; -+ } -+ -+ /* Lock the device */ -+ spin_lock_bh (&this->chip_lock); -+ -+ /* Set the device to be ready again */ -+ if (this->state == FL_SYNCING) { -+ this->state = FL_READY; -+ wake_up (&this->wq); -+ } -+ -+ /* Unlock the device */ -+ spin_unlock_bh (&this->chip_lock); -+} -+ -+ -+/* -+ * Scan for the NAND device -+ */ -+int sl2312_nand_scan (struct mtd_info *mtd, int maxchips) -+{ -+ int i, j, nand_maf_id, nand_dev_id, busw; -+ struct nand_chip *this = mtd->priv; -+ unsigned char id[4]; -+ -+ /* Get buswidth to select the correct functions*/ -+ busw = this->options & NAND_BUSWIDTH_16; -+ -+ /* check for proper chip_delay setup, set 20us if not */ -+ if (!this->chip_delay) -+ this->chip_delay = 20; -+ -+ /* check, if a user supplied command function given */ -+ if (this->cmdfunc == NULL) -+ this->cmdfunc = sl2312_nand_command; -+ -+ /* check, if a user supplied wait function given */ -+ if (this->waitfunc == NULL) -+ this->waitfunc = sl2312_nand_waitfunc; -+ -+ if (!this->select_chip) -+ this->select_chip = sl2312_nand_select_chip; -+ if (!this->write_byte) -+ this->write_byte = sl2312_nand_write_byte; //busw ? nand_write_byte16 : nand_write_byte; -+ if (!this->read_byte) -+ this->read_byte = sl2312_nand_read_byte; //busw ? nand_read_byte16 : nand_read_byte; -+// if (!this->write_word) -+// this->write_word = nand_write_word; -+// if (!this->read_word) -+// this->read_word = nand_read_word; -+// if (!this->block_bad) -+ this->block_bad = sl2312_nand_block_bad; //nand_block_bad; -+ if (!this->block_markbad) -+ this->block_markbad = sl2312_nand_default_block_markbad; -+ if (!this->write_buf) -+ this->write_buf = sl2312_nand_write_buf; //busw ? nand_write_buf16 : nand_write_buf; -+ if (!this->read_buf) -+ this->read_buf = sl2312_nand_read_buf; //busw ? nand_read_buf16 : nand_read_buf; -+ if (!this->verify_buf) -+ this->verify_buf = sl2312_nand_verify_buf; //busw ? nand_verify_buf16 : nand_verify_buf; -+ if (!this->scan_bbt) -+ this->scan_bbt = sl2312_nand_scan_bbt; -+ -+ /* Select the device */ -+ this->select_chip(mtd, 0); -+ -+ /* Read manufacturer and device IDs */ -+ nand_read_id(0,id); -+ -+ nand_maf_id = id[0]; -+ nand_dev_id = id[1]; -+ -+ /* Print and store flash device information */ -+ for (i = 0; nand_flash_ids[i].name != NULL; i++) { -+ -+ if (nand_dev_id != nand_flash_ids[i].id) -+ continue; -+ -+ if (!mtd->name) mtd->name = nand_flash_ids[i].name; -+ this->chipsize = nand_flash_ids[i].chipsize << 20; -+ -+ /* New devices have all the information in additional id bytes */ -+ if (!nand_flash_ids[i].pagesize) { -+ int extid; -+ -+ /* The 4th id byte is the important one */ -+ extid = id[3]; -+ /* Calc pagesize */ -+ mtd->oobblock = 1024 << (extid & 0x3); -+ extid >>= 2; -+ /* Calc oobsize */ -+ mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512); -+ extid >>= 2; -+ /* Calc blocksize. Blocksize is multiples of 64KiB */ -+ mtd->erasesize = (64 * 1024) << (extid & 0x03); -+ extid >>= 2; -+ /* Get buswidth information */ -+ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; -+ -+ } else { -+ /* Old devices have this data hardcoded in the -+ * device id table */ -+ mtd->erasesize = nand_flash_ids[i].erasesize; -+ mtd->oobblock = nand_flash_ids[i].pagesize; -+ mtd->oobsize = mtd->oobblock / 32; -+ busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; -+ } -+ -+ /* Check, if buswidth is correct. Hardware drivers should set -+ * this correct ! */ -+ if (busw != (this->options & NAND_BUSWIDTH_16)) { -+ printk (KERN_INFO "NAND device: Manufacturer ID:" -+ " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, -+ nand_manuf_ids[i].name , mtd->name); -+ printk (KERN_WARNING -+ "NAND bus width %d instead %d bit\n", -+ (this->options & NAND_BUSWIDTH_16) ? 16 : 8, -+ busw ? 16 : 8); -+ this->select_chip(mtd, -1); -+ return 1; -+ } -+ -+ /* Calculate the address shift from the page size */ -+ this->page_shift = ffs(mtd->oobblock) - 1; -+ this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; -+ this->chip_shift = ffs(this->chipsize) - 1; -+ -+ /* Set the bad block position */ -+ this->badblockpos = mtd->oobblock > 512 ? -+ NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; -+ -+ /* Get chip options, preserve non chip based options */ -+ this->options &= ~NAND_CHIPOPTIONS_MSK; -+ this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK; -+ /* Set this as a default. Board drivers can override it, if neccecary */ -+ this->options |= NAND_NO_AUTOINCR; -+ /* Check if this is a not a samsung device. Do not clear the options -+ * for chips which are not having an extended id. -+ */ -+ if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) -+ this->options &= ~NAND_SAMSUNG_LP_OPTIONS; -+ -+ /* Check for AND chips with 4 page planes */ -+ // if (this->options & NAND_4PAGE_ARRAY) -+ // this->erase_cmd = multi_erase_cmd; -+ // else -+ // this->erase_cmd = single_erase_cmd; -+ -+ /* Do not replace user supplied command function ! */ -+ // if (mtd->oobblock > 512 && this->cmdfunc == nand_command) -+ // this->cmdfunc = nand_command_lp; -+ -+ /* Try to identify manufacturer */ -+ for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { -+ if (nand_manuf_ids[j].id == nand_maf_id) -+ break; -+ } -+ printk (KERN_INFO "NAND device: Manufacturer ID:" -+ " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, -+ nand_manuf_ids[j].name , nand_flash_ids[i].name); -+ break; -+ } -+ ///////////////////////////// -+ -+ for (i=1; i < maxchips; i++) { -+ this->select_chip(mtd, i); -+ -+ /* Send the command for reading device ID */ -+ nand_read_id(1,id); -+ -+ /* Read manufacturer and device IDs */ -+ if (nand_maf_id != id[0] || -+ nand_dev_id != id[1]) -+ break; -+ } -+ if (i > 1) -+ printk(KERN_INFO "%d NAND chips detected\n", i); -+ -+ /* Allocate buffers, if neccecary */ -+ if (!this->oob_buf) { -+ size_t len; -+ len = mtd->oobsize << (this->phys_erase_shift - this->page_shift); -+ this->oob_buf = kmalloc (len, GFP_KERNEL); -+ if (!this->oob_buf) { -+ printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n"); -+ return -ENOMEM; -+ } -+ this->options |= NAND_OOBBUF_ALLOC; -+ } -+ -+ if (!this->data_buf) { -+ size_t len; -+ len = mtd->oobblock + mtd->oobsize; -+ this->data_buf = kmalloc (len, GFP_KERNEL); -+ if (!this->data_buf) { -+ if (this->options & NAND_OOBBUF_ALLOC) -+ kfree (this->oob_buf); -+ printk (KERN_ERR "nand_scan(): Cannot allocate data_buf\n"); -+ return -ENOMEM; -+ } -+ this->options |= NAND_DATABUF_ALLOC; -+ } -+ -+ /* Store the number of chips and calc total size for mtd */ -+ this->numchips = i; -+ mtd->size = i * this->chipsize; -+ /* Convert chipsize to number of pages per chip -1. */ -+ this->pagemask = (this->chipsize >> this->page_shift) - 1; -+ /* Preset the internal oob buffer */ -+ memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); -+ -+ /* If no default placement scheme is given, select an -+ * appropriate one */ -+ if (!this->autooob) { -+ /* Select the appropriate default oob placement scheme for -+ * placement agnostic filesystems */ -+ switch (mtd->oobsize) { -+ case 8: -+ this->autooob = &nand_oob_8; -+ break; -+ case 16: -+ this->autooob = &nand_oob_16; -+ break; -+ case 64: -+ this->autooob = &nand_oob_64; -+ break; -+ default: -+ printk (KERN_WARNING "No oob scheme defined for oobsize %d\n", -+ mtd->oobsize); -+ BUG(); -+ } -+ } -+ -+ /* The number of bytes available for the filesystem to place fs dependend -+ * oob data */ -+ if (this->options & NAND_BUSWIDTH_16) { -+ mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2); -+ if (this->autooob->eccbytes & 0x01) -+ mtd->oobavail--; -+ } else -+ mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1); -+ -+ -+ /* -+ * check ECC mode, default to software -+ * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize -+ * fallback to software ECC -+ */ -+ this->eccsize = 256; /* set default eccsize */ -+ this->eccbytes = 3; -+ -+ switch (this->eccmode) { -+ case NAND_ECC_HW12_2048: -+ if (mtd->oobblock < 2048) { -+ printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n", -+ mtd->oobblock); -+ this->eccmode = NAND_ECC_SOFT; -+ this->calculate_ecc = nand_calculate_ecc; -+ this->correct_data = nand_correct_data; -+ } else -+ this->eccsize = 2048; -+ break; -+ -+ case NAND_ECC_HW3_512: -+ case NAND_ECC_HW6_512: -+ case NAND_ECC_HW8_512: -+ if (mtd->oobblock == 256) { -+ printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); -+ this->eccmode = NAND_ECC_SOFT; -+ this->calculate_ecc = nand_calculate_ecc; -+ this->correct_data = nand_correct_data; -+ } else -+ this->eccsize = 512; /* set eccsize to 512 */ -+ break; -+ -+ case NAND_ECC_HW3_256: -+ break; -+ -+ case NAND_ECC_NONE: -+ printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); -+ this->eccmode = NAND_ECC_NONE; -+ break; -+ -+ case NAND_ECC_SOFT: -+ this->calculate_ecc = nand_calculate_ecc; -+ this->correct_data = nand_correct_data; -+ break; -+ -+ default: -+ printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); -+ BUG(); -+ } -+ -+ /* Check hardware ecc function availability and adjust number of ecc bytes per -+ * calculation step -+ */ -+ switch (this->eccmode) { -+ case NAND_ECC_HW12_2048: -+ this->eccbytes += 4; -+ case NAND_ECC_HW8_512: -+ this->eccbytes += 2; -+ case NAND_ECC_HW6_512: -+ this->eccbytes += 3; -+// case NAND_ECC_HW3_512: -+ case NAND_ECC_HW3_256: -+ if (this->calculate_ecc && this->correct_data && this->enable_hwecc) -+ break; -+ printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); -+ BUG(); -+ } -+ -+ mtd->eccsize = this->eccsize; -+ -+ /* Set the number of read / write steps for one page to ensure ECC generation */ -+ switch (this->eccmode) { -+ case NAND_ECC_HW12_2048: -+ this->eccsteps = mtd->oobblock / 2048; -+ break; -+ case NAND_ECC_HW3_512: -+ case NAND_ECC_HW6_512: -+ case NAND_ECC_HW8_512: -+ this->eccsteps = mtd->oobblock / 512; -+ break; -+ case NAND_ECC_HW3_256: -+ case NAND_ECC_SOFT: -+ this->eccsteps = mtd->oobblock / 256; -+ break; -+ -+ case NAND_ECC_NONE: -+ this->eccsteps = 1; -+ break; -+ } -+ -+ /* Initialize state, waitqueue and spinlock */ -+ this->state = FL_READY; -+ init_waitqueue_head (&this->wq); -+ spin_lock_init (&this->chip_lock); -+ -+ /* De-select the device */ -+ this->select_chip(mtd, 0); -+ -+ /* Print warning message for no device */ -+ if (!mtd->size) { -+ printk (KERN_WARNING "No NAND device found!!!\n"); -+ return 1; -+ } -+ -+ /* Fill in remaining MTD driver data */ -+ mtd->type = MTD_NANDFLASH; -+ mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; -+ mtd->ecctype = MTD_ECC_SW; -+ mtd->erase = sl2312_nand_erase; -+ mtd->point = NULL; -+ mtd->unpoint = NULL; -+ mtd->read = sl2312_nand_read; -+ mtd->write = sl2312_nand_write; -+ mtd->read_ecc = sl2312_nand_read_ecc; -+ mtd->write_ecc = sl2312_nand_write_ecc; -+ mtd->read_oob = sl2312_nand_read_oob; -+ mtd->write_oob = sl2312_nand_write_oob; -+ mtd->readv = NULL; -+ mtd->writev = sl2312_nand_writev; -+ mtd->writev_ecc = sl2312_nand_writev_ecc; -+ mtd->sync = sl2312_nand_sync; -+ mtd->lock = NULL; -+ mtd->unlock = NULL; -+ mtd->suspend = NULL; -+ mtd->resume = NULL; -+ mtd->block_isbad = sl2312_nand_block_isbad; -+ mtd->block_markbad = sl2312_nand_block_markbad; -+ -+ /* and make the autooob the default one */ -+ memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); -+ -+ mtd->owner = THIS_MODULE; -+ -+ /* Build bad block table */ -+ return this->scan_bbt (mtd); -+} -+ -+/*End Add function*/ -+ -+/* -+ * Main initialization routine -+ */ -+extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); -+ -+int __init sl2312_mtd_init (void) -+{ -+ struct nand_chip *this; -+ int err = 0; -+ struct mtd_partition *parts; -+ int nr_parts = 0; -+ int ret, data, *base; -+ -+ printk("NAND MTD Driver Start Init ......\n"); -+ -+ base = (unsigned int *)(IO_ADDRESS(SL2312_GLOBAL_BASE) + 0x30); -+ data = *base; -+ data&=0xffffffeb; -+ data|=0x3; //disable p & s flash -+ *base = data; -+ -+ /* Allocate memory for MTD device structure and private data */ -+ sl2312_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); -+ if (!sl2312_mtd) { -+ printk ("Unable to allocate SL2312 NAND MTD device structure.\n"); -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ // sl2312_device_setup(); -+ -+ /* io is indirect via a register so don't need to ioremap address */ -+ -+ /* Get pointer to private data */ -+ this = (struct nand_chip *) (&sl2312_mtd[1]); -+ -+ /* Initialize structures */ -+ memset((char *) sl2312_mtd, 0, sizeof(struct mtd_info)); -+ memset((char *) this, 0, sizeof(struct nand_chip)); -+ -+ /* Link the private data with the MTD structure */ -+ sl2312_mtd->priv = this; -+ sl2312_mtd->name = "sl2312-nand"; -+ -+ /* Set address of NAND IO lines */ -+ this->IO_ADDR_R = (void __iomem *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE+NFLASH_DATA)); //(unsigned long)&(sl2312_ndfmcptr->dtr); -+ this->IO_ADDR_W = (void __iomem *)IO_ADDRESS((SL2312_FLASH_CTRL_BASE+NFLASH_DATA)); //(unsigned long)&(sl2312_ndfmcptr->dtr); -+ this->read_byte = sl2312_nand_read_byte; -+ this->write_byte = sl2312_nand_write_byte; -+ this->write_buf = sl2312_nand_write_buf; -+ this->read_buf = sl2312_nand_read_buf; -+ this->verify_buf = sl2312_nand_verify_buf; -+ this->select_chip = sl2312_nand_select_chip; -+ this->block_bad = sl2312_nand_block_bad; -+ this->hwcontrol = sl2312_hwcontrol; -+ this->dev_ready = sl2312_device_ready; -+ this->cmdfunc = sl2312_nand_command; -+ this->waitfunc = sl2312_nand_waitfunc; -+ //this->calculate_ecc = sl2312_readecc; -+ this->enable_hwecc = sl2312_enable_hwecc; -+ this->eccmode = NAND_ECC_HW3_512; -+ /*this->eccsize = 512; */ -+ /* 20 us command delay time */ -+ this->chip_delay = 20; -+ -+ this->correct_data = nand_correct_data; -+// this->scan_bbt = sl2312_nand_scan_bbt; -+ -+ /* Allocate memory for internal data buffer */ -+ this->data_buf = kmalloc (sizeof(u_char) * (sl2312_mtd->oobblock + sl2312_mtd->oobsize), GFP_KERNEL); -+ if (!this->data_buf) { -+ printk ("Unable to allocate NAND data buffer.\n"); -+ err = -ENOMEM; -+ goto out_ior; -+ } -+ -+ /* Scan to find existance of the device */ -+ if (sl2312_nand_scan(sl2312_mtd, 1)) { -+ err = -ENXIO; -+ goto out_ior; -+ } -+ -+ /* Register the partitions */ -+ parts = sl2312_partitions; -+ nr_parts = sizeof(sl2312_partitions)/sizeof(*parts); -+ -+ ret = add_mtd_partitions(sl2312_mtd, sl2312_partitions, nr_parts); -+ /*If we got an error, free all resources.*/ -+ if (ret < 0) { -+ del_mtd_partitions(sl2312_mtd); -+ map_destroy(sl2312_mtd); -+ } -+ goto out; -+ -+//out_buf: -+// kfree (this->data_buf); -+out_ior: -+out: -+ printk("NAND MTD Driver Init Success ......\n"); -+ return err; -+} -+ -+module_init(sl2312_mtd_init); -+ -+/* -+ * Clean up routine -+ */ -+#ifdef MODULE -+static void __exit sl2312_cleanup (void) -+{ -+ struct nand_chip *this = (struct nand_chip *) &sl2312_mtd[1]; -+ -+ /* Unregister partitions */ -+ del_mtd_partitions(sl2312_mtd); -+ -+ /* Unregister the device */ -+ del_mtd_device (sl2312_mtd); -+ -+ /* Free internal data buffers */ -+ kfree (this->data_buf); -+ -+ /* Free the MTD device structure */ -+ kfree (sl2312_mtd); -+} -+module_exit(sl2312_cleanup); -+#endif -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>"); -+MODULE_DESCRIPTION("Glue layer for SmartMediaCard on Toshiba RBsl2312"); ---- /dev/null -+++ b/drivers/mtd/nand/sl2312-flash-nand.h -@@ -0,0 +1,24 @@ -+#ifndef SL2312_FLASH_NAND_H -+#define SL2312_FLASH_NAND_H -+ -+#include <linux/wait.h> -+#include <linux/spinlock.h> -+ -+/*Add function*/ -+static void nand_read_id(int chip_no,unsigned char *id); -+ -+ -+ -+#define NFLASH_WiDTH8 0x00000000 -+#define NFLASH_WiDTH16 0x00000400 -+#define NFLASH_WiDTH32 0x00000800 -+#define NFLASH_CHIP0_EN 0x00000000 // 16th bit = 0 -+#define NFLASH_CHIP1_EN 0x00010000 // 16th bit = 1 -+#define NFLASH_DIRECT 0x00004000 -+#define NFLASH_INDIRECT 0x00000000 -+ -+ -+#define DWIDTH NFLASH_WiDTH8 -+ -+ -+#endif /* SL2312_FLASH_NAND_H */ ---- /dev/null -+++ b/include/linux/mtd/kvctl.h -@@ -0,0 +1,40 @@ -+#ifndef KVCTL_H -+#define KVCTL_H -+ -+#define VCTL_HEAD_SIZE 8 -+#define VCTL_ENTRY_LEN 20 -+ -+typedef struct -+{ -+ char header[4]; -+ unsigned int entry_num; -+} vctl_mheader; -+ -+typedef struct -+{ -+ char header[4]; -+ unsigned int size; -+ unsigned int type; -+ char majorver[4]; -+ char minorver[4]; -+ unsigned char *payload; -+} vctl_entry; -+ -+typedef struct -+{ -+ unsigned char mac[6]; -+ unsigned char vlanid; -+ unsigned char vlanmap; -+} vlaninfo; -+ -+#define VCT_VENDORSPEC 0 -+#define VCT_BOOTLOADER 1 -+#define VCT_KERNEL 2 -+#define VCT_VERCTL 3 -+#define VCT_CURRCONF 4 -+#define VCT_DEFAULTCONF 5 -+#define VCT_ROOTFS 6 -+#define VCT_APP 7 -+#define VCT_VLAN 8 -+ -+#endif ---- a/drivers/mtd/maps/Makefile -+++ b/drivers/mtd/maps/Makefile -@@ -71,3 +71,7 @@ obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o - obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o - obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o - obj-$(CONFIG_MTD_TQM834x) += tqm834x.o -+###### for Storlink Soc ####### -+obj-$(CONFIG_MTD_SL2312_CFI) += sl2312-flash-cfi.o -+obj-$(CONFIG_MTD_SL2312_SERIAL_ATMEL) += sl2312-flash-atmel.o -+obj-$(CONFIG_MTD_SL2312_SERIAL_ST) += sl2312-flash-m25p80.o |