summaryrefslogtreecommitdiffstats
path: root/arch/mips/cobalt
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-06-15 17:19:55 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-06-15 17:19:55 +0000
commit5660fe08b83ac8470924ad01f49d36e6779cc689 (patch)
treebde60c61fe3a0ee9b643f802d35051dbeb917e53 /arch/mips/cobalt
parent53b3988d474435254a3b053a68bb24ce9e439295 (diff)
First round of Cobalt patches from Mathew Edward Kovach.
Diffstat (limited to 'arch/mips/cobalt')
-rw-r--r--arch/mips/cobalt/.cvsignore2
-rw-r--r--arch/mips/cobalt/Makefile24
-rw-r--r--arch/mips/cobalt/cobaltscc.c350
-rw-r--r--arch/mips/cobalt/diagdefs.h177
-rw-r--r--arch/mips/cobalt/hw-access.c58
-rw-r--r--arch/mips/cobalt/int-handler.S140
-rw-r--r--arch/mips/cobalt/pci.c348
-rw-r--r--arch/mips/cobalt/reset.c60
-rw-r--r--arch/mips/cobalt/serial.h28
-rw-r--r--arch/mips/cobalt/setup.c411
-rw-r--r--arch/mips/cobalt/via.c90
-rw-r--r--arch/mips/cobalt/z8530.h219
12 files changed, 1907 insertions, 0 deletions
diff --git a/arch/mips/cobalt/.cvsignore b/arch/mips/cobalt/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/arch/mips/cobalt/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile
new file mode 100644
index 000000000..088e1d269
--- /dev/null
+++ b/arch/mips/cobalt/Makefile
@@ -0,0 +1,24 @@
+#
+# Makefile for the Cobalt micro systems family specific parts of the kernel
+#
+# 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).
+#
+# $Id: Makefile,v 1.1 1997/10/23 22:25:41 ralf Exp $
+#
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+all: cobalt.o
+O_TARGET := cobalt.o
+O_OBJS := cobaltscc.o hw-access.o int-handler.o pci.o reset.o setup.o via.o
+
+int-handler.o: int-handler.S
+
+clean:
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/mips/cobalt/cobaltscc.c b/arch/mips/cobalt/cobaltscc.c
new file mode 100644
index 000000000..05002a130
--- /dev/null
+++ b/arch/mips/cobalt/cobaltscc.c
@@ -0,0 +1,350 @@
+/*
+ * Filename: cobaltscc.c
+ *
+ * Description: Functions for supporting and testing serial I/O
+ *
+ * Author(s): Timothy Stonis
+ *
+ * Copyright 1997, Cobalt Microserver, Inc.
+ */
+#include "z8530.h"
+#include "diagdefs.h"
+#include "serial.h"
+#include "asm/io.h"
+
+/*
+ * Function prototypes
+ */
+void InitSerialPort(unsigned char *);
+void RegisterDelay(void);
+void InitScc(void);
+
+/*
+ * Function: RegisterDelay
+ *
+ * Description: A little delay since the SCC can't handle quick consecutive
+ * accesses
+ * In: none
+ * Out: none
+ */
+void RegisterDelay(void)
+{
+ register int ctr;
+
+ for(ctr=0;ctr<0x40;ctr++);
+}
+
+/*
+ * Function: SccInit
+ *
+ * Description: Initialize all the SCC registers for 19200 baud, asynchronous,
+ * 8 bit, 1 stop bit, no parity communication (Channel A)
+ *
+ * In: none
+ *
+ * Out: none
+ */
+void InitScc(void)
+{
+ /* Force hardware reset */
+ Write8530(kSCC_ChanA | kSCC_Command, R9 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, FHWRES);
+ RegisterDelay();
+
+ /* x32 clock, 1 stop bit, no parity */
+ Write8530(kSCC_ChanA | kSCC_Command, R4 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, X16CLK | SB1);
+ RegisterDelay();
+
+ /* Rx 8 bits, Rx disabled */
+ Write8530(kSCC_ChanA | kSCC_Command, R3 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, Rx8);
+ RegisterDelay();
+
+ /* Tx 8 bits, DTR, RTS, Tx off */
+ Write8530(kSCC_ChanA | kSCC_Command, R5 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, Tx8 | DTR | RTS);
+ RegisterDelay();
+
+ /* Int. Disabled */
+ Write8530(kSCC_ChanA | kSCC_Command, R9 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, 0x0);
+ RegisterDelay();
+
+ /* NRZ */
+ Write8530(kSCC_ChanA | kSCC_Command, R10 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, NRZ);
+ RegisterDelay();
+
+ /* Tx & Rx = BRG out, TRxC = BRG out */
+ Write8530(kSCC_ChanA | kSCC_Command, R11 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, TCBR | RCBR | TRxCBR | TRxCOI);
+ RegisterDelay();
+
+ /* Time constant = 0x01 */
+ Write8530(kSCC_ChanA | kSCC_Command, R12 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, kSCC_115200 );
+ RegisterDelay();
+
+ /* Time constant high = 0x00 */
+ Write8530(kSCC_ChanA | kSCC_Command, R13 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, 0x00);
+ RegisterDelay();
+
+ /* BRG in = ~RTxC, BRG off, loopback */
+ Write8530(kSCC_ChanA | kSCC_Command, R14 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, LOOPBAK | BRSRC);
+ RegisterDelay();
+}
+
+/*
+ * Function: EnableScc
+ *
+ * Description: Enable transmit and receive on SCC Channel A
+ * In: none
+ * Out: none
+ */
+void EnableScc(void)
+{
+ /* Enable BRG */
+ Write8530(kSCC_ChanA | kSCC_Command, R14 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, BRENABL | BRSRC);
+ RegisterDelay();
+
+ /* Rx enable (Rx 8 bits) */
+ Write8530(kSCC_ChanA | kSCC_Command, R3 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, RxENABLE | Rx8);
+ RegisterDelay();
+
+ /* Tx enable (Tx8, DTR, RTS) */
+ Write8530(kSCC_ChanA | kSCC_Command, R5 | NULLCODE);
+ RegisterDelay();
+ Write8530(kSCC_ChanA, TxENAB | Tx8 | DTR | RTS);
+ RegisterDelay();
+}
+
+/*
+ * Function: SccOutb
+ *
+ * Description: Write a byte to the SCC (Channel A) and blink LED
+ * In: Byte to send
+ * Out: none
+ */
+void SccOutb(unsigned char byte)
+{
+ /* LED on.. */
+ Write8530(kSCC_ChanB | kSCC_Command, R5);
+ RegisterDelay();
+ Write8530(kSCC_ChanB | kSCC_Command, RTS);
+ RegisterDelay();
+
+ while ((Read8530(kSCC_ChanA) & Tx_BUF_EMP) == 0)
+ RegisterDelay();
+
+ Write8530(kSCC_ChanA | kSCC_Direct, byte);
+ RegisterDelay();
+
+ /* LED off.. */
+ Write8530(kSCC_ChanB | kSCC_Command, R9);
+ RegisterDelay();
+ Write8530(kSCC_ChanB | kSCC_Command, CHRB);
+ RegisterDelay();
+}
+
+/*
+ * Function: SccInb
+ *
+ * Description: Read a byte from the SCC (Channel A)
+ * In: Byte to send
+ * Out: none
+ */
+void SccInb(unsigned char *byte)
+{
+ while ((Read8530(kSCC_ChanA) & Rx_CH_AV) == 0)
+ RegisterDelay();
+
+ *byte = Read8530(kSCC_ChanA | kSCC_Direct);
+ RegisterDelay();
+}
+
+/*
+ * Function: SccWrite
+ *
+ * Description: Write a null terminated string to the SCC
+ * In: C string
+ * Out: none
+ */
+void SccWrite(const unsigned char *string)
+{
+ while((*string) != 0) {
+ if (*string == 10)
+ SccOutb((unsigned char) 13);
+ SccOutb(*(string++));
+ }
+}
+
+/*
+ * Function: InitSerialPort
+ *
+ * Description: Initialize the SCC and spit out the header message
+ * In: Header message
+ * Out: none
+ */
+void InitSerialPort(unsigned char *msg)
+{
+ InitScc();
+ EnableScc();
+ SccWrite(msg);
+}
+
+/*
+ * Function: SccInbTimeout
+ *
+ * Description: Read a byte from the SCC (Channel A) with timeout
+ * In: Byte to send
+ * Out: Timeout status
+ */
+unsigned char SccInbTimeout(unsigned char *byte, unsigned long timeout)
+{
+ unsigned long ctr = 0;
+
+ while ((Read8530(kSCC_ChanA) & Rx_CH_AV) == 0) {
+ RegisterDelay();
+ if ((ctr++) > timeout)
+ return 0xFF;
+ }
+
+ *byte = Read8530(kSCC_ChanA | kSCC_Direct);
+ RegisterDelay();
+
+ return 0;
+}
+
+#include <linux/serial_reg.h>
+
+extern int serial_echo_init (int base);
+extern int serial_echo_print (const char *s);
+
+/*
+ * this defines the address for the port to which printk echoing is done
+ * when CONFIG_SERIAL_ECHO is defined
+ */
+#define SERIAL_ECHO_PORT 0x1C800000
+
+static int serial_echo_port = 0;
+
+#define serial_echo_outb(v,a) outb((v),(a)+serial_echo_port)
+#define serial_echo_inb(a) inb((a)+serial_echo_port)
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/* Wait for transmitter & holding register to empty */
+#define WAIT_FOR_XMITR \
+ do { \
+ lsr = serial_echo_inb(UART_LSR); \
+ } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
+
+/*
+ * These two functions abstract the actual communications with the
+ * debug port. This is so we can change the underlying communications
+ * mechanism without modifying the rest of the code.
+ */
+int
+serial_echo_print(const char *s)
+{
+ int lsr, ier;
+ int i;
+
+ if (!serial_echo_port)
+ return 0;
+
+ /*
+ * First save the IER then disable the interrupts
+ */
+ ier = serial_echo_inb(UART_IER);
+ serial_echo_outb(0x00, UART_IER);
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; *s; i++, s++) {
+ WAIT_FOR_XMITR;
+
+ /* Send the character out. */
+ serial_echo_outb(*s, UART_TX);
+
+ /* if a LF, also do CR... */
+ if (*s == 10) {
+ WAIT_FOR_XMITR;
+ serial_echo_outb(13, UART_TX);
+ }
+ }
+
+ /*
+ * Finally, Wait for transmitter & holding register to empty
+ * and restore the IER
+ */
+ do {
+ lsr = serial_echo_inb(UART_LSR);
+ } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
+ serial_echo_outb(ier, UART_IER);
+
+ return 0;
+}
+
+
+int
+serial_echo_init(int base)
+{
+ int comstat, hi, lo;
+
+ serial_echo_port = base;
+
+ /*
+ * read the Divisor Latch
+ */
+ comstat = serial_echo_inb(UART_LCR);
+ serial_echo_outb(comstat | UART_LCR_DLAB, UART_LCR);
+ hi = serial_echo_inb(UART_DLM);
+ lo = serial_echo_inb(UART_DLL);
+ serial_echo_outb(comstat, UART_LCR);
+
+ /*
+ * now do hardwired init
+ */
+ serial_echo_outb(0x03, UART_LCR); /* No parity, 8 data bits, 1 stop */
+ serial_echo_outb(0x83, UART_LCR); /* Access divisor latch */
+
+ /* This is computed using:
+ *
+ * const BASE_BAUD = (18432000 / 16);
+ * UART_DLM = (BASE_BAUD / baud_I_want) >> 8;
+ * UART_DLL = (BASE_BAUD / baud_I_want) & 0xff;
+ */
+ serial_echo_outb(0x00, UART_DLM); /* 115200 baud */
+ serial_echo_outb(0x0A, UART_DLL);
+
+ serial_echo_outb(0x03, UART_LCR); /* Done with divisor */
+
+ /*
+ * Prior to disabling interrupts, read the LSR and RBR
+ * registers
+ */
+ comstat = serial_echo_inb(UART_LSR); /* COM? LSR */
+ comstat = serial_echo_inb(UART_RX); /* COM? RBR */
+ serial_echo_outb(0x00, UART_IER); /* Disable all interrupts */
+
+ return 0;
+}
diff --git a/arch/mips/cobalt/diagdefs.h b/arch/mips/cobalt/diagdefs.h
new file mode 100644
index 000000000..6bfedbd5a
--- /dev/null
+++ b/arch/mips/cobalt/diagdefs.h
@@ -0,0 +1,177 @@
+/*
+ * Filename: diagdefs.h
+ *
+ * Description: Some general definitions used by the diagnostics
+ *
+ * Author(s): Timothy Stonis
+ *
+ * Copyright 1997, Cobalt Microserver, Inc.
+ */
+
+#define KSEG0_Base 0x80000000
+#define KSEG1_Base 0xA0000000
+
+// Some useful Galileo registers/base addresses (boot time kseg1 mapping)
+#define kGal_InternalBase ( 0x14000000 | KSEG1_Base )
+#define kGal_DevBank0Base ( 0x1C000000 | KSEG1_Base )
+#define kGal_DevBank1Base ( 0x1C800000 | KSEG1_Base )
+
+#define kGal_RAS10Lo 0x008
+#define kGal_RAS10Hi 0x010
+#define kGal_RAS32Lo 0x018
+#define kGal_RAS32Hi 0x020
+
+#define kGal_PCIIOLo 0x048
+#define kGal_PCIIOHi 0x050
+
+#define kGal_RAS10LoCfg 0x000
+#define kGal_RAS10HiCfg 0x03
+#define kGal_RAS32LoCfg 0x004
+#define kGal_RAS32HiCfg 0x07
+
+#define kGal_PCIIOLoCfg 0x000
+#define kGal_PCIIOHiCfg 0x0F
+
+
+#define kGal_DevBank0PReg 0x45C
+#define kGal_DevBank1PReg 0x460
+#define kGal_DevBank2PReg 0x464
+#define kGal_DevBank3PReg 0x468
+#define kGal_DevBankBPReg 0x46C
+
+#define kGal_DRAMCReg 0x448
+#define kGal_DRAM0PReg 0x44C
+#define kGal_DRAM1PReg 0x450
+#define kGal_DRAM2PReg 0x454
+#define kGal_DRAM3PReg 0x458
+
+#define kGal_ConfigAddr 0xCF8
+#define kGal_ConfigData 0xCFC
+#define kGal_PCICfgEn 0x1F // Generate config cycle
+#define kGal_DevNum 0x00 // Technically 0x06, but 0 works too
+#define kGal_MasMemEn 0x06
+#define kGal_Latency 0x700
+
+#define kGal_RAS01StartReg 0x10
+#define kGal_RAS23StartReg 0x14
+#define kGal_RAS01SizeReg 0x0C08
+#define kGal_RAS23SizeReg 0x0C0C
+
+
+#define kGal_RAS01Start 0x000
+#define kGal_RAS23Start 0x00800000
+#define kGal_RAS01Size 0x007FFFFF
+#define kGal_RAS23Size 0x007FFFFF
+
+
+// Paramter information for devices, DRAM, etc
+#define kGal_DevBank0Cfg 0x1446DB33
+#define kGal_DevBank1Cfg 0x144FE667
+#define kGal_DevBankBCfg 0x1446DC43
+#define kGal_DRAMConfig 0x00000300
+#define kGal_DRAM0Config 0x00000010
+#define kGal_DRAM1Config 0x00000010
+#define kGal_DRAM2Config 0x00000010
+#define kGal_DRAM3Config 0x00000010
+
+#define kGal_DRAM0Hi 0x00000003
+#define kGal_DRAM0Lo 0x00000000
+#define kGal_DRAM1Hi 0x00000007
+#define kGal_DRAM1Lo 0x00000004
+#define kGal_DRAM2Hi 0x0000000B
+#define kGal_DRAM2Lo 0x00000008
+#define kGal_DRAM3Hi 0x0000000F
+#define kGal_DRAM3Lo 0x0000000C
+
+#define kGal_RAS0Lo 0x400
+#define kGal_RAS0Hi 0x404
+#define kGal_RAS1Lo 0x408
+#define kGal_RAS1Hi 0x40C
+#define kGal_RAS2Lo 0x410
+#define kGal_RAS2Hi 0x414
+#define kGal_RAS3Lo 0x418
+#define kGal_RAS3Hi 0x41C
+
+// Feedback LED indicators during setup code (reset.S, main.c)
+#define kLED_AllOn 0x0F
+#define kLED_FlashTest 0x01
+#define kLED_MemTest 0x02
+#define kLED_SCCTest 0x03
+#define kLED_GalPCI 0x04
+#define kLED_EnetTest 0x05
+#define kLED_SCSITest 0x06
+#define kLED_IOCTest 0x07
+#define kLED_Quickdone 0x0A
+#define kLED_Exception 0x0B
+#define kLED_ProcInit 0x0E
+#define kLED_AllOff 0x00
+
+#define kLEDBase kGal_DevBank0Base
+
+// Some memory related constants
+#define kRAM_Start (0x00000000 | KSEG0_Base)
+
+#define kTestPat1 0xA5A5A5A5
+#define kTestPat2 0x5A5A5A5A
+
+#define k1Meg_kseg1 (0x00100000 | KSEG0_Base)
+#define k2Meg_kseg1 (0x00200000 | KSEG0_Base)
+#define k4Meg_kseg1 (0x00400000 | KSEG0_Base)
+#define k8Meg_kseg1 (0x00800000 | KSEG0_Base)
+#define k16Meg_kseg1 (0x01000000 | KSEG0_Base)
+
+#define kInit_SP k4Meg_kseg1 - 0x100
+#define kVectorBase 0x200
+#define kDebugVectors 0x400
+#define kMallocCheese 0x80E00000
+#define kDecompAddr 0x80700000
+#define kCompAddr 0x80500000
+
+
+// Ethernet definitions
+#define kEnet_VIOBase ( 0x12100000 | KSEG1_Base )
+#define kEnet_PIOBase 0x12100000
+#define kEnet_CSCfg 0x46
+#define kEnet_DevNum 0x07
+#define kEnet_CSR3 0x18
+#define kEnet_CSR15 0x78
+
+
+#define kEnet_GEPOut 0x080f0000
+#define kEnet_GEPOn 0x000f0000
+
+
+// SCSI definitions
+#define kSCSI_VIOBase ( 0x12200000 | KSEG1_Base )
+#define kSCSI_PIOBase 0x12200000
+#define kSCSI_CSCfg 0x46
+#define kSCSI_DevNum 0x08
+#define kSCSI_GPCNTL 0x47
+#define kSCSI_GPREG 0x07
+#define kSCSI_SCRTCHA 0x34
+
+#define kSCSI_GPIOOut 0x0C
+#define kSCSI_LEDsOn 0x00
+
+// I/O Controller definitions
+#define kIOC_VIOBase ( 0x10000000 | KSEG1_Base )
+#define kIOC_RIOBase 0x10000000
+#define kIOC_DevNum 0x09
+#define kIOC_ISAFunc 0x00
+#define kIOC_IDEFunc 0x01
+#define kIOC_USBFunc 0x02
+#define kIOC_MiscC0 0x44
+#define kIOC_IDEEnable 0x40
+
+#define kIOC_PCIIDEOn 0x02800085
+#define kIOC_PriIDEOn 0x0A
+
+// Some PCI Definitions
+#define kPCI_StatCmd 0x04
+#define kPCI_LatCache 0x0C
+#define kPCI_CBIO 0x10
+#define kPCI_CBMEM 0x14
+
+// Random constants
+#define kBogoSec 0x0003F940
+#define kSCCDelay 0x00000001
diff --git a/arch/mips/cobalt/hw-access.c b/arch/mips/cobalt/hw-access.c
new file mode 100644
index 000000000..968dfefb8
--- /dev/null
+++ b/arch/mips/cobalt/hw-access.c
@@ -0,0 +1,58 @@
+/*
+ * Low-level hardware access stuff for Cobalt Microserver 27 board.
+ *
+ * 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
+ */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/linkage.h>
+#include <linux/types.h>
+#include <asm/cachectl.h>
+#include <asm/cobalt.h>
+#include <asm/segment.h>
+#include <asm/vector.h>
+
+void
+dummy(void)
+{
+ panic("What the hell is this called for?");
+}
+
+static unsigned char cobalt_read_cmos(unsigned long reg)
+{
+ unsigned char retval;
+
+ VIA_PORT_WRITE(0x70, reg);
+ retval = VIA_PORT_READ(0x71);
+ VIA_DELAY();
+
+ return retval;
+}
+
+static void cobalt_write_cmos(unsigned char val, unsigned long reg)
+{
+ VIA_PORT_WRITE(0x70, reg);
+ VIA_PORT_WRITE(0x71, val);
+}
+
+struct feature cobalt_feature = {
+ /*
+ * How to access the floppy controller's ports
+ */
+ (void *)dummy, (void *)dummy,
+ /*
+ * How to access the floppy DMA functions.
+ */
+ (void *)dummy, (void *)dummy, (void *)dummy, (void *)dummy,
+ (void *)dummy, (void *)dummy, (void *)dummy, (void *)dummy,
+ (void *)dummy, (void *)dummy, (void *)dummy,
+ /*
+ * How to access the RTC functions.
+ */
+ cobalt_read_cmos,
+ cobalt_write_cmos
+};
diff --git a/arch/mips/cobalt/int-handler.S b/arch/mips/cobalt/int-handler.S
new file mode 100644
index 000000000..66c0d78c7
--- /dev/null
+++ b/arch/mips/cobalt/int-handler.S
@@ -0,0 +1,140 @@
+/*
+ * arch/mips/cobalt/int-handler.S
+ */
+#include <asm/asm.h>
+#include <asm/mipsconfig.h>
+#include <asm/mipsregs.h>
+#include <asm/cobalt.h>
+#include <asm/irq.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+/*
+ * cobalt_handle_int: Interrupt handler for the twenty-seven board.
+ */
+ .align 5
+ .set noreorder
+ NESTED(cobalt_handle_int, PT_SIZE, ra)
+ .set noat
+ SAVE_ALL
+ REG_S sp,PT_OR2(sp)
+ CLI
+ .set at
+ mfc0 t0,CP0_CAUSE
+ mfc0 t1,CP0_STATUS
+ and t0,t1
+ xor t1,t0
+ mtc0 t1,CP0_STATUS # mask all active ints
+ /* Such a kind of cascade is optimal for R5000 */
+
+ andi t1,t0,STATUSF_IP2
+ bnez t1,ll_galileo_irq
+ andi t1,t0,STATUSF_IP3
+ bnez t1,ll_ethernet0_irq
+/*
+ * This should be conditional, and not used for the cube-1, but
+ * there is not a config flag that is useful.
+ */
+
+ andi t1,t0,STATUSF_IP4
+ bnez t1,ll_ethernet1_irq
+/* #endif */
+ andi t1,t0,STATUSF_IP6
+ bnez t1,ll_via_irq
+ andi t1,t0,STATUSF_IP5
+ bnez t1,ll_serial_irq
+ andi t1,t0,STATUSF_IP7
+ bnez t1,ll_pci_irq
+ nop
+ /* wrong alarm ... */
+ j spurious_interrupt
+ nop
+ END(cobalt_handle_int)
+
+
+ .align 5
+ .set reorder
+ll_galileo_irq: move a0,sp
+ INC_INTR_COUNT(s1,s2)
+ jal galileo_irq
+ nop
+ DEC_INTR_COUNT(s1,s2)
+ j ret_from_irq
+ nop
+
+ .align 5
+ .set reorder
+ll_via_irq: move a0,sp
+ INC_INTR_COUNT(s1,s2)
+ jal via_irq
+ nop
+ DEC_INTR_COUNT(s1,s2)
+ j ret_from_irq
+ nop
+
+ .align 5
+ .set reorder
+ll_ethernet0_irq:
+ INC_INTR_COUNT(s1,s2)
+ mfc0 s0,CP0_STATUS # mask interrupt
+ ori t0,s0,(STATUSF_IP3 | STATUSF_IP4)
+ xori t0,(STATUSF_IP3 | STATUSF_IP4)
+ mtc0 t0,CP0_STATUS
+ li a0,4
+ move a1,sp
+ jal do_IRQ
+ nop
+ mtc0 s0,CP0_STATUS
+ DEC_INTR_COUNT(s1,s2)
+ j ret_from_irq
+ nop
+
+ .align 5
+ .set reorder
+ll_serial_irq: li a0,7
+ INC_INTR_COUNT(s1,s2)
+ move a1,sp
+ jal do_IRQ
+ nop
+ DEC_INTR_COUNT(s1,s2)
+ j ret_from_irq
+ nop
+
+
+ .align 5
+ .set reorder
+ll_ethernet1_irq:
+ INC_INTR_COUNT(s1,s2)
+ mfc0 s0,CP0_STATUS # mask interrupt
+
+ ori t0,s0, (STATUSF_IP3 | STATUSF_IP4)
+ xori t0,(STATUSF_IP3 | STATUSF_IP4)
+
+ mtc0 t0,CP0_STATUS
+ li a0,13
+ move a1,sp
+ jal do_IRQ
+ nop
+ mtc0 s0,CP0_STATUS
+ DEC_INTR_COUNT(s1,s2)
+ j ret_from_irq
+ nop
+
+ #
+ # This is pretty weird. The "pci" interrupt on the hardware
+ # skematic is from the PCI side of the galileo, so we would
+ # only get interrupts here if WE write the control register
+ # that normally enables the cpu to send interrupts to the PCI.
+ #
+ # If you want to interrupt a PCI card, look elsewhere.
+ #
+ .align 5
+ .set reorder
+ll_pci_irq: li a0,7
+ INC_INTR_COUNT(s1,s2)
+ move a1,sp
+ jal do_IRQ
+ nop
+ DEC_INTR_COUNT(s1,s2)
+ j ret_from_irq
+ nop
diff --git a/arch/mips/cobalt/pci.c b/arch/mips/cobalt/pci.c
new file mode 100644
index 000000000..a325ad7b9
--- /dev/null
+++ b/arch/mips/cobalt/pci.c
@@ -0,0 +1,348 @@
+/*
+ * 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.
+ *
+ * Cobalt Qube specific PCI support.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <asm/cobalt.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+
+#undef PCI_DEBUG
+
+#ifdef CONFIG_PCI
+
+static void qube_expansion_slot_bist(void)
+{
+ unsigned char ctrl;
+ int timeout = 100000;
+
+ pcibios_read_config_byte(0, (0x0a<<3), PCI_BIST, &ctrl);
+ if(!(ctrl & PCI_BIST_CAPABLE))
+ return;
+
+ pcibios_write_config_byte(0, (0x0a<<3), PCI_BIST, ctrl|PCI_BIST_START);
+ do {
+ pcibios_read_config_byte(0, (0x0a<<3), PCI_BIST, &ctrl);
+ if(!(ctrl & PCI_BIST_START))
+ break;
+ } while(--timeout > 0);
+ if((timeout <= 0) || (ctrl & PCI_BIST_CODE_MASK))
+ printk("PCI: Expansion slot card failed BIST with code %x\n",
+ (ctrl & PCI_BIST_CODE_MASK));
+}
+
+static void qube_expansion_slot_fixup(void)
+{
+ unsigned short pci_cmd;
+ unsigned long ioaddr_base = 0x10108000; /* It's magic, ask Doug. */
+ unsigned long memaddr_base = 0x12000000;
+ int i;
+
+ /* Enable bits in COMMAND so driver can talk to it. */
+ pcibios_read_config_word(0, (0x0a<<3), PCI_COMMAND, &pci_cmd);
+ pci_cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ pcibios_write_config_word(0, (0x0a<<3), PCI_COMMAND, pci_cmd);
+
+ /* Give it a working IRQ. */
+ pcibios_write_config_byte(0, (0x0a<<3), PCI_INTERRUPT_LINE, 9);
+
+ /* Fixup base addresses, we only support I/O at the moment. */
+ for(i = 0; i <= 5; i++) {
+ unsigned int regaddr = (PCI_BASE_ADDRESS_0 + (i * 4));
+ unsigned int rval, mask, size, alignme, aspace;
+ unsigned long *basep = &ioaddr_base;
+
+ /* Check type first, punt if non-IO. */
+ pcibios_read_config_dword(0, (0x0a<<3), regaddr, &rval);
+ aspace = (rval & PCI_BASE_ADDRESS_SPACE);
+ if(aspace != PCI_BASE_ADDRESS_SPACE_IO)
+ basep = &memaddr_base;
+
+ /* Figure out how much it wants, if anything. */
+ pcibios_write_config_dword(0, (0x0a<<3), regaddr, 0xffffffff);
+ pcibios_read_config_dword(0, (0x0a<<3), regaddr, &rval);
+
+ /* Unused? */
+ if(rval == 0)
+ continue;
+
+ rval &= PCI_BASE_ADDRESS_IO_MASK;
+ mask = (~rval << 1) | 0x1;
+ size = (mask & rval) & 0xffffffff;
+ alignme = size;
+ if(alignme < 0x400)
+ alignme = 0x400;
+ rval = ((*basep + (alignme - 1)) & ~(alignme - 1));
+ *basep = (rval + size);
+ pcibios_write_config_dword(0, (0x0a<<3), regaddr, rval | aspace);
+ }
+ qube_expansion_slot_bist();
+}
+
+static void qube_raq_tulip_fixup(void)
+{
+ unsigned short pci_cmd;
+
+ /* Enable the device. */
+ pcibios_read_config_word(0, (0x0c<<3), PCI_COMMAND, &pci_cmd);
+ pci_cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MASTER);
+ pcibios_write_config_word(0, (0x0c<<3), PCI_COMMAND, pci_cmd);
+
+ /* Give it it's IRQ. */
+ /* NOTE: RaQ board #1 has a bunch of green wires which swapped the
+ * IRQ line values of Tulip 0 and Tulip 1. All other
+ * boards have eth0=4,eth1=13. -DaveM
+ */
+#ifndef RAQ_BOARD_1_WITH_HWHACKS
+ pcibios_write_config_byte(0, (0x0c<<3), PCI_INTERRUPT_LINE, 13);
+#else
+ pcibios_write_config_byte(0, (0x0c<<3), PCI_INTERRUPT_LINE, 4);
+#endif
+
+ /* And finally, a usable I/O space allocation, right after what
+ * the first Tulip uses.
+ */
+ pcibios_write_config_dword(0, (0x0c<<3), PCI_BASE_ADDRESS_0, 0x10101001);
+}
+
+static void qube_raq_scsi_fixup(void)
+{
+ unsigned short pci_cmd;
+
+ /* Enable the device. */
+ pcibios_read_config_word(0, (0x08<<3), PCI_COMMAND, &pci_cmd);
+
+ pci_cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
+ | PCI_COMMAND_INVALIDATE);
+ pcibios_write_config_word(0, (0x08<<3), PCI_COMMAND, pci_cmd);
+
+ /* Give it it's IRQ. */
+ pcibios_write_config_byte(0, (0x08<<3), PCI_INTERRUPT_LINE, 4);
+
+ /* And finally, a usable I/O space allocation, right after what
+ * the second Tulip uses.
+ */
+ pcibios_write_config_dword(0, (0x08<<3), PCI_BASE_ADDRESS_0, 0x10102001);
+ pcibios_write_config_dword(0, (0x08<<3), PCI_BASE_ADDRESS_1, 0x00002000);
+ pcibios_write_config_dword(0, (0x08<<3), PCI_BASE_ADDRESS_2, 0x00100000);
+}
+
+static unsigned long
+qube_pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
+{
+ extern int cobalt_is_raq;
+ int raq_p = cobalt_is_raq;
+ unsigned int tmp;
+
+ /* Fixup I/O and Memory space decoding on Galileo. */
+ isa_slot_offset = COBALT_LOCAL_IO_SPACE;
+
+ /* Fix PCI latency-timer and cache-line-size values in Galileo
+ * host bridge.
+ */
+ pcibios_write_config_byte(0, 0, PCI_LATENCY_TIMER, 64);
+ pcibios_write_config_byte(0, 0, PCI_CACHE_LINE_SIZE, 7);
+
+ /*
+ * Now tell the SCSI device that we expect an interrupt at
+ * IRQ 7 and not the default 0.
+ */
+ pcibios_write_config_byte(0, 0x08<<3, PCI_INTERRUPT_LINE,
+ COBALT_SCSI_IRQ);
+
+ /*
+ * Now tell the Ethernet device that we expect an interrupt at
+ * IRQ 13 and not the default 189.
+ *
+ * The IRQ of the first Tulip is different on Qube and RaQ
+ * hardware except for the weird first RaQ bringup board,
+ * see above for details. -DaveM
+ */
+ if (! raq_p) {
+ /* All Qube's route this the same way. */
+ pcibios_write_config_byte(0, 0x07<<3, PCI_INTERRUPT_LINE,
+ COBALT_ETHERNET_IRQ);
+ } else {
+#ifndef RAQ_BOARD_1_WITH_HWHACKS
+ pcibios_write_config_byte(0, (0x07<<3), PCI_INTERRUPT_LINE, 4);
+#else
+ pcibios_write_config_byte(0, (0x07<<3), PCI_INTERRUPT_LINE, 13);
+#endif
+ }
+
+ if (! raq_p) {
+ /* See if there is a device in the expansion slot, if so
+ * fixup IRQ, fix base addresses, and enable master +
+ * I/O + memory accesses in config space.
+ */
+ pcibios_read_config_dword(0, 0x0a<<3, PCI_VENDOR_ID, &tmp);
+ if(tmp != 0xffffffff && tmp != 0x00000000)
+ qube_expansion_slot_fixup();
+ } else {
+ /* If this is a RAQ, we may need to setup the second Tulip
+ * and SCSI as well. Due to the different configurations
+ * a RaQ can have, we need to explicitly check for the
+ * presence of each of these (optional) devices. -DaveM
+ */
+ pcibios_read_config_dword(0, 0x0c<<3, PCI_VENDOR_ID, &tmp);
+ if(tmp != 0xffffffff && tmp != 0x00000000)
+ qube_raq_tulip_fixup();
+
+ pcibios_read_config_dword(0, 0x08<<3, PCI_VENDOR_ID, &tmp);
+ if(tmp != 0xffffffff && tmp != 0x00000000)
+ qube_raq_scsi_fixup();
+
+ /* And if we are a 2800 we have to setup the expansion slot
+ * too.
+ */
+ pcibios_read_config_dword(0, 0x0a<<3, PCI_VENDOR_ID, &tmp);
+ if(tmp != 0xffffffff && tmp != 0x00000000)
+ qube_expansion_slot_fixup();
+ }
+
+ return mem_start;
+}
+
+static __inline__ int pci_range_ck(unsigned char bus, unsigned char dev)
+{
+ if ((bus == 0) && ( (dev==0) || ((dev>6) && (dev <= 12))) )
+ return 0; /* OK device number */
+
+ return -1; /* NOT ok device number */
+}
+
+#define PCI_CFG_DATA ((volatile unsigned long *)0xb4000cfc)
+#define PCI_CFG_CTRL ((volatile unsigned long *)0xb4000cf8)
+
+#define PCI_CFG_SET(dev,fun,off) \
+ ((*PCI_CFG_CTRL) = (0x80000000 | ((dev)<<11) | \
+ ((fun)<<8) | (off)))
+
+static int qube_pcibios_read_config_dword (unsigned char bus,
+ unsigned char dev,
+ unsigned char offset,
+ unsigned int *val)
+{
+ unsigned char fun = dev & 0x07;
+
+ dev >>= 3;
+ if (offset & 0x3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (pci_range_ck(bus, dev)) {
+ *val = 0xFFFFFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ PCI_CFG_SET(dev, fun, offset);
+ *val = *PCI_CFG_DATA;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int qube_pcibios_read_config_word (unsigned char bus,
+ unsigned char dev,
+ unsigned char offset,
+ unsigned short *val)
+{
+ unsigned char fun = dev & 0x07;
+
+ dev >>= 3;
+ if (offset & 0x1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (pci_range_ck(bus, dev)) {
+ *val = 0xffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ PCI_CFG_SET(dev, fun, (offset & ~0x3));
+ *val = *PCI_CFG_DATA >> ((offset & 3) * 8);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int qube_pcibios_read_config_byte (unsigned char bus,
+ unsigned char dev,
+ unsigned char offset,
+ unsigned char *val)
+{
+ unsigned char fun = dev & 0x07;
+
+ dev >>= 3;
+ if (pci_range_ck(bus, dev)) {
+ *val = 0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ PCI_CFG_SET(dev, fun, (offset & ~0x3));
+ *val = *PCI_CFG_DATA >> ((offset & 3) * 8);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int qube_pcibios_write_config_dword (unsigned char bus,
+ unsigned char dev,
+ unsigned char offset,
+ unsigned int val)
+{
+ unsigned char fun = dev & 0x07;
+
+ dev >>= 3;
+ if(offset & 0x3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (pci_range_ck(bus, dev))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ PCI_CFG_SET(dev, fun, offset);
+ *PCI_CFG_DATA = val;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+qube_pcibios_write_config_word (unsigned char bus, unsigned char dev,
+ unsigned char offset, unsigned short val)
+{
+ unsigned char fun = dev & 0x07;
+ unsigned long tmp;
+
+ dev >>= 3;
+ if (offset & 0x1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (pci_range_ck(bus, dev))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ PCI_CFG_SET(dev, fun, (offset & ~0x3));
+ tmp = *PCI_CFG_DATA;
+ tmp &= ~(0xffff << ((offset & 0x3) * 8));
+ tmp |= (val << ((offset & 0x3) * 8));
+ *PCI_CFG_DATA = tmp;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+qube_pcibios_write_config_byte (unsigned char bus, unsigned char dev,
+ unsigned char offset, unsigned char val)
+{
+ unsigned char fun = dev & 0x07;
+ unsigned long tmp;
+
+ dev >>= 3;
+ if (pci_range_ck(bus, dev))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ PCI_CFG_SET(dev, fun, (offset & ~0x3));
+ tmp = *PCI_CFG_DATA;
+ tmp &= ~(0xff << ((offset & 0x3) * 8));
+ tmp |= (val << ((offset & 0x3) * 8));
+ *PCI_CFG_DATA = tmp;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops qube_pci_ops = {
+ qube_pcibios_fixup,
+ qube_pcibios_read_config_byte,
+ qube_pcibios_read_config_word,
+ qube_pcibios_read_config_dword,
+ qube_pcibios_write_config_byte,
+ qube_pcibios_write_config_word,
+ qube_pcibios_write_config_dword
+};
+
+#endif /* CONFIG_PCI */
diff --git a/arch/mips/cobalt/reset.c b/arch/mips/cobalt/reset.c
new file mode 100644
index 000000000..b91c51fe5
--- /dev/null
+++ b/arch/mips/cobalt/reset.c
@@ -0,0 +1,60 @@
+/*
+ * Reset a Cobalt Qube.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/reboot.h>
+#include <asm/system.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_cp0_status((ST0_BEV | ST0_ERL), (ST0_BEV | ST0_ERL));
+ set_cp0_config(CONFIG_CM_CMASK, CONFIG_CM_UNCACHED);
+ flush_cache_all();
+ write_32bit_cp0_register(CP0_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/serial.h b/arch/mips/cobalt/serial.h
new file mode 100644
index 000000000..586f68f8c
--- /dev/null
+++ b/arch/mips/cobalt/serial.h
@@ -0,0 +1,28 @@
+/*
+ *
+ * Filename: serial.h
+ *
+ * Description: Some general definitions used for serial code
+ *
+ * Author(s): Timothy Stonis
+ *
+ * Copyright 1997, Cobalt Microserver, Inc.
+ */
+
+/*
+ * Serial port definitions
+ */
+#define kSCC_Base kGal_DevBank1Base
+#define kHelloWorldMsg "Cobalt Networks Diagnostics - 'We serve it, you surf it'\n\r"
+#define kSCC_ChanA 0x01
+#define kSCC_ChanB 0x00
+#define kSCC_Direct 0x02
+#define kSCC_Command 0x00
+
+#define kSCC_TestVal 0xA5
+#define kSCC_19200 0x07 /* x32 clock mode, 19200 baud */
+#define kSCC_115200 0x01 /* x16 clock mode, 115200 baud */
+
+#define Read8530(n) (*((unsigned char *) (kSCC_Base | (n))))
+
+#define Write8530(x,y) (*((unsigned char *) (kSCC_Base | (x))) = (y))
diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
new file mode 100644
index 000000000..cb11a59c9
--- /dev/null
+++ b/arch/mips/cobalt/setup.c
@@ -0,0 +1,411 @@
+/*
+ * Setup pointers to hardware dependand 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 by Ralf Baechle
+ */
+#include <linux/bios32.h>
+#include <linux/config.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/timex.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/cobalt.h>
+#include <asm/pci.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/reboot.h>
+#include <asm/vector.h>
+
+extern void cobalt_machine_restart(char *command);
+extern void cobalt_machine_halt(void);
+extern void cobalt_machine_power_off(void);
+
+extern int serial_console;
+
+/*
+ * Initial irq handlers.
+ */
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+}
+
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL};
+
+extern struct feature cobalt_feature;
+extern asmlinkage void cobalt_handle_int(void);
+
+static void cobalt_irq_setup(void)
+{
+ /*
+ * Clear all of the interrupts while we change the able around a bit.
+ */
+ set_cp0_status(ST0_IM, 0);
+
+ /* Sets the exception_handler array. */
+ set_except_vector(0, cobalt_handle_int);
+
+ request_region(0xb0000020, 0x20, "pic1");
+ request_region(0xb00000A0, 0x20, "pic2");
+ setup_x86_irq(2, &irq2);
+
+ cli();
+
+ set_cp0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1 | IE_IRQ0);
+
+ /* Setup VIA irq mask */
+ VIA_PORT_WRITE(0x20, 0x10);
+ VIA_PORT_WRITE(0x21, 0x00);
+ VIA_PORT_WRITE(0x21, 0x00);
+
+ VIA_PORT_WRITE(0xa0, 0x10);
+ VIA_PORT_WRITE(0xa1, 0x00);
+ VIA_PORT_WRITE(0xa1, 0x00);
+}
+
+void (*board_time_init)(struct irqaction *irq);
+
+static void cobalt_calibrate_timer(void)
+{
+ volatile unsigned long *timer_reg = (volatile unsigned long *)0xb4000850;
+
+ /* Default to 150MHZ, since this is what we are shipping. */
+ *timer_reg = 500000;
+}
+
+static void cobalt_time_init(struct irqaction *irq)
+{
+ /* Load timer value for 100 Hz */
+ cobalt_calibrate_timer();
+ /* *((volatile unsigned long *) 0xb4000850) = (unsigned long) 440000; */
+
+ setup_x86_irq(0, irq);
+
+ /* Enable timer ints */
+ *((volatile unsigned long *) 0xb4000864) = (unsigned long) 0x00000003;
+ /* Unmask timer int */
+ *((volatile unsigned long *) 0xb4000c1c) = (unsigned long) 0x00000100;
+}
+
+extern struct pci_ops qube_pci_ops;
+int cobalt_serial_present;
+int cobalt_serial_type;
+int cobalt_is_raq;
+
+void cobalt_setup(void)
+{
+ tag *atag;
+
+ /*
+ * We just check if a tag_screen_info can be gathered
+ * in setup_arch(), if yes we don't proceed futher...
+ */
+ atag = bi_TagFind(tag_screen_info);
+ if (!atag) {
+ /*
+ * If no, we try to find the tag_arc_displayinfo which is
+ * always created by Milo for an ARC box (for now Milo only
+ * works on ARC boxes :) -Stoned.
+ */
+ atag = bi_TagFind(tag_arcdisplayinfo);
+ if (atag) {
+
+ screen_info.orig_x =
+ ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_x;
+ screen_info.orig_y =
+ ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_y;
+ screen_info.orig_video_cols =
+ ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->columns;
+ screen_info.orig_video_lines =
+ ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->lines;
+ }
+ }
+
+ _machine_restart = cobalt_machine_restart;
+ _machine_halt = cobalt_machine_halt;
+ _machine_power_off = cobalt_machine_power_off;
+
+ irq_setup = cobalt_irq_setup;
+ board_time_init = cobalt_time_init;
+ feature = &cobalt_feature;
+ mips_io_port_base = COBALT_LOCAL_IO_SPACE;
+
+ pci_ops = &qube_pci_ops;
+
+#ifdef CONFIG_COBALT_SERIAL
+ serial_console = 1;
+#endif /* CONFIG_COBALT_SERIAL */
+
+ /* We have to do this early, here, before the value could
+ * possibly be overwritten by the bootup sequence.
+ */
+ cobalt_serial_present = *((unsigned long *) 0xa020001c);
+ cobalt_serial_type = *((unsigned long *) 0xa0200020);
+ cobalt_is_raq = (cobalt_serial_present != 0x0
+ && cobalt_serial_type == 0x1);
+}
+
+void AddTagsEndSymbol(void);
+int bi_TagAdd (enum bi_tag type, unsigned long size, void *data);
+unsigned long next_tag = (unsigned long) NULL;
+unsigned long memory_upper = (unsigned long) NULL;
+
+int bi_TagAdd (enum bi_tag type, unsigned long size, void *data)
+{
+ tag t;
+ unsigned long addr;
+
+ t.tag = type;
+ t.size = size;
+
+ /*
+ * If next_tag equals NULL it means it's the first tag we're asked
+ * to create.
+ */
+ if (next_tag == (unsigned long) NULL) {
+ /*
+ * If memory_upper not equals NULL it means that identify()
+ * was able to figure out how much memory is present in the
+ * box so we initialize next_tag from it.
+ */
+ if (memory_upper != (unsigned long) NULL)
+ next_tag = memory_upper;
+
+ /* Else we rely on the fact that the first tag we create for
+ * a box for which we don't know how RAM it gots is a tag of
+ * type tag_memupper. This is ensured by the first entry in
+ * the defaults tag list for such a box (see identify.c).
+ * First we check this.
+ */
+ else {
+ /* Ok it's a memupper tag: we put it's value in
+ * memory_upper so launch() can pass it to the
+ * kernel in register a0 and we initialize next_tag.
+ */
+ next_tag = *(unsigned long *) data;
+ memory_upper = *((unsigned long *) data);
+ }
+ }
+
+ /* We put the tag structure. */
+ addr = next_tag - (sizeof (tag));
+
+ memcpy ((void *) addr, (void *) &t, (size_t) (sizeof (tag)));
+
+ /* We put the tag's data if any. */
+ if (size != 0) {
+ addr = addr - size;
+ memcpy ((void *) addr, data, (size_t) (t.size));
+ }
+
+ /*
+ * Set next_tag ready for the next tag creation.
+ */
+ next_tag = addr;
+ AddTagsEndSymbol();
+
+ return 0;
+}
+
+void SetUpBootInfo(void)
+{
+ unsigned long LongVar;
+ int atag;
+
+ /*
+ * This is hard coded here but will change when we have a
+ * Size mem routine.
+ */
+
+ /*
+ * 64mb of memory.
+ */
+
+ //mips_memory_upper = 0x84000000;
+
+
+#ifndef BOOTLOADER
+
+#if 0 /* You break'a the kernel I break'a ya face. -DaveM */
+
+ /* Eight meg of memory. */
+ mips_memory_upper = 0x80800000; /* XXX this appears to be unused -
+ this assignment is not present in the normal
+ $cvstree/linux/arch/mips/cobalt/setup.c */
+#endif
+#else
+#include "../../../../include/diagdefs.h"
+ mips_memory_upper = (unsigned long) kBootloaderMipsMemoryUpper;
+#endif
+
+ LongVar = mips_memory_upper;
+ atag = bi_TagAdd(tag_memupper, ULONGSIZE, &LongVar);
+
+ /* Here is the machine type.
+ */
+ LongVar = MACH_COBALT_27;
+ atag = bi_TagAdd(tag_machtype, ULONGSIZE, &LongVar);
+
+ LongVar = 0x80000000;
+ atag = bi_TagAdd(tag_memlower, ULONGSIZE, &LongVar);
+
+ LongVar = CPU_R4300;
+ atag = bi_TagAdd(tag_cputype, ULONGSIZE, &LongVar);
+
+ LongVar = MACH_GROUP_COBALT;
+ atag = bi_TagAdd(tag_machgroup, ULONGSIZE, &LongVar);
+
+ LongVar = 0;
+ atag = bi_TagAdd(tag_scache_size, ULONGSIZE, &LongVar);
+
+ LongVar = 48;
+ atag = bi_TagAdd(tag_tlb_entries, ULONGSIZE, &LongVar);
+
+ LongVar = 0;
+ atag = bi_TagAdd(tag_drive_info, ULONGSIZE, &LongVar);
+
+ LongVar = 0xe0800000;
+ atag = bi_TagAdd(tag_vram_base, ULONGSIZE, &LongVar);
+
+ LongVar = 0;
+ atag = bi_TagAdd(tag_dummy, 0, &LongVar);
+}
+
+void AddTagsEndSymbol(void)
+{
+ short X;
+ X = 1;
+}
+
+/*
+ * Oh shit, this is so crappy ...
+ */
+#include <linux/mm.h>
+#include <asm/pgtable.h>
+int my_cacheflush(unsigned long start, unsigned long size, unsigned int what)
+{
+ flush_cache_range(current->mm, start, start + size);
+ return 0;
+}
+
+
+/*
+ * The ROM set the flag to 0x1 to turn off output. This is interpreted
+ * as "valid", "no kernel output", and index '0' into the following
+ * tables. We overload entry '0' to specify a sensible default rate.
+ */
+static int cons_baud_int[] = { 9600, 0, 9600, 0, 0, 115200, 0, 0 };
+static int cons_baud_baud[] = { B9600, 0, B9600, 0, 0, B115200, 0, 0 };
+
+static union cobalt_cons_info
+cobalt_get_console_info(void)
+{
+ char board_id = 0;
+ static union cobalt_cons_info cons_info;
+ static int read_info = 0;
+ extern void add_init_env(char *);
+
+ if (read_info)
+ return cons_info;
+
+ VIA_PORT_WRITE(VIA_CMOS_ADDR, VIA_CMOS_CONSOLE_FLG);
+ cons_info.ccons_char = VIA_PORT_READ(VIA_CMOS_DATA);
+
+#if 0
+ printk("cobalt_get_console_info: read 0x%x from console flag\n",
+ cons_info.ccons_char);
+#endif
+
+ /*
+ * CMOS hasn't been initialized or baud rate isn't known.
+ * - read the board id and provide backwards compat.
+ */
+ if (cons_info.ccons_bits.valid != VIA_CMOS_CONS_VALID
+ || ! cons_baud_int[cons_info.ccons_bits.baud]
+ || ! cons_baud_baud[cons_info.ccons_bits.baud]) {
+ pcibios_read_config_byte(0, PCI_DEVSHFT(COBALT_PCICONF_VIA),
+ VIA_COBALT_BRD_ID_REG, &board_id);
+
+#if 0
+ printk("cobalt_get_console_info: read 0x%x from board config\n",
+ board_id);
+#endif
+
+ switch (VIA_COBALT_BRD_REG_to_ID(board_id)) {
+ case COBALT_BRD_ID_QUBE1:
+ cons_info.ccons_bits.baud = VIA_CMOS_CONS_115K;
+ cons_info.ccons_bits.kout = 1;
+ break;
+ case COBALT_BRD_ID_RAQ1:
+ cons_info.ccons_bits.baud = VIA_CMOS_CONS_9600;
+ cons_info.ccons_bits.kout = 1;
+ break;
+ case COBALT_BRD_ID_QUBE2:
+ cons_info.ccons_bits.baud = VIA_CMOS_CONS_9600;
+ cons_info.ccons_bits.kout = 0;
+ break;
+ case COBALT_BRD_ID_RAQ2:
+ cons_info.ccons_bits.baud = VIA_CMOS_CONS_9600;
+ cons_info.ccons_bits.kout = 1;
+ break;
+ }
+ cons_info.ccons_bits.valid = VIA_CMOS_CONS_VALID;
+ }
+
+ read_info = 1;
+
+#if defined(DEBUG_LOADER)
+ cons_info.ccons_bits.kout = 1;
+#endif
+
+ if (!cons_info.ccons_bits.kout) {
+ add_init_env("CONSOLE=/dev/null");
+ }
+
+#if 0
+ printk("cobalt_get_console_info: returning 0x%x\n",
+ cons_info.ccons_char);
+#endif
+
+ return cons_info;
+}
+
+int
+cobalt_cons_koutok(void)
+{
+ union cobalt_cons_info cons;
+
+ cons = cobalt_get_console_info();
+
+ return cons.ccons_bits.kout;
+}
+
+int
+cobalt_cons_baudbaud(void)
+{
+ union cobalt_cons_info cons;
+
+ cons = cobalt_get_console_info();
+
+ return cons_baud_baud[cons.ccons_bits.baud];
+}
+
+int
+cobalt_cons_baudint(void)
+{
+ union cobalt_cons_info cons;
+
+ cons = cobalt_get_console_info();
+
+ return cons_baud_int[cons.ccons_bits.baud];
+}
diff --git a/arch/mips/cobalt/via.c b/arch/mips/cobalt/via.c
new file mode 100644
index 000000000..7ab5e1e69
--- /dev/null
+++ b/arch/mips/cobalt/via.c
@@ -0,0 +1,90 @@
+/*
+ * Interrupt handling for the VIA ISA bridge.
+ *
+ * Everything the same ... just different ...
+ */
+#include <linux/kernel.h>
+#include <asm/cobalt.h>
+#include <asm/ptrace.h>
+#include <asm/io.h>
+
+extern asmlinkage void do_IRQ(int irq, struct pt_regs * regs);
+
+extern unsigned char cache_21;
+extern unsigned char cache_A1;
+
+/*
+ * (un)mask_irq, disable_irq() and enable_irq() only handle (E)ISA and
+ * PCI devices. Other onboard hardware needs specific routines.
+ */
+void mask_irq(unsigned int irq_nr)
+{
+ unsigned char mask;
+
+ mask = 1 << (irq_nr & 7);
+ if (irq_nr < 8) {
+ cache_21 |= mask;
+ outb(cache_21, 0x10000021);
+ } else {
+ cache_A1 |= mask;
+ outb(cache_A1, 0x100000a1);
+ }
+}
+
+void unmask_irq(unsigned int irq_nr)
+{
+ unsigned char mask;
+
+ mask = ~(1 << (irq_nr & 7));
+ if (irq_nr < 8) {
+ cache_21 &= mask;
+ outb(cache_21, 0x10000021);
+ } else {
+ cache_A1 &= mask;
+ outb(cache_A1, 0x100000a1);
+ }
+}
+
+asmlinkage void via_irq(struct pt_regs *regs)
+{
+ char mstat, sstat;
+
+ /* Read Master Status */
+ VIA_PORT_WRITE(0x20, 0x0C);
+ mstat = VIA_PORT_READ(0x20);
+
+ if (mstat < 0) {
+ mstat &= 0x7f;
+ if (mstat != 2) {
+ do_IRQ(mstat, regs);
+ VIA_PORT_WRITE(0x20, mstat | 0x20);
+ } else {
+ sstat = VIA_PORT_READ(0xA0);
+
+ /* Slave interrupt */
+ VIA_PORT_WRITE(0xA0, 0x0C);
+ sstat = VIA_PORT_READ(0xA0);
+
+ if (sstat < 0) {
+ do_IRQ((sstat + 8) & 0x7f, regs);
+ VIA_PORT_WRITE(0x20, 0x22);
+ VIA_PORT_WRITE(0xA0, (sstat & 0x7f) | 0x20);
+ } else {
+ printk("Spurious slave interrupt...\n");
+ }
+ }
+ } else
+ printk("Spurious master interrupt...");
+}
+
+asmlinkage void galileo_irq(struct pt_regs *regs)
+{
+ unsigned long irq_src = *((unsigned long *) 0xb4000c18);
+
+ /* Check for timer irq ... */
+ if (irq_src & 0x00000100) {
+ *((volatile unsigned long *) 0xb4000c18) = 0;
+ do_IRQ(0, regs);
+ } else
+ printk("Spurious Galileo interrupt...\n");
+}
diff --git a/arch/mips/cobalt/z8530.h b/arch/mips/cobalt/z8530.h
new file mode 100644
index 000000000..6ed984da5
--- /dev/null
+++ b/arch/mips/cobalt/z8530.h
@@ -0,0 +1,219 @@
+/* 8530 Serial Communications Controller Register definitions */
+#define FLAG 0x7e
+
+/* Write Register 0 */
+#define R0 0 /* Register selects */
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define R5 5
+#define R6 6
+#define R7 7
+#define R8 8
+#define R9 9
+#define R10 10
+#define R11 11
+#define R12 12
+#define R13 13
+#define R14 14
+#define R15 15
+
+#define NULLCODE 0 /* Null Code */
+#define POINT_HIGH 0x8 /* Select upper half of registers */
+#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
+#define SEND_ABORT 0x18 /* HDLC Abort */
+#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
+#define RES_Tx_P 0x28 /* Reset TxINT Pending */
+#define ERR_RES 0x30 /* Error Reset */
+#define RES_H_IUS 0x38 /* Reset highest IUS */
+
+#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
+#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
+#define RES_EOM_L 0xC0 /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
+#define TxINT_ENAB 0x2 /* Tx Int Enable */
+#define PAR_SPEC 0x4 /* Parity is special condition */
+
+#define RxINT_DISAB 0 /* Rx Int Disable */
+#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
+#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
+#define INT_ERR_Rx 0x18 /* Int on error only */
+
+#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
+#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
+#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define RxENABLE 0x1 /* Rx Enable */
+#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
+#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
+#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
+#define ENT_HM 0x10 /* Enter Hunt Mode */
+#define AUTO_ENAB 0x20 /* Auto Enables */
+#define Rx5 0x0 /* Rx 5 Bits/Character */
+#define Rx7 0x40 /* Rx 7 Bits/Character */
+#define Rx6 0x80 /* Rx 6 Bits/Character */
+#define Rx8 0xc0 /* Rx 8 Bits/Character */
+
+/* Write Register 4 */
+
+#define PAR_ENA 0x1 /* Parity Enable */
+#define PAR_EVEN 0x2 /* Parity Even/Odd* */
+
+#define SYNC_ENAB 0 /* Sync Modes Enable */
+#define SB1 0x4 /* 1 stop bit/char */
+#define SB15 0x8 /* 1.5 stop bits/char */
+#define SB2 0xc /* 2 stop bits/char */
+
+#define MONSYNC 0 /* 8 Bit Sync character */
+#define BISYNC 0x10 /* 16 bit sync character */
+#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
+#define EXTSYNC 0x30 /* External Sync Mode */
+
+#define X1CLK 0x0 /* x1 clock mode */
+#define X16CLK 0x40 /* x16 clock mode */
+#define X32CLK 0x80 /* x32 clock mode */
+#define X64CLK 0xC0 /* x64 clock mode */
+
+/* Write Register 5 */
+
+#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
+#define RTS 0x2 /* RTS */
+#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
+#define TxENAB 0x8 /* Tx Enable */
+#define SND_BRK 0x10 /* Send Break */
+#define Tx5 0x0 /* Tx 5 bits (or less)/character */
+#define Tx7 0x20 /* Tx 7 bits/character */
+#define Tx6 0x40 /* Tx 6 bits/character */
+#define Tx8 0x60 /* Tx 8 bits/character */
+#define DTR 0x80 /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define VIS 1 /* Vector Includes Status */
+#define NV 2 /* No Vector */
+#define DLC 4 /* Disable Lower Chain */
+#define MIE 8 /* Master Interrupt Enable */
+#define STATHI 0x10 /* Status high */
+#define NORESET 0 /* No reset on write to R9 */
+#define CHRB 0x40 /* Reset channel B */
+#define CHRA 0x80 /* Reset channel A */
+#define FHWRES 0xc0 /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define BIT6 1 /* 6 bit/8bit sync */
+#define LOOPMODE 2 /* SDLC Loop mode */
+#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
+#define MARKIDLE 8 /* Mark/flag on idle */
+#define GAOP 0x10 /* Go active on poll */
+#define NRZ 0 /* NRZ mode */
+#define NRZI 0x20 /* NRZI mode */
+#define FM1 0x40 /* FM1 (transition = 1) */
+#define FM0 0x60 /* FM0 (transition = 0) */
+#define CRCPS 0x80 /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define TRxCXT 0 /* TRxC = Xtal output */
+#define TRxCTC 1 /* TRxC = Transmit clock */
+#define TRxCBR 2 /* TRxC = BR Generator Output */
+#define TRxCDP 3 /* TRxC = DPLL output */
+#define TRxCOI 4 /* TRxC O/I */
+#define TCRTxCP 0 /* Transmit clock = RTxC pin */
+#define TCTRxCP 8 /* Transmit clock = TRxC pin */
+#define TCBR 0x10 /* Transmit clock = BR Generator output */
+#define TCDPLL 0x18 /* Transmit clock = DPLL output */
+#define RCRTxCP 0 /* Receive clock = RTxC pin */
+#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
+#define RCBR 0x40 /* Receive clock = BR Generator output */
+#define RCDPLL 0x60 /* Receive clock = DPLL output */
+#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define BRENABL 1 /* Baud rate generator enable */
+#define BRSRC 2 /* Baud rate generator source */
+#define DTRREQ 4 /* DTR/Request function */
+#define AUTOECHO 8 /* Auto Echo */
+#define LOOPBAK 0x10 /* Local loopback */
+#define SEARCH 0x20 /* Enter search mode */
+#define RMC 0x40 /* Reset missing clock */
+#define DISDPLL 0x60 /* Disable DPLL */
+#define SSBR 0x80 /* Set DPLL source = BR generator */
+#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
+#define SFMM 0xc0 /* Set FM mode */
+#define SNRZI 0xe0 /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define ZCIE 2 /* Zero count IE */
+#define DCDIE 8 /* DCD IE */
+#define SYNCIE 0x10 /* Sync/hunt IE */
+#define CTSIE 0x20 /* CTS IE */
+#define TxUIE 0x40 /* Tx Underrun/EOM IE */
+#define BRKIE 0x80 /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define Rx_CH_AV 0x1 /* Rx Character Available */
+#define ZCOUNT 0x2 /* Zero count */
+#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
+#define DCD 0x8 /* DCD */
+#define SYNC_HUNT 0x10 /* Sync/hunt */
+#define CTS 0x20 /* CTS */
+#define TxEOM 0x40 /* Tx underrun */
+#define BRK_ABRT 0x80 /* Break/Abort */
+
+/* Read Register 1 */
+#define ALL_SNT 0x1 /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define RES3 0x8 /* 0/3 */
+#define RES4 0x4 /* 0/4 */
+#define RES5 0xc /* 0/5 */
+#define RES6 0x2 /* 0/6 */
+#define RES7 0xa /* 0/7 */
+#define RES8 0x6 /* 0/8 */
+#define RES18 0xe /* 1/8 */
+#define RES28 0x0 /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define PAR_ERR 0x10 /* Parity error */
+#define Rx_OVR 0x20 /* Rx Overrun Error */
+#define CRC_ERR 0x40 /* CRC/Framing Error */
+#define END_FR 0x80 /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
+#define CHBTxIP 0x2 /* Channel B Tx IP */
+#define CHBRxIP 0x4 /* Channel B Rx IP */
+#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
+#define CHATxIP 0x10 /* Channel A Tx IP */
+#define CHARxIP 0x20 /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10 (misc status bits) */
+#define ONLOOP 2 /* On loop */
+#define LOOPSEND 0x10 /* Loop sending */
+#define CLK2MIS 0x40 /* Two clocks missing */
+#define CLK1MIS 0x80 /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */