1 /***********************************************************************
3 * (C) Copyright 2004-2009
4 * DENX Software Engineering
5 * Wolfgang Denk, wd@denx.de
7 * Simple 16550A serial driver
9 * Originally from linux source (drivers/char/ps2ser.c)
11 * Used by the PS/2 multiplexer driver (ps2mult.c)
13 ***********************************************************************/
18 #include <asm/atomic.h>
20 /* This is needed for ns16550.h */
21 #ifndef CONFIG_SYS_NS16550_REG_SIZE
22 #define CONFIG_SYS_NS16550_REG_SIZE 1
26 DECLARE_GLOBAL_DATA_PTR;
30 #define PS2SER_BAUD 57600
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
48 #error CONFIG_PS2SERIAL must be in 1 ... 6
51 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
52 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
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)
59 #error CONFIG_PS2SERIAL must be in 1 ... 2
62 #endif /* CONFIG_MPC5xxx / CONFIG_MPC8540 / other */
64 static int ps2ser_getc_hw(void);
65 static void ps2ser_interrupt(void *dev_id);
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;
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;
82 volatile struct mpc5xxx_psc *psc = (struct mpc5xxx_psc *)PSC_BASE;
83 unsigned long baseclk;
87 psc->command = PSC_SEL_MODE_REG_1;
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;
98 /* switch to UART mode */
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;
107 psc->mode = PSC_MODE_ONE_STOP;
109 /* set up UART divisor */
110 div = (baseclk + (PS2SER_BAUD/2)) / PS2SER_BAUD;
111 psc->ctur = (div >> 8) & 0xff;
112 psc->ctlr = div & 0xff;
114 /* disable all interrupts */
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;
125 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
126 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
127 int ps2ser_init(void)
129 NS16550_t com_port = (NS16550_t)COM_BASE;
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);
142 #else /* !CONFIG_MPC5xxx && !CONFIG_MPC8540 / other */
144 static inline unsigned int ps2ser_in(int offset)
146 return readb((unsigned long) state->iomem_base + offset);
149 static inline void ps2ser_out(int offset, int value)
151 writeb(value, (unsigned long) state->iomem_base + offset);
154 int ps2ser_init(void)
159 state = rs_table + CONFIG_PS2SERIAL;
161 quot = state->baud_base / PS2SER_BAUD;
162 cval = 0x3; /* 8N1 - 8 data bits, no parity bits, 1 stop bit */
164 /* Set speed, enable interrupts, enable FIFO
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);
173 UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
175 /* If we read 0xff from the LSR, there is no UART here
177 if (ps2ser_in(UART_LSR) == 0xff) {
178 printf ("ps2ser.c: no UART found\n");
182 irq_install_handler(state->irq, ps2ser_interrupt, NULL);
186 #endif /* CONFIG_MPC5xxx / CONFIG_MPC8540 / other */
188 void ps2ser_putc(int chr)
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;
197 printf(">>>> 0x%02x\n", chr);
200 #ifdef CONFIG_MPC5xxx
201 while (!(psc->psc_status & PSC_SR_TXRDY));
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);
209 while (!(ps2ser_in(UART_LSR) & UART_LSR_THRE));
211 ps2ser_out(UART_TX, chr);
215 static int ps2ser_getc_hw(void)
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;
225 #ifdef CONFIG_MPC5xxx
226 if (psc->psc_status & PSC_SR_RXRDY) {
227 res = (psc->psc_buffer_8);
229 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
230 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
231 if (com_port->lsr & UART_LSR_DR) {
235 if (ps2ser_in(UART_LSR) & UART_LSR_DR) {
236 res = (ps2ser_in(UART_RX));
243 int ps2ser_getc(void)
252 flags = disable_interrupts();
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);
260 chr = ps2ser_getc_hw();
265 if (flags) enable_interrupts();
268 printf("0x%02x\n", chr);
274 int ps2ser_check(void)
278 flags = disable_interrupts();
279 ps2ser_interrupt(NULL);
280 if (flags) enable_interrupts();
282 return atomic_read(&ps2buf_cnt);
285 static void ps2ser_interrupt(void *dev_id)
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;
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;
304 status = ps2ser_in(UART_IIR);
306 if (chr < 0) continue;
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);
313 printf ("ps2ser.c: buffer overflow\n");
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);
321 } while (status & UART_IIR_RDI);
324 if (atomic_read(&ps2buf_cnt)) {
325 ps2mult_callback(atomic_read(&ps2buf_cnt));