]>
git.ipfire.org Git - people/ms/u-boot.git/blob - drivers/input/ps2ser.c
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 ***********************************************************************/
19 #include <asm/atomic.h>
21 #if defined(CFG_NS16550) || defined(CONFIG_MPC85xx)
25 DECLARE_GLOBAL_DATA_PTR
;
29 #define PS2SER_BAUD 57600
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
47 #error CONFIG_PS2SERIAL must be in 1 ... 6
50 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
51 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
53 #if CONFIG_PS2SERIAL == 1
54 #define COM_BASE (CFG_CCSRBAR+0x4500)
55 #elif CONFIG_PS2SERIAL == 2
56 #define COM_BASE (CFG_CCSRBAR+0x4600)
58 #error CONFIG_PS2SERIAL must be in 1 ... 2
61 #endif /* CONFIG_MPC5xxx / CONFIG_MPC8540 / other */
63 static int ps2ser_getc_hw(void);
64 static void ps2ser_interrupt(void *dev_id
);
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
;
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
;
81 volatile struct mpc5xxx_psc
*psc
= (struct mpc5xxx_psc
*)PSC_BASE
;
82 unsigned long baseclk
;
86 psc
->command
= PSC_SEL_MODE_REG_1
;
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;
97 /* switch to UART mode */
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
;
106 psc
->mode
= PSC_MODE_ONE_STOP
;
108 /* set up UART divisor */
109 div
= (baseclk
+ (PS2SER_BAUD
/2)) / PS2SER_BAUD
;
110 psc
->ctur
= (div
>> 8) & 0xff;
111 psc
->ctlr
= div
& 0xff;
113 /* disable all interrupts */
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
;
124 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
125 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
126 int ps2ser_init(void)
128 NS16550_t com_port
= (NS16550_t
)COM_BASE
;
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
);
141 #else /* !CONFIG_MPC5xxx && !CONFIG_MPC8540 / other */
143 static inline unsigned int ps2ser_in(int offset
)
145 return readb((unsigned long) state
->iomem_base
+ offset
);
148 static inline void ps2ser_out(int offset
, int value
)
150 writeb(value
, (unsigned long) state
->iomem_base
+ offset
);
153 int ps2ser_init(void)
158 state
= rs_table
+ CONFIG_PS2SERIAL
;
160 quot
= state
->baud_base
/ PS2SER_BAUD
;
161 cval
= 0x3; /* 8N1 - 8 data bits, no parity bits, 1 stop bit */
163 /* Set speed, enable interrupts, enable FIFO
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
);
172 UART_FCR_ENABLE_FIFO
| UART_FCR_CLEAR_RCVR
| UART_FCR_CLEAR_XMIT
);
174 /* If we read 0xff from the LSR, there is no UART here
176 if (ps2ser_in(UART_LSR
) == 0xff) {
177 printf ("ps2ser.c: no UART found\n");
181 irq_install_handler(state
->irq
, ps2ser_interrupt
, NULL
);
185 #endif /* CONFIG_MPC5xxx / CONFIG_MPC8540 / other */
187 void ps2ser_putc(int chr
)
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
;
196 printf(">>>> 0x%02x\n", chr
);
199 #ifdef CONFIG_MPC5xxx
200 while (!(psc
->psc_status
& PSC_SR_TXRDY
));
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);
208 while (!(ps2ser_in(UART_LSR
) & UART_LSR_THRE
));
210 ps2ser_out(UART_TX
, chr
);
214 static int ps2ser_getc_hw(void)
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
;
224 #ifdef CONFIG_MPC5xxx
225 if (psc
->psc_status
& PSC_SR_RXRDY
) {
226 res
= (psc
->psc_buffer_8
);
228 #elif defined(CONFIG_MPC8540) || defined(CONFIG_MPC8541) || \
229 defined(CONFIG_MPC8548) || defined(CONFIG_MPC8555)
230 if (com_port
->lsr
& LSR_DR
) {
234 if (ps2ser_in(UART_LSR
) & UART_LSR_DR
) {
235 res
= (ps2ser_in(UART_RX
));
242 int ps2ser_getc(void)
251 flags
= disable_interrupts();
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
);
259 chr
= ps2ser_getc_hw();
264 if (flags
) enable_interrupts();
267 printf("0x%02x\n", chr
);
273 int ps2ser_check(void)
277 flags
= disable_interrupts();
278 ps2ser_interrupt(NULL
);
279 if (flags
) enable_interrupts();
281 return atomic_read(&ps2buf_cnt
);
284 static void ps2ser_interrupt(void *dev_id
)
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
;
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
;
303 status
= ps2ser_in(UART_IIR
);
305 if (chr
< 0) continue;
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
);
312 printf ("ps2ser.c: buffer overflow\n");
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
);
320 } while (status
& UART_IIR_RDI
);
323 if (atomic_read(&ps2buf_cnt
)) {
324 ps2mult_callback(atomic_read(&ps2buf_cnt
));