|
|
|
@ -2,6 +2,7 @@ |
|
|
|
|
* RouterBoard 500 Platform devices |
|
|
|
|
* |
|
|
|
|
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> |
|
|
|
|
* Copyright (C) 2007 Florian Fainelli <florian@openwrt.org> |
|
|
|
|
* |
|
|
|
|
* 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 <linux/kernel.h> |
|
|
|
|
#include <linux/init.h> |
|
|
|
|
#include <linux/module.h> |
|
|
|
|
#include <linux/ctype.h> |
|
|
|
|
#include <linux/string.h> |
|
|
|
|
#include <linux/platform_device.h> |
|
|
|
|
#include <asm/unaligned.h> |
|
|
|
|
#include <asm/io.h> |
|
|
|
|
#include <linux/mtd/nand.h> |
|
|
|
|
#include <linux/mtd/mtd.h> |
|
|
|
|
#include <linux/mtd/partitions.h> |
|
|
|
|
|
|
|
|
|
#include <asm/rc32434/rc32434.h> |
|
|
|
|
#include <asm/rc32434/dma.h> |
|
|
|
@ -31,61 +30,65 @@ |
|
|
|
|
#include <asm/rc32434/rb.h> |
|
|
|
|
|
|
|
|
|
#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 |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct platform_nand_data rb500_nand_data = { |
|
|
|
|
.ctrl.dev_ready = rb500_dev_ready, |
|
|
|
|
.ctrl.cmd_ctrl = rb500_cmd_ctrl, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static struct platform_device nand_slot0 = { |
|
|
|
|
.id = 0, |
|
|
|
|
.name = "rb500-nand", |
|
|
|
|
.name = "gen_nand", |
|
|
|
|
.resource = nand_slot0_res, |
|
|
|
|
.num_resources = ARRAY_SIZE(nand_slot0_res), |
|
|
|
|
.dev.platform_data = &rb500_nand_data, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static struct platform_device rb500led = { |
|
|
|
|
.name = "rb500-led", |
|
|
|
|
.id = 0, |
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
arch_initcall(plat_setup_devices); |
|
|
|
|