diff --git a/target/linux/rb532/config-2.6.22 b/target/linux/rb532/config-2.6.22 index bc62b7787..d8d2de3e2 100644 --- a/target/linux/rb532/config-2.6.22 +++ b/target/linux/rb532/config-2.6.22 @@ -115,8 +115,8 @@ CONFIG_MTD_NAND=y CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_MUSEUM_IDS is not set # CONFIG_MTD_NAND_NANDSIM is not set -# CONFIG_MTD_NAND_PLATFORM is not set -CONFIG_MTD_NAND_RB500=y +CONFIG_MTD_NAND_PLATFORM=y +# CONFIG_MTD_NAND_RB500 is not set CONFIG_MTD_NAND_VERIFY_WRITE=y # CONFIG_MTD_ONENAND is not set CONFIG_MTD_PARTITIONS=y diff --git a/target/linux/rb532/files/arch/mips/rb500/devices.c b/target/linux/rb532/files/arch/mips/rb500/devices.c index be40106d8..d8342feb1 100644 --- a/target/linux/rb532/files/arch/mips/rb500/devices.c +++ b/target/linux/rb532/files/arch/mips/rb500/devices.c @@ -2,6 +2,7 @@ * RouterBoard 500 Platform devices * * Copyright (C) 2006 Felix Fietkau + * Copyright (C) 2007 Florian Fainelli * * 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 @@ -12,17 +13,15 @@ * 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. - * - * $Id$ */ #include #include -#include #include #include #include -#include -#include +#include +#include +#include #include #include @@ -31,61 +30,65 @@ #include #define ETH0_DMA_RX_IRQ GROUP1_IRQ_BASE + 0 -#define ETH0_DMA_TX_IRQ GROUP1_IRQ_BASE + 1 +#define ETH0_DMA_TX_IRQ GROUP1_IRQ_BASE + 1 #define ETH0_RX_OVR_IRQ GROUP3_IRQ_BASE + 9 #define ETH0_TX_UND_IRQ GROUP3_IRQ_BASE + 10 #define ETH0_RX_DMA_ADDR (DMA0_PhysicalAddress + 0*DMA_CHAN_OFFSET) #define ETH0_TX_DMA_ADDR (DMA0_PhysicalAddress + 1*DMA_CHAN_OFFSET) +/* NAND definitions */ +#define MEM32(x) *((volatile unsigned *) (x)) + +#define GPIO_RDY (1 << 0x08) +#define GPIO_WPX (1 << 0x09) +#define GPIO_ALE (1 << 0x0a) +#define GPIO_CLE (1 << 0x0b) + +extern char* board_type; + static struct resource korina_dev0_res[] = { { - .name = "korina_regs", + .name = "korina_regs", .start = ETH0_PhysicalAddress, - .end = ETH0_PhysicalAddress + sizeof(ETH_t), + .end = ETH0_PhysicalAddress + sizeof(ETH_t), .flags = IORESOURCE_MEM, - }, - { - .name = "korina_rx", + }, { + .name = "korina_rx", .start = ETH0_DMA_RX_IRQ, - .end = ETH0_DMA_RX_IRQ, + .end = ETH0_DMA_RX_IRQ, .flags = IORESOURCE_IRQ - }, - { - .name = "korina_tx", + }, { + .name = "korina_tx", .start = ETH0_DMA_TX_IRQ, - .end = ETH0_DMA_TX_IRQ, + .end = ETH0_DMA_TX_IRQ, .flags = IORESOURCE_IRQ - }, - { - .name = "korina_ovr", + }, { + .name = "korina_ovr", .start = ETH0_RX_OVR_IRQ, - .end = ETH0_RX_OVR_IRQ, + .end = ETH0_RX_OVR_IRQ, .flags = IORESOURCE_IRQ - }, - { - .name = "korina_und", + }, { + .name = "korina_und", .start = ETH0_TX_UND_IRQ, - .end = ETH0_TX_UND_IRQ, + .end = ETH0_TX_UND_IRQ, .flags = IORESOURCE_IRQ - }, - { - .name = "korina_dma_rx", + }, { + .name = "korina_dma_rx", .start = ETH0_RX_DMA_ADDR, - .end = ETH0_RX_DMA_ADDR + DMA_CHAN_OFFSET - 1, + .end = ETH0_RX_DMA_ADDR + DMA_CHAN_OFFSET - 1, .flags = IORESOURCE_MEM, - }, - { - .name = "korina_dma_tx", + }, { + .name = "korina_dma_tx", .start = ETH0_TX_DMA_ADDR, - .end = ETH0_TX_DMA_ADDR + DMA_CHAN_OFFSET - 1, + .end = ETH0_TX_DMA_ADDR + DMA_CHAN_OFFSET - 1, .flags = IORESOURCE_MEM, - } + } }; static struct korina_device korina_dev0_data = { .name = "korina0", - .mac = { 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee } + .mac = {0xde, 0xca, 0xff, 0xc0, 0xff, 0xee} }; static struct platform_device korina_dev0 = { @@ -96,18 +99,16 @@ static struct platform_device korina_dev0 = { .num_resources = ARRAY_SIZE(korina_dev0_res), }; - #define CF_GPIO_NUM 13 static struct resource cf_slot0_res[] = { { - .name = "cf_membase", + .name = "cf_membase", .flags = IORESOURCE_MEM - }, - { - .name = "cf_irq", - .start = (8 + 4 * 32 + CF_GPIO_NUM), /* 149 */ - .end = (8 + 4 * 32 + CF_GPIO_NUM), + }, { + .name = "cf_irq", + .start = (8 + 4 * 32 + CF_GPIO_NUM), /* 149 */ + .end = (8 + 4 * 32 + CF_GPIO_NUM), .flags = IORESOURCE_IRQ } }; @@ -125,55 +126,92 @@ static struct platform_device cf_slot0 = { }; /* Resources and device for NAND. There is no data needed and no irqs, so just define the memory used. */ +int rb500_dev_ready(struct mtd_info *mtd) +{ + return MEM32(IDT434_REG_BASE + GPIOD) & GPIO_RDY; +} + +void rb500_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + unsigned char orbits, nandbits; + + if (ctrl & NAND_CTRL_CHANGE) { + + orbits = (ctrl & NAND_CLE) << 1; + orbits |= (ctrl & NAND_ALE) >> 1; + + nandbits = (~ctrl & NAND_CLE) << 1; + nandbits |= (~ctrl & NAND_ALE) >> 1; + + changeLatchU5(orbits, nandbits); + } + if (cmd != NAND_CMD_NONE) + writeb(cmd, chip->IO_ADDR_W); +} + static struct resource nand_slot0_res[] = { { .name = "nand_membase", - .start = 0x18a20000, - .end = (0x18a20000+0x1000)-1, - .flags = IORESOURCE_MEM + .flags = IORESOURCE_MEM } }; - -static struct platform_device nand_slot0 = { - .id = 0, - .name = "rb500-nand", - .resource = nand_slot0_res, - .num_resources = ARRAY_SIZE(nand_slot0_res), + +struct platform_nand_data rb500_nand_data = { + .ctrl.dev_ready = rb500_dev_ready, + .ctrl.cmd_ctrl = rb500_cmd_ctrl, }; -static struct platform_device rb500led = { - .name = "rb500-led", +static struct platform_device nand_slot0 = { .id = 0, + .name = "gen_nand", + .resource = nand_slot0_res, + .num_resources = ARRAY_SIZE(nand_slot0_res), + .dev.platform_data = &rb500_nand_data, +}; + +static struct mtd_partition rb500_partition_info[] = { + { + .name = "Routerboard NAND boot", + .offset = 0, + .size = 4 * 1024 * 1024, + }, { + .name = "rootfs", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, + } }; static struct platform_device *rb500_devs[] = { &korina_dev0, &nand_slot0, - &cf_slot0, - &rb500led + &cf_slot0 }; -static void __init parse_mac_addr(char* macstr) +static void __init parse_mac_addr(char *macstr) { int i, j; unsigned char result, value; - - for (i=0; i<6; i++) { + + for (i = 0; i < 6; i++) { result = 0; - if (i != 5 && *(macstr+2) != ':') { + + if (i != 5 && *(macstr + 2) != ':') return; - } - for (j=0; j<2; j++) { - if (isxdigit(*macstr) && (value = isdigit(*macstr) ? *macstr-'0' : - toupper(*macstr)-'A'+10) < 16) { - result = result*16 + value; + + for (j = 0; j < 2; j++) { + if (isxdigit(*macstr) + && (value = + isdigit(*macstr) ? *macstr - + '0' : toupper(*macstr) - 'A' + 10) < 16) { + result = result * 16 + value; macstr++; - } - else return; + } else + return; } - - macstr++; + + macstr++; korina_dev0_data.mac[i] = result; } } @@ -187,6 +225,17 @@ static void __init parse_mac_addr(char* macstr) #define CFG_DC_DEVC 0x8 #define CFG_DC_DEVTC 0xC +/* NAND definitions */ +#define NAND_CHIP_DELAY 25 + +static void __init rb500_nand_setup(void) +{ + if (!strcmp(board_type, "500r5")) + changeLatchU5(LO_FOFF | LO_CEX, LO_ULED | LO_ALE | LO_CLE | LO_WPX); + else + changeLatchU5(LO_WPX | LO_FOFF | LO_CEX, LO_ULED | LO_ALE | LO_CLE); +} + static int __init plat_setup_devices(void) { @@ -194,25 +243,35 @@ static int __init plat_setup_devices(void) if (!readl(CFG_DC_DEV1 + CFG_DC_DEVMASK)) rb500_devs[1] = NULL; else { - cf_slot0_res[0].start = readl(CFG_DC_DEV1 + CFG_DC_DEVBASE); + cf_slot0_res[0].start = + readl(CFG_DC_DEV1 + CFG_DC_DEVBASE); cf_slot0_res[0].end = cf_slot0_res[0].start + 0x1000; } - - /* There is always a NAND device */ - nand_slot0_res[0].start = readl( CFG_DC_DEV2 + CFG_DC_DEVBASE); + + /* Initialise the NAND device */ + rb500_nand_setup(); + + /* Read the NAND resources from the device controller */ + nand_slot0_res[0].start = readl(CFG_DC_DEV2 + CFG_DC_DEVBASE); nand_slot0_res[0].end = nand_slot0_res[0].start + 0x1000; - + + /* Setup NAND specific settings */ + rb500_nand_data.chip.nr_chips = 1; + rb500_nand_data.chip.nr_partitions = ARRAY_SIZE(rb500_partition_info); + rb500_nand_data.chip.partitions = rb500_partition_info; + rb500_nand_data.chip.chip_delay = NAND_CHIP_DELAY; + rb500_nand_data.chip.options = NAND_NO_AUTOINCR; + return platform_add_devices(rb500_devs, ARRAY_SIZE(rb500_devs)); } static int __init setup_kmac(char *s) { - printk("korina mac = %s\n",s); + printk("korina mac = %s\n", s); parse_mac_addr(s); - return 0; + return 0; } __setup("kmac=", setup_kmac); + arch_initcall(plat_setup_devices); - -