From a45a416fd4f85215ccccb1200dd2c0f0f74dba17 Mon Sep 17 00:00:00 2001 From: Oliver Schinagl Date: Thu, 31 Mar 2011 14:25:25 +0000 Subject: w90n745 flash mappings and nand driver --- uClinux-2.4.20-uc1/drivers/mtd/maps/Config.in | 1 + uClinux-2.4.20-uc1/drivers/mtd/maps/Makefile | 1 + uClinux-2.4.20-uc1/drivers/mtd/maps/w90n745_map.c | 160 ++++++++++ uClinux-2.4.20-uc1/drivers/mtd/nand/Config.in | 26 ++ uClinux-2.4.20-uc1/drivers/mtd/nand/Makefile | 3 + .../drivers/mtd/nand/w90n745_128mb_nand.c | 323 +++++++++++++++++++++ .../drivers/mtd/nand/w90n745_32mb_nand.c | 310 ++++++++++++++++++++ uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_nand.h | 31 ++ uClinux-2.4.20-uc1/include/linux/mtd/map.h | 44 +++ 9 files changed, 899 insertions(+) create mode 100644 uClinux-2.4.20-uc1/drivers/mtd/maps/w90n745_map.c create mode 100644 uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_128mb_nand.c create mode 100644 uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_32mb_nand.c create mode 100644 uClinux-2.4.20-uc1/drivers/mtd/nand/w90n745_nand.h 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 #include +#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); -- cgit v0.12