1
0
Files
irix-657m-src/stand/arcs/lib/libkl/io/junkuart.c
2022-09-29 17:59:04 +03:00

344 lines
6.6 KiB
C

/***********************************************************************\
* File: junkuart.c *
* *
* IOC3 ASIC UART routines. The IOC3 ASIC resides on the IO6 *
* card and forms the basis for a system console. *
* *
\***********************************************************************/
#include <sys/types.h>
#include <sys/ns16550.h>
#include <sys/SN/arch.h>
#include <sys/SN/agent.h>
#include <stdarg.h>
#include "hub.h"
#include "junkuart.h"
#include "libasm.h"
#include "rtc.h"
#define LBYTE(caddr) \
(char) ((*(int *) ((__psunsigned_t) (caddr) & ~3) << \
((__psunsigned_t) (caddr) & 3) * 8) >> 24)
#if 1
/* Junk bus needs its registers 64-bit aligned. */
typedef __uint64_t prom_uart_reg_t;
#define PROM_SER_CLK_SPEED 12000000
#define PROM_SER_DIVISOR(x) (PROM_SER_CLK_SPEED / ((x) * 16))
#else
#define PROM_SER_CLK_SPEED SER_CLK_SPEED
#define PROM_SER_DIVISOR(y) SER_DIVISOR(y)
/* IOC3 likes its registers 32-bit aligned. */
typedef __uint32_t prom_uart_reg_t;
#endif
#define INIT_TIMEOUT 100000 /* microseconds */
#define PUTC_TIMEOUT 10000 /* microseconds */
/*
* junkuart_init
*/
static int baud_table[] = {
/* 110, 300, 1200, 2400, 4800, 9600, 19200, 38400 */
300, 1200, 2400, 9600, 19200, 38400
};
#define NBAUD (sizeof (baud_table) / sizeof (baud_table[0]))
ulong get_junkuart_base(void)
{
return (ulong)LOCAL_HUB(MD_UREG1_8);
}
int get_junkuart_baud(void)
{
return 9600;
}
/*
* junkuart_probe
*
* Returns non-zero if a junkuart is present.
*/
int junkuart_probe(void)
{
volatile prom_uart_reg_t *cntrl;
cntrl = (volatile prom_uart_reg_t *) get_junkuart_base();
WR_REG(cntrl, SCRATCH_PAD_REG, (uchar_t) 0x55);
WR_REG(cntrl, INTR_ENABLE_REG, 0x0); /* Un-float bus */
if (RD_REG(cntrl, SCRATCH_PAD_REG) != (uchar_t) 0x55)
return 0;
WR_REG(cntrl, SCRATCH_PAD_REG, (uchar_t) 0xaa);
WR_REG(cntrl, INTR_ENABLE_REG, 0x0); /* Un-float bus */
if (RD_REG(cntrl, SCRATCH_PAD_REG) != (uchar_t) 0xaa)
return 0;
WR_REG(cntrl, SCRATCH_PAD_REG, (uchar_t) 0);
return 1;
}
static int
valid_baud(int baud)
{
int i;
for (i = 0; i < NBAUD; i++)
if (baud == baud_table[i])
return 1;
return 0;
}
static int
next_baud(int baud)
{
int i;
for (i = 1; i < NBAUD; i++)
if (baud_table[i] > baud)
return baud_table[i];
return baud_table[0];
}
#define IOC3DELAY delay(2)
static void
configure_port(volatile prom_uart_reg_t *cntrl, int baud)
{
rtc_time_t expire;
int clkdiv;
clkdiv = PROM_SER_DIVISOR(baud);
expire = rtc_time() + INIT_TIMEOUT;
/* make sure the transmit FIFO is empty */
while (! (RD_REG(cntrl, LINE_STATUS_REG) & LSR_XMIT_EMPTY)) {
IOC3DELAY;
if (rtc_time() > expire)
break;
}
WR_REG(cntrl, LINE_CNTRL_REG, LCR_DLAB);
IOC3DELAY;
WR_REG(cntrl, DIVISOR_LATCH_MSB_REG, (clkdiv >> 8) & 0xff);
IOC3DELAY;
WR_REG(cntrl, DIVISOR_LATCH_LSB_REG, clkdiv & 0xff);
IOC3DELAY;
/* set operating parameters and set DLAB to 0 */
WR_REG(cntrl, LINE_CNTRL_REG, LCR_8_BITS_CHAR | LCR_1_STOP_BITS);
IOC3DELAY;
/* no interrupt */
WR_REG(cntrl, INTR_ENABLE_REG, 0x0);
IOC3DELAY;
/* enable FIFO mode and reset both FIFOs */
WR_REG(cntrl, FIFO_CNTRL_REG, FCR_ENABLE_FIFO);
IOC3DELAY;
WR_REG(cntrl, FIFO_CNTRL_REG,
FCR_ENABLE_FIFO | FCR_RCV_FIFO_RESET | FCR_XMIT_FIFO_RESET);
}
/* ARGSUSED */
void junkuart_init(void *init_data)
{
volatile prom_uart_reg_t *cntrl;
int baud;
cntrl = (volatile prom_uart_reg_t *) get_junkuart_base();
baud = get_junkuart_baud();
configure_port(cntrl, valid_baud(baud) ? baud : 9600);
}
/*
* junkuart_poll
*
* Returns 1 if a character is available, 0 if not.
*/
int junkuart_poll(void)
{
volatile prom_uart_reg_t *cntrl;
uchar_t status;
cntrl = (volatile prom_uart_reg_t *) get_junkuart_base();
status = RD_REG(cntrl, LINE_STATUS_REG);
if (status & (LSR_OVERRUN_ERR | LSR_PARITY_ERR | LSR_FRAMING_ERR)) {
if (status & LSR_OVERRUN_ERR)
junkuart_puts("\nNS16550 overrun error\n");
else if (status & LSR_FRAMING_ERR)
junkuart_puts("\nNS16550 framing error\n");
else
junkuart_puts("\nNS16550 parity error\n");
return 0;
}
return ((status & LSR_DATA_READY) != 0);
}
/*
* junkuart_readc
*
* Reads a character. May only be called after junkuart_poll has
* indicated a character is available.
*/
int junkuart_readc(void)
{
volatile prom_uart_reg_t *cntrl;
cntrl = (volatile prom_uart_reg_t *) get_junkuart_base();
return RD_REG(cntrl, RCV_BUF_REG);
}
/*
* junkuart_getc
*
* Waits for a character and returns it.
* Flashes hub LEDs while waiting.
*/
#define FLASH_CYCLES 2000
int junkuart_getc(void)
{
int f, i, c;
uchar_t status;
for (f = 0xc0; ; f ^= JUNKUART_FLASH) {
for (i = 0; i < FLASH_CYCLES; i++)
if (junkuart_poll()){
c = junkuart_readc();
return c;
}
hub_led_set(f);
}
/*NOTREACHED*/
return 0;
}
/*
* junkuart_putc
*
* Writes a single character when ready.
* Returns 0 if successful, -1 if timed out.
*
* Converts \n to \r\n (can add 256 to quote a plain \n).
*/
int junkuart_putc(int c)
{
volatile prom_uart_reg_t *cntrl;
rtc_time_t expire;
if (c > 255)
c -= 256;
else if (c == '\n' && junkuart_putc('\r') < 0)
return -1;
cntrl = (volatile prom_uart_reg_t *) get_junkuart_base();
expire = rtc_time() + PUTC_TIMEOUT;
while (! (RD_REG(cntrl, LINE_STATUS_REG) & LSR_XMIT_BUF_EMPTY))
if (rtc_time() > expire) {
return -1;
}
WR_REG(cntrl, XMIT_BUF_REG, c);
return 0;
}
/*
* junkuart_puts
*
* Writes a null-terminated string.
* Returns 0 if successful, -1 if junk_putc failed.
* Contains special support so the string may reside in the PROM.
*/
int junkuart_puts(char *s)
{
int c;
if (s == 0)
s = "<NULL>";
while ((c = LBYTE(s)) != 0) {
if (junkuart_putc(c) < 0)
return -1;
s++;
}
return 0;
}
/*
* junkuart_gets
*
* Mini version of gets for debugging.
*/
char *junkuart_gets(char *buf, int max_length)
{
int c;
char *bufp;
bufp = buf;
while ((c = junkuart_getc()) != '\r') {
junkuart_putc(c);
*bufp++ = c;
}
junkuart_putc(c);
junkuart_putc('\n');
*bufp = 0;
return buf;
}
/*
* junkuart_printf
*
* Bonus routine useful for debugging.
*/
void junkuart_printf(const char *fmt, ...)
{
va_list ap;
char buf[80];
extern int vsprintf(char *buf, const char *fmt, va_list ap);
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
junkuart_puts(buf);
}