summaryrefslogtreecommitdiffstats
path: root/arch/mips/ddb5074
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-01-26 00:07:44 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-01-26 00:07:44 +0000
commit38f0dc890f23f8de14abe63f60a9f9bf3be40271 (patch)
tree99c5b1e021cc51f059d55c7efa4b74f3f4d8a80d /arch/mips/ddb5074
parent07ebee0bea931f0d373e40205c932cae6b00a86d (diff)
Support for the NEC DDB Vrc-5074 evaluation board. Patches by
Geert Uytterhoeven (geert@linux-m68k.org).
Diffstat (limited to 'arch/mips/ddb5074')
-rw-r--r--arch/mips/ddb5074/.cvsignore2
-rw-r--r--arch/mips/ddb5074/Makefile22
-rw-r--r--arch/mips/ddb5074/int-handler.S122
-rw-r--r--arch/mips/ddb5074/irq.c230
-rw-r--r--arch/mips/ddb5074/nile4.c294
-rw-r--r--arch/mips/ddb5074/pci.c320
-rw-r--r--arch/mips/ddb5074/prom.c40
-rw-r--r--arch/mips/ddb5074/setup.c239
-rw-r--r--arch/mips/ddb5074/time.c35
9 files changed, 1304 insertions, 0 deletions
diff --git a/arch/mips/ddb5074/.cvsignore b/arch/mips/ddb5074/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/arch/mips/ddb5074/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/arch/mips/ddb5074/Makefile b/arch/mips/ddb5074/Makefile
new file mode 100644
index 000000000..d041acef5
--- /dev/null
+++ b/arch/mips/ddb5074/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for the NEC DDB Vrc-5074 specific kernel interface routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+#
+# $Id$
+#
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+O_TARGET = ddb5074.a
+O_OBJS = setup.o irq.o time.o prom.o pci.o int-handler.o nile4.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/mips/ddb5074/int-handler.S b/arch/mips/ddb5074/int-handler.S
new file mode 100644
index 000000000..07d091953
--- /dev/null
+++ b/arch/mips/ddb5074/int-handler.S
@@ -0,0 +1,122 @@
+/*
+ * arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler
+ *
+ * Based on arch/mips/sgi/kernel/indyIRQ.S
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ *
+ * $Id$
+ */
+
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+ /* A lot of complication here is taken away because:
+ *
+ * 1) We handle one interrupt and return, sitting in a loop
+ * and moving across all the pending IRQ bits in the cause
+ * register is _NOT_ the answer, the common case is one
+ * pending IRQ so optimize in that direction.
+ *
+ * 2) We need not check against bits in the status register
+ * IRQ mask, that would make this routine slow as hell.
+ *
+ * 3) Linux only thinks in terms of all IRQs on or all IRQs
+ * off, nothing in between like BSD spl() brain-damage.
+ *
+ * Furthermore, the IRQs on the INDY look basically (barring
+ * software IRQs which we don't use at all) like:
+ *
+ * MIPS IRQ Source
+ * -------- ------
+ * 0 Software (ignored)
+ * 1 Software (ignored)
+ * 2 Local IRQ level zero
+ * 3 Local IRQ level one
+ * 4 8254 Timer zero
+ * 5 8254 Timer one
+ * 6 Bus Error
+ * 7 R4k timer (what we use)
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ---- R4k Timer
+ * Local IRQ zero
+ * Local IRQ one
+ * Bus Error
+ * 8254 Timer zero
+ * Lowest ---- 8254 Timer one
+ *
+ * then we just return, if multiple IRQs are pending then
+ * we will just take another exception, big deal.
+ */
+
+ .text
+ .set noreorder
+ .set noat
+ .align 5
+ NESTED(ddbIRQ, PT_SIZE, sp)
+ SAVE_ALL
+ CLI
+ .set at
+ mfc0 s0, CP0_CAUSE # get irq mask
+
+#if 1
+ mfc0 t2,CP0_STATUS # get enabled interrupts
+ and s0,t2 # isolate allowed ones
+#endif
+ /* First we check for r4k counter/timer IRQ. */
+ andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero
+ beq a0, zero, 1f
+ andi a0, s0, CAUSEF_IP3 # delay slot, check local level one
+
+ /* Wheee, local level zero interrupt. */
+ jal ddb_local0_irqdispatch
+ move a0, sp # delay slot
+
+ j ret_from_irq
+ nop # delay slot
+
+1:
+ beq a0, zero, 1f
+ andi a0, s0, CAUSEF_IP6 # delay slot, check bus error
+
+ /* Wheee, local level one interrupt. */
+ move a0, sp
+ jal ddb_local1_irqdispatch
+ nop
+
+ j ret_from_irq
+ nop
+
+1:
+ beq a0, zero, 1f
+ nop
+
+ /* Wheee, an asynchronous bus error... */
+ move a0, sp
+ jal ddb_buserror_irq
+ nop
+
+ j ret_from_irq
+ nop
+
+1:
+ /* Here by mistake? This is possible, what can happen
+ * is that by the time we take the exception the IRQ
+ * pin goes low, so just leave if this is the case.
+ */
+ andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)
+ beq a0, zero, 1f
+
+ /* Must be one of the 8254 timers... */
+ move a0, sp
+ jal ddb_8254timer_irq
+ nop
+1:
+ j ret_from_irq
+ nop
+ END(ddbIRQ)
diff --git a/arch/mips/ddb5074/irq.c b/arch/mips/ddb5074/irq.c
new file mode 100644
index 000000000..1faba4c5c
--- /dev/null
+++ b/arch/mips/ddb5074/irq.c
@@ -0,0 +1,230 @@
+/*
+ * arch/mips/ddb5074/irq.c -- NEC DDB Vrc-5074 interrupt routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Sony Suprastructure Center Europe (SUPC-E), Brussels
+ *
+ * $Id$
+ */
+
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ptrace.h>
+#include <asm/nile4.h>
+#include <asm/ddb5074.h>
+
+
+extern void __init i8259_init(void);
+extern void i8259_disable_irq(unsigned int irq_nr);
+extern void i8259_enable_irq(unsigned int irq_nr);
+
+extern asmlinkage void ddbIRQ(void);
+extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs);
+extern asmlinkage void do_IRQ(int irq, struct pt_regs * regs);
+
+
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+}
+
+
+#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */
+#define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */
+#define M1543_PNP_DATA 0x03f1 /* PnP Data Port */
+
+#define M1543_PNP_ALT_CONFIG 0x0370 /* Alternative PnP Config Port */
+#define M1543_PNP_ALT_INDEX 0x0370 /* Alternative PnP Index Port */
+#define M1543_PNP_ALT_DATA 0x0371 /* Alternative PnP Data Port */
+
+#define M1543_INT1_MASTER_CTRL 0x0020 /* INT_1 (master) Control Register */
+#define M1543_INT1_MASTER_MASK 0x0021 /* INT_1 (master) Mask Register */
+
+#define M1543_INT1_SLAVE_CTRL 0x00a0 /* INT_1 (slave) Control Register */
+#define M1543_INT1_SLAVE_MASK 0x00a1 /* INT_1 (slave) Mask Register */
+
+#define M1543_INT1_MASTER_ELCR 0x04d0 /* INT_1 (master) Edge/Level Control */
+#define M1543_INT1_SLAVE_ELCR 0x04d1 /* INT_1 (slave) Edge/Level Control */
+
+
+static void m1543_irq_setup(void)
+{
+ /*
+ * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all
+ * the possible IO sources in the M1543 are in use by us. We will
+ * use the following mapping:
+ *
+ * IRQ1 - keyboard (default set by M1543)
+ * IRQ3 - reserved for UART B (default set by M1543) (note that
+ * the schematics for the DDB Vrc-5074 board seem to
+ * indicate that IRQ3 is connected to the DS1386
+ * watchdog timer interrupt output so we might have
+ * a conflict)
+ * IRQ4 - reserved for UART A (default set by M1543)
+ * IRQ5 - parallel (default set by M1543)
+ * IRQ8 - DS1386 time of day (RTC) interrupt
+ * IRQ12 - mouse
+ */
+
+ /*
+ * Assing mouse interrupt to IRQ12
+ */
+
+ /* Enter configuration mode */
+ outb(0x51, M1543_PNP_CONFIG);
+ outb(0x23, M1543_PNP_CONFIG);
+
+ /* Select logical device 7 (Keyboard) */
+ outb(0x07, M1543_PNP_INDEX);
+ outb(0x07, M1543_PNP_DATA);
+
+ /* Select IRQ12 */
+ outb(0x72, M1543_PNP_INDEX);
+ outb(0x0c, M1543_PNP_DATA);
+
+ /* Leave configration mode */
+ outb(0xbb, M1543_PNP_CONFIG);
+
+
+ /* Initialize the 8259 PIC in the M1543 */
+ i8259_init();
+
+ /* Enable the interrupt cascade */
+ nile4_enable_irq(NILE4_INT_INTE);
+
+ request_region(M1543_PNP_CONFIG, 2, "M1543 config");
+ request_region(M1543_INT1_MASTER_ELCR, 2, "pic ELCR");
+}
+
+static void nile4_irq_setup(void)
+{
+ int i;
+
+ /* Map all interrupts to CPU int #0 */
+ nile4_map_irq_all(0);
+
+ /* PCI INTA#-E# must be level triggered */
+ nile4_set_pci_irq_level_or_edge(0, 1);
+ nile4_set_pci_irq_level_or_edge(1, 1);
+ nile4_set_pci_irq_level_or_edge(2, 1);
+ nile4_set_pci_irq_level_or_edge(3, 1);
+ nile4_set_pci_irq_level_or_edge(4, 1);
+
+ /* PCI INTA#-D# must be active low, INTE# must be active high */
+ nile4_set_pci_irq_polarity(0, 0);
+ nile4_set_pci_irq_polarity(1, 0);
+ nile4_set_pci_irq_polarity(2, 0);
+ nile4_set_pci_irq_polarity(3, 0);
+ nile4_set_pci_irq_polarity(4, 1);
+
+ for (i = 0; i < 16; i++)
+ nile4_clear_irq(i);
+
+ /* Enable CPU int #0 */
+ nile4_enable_irq_output(0);
+
+ request_mem_region(NILE4_BASE, NILE4_SIZE, "Nile 4");
+}
+
+
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+
+static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL };
+
+
+void disable_irq(unsigned int irq_nr)
+{
+ if (is_i8259_irq(irq_nr))
+ i8259_disable_irq(irq_nr);
+ else
+ nile4_disable_irq(irq_to_nile4(irq_nr));
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ if (is_i8259_irq(irq_nr))
+ i8259_enable_irq(irq_nr);
+ else
+ nile4_enable_irq(irq_to_nile4(irq_nr));
+}
+
+int table[16] = { 0, };
+
+void ddb_local0_irqdispatch(struct pt_regs *regs)
+{
+ u32 mask;
+ int nile4_irq;
+#if 1
+ volatile static int nesting = 0;
+ if (nesting++ == 0)
+ ddb5074_led_d3(1);
+ ddb5074_led_hex(nesting < 16 ? nesting : 15);
+#endif
+
+ mask = nile4_get_irq_stat(0);
+ nile4_clear_irq_mask(mask);
+
+ /* Handle the timer interrupt first */
+ if (mask & (1<<NILE4_INT_GPT)) {
+ nile4_disable_irq(NILE4_INT_GPT);
+ do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs);
+ nile4_enable_irq(NILE4_INT_GPT);
+ mask &= ~(1<<NILE4_INT_GPT);
+ }
+ for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1)
+ if (mask & 1) {
+ nile4_disable_irq(nile4_irq);
+ if (nile4_irq == NILE4_INT_INTE) {
+ int i8259_irq = nile4_i8259_iack();
+ i8259_do_irq(i8259_irq, regs);
+ } else
+ do_IRQ(nile4_to_irq(nile4_irq), regs);
+ nile4_enable_irq(nile4_irq);
+ }
+
+#if 1
+ if (--nesting == 0)
+ ddb5074_led_d3(0);
+ ddb5074_led_hex(nesting < 16 ? nesting : 15);
+#endif
+}
+
+void ddb_local1_irqdispatch(void)
+{
+ printk("ddb_local1_irqdispatch called\n");
+}
+
+void ddb_buserror_irq(void)
+{
+ printk("ddb_buserror_irq called\n");
+}
+
+void ddb_8254timer_irq(void)
+{
+ printk("ddb_8254timer_irq called\n");
+}
+
+void __init ddb_irq_setup(void)
+{
+#ifdef CONFIG_REMOTE_DEBUG
+ if (remote_debug)
+ set_debug_traps();
+ breakpoint(); /* you may move this line to whereever you want :-) */
+#endif
+ request_region(0x20, 0x20, "pic1");
+ request_region(0xa0, 0x20, "pic2");
+ i8259_setup_irq(2, &irq2);
+
+ nile4_irq_setup();
+ m1543_irq_setup();
+
+ set_except_vector(0, ddbIRQ);
+}
+
diff --git a/arch/mips/ddb5074/nile4.c b/arch/mips/ddb5074/nile4.c
new file mode 100644
index 000000000..b670e78f2
--- /dev/null
+++ b/arch/mips/ddb5074/nile4.c
@@ -0,0 +1,294 @@
+/*
+ * arch/mips/ddb5074/nile4.c -- NEC Vrc-5074 Nile 4 support routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Sony Suprastructure Center Europe (SUPC-E), Brussels
+ *
+ * $Id$
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/nile4.h>
+
+
+ /*
+ * Physical Device Address Registers
+ *
+ * Note: 32 bit addressing only!
+ */
+
+void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, int on_memory_bus,
+ int visible)
+{
+ u32 maskbits;
+ u32 widthbits;
+
+ if (pdar > NILE4_BOOTCS || (pdar & 7)) {
+ printk("nile4_set_pdar: invalid pdar %d\n", pdar);
+ return;
+ }
+ if (pdar == NILE4_INTCS && size != 0x00200000) {
+ printk("nile4_set_pdar: INTCS size must be 2 MB\n");
+ return;
+ }
+ switch (size) {
+#if 0 /* We don't support 4 GB yet */
+ case 0x100000000: /* 4 GB */
+ maskbits = 4;
+ break;
+#endif
+ case 0x80000000: /* 2 GB */
+ maskbits = 5;
+ break;
+ case 0x40000000: /* 1 GB */
+ maskbits = 6;
+ break;
+ case 0x20000000: /* 512 MB */
+ maskbits = 7;
+ break;
+ case 0x10000000: /* 256 MB */
+ maskbits = 8;
+ break;
+ case 0x08000000: /* 128 MB */
+ maskbits = 9;
+ break;
+ case 0x04000000: /* 64 MB */
+ maskbits = 10;
+ break;
+ case 0x02000000: /* 32 MB */
+ maskbits = 11;
+ break;
+ case 0x01000000: /* 16 MB */
+ maskbits = 12;
+ break;
+ case 0x00800000: /* 8 MB */
+ maskbits = 13;
+ break;
+ case 0x00400000: /* 4 MB */
+ maskbits = 14;
+ break;
+ case 0x00200000: /* 2 MB */
+ maskbits = 15;
+ break;
+ case 0: /* OFF */
+ maskbits = 0;
+ break;
+ default:
+ printk("nile4_set_pdar: unsupported size %p\n", (void *)size);
+ return;
+ }
+ switch (width) {
+ case 8:
+ widthbits = 0;
+ break;
+ case 16:
+ widthbits = 1;
+ break;
+ case 32:
+ widthbits = 2;
+ break;
+ case 64:
+ widthbits = 3;
+ break;
+ default:
+ printk("nile4_set_pdar: unsupported width %d\n", width);
+ return;
+ }
+ nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) |
+ (visible ? 0x20 : 0) | (widthbits << 6) |
+ (phys & 0xffe00000));
+ nile4_out32(pdar+4, 0);
+ /*
+ * When programming a PDAR, the register should be read immediately after
+ * writing it. This ensures that address decoders are properly configured.
+ */
+ (void)nile4_in32(pdar);
+ (void)nile4_in32(pdar+4);
+}
+
+
+ /*
+ * PCI Master Registers
+ *
+ * Note: 32 bit addressing only!
+ */
+
+void nile4_set_pmr(u32 pmr, u32 type, u32 addr)
+{
+ if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) {
+ printk("nile4_set_pmr: invalid pmr %d\n", pmr);
+ return;
+ }
+ switch (type) {
+ case NILE4_PCICMD_IACK: /* PCI Interrupt Acknowledge */
+ case NILE4_PCICMD_IO: /* PCI I/O Space */
+ case NILE4_PCICMD_MEM: /* PCI Memory Space */
+ case NILE4_PCICMD_CFG: /* PCI Configuration Space */
+ break;
+ default:
+ printk("nile4_set_pmr: invalid type %d\n", type);
+ return;
+ }
+ nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000));
+ nile4_out32(pmr+4, 0);
+}
+
+
+ /*
+ * Interrupt Programming
+ */
+
+void nile4_map_irq(int nile4_irq, int cpu_irq)
+{
+ u32 offset, t;
+
+ offset = NILE4_INTCTRL;
+ if (nile4_irq >= 8) {
+ offset += 4;
+ nile4_irq -= 8;
+ }
+ t = nile4_in32(offset);
+ t &= ~(7 << (nile4_irq*4));
+ t |= cpu_irq << (nile4_irq*4);
+ nile4_out32(offset, t);
+}
+
+void nile4_map_irq_all(int cpu_irq)
+{
+ u32 all, t;
+
+ all = cpu_irq;
+ all |= all << 4;
+ all |= all << 8;
+ all |= all << 16;
+ t = nile4_in32(NILE4_INTCTRL);
+ t &= 0x88888888;
+ t |= all;
+ nile4_out32(NILE4_INTCTRL, t);
+ t = nile4_in32(NILE4_INTCTRL+4);
+ t &= 0x88888888;
+ t |= all;
+ nile4_out32(NILE4_INTCTRL+4, t);
+}
+
+void nile4_enable_irq(int nile4_irq)
+{
+ u32 offset, t;
+
+ offset = NILE4_INTCTRL;
+ if (nile4_irq >= 8) {
+ offset += 4;
+ nile4_irq -= 8;
+ }
+ t = nile4_in32(offset);
+ t |= 8 << (nile4_irq*4);
+ nile4_out32(offset, t);
+}
+
+void nile4_disable_irq(int nile4_irq)
+{
+ u32 offset, t;
+
+ offset = NILE4_INTCTRL;
+ if (nile4_irq >= 8) {
+ offset += 4;
+ nile4_irq -= 8;
+ }
+ t = nile4_in32(offset);
+ t &= ~(8 << (nile4_irq*4));
+ nile4_out32(offset, t);
+}
+
+void nile4_disable_irq_all(void)
+{
+ nile4_out32(NILE4_INTCTRL, 0);
+ nile4_out32(NILE4_INTCTRL+4, 0);
+}
+
+u16 nile4_get_irq_stat(int cpu_irq)
+{
+ return nile4_in16(NILE4_INTSTAT0+cpu_irq*2);
+}
+
+void nile4_enable_irq_output(int cpu_irq)
+{
+ u32 t;
+
+ t = nile4_in32(NILE4_INTSTAT1+4);
+ t |= 1 << (16+cpu_irq);
+ nile4_out32(NILE4_INTSTAT1, t);
+}
+
+void nile4_disable_irq_output(int cpu_irq)
+{
+ u32 t;
+
+ t = nile4_in32(NILE4_INTSTAT1+4);
+ t &= ~(1 << (16+cpu_irq));
+ nile4_out32(NILE4_INTSTAT1, t);
+}
+
+void nile4_set_pci_irq_polarity(int pci_irq, int high)
+{
+ u32 t;
+
+ t = nile4_in32(NILE4_INTPPES);
+ if (high)
+ t &= ~(1 << (pci_irq*2));
+ else
+ t |= 1 << (pci_irq*2);
+ nile4_out32(NILE4_INTPPES, t);
+}
+
+void nile4_set_pci_irq_level_or_edge(int pci_irq, int level)
+{
+ u32 t;
+
+ t = nile4_in32(NILE4_INTPPES);
+ if (level)
+ t |= 2 << (pci_irq*2);
+ else
+ t &= ~(2 << (pci_irq*2));
+ nile4_out32(NILE4_INTPPES, t);
+}
+
+void nile4_clear_irq(int nile4_irq)
+{
+ nile4_out32(NILE4_INTCLR, 1 << nile4_irq);
+}
+
+void nile4_clear_irq_mask(u32 mask)
+{
+ nile4_out32(NILE4_INTCLR, mask);
+}
+
+u8 nile4_i8259_iack(void)
+{
+ u8 irq;
+
+ /* Set window 0 for interrupt acknowledge */
+ nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0);
+ irq = *(volatile u8 *)NILE4_PCI_IACK_BASE;
+ /* Set window 0 for PCI I/O space */
+ nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0);
+ return irq;
+}
+
+#if 0
+void nile4_dump_irq_status(void)
+{
+ printk("CPUSTAT = %p:%p\n", (void *)nile4_in32(NILE4_CPUSTAT+4),
+ (void *)nile4_in32(NILE4_CPUSTAT));
+ printk("INTCTRL = %p:%p\n", (void *)nile4_in32(NILE4_INTCTRL+4),
+ (void *)nile4_in32(NILE4_INTCTRL));
+ printk("INTSTAT0 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT0+4),
+ (void *)nile4_in32(NILE4_INTSTAT0));
+ printk("INTSTAT1 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT1+4),
+ (void *)nile4_in32(NILE4_INTSTAT1));
+ printk("INTCLR = %p:%p\n", (void *)nile4_in32(NILE4_INTCLR+4),
+ (void *)nile4_in32(NILE4_INTCLR));
+ printk("INTPPES = %p:%p\n", (void *)nile4_in32(NILE4_INTPPES+4),
+ (void *)nile4_in32(NILE4_INTPPES));
+}
+#endif
diff --git a/arch/mips/ddb5074/pci.c b/arch/mips/ddb5074/pci.c
new file mode 100644
index 000000000..2fcd3fbf7
--- /dev/null
+++ b/arch/mips/ddb5074/pci.c
@@ -0,0 +1,320 @@
+/*
+ * arch/mips/ddb5074/pci.c -- NEC DDB Vrc-5074 PCI access routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Albert Dorofeev <albert@sonycom.com>
+ * Sony Suprastructure Center Europe (SUPC-E), Brussels
+ *
+ * $Id$
+ */
+
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm-mips/nile4.h>
+
+
+static u32 nile4_pre_pci_access0(int slot_num)
+{
+ u32 pci_addr = 0;
+ u32 virt_addr = NILE4_PCI_CFG_BASE;
+
+ /* Set window 1 address 8000000 - 64 bit - 2 MB (PCI config space) */
+ nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x00200000, 64, 0, 0);
+ if (slot_num > 2)
+ pci_addr = 0x00040000 << slot_num;
+ else
+ virt_addr += 0x00040000 << slot_num;
+ nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr);
+ return virt_addr;
+}
+
+static void nile4_post_pci_access0(void)
+{
+ /* Set window 1 back to address 8000000 - 64 bit - 128 MB (PCI IO space) */
+ nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 64,
+ 1, 1);
+ nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0);
+}
+
+
+static int nile4_pci_read_config_dword( struct pci_dev *dev,
+ int where, u32 *val)
+{
+ int slot_num, func_num;
+ u32 base;
+
+ /*
+ * For starters let's do configuration cycle 0 only (one bus only)
+ */
+ if (dev->bus->number)
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ if (slot_num == 5) {
+ /*
+ * This is Nile 4 and it will crash if we access it like other
+ * devices
+ */
+ *val = nile4_in32(NILE4_PCI_BASE + where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ base = nile4_pre_pci_access0(slot_num);
+ *val = *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc)));
+ nile4_post_pci_access0();
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_write_config_dword(struct pci_dev *dev, int where,
+ u32 val)
+{
+ int slot_num, func_num;
+ u32 base;
+
+ /*
+ * For starters let's do configuration cycle 0 only (one bus only)
+ */
+ if (dev->bus->number)
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ if (slot_num == 5) {
+ /*
+ * This is Nile 4 and it will crash if we access it like other
+ * devices
+ */
+ nile4_out32(NILE4_PCI_BASE + where, val);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ base = nile4_pre_pci_access0(slot_num);
+ *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc))) = val;
+ nile4_post_pci_access0();
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_read_config_word(struct pci_dev *dev, int where, u16 *val)
+{
+ int status;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xffff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, u8 *val)
+{
+ int status;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 1)
+ result >>= 8;
+ if (where & 2)
+ result >>= 16;
+ *val = result & 0xff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int nile4_pci_write_config_word(struct pci_dev *dev, int where, u16 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ shift += 16;
+ result &= ~(0xffff << shift);
+ result |= val << shift;
+ return nile4_pci_write_config_dword(dev, where, result);
+}
+
+static int nile4_pci_write_config_byte( struct pci_dev *dev, int where, u8 val)
+{
+ int status, shift = 0;
+ u32 result;
+
+ status = nile4_pci_read_config_dword(dev, where, &result);
+ if (status != PCIBIOS_SUCCESSFUL)
+ return status;
+ if (where & 2)
+ shift += 16;
+ if (where & 1)
+ shift += 8;
+ result &= ~(0xff << shift);
+ result |= val << shift;
+ return nile4_pci_write_config_dword(dev, where, result);
+}
+
+struct pci_ops nile4_pci_ops = {
+ nile4_pci_read_config_byte,
+ nile4_pci_read_config_word,
+ nile4_pci_read_config_dword,
+ nile4_pci_write_config_byte,
+ nile4_pci_write_config_word,
+ nile4_pci_write_config_dword
+};
+
+
+static void __init pcibios_claim_resources(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+ int idx;
+
+ while (bus) {
+ for (dev=bus->devices; dev; dev=dev->sibling) {
+ for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
+ struct resource *r = &dev->resource[idx];
+ struct resource *pr;
+ if (!r->start)
+ continue;
+ pr = pci_find_parent_resource(dev, r);
+ if (!pr || request_resource(pr, r) < 0) {
+ printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name);
+ /* We probably should disable the region, shouldn't we? */
+ }
+ }
+ }
+ if (bus->children)
+ pcibios_claim_resources(bus->children);
+ bus = bus->next;
+ }
+}
+
+
+void pcibios_init(void)
+{
+ printk("PCI: Probing PCI hardware\n");
+ ioport_resource.end = 0x1ffffff;
+ pci_scan_bus(0, &nile4_pci_ops, NULL);
+ pcibios_claim_resources(pci_root);
+
+#if 0
+ {
+ char buf[PAGE_SIZE];
+ printk("*** PCI Devices ***\n");
+ get_pci_list(buf);
+ printk(buf);
+ printk("*** PCI I/O Space ***\n");
+ buf[0] = '\0';
+ get_ioport_list(buf);
+ printk(buf);
+ printk("*** PCI Memory ***\n");
+ buf[0] = '\0';
+ get_mem_list(buf);
+ printk(buf);
+ }
+#endif
+}
+
+void pcibios_fixup_bus(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+ extern struct pci_dev *pci_pmu; /* for LEDs D2 and D3 */
+ u8 t8;
+
+ /*
+ * FIXME: PMON doesn't autoconfigure the PCI devices
+ * For now we just hardcode them for our configuration
+ */
+ for (dev = bus->devices; dev; dev = dev->sibling) {
+ int slot_num, func_num;
+
+ slot_num = PCI_SLOT(dev->devfn);
+ func_num = PCI_FUNC(dev->devfn);
+ printk(" Device %2d: ", slot_num);
+ switch (slot_num) {
+ case 0:
+ printk("[onboard] Acer Labs M1533 Aladdin IV\n");
+ dev->irq = nile4_to_irq(NILE4_INT_INTE);
+ break;
+ case 1:
+ printk("[onboard] DEC DC21140\n");
+ dev->irq = nile4_to_irq(NILE4_INT_INTA);
+ dev->resource[0].start = 0x100000;
+ dev->resource[0].end = dev->resource[0].start+0x7f;
+ nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
+ dev->resource[0].start);
+ dev->resource[1].start = 0x1000000;
+ dev->resource[1].end = dev->resource[1].start+0x7f;
+ nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
+ dev->resource[1].start);
+ break;
+ case 2:
+ printk("[slot 1] Realtek 8029\n");
+ dev->irq = nile4_to_irq(NILE4_INT_INTA);
+ dev->resource[0].start = 0x800000;
+ dev->resource[0].end = dev->resource[0].start+0x1f;
+ nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
+ dev->resource[0].start);
+ break;
+ case 3:
+ printk("[slot 2] DEC DC21140 (#2)\n");
+ dev->irq = nile4_to_irq(NILE4_INT_INTB);
+ dev->resource[0].start = 0x1000000;
+ dev->resource[0].end = dev->resource[0].start+0x7f;
+ nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
+ dev->resource[0].start);
+ dev->resource[1].start = 0x4000000;
+ dev->resource[1].end = dev->resource[1].start+0x7f;
+ nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
+ dev->resource[1].start);
+ break;
+ case 4:
+ printk("[slot 3] Promise Technology IDE UltraDMA/33");
+ printk(" Or 3Com 3c905 :-)\n");
+ dev->irq = nile4_to_irq(NILE4_INT_INTC);
+ dev->resource[0].start = 0x1800000;
+ dev->resource[0].end = dev->resource[0].start+0x7fffff;
+ nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
+ dev->resource[0].start);
+ break;
+ case 10:
+ printk("[onboard] Acer Labs M7101 PMU\n");
+ pci_pmu = dev;
+ /* Program the lines for LEDs D2 and D3 to output */
+ nile4_pci_read_config_byte(dev, 0x7d, &t8);
+ t8 |= 0xc0;
+ nile4_pci_write_config_byte(dev, 0x7d, t8);
+ /* Turn LEDs D2 and D3 off */
+ nile4_pci_read_config_byte(dev, 0x7e, &t8);
+ t8 |= 0xc0;
+ nile4_pci_write_config_byte(dev, 0x7e, t8);
+ break;
+ case 13:
+ printk("[onboard] Acer Labs M5237 USB\n");
+ dev->irq = nile4_to_irq(NILE4_INT_INTE);
+ dev->resource[0].start = 0x1001000;
+ dev->resource[0].end = dev->resource[0].start+0xfff;
+ nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
+ dev->resource[0].start);
+ break;
+ default:
+ printk("\n");
+ break;
+ }
+ }
+}
+
+char *pcibios_setup (char *str)
+{
+ return str;
+}
+
+struct pci_fixup pcibios_fixups[] = {};
+
diff --git a/arch/mips/ddb5074/prom.c b/arch/mips/ddb5074/prom.c
new file mode 100644
index 000000000..277d37630
--- /dev/null
+++ b/arch/mips/ddb5074/prom.c
@@ -0,0 +1,40 @@
+/*
+ * arch/mips/ddb5074/prom.c -- NEC DDB Vrc-5074 PROM routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Sony Suprastructure Center Europe (SUPC-E), Brussels
+ *
+ * $Id$
+ */
+
+#include <linux/init.h>
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+
+
+char arcs_cmdline[CL_SIZE];
+
+void __init prom_init(const char *s)
+{
+ int i = 0;
+
+// _serinit();
+
+ if (s != (void *)-1)
+ while (*s && i < sizeof(arcs_cmdline)-1)
+ arcs_cmdline[i++] = *s++;
+ arcs_cmdline[i] = '\0';
+
+ mips_machgroup = MACH_GROUP_NEC_DDB;
+ mips_machtype = MACH_NEC_DDB5074;
+ /* 64 MB non-upgradable */
+ mips_memory_upper = KSEG0+64*1024*1024;
+}
+
+void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
+{
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
diff --git a/arch/mips/ddb5074/setup.c b/arch/mips/ddb5074/setup.c
new file mode 100644
index 000000000..69a455e30
--- /dev/null
+++ b/arch/mips/ddb5074/setup.c
@@ -0,0 +1,239 @@
+/*
+ * arch/mips/ddb5074/setup.c -- NEC DDB Vrc-5074 setup routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Sony Suprastructure Center Europe (SUPC-E), Brussels
+ *
+ * $Id$
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/console.h>
+#include <linux/sched.h>
+#include <linux/mc146818rtc.h>
+#include <linux/pc_keyb.h>
+#include <linux/pci.h>
+
+#include <asm/addrspace.h>
+#include <asm/bcache.h>
+#include <asm/keyboard.h>
+#include <asm/irq.h>
+#include <asm/reboot.h>
+#include <asm/gdb-stub.h>
+#include <asm/nile4.h>
+#include <asm/ddb5074.h>
+
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void rs_kgdb_hook(int);
+extern void breakpoint(void);
+#endif
+
+#if defined(CONFIG_SERIAL_CONSOLE)
+extern void console_setup(char *);
+#endif
+
+extern struct rtc_ops ddb_rtc_ops;
+
+static void ddb_machine_restart(char *command)
+{
+ u32 t;
+
+ // FIXME: This doesn't seem to work...
+ printk("Restarting DDB Vrc-5074...");
+ /* PCI cold reset */
+ t = nile4_in32(NILE4_PCICTRL+4);
+ t |= 0x40000000;
+ nile4_out32(NILE4_PCICTRL+4, t);
+ /* CPU cold reset */
+ t = nile4_in32(NILE4_CPUSTAT);
+ t |= 1;
+ nile4_out32(NILE4_CPUSTAT, t);
+ printk("Restart failed!\n");
+ do {} while (1);
+}
+
+static void ddb_machine_halt(void)
+{
+ printk("DDB Vrc-5074 halted.\n");
+ do {} while (1);
+}
+
+static void ddb_machine_power_off(void)
+{
+ printk("DDB Vrc-5074 halted. Please turn off the power.\n");
+ do {} while (1);
+}
+
+extern void ddb_irq_setup(void);
+
+void (*board_time_init)(struct irqaction *irq);
+
+
+static void __init ddb_time_init(struct irqaction *irq)
+{
+ /* set the clock to 1 Hz */
+ nile4_out32(NILE4_T2CTRL, 1000000);
+ /* enable the General-Purpose Timer */
+ nile4_out32(NILE4_T2CTRL+4, 0x00000001);
+ /* reset timer */
+ nile4_out32(NILE4_T2CNTR, 0);
+ /* enable interrupt */
+ nile4_enable_irq(NILE4_INT_GPT);
+ i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq);
+ set_cp0_status(ST0_IM, IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
+}
+
+void __init ddb_setup(void)
+{
+ irq_setup = ddb_irq_setup;
+ mips_io_port_base = NILE4_PCI_IO_BASE;
+ isa_slot_offset = NILE4_PCI_MEM_BASE;
+ request_region(0x00, 0x20, "dma1");
+ request_region(0x40, 0x20, "timer");
+ request_region(0x70, 0x10, "rtc");
+ request_region(0x80, 0x10, "dma page reg");
+ request_region(0xc0, 0x20, "dma2");
+ board_time_init = ddb_time_init;
+
+ _machine_restart = ddb_machine_restart;
+ _machine_halt = ddb_machine_halt;
+ _machine_power_off = ddb_machine_power_off;
+
+ rtc_ops = &ddb_rtc_ops;
+}
+
+
+#define USE_NILE4_SERIAL 0
+
+#if USE_NILE4_SERIAL
+#define ns16550_in(reg) nile4_in8((reg)*8)
+#define ns16550_out(reg, val) nile4_out8((reg)*8, (val))
+#else
+#define NS16550_BASE (NILE4_PCI_IO_BASE+0x03f8)
+static inline u8 ns16550_in(u32 reg)
+{
+ return *(volatile u8 *)(NS16550_BASE+reg);
+}
+
+static inline void ns16550_out(u32 reg, u8 val)
+{
+ *(volatile u8 *)(NS16550_BASE+reg) = val;
+}
+#endif
+
+#define NS16550_RBR 0
+#define NS16550_THR 0
+#define NS16550_DLL 0
+#define NS16550_IER 1
+#define NS16550_DLM 1
+#define NS16550_FCR 2
+#define NS16550_IIR 2
+#define NS16550_LCR 3
+#define NS16550_MCR 4
+#define NS16550_LSR 5
+#define NS16550_MSR 6
+#define NS16550_SCR 7
+
+#define NS16550_LSR_DR 0x01 /* Data ready */
+#define NS16550_LSR_OE 0x02 /* Overrun */
+#define NS16550_LSR_PE 0x04 /* Parity error */
+#define NS16550_LSR_FE 0x08 /* Framing error */
+#define NS16550_LSR_BI 0x10 /* Break */
+#define NS16550_LSR_THRE 0x20 /* Xmit holding register empty */
+#define NS16550_LSR_TEMT 0x40 /* Xmitter empty */
+#define NS16550_LSR_ERR 0x80 /* Error */
+
+
+void _serinit(void)
+{
+#if USE_NILE4_SERIAL
+ ns16550_out(NS16550_LCR, 0x80);
+ ns16550_out(NS16550_DLM, 0x00);
+ ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */
+ ns16550_out(NS16550_LCR, 0x00);
+ ns16550_out(NS16550_LCR, 0x03);
+ ns16550_out(NS16550_FCR, 0x47);
+#else
+ /* done by PMON */
+#endif
+}
+
+void _putc(char c)
+{
+ while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
+ ns16550_out(NS16550_THR, c);
+ if (c == '\n') {
+ while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE));
+ ns16550_out(NS16550_THR, '\r');
+ }
+}
+
+void _puts(const char *s)
+{
+ char c;
+ while ((c = *s++))
+ _putc(c);
+}
+
+char _getc(void)
+{
+ while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR));
+ return ns16550_in(NS16550_RBR);
+}
+
+int _testc(void)
+{
+ return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0;
+}
+
+
+ /*
+ * Hexadecimal 7-segment LED
+ */
+
+void ddb5074_led_hex(int hex)
+{
+ outb(hex, 0x80);
+}
+
+
+ /*
+ * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543
+ */
+
+struct pci_dev *pci_pmu = NULL;
+
+void ddb5074_led_d2(int on)
+{
+ u8 t;
+
+ if (pci_pmu) {
+ pci_read_config_byte(pci_pmu, 0x7e, &t);
+ if (on)
+ t &= 0x7f;
+ else
+ t |= 0x80;
+ pci_write_config_byte(pci_pmu, 0x7e, t);
+ }
+}
+
+void ddb5074_led_d3(int on)
+{
+ u8 t;
+
+ if (pci_pmu) {
+ pci_read_config_byte(pci_pmu, 0x7e, &t);
+ if (on)
+ t &= 0xbf;
+ else
+ t |= 0x40;
+ pci_write_config_byte(pci_pmu, 0x7e, t);
+ }
+}
+
diff --git a/arch/mips/ddb5074/time.c b/arch/mips/ddb5074/time.c
new file mode 100644
index 000000000..7cc61eea5
--- /dev/null
+++ b/arch/mips/ddb5074/time.c
@@ -0,0 +1,35 @@
+/*
+ * arch.mips/ddb5074/time.c -- Timer routines
+ *
+ * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
+ * Sony Suprastructure Center Europe (SUPC-E), Brussels
+ *
+ * $Id*
+ */
+
+#include <linux/init.h>
+#include <asm/mc146818rtc.h>
+
+static unsigned char ddb_rtc_read_data(unsigned long addr)
+{
+ outb_p(addr, RTC_PORT(0));
+ return inb_p(RTC_PORT(1));
+}
+
+static void ddb_rtc_write_data(unsigned char data, unsigned long addr)
+{
+ outb_p(addr, RTC_PORT(0));
+ outb_p(data, RTC_PORT(1));
+}
+
+static int ddb_rtc_bcd_mode(void)
+{
+ return 1;
+}
+
+struct rtc_ops ddb_rtc_ops = {
+ ddb_rtc_read_data,
+ ddb_rtc_write_data,
+ ddb_rtc_bcd_mode
+};
+