[MIPS] Routerboard 532: Support for base system

Signed-off-by: Phil Sutter <n0-1@freewrt.org>
Signed-off-by: Florian Fainelli <florian.fainelli@telecomint.eu>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Ralf Baechle
2008-07-16 16:12:25 +01:00
parent 36a0a3cd45
commit 73b4390fb2
30 changed files with 4515 additions and 1 deletions

7
arch/mips/rb532/Makefile Normal file
View File

@@ -0,0 +1,7 @@
#
# Makefile for the RB532 board specific parts of the kernel
#
obj-y += irq.o time.o setup.o serial.o prom.o gpio.o devices.o
EXTRA_CFLAGS += -Werror

331
arch/mips/rb532/devices.c Normal file
View File

@@ -0,0 +1,331 @@
/*
* 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/mach-rc32434/rc32434.h>
#include <asm/mach-rc32434/dma.h>
#include <asm/mach-rc32434/dma_v.h>
#include <asm/mach-rc32434/eth.h>
#include <asm/mach-rc32434/rb.h>
#include <asm/mach-rc32434/integ.h>
#include <asm/mach-rc32434/gpio.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_BASE_ADDR + 0 * DMA_CHAN_OFFSET)
#define ETH0_TX_DMA_ADDR (DMA0_BASE_ADDR + 1 * DMA_CHAN_OFFSET)
/* NAND definitions */
#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_BASE_ADDR,
.end = ETH0_BASE_ADDR + sizeof(struct eth_regs),
.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 = "pata-rb532-cf",
.dev.platform_data = &cf_slot0_data,
.resource = cf_slot0_res,
.num_resources = ARRAY_SIZE(cf_slot0_res),
};
/* Resources and device for NAND */
static int rb532_dev_ready(struct mtd_info *mtd)
{
return readl(IDT434_REG_BASE + GPIOD) & GPIO_RDY;
}
static void rb532_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;
set_latch_u5(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
}
};
static struct platform_nand_data rb532_nand_data = {
.ctrl.dev_ready = rb532_dev_ready,
.ctrl.cmd_ctrl = rb532_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 = &rb532_nand_data,
};
static struct mtd_partition rb532_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 rb532_led = {
.name = "rb532-led",
.id = 0,
};
static struct gpio_keys_button rb532_gpio_btn[] = {
{
.gpio = 1,
.code = BTN_0,
.desc = "S1",
.active_low = 1,
}
};
static struct gpio_keys_platform_data rb532_gpio_btn_data = {
.buttons = rb532_gpio_btn,
.nbuttons = ARRAY_SIZE(rb532_gpio_btn),
};
static struct platform_device rb532_button = {
.name = "gpio-keys",
.id = -1,
.dev = {
.platform_data = &rb532_gpio_btn_data,
}
};
static struct resource rb532_wdt_res[] = {
{
.name = "rb532_wdt_res",
.start = INTEG0_BASE_ADDR,
.end = INTEG0_BASE_ADDR + sizeof(struct integ),
.flags = IORESOURCE_MEM,
}
};
static struct platform_device rb532_wdt = {
.name = "rc32434_wdt",
.id = -1,
.resource = rb532_wdt_res,
.num_resources = ARRAY_SIZE(rb532_wdt_res),
};
static struct platform_device *rb532_devs[] = {
&korina_dev0,
&nand_slot0,
&cf_slot0,
&rb532_led,
&rb532_button,
&rb532_wdt
};
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 void __init rb532_nand_setup(void)
{
switch (mips_machtype) {
case MACH_MIKROTIK_RB532A:
set_latch_u5(LO_FOFF | LO_CEX,
LO_ULED | LO_ALE | LO_CLE | LO_WPX);
break;
default:
set_latch_u5(LO_WPX | LO_FOFF | LO_CEX,
LO_ULED | LO_ALE | LO_CLE);
break;
}
/* Setup NAND specific settings */
rb532_nand_data.chip.nr_chips = 1;
rb532_nand_data.chip.nr_partitions = ARRAY_SIZE(rb532_partition_info);
rb532_nand_data.chip.partitions = rb532_partition_info;
rb532_nand_data.chip.chip_delay = NAND_CHIP_DELAY;
rb532_nand_data.chip.options = NAND_NO_AUTOINCR;
}
static int __init plat_setup_devices(void)
{
/* Look for the CF card reader */
if (!readl(CFG_DC_DEV1 + CFG_DC_DEVMASK))
rb532_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 */
rb532_nand_setup();
return platform_add_devices(rb532_devs, ARRAY_SIZE(rb532_devs));
}
static int __init setup_kmac(char *s)
{
printk(KERN_INFO "korina mac = %s\n", s);
parse_mac_addr(s);
return 0;
}
__setup("kmac=", setup_kmac);
arch_initcall(plat_setup_devices);

220
arch/mips/rb532/gpio.c Normal file
View File

@@ -0,0 +1,220 @@
/*
* 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/gpio.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/mach-rc32434/rb.h>
struct rb532_gpio_reg __iomem *rb532_gpio_reg0;
EXPORT_SYMBOL(rb532_gpio_reg0);
struct mpmc_device dev3;
static struct resource rb532_gpio_reg0_res[] = {
{
.name = "gpio_reg0",
.start = (u32)(IDT434_REG_BASE + GPIOBASE),
.end = (u32)(IDT434_REG_BASE + GPIOBASE + sizeof(struct rb532_gpio_reg)),
.flags = IORESOURCE_MEM,
}
};
static struct resource rb532_dev3_ctl_res[] = {
{
.name = "dev3_ctl",
.start = (u32)(IDT434_REG_BASE + DEV3BASE),
.end = (u32)(IDT434_REG_BASE + DEV3BASE + sizeof(struct dev_reg)),
.flags = IORESOURCE_MEM,
}
};
void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned val)
{
unsigned flags, data;
unsigned i = 0;
spin_lock_irqsave(&dev3.lock, flags);
data = *(volatile unsigned *) (IDT434_REG_BASE + reg_offs);
for (i = 0; i != len; ++i) {
if (val & (1 << i))
data |= (1 << (i + bit));
else
data &= ~(1 << (i + bit));
}
writel(data, (IDT434_REG_BASE + reg_offs));
spin_unlock_irqrestore(&dev3.lock, flags);
}
EXPORT_SYMBOL(set_434_reg);
unsigned get_434_reg(unsigned reg_offs)
{
return readl(IDT434_REG_BASE + reg_offs);
}
EXPORT_SYMBOL(get_434_reg);
void set_latch_u5(unsigned char or_mask, unsigned char nand_mask)
{
unsigned flags;
spin_lock_irqsave(&dev3.lock, flags);
dev3.state = (dev3.state | or_mask) & ~nand_mask;
writel(dev3.state, &dev3.base);
spin_unlock_irqrestore(&dev3.lock, flags);
}
EXPORT_SYMBOL(set_latch_u5);
unsigned char get_latch_u5(void)
{
return dev3.state;
}
EXPORT_SYMBOL(get_latch_u5);
int rb532_gpio_get_value(unsigned gpio)
{
return readl(&rb532_gpio_reg0->gpiod) & (1 << gpio);
}
EXPORT_SYMBOL(rb532_gpio_get_value);
void rb532_gpio_set_value(unsigned gpio, int value)
{
unsigned tmp;
tmp = readl(&rb532_gpio_reg0->gpiod) & ~(1 << gpio);
if (value)
tmp |= 1 << gpio;
writel(tmp, (void *)&rb532_gpio_reg0->gpiod);
}
EXPORT_SYMBOL(rb532_gpio_set_value);
int rb532_gpio_direction_input(unsigned gpio)
{
writel(readl(&rb532_gpio_reg0->gpiocfg) & ~(1 << gpio),
(void *)&rb532_gpio_reg0->gpiocfg);
return 0;
}
EXPORT_SYMBOL(rb532_gpio_direction_input);
int rb532_gpio_direction_output(unsigned gpio, int value)
{
gpio_set_value(gpio, value);
writel(readl(&rb532_gpio_reg0->gpiocfg) | (1 << gpio),
(void *)&rb532_gpio_reg0->gpiocfg);
return 0;
}
EXPORT_SYMBOL(rb532_gpio_direction_output);
void rb532_gpio_set_int_level(unsigned gpio, int value)
{
unsigned tmp;
tmp = readl(&rb532_gpio_reg0->gpioilevel) & ~(1 << gpio);
if (value)
tmp |= 1 << gpio;
writel(tmp, (void *)&rb532_gpio_reg0->gpioilevel);
}
EXPORT_SYMBOL(rb532_gpio_set_int_level);
int rb532_gpio_get_int_level(unsigned gpio)
{
return readl(&rb532_gpio_reg0->gpioilevel) & (1 << gpio);
}
EXPORT_SYMBOL(rb532_gpio_get_int_level);
void rb532_gpio_set_int_status(unsigned gpio, int value)
{
unsigned tmp;
tmp = readl(&rb532_gpio_reg0->gpioistat);
if (value)
tmp |= 1 << gpio;
writel(tmp, (void *)&rb532_gpio_reg0->gpioistat);
}
EXPORT_SYMBOL(rb532_gpio_set_int_status);
int rb532_gpio_get_int_status(unsigned gpio)
{
return readl(&rb532_gpio_reg0->gpioistat) & (1 << gpio);
}
EXPORT_SYMBOL(rb532_gpio_get_int_status);
void rb532_gpio_set_func(unsigned gpio, int value)
{
unsigned tmp;
tmp = readl(&rb532_gpio_reg0->gpiofunc);
if (value)
tmp |= 1 << gpio;
writel(tmp, (void *)&rb532_gpio_reg0->gpiofunc);
}
EXPORT_SYMBOL(rb532_gpio_set_func);
int rb532_gpio_get_func(unsigned gpio)
{
return readl(&rb532_gpio_reg0->gpiofunc) & (1 << gpio);
}
EXPORT_SYMBOL(rb532_gpio_get_func);
int __init rb532_gpio_init(void)
{
rb532_gpio_reg0 = ioremap_nocache(rb532_gpio_reg0_res[0].start,
rb532_gpio_reg0_res[0].end -
rb532_gpio_reg0_res[0].start);
if (!rb532_gpio_reg0) {
printk(KERN_ERR "rb532: cannot remap GPIO register 0\n");
return -ENXIO;
}
dev3.base = ioremap_nocache(rb532_dev3_ctl_res[0].start,
rb532_dev3_ctl_res[0].end -
rb532_dev3_ctl_res[0].start);
if (!dev3.base) {
printk(KERN_ERR "rb532: cannot remap device controller 3\n");
return -ENXIO;
}
return 0;
}
arch_initcall(rb532_gpio_init);

209
arch/mips/rb532/irq.c Normal file
View File

@@ -0,0 +1,209 @@
/*
* 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.
*
* Copyright 2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* stevel@mvista.com or source@mvista.com
*/
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/io.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/bootinfo.h>
#include <asm/time.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/mach-rc32434/rc32434.h>
struct intr_group {
u32 mask; /* mask of valid bits in pending/mask registers */
volatile u32 *base_addr;
};
#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 struct intr_group intr_group[NUM_INTR_GROUPS] = {
{
.mask = 0x0000efff,
.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)},
{
.mask = 0x00001fff,
.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)},
{
.mask = 0x00000007,
.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)},
{
.mask = 0x0003ffff,
.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)},
{
.mask = 0xffffffff,
.base_addr = (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;
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 rb532_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 rb532_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 void rb532_mask_and_ack_irq(unsigned int irq_nr)
{
rb532_disable_irq(irq_nr);
ack_local_irq(group_to_ip(irq_to_group(irq_nr)));
}
static struct irq_chip rc32434_irq_type = {
.name = "RB532",
.ack = rb532_disable_irq,
.mask = rb532_disable_irq,
.mask_ack = rb532_mask_and_ack_irq,
.unmask = rb532_enable_irq,
};
void __init arch_init_irq(void)
{
int i;
pr_info("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS);
for (i = 0; i < RC32434_NR_IRQS; i++)
set_irq_chip_and_handler(i, &rc32434_irq_type,
handle_level_irq);
}
/* 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) {
do_IRQ(7);
} else {
ip = (cp0_cause & 0x7c00);
if (ip) {
group = 21 + (fls(ip) - 32);
addr = intr_group[group].base_addr;
pend = READ_PEND(addr);
pend &= ~READ_MASK(addr); /* only unmasked interrupts */
pend = 39 + (fls(pend) - 32);
do_IRQ((group << 5) + pend);
}
}
}

158
arch/mips/rb532/prom.c Normal file
View File

@@ -0,0 +1,158 @@
/*
* RouterBoard 500 specific prom routines
*
* Copyright (C) 2003, Peter Sadik <peter.sadik@idt.com>
* Copyright (C) 2005-2006, P.Christeas <p_christ@hol.gr>
* Copyright (C) 2007, Gabor Juhos <juhosg@openwrt.org>
* Felix Fietkau <nbd@openwrt.org>
* 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.
*
* 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/console.h>
#include <linux/bootmem.h>
#include <linux/ioport.h>
#include <linux/blkdev.h>
#include <asm/bootinfo.h>
#include <asm/mach-rc32434/ddr.h>
#include <asm/mach-rc32434/prom.h>
extern void __init setup_serial_port(void);
unsigned int idt_cpu_freq = 132000000;
EXPORT_SYMBOL(idt_cpu_freq);
unsigned int gpio_bootup_state;
EXPORT_SYMBOL(gpio_bootup_state);
static struct resource ddr_reg[] = {
{
.name = "ddr-reg",
.start = DDR0_PHYS_ADDR,
.end = DDR0_PHYS_ADDR + sizeof(struct ddr_ram),
.flags = IORESOURCE_MEM,
}
};
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;
num = arg + strlen(tag);
return simple_strtoul(num, 0, 10);
}
void __init prom_setup_cmdline(void)
{
char cmd_line[CL_SIZE];
char *cp, *board;
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)) {
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++) = ' ';
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);
}
void __init prom_init(void)
{
struct ddr_ram __iomem *ddr;
phys_t memsize;
phys_t ddrbase;
ddr = ioremap_nocache(ddr_reg[0].start,
ddr_reg[0].end - ddr_reg[0].start);
if (!ddr) {
printk(KERN_ERR "Unable to remap DDR register\n");
return;
}
ddrbase = (phys_t)&ddr->ddrbase;
memsize = (phys_t)&ddr->ddrmask;
memsize = 0 - memsize;
prom_setup_cmdline();
/* give all RAM to boot allocator,
* except for the first 0x400 and the last 0x200 bytes */
add_memory_region(ddrbase + 0x400, memsize - 0x600, BOOT_MEM_RAM);
}

53
arch/mips/rb532/serial.c Normal file
View File

@@ -0,0 +1,53 @@
/*
* 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.
*/
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <asm/serial.h>
#include <asm/mach-rc32434/rc32434.h>
extern unsigned int idt_cpu_freq;
static struct uart_port rb532_uart = {
.type = PORT_16550A,
.line = 0,
.irq = RC32434_UART0_IRQ,
.iotype = UPIO_MEM,
.membase = (char *)KSEG1ADDR(RC32434_UART0_BASE),
.regshift = 2
};
int __init setup_serial_port(void)
{
rb532_uart.uartclk = idt_cpu_freq;
return early_serial_setup(&rb532_uart);
}
arch_initcall(setup_serial_port);

79
arch/mips/rb532/setup.c Normal file
View File

@@ -0,0 +1,79 @@
/*
* setup.c - boot time setup code
*/
#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/reboot.h>
#include <asm/time.h>
#include <linux/ioport.h>
#include <asm/mach-rc32434/rc32434.h>
#include <asm/mach-rc32434/pci.h>
struct pci_reg __iomem *pci_reg;
EXPORT_SYMBOL(pci_reg);
static struct resource pci0_res[] = {
{
.name = "pci_reg0",
.start = PCI0_BASE_ADDR,
.end = PCI0_BASE_ADDR + sizeof(struct pci_reg),
.flags = IORESOURCE_MEM,
}
};
static void rb_machine_restart(char *command)
{
/* just jump to the reset vector */
writel(0x80000001, (void *)KSEG1ADDR(RC32434_REG_BASE + RC32434_RST));
((void (*)(void)) KSEG1ADDR(0x1FC00000u))();
}
static void rb_machine_halt(void)
{
for (;;)
continue;
}
void __init plat_mem_setup(void)
{
u32 val;
_machine_restart = rb_machine_restart;
_machine_halt = rb_machine_halt;
pm_power_off = rb_machine_halt;
set_io_port_base(KSEG1);
pci_reg = ioremap_nocache(pci0_res[0].start,
pci0_res[0].end - pci0_res[0].start);
if (!pci_reg) {
printk(KERN_ERR "Could not remap PCI registers\n");
return;
}
val = __raw_readl(&pci_reg->pcic);
val &= 0xFFFFFF7;
__raw_writel(val, (void *)&pci_reg->pcic);
#ifdef CONFIG_PCI
/* Enable PCI interrupts in EPLD Mask register */
*epld_mask = 0x0;
*(epld_mask + 1) = 0x0;
#endif
write_c0_wired(0);
}
const char *get_system_type(void)
{
switch (mips_machtype) {
case MACH_MIKROTIK_RB532A:
return "Mikrotik RB532A";
break;
default:
return "Mikrotik RB532";
break;
}
}

67
arch/mips/rb532/time.c Normal file
View File

@@ -0,0 +1,67 @@
/*
* 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.
*/
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/ptrace.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/mc146818rtc.h>
#include <linux/irq.h>
#include <linux/timex.h>
#include <asm/mipsregs.h>
#include <asm/debug.h>
#include <asm/time.h>
#include <asm/mach-rc32434/rc32434.h>
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 plat_time_init(void)
{
unsigned int est_freq, flags;
unsigned long r4k_offset;
local_irq_save(flags);
printk(KERN_INFO "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(KERN_INFO "CPU frequency %d.%02d MHz\n", est_freq / 1000000,
(est_freq % 1000000) * 100 / 1000000);
local_irq_restore(flags);
}