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 #ifdef CONFIG_MPC5xxx 33 #if CONFIG_PS2SERIAL == 1 34 #define PSC_BASE MPC5XXX_PSC1 35 #elif CONFIG_PS2SERIAL == 2 36 #define PSC_BASE MPC5XXX_PSC2 37 #elif CONFIG_PS2SERIAL == 3 38 #define PSC_BASE MPC5XXX_PSC3 39 #elif defined(CONFIG_MGT5100) 40 #error CONFIG_PS2SERIAL must be in 1, 2 or 3 41 #elif CONFIG_PS2SERIAL == 4 42 #define PSC_BASE MPC5XXX_PSC4 43 #elif CONFIG_PS2SERIAL == 5 44 #define PSC_BASE MPC5XXX_PSC5 45 #elif CONFIG_PS2SERIAL == 6 46 #define PSC_BASE MPC5XXX_PSC6 47 #else 48 #error CONFIG_PS2SERIAL must be in 1 ... 6 49 #endif 50 51 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ 52 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) 53 54 #if CONFIG_PS2SERIAL == 1 55 #define COM_BASE (CONFIG_SYS_CCSRBAR+0x4500) 56 #elif CONFIG_PS2SERIAL == 2 57 #define COM_BASE (CONFIG_SYS_CCSRBAR+0x4600) 58 #else 59 #error CONFIG_PS2SERIAL must be in 1 ... 2 60 #endif 61 62 #endif /* CONFIG_MPC5xxx / CONFIG_MPC8540 / other */ 63 64 static int ps2ser_getc_hw(void); 65 static void ps2ser_interrupt(void *dev_id); 66 67 extern struct serial_state rs_table[]; /* in serial.c */ 68 #if !defined(CONFIG_MPC5xxx) && !defined(CONFIG_MPC8540) && \ 69 !defined(CONFIG_MPC8541) && !defined(CONFIG_MPC8548) && \ 70 !defined(CONFIG_MPC8555) 71 static struct serial_state *state; 72 #endif 73 74 static u_char ps2buf[PS2BUF_SIZE]; 75 static atomic_t ps2buf_cnt; 76 static int ps2buf_in_idx; 77 static int ps2buf_out_idx; 78 79 #ifdef CONFIG_MPC5xxx 80 int ps2ser_init(void) 81 { 82 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE; 83 unsigned long baseclk; 84 int div; 85 86 /* reset PSC */ 87 psc->command = PSC_SEL_MODE_REG_1; 88 89 /* select clock sources */ 90 #if defined(CONFIG_MGT5100) 91 psc->psc_clock_select = 0xdd00; 92 baseclk = (CONFIG_SYS_MPC5XXX_CLKIN + 16) / 32; 93 #elif defined(CONFIG_MPC5200) 94 psc->psc_clock_select = 0; 95 baseclk = (gd->ipb_clk + 16) / 32; 96 #endif 97 98 /* switch to UART mode */ 99 psc->sicr = 0; 100 101 /* configure parity, bit length and so on */ 102 #if defined(CONFIG_MGT5100) 103 psc->mode = PSC_MODE_ERR | PSC_MODE_8_BITS | PSC_MODE_PARNONE; 104 #elif defined(CONFIG_MPC5200) 105 psc->mode = PSC_MODE_8_BITS | PSC_MODE_PARNONE; 106 #endif 107 psc->mode = PSC_MODE_ONE_STOP; 108 109 /* set up UART divisor */ 110 div = (baseclk + (PS2SER_BAUD/2)) / PS2SER_BAUD; 111 psc->ctur = (div >> 8) & 0xff; 112 psc->ctlr = div & 0xff; 113 114 /* disable all interrupts */ 115 psc->psc_imr = 0; 116 117 /* reset and enable Rx/Tx */ 118 psc->command = PSC_RST_RX; 119 psc->command = PSC_RST_TX; 120 psc->command = PSC_RX_ENABLE | PSC_TX_ENABLE; 121 122 return (0); 123 } 124 125 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ 126 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) 127 int ps2ser_init(void) 128 { 129 NS16550_t com_port = (NS16550_t)COM_BASE; 130 131 com_port->ier = 0x00; 132 com_port->lcr = UART_LCR_BKSE | UART_LCR_8N1; 133 com_port->dll = (CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) & 0xff; 134 com_port->dlm = ((CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) >> 8) & 0xff; 135 com_port->lcr = UART_LCR_8N1; 136 com_port->mcr = (UART_MCR_DTR | UART_MCR_RTS); 137 com_port->fcr = (UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR); 138 139 return (0); 140 } 141 142 #else /* !CONFIG_MPC5xxx && !CONFIG_MPC8540 / other */ 143 144 static inline unsigned int ps2ser_in(int offset) 145 { 146 return readb((unsigned long) state->iomem_base + offset); 147 } 148 149 static inline void ps2ser_out(int offset, int value) 150 { 151 writeb(value, (unsigned long) state->iomem_base + offset); 152 } 153 154 int ps2ser_init(void) 155 { 156 int quot; 157 unsigned cval; 158 159 state = rs_table + CONFIG_PS2SERIAL; 160 161 quot = state->baud_base / PS2SER_BAUD; 162 cval = 0x3; /* 8N1 - 8 data bits, no parity bits, 1 stop bit */ 163 164 /* Set speed, enable interrupts, enable FIFO 165 */ 166 ps2ser_out(UART_LCR, cval | UART_LCR_DLAB); 167 ps2ser_out(UART_DLL, quot & 0xff); 168 ps2ser_out(UART_DLM, quot >> 8); 169 ps2ser_out(UART_LCR, cval); 170 ps2ser_out(UART_IER, UART_IER_RDI); 171 ps2ser_out(UART_MCR, UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS); 172 ps2ser_out(UART_FCR, 173 UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); 174 175 /* If we read 0xff from the LSR, there is no UART here 176 */ 177 if (ps2ser_in(UART_LSR) == 0xff) { 178 printf ("ps2ser.c: no UART found\n"); 179 return -1; 180 } 181 182 irq_install_handler(state->irq, ps2ser_interrupt, NULL); 183 184 return 0; 185 } 186 #endif /* CONFIG_MPC5xxx / CONFIG_MPC8540 / other */ 187 188 void ps2ser_putc(int chr) 189 { 190 #ifdef CONFIG_MPC5xxx 191 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE; 192 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ 193 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) 194 NS16550_t com_port = (NS16550_t)COM_BASE; 195 #endif 196 #ifdef DEBUG 197 printf(">>>> 0x%02x\n", chr); 198 #endif 199 200 #ifdef CONFIG_MPC5xxx 201 while (!(psc->psc_status & PSC_SR_TXRDY)); 202 203 psc->psc_buffer_8 = chr; 204 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ 205 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) 206 while ((com_port->lsr & UART_LSR_THRE) == 0); 207 com_port->thr = chr; 208 #else 209 while (!(ps2ser_in(UART_LSR) & UART_LSR_THRE)); 210 211 ps2ser_out(UART_TX, chr); 212 #endif 213 } 214 215 static int ps2ser_getc_hw(void) 216 { 217 #ifdef CONFIG_MPC5xxx 218 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE; 219 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ 220 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) 221 NS16550_t com_port = (NS16550_t)COM_BASE; 222 #endif 223 int res = -1; 224 225 #ifdef CONFIG_MPC5xxx 226 if (psc->psc_status & PSC_SR_RXRDY) { 227 res = (psc->psc_buffer_8); 228 } 229 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ 230 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) 231 if (com_port->lsr & UART_LSR_DR) { 232 res = com_port->rbr; 233 } 234 #else 235 if (ps2ser_in(UART_LSR) & UART_LSR_DR) { 236 res = (ps2ser_in(UART_RX)); 237 } 238 #endif 239 240 return res; 241 } 242 243 int ps2ser_getc(void) 244 { 245 volatile int chr; 246 int flags; 247 248 #ifdef DEBUG 249 printf("<< "); 250 #endif 251 252 flags = disable_interrupts(); 253 254 do { 255 if (atomic_read(&ps2buf_cnt) != 0) { 256 chr = ps2buf[ps2buf_out_idx++]; 257 ps2buf_out_idx &= (PS2BUF_SIZE - 1); 258 atomic_dec(&ps2buf_cnt); 259 } else { 260 chr = ps2ser_getc_hw(); 261 } 262 } 263 while (chr < 0); 264 265 if (flags) enable_interrupts(); 266 267 #ifdef DEBUG 268 printf("0x%02x\n", chr); 269 #endif 270 271 return chr; 272 } 273 274 int ps2ser_check(void) 275 { 276 int flags; 277 278 flags = disable_interrupts(); 279 ps2ser_interrupt(NULL); 280 if (flags) enable_interrupts(); 281 282 return atomic_read(&ps2buf_cnt); 283 } 284 285 static void ps2ser_interrupt(void *dev_id) 286 { 287 #ifdef CONFIG_MPC5xxx 288 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE; 289 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ 290 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) 291 NS16550_t com_port = (NS16550_t)COM_BASE; 292 #endif 293 int chr; 294 int status; 295 296 do { 297 chr = ps2ser_getc_hw(); 298 #ifdef CONFIG_MPC5xxx 299 status = psc->psc_status; 300 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ 301 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) 302 status = com_port->lsr; 303 #else 304 status = ps2ser_in(UART_IIR); 305 #endif 306 if (chr < 0) continue; 307 308 if (atomic_read(&ps2buf_cnt) < PS2BUF_SIZE) { 309 ps2buf[ps2buf_in_idx++] = chr; 310 ps2buf_in_idx &= (PS2BUF_SIZE - 1); 311 atomic_inc(&ps2buf_cnt); 312 } else { 313 printf ("ps2ser.c: buffer overflow\n"); 314 } 315 #ifdef CONFIG_MPC5xxx 316 } while (status & PSC_SR_RXRDY); 317 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \ 318 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555) 319 } while (status & UART_LSR_DR); 320 #else 321 } while (status & UART_IIR_RDI); 322 #endif 323 324 if (atomic_read(&ps2buf_cnt)) { 325 ps2mult_callback(atomic_read(&ps2buf_cnt)); 326 } 327 } 328