summaryrefslogtreecommitdiff
path: root/arch/mips/cobalt
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/cobalt')
-rw-r--r--arch/mips/cobalt/Makefile7
-rw-r--r--arch/mips/cobalt/int-handler.S25
-rw-r--r--arch/mips/cobalt/irq.c102
-rw-r--r--arch/mips/cobalt/promcon.c87
-rw-r--r--arch/mips/cobalt/reset.c68
-rw-r--r--arch/mips/cobalt/setup.c150
6 files changed, 439 insertions, 0 deletions
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile
new file mode 100644
index 000000000000..a5e6554b2326
--- /dev/null
+++ b/arch/mips/cobalt/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Cobalt micro systems family specific parts of the kernel
+#
+
+obj-y := irq.o int-handler.o reset.o setup.o promcon.o
+
+EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/cobalt/int-handler.S b/arch/mips/cobalt/int-handler.S
new file mode 100644
index 000000000000..1a21dec1b3ca
--- /dev/null
+++ b/arch/mips/cobalt/int-handler.S
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 1995, 1996, 1997, 2003 by Ralf Baechle
+ * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
+ */
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/cobalt/cobalt.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+ .text
+ .align 5
+ NESTED(cobalt_handle_int, PT_SIZE, sp)
+ SAVE_ALL
+ CLI
+
+ la ra, ret_from_irq
+ move a1, sp
+ j cobalt_irq
+
+ END(cobalt_handle_int)
diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c
new file mode 100644
index 000000000000..6d2a81581397
--- /dev/null
+++ b/arch/mips/cobalt/irq.c
@@ -0,0 +1,102 @@
+/*
+ * IRQ vector handles
+ *
+ * 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.
+ *
+ * Copyright (C) 1995, 1996, 1997, 2003 by Ralf Baechle
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/i8259.h>
+#include <asm/irq_cpu.h>
+#include <asm/gt64120.h>
+#include <asm/ptrace.h>
+
+#include <asm/cobalt/cobalt.h>
+
+extern void cobalt_handle_int(void);
+
+/*
+ * We have two types of interrupts that we handle, ones that come in through
+ * the CPU interrupt lines, and ones that come in on the via chip. The CPU
+ * mappings are:
+ *
+ * 16, - Software interrupt 0 (unused) IE_SW0
+ * 17 - Software interrupt 1 (unused) IE_SW0
+ * 18 - Galileo chip (timer) IE_IRQ0
+ * 19 - Tulip 0 + NCR SCSI IE_IRQ1
+ * 20 - Tulip 1 IE_IRQ2
+ * 21 - 16550 UART IE_IRQ3
+ * 22 - VIA southbridge PIC IE_IRQ4
+ * 23 - unused IE_IRQ5
+ *
+ * The VIA chip is a master/slave 8259 setup and has the following interrupts:
+ *
+ * 8 - RTC
+ * 9 - PCI
+ * 14 - IDE0
+ * 15 - IDE1
+ */
+
+asmlinkage void cobalt_irq(struct pt_regs *regs)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause();
+
+ if (pending & CAUSEF_IP2) { /* int 18 */
+ unsigned long irq_src = GALILEO_INL(GT_INTRCAUSE_OFS);
+
+ /* Check for timer irq ... */
+ if (irq_src & GALILEO_T0EXP) {
+ /* Clear the int line */
+ GALILEO_OUTL(0, GT_INTRCAUSE_OFS);
+ do_IRQ(COBALT_TIMER_IRQ, regs);
+ }
+ return;
+ }
+
+ if (pending & CAUSEF_IP6) { /* int 22 */
+ int irq = i8259_irq();
+
+ if (irq >= 0)
+ do_IRQ(irq, regs);
+ return;
+ }
+
+ if (pending & CAUSEF_IP3) { /* int 19 */
+ do_IRQ(COBALT_ETH0_IRQ, regs);
+ return;
+ }
+
+ if (pending & CAUSEF_IP4) { /* int 20 */
+ do_IRQ(COBALT_ETH1_IRQ, regs);
+ return;
+ }
+
+ if (pending & CAUSEF_IP5) { /* int 21 */
+ do_IRQ(COBALT_SERIAL_IRQ, regs);
+ return;
+ }
+
+ if (pending & CAUSEF_IP7) { /* int 23 */
+ do_IRQ(COBALT_QUBE_SLOT_IRQ, regs);
+ return;
+ }
+}
+
+void __init arch_init_irq(void)
+{
+ set_except_vector(0, cobalt_handle_int);
+
+ init_i8259_irqs(); /* 0 ... 15 */
+ mips_cpu_irq_init(16); /* 16 ... 23 */
+
+ /*
+ * Mask all cpu interrupts
+ * (except IE4, we already masked those at VIA level)
+ */
+ change_c0_status(ST0_IM, IE_IRQ4);
+}
diff --git a/arch/mips/cobalt/promcon.c b/arch/mips/cobalt/promcon.c
new file mode 100644
index 000000000000..f03df761e9f1
--- /dev/null
+++ b/arch/mips/cobalt/promcon.c
@@ -0,0 +1,87 @@
+/*
+ * PROM console for Cobalt Raq2
+ *
+ * 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.
+ *
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
+ * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv)
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/kdev_t.h>
+#include <linux/serial_reg.h>
+
+#include <asm/delay.h>
+#include <asm/serial.h>
+#include <asm/io.h>
+
+static unsigned long port = 0xc800000;
+
+static __inline__ void ns16550_cons_put_char(char ch, unsigned long ioaddr)
+{
+ char lsr;
+
+ do {
+ lsr = inb(ioaddr + UART_LSR);
+ } while ((lsr & (UART_LSR_TEMT | UART_LSR_THRE)) != (UART_LSR_TEMT | UART_LSR_THRE));
+ outb(ch, ioaddr + UART_TX);
+}
+
+static __inline__ char ns16550_cons_get_char(unsigned long ioaddr)
+{
+ while ((inb(ioaddr + UART_LSR) & UART_LSR_DR) == 0)
+ udelay(1);
+ return inb(ioaddr + UART_RX);
+}
+
+void ns16550_console_write(struct console *co, const char *s, unsigned count)
+{
+ char lsr, ier;
+ unsigned i;
+
+ ier = inb(port + UART_IER);
+ outb(0x00, port + UART_IER);
+ for (i=0; i < count; i++, s++) {
+
+ if(*s == '\n')
+ ns16550_cons_put_char('\r', port);
+ ns16550_cons_put_char(*s, port);
+ }
+
+ do {
+ lsr = inb(port + UART_LSR);
+ } while ((lsr & (UART_LSR_TEMT | UART_LSR_THRE)) != (UART_LSR_TEMT | UART_LSR_THRE));
+
+ outb(ier, port + UART_IER);
+}
+
+char getDebugChar(void)
+{
+ return ns16550_cons_get_char(port);
+}
+
+void putDebugChar(char kgdb_char)
+{
+ ns16550_cons_put_char(kgdb_char, port);
+}
+
+static struct console ns16550_console = {
+ .name = "prom",
+ .setup = NULL,
+ .write = ns16550_console_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+static int __init ns16550_setup_console(void)
+{
+ register_console(&ns16550_console);
+
+ return 0;
+}
+
+console_initcall(ns16550_setup_console);
diff --git a/arch/mips/cobalt/reset.c b/arch/mips/cobalt/reset.c
new file mode 100644
index 000000000000..084c8e59f42c
--- /dev/null
+++ b/arch/mips/cobalt/reset.c
@@ -0,0 +1,68 @@
+/*
+ * Cobalt Reset operations
+ *
+ * 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.
+ *
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
+ * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv)
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+#include <asm/mipsregs.h>
+
+void cobalt_machine_restart(char *command)
+{
+ *(volatile char *)0xbc000000 = 0x0f;
+
+ /*
+ * Ouch, we're still alive ... This time we take the silver bullet ...
+ * ... and find that we leave the hardware in a state in which the
+ * kernel in the flush locks up somewhen during of after the PCI
+ * detection stuff.
+ */
+ set_c0_status(ST0_BEV | 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));
+}
+
+extern int led_state;
+#define kLED 0xBC000000
+#define LEDSet(x) (*(volatile unsigned char *) kLED) = (( unsigned char)x)
+
+void cobalt_machine_halt(void)
+{
+ int mark;
+
+ /* Blink our cute? little LED (number 3)... */
+ while (1) {
+ led_state = led_state | ( 1 << 3 );
+ LEDSet(led_state);
+ mark = jiffies;
+ while (jiffies<(mark+HZ));
+ led_state = led_state & ~( 1 << 3 );
+ LEDSet(led_state);
+ mark = jiffies;
+ while (jiffies<(mark+HZ));
+ }
+}
+
+/*
+ * This triggers the luser mode device driver for the power switch ;-)
+ */
+void cobalt_machine_power_off(void)
+{
+ printk("You can switch the machine off now.\n");
+ cobalt_machine_halt();
+}
diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
new file mode 100644
index 000000000000..6b4737e425ed
--- /dev/null
+++ b/arch/mips/cobalt/setup.c
@@ -0,0 +1,150 @@
+/*
+ * Setup pointers to hardware dependent routines.
+ *
+ * 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.
+ *
+ * Copyright (C) 1996, 1997, 2004 by Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
+ *
+ */
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/gt64120.h>
+
+#include <asm/cobalt/cobalt.h>
+
+extern void cobalt_machine_restart(char *command);
+extern void cobalt_machine_halt(void);
+extern void cobalt_machine_power_off(void);
+
+int cobalt_board_id;
+
+static char my_cmdline[CL_SIZE] = {
+ "console=ttyS0,115200 "
+#ifdef CONFIG_IP_PNP
+ "ip=on "
+#endif
+#ifdef CONFIG_ROOT_NFS
+ "root=/dev/nfs "
+#else
+ "root=/dev/hda1 "
+#endif
+ };
+
+const char *get_system_type(void)
+{
+ return "MIPS Cobalt";
+}
+
+static void __init cobalt_timer_setup(struct irqaction *irq)
+{
+ /* Load timer value for 150 Hz */
+ GALILEO_OUTL(500000, GT_TC0_OFS);
+
+ /* Register our timer interrupt */
+ setup_irq(COBALT_TIMER_IRQ, irq);
+
+ /* Enable timer ints */
+ GALILEO_OUTL((GALILEO_ENTC0 | GALILEO_SELTC0), GT_TC_CONTROL_OFS);
+ /* Unmask timer int */
+ GALILEO_OUTL(0x100, GT_INTRMASK_OFS);
+}
+
+extern struct pci_ops gt64111_pci_ops;
+
+static struct resource cobalt_mem_resource = {
+ "GT64111 PCI MEM", GT64111_IO_BASE, 0xffffffffUL, IORESOURCE_MEM
+};
+
+static struct resource cobalt_io_resource = {
+ "GT64111 IO MEM", 0x00001000UL, 0x0fffffffUL, IORESOURCE_IO
+};
+
+static struct resource cobalt_io_resources[] = {
+ { "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
+ { "timer", 0x40, 0x5f, IORESOURCE_BUSY },
+ { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY },
+ { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
+ { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
+};
+
+#define COBALT_IO_RESOURCES (sizeof(cobalt_io_resources)/sizeof(struct resource))
+
+static struct pci_controller cobalt_pci_controller = {
+ .pci_ops = &gt64111_pci_ops,
+ .mem_resource = &cobalt_mem_resource,
+ .mem_offset = 0,
+ .io_resource = &cobalt_io_resource,
+ .io_offset = 0x00001000UL - GT64111_IO_BASE
+};
+
+static void __init cobalt_setup(void)
+{
+ unsigned int devfn = PCI_DEVFN(COBALT_PCICONF_VIA, 0);
+ int i;
+
+ _machine_restart = cobalt_machine_restart;
+ _machine_halt = cobalt_machine_halt;
+ _machine_power_off = cobalt_machine_power_off;
+
+ board_timer_setup = cobalt_timer_setup;
+
+ set_io_port_base(KSEG1ADDR(GT64111_IO_BASE));
+
+ /*
+ * This is a prom style console. We just poke at the
+ * UART to make it talk.
+ * Only use this console if you really screw up and can't
+ * get to the stage of setting up a real serial console.
+ */
+ /*ns16550_setup_console();*/
+
+ /* request I/O space for devices used on all i[345]86 PCs */
+ for (i = 0; i < COBALT_IO_RESOURCES; i++)
+ request_resource(&ioport_resource, cobalt_io_resources + i);
+
+ /* Read the cobalt id register out of the PCI config space */
+ PCI_CFG_SET(devfn, (VIA_COBALT_BRD_ID_REG & ~0x3));
+ cobalt_board_id = GALILEO_INL(GT_PCI0_CFGDATA_OFS);
+ cobalt_board_id >>= ((VIA_COBALT_BRD_ID_REG & 3) * 8);
+ cobalt_board_id = VIA_COBALT_BRD_REG_to_ID(cobalt_board_id);
+
+#ifdef CONFIG_PCI
+ register_pci_controller(&cobalt_pci_controller);
+#endif
+}
+
+early_initcall(cobalt_setup);
+
+/*
+ * Prom init. We read our one and only communication with the firmware.
+ * Grab the amount of installed memory
+ */
+
+void __init prom_init(void)
+{
+ int argc = fw_arg0;
+
+ strcpy(arcs_cmdline, my_cmdline);
+
+ mips_machgroup = MACH_GROUP_COBALT;
+
+ add_memory_region(0x0, argc & 0x7fffffff, BOOT_MEM_RAM);
+}
+
+unsigned long __init prom_free_prom_memory(void)
+{
+ /* Nothing to do! */
+ return 0;
+}