diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index cfe288a..c528024 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -55,6 +55,12 @@ config MTD_NAND_TOTO help Support for NAND flash on Texas Instruments Toto platform. +config MTD_NAND_RB500 + tristate "NAND Flash device on RB500 board" + depends on MTD_NAND + help + Support for NAND flash on RB500 platform. + config MTD_NAND_IDS tristate diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 4174202..2be57c1 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_MTD_NAND_IDS) += nand_ids. obj-$(CONFIG_MTD_NAND_SPIA) += spia.o obj-$(CONFIG_MTD_NAND_TOTO) += toto.o +obj-$(CONFIG_MTD_NAND_RB500) += rbmipsnand.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o diff --git a/drivers/mtd/nand/rbmipsnand.c b/drivers/mtd/nand/rbmipsnand.c new file mode 100644 index 0000000..6f7452a --- /dev/null +++ b/drivers/mtd/nand/rbmipsnand.c @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include +#include +#include +#include +//#include + +#define IDT434_REG_BASE ((volatile void *) KSEG1ADDR(0x18000000)) + +#define SMEM1(x) (*((volatile unsigned char *) (KSEG1ADDR(SMEM1_BASE) + x))) + +#define GPIOF 0x050000 +#define GPIOC 0x050004 +#define GPIOD 0x050008 + +#define GPIO_RDY (1 << 0x08) +#define GPIO_WPX (1 << 0x09) +#define GPIO_ALE (1 << 0x0a) +#define GPIO_CLE (1 << 0x0b) + +#define NAND_RW_REG 0x0 //data register +#define NAND_SET_CEn 0x1 //CE# low +#define NAND_CLR_CEn 0x2 //CE# high +#define NAND_CLR_CLE 0x3 //CLE low +#define NAND_SET_CLE 0x4 //CLE high +#define NAND_CLR_ALE 0x5 //ALE low +#define NAND_SET_ALE 0x6 //ALE high +#define NAND_SET_SPn 0x7 //SP# low (use spare area) +#define NAND_CLR_SPn 0x8 //SP# high (do not use spare area) +#define NAND_SET_WPn 0x9 //WP# low +#define NAND_CLR_WPn 0xA //WP# high +#define NAND_STS_REG 0xB //Status register + +#define DEV2BASE 0x010020 + +#define LO_WPX (1 << 0) +#define LO_ALE (1 << 1) +#define LO_CLE (1 << 2) +#define LO_CEX (1 << 3) +#define LO_FOFF (1 << 5) +#define LO_SPICS (1 << 6) +#define LO_ULED (1 << 7) + +#define MEM32(x) *((volatile unsigned *) (x)) +static void __iomem *p_nand; + +extern void changeLatchU5(unsigned char orMask, unsigned char nandMask); + +static int rb500_dev_ready(struct mtd_info *mtd) { + return MEM32(IDT434_REG_BASE + GPIOD) & GPIO_RDY; +} +/* +static int rb100_dev_ready(struct mtd_info *mtd) { + return SMEM1(NAND_STS_REG) & 0x80; +} +*/ +static unsigned long iflags = 0; +static int ioff = 0; +/* +static void rbmips_hwcontrol400(struct mtd_info *mtd, int cmd) { + switch (cmd) { + case NAND_CTL_SETCLE: + MEM32(IDT434_REG_BASE + GPIOD) |= GPIO_CLE; + break; + case NAND_CTL_CLRCLE: + MEM32(IDT434_REG_BASE + GPIOD) &= ~GPIO_CLE; + break; + case NAND_CTL_SETALE: + MEM32(IDT434_REG_BASE + GPIOD) |= GPIO_ALE; + break; + case NAND_CTL_CLRALE: + MEM32(IDT434_REG_BASE + GPIOD) &= ~GPIO_ALE; + break; + default: + break; + } +} +*/ +static void rbmips_hwcontrol500(struct mtd_info *mtd, int cmd) { + switch (cmd) { + case NAND_CTL_SETCLE: + changeLatchU5(LO_CLE, 0); + break; + case NAND_CTL_CLRCLE: + changeLatchU5(0, LO_CLE); + break; + case NAND_CTL_SETALE: + changeLatchU5(LO_ALE, 0); + break; + case NAND_CTL_CLRALE: + changeLatchU5(0, LO_ALE); + break; + default: + break; + } +} +/* +static void rbmips_hwcontrol100(struct mtd_info *mtd, int cmd){ + switch(cmd){ + case NAND_CTL_SETCLE: + SMEM1(NAND_SET_CLE) = 0x01; + break; + case NAND_CTL_CLRCLE: + SMEM1(NAND_CLR_CLE) = 0x01; + break; + case NAND_CTL_SETALE: + SMEM1(NAND_SET_ALE) = 0x01; + break; + case NAND_CTL_CLRALE: + SMEM1(NAND_CLR_ALE) = 0x01; + break; + case NAND_CTL_SETNCE: + SMEM1(NAND_SET_CEn) = 0x01; + break; + case NAND_CTL_CLRNCE: + SMEM1(NAND_CLR_CEn) = 0x01; + break; + } +} +*/ +static struct mtd_partition partition_info[] = { + { + name: "RouterBoard NAND Boot", + offset: 0, + size: 4 * 1024 * 1024 + }, + { + name: "RouterBoard NAND Main", + offset: MTDPART_OFS_NXTBLK, + size: MTDPART_SIZ_FULL + } +}; + +static struct mtd_info rmtd; +static struct nand_chip rnand; + +static unsigned init_ok = 0; + +unsigned get_rbnand_block_size(void) { + if (init_ok) return rmtd.oobblock; else return 0; +} + +EXPORT_SYMBOL(get_rbnand_block_size); + +int __init rbmips_init(void) { + memset(&rmtd, 0, sizeof(rmtd)); + memset(&rnand, 0, sizeof(rnand)); +/* + if (is_rb500()) { + if (is_rb400()) { + printk("RB400 nand\n"); + MEM32(IDT434_REG_BASE + GPIOD) |= GPIO_WPX; + MEM32(IDT434_REG_BASE + GPIOD) &= ~GPIO_CLE; + MEM32(IDT434_REG_BASE + GPIOD) &= ~GPIO_ALE; + rnand.hwcontrol = rbmips_hwcontrol400; + } else { +*/ + printk("RB500 nand\n"); + changeLatchU5(LO_WPX | LO_FOFF | LO_CEX, + LO_ULED | LO_ALE | LO_CLE); + rnand.hwcontrol = rbmips_hwcontrol500; +// } + + rnand.dev_ready = rb500_dev_ready; + rnand.IO_ADDR_W = (unsigned char *) + KSEG1ADDR(MEM32(IDT434_REG_BASE + DEV2BASE)); + rnand.IO_ADDR_R = rnand.IO_ADDR_W; +/* } else if (is_rb100()) { + printk("RB100 nand\n"); + MEM32(0xB2000064) = 0x100; + MEM32(0xB2000008) = 0x1; + SMEM1(NAND_SET_SPn) = 0x01; + SMEM1(NAND_CLR_WPn) = 0x01; + rnand.IO_ADDR_R = (unsigned char *)KSEG1ADDR(SMEM1_BASE); + rnand.IO_ADDR_W = rnand.IO_ADDR_R; + rnand.hwcontrol = rbmips_hwcontrol100; + rnand.dev_ready = rb100_dev_ready; + } +*/ + p_nand = (void __iomem *)ioremap(( void*)0x18a20000, 0x1000); + if (!p_nand) { + printk("RBnand Unable ioremap buffer"); + return -ENXIO; + } + rnand.eccmode = NAND_ECC_SOFT; + rnand.chip_delay = 25; + rnand.options |= NAND_NO_AUTOINCR; + rmtd.priv = &rnand; + + int *b = ( int *)KSEG1ADDR( 0x18010020); + printk( "dev2base 0x%08x mask 0x%08x c 0x%08x tc 0x%08x\n", b[ 0], b[ 1], b[ 2], b[ 3]); + + if (nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1) + && nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1)) { + printk("RBxxx nand device not found"); + iounmap ((void *)p_nand); + return -ENXIO; + } + + add_mtd_partitions(&rmtd, partition_info, 2); + init_ok = 1; + return 0; +} + +module_init(rbmips_init); + + + + +