summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Schinagl <oliver@schinagl.nl>2011-03-31 14:25:25 (GMT)
committerOliver Schinagl <oliver@schinagl.nl>2011-03-31 14:25:25 (GMT)
commita45a416fd4f85215ccccb1200dd2c0f0f74dba17 (patch)
tree6d7513f7002cbbd7c612fb2a9b0e40a147c54474
parentd810895d6ad59222c4b220d602fc307d80ee97a2 (diff)
downloadopenipcam-a45a416fd4f85215ccccb1200dd2c0f0f74dba17.zip
openipcam-a45a416fd4f85215ccccb1200dd2c0f0f74dba17.tar.gz
openipcam-a45a416fd4f85215ccccb1200dd2c0f0f74dba17.tar.bz2
w90n745 flash mappings and nand driver
-rw-r--r--uClinux-2.4.20-uc1/drivers/mtd/maps/Config.in1
-rw-r--r--uClinux-2.4.20-uc1/drivers/mtd/maps/Makefile1
-rw-r--r--uClinux-2.4.20-uc1/drivers/mtd/maps/w90n745_map.c160
-rw-r--r--uClinux-2.4.20-uc1/drivers/mtd/nand/Config.in26
-rw-r--r--uClinux-2.4.20-uc1/drivers/mtd/nand/Makefile3
-rw-r--r--uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_128mb_nand.c323
-rw-r--r--uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_32mb_nand.c310
-rw-r--r--uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_nand.h31
-rw-r--r--uClinux-2.4.20-uc1/include/linux/mtd/map.h44
9 files changed, 899 insertions, 0 deletions
diff --git a/uClinux-2.4.20-uc1/drivers/mtd/maps/Config.in b/uClinux-2.4.20-uc1/drivers/mtd/maps/Config.in
index f01ee4d..d0f9723 100644
--- a/uClinux-2.4.20-uc1/drivers/mtd/maps/Config.in
+++ b/uClinux-2.4.20-uc1/drivers/mtd/maps/Config.in
@@ -99,6 +99,7 @@ if [ "$CONFIG_ARM" = "y" ]; then
dep_tristate ' CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310
dep_tristate ' CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
dep_tristate ' NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12
+ dep_tristate ' W90N745 board mappings' CONFIG_MTD_W90N745 $CONFIG_BOARD_W90N745
fi
if [ "$CONFIG_COBRA5272" = "y" ]; then
diff --git a/uClinux-2.4.20-uc1/drivers/mtd/maps/Makefile b/uClinux-2.4.20-uc1/drivers/mtd/maps/Makefile
index 0dfd007..e8b8ef6 100644
--- a/uClinux-2.4.20-uc1/drivers/mtd/maps/Makefile
+++ b/uClinux-2.4.20-uc1/drivers/mtd/maps/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_MTD_PB1100) += pb1xxx-flash.o
obj-$(CONFIG_MTD_PB1500) += pb1xxx-flash.o
obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
+obj-$(CONFIG_MTD_W90N745) += w90n745_map.o
include $(TOPDIR)/Rules.make
diff --git a/uClinux-2.4.20-uc1/drivers/mtd/maps/w90n745_map.c b/uClinux-2.4.20-uc1/drivers/mtd/maps/w90n745_map.c
new file mode 100644
index 0000000..a3fd78b
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/mtd/maps/w90n745_map.c
@@ -0,0 +1,160 @@
+#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 <linux/config.h>
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <asm/io.h>
+
+
+#if 1
+#define DEBUGMTD printk
+#else
+#define DEBUGMTD
+#endif
+
+#define WINDOW_ADDR 0xFF000000 //lsshi
+#define WINDOW_SIZE 0x400000 //flash size (4M)
+
+#define BUSWIDTH 2
+
+
+
+static struct mtd_info *mymtd;
+
+__u8 W90N745_read8(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readb(map->map_priv_1 + ofs);
+}
+
+struct map_info W90N745_map;
+
+__u16 W90N745_read16(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readw(map->map_priv_1 + ofs);
+}
+
+map_word W90N745_read(struct map_info *map, unsigned long ofs)
+{
+ map_word r;
+
+ r.x[0] = __raw_readw(map->map_priv_1 + ofs);
+ return r;
+}
+
+__u32 W90N745_read32(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void W90N745_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void W90N745_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ __raw_writeb(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void W90N745_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ __raw_writew(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void W90N745_write(struct map_info *map, const map_word datum, unsigned long ofs)
+{
+ __raw_writew(datum.x[0], map->map_priv_1 + ofs);
+
+ mb();
+}
+
+void W90N745_write32(struct map_info *map, __u32 d, unsigned long adr)
+
+{
+ __raw_writel(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void W90N745_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+struct map_info W90N745_map = {
+ name: "POS-TAX flash device", //lsshi W90N745 flash device
+ size: WINDOW_SIZE,
+ buswidth: BUSWIDTH,
+ read: W90N745_read,
+ read8: W90N745_read8,
+ read16: W90N745_read16,
+ read32: W90N745_read32,
+ copy_from: W90N745_copy_from,
+ write8: W90N745_write8,
+ write16: W90N745_write16,
+ write: W90N745_write,
+ write32: W90N745_write32,
+ copy_to: W90N745_copy_to
+};
+
+/*
+ * MTD 'PARTITIONING' STUFF
+ */
+
+static struct mtd_partition W90N745_partitions[] = {
+ {
+ name: "images 3M",
+ size: 0x300000,
+ offset: 0
+ }, {
+ /*if jffs2 can run on this partition the size can not less than 6 sectors*/
+ name: "user 1M",
+ size: 0x100000,
+ offset: 0x00300000 //offset
+ }
+};
+
+int __init init_POS_FLASH(void)
+{
+ W90N745_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+ if (!W90N745_map.map_priv_1) {
+ printk("Failed to ioremap\n");
+ return -EIO;
+ }
+
+ mymtd = do_map_probe("cfi_probe", &W90N745_map);
+
+ if (mymtd) {
+// mymtd->owner = THIS_MODULE;
+ return add_mtd_partitions(mymtd, W90N745_partitions, sizeof(W90N745_partitions) / sizeof(struct mtd_partition));
+ }
+
+ iounmap((void *)W90N745_map.map_priv_1);
+
+ return -ENXIO;
+}
+
+static void __exit cleanup_POS_FLASH(void)
+{
+ if (mymtd) {
+ del_mtd_partitions(mymtd);
+ map_destroy(mymtd);
+ }
+
+ if (W90N745_map.map_priv_1) {
+ iounmap((void *)W90N745_map.map_priv_1);
+ W90N745_map.map_priv_1 = 0;
+ }
+}
+
+module_init(init_POS_FLASH);
+module_exit(cleanup_POS_FLASH);
diff --git a/uClinux-2.4.20-uc1/drivers/mtd/nand/Config.in b/uClinux-2.4.20-uc1/drivers/mtd/nand/Config.in
index 29d7e58..5c5f30a 100644
--- a/uClinux-2.4.20-uc1/drivers/mtd/nand/Config.in
+++ b/uClinux-2.4.20-uc1/drivers/mtd/nand/Config.in
@@ -12,7 +12,33 @@ if [ "$CONFIG_MTD_NAND" = "y" -o "$CONFIG_MTD_NAND" = "m" ]; then
bool ' Verify NAND page writes' CONFIG_MTD_NAND_VERIFY_WRITE
fi
if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_P720T" = "y" ]; then
+ dep_tristate ' NAND Flash device on WINBOND board' CONFIG_MTD_NAND_WINBOND $CONFIG_MTD_NAND $CONFIG_ARCH_WINBOND
+ if [ "$CONFIG_MTD_NAND_WINBOND" != "n" ]; then
+ choice 'NAND is to be used in the system' \
+ "128MB_2k_page_size CONFIG_128MB_NAND \
+ 32MB_512_page_size CONFIG_32MB_NAND" 128MB_2k_page_size
+ fi
+ # NAND type must be set, makefile use this to decide which yaffs2 directory to link.
+ if [ "$CONFIG_128MB_NAND" = "y" ]; then
+ define_bool CONFIG_2K_PAGE_SIZE y
+ fi
+ if [ "$CONFIG_32MB_NAND" = "y" ]; then
+ define_bool CONFIG_512B_PAGE_SIZE y
+ fi
dep_tristate ' NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND
+ dep_tristate ' NAND Flash device on WINBOND board' CONFIG_MTD_NAND_WINBOND $CONFIG_MTD_NAND $CONFIG_ARCH_WINBOND
+ if [ "$CONFIG_MTD_NAND_WINBOND" != "n" ]; then
+ choice 'NAND is to be used in the system' \
+ "128MB_2k_page_size CONFIG_128MB_NAND\
+ 32MB_512_page_size CONFIG_32MB_NAND" 128MB_2k_page_size
+ fi
+ # NAND type must be set, makefile use this to decide which yaffs2 directory to link.
+ if [ "$CONFIG_128MB_NAND" = "y" ]; then
+ define_bool CONFIG_2K_PAGE_SIZE y
+ fi
+ if [ "$CONFIG_32MB_NAND" = "y" ]; then
+ define_bool CONFIG_512B_PAGE_SIZE y
+ fi
fi
endmenu
diff --git a/uClinux-2.4.20-uc1/drivers/mtd/nand/Makefile b/uClinux-2.4.20-uc1/drivers/mtd/nand/Makefile
index 87de013..387cc71 100644
--- a/uClinux-2.4.20-uc1/drivers/mtd/nand/Makefile
+++ b/uClinux-2.4.20-uc1/drivers/mtd/nand/Makefile
@@ -12,5 +12,8 @@ nandobjs-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_MTD_NAND) += $(nandobjs-y)
obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
+#obj-$(CONFIG_MTD_NAND_WINBOND) += w90n745_nand.o
+obj-$(CONFIG_128MB_NAND) += w90n745_128mb_nand.o
+obj-$(CONFIG_32MB_NAND) += w90n745_32mb_nand.o
include $(TOPDIR)/Rules.make
diff --git a/uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_128mb_nand.c b/uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_128mb_nand.c
new file mode 100644
index 0000000..37330c8
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_128mb_nand.c
@@ -0,0 +1,323 @@
+/*
+ * linux/drivers/mtd/nand/w90n745_nand.c
+ *
+ * Copyright (c) 2006 Winbond (http://www.winbond.com.tw)
+ *
+ * History:
+ * 2006/08/24 Created by NS24 zswan v1.0 for nand 512b per page
+ * 2006/12/12 Created by NS24 zswan v1.1 for nand 2kb per page
+ * mail:zswan@winbond.com.tw
+ */
+
+#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/partitions.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "w90n745_nand.h"
+
+#define write_cmd_reg(cmd) outb(cmd, REG_SMCMD)
+#define write_addr_reg(addr) outb(addr, REG_SMADDR)
+#define read_data_reg() inb(REG_SMDATA)
+#define write_data_reg(value) outb(value, REG_SMDATA)
+
+
+typedef unsigned int UINT32;
+typedef unsigned char UINT8;
+UINT32 blockaddr;
+UINT8 _fmi_ucBaseAddr1, _fmi_ucBaseAddr2;
+/*
+ * MTD structure for NAND controller
+ */
+static struct mtd_info *w90n745_mtd = NULL;
+//static u_char data_buf[2048 + 64];
+//static u_char oob_buf[64*64];
+/*
+ * Define partitions for flash device
+ */
+#define NUM_PARTITIONS 2
+const static struct mtd_partition partition_info[NUM_PARTITIONS] = {
+ {
+ .name = "w90n745 2K NAND PAR1",
+ .offset = 0,
+ .size = 64*1024*1024
+ }, {
+ .name = "w90n745 2K NAND PAR2",
+ .offset = 64*1024*1024,
+ .size = 64*1024*1024
+ },
+};
+
+static int w90n745_device_ready(struct mtd_info *mtd)
+{
+ int ready;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_device_ready\n");
+#endif
+ ready = (ebiCheckRB()) ? 1 : 0; // rb# status
+ return ready;
+}
+
+static u_char w90n745_nand_read_byte(struct mtd_info *mtd)
+{
+ u_char ret;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_read_byte\n");
+#endif
+ ret = (u_char)read_data_reg();
+ return ret;
+}
+
+static void w90n745_nand_write_byte(struct mtd_info *mtd, u_char byte)
+{
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_write_byte\n");
+#endif
+ write_data_reg(byte);
+}
+
+int ebiCheckRB(void)
+{
+ return (inl(0xfff8305c) & 0x10);
+}
+
+static void nand_reset(void)
+{
+ UINT32 volatile i;
+
+#ifdef _DEBUG_NAND
+ printk("nand_reset\n");
+#endif
+ outb(0xff, REG_SMCMD);
+ for (i=100; i>0; i--);
+ while (!ebiCheckRB());
+}
+
+static void w90n745_nand_write_buf(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ int i;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_write_buf\n");
+#endif
+ for (i=0; i < len; i++){
+ write_data_reg(buf[i]);
+ }
+}
+
+
+static void w90n745_nand_read_buf(struct mtd_info *mtd,
+ u_char *buf, int len)
+{
+ int i;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_read_buf\n");
+#endif
+ for (i = 0; i < len; i++){
+ buf[i] =(u_char)read_data_reg();
+ }
+}
+
+static int
+w90n745_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ int i;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_verify_buf\n");
+#endif
+ for (i=0; i < len; i++) {
+ if (buf[i] != (u_char)read_data_reg()) {
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
+
+static void w90n745_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_select_chip\n");
+#endif
+}
+
+static void w90n745_nand_command (struct mtd_info *mtd, unsigned command,
+ int column, int page_addr)
+{
+ register struct nand_chip *this = mtd->priv;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_command\n");
+#endif
+ /* Emulate NAND_CMD_READOOB */
+ if (command == NAND_CMD_READOOB) {
+ column += mtd->oobblock;
+
+ command = NAND_CMD_READ0;
+ }
+
+ /* Write out the command to the device. */
+ write_cmd_reg(command);
+
+ if (column != -1 || page_addr != -1) {
+ //this->hwcontrol(mtd, NAND_CTL_SETALE);
+
+ /* Serially input address */
+ if (column != -1) {
+ /* Adjust columns for 16 bit buswidth */
+ if (this->options & NAND_BUSWIDTH_16){
+ column >>= 1;
+ printk("********NAND_BUSWIDTH_16********\n");
+ }
+ write_addr_reg( column & 0xff);
+ write_addr_reg(column >> 8);
+
+ }
+ if (page_addr != -1) {
+
+ write_addr_reg((unsigned char)(page_addr )& 0xff);
+ write_addr_reg((unsigned char) ((page_addr>>8 )& 0xff));
+ /* One more address cycle for devices > 128MiB */
+ if (this->chipsize > (128 << 20)) {
+ write_addr_reg((unsigned char) ((page_addr >> 16) & 0xff));
+ }
+ }
+ }
+
+ /*
+ * program and erase have their own busy handlers
+ * status and sequential in needs no delay
+ */
+ switch (command) {
+ case NAND_CMD_CACHEDPROG:
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_ERASE2:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_STATUS:
+ return;
+ case NAND_CMD_RESET:
+ nand_reset();
+ return;
+ case NAND_CMD_READ0:
+ write_cmd_reg(NAND_CMD_READSTART);
+ /* This applies to read commands */
+ default:
+ /*
+ * If we don't have access to the busy pin, we apply the given
+ * command delay
+ */
+ udelay(this->chip_delay);
+ return;
+ }
+
+ /* Apply this short delay always to ensure that we do wait tWB in
+ * any case on any machine. */
+ while (!this->dev_ready(mtd));
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init w90n745_init (void)
+{
+ struct nand_chip *this;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_init\n");
+#endif
+ // set EBI
+ #ifdef EBI_BANK2
+ Setup_EXTIO2_Base();
+ #else
+ Setup_EXTIO3_Base();
+ #endif
+
+ // set GPIO
+ outpw(0xfff83050, inpw(0xfff83050) & 0xfffff0ff); // GPIO5-4 and GPIO5-5
+ outpw(0xfff83054, (inpw(0xfff83054) & 0xffffffcf) | 0x20);
+ outpw(0xfff83058, inpw(0xfff83058) | 0x20);
+
+ /* Allocate memory for MTD device structure and private data */
+ w90n745_mtd = kmalloc (sizeof(struct mtd_info) +
+ sizeof (struct nand_chip), GFP_KERNEL);
+ //w90n745_mtd=kmalloc (1024, GFP_KERNEL);
+ //kfree (w90n745_mtd);
+ if (!w90n745_mtd) {
+ printk ("Unable to allocate NAND MTD dev structure.\n");
+ return -ENOMEM;
+ }
+
+ /* Get pointer to private data */
+ this = (struct nand_chip *) (&w90n745_mtd[1]);
+
+ /* Initialize structures */
+ memset((char *) w90n745_mtd, 0, sizeof(struct mtd_info));
+ memset((char *) this, 0, sizeof(struct nand_chip));
+
+ /* Link the private data with the MTD structure */
+ w90n745_mtd->priv = this;
+
+ /* Set address of hardware control function */
+
+ this->dev_ready = w90n745_device_ready;
+ /* 30 us command delay time */
+ this->chip_delay = 100;
+
+ this->cmdfunc = w90n745_nand_command;
+ this->select_chip = w90n745_nand_select_chip;
+ //this->select_chip = NULL;
+ this->write_byte = w90n745_nand_write_byte;
+ this->read_byte = w90n745_nand_read_byte;
+ this->write_buf = w90n745_nand_write_buf;
+ this->read_buf = w90n745_nand_read_buf;
+ this->verify_buf = w90n745_nand_verify_buf;
+
+ this->eccmode = NAND_ECC_SOFT;
+
+ this->data_buf = NULL;
+ this->oob_buf = NULL;
+ //w90n745_nand_Reset();
+ /* Scan to find existence of the device */
+ if (nand_scan (w90n745_mtd, 1)) {
+ kfree (w90n745_mtd);
+ return -ENXIO;
+ }
+
+ /* Register the partitions */
+ add_mtd_partitions(w90n745_mtd, partition_info, NUM_PARTITIONS);
+
+ return 0;
+}
+
+static void __exit w90n745_exit(void)
+{
+ struct nand_chip *this = (struct nand_chip *) &w90n745_mtd[1];
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_exit\n");
+#endif
+ /* Unregister partitions */
+ del_mtd_partitions(w90n745_mtd);
+
+ /* Unregister the device */
+ del_mtd_device (w90n745_mtd);
+
+ /* Free the MTD device structure */
+ kfree (w90n745_mtd);
+}
+
+module_init(w90n745_init);
+module_exit(w90n745_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("NS24 zswan, zswan@Winbond.com.tw");
+MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on w90n745 board");
diff --git a/uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_32mb_nand.c b/uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_32mb_nand.c
new file mode 100644
index 0000000..9a5c6b5
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_32mb_nand.c
@@ -0,0 +1,310 @@
+/*
+ * linux/drivers/mtd/nand/w90n745_nand.c
+ *
+ * Copyright (c) 2006 Winbond (http://www.winbond.com.tw)
+ *
+ * History:
+ * 2006/08/24 Created by NS24 zswan v1.0 for nand 512b per page
+ * 2006/12/12 Created by NS24 zswan v1.1 for nand 2kb per page
+ * mail:zswan@winbond.com.tw
+ */
+
+#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/partitions.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "w90n745_nand.h"
+
+#define write_cmd_reg(cmd) outb(cmd, REG_SMCMD)
+#define write_addr_reg(addr) outb(addr, REG_SMADDR)
+#define read_data_reg() inb(REG_SMDATA)
+#define write_data_reg(value) outb(value, REG_SMDATA)
+
+
+typedef unsigned int UINT32;
+typedef unsigned char UINT8;
+UINT32 blockaddr;
+UINT8 _fmi_ucBaseAddr1, _fmi_ucBaseAddr2;
+/*
+ * MTD structure for NAND controller
+ */
+static struct mtd_info *w90n745_mtd = NULL;
+//static u_char data_buf[2048 + 64];
+//static u_char oob_buf[64*64];
+/*
+ * Define partitions for flash device
+ */
+#define NUM_PARTITIONS 2
+const static struct mtd_partition partition_info[NUM_PARTITIONS] = {
+ {
+ .name = "w90n745 512B NAND PAR1",
+ .offset = 0,
+ .size = 16*1024*1024
+ }, {
+ .name = "w90n745 512B NAND PAR2",
+ .offset = 16*1024*1024,
+ .size = 16*1024*1024
+ },
+};
+
+static int w90n745_device_ready(struct mtd_info *mtd)
+{
+ int ready;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_device_ready\n");
+#endif
+ ready = (ebiCheckRB()) ? 1 : 0; // rb# status
+ return ready;
+}
+
+static u_char w90n745_nand_read_byte(struct mtd_info *mtd)
+{
+ u_char ret;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_read_byte\n");
+#endif
+ ret = (u_char)read_data_reg();
+ return ret;
+}
+
+static void w90n745_nand_write_byte(struct mtd_info *mtd, u_char byte)
+{
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_write_byte\n");
+#endif
+ write_data_reg(byte);
+}
+
+int ebiCheckRB(void)
+{
+ return (inl(0xfff8305c) & 0x10);
+}
+
+static void nand_reset(void)
+{
+ UINT32 volatile i;
+
+#ifdef _DEBUG_NAND
+ printk("nand_reset\n");
+#endif
+ outb(0xff, REG_SMCMD);
+ for (i=100; i>0; i--);
+ while (!ebiCheckRB());
+}
+
+static void w90n745_nand_write_buf(struct mtd_info *mtd,
+ const u_char *buf, int len)
+{
+ int i;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_write_buf\n");
+#endif
+ for (i=0; i < len; i++){
+ write_data_reg(buf[i]);
+ }
+}
+
+
+static void w90n745_nand_read_buf(struct mtd_info *mtd,
+ u_char *buf, int len)
+{
+ int i;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_read_buf\n");
+#endif
+ for (i = 0; i < len; i++){
+ buf[i] =(u_char)read_data_reg();
+ }
+}
+
+static int
+w90n745_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ int i;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_verify_buf\n");
+#endif
+ for (i=0; i < len; i++) {
+ if (buf[i] != (u_char)read_data_reg()) {
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
+
+static void w90n745_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_select_chip\n");
+#endif
+}
+
+static void w90n745_nand_command (struct mtd_info *mtd, unsigned command,
+ int column, int page_addr)
+{
+ register struct nand_chip *this = mtd->priv;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_nand_command\n");
+#endif
+ if (command == NAND_CMD_SEQIN) {
+ int readcmd;
+
+ if (column >= mtd->oobblock) {
+ /* OOB area */
+ column -= mtd->oobblock;
+ readcmd = NAND_CMD_READOOB;
+ } else if (column < 256) {
+ /* First 256 bytes --> READ0 */
+ readcmd = NAND_CMD_READ0;
+ } else {
+ column -= 256;
+ readcmd = NAND_CMD_READ1;
+ }
+ write_cmd_reg(readcmd);
+ }
+
+ write_cmd_reg(command);
+
+ if (column != -1 || page_addr != -1) {
+
+ /* Serially input address */
+ if (column != -1) {
+ write_addr_reg(column);
+ }
+ if (page_addr != -1) {
+ write_addr_reg((unsigned char)(page_addr )& 0xff);
+ write_addr_reg((unsigned char) ((page_addr>>8 )& 0xff));
+ }
+ /* One more address cycle for higher density devices */
+ if (mtd->size & 0x0c000000) {
+ //write_addr_reg((unsigned char) ((page_addr >> 16) & 0x0f));
+ }
+ }
+
+ switch (command) {
+ case NAND_CMD_PAGEPROG:
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_ERASE2:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_STATUS:
+ break;
+ case NAND_CMD_RESET:
+ write_cmd_reg(command);
+ //udelay(this->chip_delay);
+ //while(!(inl(REG_SMISR) & 0x10)); // rb# status
+ nand_reset();
+ break;
+ default:
+ udelay(this->chip_delay);
+ break;
+ }
+
+ while (!this->dev_ready(mtd));
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init w90n745_init (void)
+{
+ struct nand_chip *this;
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_init\n");
+#endif
+ // set EBI
+ #ifdef EBI_BANK2
+ Setup_EXTIO2_Base();
+ #else
+ Setup_EXTIO3_Base();
+ #endif
+
+ // set GPIO
+ outpw(0xfff83050, inpw(0xfff83050) & 0xfffff0ff); // GPIO5-4 and GPIO5-5
+ outpw(0xfff83054, (inpw(0xfff83054) & 0xffffffcf) | 0x20);
+ outpw(0xfff83058, inpw(0xfff83058) | 0x20);
+
+ /* Allocate memory for MTD device structure and private data */
+ w90n745_mtd = kmalloc (sizeof(struct mtd_info) +
+ sizeof (struct nand_chip), GFP_KERNEL);
+ //w90n745_mtd=kmalloc (1024, GFP_KERNEL);
+ //kfree (w90n745_mtd);
+ if (!w90n745_mtd) {
+ printk ("Unable to allocate NAND MTD dev structure.\n");
+ return -ENOMEM;
+ }
+
+ /* Get pointer to private data */
+ this = (struct nand_chip *) (&w90n745_mtd[1]);
+
+ /* Initialize structures */
+ memset((char *) w90n745_mtd, 0, sizeof(struct mtd_info));
+ memset((char *) this, 0, sizeof(struct nand_chip));
+
+ /* Link the private data with the MTD structure */
+ w90n745_mtd->priv = this;
+
+
+ this->dev_ready = w90n745_device_ready;
+ /* 30 us command delay time */
+ this->chip_delay = 100;
+
+ this->cmdfunc = w90n745_nand_command;
+ this->select_chip = w90n745_nand_select_chip;
+ //this->select_chip = NULL;
+ this->write_byte = w90n745_nand_write_byte;
+ this->read_byte = w90n745_nand_read_byte;
+ this->write_buf = w90n745_nand_write_buf;
+ this->read_buf = w90n745_nand_read_buf;
+ this->verify_buf = w90n745_nand_verify_buf;
+
+ this->eccmode = NAND_ECC_NONE;
+ this->data_buf = NULL;
+ this->oob_buf = NULL;
+ //w90n745_nand_Reset();
+ /* Scan to find existence of the device */
+ if (nand_scan (w90n745_mtd, 1)) {
+ kfree (w90n745_mtd);
+ return -ENXIO;
+ }
+
+ /* Register the partitions */
+ add_mtd_partitions(w90n745_mtd, partition_info, NUM_PARTITIONS);
+
+ return 0;
+}
+
+static void __exit w90n745_exit(void)
+{
+ struct nand_chip *this = (struct nand_chip *) &w90n745_mtd[1];
+
+#ifdef _DEBUG_NAND
+ printk("w90n745_exit\n");
+#endif
+ /* Unregister partitions */
+ del_mtd_partitions(w90n745_mtd);
+
+ /* Unregister the device */
+ del_mtd_device (w90n745_mtd);
+
+ /* Free the MTD device structure */
+ kfree (w90n745_mtd);
+}
+
+module_init(w90n745_init);
+module_exit(w90n745_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("NS24 zswan, zswan@Winbond.com.tw");
+MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on w90n745 board");
diff --git a/uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_nand.h b/uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_nand.h
new file mode 100644
index 0000000..d7a6b28
--- /dev/null
+++ b/uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_nand.h
@@ -0,0 +1,31 @@
+/*
+ * linux/drivers/mtd/nand/w99702g_nand.h
+ *
+ * Copyright (c) 2005 Winbond (http://www.winbond.com.tw)
+ *
+ * History:
+ * 2006/08/24 Created by NS24 zswan
+ */
+
+#define EBI_BANK2
+//#define EBI_BANK3
+#ifdef EBI_BANK2
+#define EXT2CON 0xFFF01020
+#else
+#define EXT3CON 0xFFF01024
+#endif
+#define EBI_BASE_ADDR 0xF0000000
+
+#define outpb(port,value) (*((unsigned char volatile *) (port))=value)
+#define inpb(port) (*((unsigned char volatile *) (port)))
+#define outpw(port,value) (*((unsigned int volatile *) (port))=value)
+#define inpw(port) (*((unsigned int volatile *) (port)))
+
+#define REG_SMCMD (EBI_BASE_ADDR + 0x04)
+#define REG_SMADDR (EBI_BASE_ADDR + 0x08)
+#define REG_SMDATA (EBI_BASE_ADDR + 0x0)
+#ifdef EBI_BANK2
+#define Setup_EXTIO2_Base() (*((unsigned int volatile *)(EXT2CON))=0xE0004491);
+#else
+#define Setup_EXTIO3_Base() (*((unsigned int volatile *)(EXT3CON))=0xE0004491);
+#endif
diff --git a/uClinux-2.4.20-uc1/include/linux/mtd/map.h b/uClinux-2.4.20-uc1/include/linux/mtd/map.h
index 94ffed2..4527e83 100644
--- a/uClinux-2.4.20-uc1/include/linux/mtd/map.h
+++ b/uClinux-2.4.20-uc1/include/linux/mtd/map.h
@@ -10,6 +10,48 @@
#include <linux/mtd/mtd.h>
#include <linux/slab.h>
+#ifdef CONFIG_MTD_CFI_B1
+#define map_bankwidth(map) 1
+#define map_bankwidth_is_1(map) (map_bankwidth(map) == 1)
+#define MAX_MAP_BANKWIDTH 1
+#else
+#define map_bankwidth_is_1(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_CFI_B2
+# ifdef map_bankwidth
+# undef map_bankwidth
+# define map_bankwidth(map) ((map)->bankwidth)
+# else
+# define map_bankwidth(map) 2
+# endif
+#define map_bankwidth_is_2(map) (map_bankwidth(map) == 2)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 2
+#else
+#define map_bankwidth_is_2(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_CFI_B4
+# ifdef map_bankwidth
+# undef map_bankwidth
+# define map_bankwidth(map) ((map)->bankwidth)
+# else
+# define map_bankwidth(map) 4
+# endif
+#define map_bankwidth_is_4(map) (map_bankwidth(map) == 4)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 4
+#else
+#define map_bankwidth_is_4(map) (0)
+#endif
+
+#define MAX_MAP_LONGS ( ((MAX_MAP_BANKWIDTH*8) + BITS_PER_LONG - 1) / BITS_PER_LONG )
+
+typedef union {
+ unsigned long x[MAX_MAP_LONGS];
+} map_word;
+
/* The map stuff is very simple. You fill in your struct map_info with
a handful of routines for accessing the device, making sure they handle
paging etc. correctly if your device needs it. Then you pass it off
@@ -38,10 +80,12 @@ struct map_info {
* I won't.
* dwmw2 */
+ map_word (*read)(struct map_info *, unsigned long);
void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t);
void (*write8)(struct map_info *, __u8, unsigned long);
void (*write16)(struct map_info *, __u16, unsigned long);
void (*write32)(struct map_info *, __u32, unsigned long);
+ void (*write)(struct map_info *, const map_word, unsigned long);
void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
void (*set_vpp)(struct map_info *, int);