]>
git.ipfire.org Git - people/ms/u-boot.git/blob - drivers/ps2ser.c
e2a38dc3dccd923c1c807e48d5a8e25048b99f42
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>
26 #define PS2SER_BAUD 57600
29 #if CONFIG_PS2SERIAL == 1
30 #define PSC_BASE MPC5XXX_PSC1
31 #elif CONFIG_PS2SERIAL == 2
32 #define PSC_BASE MPC5XXX_PSC2
33 #elif CONFIG_PS2SERIAL == 3
34 #define PSC_BASE MPC5XXX_PSC3
35 #elif defined(CONFIG_MGT5100)
36 #error CONFIG_PS2SERIAL must be in 1, 2 or 3
37 #elif CONFIG_PS2SERIAL == 4
38 #define PSC_BASE MPC5XXX_PSC4
39 #elif CONFIG_PS2SERIAL == 5
40 #define PSC_BASE MPC5XXX_PSC5
41 #elif CONFIG_PS2SERIAL == 6
42 #define PSC_BASE MPC5XXX_PSC6
44 #error CONFIG_PS2SERIAL must be in 1 ... 6
46 #endif /* CONFIG_MPC5xxx */
48 static int ps2ser_getc_hw(void);
49 static void ps2ser_interrupt(void *dev_id
);
51 extern struct serial_state rs_table
[]; /* in serial.c */
52 #ifndef CONFIG_MPC5xxx
53 static struct serial_state
*state
;
56 static u_char ps2buf
[PS2BUF_SIZE
];
57 static atomic_t ps2buf_cnt
;
58 static int ps2buf_in_idx
;
59 static int ps2buf_out_idx
;
64 DECLARE_GLOBAL_DATA_PTR
;
66 volatile struct mpc5xxx_psc
*psc
= (struct mpc5xxx_psc
*)PSC_BASE
;
67 unsigned long baseclk
;
71 psc
->command
= PSC_SEL_MODE_REG_1
;
73 /* select clock sources */
74 #if defined(CONFIG_MGT5100)
75 psc
->psc_clock_select
= 0xdd00;
76 baseclk
= (CFG_MPC5XXX_CLKIN
+ 16) / 32;
77 #elif defined(CONFIG_MPC5200)
78 psc
->psc_clock_select
= 0;
79 baseclk
= (gd
->ipb_clk
+ 16) / 32;
82 /* switch to UART mode */
85 /* configure parity, bit length and so on */
86 #if defined(CONFIG_MGT5100)
87 psc
->mode
= PSC_MODE_ERR
| PSC_MODE_8_BITS
| PSC_MODE_PARNONE
;
88 #elif defined(CONFIG_MPC5200)
89 psc
->mode
= PSC_MODE_8_BITS
| PSC_MODE_PARNONE
;
91 psc
->mode
= PSC_MODE_ONE_STOP
;
93 /* set up UART divisor */
94 div
= (baseclk
+ (PS2SER_BAUD
/2)) / PS2SER_BAUD
;
95 psc
->ctur
= (div
>> 8) & 0xff;
96 psc
->ctlr
= div
& 0xff;
98 /* disable all interrupts */
101 /* reset and enable Rx/Tx */
102 psc
->command
= PSC_RST_RX
;
103 psc
->command
= PSC_RST_TX
;
104 psc
->command
= PSC_RX_ENABLE
| PSC_TX_ENABLE
;
109 #else /* !CONFIG_MPC5xxx */
111 static inline unsigned int ps2ser_in(int offset
)
113 return readb((unsigned long) state
->iomem_base
+ offset
);
116 static inline void ps2ser_out(int offset
, int value
)
118 writeb(value
, (unsigned long) state
->iomem_base
+ offset
);
121 int ps2ser_init(void)
126 state
= rs_table
+ CONFIG_PS2SERIAL
;
128 quot
= state
->baud_base
/ PS2SER_BAUD
;
129 cval
= 0x3; /* 8N1 - 8 data bits, no parity bits, 1 stop bit */
131 /* Set speed, enable interrupts, enable FIFO
133 ps2ser_out(UART_LCR
, cval
| UART_LCR_DLAB
);
134 ps2ser_out(UART_DLL
, quot
& 0xff);
135 ps2ser_out(UART_DLM
, quot
>> 8);
136 ps2ser_out(UART_LCR
, cval
);
137 ps2ser_out(UART_IER
, UART_IER_RDI
);
138 ps2ser_out(UART_MCR
, UART_MCR_OUT2
| UART_MCR_DTR
| UART_MCR_RTS
);
140 UART_FCR_ENABLE_FIFO
| UART_FCR_CLEAR_RCVR
| UART_FCR_CLEAR_XMIT
);
142 /* If we read 0xff from the LSR, there is no UART here
144 if (ps2ser_in(UART_LSR
) == 0xff) {
145 printf ("ps2ser.c: no UART found\n");
149 irq_install_handler(state
->irq
, ps2ser_interrupt
, NULL
);
153 #endif /* CONFIG_MPC5xxx */
155 void ps2ser_putc(int chr
)
157 #ifdef CONFIG_MPC5xxx
158 volatile struct mpc5xxx_psc
*psc
= (struct mpc5xxx_psc
*)PSC_BASE
;
161 printf(">>>> 0x%02x\n", chr
);
164 #ifdef CONFIG_MPC5xxx
165 while (!(psc
->psc_status
& PSC_SR_TXRDY
));
167 psc
->psc_buffer_8
= chr
;
169 while (!(ps2ser_in(UART_LSR
) & UART_LSR_THRE
));
171 ps2ser_out(UART_TX
, chr
);
175 static int ps2ser_getc_hw(void)
177 #ifdef CONFIG_MPC5xxx
178 volatile struct mpc5xxx_psc
*psc
= (struct mpc5xxx_psc
*)PSC_BASE
;
182 #ifdef CONFIG_MPC5xxx
183 if (psc
->psc_status
& PSC_SR_RXRDY
) {
184 res
= (psc
->psc_buffer_8
);
187 if (ps2ser_in(UART_LSR
) & UART_LSR_DR
) {
188 res
= (ps2ser_in(UART_RX
));
195 int ps2ser_getc(void)
204 flags
= disable_interrupts();
207 if (atomic_read(&ps2buf_cnt
) != 0) {
208 chr
= ps2buf
[ps2buf_out_idx
++];
209 ps2buf_out_idx
&= (PS2BUF_SIZE
- 1);
210 atomic_dec(&ps2buf_cnt
);
212 chr
= ps2ser_getc_hw();
217 if (flags
) enable_interrupts();
220 printf("0x%02x\n", chr
);
226 int ps2ser_check(void)
230 flags
= disable_interrupts();
231 ps2ser_interrupt(NULL
);
232 if (flags
) enable_interrupts();
234 return atomic_read(&ps2buf_cnt
);
237 static void ps2ser_interrupt(void *dev_id
)
239 #ifdef CONFIG_MPC5xxx
240 volatile struct mpc5xxx_psc
*psc
= (struct mpc5xxx_psc
*)PSC_BASE
;
246 chr
= ps2ser_getc_hw();
247 #ifdef CONFIG_MPC5xxx
248 status
= psc
->psc_status
;
250 status
= ps2ser_in(UART_IIR
);
252 if (chr
< 0) continue;
254 if (atomic_read(&ps2buf_cnt
) < PS2BUF_SIZE
) {
255 ps2buf
[ps2buf_in_idx
++] = chr
;
256 ps2buf_in_idx
&= (PS2BUF_SIZE
- 1);
257 atomic_inc(&ps2buf_cnt
);
259 printf ("ps2ser.c: buffer overflow\n");
261 #ifdef CONFIG_MPC5xxx
262 } while (status
& PSC_SR_RXRDY
);
264 } while (status
& UART_IIR_RDI
);
267 if (atomic_read(&ps2buf_cnt
)) {
268 ps2mult_callback(atomic_read(&ps2buf_cnt
));
272 #endif /* CONFIG_PS2SERIAL */