1 /***********************************************************************
4 * DENX Software Engineering
5 * Wolfgang Denk, wd@denx.de
8 * Simple 16550A serial driver
10 * Originally from linux source (drivers/char/ps2ser.c)
12 * Used by the PS/2 multiplexer driver (ps2mult.c)
14 ***********************************************************************/
18 #ifdef CONFIG_PS2SERIAL
21 #include <asm/atomic.h>
23 #if defined(CFG_NS16550) || defined(CONFIG_MPC85xx)
27 DECLARE_GLOBAL_DATA_PTR
;
31 #define PS2SER_BAUD 57600
34 #if CONFIG_PS2SERIAL == 1
35 #define PSC_BASE MPC5XXX_PSC1
36 #elif CONFIG_PS2SERIAL == 2
37 #define PSC_BASE MPC5XXX_PSC2
38 #elif CONFIG_PS2SERIAL == 3
39 #define PSC_BASE MPC5XXX_PSC3
40 #elif defined(CONFIG_MGT5100)
41 #error CONFIG_PS2SERIAL must be in 1, 2 or 3
42 #elif CONFIG_PS2SERIAL == 4
43 #define PSC_BASE MPC5XXX_PSC4
44 #elif CONFIG_PS2SERIAL == 5
45 #define PSC_BASE MPC5XXX_PSC5
46 #elif CONFIG_PS2SERIAL == 6
47 #define PSC_BASE MPC5XXX_PSC6
49 #error CONFIG_PS2SERIAL must be in 1 ... 6
52 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
54 #if CONFIG_PS2SERIAL == 1
55 #define COM_BASE (CFG_CCSRBAR+0x4500)
56 #elif CONFIG_PS2SERIAL == 2
57 #define COM_BASE (CFG_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) && !defined(CONFIG_MPC8541) && !defined(CONFIG_MPC8555)
69 static struct serial_state
*state
;
72 static u_char ps2buf
[PS2BUF_SIZE
];
73 static atomic_t ps2buf_cnt
;
74 static int ps2buf_in_idx
;
75 static int ps2buf_out_idx
;
80 volatile struct mpc5xxx_psc
*psc
= (struct mpc5xxx_psc
*)PSC_BASE
;
81 unsigned long baseclk
;
85 psc
->command
= PSC_SEL_MODE_REG_1
;
87 /* select clock sources */
88 #if defined(CONFIG_MGT5100)
89 psc
->psc_clock_select
= 0xdd00;
90 baseclk
= (CFG_MPC5XXX_CLKIN
+ 16) / 32;
91 #elif defined(CONFIG_MPC5200)
92 psc
->psc_clock_select
= 0;
93 baseclk
= (gd
->ipb_clk
+ 16) / 32;
96 /* switch to UART mode */
99 /* configure parity, bit length and so on */
100 #if defined(CONFIG_MGT5100)
101 psc
->mode
= PSC_MODE_ERR
| PSC_MODE_8_BITS
| PSC_MODE_PARNONE
;
102 #elif defined(CONFIG_MPC5200)
103 psc
->mode
= PSC_MODE_8_BITS
| PSC_MODE_PARNONE
;
105 psc
->mode
= PSC_MODE_ONE_STOP
;
107 /* set up UART divisor */
108 div
= (baseclk
+ (PS2SER_BAUD
/2)) / PS2SER_BAUD
;
109 psc
->ctur
= (div
>> 8) & 0xff;
110 psc
->ctlr
= div
& 0xff;
112 /* disable all interrupts */
115 /* reset and enable Rx/Tx */
116 psc
->command
= PSC_RST_RX
;
117 psc
->command
= PSC_RST_TX
;
118 psc
->command
= PSC_RX_ENABLE
| PSC_TX_ENABLE
;
123 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
124 int ps2ser_init(void)
126 NS16550_t com_port
= (NS16550_t
)COM_BASE
;
128 com_port
->ier
= 0x00;
129 com_port
->lcr
= LCR_BKSE
| LCR_8N1
;
130 com_port
->dll
= (CFG_NS16550_CLK
/ 16 / PS2SER_BAUD
) & 0xff;
131 com_port
->dlm
= ((CFG_NS16550_CLK
/ 16 / PS2SER_BAUD
) >> 8) & 0xff;
132 com_port
->lcr
= LCR_8N1
;
133 com_port
->mcr
= (MCR_DTR
| MCR_RTS
);
134 com_port
->fcr
= (FCR_FIFO_EN
| FCR_RXSR
| FCR_TXSR
);
139 #else /* !CONFIG_MPC5xxx && !CONFIG_MPC8540 / other */
141 static inline unsigned int ps2ser_in(int offset
)
143 return readb((unsigned long) state
->iomem_base
+ offset
);
146 static inline void ps2ser_out(int offset
, int value
)
148 writeb(value
, (unsigned long) state
->iomem_base
+ offset
);
151 int ps2ser_init(void)
156 state
= rs_table
+ CONFIG_PS2SERIAL
;
158 quot
= state
->baud_base
/ PS2SER_BAUD
;
159 cval
= 0x3; /* 8N1 - 8 data bits, no parity bits, 1 stop bit */
161 /* Set speed, enable interrupts, enable FIFO
163 ps2ser_out(UART_LCR
, cval
| UART_LCR_DLAB
);
164 ps2ser_out(UART_DLL
, quot
& 0xff);
165 ps2ser_out(UART_DLM
, quot
>> 8);
166 ps2ser_out(UART_LCR
, cval
);
167 ps2ser_out(UART_IER
, UART_IER_RDI
);
168 ps2ser_out(UART_MCR
, UART_MCR_OUT2
| UART_MCR_DTR
| UART_MCR_RTS
);
170 UART_FCR_ENABLE_FIFO
| UART_FCR_CLEAR_RCVR
| UART_FCR_CLEAR_XMIT
);
172 /* If we read 0xff from the LSR, there is no UART here
174 if (ps2ser_in(UART_LSR
) == 0xff) {
175 printf ("ps2ser.c: no UART found\n");
179 irq_install_handler(state
->irq
, ps2ser_interrupt
, NULL
);
183 #endif /* CONFIG_MPC5xxx / CONFIG_MPC8540 / other */
185 void ps2ser_putc(int chr
)
187 #ifdef CONFIG_MPC5xxx
188 volatile struct mpc5xxx_psc
*psc
= (struct mpc5xxx_psc
*)PSC_BASE
;
189 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
190 NS16550_t com_port
= (NS16550_t
)COM_BASE
;
193 printf(">>>> 0x%02x\n", chr
);
196 #ifdef CONFIG_MPC5xxx
197 while (!(psc
->psc_status
& PSC_SR_TXRDY
));
199 psc
->psc_buffer_8
= chr
;
200 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
201 while ((com_port
->lsr
& LSR_THRE
) == 0);
204 while (!(ps2ser_in(UART_LSR
) & UART_LSR_THRE
));
206 ps2ser_out(UART_TX
, chr
);
210 static int ps2ser_getc_hw(void)
212 #ifdef CONFIG_MPC5xxx
213 volatile struct mpc5xxx_psc
*psc
= (struct mpc5xxx_psc
*)PSC_BASE
;
214 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
215 NS16550_t com_port
= (NS16550_t
)COM_BASE
;
219 #ifdef CONFIG_MPC5xxx
220 if (psc
->psc_status
& PSC_SR_RXRDY
) {
221 res
= (psc
->psc_buffer_8
);
223 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
224 if (com_port
->lsr
& LSR_DR
) {
228 if (ps2ser_in(UART_LSR
) & UART_LSR_DR
) {
229 res
= (ps2ser_in(UART_RX
));
236 int ps2ser_getc(void)
245 flags
= disable_interrupts();
248 if (atomic_read(&ps2buf_cnt
) != 0) {
249 chr
= ps2buf
[ps2buf_out_idx
++];
250 ps2buf_out_idx
&= (PS2BUF_SIZE
- 1);
251 atomic_dec(&ps2buf_cnt
);
253 chr
= ps2ser_getc_hw();
258 if (flags
) enable_interrupts();
261 printf("0x%02x\n", chr
);
267 int ps2ser_check(void)
271 flags
= disable_interrupts();
272 ps2ser_interrupt(NULL
);
273 if (flags
) enable_interrupts();
275 return atomic_read(&ps2buf_cnt
);
278 static void ps2ser_interrupt(void *dev_id
)
280 #ifdef CONFIG_MPC5xxx
281 volatile struct mpc5xxx_psc
*psc
= (struct mpc5xxx_psc
*)PSC_BASE
;
282 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
283 NS16550_t com_port
= (NS16550_t
)COM_BASE
;
289 chr
= ps2ser_getc_hw();
290 #ifdef CONFIG_MPC5xxx
291 status
= psc
->psc_status
;
292 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
293 status
= com_port
->lsr
;
295 status
= ps2ser_in(UART_IIR
);
297 if (chr
< 0) continue;
299 if (atomic_read(&ps2buf_cnt
) < PS2BUF_SIZE
) {
300 ps2buf
[ps2buf_in_idx
++] = chr
;
301 ps2buf_in_idx
&= (PS2BUF_SIZE
- 1);
302 atomic_inc(&ps2buf_cnt
);
304 printf ("ps2ser.c: buffer overflow\n");
306 #ifdef CONFIG_MPC5xxx
307 } while (status
& PSC_SR_RXRDY
);
308 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || defined(CONFIG_MPC8555)
309 } while (status
& LSR_DR
);
311 } while (status
& UART_IIR_RDI
);
314 if (atomic_read(&ps2buf_cnt
)) {
315 ps2mult_callback(atomic_read(&ps2buf_cnt
));
319 #endif /* CONFIG_PS2SERIAL */