xref: /openbmc/u-boot/drivers/serial/serial.c (revision bfb7d7a3)
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>
297742aa65SMarek Vasut 
307742aa65SMarek Vasut DECLARE_GLOBAL_DATA_PTR;
317742aa65SMarek Vasut 
327742aa65SMarek Vasut static struct serial_device *serial_devices;
337742aa65SMarek Vasut static struct serial_device *serial_current;
347742aa65SMarek Vasut 
357742aa65SMarek Vasut static void serial_null(void)
367742aa65SMarek Vasut {
377742aa65SMarek Vasut }
387742aa65SMarek Vasut 
397742aa65SMarek Vasut #define serial_initfunc(name)					\
407742aa65SMarek Vasut 	void name(void)						\
417742aa65SMarek Vasut 		__attribute__((weak, alias("serial_null")));
427742aa65SMarek Vasut 
437742aa65SMarek Vasut serial_initfunc(mpc8xx_serial_initialize);
447742aa65SMarek Vasut serial_initfunc(ns16550_serial_initialize);
457742aa65SMarek Vasut serial_initfunc(pxa_serial_initialize);
467742aa65SMarek Vasut serial_initfunc(s3c24xx_serial_initialize);
477742aa65SMarek Vasut serial_initfunc(s5p_serial_initialize);
487742aa65SMarek Vasut serial_initfunc(zynq_serial_initalize);
497742aa65SMarek Vasut serial_initfunc(bfin_serial_initialize);
507742aa65SMarek Vasut serial_initfunc(bfin_jtag_initialize);
517742aa65SMarek Vasut serial_initfunc(mpc512x_serial_initialize);
527742aa65SMarek Vasut serial_initfunc(uartlite_serial_initialize);
537742aa65SMarek Vasut serial_initfunc(au1x00_serial_initialize);
547742aa65SMarek Vasut serial_initfunc(asc_serial_initialize);
557742aa65SMarek Vasut serial_initfunc(jz_serial_initialize);
567742aa65SMarek Vasut serial_initfunc(mpc5xx_serial_initialize);
577742aa65SMarek Vasut serial_initfunc(mpc8220_serial_initialize);
587742aa65SMarek Vasut serial_initfunc(mpc8260_scc_serial_initialize);
597742aa65SMarek Vasut serial_initfunc(mpc8260_smc_serial_initialize);
607742aa65SMarek Vasut serial_initfunc(mpc85xx_serial_initialize);
617742aa65SMarek Vasut serial_initfunc(iop480_serial_initialize);
627742aa65SMarek Vasut serial_initfunc(leon2_serial_initialize);
637742aa65SMarek Vasut serial_initfunc(leon3_serial_initialize);
647742aa65SMarek Vasut serial_initfunc(marvell_serial_initialize);
657742aa65SMarek Vasut serial_initfunc(amirix_serial_initialize);
667742aa65SMarek Vasut serial_initfunc(bmw_serial_initialize);
677742aa65SMarek Vasut serial_initfunc(cogent_serial_initialize);
687742aa65SMarek Vasut serial_initfunc(cpci750_serial_initialize);
697742aa65SMarek Vasut serial_initfunc(evb64260_serial_initialize);
707742aa65SMarek Vasut serial_initfunc(ml2_serial_initialize);
717742aa65SMarek Vasut serial_initfunc(sconsole_serial_initialize);
727742aa65SMarek Vasut serial_initfunc(p3mx_serial_initialize);
737742aa65SMarek Vasut serial_initfunc(altera_jtag_serial_initialize);
747742aa65SMarek Vasut serial_initfunc(altera_serial_initialize);
757742aa65SMarek Vasut serial_initfunc(atmel_serial_initialize);
767742aa65SMarek Vasut serial_initfunc(lpc32xx_serial_initialize);
777742aa65SMarek Vasut serial_initfunc(mcf_serial_initialize);
787742aa65SMarek Vasut serial_initfunc(ns9750_serial_initialize);
797742aa65SMarek Vasut serial_initfunc(oc_serial_initialize);
807742aa65SMarek Vasut serial_initfunc(s3c4510b_serial_initialize);
817742aa65SMarek Vasut serial_initfunc(s3c64xx_serial_initialize);
827742aa65SMarek Vasut serial_initfunc(sandbox_serial_initialize);
837742aa65SMarek Vasut serial_initfunc(clps7111_serial_initialize);
847742aa65SMarek Vasut serial_initfunc(imx_serial_initialize);
857742aa65SMarek Vasut serial_initfunc(ixp_serial_initialize);
867742aa65SMarek Vasut serial_initfunc(ks8695_serial_initialize);
877742aa65SMarek Vasut serial_initfunc(lh7a40x_serial_initialize);
887742aa65SMarek Vasut serial_initfunc(lpc2292_serial_initialize);
897742aa65SMarek Vasut serial_initfunc(max3100_serial_initialize);
907742aa65SMarek Vasut serial_initfunc(mxc_serial_initialize);
917742aa65SMarek Vasut serial_initfunc(netarm_serial_initialize);
927742aa65SMarek Vasut serial_initfunc(pl01x_serial_initialize);
937742aa65SMarek Vasut serial_initfunc(s3c44b0_serial_initialize);
947742aa65SMarek Vasut serial_initfunc(sa1100_serial_initialize);
957742aa65SMarek Vasut serial_initfunc(sh_serial_initialize);
967742aa65SMarek Vasut 
977742aa65SMarek Vasut void serial_register(struct serial_device *dev)
987742aa65SMarek Vasut {
997742aa65SMarek Vasut #ifdef CONFIG_NEEDS_MANUAL_RELOC
100f2760c4aSMarek Vasut 	if (dev->start)
1017742aa65SMarek Vasut 		dev->start += gd->reloc_off;
102f2760c4aSMarek Vasut 	if (dev->stop)
103f2760c4aSMarek Vasut 		dev->stop += gd->reloc_off;
104f2760c4aSMarek Vasut 	if (dev->setbrg)
1057742aa65SMarek Vasut 		dev->setbrg += gd->reloc_off;
106f2760c4aSMarek Vasut 	if (dev->getc)
1077742aa65SMarek Vasut 		dev->getc += gd->reloc_off;
108f2760c4aSMarek Vasut 	if (dev->tstc)
1097742aa65SMarek Vasut 		dev->tstc += gd->reloc_off;
110f2760c4aSMarek Vasut 	if (dev->putc)
1117742aa65SMarek Vasut 		dev->putc += gd->reloc_off;
112f2760c4aSMarek Vasut 	if (dev->puts)
1137742aa65SMarek Vasut 		dev->puts += gd->reloc_off;
1147742aa65SMarek Vasut #endif
1157742aa65SMarek Vasut 
1167742aa65SMarek Vasut 	dev->next = serial_devices;
1177742aa65SMarek Vasut 	serial_devices = dev;
1187742aa65SMarek Vasut }
1197742aa65SMarek Vasut 
1207742aa65SMarek Vasut void serial_initialize(void)
1217742aa65SMarek Vasut {
1227742aa65SMarek Vasut 	mpc8xx_serial_initialize();
1237742aa65SMarek Vasut 	ns16550_serial_initialize();
1247742aa65SMarek Vasut 	pxa_serial_initialize();
1257742aa65SMarek Vasut 	s3c24xx_serial_initialize();
1267742aa65SMarek Vasut 	s5p_serial_initialize();
1277742aa65SMarek Vasut 	mpc512x_serial_initialize();
1287742aa65SMarek Vasut 	bfin_serial_initialize();
1297742aa65SMarek Vasut 	bfin_jtag_initialize();
1307742aa65SMarek Vasut 	uartlite_serial_initialize();
1317742aa65SMarek Vasut 	zynq_serial_initalize();
1327742aa65SMarek Vasut 	au1x00_serial_initialize();
1337742aa65SMarek Vasut 	asc_serial_initialize();
1347742aa65SMarek Vasut 	jz_serial_initialize();
1357742aa65SMarek Vasut 	mpc5xx_serial_initialize();
1367742aa65SMarek Vasut 	mpc8220_serial_initialize();
1377742aa65SMarek Vasut 	mpc8260_scc_serial_initialize();
1387742aa65SMarek Vasut 	mpc8260_smc_serial_initialize();
1397742aa65SMarek Vasut 	mpc85xx_serial_initialize();
1407742aa65SMarek Vasut 	iop480_serial_initialize();
1417742aa65SMarek Vasut 	leon2_serial_initialize();
1427742aa65SMarek Vasut 	leon3_serial_initialize();
1437742aa65SMarek Vasut 	marvell_serial_initialize();
1447742aa65SMarek Vasut 	amirix_serial_initialize();
1457742aa65SMarek Vasut 	bmw_serial_initialize();
1467742aa65SMarek Vasut 	cogent_serial_initialize();
1477742aa65SMarek Vasut 	cpci750_serial_initialize();
1487742aa65SMarek Vasut 	evb64260_serial_initialize();
1497742aa65SMarek Vasut 	ml2_serial_initialize();
1507742aa65SMarek Vasut 	sconsole_serial_initialize();
1517742aa65SMarek Vasut 	p3mx_serial_initialize();
1527742aa65SMarek Vasut 	altera_jtag_serial_initialize();
1537742aa65SMarek Vasut 	altera_serial_initialize();
1547742aa65SMarek Vasut 	atmel_serial_initialize();
1557742aa65SMarek Vasut 	lpc32xx_serial_initialize();
1567742aa65SMarek Vasut 	mcf_serial_initialize();
1577742aa65SMarek Vasut 	ns9750_serial_initialize();
1587742aa65SMarek Vasut 	oc_serial_initialize();
1597742aa65SMarek Vasut 	s3c4510b_serial_initialize();
1607742aa65SMarek Vasut 	s3c64xx_serial_initialize();
1617742aa65SMarek Vasut 	sandbox_serial_initialize();
1627742aa65SMarek Vasut 	clps7111_serial_initialize();
1637742aa65SMarek Vasut 	imx_serial_initialize();
1647742aa65SMarek Vasut 	ixp_serial_initialize();
1657742aa65SMarek Vasut 	ks8695_serial_initialize();
1667742aa65SMarek Vasut 	lh7a40x_serial_initialize();
1677742aa65SMarek Vasut 	lpc2292_serial_initialize();
1687742aa65SMarek Vasut 	max3100_serial_initialize();
1697742aa65SMarek Vasut 	mxc_serial_initialize();
1707742aa65SMarek Vasut 	netarm_serial_initialize();
1717742aa65SMarek Vasut 	pl01x_serial_initialize();
1727742aa65SMarek Vasut 	s3c44b0_serial_initialize();
1737742aa65SMarek Vasut 	sa1100_serial_initialize();
1747742aa65SMarek Vasut 	sh_serial_initialize();
1757742aa65SMarek Vasut 
1767742aa65SMarek Vasut 	serial_assign(default_serial_console()->name);
1777742aa65SMarek Vasut }
1787742aa65SMarek Vasut 
1797742aa65SMarek Vasut void serial_stdio_init(void)
1807742aa65SMarek Vasut {
1817742aa65SMarek Vasut 	struct stdio_dev dev;
1827742aa65SMarek Vasut 	struct serial_device *s = serial_devices;
1837742aa65SMarek Vasut 
1847742aa65SMarek Vasut 	while (s) {
1857742aa65SMarek Vasut 		memset(&dev, 0, sizeof(dev));
1867742aa65SMarek Vasut 
1877742aa65SMarek Vasut 		strcpy(dev.name, s->name);
1887742aa65SMarek Vasut 		dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
1897742aa65SMarek Vasut 
1907742aa65SMarek Vasut 		dev.start = s->start;
1917742aa65SMarek Vasut 		dev.stop = s->stop;
1927742aa65SMarek Vasut 		dev.putc = s->putc;
1937742aa65SMarek Vasut 		dev.puts = s->puts;
1947742aa65SMarek Vasut 		dev.getc = s->getc;
1957742aa65SMarek Vasut 		dev.tstc = s->tstc;
1967742aa65SMarek Vasut 
1977742aa65SMarek Vasut 		stdio_register(&dev);
1987742aa65SMarek Vasut 
1997742aa65SMarek Vasut 		s = s->next;
2007742aa65SMarek Vasut 	}
2017742aa65SMarek Vasut }
2027742aa65SMarek Vasut 
2037742aa65SMarek Vasut int serial_assign(const char *name)
2047742aa65SMarek Vasut {
2057742aa65SMarek Vasut 	struct serial_device *s;
2067742aa65SMarek Vasut 
2077742aa65SMarek Vasut 	for (s = serial_devices; s; s = s->next) {
2087742aa65SMarek Vasut 		if (strcmp(s->name, name) == 0) {
2097742aa65SMarek Vasut 			serial_current = s;
2107742aa65SMarek Vasut 			return 0;
2117742aa65SMarek Vasut 		}
2127742aa65SMarek Vasut 	}
2137742aa65SMarek Vasut 
2147742aa65SMarek Vasut 	return 1;
2157742aa65SMarek Vasut }
2167742aa65SMarek Vasut 
2177742aa65SMarek Vasut void serial_reinit_all(void)
2187742aa65SMarek Vasut {
2197742aa65SMarek Vasut 	struct serial_device *s;
2207742aa65SMarek Vasut 
2217742aa65SMarek Vasut 	for (s = serial_devices; s; s = s->next)
2227742aa65SMarek Vasut 		s->start();
2237742aa65SMarek Vasut }
2247742aa65SMarek Vasut 
2257742aa65SMarek Vasut static struct serial_device *get_current(void)
2267742aa65SMarek Vasut {
2277742aa65SMarek Vasut 	struct serial_device *dev;
2287742aa65SMarek Vasut 
2297742aa65SMarek Vasut 	if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
2307742aa65SMarek Vasut 		dev = default_serial_console();
2317742aa65SMarek Vasut 
2327742aa65SMarek Vasut 		/* We must have a console device */
2337742aa65SMarek Vasut 		if (!dev) {
2347742aa65SMarek Vasut #ifdef CONFIG_SPL_BUILD
2357742aa65SMarek Vasut 			puts("Cannot find console\n");
2367742aa65SMarek Vasut 			hang();
2377742aa65SMarek Vasut #else
2387742aa65SMarek Vasut 			panic("Cannot find console\n");
2397742aa65SMarek Vasut #endif
2407742aa65SMarek Vasut 		}
2417742aa65SMarek Vasut 	} else
2427742aa65SMarek Vasut 		dev = serial_current;
2437742aa65SMarek Vasut 	return dev;
2447742aa65SMarek Vasut }
2457742aa65SMarek Vasut 
2467742aa65SMarek Vasut int serial_init(void)
2477742aa65SMarek Vasut {
2487742aa65SMarek Vasut 	return get_current()->start();
2497742aa65SMarek Vasut }
2507742aa65SMarek Vasut 
2517742aa65SMarek Vasut void serial_setbrg(void)
2527742aa65SMarek Vasut {
2537742aa65SMarek Vasut 	get_current()->setbrg();
2547742aa65SMarek Vasut }
2557742aa65SMarek Vasut 
2567742aa65SMarek Vasut int serial_getc(void)
2577742aa65SMarek Vasut {
2587742aa65SMarek Vasut 	return get_current()->getc();
2597742aa65SMarek Vasut }
2607742aa65SMarek Vasut 
2617742aa65SMarek Vasut int serial_tstc(void)
2627742aa65SMarek Vasut {
2637742aa65SMarek Vasut 	return get_current()->tstc();
2647742aa65SMarek Vasut }
2657742aa65SMarek Vasut 
2667742aa65SMarek Vasut void serial_putc(const char c)
2677742aa65SMarek Vasut {
2687742aa65SMarek Vasut 	get_current()->putc(c);
2697742aa65SMarek Vasut }
2707742aa65SMarek Vasut 
2717742aa65SMarek Vasut void serial_puts(const char *s)
2727742aa65SMarek Vasut {
2737742aa65SMarek Vasut 	get_current()->puts(s);
2747742aa65SMarek Vasut }
2757742aa65SMarek Vasut 
276*bfb7d7a3SMarek Vasut void default_serial_puts(const char *s)
277*bfb7d7a3SMarek Vasut {
278*bfb7d7a3SMarek Vasut 	struct serial_device *dev = get_current();
279*bfb7d7a3SMarek Vasut 	while (*s)
280*bfb7d7a3SMarek Vasut 		dev->putc(*s++);
281*bfb7d7a3SMarek Vasut }
282*bfb7d7a3SMarek Vasut 
2837742aa65SMarek Vasut #if CONFIG_POST & CONFIG_SYS_POST_UART
2847742aa65SMarek Vasut static const int bauds[] = CONFIG_SYS_BAUDRATE_TABLE;
2857742aa65SMarek Vasut 
2867742aa65SMarek Vasut /* Mark weak until post/cpu/.../uart.c migrate over */
2877742aa65SMarek Vasut __weak
2887742aa65SMarek Vasut int uart_post_test(int flags)
2897742aa65SMarek Vasut {
2907742aa65SMarek Vasut 	unsigned char c;
2917742aa65SMarek Vasut 	int ret, saved_baud, b;
2927742aa65SMarek Vasut 	struct serial_device *saved_dev, *s;
2937742aa65SMarek Vasut 	bd_t *bd = gd->bd;
2947742aa65SMarek Vasut 
2957742aa65SMarek Vasut 	/* Save current serial state */
2967742aa65SMarek Vasut 	ret = 0;
2977742aa65SMarek Vasut 	saved_dev = serial_current;
2987742aa65SMarek Vasut 	saved_baud = bd->bi_baudrate;
2997742aa65SMarek Vasut 
3007742aa65SMarek Vasut 	for (s = serial_devices; s; s = s->next) {
3017742aa65SMarek Vasut 		/* If this driver doesn't support loop back, skip it */
3027742aa65SMarek Vasut 		if (!s->loop)
3037742aa65SMarek Vasut 			continue;
3047742aa65SMarek Vasut 
3057742aa65SMarek Vasut 		/* Test the next device */
3067742aa65SMarek Vasut 		serial_current = s;
3077742aa65SMarek Vasut 
3087742aa65SMarek Vasut 		ret = serial_init();
3097742aa65SMarek Vasut 		if (ret)
3107742aa65SMarek Vasut 			goto done;
3117742aa65SMarek Vasut 
3127742aa65SMarek Vasut 		/* Consume anything that happens to be queued */
3137742aa65SMarek Vasut 		while (serial_tstc())
3147742aa65SMarek Vasut 			serial_getc();
3157742aa65SMarek Vasut 
3167742aa65SMarek Vasut 		/* Enable loop back */
3177742aa65SMarek Vasut 		s->loop(1);
3187742aa65SMarek Vasut 
3197742aa65SMarek Vasut 		/* Test every available baud rate */
3207742aa65SMarek Vasut 		for (b = 0; b < ARRAY_SIZE(bauds); ++b) {
3217742aa65SMarek Vasut 			bd->bi_baudrate = bauds[b];
3227742aa65SMarek Vasut 			serial_setbrg();
3237742aa65SMarek Vasut 
3247742aa65SMarek Vasut 			/*
3257742aa65SMarek Vasut 			 * Stick to printable chars to avoid issues:
3267742aa65SMarek Vasut 			 *  - terminal corruption
3277742aa65SMarek Vasut 			 *  - serial program reacting to sequences and sending
3287742aa65SMarek Vasut 			 *    back random extra data
3297742aa65SMarek Vasut 			 *  - most serial drivers add in extra chars (like \r\n)
3307742aa65SMarek Vasut 			 */
3317742aa65SMarek Vasut 			for (c = 0x20; c < 0x7f; ++c) {
3327742aa65SMarek Vasut 				/* Send it out */
3337742aa65SMarek Vasut 				serial_putc(c);
3347742aa65SMarek Vasut 
3357742aa65SMarek Vasut 				/* Make sure it's the same one */
3367742aa65SMarek Vasut 				ret = (c != serial_getc());
3377742aa65SMarek Vasut 				if (ret) {
3387742aa65SMarek Vasut 					s->loop(0);
3397742aa65SMarek Vasut 					goto done;
3407742aa65SMarek Vasut 				}
3417742aa65SMarek Vasut 
3427742aa65SMarek Vasut 				/* Clean up the output in case it was sent */
3437742aa65SMarek Vasut 				serial_putc('\b');
3447742aa65SMarek Vasut 				ret = ('\b' != serial_getc());
3457742aa65SMarek Vasut 				if (ret) {
3467742aa65SMarek Vasut 					s->loop(0);
3477742aa65SMarek Vasut 					goto done;
3487742aa65SMarek Vasut 				}
3497742aa65SMarek Vasut 			}
3507742aa65SMarek Vasut 		}
3517742aa65SMarek Vasut 
3527742aa65SMarek Vasut 		/* Disable loop back */
3537742aa65SMarek Vasut 		s->loop(0);
3547742aa65SMarek Vasut 
3557742aa65SMarek Vasut 		/* XXX: There is no serial_stop() !? */
3567742aa65SMarek Vasut 		if (s->stop)
3577742aa65SMarek Vasut 			s->stop();
3587742aa65SMarek Vasut 	}
3597742aa65SMarek Vasut 
3607742aa65SMarek Vasut  done:
3617742aa65SMarek Vasut 	/* Restore previous serial state */
3627742aa65SMarek Vasut 	serial_current = saved_dev;
3637742aa65SMarek Vasut 	bd->bi_baudrate = saved_baud;
3647742aa65SMarek Vasut 	serial_reinit_all();
3657742aa65SMarek Vasut 	serial_setbrg();
3667742aa65SMarek Vasut 
3677742aa65SMarek Vasut 	return ret;
3687742aa65SMarek Vasut }
3697742aa65SMarek Vasut #endif
370