xref: /OK3568_Linux_fs/u-boot/drivers/serial/ns16550.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * COM1 NS16550 support
3*4882a593Smuzhiyun  * originally from linux source (arch/powerpc/boot/ns16550.c)
4*4882a593Smuzhiyun  * modified to use CONFIG_SYS_ISA_MEM and new defines
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <clk.h>
9*4882a593Smuzhiyun #include <dm.h>
10*4882a593Smuzhiyun #include <errno.h>
11*4882a593Smuzhiyun #include <ns16550.h>
12*4882a593Smuzhiyun #include <serial.h>
13*4882a593Smuzhiyun #include <watchdog.h>
14*4882a593Smuzhiyun #include <linux/types.h>
15*4882a593Smuzhiyun #include <asm/io.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define UART_LCRVAL UART_LCR_8N1		/* 8 data, 1 stop, no parity */
20*4882a593Smuzhiyun #define UART_MCRVAL (UART_MCR_DTR | \
21*4882a593Smuzhiyun 		     UART_MCR_RTS)		/* RTS/DTR */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #ifndef CONFIG_DM_SERIAL
24*4882a593Smuzhiyun #ifdef CONFIG_SYS_NS16550_PORT_MAPPED
25*4882a593Smuzhiyun #define serial_out(x, y)	outb(x, (ulong)y)
26*4882a593Smuzhiyun #define serial_in(y)		inb((ulong)y)
27*4882a593Smuzhiyun #elif defined(CONFIG_SYS_NS16550_MEM32) && (CONFIG_SYS_NS16550_REG_SIZE > 0)
28*4882a593Smuzhiyun #define serial_out(x, y)	out_be32(y, x)
29*4882a593Smuzhiyun #define serial_in(y)		in_be32(y)
30*4882a593Smuzhiyun #elif defined(CONFIG_SYS_NS16550_MEM32) && (CONFIG_SYS_NS16550_REG_SIZE < 0)
31*4882a593Smuzhiyun #define serial_out(x, y)	out_le32(y, x)
32*4882a593Smuzhiyun #define serial_in(y)		in_le32(y)
33*4882a593Smuzhiyun #else
34*4882a593Smuzhiyun #define serial_out(x, y)	writeb(x, y)
35*4882a593Smuzhiyun #define serial_in(y)		readb(y)
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun #endif /* !CONFIG_DM_SERIAL */
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #if defined(CONFIG_SOC_KEYSTONE)
40*4882a593Smuzhiyun #define UART_REG_VAL_PWREMU_MGMT_UART_DISABLE   0
41*4882a593Smuzhiyun #define UART_REG_VAL_PWREMU_MGMT_UART_ENABLE ((1 << 14) | (1 << 13) | (1 << 0))
42*4882a593Smuzhiyun #undef UART_MCRVAL
43*4882a593Smuzhiyun #ifdef CONFIG_SERIAL_HW_FLOW_CONTROL
44*4882a593Smuzhiyun #define UART_MCRVAL             (UART_MCR_RTS | UART_MCR_AFE)
45*4882a593Smuzhiyun #else
46*4882a593Smuzhiyun #define UART_MCRVAL             (UART_MCR_RTS)
47*4882a593Smuzhiyun #endif
48*4882a593Smuzhiyun #endif
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #ifndef CONFIG_SYS_NS16550_IER
51*4882a593Smuzhiyun #define CONFIG_SYS_NS16550_IER  0x00
52*4882a593Smuzhiyun #endif /* CONFIG_SYS_NS16550_IER */
53*4882a593Smuzhiyun 
serial_out_shift(void * addr,int shift,int value)54*4882a593Smuzhiyun static inline void serial_out_shift(void *addr, int shift, int value)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun #ifdef CONFIG_SYS_NS16550_PORT_MAPPED
57*4882a593Smuzhiyun 	outb(value, (ulong)addr);
58*4882a593Smuzhiyun #elif defined(CONFIG_SYS_NS16550_MEM32) && !defined(CONFIG_SYS_BIG_ENDIAN)
59*4882a593Smuzhiyun 	out_le32(addr, value);
60*4882a593Smuzhiyun #elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN)
61*4882a593Smuzhiyun 	out_be32(addr, value);
62*4882a593Smuzhiyun #elif defined(CONFIG_SYS_NS16550_MEM32)
63*4882a593Smuzhiyun 	writel(value, addr);
64*4882a593Smuzhiyun #elif defined(CONFIG_SYS_BIG_ENDIAN)
65*4882a593Smuzhiyun 	writeb(value, addr + (1 << shift) - 1);
66*4882a593Smuzhiyun #else
67*4882a593Smuzhiyun 	writeb(value, addr);
68*4882a593Smuzhiyun #endif
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
serial_in_shift(void * addr,int shift)71*4882a593Smuzhiyun static inline int serial_in_shift(void *addr, int shift)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun #ifdef CONFIG_SYS_NS16550_PORT_MAPPED
74*4882a593Smuzhiyun 	return inb((ulong)addr);
75*4882a593Smuzhiyun #elif defined(CONFIG_SYS_NS16550_MEM32) && !defined(CONFIG_SYS_BIG_ENDIAN)
76*4882a593Smuzhiyun 	return in_le32(addr);
77*4882a593Smuzhiyun #elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN)
78*4882a593Smuzhiyun 	return in_be32(addr);
79*4882a593Smuzhiyun #elif defined(CONFIG_SYS_NS16550_MEM32)
80*4882a593Smuzhiyun 	return readl(addr);
81*4882a593Smuzhiyun #elif defined(CONFIG_SYS_BIG_ENDIAN)
82*4882a593Smuzhiyun 	return readb(addr + (1 << shift) - 1);
83*4882a593Smuzhiyun #else
84*4882a593Smuzhiyun 	return readb(addr);
85*4882a593Smuzhiyun #endif
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun #ifdef CONFIG_DM_SERIAL
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun #ifndef CONFIG_SYS_NS16550_CLK
91*4882a593Smuzhiyun #define CONFIG_SYS_NS16550_CLK  0
92*4882a593Smuzhiyun #endif
93*4882a593Smuzhiyun 
ns16550_writeb(NS16550_t port,int offset,int value)94*4882a593Smuzhiyun static void ns16550_writeb(NS16550_t port, int offset, int value)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	struct ns16550_platdata *plat = port->plat;
97*4882a593Smuzhiyun 	unsigned char *addr;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	offset *= 1 << plat->reg_shift;
100*4882a593Smuzhiyun 	addr = (unsigned char *)plat->base + offset;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	/*
103*4882a593Smuzhiyun 	 * As far as we know it doesn't make sense to support selection of
104*4882a593Smuzhiyun 	 * these options at run-time, so use the existing CONFIG options.
105*4882a593Smuzhiyun 	 */
106*4882a593Smuzhiyun 	serial_out_shift(addr + plat->reg_offset, plat->reg_shift, value);
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
ns16550_readb(NS16550_t port,int offset)109*4882a593Smuzhiyun static int ns16550_readb(NS16550_t port, int offset)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	struct ns16550_platdata *plat = port->plat;
112*4882a593Smuzhiyun 	unsigned char *addr;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	offset *= 1 << plat->reg_shift;
115*4882a593Smuzhiyun 	addr = (unsigned char *)plat->base + offset;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	return serial_in_shift(addr + plat->reg_offset, plat->reg_shift);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
ns16550_getfcr(NS16550_t port)120*4882a593Smuzhiyun static u32 ns16550_getfcr(NS16550_t port)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	struct ns16550_platdata *plat = port->plat;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	return plat->fcr;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun /* We can clean these up once everything is moved to driver model */
128*4882a593Smuzhiyun #define serial_out(value, addr)	\
129*4882a593Smuzhiyun 	ns16550_writeb(com_port, \
130*4882a593Smuzhiyun 		(unsigned char *)addr - (unsigned char *)com_port, value)
131*4882a593Smuzhiyun #define serial_in(addr) \
132*4882a593Smuzhiyun 	ns16550_readb(com_port, \
133*4882a593Smuzhiyun 		(unsigned char *)addr - (unsigned char *)com_port)
134*4882a593Smuzhiyun #else
ns16550_getfcr(NS16550_t port)135*4882a593Smuzhiyun static u32 ns16550_getfcr(NS16550_t port)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	return UART_FCR_DEFVAL;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun #endif
140*4882a593Smuzhiyun 
ns16550_calc_divisor(NS16550_t port,int clock,int baudrate)141*4882a593Smuzhiyun int ns16550_calc_divisor(NS16550_t port, int clock, int baudrate)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	const unsigned int mode_x_div = 16;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	return DIV_ROUND_CLOSEST(clock, mode_x_div * baudrate);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
NS16550_setbrg(NS16550_t com_port,int baud_divisor)148*4882a593Smuzhiyun static void NS16550_setbrg(NS16550_t com_port, int baud_divisor)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun 	serial_out(UART_LCR_BKSE | UART_LCRVAL, &com_port->lcr);
151*4882a593Smuzhiyun 	serial_out(baud_divisor & 0xff, &com_port->dll);
152*4882a593Smuzhiyun 	serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
153*4882a593Smuzhiyun 	serial_out(UART_LCRVAL, &com_port->lcr);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
NS16550_init(NS16550_t com_port,int baud_divisor)156*4882a593Smuzhiyun void NS16550_init(NS16550_t com_port, int baud_divisor)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun #if (defined(CONFIG_SPL_BUILD) && \
159*4882a593Smuzhiyun 		(defined(CONFIG_OMAP34XX) || defined(CONFIG_OMAP44XX)))
160*4882a593Smuzhiyun 	/*
161*4882a593Smuzhiyun 	 * On some OMAP3/OMAP4 devices when UART3 is configured for boot mode
162*4882a593Smuzhiyun 	 * before SPL starts only THRE bit is set. We have to empty the
163*4882a593Smuzhiyun 	 * transmitter before initialization starts.
164*4882a593Smuzhiyun 	 */
165*4882a593Smuzhiyun 	if ((serial_in(&com_port->lsr) & (UART_LSR_TEMT | UART_LSR_THRE))
166*4882a593Smuzhiyun 	     == UART_LSR_THRE) {
167*4882a593Smuzhiyun 		if (baud_divisor != -1)
168*4882a593Smuzhiyun 			NS16550_setbrg(com_port, baud_divisor);
169*4882a593Smuzhiyun 		serial_out(0, &com_port->mdr1);
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun #endif
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	while (!(serial_in(&com_port->lsr) & UART_LSR_TEMT))
174*4882a593Smuzhiyun 		;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier);
177*4882a593Smuzhiyun #if defined(CONFIG_ARCH_OMAP2PLUS)
178*4882a593Smuzhiyun 	serial_out(0x7, &com_port->mdr1);	/* mode select reset TL16C750*/
179*4882a593Smuzhiyun #endif
180*4882a593Smuzhiyun 	serial_out(UART_MCRVAL, &com_port->mcr);
181*4882a593Smuzhiyun 	serial_out(ns16550_getfcr(com_port), &com_port->fcr);
182*4882a593Smuzhiyun 	if (baud_divisor != -1)
183*4882a593Smuzhiyun 		NS16550_setbrg(com_port, baud_divisor);
184*4882a593Smuzhiyun #if defined(CONFIG_ARCH_OMAP2PLUS) || defined(CONFIG_SOC_DA8XX)
185*4882a593Smuzhiyun 	/* /16 is proper to hit 115200 with 48MHz */
186*4882a593Smuzhiyun 	serial_out(0, &com_port->mdr1);
187*4882a593Smuzhiyun #endif
188*4882a593Smuzhiyun #if defined(CONFIG_SOC_KEYSTONE)
189*4882a593Smuzhiyun 	serial_out(UART_REG_VAL_PWREMU_MGMT_UART_ENABLE, &com_port->regC);
190*4882a593Smuzhiyun #endif
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun #ifndef CONFIG_NS16550_MIN_FUNCTIONS
NS16550_reinit(NS16550_t com_port,int baud_divisor)194*4882a593Smuzhiyun void NS16550_reinit(NS16550_t com_port, int baud_divisor)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier);
197*4882a593Smuzhiyun 	NS16550_setbrg(com_port, 0);
198*4882a593Smuzhiyun 	serial_out(UART_MCRVAL, &com_port->mcr);
199*4882a593Smuzhiyun 	serial_out(ns16550_getfcr(com_port), &com_port->fcr);
200*4882a593Smuzhiyun 	NS16550_setbrg(com_port, baud_divisor);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun #endif /* CONFIG_NS16550_MIN_FUNCTIONS */
203*4882a593Smuzhiyun 
NS16550_putc(NS16550_t com_port,char c)204*4882a593Smuzhiyun void NS16550_putc(NS16550_t com_port, char c)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	while ((serial_in(&com_port->lsr) & UART_LSR_THRE) == 0)
207*4882a593Smuzhiyun 		;
208*4882a593Smuzhiyun 	serial_out(c, &com_port->thr);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	/*
211*4882a593Smuzhiyun 	 * Call watchdog_reset() upon newline. This is done here in putc
212*4882a593Smuzhiyun 	 * since the environment code uses a single puts() to print the complete
213*4882a593Smuzhiyun 	 * environment upon "printenv". So we can't put this watchdog call
214*4882a593Smuzhiyun 	 * in puts().
215*4882a593Smuzhiyun 	 */
216*4882a593Smuzhiyun 	if (c == '\n')
217*4882a593Smuzhiyun 		WATCHDOG_RESET();
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun #ifndef CONFIG_NS16550_MIN_FUNCTIONS
NS16550_getc(NS16550_t com_port)221*4882a593Smuzhiyun char NS16550_getc(NS16550_t com_port)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	while ((serial_in(&com_port->lsr) & UART_LSR_DR) == 0) {
224*4882a593Smuzhiyun #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_TTY)
225*4882a593Smuzhiyun 		extern void usbtty_poll(void);
226*4882a593Smuzhiyun 		usbtty_poll();
227*4882a593Smuzhiyun #endif
228*4882a593Smuzhiyun 		WATCHDOG_RESET();
229*4882a593Smuzhiyun 	}
230*4882a593Smuzhiyun 	return serial_in(&com_port->rbr);
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun 
NS16550_tstc(NS16550_t com_port)233*4882a593Smuzhiyun int NS16550_tstc(NS16550_t com_port)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	return (serial_in(&com_port->lsr) & UART_LSR_DR) != 0;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun #endif /* CONFIG_NS16550_MIN_FUNCTIONS */
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_UART_NS16550
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun #include <debug_uart.h>
243*4882a593Smuzhiyun 
_debug_uart_init(void)244*4882a593Smuzhiyun static inline void _debug_uart_init(void)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
247*4882a593Smuzhiyun 	int baud_divisor;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	if (gd && gd->flags & GD_FLG_DISABLE_CONSOLE)
250*4882a593Smuzhiyun 		return;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	if (gd && gd->serial.using_pre_serial)
253*4882a593Smuzhiyun 		return;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	/*
256*4882a593Smuzhiyun 	 * We copy the code from above because it is already horribly messy.
257*4882a593Smuzhiyun 	 * Trying to refactor to nicely remove the duplication doesn't seem
258*4882a593Smuzhiyun 	 * feasible. The better fix is to move all users of this driver to
259*4882a593Smuzhiyun 	 * driver model.
260*4882a593Smuzhiyun 	 */
261*4882a593Smuzhiyun 	baud_divisor = ns16550_calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK,
262*4882a593Smuzhiyun 					    CONFIG_BAUDRATE);
263*4882a593Smuzhiyun 	serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER);
264*4882a593Smuzhiyun 	serial_dout(&com_port->mcr, UART_MCRVAL);
265*4882a593Smuzhiyun 	serial_dout(&com_port->fcr, UART_FCR_DEFVAL);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
268*4882a593Smuzhiyun 	serial_dout(&com_port->dll, baud_divisor & 0xff);
269*4882a593Smuzhiyun 	serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
270*4882a593Smuzhiyun 	serial_dout(&com_port->lcr, UART_LCRVAL);
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun 
_debug_uart_putc(int ch)273*4882a593Smuzhiyun static inline void _debug_uart_putc(int ch)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun 	struct NS16550 *com_port;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	if (gd && gd->flags & GD_FLG_DISABLE_CONSOLE)
278*4882a593Smuzhiyun 		return;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	if (gd && gd->serial.addr)
281*4882a593Smuzhiyun 		com_port = (struct NS16550 *)gd->serial.addr;
282*4882a593Smuzhiyun 	else
283*4882a593Smuzhiyun 		com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	while (!(serial_din(&com_port->lsr) & UART_LSR_THRE))
286*4882a593Smuzhiyun 		;
287*4882a593Smuzhiyun 	serial_dout(&com_port->thr, ch);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
_debug_uart_getc(void)290*4882a593Smuzhiyun static inline int _debug_uart_getc(void)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	struct NS16550 *com_port;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	if (gd && gd->flags & GD_FLG_DISABLE_CONSOLE)
295*4882a593Smuzhiyun 		return 0;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	if (gd && gd->serial.addr)
298*4882a593Smuzhiyun 		com_port = (struct NS16550 *)gd->serial.addr;
299*4882a593Smuzhiyun 	else
300*4882a593Smuzhiyun 		com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	while (!(serial_din(&com_port->lsr) & UART_LSR_DR))
303*4882a593Smuzhiyun 		;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	return serial_din(&com_port->rbr);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
_debug_uart_tstc(int input)308*4882a593Smuzhiyun static inline int _debug_uart_tstc(int input)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	struct NS16550 *com_port;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	if (gd && gd->flags & GD_FLG_DISABLE_CONSOLE)
313*4882a593Smuzhiyun 		return 0;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	if (gd && gd->serial.addr)
316*4882a593Smuzhiyun 		com_port = (struct NS16550 *)gd->serial.addr;
317*4882a593Smuzhiyun 	else
318*4882a593Smuzhiyun 		com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (input)
321*4882a593Smuzhiyun 		return serial_din(&com_port->lsr) & UART_LSR_DR ? 1 : 0;
322*4882a593Smuzhiyun 	else
323*4882a593Smuzhiyun 		return serial_din(&com_port->lsr) & UART_LSR_THRE ? 0 : 1;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun 
_debug_uart_clrc(void)326*4882a593Smuzhiyun static inline int _debug_uart_clrc(void)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	struct NS16550 *com_port;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if (gd && gd->flags & GD_FLG_DISABLE_CONSOLE)
331*4882a593Smuzhiyun 		return 0;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	if (gd && gd->serial.addr)
334*4882a593Smuzhiyun 		com_port = (struct NS16550 *)gd->serial.addr;
335*4882a593Smuzhiyun 	else
336*4882a593Smuzhiyun 		com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	serial_dout(&com_port->fcr, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	return 0;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
_debug_uart_flushc(void)343*4882a593Smuzhiyun static inline int _debug_uart_flushc(void)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	struct NS16550 *com_port;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	if (gd && gd->flags & GD_FLG_DISABLE_CONSOLE)
348*4882a593Smuzhiyun 		return 0;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	if (gd && gd->serial.addr)
351*4882a593Smuzhiyun 		com_port = (struct NS16550 *)gd->serial.addr;
352*4882a593Smuzhiyun 	else
353*4882a593Smuzhiyun 		com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	/*
356*4882a593Smuzhiyun 	 * Wait fifo flush.
357*4882a593Smuzhiyun 	 *
358*4882a593Smuzhiyun 	 * UART_USR: bit2 trans_fifo_empty:
359*4882a593Smuzhiyun 	 *	0 = Transmit FIFO is not empty
360*4882a593Smuzhiyun 	 *	1 = Transmit FIFO is empty
361*4882a593Smuzhiyun 	 */
362*4882a593Smuzhiyun 	while (!(serial_din(&com_port->rbr + 0x1f) & 0x04))
363*4882a593Smuzhiyun 		;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	return 0;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun /* should use gd->baudrate, it can be updated by env callback: on_baudrate() */
_debug_uart_setbrg(void)369*4882a593Smuzhiyun static inline int _debug_uart_setbrg(void)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun 	struct NS16550 *com_port;
372*4882a593Smuzhiyun 	int baud_divisor;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	if (gd && gd->flags & GD_FLG_DISABLE_CONSOLE)
375*4882a593Smuzhiyun 		return 0;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	if (gd && gd->serial.addr) {
378*4882a593Smuzhiyun 		com_port = (struct NS16550 *)gd->serial.addr;
379*4882a593Smuzhiyun 		baud_divisor = ns16550_calc_divisor(com_port,
380*4882a593Smuzhiyun 			CONFIG_DEBUG_UART_CLOCK, gd->baudrate);
381*4882a593Smuzhiyun 	} else {
382*4882a593Smuzhiyun 		com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
383*4882a593Smuzhiyun 		baud_divisor = ns16550_calc_divisor(com_port,
384*4882a593Smuzhiyun 			CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
385*4882a593Smuzhiyun 	}
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
388*4882a593Smuzhiyun 	serial_dout(&com_port->dll, baud_divisor & 0xff);
389*4882a593Smuzhiyun 	serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
390*4882a593Smuzhiyun 	serial_dout(&com_port->lcr, UART_LCRVAL);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	return 0;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun DEBUG_UART_FUNCS
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun #endif
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_UART_OMAP
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun #include <debug_uart.h>
402*4882a593Smuzhiyun 
_debug_uart_init(void)403*4882a593Smuzhiyun static inline void _debug_uart_init(void)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun 	struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
406*4882a593Smuzhiyun 	int baud_divisor;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	baud_divisor = ns16550_calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK,
409*4882a593Smuzhiyun 					    CONFIG_BAUDRATE);
410*4882a593Smuzhiyun 	serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER);
411*4882a593Smuzhiyun 	serial_dout(&com_port->mdr1, 0x7);
412*4882a593Smuzhiyun 	serial_dout(&com_port->mcr, UART_MCRVAL);
413*4882a593Smuzhiyun 	serial_dout(&com_port->fcr, UART_FCR_DEFVAL);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
416*4882a593Smuzhiyun 	serial_dout(&com_port->dll, baud_divisor & 0xff);
417*4882a593Smuzhiyun 	serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
418*4882a593Smuzhiyun 	serial_dout(&com_port->lcr, UART_LCRVAL);
419*4882a593Smuzhiyun 	serial_dout(&com_port->mdr1, 0x0);
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun 
_debug_uart_putc(int ch)422*4882a593Smuzhiyun static inline void _debug_uart_putc(int ch)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	while (!(serial_din(&com_port->lsr) & UART_LSR_THRE))
427*4882a593Smuzhiyun 		;
428*4882a593Smuzhiyun 	serial_dout(&com_port->thr, ch);
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun DEBUG_UART_FUNCS
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun #endif
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun #ifdef CONFIG_DM_SERIAL
ns16550_serial_putc(struct udevice * dev,const char ch)436*4882a593Smuzhiyun static int ns16550_serial_putc(struct udevice *dev, const char ch)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	struct NS16550 *const com_port = dev_get_priv(dev);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	/*
441*4882a593Smuzhiyun 	 * Use fifo function.
442*4882a593Smuzhiyun 	 *
443*4882a593Smuzhiyun 	 * UART_USR: bit1 trans_fifo_not_full:
444*4882a593Smuzhiyun 	 *	0 = Transmit FIFO is full;
445*4882a593Smuzhiyun 	 *	1 = Transmit FIFO is not full;
446*4882a593Smuzhiyun 	 */
447*4882a593Smuzhiyun 	while (!(serial_in(&com_port->rbr + 0x1f) & 0x02))
448*4882a593Smuzhiyun 		;
449*4882a593Smuzhiyun 	serial_out(ch, &com_port->thr);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	/*
452*4882a593Smuzhiyun 	 * Call watchdog_reset() upon newline. This is done here in putc
453*4882a593Smuzhiyun 	 * since the environment code uses a single puts() to print the complete
454*4882a593Smuzhiyun 	 * environment upon "printenv". So we can't put this watchdog call
455*4882a593Smuzhiyun 	 * in puts().
456*4882a593Smuzhiyun 	 */
457*4882a593Smuzhiyun 	if (ch == '\n')
458*4882a593Smuzhiyun 		WATCHDOG_RESET();
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	return 0;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun 
ns16550_serial_pending(struct udevice * dev,bool input)463*4882a593Smuzhiyun static int ns16550_serial_pending(struct udevice *dev, bool input)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun 	struct NS16550 *const com_port = dev_get_priv(dev);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	if (input)
468*4882a593Smuzhiyun 		return serial_in(&com_port->lsr) & UART_LSR_DR ? 1 : 0;
469*4882a593Smuzhiyun 	else
470*4882a593Smuzhiyun 		return serial_in(&com_port->lsr) & UART_LSR_THRE ? 0 : 1;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
ns16550_serial_getc(struct udevice * dev)473*4882a593Smuzhiyun static int ns16550_serial_getc(struct udevice *dev)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	struct NS16550 *const com_port = dev_get_priv(dev);
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	if (!(serial_in(&com_port->lsr) & UART_LSR_DR))
478*4882a593Smuzhiyun 		return -EAGAIN;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	return serial_in(&com_port->rbr);
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
ns16550_serial_setbrg(struct udevice * dev,int baudrate)483*4882a593Smuzhiyun static int ns16550_serial_setbrg(struct udevice *dev, int baudrate)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	struct NS16550 *const com_port = dev_get_priv(dev);
486*4882a593Smuzhiyun 	struct ns16550_platdata *plat = com_port->plat;
487*4882a593Smuzhiyun 	int clock_divisor;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	clock_divisor = ns16550_calc_divisor(com_port, plat->clock, baudrate);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	NS16550_setbrg(com_port, clock_divisor);
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	return 0;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun 
ns16550_serial_clear(struct udevice * dev)496*4882a593Smuzhiyun static int ns16550_serial_clear(struct udevice *dev)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun 	struct NS16550 *const com_port = dev_get_priv(dev);
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	serial_out(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, &com_port->fcr);
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	return 0;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun 
ns16550_serial_probe(struct udevice * dev)505*4882a593Smuzhiyun int ns16550_serial_probe(struct udevice *dev)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	struct NS16550 *const com_port = dev_get_priv(dev);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	com_port->plat = dev_get_platdata(dev);
510*4882a593Smuzhiyun 	NS16550_init(com_port, -1);
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	return 0;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_CONTROL)
516*4882a593Smuzhiyun enum {
517*4882a593Smuzhiyun 	PORT_NS16550 = 0,
518*4882a593Smuzhiyun 	PORT_JZ4780,
519*4882a593Smuzhiyun };
520*4882a593Smuzhiyun #endif
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
ns16550_serial_ofdata_to_platdata(struct udevice * dev)523*4882a593Smuzhiyun int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun 	struct ns16550_platdata *plat = dev->platdata;
526*4882a593Smuzhiyun 	const u32 port_type = dev_get_driver_data(dev);
527*4882a593Smuzhiyun 	fdt_addr_t addr;
528*4882a593Smuzhiyun 	struct clk clk;
529*4882a593Smuzhiyun 	int err;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	/* try Processor Local Bus device first */
532*4882a593Smuzhiyun 	addr = dev_read_addr(dev);
533*4882a593Smuzhiyun #if defined(CONFIG_PCI) && CONFIG_IS_ENABLED(DM_PCI)
534*4882a593Smuzhiyun 	if (addr == FDT_ADDR_T_NONE) {
535*4882a593Smuzhiyun 		/* then try pci device */
536*4882a593Smuzhiyun 		struct fdt_pci_addr pci_addr;
537*4882a593Smuzhiyun 		u32 bar;
538*4882a593Smuzhiyun 		int ret;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 		/* we prefer to use a memory-mapped register */
541*4882a593Smuzhiyun 		ret = fdtdec_get_pci_addr(gd->fdt_blob, dev_of_offset(dev),
542*4882a593Smuzhiyun 					  FDT_PCI_SPACE_MEM32, "reg",
543*4882a593Smuzhiyun 					  &pci_addr);
544*4882a593Smuzhiyun 		if (ret) {
545*4882a593Smuzhiyun 			/* try if there is any i/o-mapped register */
546*4882a593Smuzhiyun 			ret = fdtdec_get_pci_addr(gd->fdt_blob,
547*4882a593Smuzhiyun 						  dev_of_offset(dev),
548*4882a593Smuzhiyun 						  FDT_PCI_SPACE_IO,
549*4882a593Smuzhiyun 						  "reg", &pci_addr);
550*4882a593Smuzhiyun 			if (ret)
551*4882a593Smuzhiyun 				return ret;
552*4882a593Smuzhiyun 		}
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 		ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
555*4882a593Smuzhiyun 		if (ret)
556*4882a593Smuzhiyun 			return ret;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 		addr = bar;
559*4882a593Smuzhiyun 	}
560*4882a593Smuzhiyun #endif
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	if (addr == FDT_ADDR_T_NONE)
563*4882a593Smuzhiyun 		return -EINVAL;
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun #ifdef CONFIG_SYS_NS16550_PORT_MAPPED
566*4882a593Smuzhiyun 	plat->base = addr;
567*4882a593Smuzhiyun #else
568*4882a593Smuzhiyun 	plat->base = (unsigned long)map_physmem(addr, 0, MAP_NOCACHE);
569*4882a593Smuzhiyun #endif
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	plat->reg_offset = dev_read_u32_default(dev, "reg-offset", 0);
572*4882a593Smuzhiyun 	plat->reg_shift = dev_read_u32_default(dev, "reg-shift", 0);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	err = clk_get_by_index(dev, 0, &clk);
575*4882a593Smuzhiyun 	if (!err) {
576*4882a593Smuzhiyun 		err = clk_get_rate(&clk);
577*4882a593Smuzhiyun 		if (!IS_ERR_VALUE(err))
578*4882a593Smuzhiyun 			plat->clock = err;
579*4882a593Smuzhiyun 	} else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
580*4882a593Smuzhiyun 		printf("ns16550 failed to get clock, err=%d\n", err);
581*4882a593Smuzhiyun 		return err;
582*4882a593Smuzhiyun 	}
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	if (!plat->clock)
585*4882a593Smuzhiyun 		plat->clock = dev_read_u32_default(dev, "clock-frequency",
586*4882a593Smuzhiyun 						   CONFIG_SYS_NS16550_CLK);
587*4882a593Smuzhiyun 	if (!plat->clock) {
588*4882a593Smuzhiyun 		debug("ns16550 clock not defined\n");
589*4882a593Smuzhiyun 		return -EINVAL;
590*4882a593Smuzhiyun 	}
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	plat->fcr = UART_FCR_DEFVAL;
593*4882a593Smuzhiyun 	if (port_type == PORT_JZ4780)
594*4882a593Smuzhiyun 		plat->fcr |= UART_FCR_UME;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	return 0;
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun #endif
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun const struct dm_serial_ops ns16550_serial_ops = {
601*4882a593Smuzhiyun 	.putc = ns16550_serial_putc,
602*4882a593Smuzhiyun 	.pending = ns16550_serial_pending,
603*4882a593Smuzhiyun 	.getc = ns16550_serial_getc,
604*4882a593Smuzhiyun 	.setbrg = ns16550_serial_setbrg,
605*4882a593Smuzhiyun 	.clear = ns16550_serial_clear,
606*4882a593Smuzhiyun };
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(SERIAL_PRESENT)
609*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
610*4882a593Smuzhiyun /*
611*4882a593Smuzhiyun  * Please consider existing compatible strings before adding a new
612*4882a593Smuzhiyun  * one to keep this table compact. Or you may add a generic "ns16550"
613*4882a593Smuzhiyun  * compatible string to your dts.
614*4882a593Smuzhiyun  */
615*4882a593Smuzhiyun static const struct udevice_id ns16550_serial_ids[] = {
616*4882a593Smuzhiyun 	{ .compatible = "ns16550",		.data = PORT_NS16550 },
617*4882a593Smuzhiyun 	{ .compatible = "ns16550a",		.data = PORT_NS16550 },
618*4882a593Smuzhiyun 	{ .compatible = "ingenic,jz4780-uart",	.data = PORT_JZ4780  },
619*4882a593Smuzhiyun 	{ .compatible = "nvidia,tegra20-uart",	.data = PORT_NS16550 },
620*4882a593Smuzhiyun 	{ .compatible = "snps,dw-apb-uart",	.data = PORT_NS16550 },
621*4882a593Smuzhiyun 	{ .compatible = "ti,omap2-uart",	.data = PORT_NS16550 },
622*4882a593Smuzhiyun 	{ .compatible = "ti,omap3-uart",	.data = PORT_NS16550 },
623*4882a593Smuzhiyun 	{ .compatible = "ti,omap4-uart",	.data = PORT_NS16550 },
624*4882a593Smuzhiyun 	{ .compatible = "ti,am3352-uart",	.data = PORT_NS16550 },
625*4882a593Smuzhiyun 	{ .compatible = "ti,am4372-uart",	.data = PORT_NS16550 },
626*4882a593Smuzhiyun 	{ .compatible = "ti,dra742-uart",	.data = PORT_NS16550 },
627*4882a593Smuzhiyun 	{}
628*4882a593Smuzhiyun };
629*4882a593Smuzhiyun #endif /* OF_CONTROL && !OF_PLATDATA */
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun /* TODO(sjg@chromium.org): Integrate this into a macro like CONFIG_IS_ENABLED */
632*4882a593Smuzhiyun #if !defined(CONFIG_TPL_BUILD) || defined(CONFIG_TPL_DM_SERIAL)
633*4882a593Smuzhiyun U_BOOT_DRIVER(ns16550_serial) = {
634*4882a593Smuzhiyun 	.name	= "ns16550_serial",
635*4882a593Smuzhiyun 	.id	= UCLASS_SERIAL,
636*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
637*4882a593Smuzhiyun 	.of_match = ns16550_serial_ids,
638*4882a593Smuzhiyun 	.ofdata_to_platdata = ns16550_serial_ofdata_to_platdata,
639*4882a593Smuzhiyun 	.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
640*4882a593Smuzhiyun #endif
641*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct NS16550),
642*4882a593Smuzhiyun 	.probe = ns16550_serial_probe,
643*4882a593Smuzhiyun 	.ops	= &ns16550_serial_ops,
644*4882a593Smuzhiyun 	.flags	= DM_FLAG_PRE_RELOC,
645*4882a593Smuzhiyun };
646*4882a593Smuzhiyun #endif
647*4882a593Smuzhiyun #endif /* SERIAL_PRESENT */
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun #endif /* CONFIG_DM_SERIAL */
650