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