From c4ed38a0c6e2e5c4906296758f816ee71373792f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 21 Feb 2005 16:18:36 +0000 Subject: Resurrect Cobalt support for 2.6. Signed-off-by: Ralf Baechle --- arch/mips/Makefile | 1 + arch/mips/cobalt/Makefile | 2 +- arch/mips/cobalt/int-handler.S | 4 +- arch/mips/cobalt/irq.c | 111 +++++++++++++++++++++++++++-------------- arch/mips/cobalt/promcon.c | 87 -------------------------------- arch/mips/cobalt/reset.c | 59 +++++++++++----------- arch/mips/cobalt/setup.c | 100 ++++++++++++++++++++++++++----------- arch/mips/pci/fixup-cobalt.c | 55 ++++++++++++++++++-- arch/mips/pci/ops-gt64111.c | 10 ++-- 9 files changed, 233 insertions(+), 196 deletions(-) delete mode 100644 arch/mips/cobalt/promcon.c (limited to 'arch') diff --git a/arch/mips/Makefile b/arch/mips/Makefile index dbd79bef34a..5f2dfcddb9f 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -323,6 +323,7 @@ load-$(CONFIG_MIPS_XXS1500) += 0xffffffff80100000 # Cobalt Server # core-$(CONFIG_MIPS_COBALT) += arch/mips/cobalt/ +cflags-$(CONFIG_MIPS_COBALT) += -Iinclude/asm-mips/cobalt load-$(CONFIG_MIPS_COBALT) += 0xffffffff80080000 # diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile index a5e6554b232..3b6b7579d1d 100644 --- a/arch/mips/cobalt/Makefile +++ b/arch/mips/cobalt/Makefile @@ -2,6 +2,6 @@ # 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 +obj-y := irq.o int-handler.o reset.o setup.o EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/cobalt/int-handler.S b/arch/mips/cobalt/int-handler.S index 1a21dec1b3c..f92608e8d84 100644 --- a/arch/mips/cobalt/int-handler.S +++ b/arch/mips/cobalt/int-handler.S @@ -18,8 +18,8 @@ SAVE_ALL CLI - la ra, ret_from_irq - move a1, sp + PTR_LA ra, ret_from_irq + move a0, sp j cobalt_irq END(cobalt_handle_int) diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c index 6d2a8158139..0d90851f925 100644 --- a/arch/mips/cobalt/irq.c +++ b/arch/mips/cobalt/irq.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include @@ -25,8 +27,8 @@ extern void cobalt_handle_int(void); * 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 + * 16 - Software interrupt 0 (unused) IE_SW0 + * 17 - Software interrupt 1 (unused) IE_SW1 * 18 - Galileo chip (timer) IE_IRQ0 * 19 - Tulip 0 + NCR SCSI IE_IRQ1 * 20 - Tulip 1 IE_IRQ2 @@ -42,61 +44,94 @@ extern void cobalt_handle_int(void); * 15 - IDE1 */ -asmlinkage void cobalt_irq(struct pt_regs *regs) +static inline void galileo_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; - } + unsigned int mask, pending, devfn; - if (pending & CAUSEF_IP6) { /* int 22 */ - int irq = i8259_irq(); + mask = GALILEO_INL(GT_INTRMASK_OFS); + pending = GALILEO_INL(GT_INTRCAUSE_OFS) & mask; - if (irq >= 0) - do_IRQ(irq, regs); - return; - } + if (pending & GALILEO_INTR_T0EXP) { - if (pending & CAUSEF_IP3) { /* int 19 */ - do_IRQ(COBALT_ETH0_IRQ, regs); - return; - } + GALILEO_OUTL(~GALILEO_INTR_T0EXP, GT_INTRCAUSE_OFS); + do_IRQ(COBALT_GALILEO_IRQ, regs); - if (pending & CAUSEF_IP4) { /* int 20 */ - do_IRQ(COBALT_ETH1_IRQ, regs); - return; - } + } else if (pending & GALILEO_INTR_RETRY_CTR) { - if (pending & CAUSEF_IP5) { /* int 21 */ - do_IRQ(COBALT_SERIAL_IRQ, regs); - return; - } + devfn = GALILEO_INL(GT_PCI0_CFGADDR_OFS) >> 8; + GALILEO_OUTL(~GALILEO_INTR_RETRY_CTR, GT_INTRCAUSE_OFS); + printk(KERN_WARNING "Galileo: PCI retry count exceeded (%02x.%u)\n", + PCI_SLOT(devfn), PCI_FUNC(devfn)); + + } else { - if (pending & CAUSEF_IP7) { /* int 23 */ - do_IRQ(COBALT_QUBE_SLOT_IRQ, regs); - return; + GALILEO_OUTL(mask & ~pending, GT_INTRMASK_OFS); + printk(KERN_WARNING "Galileo: masking unexpected interrupt %08x\n", pending); } } +static inline void via_pic_irq(struct pt_regs *regs) +{ + int irq; + + irq = i8259_irq(); + if (irq >= 0) + do_IRQ(irq, regs); +} + +asmlinkage void cobalt_irq(struct pt_regs *regs) +{ + unsigned pending; + + pending = read_c0_status() & read_c0_cause(); + + if (pending & CAUSEF_IP2) /* COBALT_GALILEO_IRQ (18) */ + + galileo_irq(regs); + + else if (pending & CAUSEF_IP6) /* COBALT_VIA_IRQ (22) */ + + via_pic_irq(regs); + + else if (pending & CAUSEF_IP3) /* COBALT_ETH0_IRQ (19) */ + + do_IRQ(COBALT_CPU_IRQ + 3, regs); + + else if (pending & CAUSEF_IP4) /* COBALT_ETH1_IRQ (20) */ + + do_IRQ(COBALT_CPU_IRQ + 4, regs); + + else if (pending & CAUSEF_IP5) /* COBALT_SERIAL_IRQ (21) */ + + do_IRQ(COBALT_CPU_IRQ + 5, regs); + + else if (pending & CAUSEF_IP7) /* IRQ 23 */ + + do_IRQ(COBALT_CPU_IRQ + 7, regs); +} + +static struct irqaction irq_via = { + no_action, 0, { { 0, } }, "cascade", NULL, NULL +}; + void __init arch_init_irq(void) { + /* + * Mask all Galileo interrupts. The Galileo + * handler is set in cobalt_timer_setup() + */ + GALILEO_OUTL(0, GT_INTRMASK_OFS); + set_except_vector(0, cobalt_handle_int); init_i8259_irqs(); /* 0 ... 15 */ - mips_cpu_irq_init(16); /* 16 ... 23 */ + mips_cpu_irq_init(COBALT_CPU_IRQ); /* 16 ... 23 */ /* * Mask all cpu interrupts * (except IE4, we already masked those at VIA level) */ change_c0_status(ST0_IM, IE_IRQ4); + + setup_irq(COBALT_VIA_IRQ, &irq_via); } diff --git a/arch/mips/cobalt/promcon.c b/arch/mips/cobalt/promcon.c deleted file mode 100644 index f03df761e9f..00000000000 --- a/arch/mips/cobalt/promcon.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 -#include -#include -#include - -#include -#include -#include - -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 index 084c8e59f42..805a0e88507 100644 --- a/arch/mips/cobalt/reset.c +++ b/arch/mips/cobalt/reset.c @@ -16,48 +16,45 @@ #include #include #include +#include -void cobalt_machine_restart(char *command) +void cobalt_machine_halt(void) { - *(volatile char *)0xbc000000 = 0x0f; + int state, last, diff; + unsigned long mark; /* - * 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. + * turn off bar on Qube, flash power off LED on RaQ (0.5Hz) + * + * restart if ENTER and SELECT are pressed */ - 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) + last = COBALT_KEY_PORT; -void cobalt_machine_halt(void) -{ - int mark; + for (state = 0;;) { + + state ^= COBALT_LED_POWER_OFF; + COBALT_LED_PORT = state; + + diff = COBALT_KEY_PORT ^ last; + last ^= diff; - /* 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)); + if((diff & (COBALT_KEY_ENTER | COBALT_KEY_SELECT)) && !(~last & (COBALT_KEY_ENTER | COBALT_KEY_SELECT))) + COBALT_LED_PORT = COBALT_LED_RESET; + + for (mark = jiffies; jiffies - mark < HZ;) + ; } } +void cobalt_machine_restart(char *command) +{ + COBALT_LED_PORT = COBALT_LED_RESET; + + /* we should never get here */ + cobalt_machine_halt(); +} + /* * This triggers the luser mode device driver for the power switch ;-) */ diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index f8138c15a53..d358a118fa3 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -21,6 +23,7 @@ #include #include #include +#include #include @@ -30,45 +33,44 @@ 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) { + switch (cobalt_board_id) { + case COBALT_BRD_ID_QUBE1: + return "Cobalt Qube"; + case COBALT_BRD_ID_RAQ1: + return "Cobalt RaQ"; + case COBALT_BRD_ID_QUBE2: + return "Cobalt Qube2"; + case COBALT_BRD_ID_RAQ2: + return "Cobalt RaQ2"; + } return "MIPS Cobalt"; } static void __init cobalt_timer_setup(struct irqaction *irq) { - /* Load timer value for 150 Hz */ - GALILEO_OUTL(500000, GT_TC0_OFS); + /* Load timer value for 1KHz (TCLK is 50MHz) */ + GALILEO_OUTL(50*1000*1000 / 1000, GT_TC0_OFS); - /* Register our timer interrupt */ - setup_irq(COBALT_TIMER_IRQ, irq); + /* Enable timer */ + GALILEO_OUTL(GALILEO_ENTC0 | GALILEO_SELTC0, GT_TC_CONTROL_OFS); - /* Enable timer ints */ - GALILEO_OUTL((GALILEO_ENTC0 | GALILEO_SELTC0), GT_TC_CONTROL_OFS); - /* Unmask timer int */ - GALILEO_OUTL(0x100, GT_INTRMASK_OFS); + /* Register interrupt */ + setup_irq(COBALT_GALILEO_IRQ, irq); + + /* Enable interrupt */ + GALILEO_OUTL(GALILEO_INTR_T0EXP | GALILEO_INL(GT_INTRMASK_OFS), 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 + "PCI memory", GT64111_MEM_BASE, GT64111_MEM_END, IORESOURCE_MEM }; static struct resource cobalt_io_resource = { - "GT64111 IO MEM", 0x00001000UL, 0x0fffffffUL, IORESOURCE_IO + "PCI I/O", 0x1000, 0xffff, IORESOURCE_IO }; static struct resource cobalt_io_resources[] = { @@ -86,11 +88,12 @@ static struct pci_controller cobalt_pci_controller = { .mem_resource = &cobalt_mem_resource, .mem_offset = 0, .io_resource = &cobalt_io_resource, - .io_offset = 0x00001000UL - GT64111_IO_BASE + .io_offset = 0 - GT64111_IO_BASE }; void __init plat_setup(void) { + static struct uart_port uart; unsigned int devfn = PCI_DEVFN(COBALT_PCICONF_VIA, 0); int i; @@ -100,7 +103,10 @@ void __init plat_setup(void) board_timer_setup = cobalt_timer_setup; - set_io_port_base(KSEG1ADDR(GT64111_IO_BASE)); + set_io_port_base(CKSEG1ADDR(GT64111_IO_BASE)); + + /* I/O port resource must include UART and LCD/buttons */ + ioport_resource.end = 0x0fffffff; /* * This is a prom style console. We just poke at the @@ -120,25 +126,61 @@ void __init plat_setup(void) cobalt_board_id >>= ((VIA_COBALT_BRD_ID_REG & 3) * 8); cobalt_board_id = VIA_COBALT_BRD_REG_to_ID(cobalt_board_id); + printk("Cobalt board ID: %d\n", cobalt_board_id); + #ifdef CONFIG_PCI register_pci_controller(&cobalt_pci_controller); #endif + +#ifdef CONFIG_SERIAL_8250 + if (cobalt_board_id > COBALT_BRD_ID_RAQ1) { + + uart.line = 0; + uart.type = PORT_UNKNOWN; + uart.uartclk = 18432000; + uart.irq = COBALT_SERIAL_IRQ; + uart.flags = STD_COM_FLAGS; + uart.iobase = 0xc800000; + uart.iotype = UPIO_PORT; + + early_serial_setup(&uart); + } +#endif } /* * Prom init. We read our one and only communication with the firmware. - * Grab the amount of installed memory + * Grab the amount of installed memory. + * Better boot loaders (CoLo) pass a command line too :-) */ void __init prom_init(void) { - int argc = fw_arg0; - - strcpy(arcs_cmdline, my_cmdline); + int narg, indx, posn, nchr; + unsigned long memsz; + char **argv; mips_machgroup = MACH_GROUP_COBALT; - add_memory_region(0x0, argc & 0x7fffffff, BOOT_MEM_RAM); + memsz = fw_arg0 & 0x7fff0000; + narg = fw_arg0 & 0x0000ffff; + + if (narg) { + arcs_cmdline[0] = '\0'; + argv = (char **) fw_arg1; + posn = 0; + for (indx = 1; indx < narg; ++indx) { + nchr = strlen(argv[indx]); + if (posn + 1 + nchr + 1 > sizeof(arcs_cmdline)) + break; + if (posn) + arcs_cmdline[posn++] = ' '; + strcpy(arcs_cmdline + posn, argv[indx]); + posn += nchr; + } + } + + add_memory_region(0x0, memsz, BOOT_MEM_RAM); } unsigned long __init prom_free_prom_memory(void) diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c index 57e1ca2116b..909292f50d0 100644 --- a/arch/mips/pci/fixup-cobalt.c +++ b/arch/mips/pci/fixup-cobalt.c @@ -21,6 +21,20 @@ extern int cobalt_board_id; +static void qube_raq_galileo_early_fixup(struct pci_dev *dev) +{ + if (dev->devfn == PCI_DEVFN(0, 0) && + (dev->class >> 8) == PCI_CLASS_MEMORY_OTHER) { + + dev->class = (PCI_CLASS_BRIDGE_HOST << 8) | (dev->class & 0xff); + + printk(KERN_INFO "Galileo: fixed bridge class\n"); + } +} + +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111, + qube_raq_galileo_early_fixup); + static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev) { unsigned short cfgword; @@ -48,6 +62,9 @@ static void qube_raq_galileo_fixup(struct pci_dev *dev) { unsigned short galileo_id; + if (dev->devfn != PCI_DEVFN(0, 0)) + return; + /* Fix PCI latency-timer and cache-line-size values in Galileo * host bridge. */ @@ -55,6 +72,13 @@ static void qube_raq_galileo_fixup(struct pci_dev *dev) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 7); /* + * The code described by the comment below has been removed + * as it causes bus mastering by the Ethernet controllers + * to break under any kind of network load. We always set + * the retry timeouts to their maximum. + * + * --x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x--x-- + * * On all machines prior to Q2, we had the STOP line disconnected * from Galileo to VIA on PCI. The new Galileo does not function * correctly unless we have it connected. @@ -64,21 +88,43 @@ static void qube_raq_galileo_fixup(struct pci_dev *dev) */ pci_read_config_word(dev, PCI_REVISION_ID, &galileo_id); galileo_id &= 0xff; /* mask off class info */ + + printk(KERN_INFO "Galileo: revision %u\n", galileo_id); + +#if 0 if (galileo_id >= 0x10) { /* New Galileo, assumes PCI stop line to VIA is connected. */ GALILEO_OUTL(0x4020, GT_PCI0_TOR_OFS); - } else if (galileo_id == 0x1 || galileo_id == 0x2) { + } else if (galileo_id == 0x1 || galileo_id == 0x2) +#endif + { signed int timeo; /* XXX WE MUST DO THIS ELSE GALILEO LOCKS UP! -DaveM */ timeo = GALILEO_INL(GT_PCI0_TOR_OFS); /* Old Galileo, assumes PCI STOP line to VIA is disconnected. */ - GALILEO_OUTL(0xffff, GT_PCI0_TOR_OFS); + GALILEO_OUTL( + (0xff << 16) | /* retry count */ + (0xff << 8) | /* timeout 1 */ + 0xff, /* timeout 0 */ + GT_PCI0_TOR_OFS); + + /* enable PCI retry exceeded interrupt */ + GALILEO_OUTL(GALILEO_INTR_RETRY_CTR | GALILEO_INL(GT_INTRMASK_OFS), GT_INTRMASK_OFS); } } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_GALILEO, PCI_ANY_ID, +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111, qube_raq_galileo_fixup); +static char irq_tab_qube1[] __initdata = { + [COBALT_PCICONF_CPU] = 0, + [COBALT_PCICONF_ETH0] = COBALT_QUBE1_ETH0_IRQ, + [COBALT_PCICONF_RAQSCSI] = COBALT_SCSI_IRQ, + [COBALT_PCICONF_VIA] = 0, + [COBALT_PCICONF_PCISLOT] = COBALT_QUBE_SLOT_IRQ, + [COBALT_PCICONF_ETH1] = 0 +}; + static char irq_tab_cobalt[] __initdata = { [COBALT_PCICONF_CPU] = 0, [COBALT_PCICONF_ETH0] = COBALT_ETH0_IRQ, @@ -99,6 +145,9 @@ static char irq_tab_raq2[] __initdata = { int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { + if (cobalt_board_id < COBALT_BRD_ID_QUBE2) + return irq_tab_qube1[slot]; + if (cobalt_board_id == COBALT_BRD_ID_RAQ2) return irq_tab_raq2[slot]; diff --git a/arch/mips/pci/ops-gt64111.c b/arch/mips/pci/ops-gt64111.c index c5b0fc184c2..c1807934768 100644 --- a/arch/mips/pci/ops-gt64111.c +++ b/arch/mips/pci/ops-gt64111.c @@ -18,15 +18,15 @@ #include /* - * Accessing device 31 hangs the GT64120. Not sure if this will also hang - * the GT64111, let's be paranoid for now. + * Device 31 on the GT64111 is used to generate PCI special + * cycles, so we shouldn't expected to find a device there ... */ static inline int pci_range_ck(struct pci_bus *bus, unsigned int devfn) { - if (bus->number == 0 && devfn == PCI_DEVFN(31, 0)) - return -1; + if (bus->number == 0 && PCI_SLOT(devfn) < 31) + return 0; - return 0; + return -1; } static int gt64111_pci_read_config(struct pci_bus *bus, unsigned int devfn, -- cgit v1.2.3