summaryrefslogtreecommitdiff
path: root/target/linux/rb532/files-2.6.23/arch/mips/rb500
diff options
context:
space:
mode:
authorflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-07-15 17:17:04 +0000
committerflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-07-15 17:17:04 +0000
commit42c88ed264e86b3e8287f85e2099bc2ca7c5f51d (patch)
tree03c3dac161ce721fd65cb2f2d967eda861999b74 /target/linux/rb532/files-2.6.23/arch/mips/rb500
parent69f7e26c1a2390ae345cfa94dadcc59a3fb118f7 (diff)
Move files and patches to files-2.6.23 and patches-2.6.23
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11843 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/rb532/files-2.6.23/arch/mips/rb500')
-rw-r--r--target/linux/rb532/files-2.6.23/arch/mips/rb500/Makefile5
-rw-r--r--target/linux/rb532/files-2.6.23/arch/mips/rb500/devices.c338
-rw-r--r--target/linux/rb532/files-2.6.23/arch/mips/rb500/gpio.c198
-rw-r--r--target/linux/rb532/files-2.6.23/arch/mips/rb500/irq.c265
-rw-r--r--target/linux/rb532/files-2.6.23/arch/mips/rb500/prom.c178
-rw-r--r--target/linux/rb532/files-2.6.23/arch/mips/rb500/serial.c78
-rw-r--r--target/linux/rb532/files-2.6.23/arch/mips/rb500/setup.c81
-rw-r--r--target/linux/rb532/files-2.6.23/arch/mips/rb500/time.c94
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);
+}
+