xref: /openbmc/u-boot/drivers/serial/serial.c (revision 6d93e258)
17742aa65SMarek Vasut /*
27742aa65SMarek Vasut  * (C) Copyright 2004
37742aa65SMarek Vasut  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
47742aa65SMarek Vasut  *
57742aa65SMarek Vasut  * See file CREDITS for list of people who contributed to this
67742aa65SMarek Vasut  * project.
77742aa65SMarek Vasut  *
87742aa65SMarek Vasut  * This program is free software; you can redistribute it and/or
97742aa65SMarek Vasut  * modify it under the terms of the GNU General Public License as
107742aa65SMarek Vasut  * published by the Free Software Foundation; either version 2 of
117742aa65SMarek Vasut  * the License, or (at your option) any later version.
127742aa65SMarek Vasut  *
137742aa65SMarek Vasut  * This program is distributed in the hope that it will be useful,
147742aa65SMarek Vasut  * but WITHOUT ANY WARRANTY; without even the implied warranty of
157742aa65SMarek Vasut  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
167742aa65SMarek Vasut  * GNU General Public License for more details.
177742aa65SMarek Vasut  *
187742aa65SMarek Vasut  * You should have received a copy of the GNU General Public License
197742aa65SMarek Vasut  * along with this program; if not, write to the Free Software
207742aa65SMarek Vasut  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
217742aa65SMarek Vasut  * MA 02111-1307 USA
227742aa65SMarek Vasut  */
237742aa65SMarek Vasut 
247742aa65SMarek Vasut #include <common.h>
257742aa65SMarek Vasut #include <serial.h>
267742aa65SMarek Vasut #include <stdio_dev.h>
277742aa65SMarek Vasut #include <post.h>
287742aa65SMarek Vasut #include <linux/compiler.h>
29*6d93e258SMarek Vasut #include <errno.h>
307742aa65SMarek Vasut 
317742aa65SMarek Vasut DECLARE_GLOBAL_DATA_PTR;
327742aa65SMarek Vasut 
337742aa65SMarek Vasut static struct serial_device *serial_devices;
347742aa65SMarek Vasut static struct serial_device *serial_current;
357742aa65SMarek Vasut 
367742aa65SMarek Vasut static void serial_null(void)
377742aa65SMarek Vasut {
387742aa65SMarek Vasut }
397742aa65SMarek Vasut 
407742aa65SMarek Vasut #define serial_initfunc(name)					\
417742aa65SMarek Vasut 	void name(void)						\
427742aa65SMarek Vasut 		__attribute__((weak, alias("serial_null")));
437742aa65SMarek Vasut 
447742aa65SMarek Vasut serial_initfunc(mpc8xx_serial_initialize);
457742aa65SMarek Vasut serial_initfunc(ns16550_serial_initialize);
467742aa65SMarek Vasut serial_initfunc(pxa_serial_initialize);
477742aa65SMarek Vasut serial_initfunc(s3c24xx_serial_initialize);
487742aa65SMarek Vasut serial_initfunc(s5p_serial_initialize);
497742aa65SMarek Vasut serial_initfunc(zynq_serial_initalize);
507742aa65SMarek Vasut serial_initfunc(bfin_serial_initialize);
517742aa65SMarek Vasut serial_initfunc(bfin_jtag_initialize);
527742aa65SMarek Vasut serial_initfunc(mpc512x_serial_initialize);
537742aa65SMarek Vasut serial_initfunc(uartlite_serial_initialize);
547742aa65SMarek Vasut serial_initfunc(au1x00_serial_initialize);
557742aa65SMarek Vasut serial_initfunc(asc_serial_initialize);
567742aa65SMarek Vasut serial_initfunc(jz_serial_initialize);
577742aa65SMarek Vasut serial_initfunc(mpc5xx_serial_initialize);
587742aa65SMarek Vasut serial_initfunc(mpc8220_serial_initialize);
597742aa65SMarek Vasut serial_initfunc(mpc8260_scc_serial_initialize);
607742aa65SMarek Vasut serial_initfunc(mpc8260_smc_serial_initialize);
617742aa65SMarek Vasut serial_initfunc(mpc85xx_serial_initialize);
627742aa65SMarek Vasut serial_initfunc(iop480_serial_initialize);
637742aa65SMarek Vasut serial_initfunc(leon2_serial_initialize);
647742aa65SMarek Vasut serial_initfunc(leon3_serial_initialize);
657742aa65SMarek Vasut serial_initfunc(marvell_serial_initialize);
667742aa65SMarek Vasut serial_initfunc(amirix_serial_initialize);
677742aa65SMarek Vasut serial_initfunc(bmw_serial_initialize);
687742aa65SMarek Vasut serial_initfunc(cogent_serial_initialize);
697742aa65SMarek Vasut serial_initfunc(cpci750_serial_initialize);
707742aa65SMarek Vasut serial_initfunc(evb64260_serial_initialize);
717742aa65SMarek Vasut serial_initfunc(ml2_serial_initialize);
727742aa65SMarek Vasut serial_initfunc(sconsole_serial_initialize);
737742aa65SMarek Vasut serial_initfunc(p3mx_serial_initialize);
747742aa65SMarek Vasut serial_initfunc(altera_jtag_serial_initialize);
757742aa65SMarek Vasut serial_initfunc(altera_serial_initialize);
767742aa65SMarek Vasut serial_initfunc(atmel_serial_initialize);
777742aa65SMarek Vasut serial_initfunc(lpc32xx_serial_initialize);
787742aa65SMarek Vasut serial_initfunc(mcf_serial_initialize);
797742aa65SMarek Vasut serial_initfunc(ns9750_serial_initialize);
807742aa65SMarek Vasut serial_initfunc(oc_serial_initialize);
817742aa65SMarek Vasut serial_initfunc(s3c4510b_serial_initialize);
827742aa65SMarek Vasut serial_initfunc(s3c64xx_serial_initialize);
837742aa65SMarek Vasut serial_initfunc(sandbox_serial_initialize);
847742aa65SMarek Vasut serial_initfunc(clps7111_serial_initialize);
857742aa65SMarek Vasut serial_initfunc(imx_serial_initialize);
867742aa65SMarek Vasut serial_initfunc(ixp_serial_initialize);
877742aa65SMarek Vasut serial_initfunc(ks8695_serial_initialize);
887742aa65SMarek Vasut serial_initfunc(lh7a40x_serial_initialize);
897742aa65SMarek Vasut serial_initfunc(lpc2292_serial_initialize);
907742aa65SMarek Vasut serial_initfunc(max3100_serial_initialize);
917742aa65SMarek Vasut serial_initfunc(mxc_serial_initialize);
927742aa65SMarek Vasut serial_initfunc(netarm_serial_initialize);
937742aa65SMarek Vasut serial_initfunc(pl01x_serial_initialize);
947742aa65SMarek Vasut serial_initfunc(s3c44b0_serial_initialize);
957742aa65SMarek Vasut serial_initfunc(sa1100_serial_initialize);
967742aa65SMarek Vasut serial_initfunc(sh_serial_initialize);
977742aa65SMarek Vasut 
987742aa65SMarek Vasut void serial_register(struct serial_device *dev)
997742aa65SMarek Vasut {
1007742aa65SMarek Vasut #ifdef CONFIG_NEEDS_MANUAL_RELOC
101f2760c4aSMarek Vasut 	if (dev->start)
1027742aa65SMarek Vasut 		dev->start += gd->reloc_off;
103f2760c4aSMarek Vasut 	if (dev->stop)
104f2760c4aSMarek Vasut 		dev->stop += gd->reloc_off;
105f2760c4aSMarek Vasut 	if (dev->setbrg)
1067742aa65SMarek Vasut 		dev->setbrg += gd->reloc_off;
107f2760c4aSMarek Vasut 	if (dev->getc)
1087742aa65SMarek Vasut 		dev->getc += gd->reloc_off;
109f2760c4aSMarek Vasut 	if (dev->tstc)
1107742aa65SMarek Vasut 		dev->tstc += gd->reloc_off;
111f2760c4aSMarek Vasut 	if (dev->putc)
1127742aa65SMarek Vasut 		dev->putc += gd->reloc_off;
113f2760c4aSMarek Vasut 	if (dev->puts)
1147742aa65SMarek Vasut 		dev->puts += gd->reloc_off;
1157742aa65SMarek Vasut #endif
1167742aa65SMarek Vasut 
1177742aa65SMarek Vasut 	dev->next = serial_devices;
1187742aa65SMarek Vasut 	serial_devices = dev;
1197742aa65SMarek Vasut }
1207742aa65SMarek Vasut 
1217742aa65SMarek Vasut void serial_initialize(void)
1227742aa65SMarek Vasut {
1237742aa65SMarek Vasut 	mpc8xx_serial_initialize();
1247742aa65SMarek Vasut 	ns16550_serial_initialize();
1257742aa65SMarek Vasut 	pxa_serial_initialize();
1267742aa65SMarek Vasut 	s3c24xx_serial_initialize();
1277742aa65SMarek Vasut 	s5p_serial_initialize();
1287742aa65SMarek Vasut 	mpc512x_serial_initialize();
1297742aa65SMarek Vasut 	bfin_serial_initialize();
1307742aa65SMarek Vasut 	bfin_jtag_initialize();
1317742aa65SMarek Vasut 	uartlite_serial_initialize();
1327742aa65SMarek Vasut 	zynq_serial_initalize();
1337742aa65SMarek Vasut 	au1x00_serial_initialize();
1347742aa65SMarek Vasut 	asc_serial_initialize();
1357742aa65SMarek Vasut 	jz_serial_initialize();
1367742aa65SMarek Vasut 	mpc5xx_serial_initialize();
1377742aa65SMarek Vasut 	mpc8220_serial_initialize();
1387742aa65SMarek Vasut 	mpc8260_scc_serial_initialize();
1397742aa65SMarek Vasut 	mpc8260_smc_serial_initialize();
1407742aa65SMarek Vasut 	mpc85xx_serial_initialize();
1417742aa65SMarek Vasut 	iop480_serial_initialize();
1427742aa65SMarek Vasut 	leon2_serial_initialize();
1437742aa65SMarek Vasut 	leon3_serial_initialize();
1447742aa65SMarek Vasut 	marvell_serial_initialize();
1457742aa65SMarek Vasut 	amirix_serial_initialize();
1467742aa65SMarek Vasut 	bmw_serial_initialize();
1477742aa65SMarek Vasut 	cogent_serial_initialize();
1487742aa65SMarek Vasut 	cpci750_serial_initialize();
1497742aa65SMarek Vasut 	evb64260_serial_initialize();
1507742aa65SMarek Vasut 	ml2_serial_initialize();
1517742aa65SMarek Vasut 	sconsole_serial_initialize();
1527742aa65SMarek Vasut 	p3mx_serial_initialize();
1537742aa65SMarek Vasut 	altera_jtag_serial_initialize();
1547742aa65SMarek Vasut 	altera_serial_initialize();
1557742aa65SMarek Vasut 	atmel_serial_initialize();
1567742aa65SMarek Vasut 	lpc32xx_serial_initialize();
1577742aa65SMarek Vasut 	mcf_serial_initialize();
1587742aa65SMarek Vasut 	ns9750_serial_initialize();
1597742aa65SMarek Vasut 	oc_serial_initialize();
1607742aa65SMarek Vasut 	s3c4510b_serial_initialize();
1617742aa65SMarek Vasut 	s3c64xx_serial_initialize();
1627742aa65SMarek Vasut 	sandbox_serial_initialize();
1637742aa65SMarek Vasut 	clps7111_serial_initialize();
1647742aa65SMarek Vasut 	imx_serial_initialize();
1657742aa65SMarek Vasut 	ixp_serial_initialize();
1667742aa65SMarek Vasut 	ks8695_serial_initialize();
1677742aa65SMarek Vasut 	lh7a40x_serial_initialize();
1687742aa65SMarek Vasut 	lpc2292_serial_initialize();
1697742aa65SMarek Vasut 	max3100_serial_initialize();
1707742aa65SMarek Vasut 	mxc_serial_initialize();
1717742aa65SMarek Vasut 	netarm_serial_initialize();
1727742aa65SMarek Vasut 	pl01x_serial_initialize();
1737742aa65SMarek Vasut 	s3c44b0_serial_initialize();
1747742aa65SMarek Vasut 	sa1100_serial_initialize();
1757742aa65SMarek Vasut 	sh_serial_initialize();
1767742aa65SMarek Vasut 
1777742aa65SMarek Vasut 	serial_assign(default_serial_console()->name);
1787742aa65SMarek Vasut }
1797742aa65SMarek Vasut 
1807742aa65SMarek Vasut void serial_stdio_init(void)
1817742aa65SMarek Vasut {
1827742aa65SMarek Vasut 	struct stdio_dev dev;
1837742aa65SMarek Vasut 	struct serial_device *s = serial_devices;
1847742aa65SMarek Vasut 
1857742aa65SMarek Vasut 	while (s) {
1867742aa65SMarek Vasut 		memset(&dev, 0, sizeof(dev));
1877742aa65SMarek Vasut 
1887742aa65SMarek Vasut 		strcpy(dev.name, s->name);
1897742aa65SMarek Vasut 		dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
1907742aa65SMarek Vasut 
1917742aa65SMarek Vasut 		dev.start = s->start;
1927742aa65SMarek Vasut 		dev.stop = s->stop;
1937742aa65SMarek Vasut 		dev.putc = s->putc;
1947742aa65SMarek Vasut 		dev.puts = s->puts;
1957742aa65SMarek Vasut 		dev.getc = s->getc;
1967742aa65SMarek Vasut 		dev.tstc = s->tstc;
1977742aa65SMarek Vasut 
1987742aa65SMarek Vasut 		stdio_register(&dev);
1997742aa65SMarek Vasut 
2007742aa65SMarek Vasut 		s = s->next;
2017742aa65SMarek Vasut 	}
2027742aa65SMarek Vasut }
2037742aa65SMarek Vasut 
2047742aa65SMarek Vasut int serial_assign(const char *name)
2057742aa65SMarek Vasut {
2067742aa65SMarek Vasut 	struct serial_device *s;
2077742aa65SMarek Vasut 
2087742aa65SMarek Vasut 	for (s = serial_devices; s; s = s->next) {
209*6d93e258SMarek Vasut 		if (strcmp(s->name, name))
210*6d93e258SMarek Vasut 			continue;
2117742aa65SMarek Vasut 		serial_current = s;
2127742aa65SMarek Vasut 		return 0;
2137742aa65SMarek Vasut 	}
2147742aa65SMarek Vasut 
215*6d93e258SMarek Vasut 	return -EINVAL;
2167742aa65SMarek Vasut }
2177742aa65SMarek Vasut 
2187742aa65SMarek Vasut void serial_reinit_all(void)
2197742aa65SMarek Vasut {
2207742aa65SMarek Vasut 	struct serial_device *s;
2217742aa65SMarek Vasut 
2227742aa65SMarek Vasut 	for (s = serial_devices; s; s = s->next)
2237742aa65SMarek Vasut 		s->start();
2247742aa65SMarek Vasut }
2257742aa65SMarek Vasut 
2267742aa65SMarek Vasut static struct serial_device *get_current(void)
2277742aa65SMarek Vasut {
2287742aa65SMarek Vasut 	struct serial_device *dev;
2297742aa65SMarek Vasut 
2307742aa65SMarek Vasut 	if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
2317742aa65SMarek Vasut 		dev = default_serial_console();
2327742aa65SMarek Vasut 
2337742aa65SMarek Vasut 		/* We must have a console device */
2347742aa65SMarek Vasut 		if (!dev) {
2357742aa65SMarek Vasut #ifdef CONFIG_SPL_BUILD
2367742aa65SMarek Vasut 			puts("Cannot find console\n");
2377742aa65SMarek Vasut 			hang();
2387742aa65SMarek Vasut #else
2397742aa65SMarek Vasut 			panic("Cannot find console\n");
2407742aa65SMarek Vasut #endif
2417742aa65SMarek Vasut 		}
2427742aa65SMarek Vasut 	} else
2437742aa65SMarek Vasut 		dev = serial_current;
2447742aa65SMarek Vasut 	return dev;
2457742aa65SMarek Vasut }
2467742aa65SMarek Vasut 
2477742aa65SMarek Vasut int serial_init(void)
2487742aa65SMarek Vasut {
2497742aa65SMarek Vasut 	return get_current()->start();
2507742aa65SMarek Vasut }
2517742aa65SMarek Vasut 
2527742aa65SMarek Vasut void serial_setbrg(void)
2537742aa65SMarek Vasut {
2547742aa65SMarek Vasut 	get_current()->setbrg();
2557742aa65SMarek Vasut }
2567742aa65SMarek Vasut 
2577742aa65SMarek Vasut int serial_getc(void)
2587742aa65SMarek Vasut {
2597742aa65SMarek Vasut 	return get_current()->getc();
2607742aa65SMarek Vasut }
2617742aa65SMarek Vasut 
2627742aa65SMarek Vasut int serial_tstc(void)
2637742aa65SMarek Vasut {
2647742aa65SMarek Vasut 	return get_current()->tstc();
2657742aa65SMarek Vasut }
2667742aa65SMarek Vasut 
2677742aa65SMarek Vasut void serial_putc(const char c)
2687742aa65SMarek Vasut {
2697742aa65SMarek Vasut 	get_current()->putc(c);
2707742aa65SMarek Vasut }
2717742aa65SMarek Vasut 
2727742aa65SMarek Vasut void serial_puts(const char *s)
2737742aa65SMarek Vasut {
2747742aa65SMarek Vasut 	get_current()->puts(s);
2757742aa65SMarek Vasut }
2767742aa65SMarek Vasut 
277bfb7d7a3SMarek Vasut void default_serial_puts(const char *s)
278bfb7d7a3SMarek Vasut {
279bfb7d7a3SMarek Vasut 	struct serial_device *dev = get_current();
280bfb7d7a3SMarek Vasut 	while (*s)
281bfb7d7a3SMarek Vasut 		dev->putc(*s++);
282bfb7d7a3SMarek Vasut }
283bfb7d7a3SMarek Vasut 
2847742aa65SMarek Vasut #if CONFIG_POST & CONFIG_SYS_POST_UART
2857742aa65SMarek Vasut static const int bauds[] = CONFIG_SYS_BAUDRATE_TABLE;
2867742aa65SMarek Vasut 
2877742aa65SMarek Vasut /* Mark weak until post/cpu/.../uart.c migrate over */
2887742aa65SMarek Vasut __weak
2897742aa65SMarek Vasut int uart_post_test(int flags)
2907742aa65SMarek Vasut {
2917742aa65SMarek Vasut 	unsigned char c;
2927742aa65SMarek Vasut 	int ret, saved_baud, b;
2937742aa65SMarek Vasut 	struct serial_device *saved_dev, *s;
2947742aa65SMarek Vasut 	bd_t *bd = gd->bd;
2957742aa65SMarek Vasut 
2967742aa65SMarek Vasut 	/* Save current serial state */
2977742aa65SMarek Vasut 	ret = 0;
2987742aa65SMarek Vasut 	saved_dev = serial_current;
2997742aa65SMarek Vasut 	saved_baud = bd->bi_baudrate;
3007742aa65SMarek Vasut 
3017742aa65SMarek Vasut 	for (s = serial_devices; s; s = s->next) {
3027742aa65SMarek Vasut 		/* If this driver doesn't support loop back, skip it */
3037742aa65SMarek Vasut 		if (!s->loop)
3047742aa65SMarek Vasut 			continue;
3057742aa65SMarek Vasut 
3067742aa65SMarek Vasut 		/* Test the next device */
3077742aa65SMarek Vasut 		serial_current = s;
3087742aa65SMarek Vasut 
3097742aa65SMarek Vasut 		ret = serial_init();
3107742aa65SMarek Vasut 		if (ret)
3117742aa65SMarek Vasut 			goto done;
3127742aa65SMarek Vasut 
3137742aa65SMarek Vasut 		/* Consume anything that happens to be queued */
3147742aa65SMarek Vasut 		while (serial_tstc())
3157742aa65SMarek Vasut 			serial_getc();
3167742aa65SMarek Vasut 
3177742aa65SMarek Vasut 		/* Enable loop back */
3187742aa65SMarek Vasut 		s->loop(1);
3197742aa65SMarek Vasut 
3207742aa65SMarek Vasut 		/* Test every available baud rate */
3217742aa65SMarek Vasut 		for (b = 0; b < ARRAY_SIZE(bauds); ++b) {
3227742aa65SMarek Vasut 			bd->bi_baudrate = bauds[b];
3237742aa65SMarek Vasut 			serial_setbrg();
3247742aa65SMarek Vasut 
3257742aa65SMarek Vasut 			/*
3267742aa65SMarek Vasut 			 * Stick to printable chars to avoid issues:
3277742aa65SMarek Vasut 			 *  - terminal corruption
3287742aa65SMarek Vasut 			 *  - serial program reacting to sequences and sending
3297742aa65SMarek Vasut 			 *    back random extra data
3307742aa65SMarek Vasut 			 *  - most serial drivers add in extra chars (like \r\n)
3317742aa65SMarek Vasut 			 */
3327742aa65SMarek Vasut 			for (c = 0x20; c < 0x7f; ++c) {
3337742aa65SMarek Vasut 				/* Send it out */
3347742aa65SMarek Vasut 				serial_putc(c);
3357742aa65SMarek Vasut 
3367742aa65SMarek Vasut 				/* Make sure it's the same one */
3377742aa65SMarek Vasut 				ret = (c != serial_getc());
3387742aa65SMarek Vasut 				if (ret) {
3397742aa65SMarek Vasut 					s->loop(0);
3407742aa65SMarek Vasut 					goto done;
3417742aa65SMarek Vasut 				}
3427742aa65SMarek Vasut 
3437742aa65SMarek Vasut 				/* Clean up the output in case it was sent */
3447742aa65SMarek Vasut 				serial_putc('\b');
3457742aa65SMarek Vasut 				ret = ('\b' != serial_getc());
3467742aa65SMarek Vasut 				if (ret) {
3477742aa65SMarek Vasut 					s->loop(0);
3487742aa65SMarek Vasut 					goto done;
3497742aa65SMarek Vasut 				}
3507742aa65SMarek Vasut 			}
3517742aa65SMarek Vasut 		}
3527742aa65SMarek Vasut 
3537742aa65SMarek Vasut 		/* Disable loop back */
3547742aa65SMarek Vasut 		s->loop(0);
3557742aa65SMarek Vasut 
3567742aa65SMarek Vasut 		/* XXX: There is no serial_stop() !? */
3577742aa65SMarek Vasut 		if (s->stop)
3587742aa65SMarek Vasut 			s->stop();
3597742aa65SMarek Vasut 	}
3607742aa65SMarek Vasut 
3617742aa65SMarek Vasut  done:
3627742aa65SMarek Vasut 	/* Restore previous serial state */
3637742aa65SMarek Vasut 	serial_current = saved_dev;
3647742aa65SMarek Vasut 	bd->bi_baudrate = saved_baud;
3657742aa65SMarek Vasut 	serial_reinit_all();
3667742aa65SMarek Vasut 	serial_setbrg();
3677742aa65SMarek Vasut 
3687742aa65SMarek Vasut 	return ret;
3697742aa65SMarek Vasut }
3707742aa65SMarek Vasut #endif
371