From 5660fe08b83ac8470924ad01f49d36e6779cc689 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 15 Jun 2000 17:19:55 +0000 Subject: First round of Cobalt patches from Mathew Edward Kovach. --- arch/mips/cobalt/.cvsignore | 2 + arch/mips/cobalt/Makefile | 24 +++ arch/mips/cobalt/cobaltscc.c | 350 +++++++++++++++++++++++++++++++++++ arch/mips/cobalt/diagdefs.h | 177 ++++++++++++++++++ arch/mips/cobalt/hw-access.c | 58 ++++++ arch/mips/cobalt/int-handler.S | 140 ++++++++++++++ arch/mips/cobalt/pci.c | 348 ++++++++++++++++++++++++++++++++++ arch/mips/cobalt/reset.c | 60 ++++++ arch/mips/cobalt/serial.h | 28 +++ arch/mips/cobalt/setup.c | 411 +++++++++++++++++++++++++++++++++++++++++ arch/mips/cobalt/via.c | 90 +++++++++ arch/mips/cobalt/z8530.h | 219 ++++++++++++++++++++++ 12 files changed, 1907 insertions(+) create mode 100644 arch/mips/cobalt/.cvsignore create mode 100644 arch/mips/cobalt/Makefile create mode 100644 arch/mips/cobalt/cobaltscc.c create mode 100644 arch/mips/cobalt/diagdefs.h create mode 100644 arch/mips/cobalt/hw-access.c create mode 100644 arch/mips/cobalt/int-handler.S create mode 100644 arch/mips/cobalt/pci.c create mode 100644 arch/mips/cobalt/reset.c create mode 100644 arch/mips/cobalt/serial.h create mode 100644 arch/mips/cobalt/setup.c create mode 100644 arch/mips/cobalt/via.c create mode 100644 arch/mips/cobalt/z8530.h (limited to 'arch/mips/cobalt') 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 + +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 +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include +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 +#include +#include +#include + +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) */ -- cgit v1.2.3