diff options
Diffstat (limited to 'arch/mips/cobalt')
-rw-r--r-- | arch/mips/cobalt/Makefile | 7 | ||||
-rw-r--r-- | arch/mips/cobalt/int-handler.S | 25 | ||||
-rw-r--r-- | arch/mips/cobalt/irq.c | 102 | ||||
-rw-r--r-- | arch/mips/cobalt/promcon.c | 87 | ||||
-rw-r--r-- | arch/mips/cobalt/reset.c | 68 | ||||
-rw-r--r-- | arch/mips/cobalt/setup.c | 150 |
6 files changed, 439 insertions, 0 deletions
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile new file mode 100644 index 00000000000..a5e6554b232 --- /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 00000000000..1a21dec1b3c --- /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 00000000000..6d2a8158139 --- /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 00000000000..f03df761e9f --- /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 00000000000..084c8e59f42 --- /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 00000000000..6b4737e425e --- /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 = >64111_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; +} |