summaryrefslogtreecommitdiff
path: root/arch/mips/vr4181
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/mips/vr4181
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/mips/vr4181')
-rw-r--r--arch/mips/vr4181/common/Makefile7
-rw-r--r--arch/mips/vr4181/common/int_handler.S206
-rw-r--r--arch/mips/vr4181/common/irq.c239
-rw-r--r--arch/mips/vr4181/common/serial.c51
-rw-r--r--arch/mips/vr4181/common/time.c145
-rw-r--r--arch/mips/vr4181/osprey/Makefile7
-rw-r--r--arch/mips/vr4181/osprey/dbg_io.c136
-rw-r--r--arch/mips/vr4181/osprey/prom.c49
-rw-r--r--arch/mips/vr4181/osprey/reset.c40
-rw-r--r--arch/mips/vr4181/osprey/setup.c68
10 files changed, 948 insertions, 0 deletions
diff --git a/arch/mips/vr4181/common/Makefile b/arch/mips/vr4181/common/Makefile
new file mode 100644
index 000000000000..f7587ca64ead
--- /dev/null
+++ b/arch/mips/vr4181/common/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for common code of NEC vr4181 based boards
+#
+
+obj-y := irq.o int_handler.o serial.o time.o
+
+EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/vr4181/common/int_handler.S b/arch/mips/vr4181/common/int_handler.S
new file mode 100644
index 000000000000..2c041b8ee52b
--- /dev/null
+++ b/arch/mips/vr4181/common/int_handler.S
@@ -0,0 +1,206 @@
+/*
+ * arch/mips/vr4181/common/int_handler.S
+ *
+ * Adapted to the VR4181 and almost entirely rewritten:
+ * Copyright (C) 1999 Bradley D. LaRonde and Michael Klar
+ *
+ * Clean up to conform to the new IRQ
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+
+#include <asm/vr4181/vr4181.h>
+
+/*
+ * [jsun]
+ * See include/asm/vr4181/irq.h for IRQ assignment and strategy.
+ */
+
+ .text
+ .set noreorder
+
+ .align 5
+ NESTED(vr4181_handle_irq, PT_SIZE, ra)
+
+ .set noat
+ SAVE_ALL
+ CLI
+
+ .set at
+ .set noreorder
+
+ mfc0 t0, CP0_CAUSE
+ mfc0 t2, CP0_STATUS
+
+ and t0, t2
+
+ /* we check IP3 first; it happens most frequently */
+ andi t1, t0, STATUSF_IP3
+ bnez t1, ll_cpu_ip3
+ andi t1, t0, STATUSF_IP2
+ bnez t1, ll_cpu_ip2
+ andi t1, t0, STATUSF_IP7 /* cpu timer */
+ bnez t1, ll_cputimer_irq
+ andi t1, t0, STATUSF_IP4
+ bnez t1, ll_cpu_ip4
+ andi t1, t0, STATUSF_IP5
+ bnez t1, ll_cpu_ip5
+ andi t1, t0, STATUSF_IP6
+ bnez t1, ll_cpu_ip6
+ andi t1, t0, STATUSF_IP0 /* software int 0 */
+ bnez t1, ll_cpu_ip0
+ andi t1, t0, STATUSF_IP1 /* software int 1 */
+ bnez t1, ll_cpu_ip1
+ nop
+
+ .set reorder
+do_spurious:
+ j spurious_interrupt
+
+/*
+ * regular CPU irqs
+ */
+ll_cputimer_irq:
+ li a0, VR4181_IRQ_TIMER
+ move a1, sp
+ jal do_IRQ
+ j ret_from_irq
+
+
+ll_cpu_ip0:
+ li a0, VR4181_IRQ_SW1
+ move a1, sp
+ jal do_IRQ
+ j ret_from_irq
+
+ll_cpu_ip1:
+ li a0, VR4181_IRQ_SW2
+ move a1, sp
+ jal do_IRQ
+ j ret_from_irq
+
+ll_cpu_ip3:
+ li a0, VR4181_IRQ_INT1
+ move a1, sp
+ jal do_IRQ
+ j ret_from_irq
+
+ll_cpu_ip4:
+ li a0, VR4181_IRQ_INT2
+ move a1, sp
+ jal do_IRQ
+ j ret_from_irq
+
+ll_cpu_ip5:
+ li a0, VR4181_IRQ_INT3
+ move a1, sp
+ jal do_IRQ
+ j ret_from_irq
+
+ll_cpu_ip6:
+ li a0, VR4181_IRQ_INT4
+ move a1, sp
+ jal do_IRQ
+ j ret_from_irq
+
+/*
+ * One of the sys irq has happend.
+ *
+ * In the interest of speed, we first determine in the following order
+ * which 16-irq block have pending interrupts:
+ * sysint1 (16 sources, including cascading intrs from GPIO)
+ * sysint2
+ * gpio (16 intr sources)
+ *
+ * Then we do binary search to find the exact interrupt source.
+ */
+ll_cpu_ip2:
+
+ lui t3,%hi(VR4181_SYSINT1REG)
+ lhu t0,%lo(VR4181_SYSINT1REG)(t3)
+ lhu t2,%lo(VR4181_MSYSINT1REG)(t3)
+ and t0, 0xfffb /* hack - remove RTC Long 1 intr */
+ and t0, t2
+ beqz t0, check_sysint2
+
+ /* check for GPIO interrupts */
+ andi t1, t0, 0x0100
+ bnez t1, check_gpio_int
+
+ /* so we have an interrupt in sysint1 which is not gpio int */
+ li a0, VR4181_SYS_IRQ_BASE - 1
+ j check_16
+
+check_sysint2:
+
+ lhu t0,%lo(VR4181_SYSINT2REG)(t3)
+ lhu t2,%lo(VR4181_MSYSINT2REG)(t3)
+ and t0, 0xfffe /* hack - remove RTC Long 2 intr */
+ and t0, t2
+ li a0, VR4181_SYS_IRQ_BASE + 16 - 1
+ j check_16
+
+check_gpio_int:
+ lui t3,%hi(VR4181_GPINTMSK)
+ lhu t0,%lo(VR4181_GPINTMSK)(t3)
+ lhu t2,%lo(VR4181_GPINTSTAT)(t3)
+ xori t0, 0xffff /* why? reverse logic? */
+ and t0, t2
+ li a0, VR4181_GPIO_IRQ_BASE - 1
+ j check_16
+
+/*
+ * When we reach check_16, we have 16-bit status in t0 and base irq number
+ * in a0.
+ */
+check_16:
+ andi t1, t0, 0xff
+ bnez t1, check_8
+
+ srl t0, 8
+ addi a0, 8
+ j check_8
+
+/*
+ * When we reach check_8, we have 8-bit status in t0 and base irq number
+ * in a0.
+ */
+check_8:
+ andi t1, t0, 0xf
+ bnez t1, check_4
+
+ srl t0, 4
+ addi a0, 4
+ j check_4
+
+/*
+ * When we reach check_4, we have 4-bit status in t0 and base irq number
+ * in a0.
+ */
+check_4:
+ andi t0, t0, 0xf
+ beqz t0, do_spurious
+
+loop:
+ andi t2, t0, 0x1
+ srl t0, 1
+ addi a0, 1
+ beqz t2, loop
+
+found_it:
+ move a1, sp
+ jal do_IRQ
+
+ j ret_from_irq
+
+ END(vr4181_handle_irq)
diff --git a/arch/mips/vr4181/common/irq.c b/arch/mips/vr4181/common/irq.c
new file mode 100644
index 000000000000..2cdf77c5cb3e
--- /dev/null
+++ b/arch/mips/vr4181/common/irq.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
+ *
+ * linux/arch/mips/vr4181/common/irq.c
+ * Completely re-written to use the new irq.c
+ *
+ * Credits to Bradley D. LaRonde and Michael Klar for writing the original
+ * irq.c file which was derived from the common irq.c file.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/gdb-stub.h>
+
+#include <asm/vr4181/vr4181.h>
+
+/*
+ * Strategy:
+ *
+ * We essentially have three irq controllers, CPU, system, and gpio.
+ *
+ * CPU irq controller is taken care by arch/mips/kernel/irq_cpu.c and
+ * CONFIG_IRQ_CPU config option.
+ *
+ * We here provide sys_irq and gpio_irq controller code.
+ */
+
+static int sys_irq_base;
+static int gpio_irq_base;
+
+/* ---------------------- sys irq ------------------------ */
+static void
+sys_irq_enable(unsigned int irq)
+{
+ irq -= sys_irq_base;
+ if (irq < 16) {
+ *VR4181_MSYSINT1REG |= (u16)(1 << irq);
+ } else {
+ irq -= 16;
+ *VR4181_MSYSINT2REG |= (u16)(1 << irq);
+ }
+}
+
+static void
+sys_irq_disable(unsigned int irq)
+{
+ irq -= sys_irq_base;
+ if (irq < 16) {
+ *VR4181_MSYSINT1REG &= ~((u16)(1 << irq));
+ } else {
+ irq -= 16;
+ *VR4181_MSYSINT2REG &= ~((u16)(1 << irq));
+ }
+
+}
+
+static unsigned int
+sys_irq_startup(unsigned int irq)
+{
+ sys_irq_enable(irq);
+ return 0;
+}
+
+#define sys_irq_shutdown sys_irq_disable
+#define sys_irq_ack sys_irq_disable
+
+static void
+sys_irq_end(unsigned int irq)
+{
+ if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ sys_irq_enable(irq);
+}
+
+static hw_irq_controller sys_irq_controller = {
+ "vr4181_sys_irq",
+ sys_irq_startup,
+ sys_irq_shutdown,
+ sys_irq_enable,
+ sys_irq_disable,
+ sys_irq_ack,
+ sys_irq_end,
+ NULL /* no affinity stuff for UP */
+};
+
+/* ---------------------- gpio irq ------------------------ */
+/* gpio irq lines use reverse logic */
+static void
+gpio_irq_enable(unsigned int irq)
+{
+ irq -= gpio_irq_base;
+ *VR4181_GPINTMSK &= ~((u16)(1 << irq));
+}
+
+static void
+gpio_irq_disable(unsigned int irq)
+{
+ irq -= gpio_irq_base;
+ *VR4181_GPINTMSK |= (u16)(1 << irq);
+}
+
+static unsigned int
+gpio_irq_startup(unsigned int irq)
+{
+ gpio_irq_enable(irq);
+
+ irq -= gpio_irq_base;
+ *VR4181_GPINTEN |= (u16)(1 << irq );
+
+ return 0;
+}
+
+static void
+gpio_irq_shutdown(unsigned int irq)
+{
+ gpio_irq_disable(irq);
+
+ irq -= gpio_irq_base;
+ *VR4181_GPINTEN &= ~((u16)(1 << irq ));
+}
+
+static void
+gpio_irq_ack(unsigned int irq)
+{
+ u16 irqtype;
+ u16 irqshift;
+
+ gpio_irq_disable(irq);
+
+ /* we clear interrupt if it is edge triggered */
+ irq -= gpio_irq_base;
+ if (irq < 8) {
+ irqtype = *VR4181_GPINTTYPL;
+ irqshift = 2 << (irq*2);
+ } else {
+ irqtype = *VR4181_GPINTTYPH;
+ irqshift = 2 << ((irq-8)*2);
+ }
+ if ( ! (irqtype & irqshift) ) {
+ *VR4181_GPINTSTAT = (u16) (1 << irq);
+ }
+}
+
+static void
+gpio_irq_end(unsigned int irq)
+{
+ if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ gpio_irq_enable(irq);
+}
+
+static hw_irq_controller gpio_irq_controller = {
+ "vr4181_gpio_irq",
+ gpio_irq_startup,
+ gpio_irq_shutdown,
+ gpio_irq_enable,
+ gpio_irq_disable,
+ gpio_irq_ack,
+ gpio_irq_end,
+ NULL /* no affinity stuff for UP */
+};
+
+/* --------------------- IRQ init stuff ---------------------- */
+
+extern asmlinkage void vr4181_handle_irq(void);
+extern void breakpoint(void);
+extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
+extern void mips_cpu_irq_init(u32 irq_base);
+
+static struct irqaction cascade =
+ { no_action, SA_INTERRUPT, CPU_MASK_NONE, "cascade", NULL, NULL };
+static struct irqaction reserved =
+ { no_action, SA_INTERRUPT, CPU_MASK_NONE, "cascade", NULL, NULL };
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ set_except_vector(0, vr4181_handle_irq);
+
+ /* init CPU irqs */
+ mips_cpu_irq_init(VR4181_CPU_IRQ_BASE);
+
+ /* init sys irqs */
+ sys_irq_base = VR4181_SYS_IRQ_BASE;
+ for (i=sys_irq_base; i < sys_irq_base + VR4181_NUM_SYS_IRQ; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = NULL;
+ irq_desc[i].depth = 1;
+ irq_desc[i].handler = &sys_irq_controller;
+ }
+
+ /* init gpio irqs */
+ gpio_irq_base = VR4181_GPIO_IRQ_BASE;
+ for (i=gpio_irq_base; i < gpio_irq_base + VR4181_NUM_GPIO_IRQ; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ irq_desc[i].action = NULL;
+ irq_desc[i].depth = 1;
+ irq_desc[i].handler = &gpio_irq_controller;
+ }
+
+ /* Default all ICU IRQs to off ... */
+ *VR4181_MSYSINT1REG = 0;
+ *VR4181_MSYSINT2REG = 0;
+
+ /* We initialize the level 2 ICU registers to all bits disabled. */
+ *VR4181_MPIUINTREG = 0;
+ *VR4181_MAIUINTREG = 0;
+ *VR4181_MKIUINTREG = 0;
+
+ /* disable all GPIO intrs */
+ *VR4181_GPINTMSK = 0xffff;
+
+ /* vector handler. What these do is register the IRQ as non-sharable */
+ setup_irq(VR4181_IRQ_INT0, &cascade);
+ setup_irq(VR4181_IRQ_GIU, &cascade);
+
+ /*
+ * RTC interrupts are interesting. They have two destinations.
+ * One is at sys irq controller, and the other is at CPU IP3 and IP4.
+ * RTC timer is used as system timer.
+ * We enable them here, but timer routine will register later
+ * with CPU IP3/IP4.
+ */
+ setup_irq(VR4181_IRQ_RTCL1, &reserved);
+ setup_irq(VR4181_IRQ_RTCL2, &reserved);
+}
diff --git a/arch/mips/vr4181/common/serial.c b/arch/mips/vr4181/common/serial.c
new file mode 100644
index 000000000000..3f62c62b107f
--- /dev/null
+++ b/arch/mips/vr4181/common/serial.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * arch/mips/vr4181/common/serial.c
+ * initialize serial port on vr4181.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * [jsun, 010925]
+ * You need to make sure rs_table has at least one element in
+ * drivers/char/serial.c file. There is no good way to do it right
+ * now. A workaround is to include CONFIG_SERIAL_MANY_PORTS in your
+ * configure file, which would gives you 64 ports and wastes 11K ram.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+
+#include <asm/vr4181/vr4181.h>
+
+void __init vr4181_init_serial(void)
+{
+ struct serial_struct s;
+
+ /* turn on UART clock */
+ *VR4181_CMUCLKMSK |= VR4181_CMUCLKMSK_MSKSIU;
+
+ /* clear memory */
+ memset(&s, 0, sizeof(s));
+
+ s.line = 0; /* we set the first one */
+ s.baud_base = 1152000;
+ s.irq = VR4181_IRQ_SIU;
+ s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; /* STD_COM_FLAGS */
+ s.iomem_base = (u8*)VR4181_SIURB;
+ s.iomem_reg_shift = 0;
+ s.io_type = SERIAL_IO_MEM;
+ if (early_serial_setup(&s) != 0) {
+ panic("vr4181_init_serial() failed!");
+ }
+}
+
diff --git a/arch/mips/vr4181/common/time.c b/arch/mips/vr4181/common/time.c
new file mode 100644
index 000000000000..17814076b6f4
--- /dev/null
+++ b/arch/mips/vr4181/common/time.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * rtc and time ops for vr4181. Part of code is drived from
+ * linux-vr, originally written by Bradley D. LaRonde & Michael Klar.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/param.h> /* for HZ */
+#include <linux/time.h>
+#include <linux/interrupt.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+
+#include <asm/vr4181/vr4181.h>
+
+#define COUNTS_PER_JIFFY ((32768 + HZ/2) / HZ)
+
+/*
+ * RTC ops
+ */
+
+DEFINE_SPINLOCK(rtc_lock);
+
+/* per VR41xx docs, bad data can be read if between 2 counts */
+static inline unsigned short
+read_time_reg(volatile unsigned short *reg)
+{
+ unsigned short value;
+ do {
+ value = *reg;
+ barrier();
+ } while (value != *reg);
+ return value;
+}
+
+static unsigned long
+vr4181_rtc_get_time(void)
+{
+ unsigned short regh, regm, regl;
+
+ // why this crazy order, you ask? to guarantee that neither m
+ // nor l wrap before all 3 read
+ do {
+ regm = read_time_reg(VR4181_ETIMEMREG);
+ barrier();
+ regh = read_time_reg(VR4181_ETIMEHREG);
+ barrier();
+ regl = read_time_reg(VR4181_ETIMELREG);
+ } while (regm != read_time_reg(VR4181_ETIMEMREG));
+ return ((regh << 17) | (regm << 1) | (regl >> 15));
+}
+
+static int
+vr4181_rtc_set_time(unsigned long timeval)
+{
+ unsigned short intreg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ intreg = *VR4181_RTCINTREG & 0x05;
+ barrier();
+ *VR4181_ETIMELREG = timeval << 15;
+ *VR4181_ETIMEMREG = timeval >> 1;
+ *VR4181_ETIMEHREG = timeval >> 17;
+ barrier();
+ // assume that any ints that just triggered are invalid, since the
+ // time value is written non-atomically in 3 separate regs
+ *VR4181_RTCINTREG = 0x05 ^ intreg;
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ return 0;
+}
+
+
+/*
+ * timer interrupt routine (wrapper)
+ *
+ * we need our own interrupt routine because we need to clear
+ * RTC1 interrupt.
+ */
+static void
+vr4181_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ /* Clear the interrupt. */
+ *VR4181_RTCINTREG = 0x2;
+
+ /* call the generic one */
+ timer_interrupt(irq, dev_id, regs);
+}
+
+
+/*
+ * vr4181_time_init:
+ *
+ * We pick the following choices:
+ * . we use elapsed timer as the RTC. We set some reasonable init data since
+ * it does not persist across reset
+ * . we use RTC1 as the system timer interrupt source.
+ * . we use CPU counter for fast_gettimeoffset and we calivrate the cpu
+ * frequency. In other words, we use calibrate_div64_gettimeoffset().
+ * . we use our own timer interrupt routine which clears the interrupt
+ * and then calls the generic high-level timer interrupt routine.
+ *
+ */
+
+extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
+
+static void
+vr4181_timer_setup(struct irqaction *irq)
+{
+ /* over-write the handler to be our own one */
+ irq->handler = vr4181_timer_interrupt;
+
+ /* sets up the frequency */
+ *VR4181_RTCL1LREG = COUNTS_PER_JIFFY;
+ *VR4181_RTCL1HREG = 0;
+
+ /* and ack any pending ints */
+ *VR4181_RTCINTREG = 0x2;
+
+ /* setup irqaction */
+ setup_irq(VR4181_IRQ_INT1, irq);
+
+}
+
+void
+vr4181_init_time(void)
+{
+ /* setup hookup functions */
+ rtc_get_time = vr4181_rtc_get_time;
+ rtc_set_time = vr4181_rtc_set_time;
+
+ board_timer_setup = vr4181_timer_setup;
+}
+
diff --git a/arch/mips/vr4181/osprey/Makefile b/arch/mips/vr4181/osprey/Makefile
new file mode 100644
index 000000000000..34be05790883
--- /dev/null
+++ b/arch/mips/vr4181/osprey/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for common code of NEC Osprey board
+#
+
+obj-y := setup.o prom.o reset.o
+
+obj-$(CONFIG_KGDB) += dbg_io.o
diff --git a/arch/mips/vr4181/osprey/dbg_io.c b/arch/mips/vr4181/osprey/dbg_io.c
new file mode 100644
index 000000000000..5e8a84072d5b
--- /dev/null
+++ b/arch/mips/vr4181/osprey/dbg_io.c
@@ -0,0 +1,136 @@
+/*
+ * kgdb io functions for osprey. We use the serial port on debug board.
+ *
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * 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.
+ *
+ */
+
+/* ======================= CONFIG ======================== */
+
+/* [jsun] we use the second serial port for kdb */
+#define BASE 0xb7fffff0
+#define MAX_BAUD 115200
+
+/* distance in bytes between two serial registers */
+#define REG_OFFSET 1
+
+/*
+ * 0 - kgdb does serial init
+ * 1 - kgdb skip serial init
+ */
+static int remoteDebugInitialized = 1;
+
+/*
+ * the default baud rate *if* kgdb does serial init
+ */
+#define BAUD_DEFAULT UART16550_BAUD_38400
+
+/* ======================= END OF CONFIG ======================== */
+
+typedef unsigned char uint8;
+typedef unsigned int uint32;
+
+#define UART16550_BAUD_2400 2400
+#define UART16550_BAUD_4800 4800
+#define UART16550_BAUD_9600 9600
+#define UART16550_BAUD_19200 19200
+#define UART16550_BAUD_38400 38400
+#define UART16550_BAUD_57600 57600
+#define UART16550_BAUD_115200 115200
+
+#define UART16550_PARITY_NONE 0
+#define UART16550_PARITY_ODD 0x08
+#define UART16550_PARITY_EVEN 0x18
+#define UART16550_PARITY_MARK 0x28
+#define UART16550_PARITY_SPACE 0x38
+
+#define UART16550_DATA_5BIT 0x0
+#define UART16550_DATA_6BIT 0x1
+#define UART16550_DATA_7BIT 0x2
+#define UART16550_DATA_8BIT 0x3
+
+#define UART16550_STOP_1BIT 0x0
+#define UART16550_STOP_2BIT 0x4
+
+/* register offset */
+#define OFS_RCV_BUFFER 0
+#define OFS_TRANS_HOLD 0
+#define OFS_SEND_BUFFER 0
+#define OFS_INTR_ENABLE (1*REG_OFFSET)
+#define OFS_INTR_ID (2*REG_OFFSET)
+#define OFS_DATA_FORMAT (3*REG_OFFSET)
+#define OFS_LINE_CONTROL (3*REG_OFFSET)
+#define OFS_MODEM_CONTROL (4*REG_OFFSET)
+#define OFS_RS232_OUTPUT (4*REG_OFFSET)
+#define OFS_LINE_STATUS (5*REG_OFFSET)
+#define OFS_MODEM_STATUS (6*REG_OFFSET)
+#define OFS_RS232_INPUT (6*REG_OFFSET)
+#define OFS_SCRATCH_PAD (7*REG_OFFSET)
+
+#define OFS_DIVISOR_LSB (0*REG_OFFSET)
+#define OFS_DIVISOR_MSB (1*REG_OFFSET)
+
+
+/* memory-mapped read/write of the port */
+#define UART16550_READ(y) (*((volatile uint8*)(BASE + y)))
+#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z)
+
+void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
+{
+ /* disable interrupts */
+ UART16550_WRITE(OFS_INTR_ENABLE, 0);
+
+ /* set up buad rate */
+ {
+ uint32 divisor;
+
+ /* set DIAB bit */
+ UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
+
+ /* set divisor */
+ divisor = MAX_BAUD / baud;
+ UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
+ UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
+
+ /* clear DIAB bit */
+ UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
+ }
+
+ /* set data format */
+ UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
+}
+
+
+uint8 getDebugChar(void)
+{
+ if (!remoteDebugInitialized) {
+ remoteDebugInitialized = 1;
+ debugInit(BAUD_DEFAULT,
+ UART16550_DATA_8BIT,
+ UART16550_PARITY_NONE, UART16550_STOP_1BIT);
+ }
+
+ while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
+ return UART16550_READ(OFS_RCV_BUFFER);
+}
+
+
+int putDebugChar(uint8 byte)
+{
+ if (!remoteDebugInitialized) {
+ remoteDebugInitialized = 1;
+ debugInit(BAUD_DEFAULT,
+ UART16550_DATA_8BIT,
+ UART16550_PARITY_NONE, UART16550_STOP_1BIT);
+ }
+
+ while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
+ UART16550_WRITE(OFS_SEND_BUFFER, byte);
+ return 1;
+}
diff --git a/arch/mips/vr4181/osprey/prom.c b/arch/mips/vr4181/osprey/prom.c
new file mode 100644
index 000000000000..af0d14561619
--- /dev/null
+++ b/arch/mips/vr4181/osprey/prom.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * arch/mips/vr4181/osprey/prom.c
+ * prom code for osprey.
+ *
+ * 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.
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+
+const char *get_system_type(void)
+{
+ return "NEC_Vr41xx Osprey";
+}
+
+/*
+ * [jsun] right now we assume it is the nec debug monitor, which does
+ * not pass any arguments.
+ */
+void __init prom_init(void)
+{
+ // cmdline is now set in default config
+ // strcpy(arcs_cmdline, "ip=bootp ");
+ // strcat(arcs_cmdline, "ether=46,0x03fe0300,eth0 ");
+ // strcpy(arcs_cmdline, "ether=0,0x0300,eth0 "
+ // strcat(arcs_cmdline, "video=vr4181fb:xres:240,yres:320,bpp:8 ");
+
+ mips_machgroup = MACH_GROUP_NEC_VR41XX;
+ mips_machtype = MACH_NEC_OSPREY;
+
+ /* 16MB fixed */
+ add_memory_region(0, 16 << 20, BOOT_MEM_RAM);
+}
+
+unsigned long __init prom_free_prom_memory(void)
+{
+ return 0;
+}
diff --git a/arch/mips/vr4181/osprey/reset.c b/arch/mips/vr4181/osprey/reset.c
new file mode 100644
index 000000000000..036ae83d89d6
--- /dev/null
+++ b/arch/mips/vr4181/osprey/reset.c
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 1997, 2001 Ralf Baechle
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+
+void nec_osprey_restart(char *command)
+{
+ set_c0_status(ST0_ERL);
+ change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+ flush_cache_all();
+ write_c0_wired(0);
+ __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
+}
+
+void nec_osprey_halt(void)
+{
+ printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+ while (1)
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+}
+
+void nec_osprey_power_off(void)
+{
+ nec_osprey_halt();
+}
diff --git a/arch/mips/vr4181/osprey/setup.c b/arch/mips/vr4181/osprey/setup.c
new file mode 100644
index 000000000000..2ff7140e7ed7
--- /dev/null
+++ b/arch/mips/vr4181/osprey/setup.c
@@ -0,0 +1,68 @@
+/*
+ * linux/arch/mips/vr4181/setup.c
+ *
+ * VR41xx setup routines
+ *
+ * Copyright (C) 1999 Bradley D. LaRonde
+ * Copyright (C) 1999, 2000 Michael Klar
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/reboot.h>
+#include <asm/vr4181/vr4181.h>
+#include <asm/io.h>
+
+
+extern void nec_osprey_restart(char* c);
+extern void nec_osprey_halt(void);
+extern void nec_osprey_power_off(void);
+
+extern void vr4181_init_serial(void);
+extern void vr4181_init_time(void);
+
+static void __init nec_osprey_setup(void)
+{
+ set_io_port_base(VR4181_PORT_BASE);
+ isa_slot_offset = VR4181_ISAMEM_BASE;
+
+ vr4181_init_serial();
+ vr4181_init_time();
+
+ _machine_restart = nec_osprey_restart;
+ _machine_halt = nec_osprey_halt;
+ _machine_power_off = nec_osprey_power_off;
+
+ /* setup resource limit */
+ ioport_resource.end = 0xffffffff;
+ iomem_resource.end = 0xffffffff;
+
+ /* [jsun] hack */
+ /*
+ printk("[jsun] hack to change external ISA control register, %x -> %x\n",
+ (*VR4181_XISACTL),
+ (*VR4181_XISACTL) | 0x2);
+ *VR4181_XISACTL |= 0x2;
+ */
+
+ // *VR4181_GPHIBSTH = 0x2000;
+ // *VR4181_GPMD0REG = 0x00c0;
+ // *VR4181_GPINTEN = 1<<6;
+
+ /* [jsun] I believe this will get the interrupt type right
+ * for the ether port.
+ */
+ *VR4181_GPINTTYPL = 0x3000;
+}
+
+early_initcall(nec_osprey_setup);