patch-2.4.0-test3 linux/arch/mips/cobalt/cobaltscc.c

Next file: linux/arch/mips/cobalt/diagdefs.h
Previous file: linux/arch/mips/cobalt/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test2/linux/arch/mips/cobalt/cobaltscc.c linux/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;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)