xref: /rk3399_rockchip-uboot/drivers/input/ps2ser.c (revision 064b55cfcb25c0f7692ecf6d4a38f12cd82739f7)
116b195c8SJean-Christophe PLAGNIOL-VILLARD /***********************************************************************
216b195c8SJean-Christophe PLAGNIOL-VILLARD  *
3200779e3SDetlev Zundel  * (C) Copyright 2004-2009
416b195c8SJean-Christophe PLAGNIOL-VILLARD  * DENX Software Engineering
516b195c8SJean-Christophe PLAGNIOL-VILLARD  * Wolfgang Denk, wd@denx.de
616b195c8SJean-Christophe PLAGNIOL-VILLARD  *
716b195c8SJean-Christophe PLAGNIOL-VILLARD  * Simple 16550A serial driver
816b195c8SJean-Christophe PLAGNIOL-VILLARD  *
916b195c8SJean-Christophe PLAGNIOL-VILLARD  * Originally from linux source (drivers/char/ps2ser.c)
1016b195c8SJean-Christophe PLAGNIOL-VILLARD  *
1116b195c8SJean-Christophe PLAGNIOL-VILLARD  * Used by the PS/2 multiplexer driver (ps2mult.c)
1216b195c8SJean-Christophe PLAGNIOL-VILLARD  *
1316b195c8SJean-Christophe PLAGNIOL-VILLARD  ***********************************************************************/
1416b195c8SJean-Christophe PLAGNIOL-VILLARD 
1516b195c8SJean-Christophe PLAGNIOL-VILLARD #include <common.h>
1616b195c8SJean-Christophe PLAGNIOL-VILLARD 
1716b195c8SJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h>
1816b195c8SJean-Christophe PLAGNIOL-VILLARD #include <asm/atomic.h>
1916b195c8SJean-Christophe PLAGNIOL-VILLARD #include <ps2mult.h>
20200779e3SDetlev Zundel /* This is needed for ns16550.h */
21200779e3SDetlev Zundel #ifndef CONFIG_SYS_NS16550_REG_SIZE
22200779e3SDetlev Zundel #define CONFIG_SYS_NS16550_REG_SIZE 1
2316b195c8SJean-Christophe PLAGNIOL-VILLARD #endif
24200779e3SDetlev Zundel #include <ns16550.h>
2516b195c8SJean-Christophe PLAGNIOL-VILLARD 
2616b195c8SJean-Christophe PLAGNIOL-VILLARD DECLARE_GLOBAL_DATA_PTR;
2716b195c8SJean-Christophe PLAGNIOL-VILLARD 
2816b195c8SJean-Christophe PLAGNIOL-VILLARD /* #define	DEBUG */
2916b195c8SJean-Christophe PLAGNIOL-VILLARD 
3016b195c8SJean-Christophe PLAGNIOL-VILLARD #define PS2SER_BAUD	57600
3116b195c8SJean-Christophe PLAGNIOL-VILLARD 
3216b195c8SJean-Christophe PLAGNIOL-VILLARD #if CONFIG_PS2SERIAL == 1
336d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define COM_BASE (CONFIG_SYS_CCSRBAR+0x4500)
3416b195c8SJean-Christophe PLAGNIOL-VILLARD #elif CONFIG_PS2SERIAL == 2
356d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define COM_BASE (CONFIG_SYS_CCSRBAR+0x4600)
3616b195c8SJean-Christophe PLAGNIOL-VILLARD #else
3716b195c8SJean-Christophe PLAGNIOL-VILLARD #error CONFIG_PS2SERIAL must be in 1 ... 2
3816b195c8SJean-Christophe PLAGNIOL-VILLARD #endif
3916b195c8SJean-Christophe PLAGNIOL-VILLARD 
4016b195c8SJean-Christophe PLAGNIOL-VILLARD static int	ps2ser_getc_hw(void);
4116b195c8SJean-Christophe PLAGNIOL-VILLARD static void	ps2ser_interrupt(void *dev_id);
4216b195c8SJean-Christophe PLAGNIOL-VILLARD 
4316b195c8SJean-Christophe PLAGNIOL-VILLARD extern struct	serial_state rs_table[]; /* in serial.c */
4416b195c8SJean-Christophe PLAGNIOL-VILLARD 
4516b195c8SJean-Christophe PLAGNIOL-VILLARD static u_char	ps2buf[PS2BUF_SIZE];
4616b195c8SJean-Christophe PLAGNIOL-VILLARD static atomic_t	ps2buf_cnt;
4716b195c8SJean-Christophe PLAGNIOL-VILLARD static int	ps2buf_in_idx;
4816b195c8SJean-Christophe PLAGNIOL-VILLARD static int	ps2buf_out_idx;
4916b195c8SJean-Christophe PLAGNIOL-VILLARD 
ps2ser_init(void)5016b195c8SJean-Christophe PLAGNIOL-VILLARD int ps2ser_init(void)
5116b195c8SJean-Christophe PLAGNIOL-VILLARD {
5216b195c8SJean-Christophe PLAGNIOL-VILLARD 	NS16550_t com_port = (NS16550_t)COM_BASE;
5316b195c8SJean-Christophe PLAGNIOL-VILLARD 
5416b195c8SJean-Christophe PLAGNIOL-VILLARD 	com_port->ier = 0x00;
55200779e3SDetlev Zundel 	com_port->lcr = UART_LCR_BKSE | UART_LCR_8N1;
566d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	com_port->dll = (CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) & 0xff;
576d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	com_port->dlm = ((CONFIG_SYS_NS16550_CLK / 16 / PS2SER_BAUD) >> 8) & 0xff;
58200779e3SDetlev Zundel 	com_port->lcr = UART_LCR_8N1;
59200779e3SDetlev Zundel 	com_port->mcr = (UART_MCR_DTR | UART_MCR_RTS);
60200779e3SDetlev Zundel 	com_port->fcr = (UART_FCR_FIFO_EN | UART_FCR_RXSR | UART_FCR_TXSR);
6116b195c8SJean-Christophe PLAGNIOL-VILLARD 
6216b195c8SJean-Christophe PLAGNIOL-VILLARD 	return (0);
6316b195c8SJean-Christophe PLAGNIOL-VILLARD }
6416b195c8SJean-Christophe PLAGNIOL-VILLARD 
ps2ser_putc(int chr)6516b195c8SJean-Christophe PLAGNIOL-VILLARD void ps2ser_putc(int chr)
6616b195c8SJean-Christophe PLAGNIOL-VILLARD {
6716b195c8SJean-Christophe PLAGNIOL-VILLARD 	NS16550_t com_port = (NS16550_t)COM_BASE;
68*77efe35fSWolfgang Denk 	debug(">>>> 0x%02x\n", chr);
6916b195c8SJean-Christophe PLAGNIOL-VILLARD 
70200779e3SDetlev Zundel 	while ((com_port->lsr & UART_LSR_THRE) == 0);
7116b195c8SJean-Christophe PLAGNIOL-VILLARD 	com_port->thr = chr;
7216b195c8SJean-Christophe PLAGNIOL-VILLARD }
7316b195c8SJean-Christophe PLAGNIOL-VILLARD 
ps2ser_getc_hw(void)7416b195c8SJean-Christophe PLAGNIOL-VILLARD static int ps2ser_getc_hw(void)
7516b195c8SJean-Christophe PLAGNIOL-VILLARD {
7616b195c8SJean-Christophe PLAGNIOL-VILLARD 	NS16550_t com_port = (NS16550_t)COM_BASE;
7716b195c8SJean-Christophe PLAGNIOL-VILLARD 	int res = -1;
7816b195c8SJean-Christophe PLAGNIOL-VILLARD 
79200779e3SDetlev Zundel 	if (com_port->lsr & UART_LSR_DR) {
8016b195c8SJean-Christophe PLAGNIOL-VILLARD 		res = com_port->rbr;
8116b195c8SJean-Christophe PLAGNIOL-VILLARD 	}
8216b195c8SJean-Christophe PLAGNIOL-VILLARD 
8316b195c8SJean-Christophe PLAGNIOL-VILLARD 	return res;
8416b195c8SJean-Christophe PLAGNIOL-VILLARD }
8516b195c8SJean-Christophe PLAGNIOL-VILLARD 
ps2ser_getc(void)8616b195c8SJean-Christophe PLAGNIOL-VILLARD int ps2ser_getc(void)
8716b195c8SJean-Christophe PLAGNIOL-VILLARD {
8816b195c8SJean-Christophe PLAGNIOL-VILLARD 	volatile int chr;
8916b195c8SJean-Christophe PLAGNIOL-VILLARD 	int flags;
9016b195c8SJean-Christophe PLAGNIOL-VILLARD 
91*77efe35fSWolfgang Denk 	debug("<< ");
9216b195c8SJean-Christophe PLAGNIOL-VILLARD 
9316b195c8SJean-Christophe PLAGNIOL-VILLARD 	flags = disable_interrupts();
9416b195c8SJean-Christophe PLAGNIOL-VILLARD 
9516b195c8SJean-Christophe PLAGNIOL-VILLARD 	do {
9616b195c8SJean-Christophe PLAGNIOL-VILLARD 		if (atomic_read(&ps2buf_cnt) != 0) {
9716b195c8SJean-Christophe PLAGNIOL-VILLARD 			chr = ps2buf[ps2buf_out_idx++];
9816b195c8SJean-Christophe PLAGNIOL-VILLARD 			ps2buf_out_idx &= (PS2BUF_SIZE - 1);
9916b195c8SJean-Christophe PLAGNIOL-VILLARD 			atomic_dec(&ps2buf_cnt);
10016b195c8SJean-Christophe PLAGNIOL-VILLARD 		} else {
10116b195c8SJean-Christophe PLAGNIOL-VILLARD 			chr = ps2ser_getc_hw();
10216b195c8SJean-Christophe PLAGNIOL-VILLARD 		}
10316b195c8SJean-Christophe PLAGNIOL-VILLARD 	}
10416b195c8SJean-Christophe PLAGNIOL-VILLARD 	while (chr < 0);
10516b195c8SJean-Christophe PLAGNIOL-VILLARD 
106*77efe35fSWolfgang Denk 	if (flags)
107*77efe35fSWolfgang Denk 		enable_interrupts();
10816b195c8SJean-Christophe PLAGNIOL-VILLARD 
109*77efe35fSWolfgang Denk 	debug("0x%02x\n", chr);
11016b195c8SJean-Christophe PLAGNIOL-VILLARD 
11116b195c8SJean-Christophe PLAGNIOL-VILLARD 	return chr;
11216b195c8SJean-Christophe PLAGNIOL-VILLARD }
11316b195c8SJean-Christophe PLAGNIOL-VILLARD 
ps2ser_check(void)11416b195c8SJean-Christophe PLAGNIOL-VILLARD int ps2ser_check(void)
11516b195c8SJean-Christophe PLAGNIOL-VILLARD {
11616b195c8SJean-Christophe PLAGNIOL-VILLARD 	int flags;
11716b195c8SJean-Christophe PLAGNIOL-VILLARD 
11816b195c8SJean-Christophe PLAGNIOL-VILLARD 	flags = disable_interrupts();
11916b195c8SJean-Christophe PLAGNIOL-VILLARD 	ps2ser_interrupt(NULL);
12016b195c8SJean-Christophe PLAGNIOL-VILLARD 	if (flags) enable_interrupts();
12116b195c8SJean-Christophe PLAGNIOL-VILLARD 
12216b195c8SJean-Christophe PLAGNIOL-VILLARD 	return atomic_read(&ps2buf_cnt);
12316b195c8SJean-Christophe PLAGNIOL-VILLARD }
12416b195c8SJean-Christophe PLAGNIOL-VILLARD 
ps2ser_interrupt(void * dev_id)12516b195c8SJean-Christophe PLAGNIOL-VILLARD static void ps2ser_interrupt(void *dev_id)
12616b195c8SJean-Christophe PLAGNIOL-VILLARD {
12716b195c8SJean-Christophe PLAGNIOL-VILLARD 	NS16550_t com_port = (NS16550_t)COM_BASE;
12816b195c8SJean-Christophe PLAGNIOL-VILLARD 	int chr;
12916b195c8SJean-Christophe PLAGNIOL-VILLARD 	int status;
13016b195c8SJean-Christophe PLAGNIOL-VILLARD 
13116b195c8SJean-Christophe PLAGNIOL-VILLARD 	do {
13216b195c8SJean-Christophe PLAGNIOL-VILLARD 		chr = ps2ser_getc_hw();
133*77efe35fSWolfgang Denk 		status = com_port->lsr;
13416b195c8SJean-Christophe PLAGNIOL-VILLARD 		if (chr < 0) continue;
13516b195c8SJean-Christophe PLAGNIOL-VILLARD 
13616b195c8SJean-Christophe PLAGNIOL-VILLARD 		if (atomic_read(&ps2buf_cnt) < PS2BUF_SIZE) {
13716b195c8SJean-Christophe PLAGNIOL-VILLARD 			ps2buf[ps2buf_in_idx++] = chr;
13816b195c8SJean-Christophe PLAGNIOL-VILLARD 			ps2buf_in_idx &= (PS2BUF_SIZE - 1);
13916b195c8SJean-Christophe PLAGNIOL-VILLARD 			atomic_inc(&ps2buf_cnt);
14016b195c8SJean-Christophe PLAGNIOL-VILLARD 		} else {
14116b195c8SJean-Christophe PLAGNIOL-VILLARD 			printf ("ps2ser.c: buffer overflow\n");
14216b195c8SJean-Christophe PLAGNIOL-VILLARD 		}
143*77efe35fSWolfgang Denk 	} while (status & UART_LSR_DR);
14416b195c8SJean-Christophe PLAGNIOL-VILLARD 	if (atomic_read(&ps2buf_cnt)) {
14516b195c8SJean-Christophe PLAGNIOL-VILLARD 		ps2mult_callback(atomic_read(&ps2buf_cnt));
14616b195c8SJean-Christophe PLAGNIOL-VILLARD 	}
14716b195c8SJean-Christophe PLAGNIOL-VILLARD }
148