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