1*4882a593Smuzhiyun /*********************************************************************** 2*4882a593Smuzhiyun * 3*4882a593Smuzhiyun * (C) Copyright 2004-2009 4*4882a593Smuzhiyun * DENX Software Engineering 5*4882a593Smuzhiyun * Wolfgang Denk, wd@denx.de 6*4882a593Smuzhiyun * 7*4882a593Smuzhiyun * Simple 16550A serial driver 8*4882a593Smuzhiyun * 9*4882a593Smuzhiyun * Originally from linux source (drivers/char/ps2ser.c) 10*4882a593Smuzhiyun * 11*4882a593Smuzhiyun * Used by the PS/2 multiplexer driver (ps2mult.c) 12*4882a593Smuzhiyun * 13*4882a593Smuzhiyun ***********************************************************************/ 14*4882a593Smuzhiyun 15*4882a593Smuzhiyun #include <common.h> 16*4882a593Smuzhiyun 17*4882a593Smuzhiyun #include <asm/io.h> 18*4882a593Smuzhiyun #include <asm/atomic.h> 19*4882a593Smuzhiyun #include <ps2mult.h> 20*4882a593Smuzhiyun /* This is needed for ns16550.h */ 21*4882a593Smuzhiyun #ifndef CONFIG_SYS_NS16550_REG_SIZE 22*4882a593Smuzhiyun #define CONFIG_SYS_NS16550_REG_SIZE 1 23*4882a593Smuzhiyun #endif 24*4882a593Smuzhiyun #include <ns16550.h> 25*4882a593Smuzhiyun 26*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR; 27*4882a593Smuzhiyun 28*4882a593Smuzhiyun /* #define DEBUG */ 29*4882a593Smuzhiyun 30*4882a593Smuzhiyun #define PS2SER_BAUD 57600 31*4882a593Smuzhiyun 32*4882a593Smuzhiyun #if CONFIG_PS2SERIAL == 1 33*4882a593Smuzhiyun #define COM_BASE (CONFIG_SYS_CCSRBAR+0x4500) 34*4882a593Smuzhiyun #elif CONFIG_PS2SERIAL == 2 35*4882a593Smuzhiyun #define COM_BASE (CONFIG_SYS_CCSRBAR+0x4600) 36*4882a593Smuzhiyun #else 37*4882a593Smuzhiyun #error CONFIG_PS2SERIAL must be in 1 ... 2 38*4882a593Smuzhiyun #endif 39*4882a593Smuzhiyun 40*4882a593Smuzhiyun static int ps2ser_getc_hw(void); 41*4882a593Smuzhiyun static void ps2ser_interrupt(void *dev_id); 42*4882a593Smuzhiyun 43*4882a593Smuzhiyun extern struct serial_state rs_table[]; /* in serial.c */ 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun static u_char ps2buf[PS2BUF_SIZE]; 46*4882a593Smuzhiyun static atomic_t ps2buf_cnt; 47*4882a593Smuzhiyun static int ps2buf_in_idx; 48*4882a593Smuzhiyun static int ps2buf_out_idx; 49*4882a593Smuzhiyun ps2ser_init(void)50*4882a593Smuzhiyunint ps2ser_init(void) 51*4882a593Smuzhiyun { 52*4882a593Smuzhiyun NS16550_t com_port = (NS16550_t)COM_BASE; 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun com_port->ier = 0x00; 55*4882a593Smuzhiyun com_port->lcr = UART_LCR_BKSE | UART_LCR_8N1; 56*4882a593Smuzhiyun com_port->dll = (CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) & 0xff; 57*4882a593Smuzhiyun com_port->dlm = ((CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) >> 8) & 0xff; 58*4882a593Smuzhiyun com_port->lcr = UART_LCR_8N1; 59*4882a593Smuzhiyun com_port->mcr = (UART_MCR_DTR | UART_MCR_RTS); 60*4882a593Smuzhiyun com_port->fcr = (UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR); 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun return (0); 63*4882a593Smuzhiyun } 64*4882a593Smuzhiyun ps2ser_putc(int chr)65*4882a593Smuzhiyunvoid ps2ser_putc(int chr) 66*4882a593Smuzhiyun { 67*4882a593Smuzhiyun NS16550_t com_port = (NS16550_t)COM_BASE; 68*4882a593Smuzhiyun debug(">>>> 0x%02x\n", chr); 69*4882a593Smuzhiyun 70*4882a593Smuzhiyun while ((com_port->lsr & UART_LSR_THRE) == 0); 71*4882a593Smuzhiyun com_port->thr = chr; 72*4882a593Smuzhiyun } 73*4882a593Smuzhiyun ps2ser_getc_hw(void)74*4882a593Smuzhiyunstatic int ps2ser_getc_hw(void) 75*4882a593Smuzhiyun { 76*4882a593Smuzhiyun NS16550_t com_port = (NS16550_t)COM_BASE; 77*4882a593Smuzhiyun int res = -1; 78*4882a593Smuzhiyun 79*4882a593Smuzhiyun if (com_port->lsr & UART_LSR_DR) { 80*4882a593Smuzhiyun res = com_port->rbr; 81*4882a593Smuzhiyun } 82*4882a593Smuzhiyun 83*4882a593Smuzhiyun return res; 84*4882a593Smuzhiyun } 85*4882a593Smuzhiyun ps2ser_getc(void)86*4882a593Smuzhiyunint ps2ser_getc(void) 87*4882a593Smuzhiyun { 88*4882a593Smuzhiyun volatile int chr; 89*4882a593Smuzhiyun int flags; 90*4882a593Smuzhiyun 91*4882a593Smuzhiyun debug("<< "); 92*4882a593Smuzhiyun 93*4882a593Smuzhiyun flags = disable_interrupts(); 94*4882a593Smuzhiyun 95*4882a593Smuzhiyun do { 96*4882a593Smuzhiyun if (atomic_read(&ps2buf_cnt) != 0) { 97*4882a593Smuzhiyun chr = ps2buf[ps2buf_out_idx++]; 98*4882a593Smuzhiyun ps2buf_out_idx &= (PS2BUF_SIZE - 1); 99*4882a593Smuzhiyun atomic_dec(&ps2buf_cnt); 100*4882a593Smuzhiyun } else { 101*4882a593Smuzhiyun chr = ps2ser_getc_hw(); 102*4882a593Smuzhiyun } 103*4882a593Smuzhiyun } 104*4882a593Smuzhiyun while (chr < 0); 105*4882a593Smuzhiyun 106*4882a593Smuzhiyun if (flags) 107*4882a593Smuzhiyun enable_interrupts(); 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun debug("0x%02x\n", chr); 110*4882a593Smuzhiyun 111*4882a593Smuzhiyun return chr; 112*4882a593Smuzhiyun } 113*4882a593Smuzhiyun ps2ser_check(void)114*4882a593Smuzhiyunint ps2ser_check(void) 115*4882a593Smuzhiyun { 116*4882a593Smuzhiyun int flags; 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun flags = disable_interrupts(); 119*4882a593Smuzhiyun ps2ser_interrupt(NULL); 120*4882a593Smuzhiyun if (flags) enable_interrupts(); 121*4882a593Smuzhiyun 122*4882a593Smuzhiyun return atomic_read(&ps2buf_cnt); 123*4882a593Smuzhiyun } 124*4882a593Smuzhiyun ps2ser_interrupt(void * dev_id)125*4882a593Smuzhiyunstatic void ps2ser_interrupt(void *dev_id) 126*4882a593Smuzhiyun { 127*4882a593Smuzhiyun NS16550_t com_port = (NS16550_t)COM_BASE; 128*4882a593Smuzhiyun int chr; 129*4882a593Smuzhiyun int status; 130*4882a593Smuzhiyun 131*4882a593Smuzhiyun do { 132*4882a593Smuzhiyun chr = ps2ser_getc_hw(); 133*4882a593Smuzhiyun status = com_port->lsr; 134*4882a593Smuzhiyun if (chr < 0) continue; 135*4882a593Smuzhiyun 136*4882a593Smuzhiyun if (atomic_read(&ps2buf_cnt) < PS2BUF_SIZE) { 137*4882a593Smuzhiyun ps2buf[ps2buf_in_idx++] = chr; 138*4882a593Smuzhiyun ps2buf_in_idx &= (PS2BUF_SIZE - 1); 139*4882a593Smuzhiyun atomic_inc(&ps2buf_cnt); 140*4882a593Smuzhiyun } else { 141*4882a593Smuzhiyun printf ("ps2ser.c: buffer overflow\n"); 142*4882a593Smuzhiyun } 143*4882a593Smuzhiyun } while (status & UART_LSR_DR); 144*4882a593Smuzhiyun if (atomic_read(&ps2buf_cnt)) { 145*4882a593Smuzhiyun ps2mult_callback(atomic_read(&ps2buf_cnt)); 146*4882a593Smuzhiyun } 147*4882a593Smuzhiyun } 148