diff options
Diffstat (limited to 'target/linux/rb532/files-2.6.23/arch/mips/rb500')
8 files changed, 1237 insertions, 0 deletions
diff --git a/target/linux/rb532/files-2.6.23/arch/mips/rb500/Makefile b/target/linux/rb532/files-2.6.23/arch/mips/rb500/Makefile new file mode 100644 index 0000000000..d3ae3d9122 --- /dev/null +++ b/target/linux/rb532/files-2.6.23/arch/mips/rb500/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the RB500 board specific parts of the kernel +# + +obj-y += irq.o time.o setup.o serial.o prom.o gpio.o devices.o diff --git a/target/linux/rb532/files-2.6.23/arch/mips/rb500/devices.c b/target/linux/rb532/files-2.6.23/arch/mips/rb500/devices.c new file mode 100644 index 0000000000..6372737de7 --- /dev/null +++ b/target/linux/rb532/files-2.6.23/arch/mips/rb500/devices.c @@ -0,0 +1,338 @@ +/* + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * 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. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/platform_device.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> + +#include <asm/bootinfo.h> + +#include <asm/rc32434/rc32434.h> +#include <asm/rc32434/dma.h> +#include <asm/rc32434/dma_v.h> +#include <asm/rc32434/eth.h> +#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_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", + .start = ETH0_PhysicalAddress, + .end = ETH0_PhysicalAddress + sizeof(ETH_t), + .flags = IORESOURCE_MEM, + }, { + .name = "korina_rx", + .start = ETH0_DMA_RX_IRQ, + .end = ETH0_DMA_RX_IRQ, + .flags = IORESOURCE_IRQ + }, { + .name = "korina_tx", + .start = ETH0_DMA_TX_IRQ, + .end = ETH0_DMA_TX_IRQ, + .flags = IORESOURCE_IRQ + }, { + .name = "korina_ovr", + .start = ETH0_RX_OVR_IRQ, + .end = ETH0_RX_OVR_IRQ, + .flags = IORESOURCE_IRQ + }, { + .name = "korina_und", + .start = ETH0_TX_UND_IRQ, + .end = ETH0_TX_UND_IRQ, + .flags = IORESOURCE_IRQ + }, { + .name = "korina_dma_rx", + .start = ETH0_RX_DMA_ADDR, + .end = ETH0_RX_DMA_ADDR + DMA_CHAN_OFFSET - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "korina_dma_tx", + .start = ETH0_TX_DMA_ADDR, + .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} +}; + +static struct platform_device korina_dev0 = { + .id = 0, + .name = "korina", + .dev.platform_data = &korina_dev0_data, + .resource = korina_dev0_res, + .num_resources = ARRAY_SIZE(korina_dev0_res), +}; + +#define CF_GPIO_NUM 13 + +static struct resource cf_slot0_res[] = { + { + .name = "cf_membase", + .flags = IORESOURCE_MEM + }, { + .name = "cf_irq", + .start = (8 + 4 * 32 + CF_GPIO_NUM), /* 149 */ + .end = (8 + 4 * 32 + CF_GPIO_NUM), + .flags = IORESOURCE_IRQ + } +}; + +static struct cf_device cf_slot0_data = { + .gpio_pin = 13 +}; + +static struct platform_device cf_slot0 = { + .id = 0, + .name = "rb500-cf", + .dev.platform_data = &cf_slot0_data, + .resource = cf_slot0_res, + .num_resources = ARRAY_SIZE(cf_slot0_res), +}; + +/* Resources and device for NAND. There is no data needed and no irqs, so just define the memory used. */ + +/* + * We need to use the OLD Yaffs-1 OOB layout, otherwise the RB bootloader + * will not be able to find the kernel that we load. So set the oobinfo + * when creating the partitions + */ +static struct nand_ecclayout rb500_nand_ecclayout = { + .eccbytes = 6, + .eccpos = { 8, 9, 10, 13, 14, 15 }, + .oobavail = 9, + .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } } +}; + +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[] = { + [0] = { + .name = "nand_membase", + .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 = { + .name = "gen_nand", + .id = -1, + .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_led = { + .name = "rb500-led", + .id = 0, +}; + +static struct gpio_keys_button rb500_gpio_btn[] = { + { + .gpio = 1, + .code = BTN_0, + .desc = "S1", + .active_low = 1, + } +}; + +static struct gpio_keys_platform_data rb500_gpio_btn_data = { + .buttons = rb500_gpio_btn, + .nbuttons = ARRAY_SIZE(rb500_gpio_btn), +}; + +static struct platform_device rb500_button = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &rb500_gpio_btn_data, + } +}; + +static struct platform_device *rb500_devs[] = { + &korina_dev0, + &nand_slot0, + &cf_slot0, + &rb500_led, + &rb500_button +}; + +static void __init parse_mac_addr(char *macstr) +{ + int i, j; + unsigned char result, value; + + for (i = 0; i < 6; i++) { + result = 0; + + 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; + macstr++; + } else + return; + } + + macstr++; + korina_dev0_data.mac[i] = result; + } +} + + +/* DEVICE CONTROLLER 1 */ +#define CFG_DC_DEV1 (void*)0xb8010010 +#define CFG_DC_DEV2 (void*)0xb8010020 +#define CFG_DC_DEVBASE 0x0 +#define CFG_DC_DEVMASK 0x4 +#define CFG_DC_DEVC 0x8 +#define CFG_DC_DEVTC 0xC + +/* NAND definitions */ +#define NAND_CHIP_DELAY 25 + +static int rb500_nand_fixup(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + + if (mtd->writesize == 512) + chip->ecc.layout = &rb500_nand_ecclayout; + + return 0; +} + +static void __init rb500_nand_setup(void) +{ + switch (mips_machtype) { + case MACH_MIKROTIK_RB532A: + changeLatchU5(LO_FOFF | LO_CEX, LO_ULED | LO_ALE | LO_CLE | LO_WPX); + break; + default: + changeLatchU5(LO_WPX | LO_FOFF | LO_CEX, LO_ULED | LO_ALE | LO_CLE); + break; + } + + /* 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; + + rb500_nand_data.chip.chip_fixup = &rb500_nand_fixup; +} + + +static int __init plat_setup_devices(void) +{ + /* Look for the CF card reader */ + 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].end = cf_slot0_res[0].start + 0x1000; + } + + /* 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; + + /* Initialise the NAND device */ + rb500_nand_setup(); + + return platform_add_devices(rb500_devs, ARRAY_SIZE(rb500_devs)); +} + +static int __init setup_kmac(char *s) +{ + printk("korina mac = %s\n", s); + parse_mac_addr(s); + return 0; +} + +__setup("kmac=", setup_kmac); + +arch_initcall(plat_setup_devices); diff --git a/target/linux/rb532/files-2.6.23/arch/mips/rb500/gpio.c b/target/linux/rb532/files-2.6.23/arch/mips/rb500/gpio.c new file mode 100644 index 0000000000..6c92a8fe56 --- /dev/null +++ b/target/linux/rb532/files-2.6.23/arch/mips/rb500/gpio.c @@ -0,0 +1,198 @@ +/* + * Miscellaneous functions for IDT EB434 board + * + * Copyright 2004 IDT Inc. (rischelp@idt.com) + * Copyright 2006 Phil Sutter <n0-1@freewrt.org> + * Copyright 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 the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/platform_device.h> + +#include <asm/addrspace.h> +#include <asm/gpio.h> + +#include <asm/rc32434/rb.h> + +#define GPIO_BADDR 0x18050000 + +static volatile unsigned char *devCtl3Base; +static unsigned char latchU5State; +static spinlock_t clu5Lock = SPIN_LOCK_UNLOCKED; + +struct rb500_gpio_reg __iomem *rb500_gpio_reg0; +EXPORT_SYMBOL(rb500_gpio_reg0); + +static struct resource rb500_gpio_reg0_res[] = { + { + .name = "gpio_reg0", + .start = GPIO_BADDR, + .end = GPIO_BADDR + sizeof(struct rb500_gpio_reg), + .flags = IORESOURCE_MEM, + } +}; + +void set434Reg(unsigned regOffs, unsigned bit, unsigned len, unsigned val) +{ + unsigned flags, data; + unsigned i = 0; + + spin_lock_irqsave(&clu5Lock, flags); + data = *(volatile unsigned *) (IDT434_REG_BASE + regOffs); + for (i = 0; i != len; ++i) { + if (val & (1 << i)) + data |= (1 << (i + bit)); + else + data &= ~(1 << (i + bit)); + } + *(volatile unsigned *) (IDT434_REG_BASE + regOffs) = data; + spin_unlock_irqrestore(&clu5Lock, flags); +} +EXPORT_SYMBOL(set434Reg); + +void changeLatchU5(unsigned char orMask, unsigned char nandMask) +{ + unsigned flags; + + spin_lock_irqsave(&clu5Lock, flags); + latchU5State = (latchU5State | orMask) & ~nandMask; + if (!devCtl3Base) + devCtl3Base = (volatile unsigned char *) + KSEG1ADDR(*(volatile unsigned *) + KSEG1ADDR(0x18010030)); + *devCtl3Base = latchU5State; + spin_unlock_irqrestore(&clu5Lock, flags); +} +EXPORT_SYMBOL(changeLatchU5); + +unsigned char getLatchU5State(void) +{ + return latchU5State; +} +EXPORT_SYMBOL(getLatchU5State); + +int rb500_gpio_get_value(unsigned gpio) +{ + return readl(&rb500_gpio_reg0->gpiod) & (1 << gpio); +} +EXPORT_SYMBOL(rb500_gpio_get_value); + +void rb500_gpio_set_value(unsigned gpio, int value) +{ + unsigned tmp; + + tmp = readl(&rb500_gpio_reg0->gpiod) & ~(1 << gpio); + if (value) + tmp |= 1 << gpio; + + writel(tmp, (void *)&rb500_gpio_reg0->gpiod); +} +EXPORT_SYMBOL(rb500_gpio_set_value); + +int rb500_gpio_direction_input(unsigned gpio) +{ + writel(readl(&rb500_gpio_reg0->gpiocfg) & ~(1 << gpio), (void *)&rb500_gpio_reg0->gpiocfg); + + return 0; +} +EXPORT_SYMBOL(rb500_gpio_direction_input); + +int rb500_gpio_direction_output(unsigned gpio, int value) +{ + gpio_set_value(gpio, value); + writel(readl(&rb500_gpio_reg0->gpiocfg) | (1 << gpio), (void *)&rb500_gpio_reg0->gpiocfg); + + return 0; +} +EXPORT_SYMBOL(rb500_gpio_direction_output); + +void rb500_gpio_set_int_level(unsigned gpio, int value) +{ + unsigned tmp; + + tmp = readl(&rb500_gpio_reg0->gpioilevel) & ~(1 << gpio); + if (value) + tmp |= 1 << gpio; + writel(tmp, (void *)&rb500_gpio_reg0->gpioilevel); +} +EXPORT_SYMBOL(rb500_gpio_set_int_level); + +int rb500_gpio_get_int_level(unsigned gpio) +{ + return readl(&rb500_gpio_reg0->gpioilevel) & (1 << gpio); +} +EXPORT_SYMBOL(rb500_gpio_get_int_level); + +void rb500_gpio_set_int_status(unsigned gpio, int value) +{ + unsigned tmp; + + tmp = readl(&rb500_gpio_reg0->gpioistat); + if (value) + tmp |= 1 << gpio; + writel(tmp, (void *)&rb500_gpio_reg0->gpioistat); +} +EXPORT_SYMBOL(rb500_gpio_set_int_status); + +int rb500_gpio_get_int_status(unsigned gpio) +{ + return readl(&rb500_gpio_reg0->gpioistat) & (1 << gpio); +} +EXPORT_SYMBOL(rb500_gpio_get_int_status); + +void rb500_gpio_set_func(unsigned gpio, int value) +{ + unsigned tmp; + + tmp = readl(&rb500_gpio_reg0->gpiofunc); + if (value) + tmp |= 1 << gpio; + writel(tmp, (void *)&rb500_gpio_reg0->gpiofunc); +} +EXPORT_SYMBOL(rb500_gpio_set_func); + +int rb500_gpio_get_func(unsigned gpio) +{ + return readl(&rb500_gpio_reg0->gpiofunc) & (1 << gpio); +} +EXPORT_SYMBOL(rb500_gpio_get_func); + +int __init rb500_gpio_init(void) +{ + rb500_gpio_reg0 = ioremap_nocache(rb500_gpio_reg0_res[0].start, + rb500_gpio_reg0_res[0].end - + rb500_gpio_reg0_res[0].start); + + if (!rb500_gpio_reg0) { + printk(KERN_ERR "rb500: cannot remap GPIO register 0\n"); + return -ENXIO; + } + + return 0; +} +arch_initcall(rb500_gpio_init); diff --git a/target/linux/rb532/files-2.6.23/arch/mips/rb500/irq.c b/target/linux/rb532/files-2.6.23/arch/mips/rb500/irq.c new file mode 100644 index 0000000000..5a4d349d49 --- /dev/null +++ b/target/linux/rb532/files-2.6.23/arch/mips/rb500/irq.c @@ -0,0 +1,265 @@ +/* + * BRIEF MODULE DESCRIPTION + * RC32434 interrupt routines. + * + * Copyright 2002 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or source@mvista.com + * + * 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 the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/module.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timex.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/delay.h> + +#include <asm/bitops.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/time.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/rc32434/rc32434.h> +#include <asm/rc32434/gpio.h> + +extern void set_debug_traps(void); +extern irq_cpustat_t irq_stat [NR_CPUS]; +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; + +static unsigned int startup_irq(unsigned int irq); +static void rb500_end_irq(unsigned int irq_nr); +static void mask_and_ack_irq(unsigned int irq_nr); +static void rb500_enable_irq(unsigned int irq_nr); +static void rb500_disable_irq(unsigned int irq_nr); + +extern void __init init_generic_irq(void); +extern struct rb500_gpio_reg __iomem *rb500_gpio_reg0; + +typedef struct { + u32 mask; /* mask of valid bits in pending/mask registers */ + volatile u32 *base_addr; +} intr_group_t; + +#define RC32434_NR_IRQS (GROUP4_IRQ_BASE + 32) + +#if (NR_IRQS < RC32434_NR_IRQS) +#error Too little irqs defined. Did you override <asm/irq.h> ? +#endif + +static const intr_group_t intr_group[NUM_INTR_GROUPS] = { + { 0x0000efff, (u32 *)KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET) }, + { 0x00001fff, (u32 *)KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET) }, + { 0x00000007, (u32 *)KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET) }, + { 0x0003ffff, (u32 *)KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET) }, + { 0xffffffff, (u32 *)KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET) } +}; + +#define READ_PEND(base) (*(base)) +#define READ_MASK(base) (*(base + 2)) +#define WRITE_MASK(base, val) (*(base + 2) = (val)) + +static inline int irq_to_group(unsigned int irq_nr) +{ + return ((irq_nr - GROUP0_IRQ_BASE) >> 5); +} + +static inline int group_to_ip(unsigned int group) +{ + return group + 2; +} + +static inline void enable_local_irq(unsigned int ip) +{ + int ipnum = 0x100 << ip; + clear_c0_cause(ipnum); + set_c0_status(ipnum); +} + +static inline void disable_local_irq(unsigned int ip) +{ + int ipnum = 0x100 << ip; + clear_c0_status(ipnum); +} + +static inline void ack_local_irq(unsigned int ip) +{ + int ipnum = 0x100 << ip; + clear_c0_cause(ipnum); +} + +static void rb500_enable_irq(unsigned int irq_nr) +{ + int ip = irq_nr - GROUP0_IRQ_BASE; + unsigned int group, intr_bit; + volatile unsigned int *addr; + + + if (ip < 0) + enable_local_irq(irq_nr); + else { + group = ip >> 5; + + ip &= (1<<5)-1; + intr_bit = 1 << ip; + + enable_local_irq(group_to_ip(group)); + + addr = intr_group[group].base_addr; + WRITE_MASK(addr, READ_MASK(addr) & ~intr_bit); + } +} + +static void rb500_disable_irq(unsigned int irq_nr) +{ + int ip = irq_nr - GROUP0_IRQ_BASE; + unsigned int group, intr_bit, mask; + volatile unsigned int *addr; + + if (ip < 0) { + disable_local_irq(irq_nr); + }else{ + group = ip >> 5; + + ip &= (1<<5) -1; + intr_bit = 1 << ip; + addr = intr_group[group].base_addr; + mask = READ_MASK(addr); + mask |= intr_bit; + WRITE_MASK(addr,mask); + + /* + * if there are no more interrupts enabled in this + * group, disable corresponding IP + */ + if (mask == intr_group[group].mask) + disable_local_irq(group_to_ip(group)); + } +} + +static unsigned int startup_irq(unsigned int irq_nr) +{ + rb500_enable_irq(irq_nr); + return 0; +} + +static void shutdown_irq(unsigned int irq_nr) +{ + rb500_disable_irq(irq_nr); + return; +} + +static void mask_and_ack_irq(unsigned int irq_nr) +{ + rb500_disable_irq(irq_nr); + ack_local_irq(group_to_ip(irq_to_group(irq_nr))); +} + +static void rb500_end_irq(unsigned int irq_nr) +{ + + int ip = irq_nr - GROUP0_IRQ_BASE; + unsigned int intr_bit, group; + volatile unsigned int *addr; + + if ((irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + printk("warning: end_irq %d did not enable (%x)\n", + irq_nr, irq_desc[irq_nr].status); + return; + } + + if (ip < 0) { + enable_local_irq(irq_nr); + } else { + group = ip >> 5; + + ip &= (1 << 5) - 1; + intr_bit = 1 << ip; + + if (irq_nr >= GROUP4_IRQ_BASE && irq_nr <= (GROUP4_IRQ_BASE + 13)) { + rb500_gpio_reg0->gpioistat = rb500_gpio_reg0->gpioistat & ~intr_bit; + } + + enable_local_irq(group_to_ip(group)); + + addr = intr_group[group].base_addr; + WRITE_MASK(addr, READ_MASK(addr) & ~intr_bit); + } +} + +static struct hw_interrupt_type rc32434_irq_type = { + .typename = "RB500", + .startup = startup_irq, + .shutdown = shutdown_irq, + .enable = rb500_enable_irq, + .disable = rb500_disable_irq, + .ack = mask_and_ack_irq, + .end = rb500_end_irq, +}; + + +void __init arch_init_irq(void) +{ + int i; + + printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS); + memset(irq_desc, 0, sizeof(irq_desc)); + + for (i = 0; i < RC32434_NR_IRQS; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].chip = &rc32434_irq_type; + spin_lock_init(&irq_desc[i].lock); + } +} + +/* Main Interrupt dispatcher */ +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int ip, pend, group; + volatile unsigned int *addr; + unsigned int cp0_cause = read_c0_cause() & read_c0_status(); + + if (cp0_cause & CAUSEF_IP7) { + ll_timer_interrupt(7); + } else if ((ip = (cp0_cause & 0x7c00))) { + group = 21 - rc32434_clz(ip); + + addr = intr_group[group].base_addr; + + pend = READ_PEND(addr); + pend &= ~READ_MASK(addr); // only unmasked interrupts + pend = 39 - rc32434_clz(pend); + do_IRQ((group << 5) + pend); + } +} diff --git a/target/linux/rb532/files-2.6.23/arch/mips/rb500/prom.c b/target/linux/rb532/files-2.6.23/arch/mips/rb500/prom.c new file mode 100644 index 0000000000..b10172fb51 --- /dev/null +++ b/target/linux/rb532/files-2.6.23/arch/mips/rb500/prom.c @@ -0,0 +1,178 @@ +/* +* prom.c +********************************************************************** +* P . Sadik Oct 10, 2003 +* +* Started change log +* idt_cpu_freq is make a kernel configuration parameter +* idt_cpu_freq is exported so that other modules can use it. +* Code cleanup +********************************************************************** +* P. Sadik Oct 20, 2003 +* +* Removed NVRAM code from here, since they are already available under +* nvram directory. +* Added serial port initialisation. +********************************************************************** +********************************************************************** +* P. Sadik Oct 30, 2003 +* +* Added reset_cons_port +********************************************************************** + + P.Christeas, 2005-2006 + Port to 2.6, add 2.6 cmdline parsing + +*/ + +#include <linux/autoconf.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/console.h> +#include <asm/bootinfo.h> +#include <linux/bootmem.h> +#include <linux/ioport.h> +#include <linux/blkdev.h> +#include <asm/rc32434/ddr.h> + +#define PROM_ENTRY(x) (0xbfc00000+((x)*8)) +extern void __init setup_serial_port(void); + +unsigned int idt_cpu_freq = 132000000; +EXPORT_SYMBOL(idt_cpu_freq); +unsigned int gpio_bootup_state = 0; +EXPORT_SYMBOL(gpio_bootup_state); + +char mips_mac_address[18] = "08:00:06:05:40:01"; +EXPORT_SYMBOL(mips_mac_address); + +/* what to append to cmdline when button is [not] pressed */ +#define GPIO_INIT_NOBUTTON "" +#define GPIO_INIT_BUTTON " 2" + +#ifdef CONFIG_MIKROTIK_RB500 +unsigned soft_reboot = 0; +EXPORT_SYMBOL(soft_reboot); +#endif + +#define SR_NMI 0x00180000 /* NMI */ +#define SERIAL_SPEED_ENTRY 0x00000001 + +#ifdef CONFIG_REMOTE_DEBUG +extern int remote_debug; +#endif + +#define FREQ_TAG "HZ=" +#define GPIO_TAG "gpio=" +#define KMAC_TAG "kmac=" +#define MEM_TAG "mem=" +#define BOARD_TAG "board=" +#define IGNORE_CMDLINE_MEM 1 +#define DEBUG_DDR + +#define BOARD_RB532 "500" +#define BOARD_RB532A "500r5" + +void parse_soft_settings(unsigned *ptr, unsigned size); +void parse_hard_settings(unsigned *ptr, unsigned size); + +void __init prom_setup_cmdline(void); + +void __init prom_init(void) +{ + DDR_t ddr = (DDR_t) DDR_VirtualAddress; /* define the pointer to the DDR registers */ + phys_t memsize = 0-ddr->ddrmask; + + /* this should be the very first message, even before serial is properly initialized */ + prom_setup_cmdline(); + setup_serial_port(); + + mips_machgroup = MACH_GROUP_MIKROTIK; + soft_reboot = read_c0_status() & SR_NMI; + pm_power_off = NULL; + + /* + * give all RAM to boot allocator, + * except for the first 0x400 and the last 0x200 bytes + */ + add_memory_region(ddr->ddrbase + 0x400, memsize - 0x600, BOOT_MEM_RAM); +} + +void __init prom_free_prom_memory(void) +{ + /* No prom memory to free */ +} + +static inline int match_tag(char *arg, const char *tag) +{ + return (strncmp(arg, tag, strlen(tag)) == 0); +} + +static inline unsigned long tag2ul(char *arg, const char *tag) +{ + char *num = arg+strlen(tag); + return simple_strtoul(num, 0, 10); +} + +extern char _image_cmdline; +void __init prom_setup_cmdline(void){ + char cmd_line[CL_SIZE]; + char *cp; + int prom_argc; + char **prom_argv, **prom_envp; + int i; + + prom_argc = fw_arg0; + prom_argv = (char **) fw_arg1; + prom_envp = (char **) fw_arg2; + + cp=cmd_line; + /* Note: it is common that parameters start at argv[1] and not argv[0], + however, our elf loader starts at [0] */ + for(i=0;i<prom_argc;i++){ + if (match_tag(prom_argv[i], FREQ_TAG)) { + idt_cpu_freq = tag2ul(prom_argv[i], FREQ_TAG); + continue; + } +#ifdef IGNORE_CMDLINE_MEM + /* parses out the "mem=xx" arg */ + if (match_tag(prom_argv[i], MEM_TAG)) { + continue; + } +#endif + if (i>0) *(cp++) = ' '; + if (match_tag(prom_argv[i], BOARD_TAG)) { + char *board = prom_argv[i] + strlen(BOARD_TAG); + if (match_tag(board, BOARD_RB532A)) + mips_machtype = MACH_MIKROTIK_RB532A; + else + mips_machtype = MACH_MIKROTIK_RB532; + } + + if (match_tag(prom_argv[i], GPIO_TAG)) { + gpio_bootup_state = tag2ul(prom_argv[i], GPIO_TAG); + } + strcpy(cp,prom_argv[i]); + cp+=strlen(prom_argv[i]); + } + *(cp++) = ' '; + strcpy(cp,(&_image_cmdline + 8)); + cp += strlen(&_image_cmdline); + + i=strlen(arcs_cmdline); + if (i>0){ + *(cp++) = ' '; + strcpy(cp,arcs_cmdline); + cp+=strlen(arcs_cmdline); + } + if (gpio_bootup_state&0x02) + strcpy(cp,GPIO_INIT_NOBUTTON); + else + strcpy(cp,GPIO_INIT_BUTTON); + cmd_line[CL_SIZE-1] = '\0'; + + strcpy(arcs_cmdline,cmd_line); +} + diff --git a/target/linux/rb532/files-2.6.23/arch/mips/rb500/serial.c b/target/linux/rb532/files-2.6.23/arch/mips/rb500/serial.c new file mode 100644 index 0000000000..25a03e0108 --- /dev/null +++ b/target/linux/rb532/files-2.6.23/arch/mips/rb500/serial.c @@ -0,0 +1,78 @@ +/************************************************************************** + * + * BRIEF MODULE DESCRIPTION + * Serial port initialisation. + * + * Copyright 2004 IDT Inc. (rischelp@idt.com) + * + * 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 the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + ************************************************************************** + * May 2004 rkt, neb + * + * Initial Release + * + * + * + ************************************************************************** + */ + + +#include <linux/autoconf.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/serial_8250.h> + +#include <asm/time.h> +#include <asm/cpu.h> +#include <asm/bootinfo.h> +#include <asm/irq.h> +#include <asm/serial.h> +#include <asm/rc32434/rc32434.h> + +extern unsigned int idt_cpu_freq; + +static struct uart_port serial_req = { + .type = PORT_16550A, + .line = 0, + .irq = RC32434_UART0_IRQ, + //.flags = STD_COM_FLAGS, + .iotype = UPIO_MEM, + .membase = (char *) KSEG1ADDR(RC32434_UART0_BASE), +// .fifosize = 14 + .regshift = 2 +}; + +int __init setup_serial_port(void) +{ + serial_req.uartclk = idt_cpu_freq; + + if (early_serial_setup(&serial_req)) + return -ENODEV; + + return(0); +} diff --git a/target/linux/rb532/files-2.6.23/arch/mips/rb500/setup.c b/target/linux/rb532/files-2.6.23/arch/mips/rb500/setup.c new file mode 100644 index 0000000000..2fda0e2ab1 --- /dev/null +++ b/target/linux/rb532/files-2.6.23/arch/mips/rb500/setup.c @@ -0,0 +1,81 @@ +/* + * setup.c - boot time setup code + */ + +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/irq.h> +#include <linux/ioport.h> +#include <linux/pm.h> +#include <asm/bootinfo.h> +#include <asm/mipsregs.h> +#include <asm/pgtable.h> +#include <asm/reboot.h> +#include <asm/addrspace.h> /* for KSEG1ADDR() */ +#include <asm/time.h> +#include <asm/io.h> +#include <asm/rc32434/rc32434.h> +#include <asm/rc32434/pci.h> + +#ifdef CONFIG_PCI +extern void rc32434_time_init(void); +extern int __init rc32434_pcibridge_init(void); +#endif + +#define epldMask ((volatile unsigned char *)0xB900000d) + +static void rb_machine_restart(char *command) +{ + /* just jump to the reset vector */ + * (volatile unsigned *) KSEG1ADDR(0x18008000) = 0x80000001; + ((void (*)(void))KSEG1ADDR(0x1FC00000u))(); +} + +static void rb_machine_halt(void) +{ + for(;;) continue; +} + +#ifdef CONFIG_CPU_HAS_WB +void (*__wbflush) (void); + +static void rb_write_buffer_flush(void) +{ + __asm__ __volatile__ + ("sync\n\t" "nop\n\t" "loop: bc0f loop\n\t" "nop\n\t"); +} +#endif + +void __init plat_mem_setup(void) +{ + unsigned int pciCntlVal; + + board_time_init = rc32434_time_init; + +#ifdef CONFIG_CPU_HAS_WB + __wbflush = rb_write_buffer_flush; +#endif + _machine_restart = rb_machine_restart; + _machine_halt = rb_machine_halt; + /*_machine_power_off = rb_machine_power_halt;*/ + pm_power_off = rb_machine_halt; + + set_io_port_base(KSEG1); + + pciCntlVal=rc32434_pci->pcic; + pciCntlVal &= 0xFFFFFF7; + rc32434_pci->pcic = pciCntlVal; + +#ifdef CONFIG_PCI + /* Enable PCI interrupts in EPLD Mask register */ + *epldMask = 0x0; + *(epldMask + 1) = 0x0; +#endif + write_c0_wired(0); +} + +const char *get_system_type(void) +{ + return "MIPS RB500"; +} diff --git a/target/linux/rb532/files-2.6.23/arch/mips/rb500/time.c b/target/linux/rb532/files-2.6.23/arch/mips/rb500/time.c new file mode 100644 index 0000000000..13320a6caf --- /dev/null +++ b/target/linux/rb532/files-2.6.23/arch/mips/rb500/time.c @@ -0,0 +1,94 @@ +/* +**************************************************************************** +* Carsten Langgaard, carstenl@mips.com +* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. +* +*************************************************************************** +* +* This program is free software; you can distribute it and/or modify it +* under the terms of the GNU General Public License (Version 2) as +* published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, 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. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +* +**************************************************************************** +* +* Setting up the clock on the MIPS boards. +* +**************************************************************************** +* P. Sadik Oct 10, 2003 +* +* Started change log. +* mips_counter_frequency is now calculated at run time, based on idt_cpu_freq. +* Code cleanup +**************************************************************************** +*/ + +#include <linux/autoconf.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/mc146818rtc.h> +#include <linux/irq.h> +#include <linux/timex.h> + +#include <asm/irq_cpu.h> +#include <asm/mipsregs.h> +#include <asm/ptrace.h> +#include <asm/debug.h> +#include <asm/rc32434/rc32434.h> + +static unsigned long r4k_offset; /* Amount to incr compare reg each time */ +static unsigned long r4k_cur; /* What counter should be at next timer irq */ +extern unsigned int mips_hpt_frequency; +extern unsigned int idt_cpu_freq; + +/* + * Figure out the r4k offset, the amount to increment the compare + * register for each time tick. There is no RTC available. + * + * The RC32434 counts at half the CPU *core* speed. + */ +static unsigned long __init cal_r4koff(void) +{ + mips_hpt_frequency = idt_cpu_freq * IDT_CLOCK_MULT / 2; + return (mips_hpt_frequency / HZ); +} + + +void __init rc32434_time_init(void) +{ + unsigned int est_freq, flags; + + local_irq_save(flags); + + printk("calculating r4koff... "); + r4k_offset = cal_r4koff(); + printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset); + + est_freq = 2*r4k_offset*HZ; + est_freq += 5000; /* round */ + est_freq -= est_freq%10000; + printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, + (est_freq%1000000)*100/1000000); + local_irq_restore(flags); +} + +void __init plat_timer_setup(struct irqaction *irq) +{ + /* we are using the cpu counter for timer interrupts */ + setup_irq(MIPS_CPU_TIMER_IRQ, irq); + + /* to generate the first timer interrupt */ + r4k_cur = (read_c0_count() + r4k_offset); + write_c0_compare(r4k_cur); +} + |