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 100*f2760c4aSMarek Vasut if (dev->start) 1017742aa65SMarek Vasut dev->start += gd->reloc_off; 102*f2760c4aSMarek Vasut if (dev->stop) 103*f2760c4aSMarek Vasut dev->stop += gd->reloc_off; 104*f2760c4aSMarek Vasut if (dev->setbrg) 1057742aa65SMarek Vasut dev->setbrg += gd->reloc_off; 106*f2760c4aSMarek Vasut if (dev->getc) 1077742aa65SMarek Vasut dev->getc += gd->reloc_off; 108*f2760c4aSMarek Vasut if (dev->tstc) 1097742aa65SMarek Vasut dev->tstc += gd->reloc_off; 110*f2760c4aSMarek Vasut if (dev->putc) 1117742aa65SMarek Vasut dev->putc += gd->reloc_off; 112*f2760c4aSMarek 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 2767742aa65SMarek Vasut #if CONFIG_POST & CONFIG_SYS_POST_UART 2777742aa65SMarek Vasut static const int bauds[] = CONFIG_SYS_BAUDRATE_TABLE; 2787742aa65SMarek Vasut 2797742aa65SMarek Vasut /* Mark weak until post/cpu/.../uart.c migrate over */ 2807742aa65SMarek Vasut __weak 2817742aa65SMarek Vasut int uart_post_test(int flags) 2827742aa65SMarek Vasut { 2837742aa65SMarek Vasut unsigned char c; 2847742aa65SMarek Vasut int ret, saved_baud, b; 2857742aa65SMarek Vasut struct serial_device *saved_dev, *s; 2867742aa65SMarek Vasut bd_t *bd = gd->bd; 2877742aa65SMarek Vasut 2887742aa65SMarek Vasut /* Save current serial state */ 2897742aa65SMarek Vasut ret = 0; 2907742aa65SMarek Vasut saved_dev = serial_current; 2917742aa65SMarek Vasut saved_baud = bd->bi_baudrate; 2927742aa65SMarek Vasut 2937742aa65SMarek Vasut for (s = serial_devices; s; s = s->next) { 2947742aa65SMarek Vasut /* If this driver doesn't support loop back, skip it */ 2957742aa65SMarek Vasut if (!s->loop) 2967742aa65SMarek Vasut continue; 2977742aa65SMarek Vasut 2987742aa65SMarek Vasut /* Test the next device */ 2997742aa65SMarek Vasut serial_current = s; 3007742aa65SMarek Vasut 3017742aa65SMarek Vasut ret = serial_init(); 3027742aa65SMarek Vasut if (ret) 3037742aa65SMarek Vasut goto done; 3047742aa65SMarek Vasut 3057742aa65SMarek Vasut /* Consume anything that happens to be queued */ 3067742aa65SMarek Vasut while (serial_tstc()) 3077742aa65SMarek Vasut serial_getc(); 3087742aa65SMarek Vasut 3097742aa65SMarek Vasut /* Enable loop back */ 3107742aa65SMarek Vasut s->loop(1); 3117742aa65SMarek Vasut 3127742aa65SMarek Vasut /* Test every available baud rate */ 3137742aa65SMarek Vasut for (b = 0; b < ARRAY_SIZE(bauds); ++b) { 3147742aa65SMarek Vasut bd->bi_baudrate = bauds[b]; 3157742aa65SMarek Vasut serial_setbrg(); 3167742aa65SMarek Vasut 3177742aa65SMarek Vasut /* 3187742aa65SMarek Vasut * Stick to printable chars to avoid issues: 3197742aa65SMarek Vasut * - terminal corruption 3207742aa65SMarek Vasut * - serial program reacting to sequences and sending 3217742aa65SMarek Vasut * back random extra data 3227742aa65SMarek Vasut * - most serial drivers add in extra chars (like \r\n) 3237742aa65SMarek Vasut */ 3247742aa65SMarek Vasut for (c = 0x20; c < 0x7f; ++c) { 3257742aa65SMarek Vasut /* Send it out */ 3267742aa65SMarek Vasut serial_putc(c); 3277742aa65SMarek Vasut 3287742aa65SMarek Vasut /* Make sure it's the same one */ 3297742aa65SMarek Vasut ret = (c != serial_getc()); 3307742aa65SMarek Vasut if (ret) { 3317742aa65SMarek Vasut s->loop(0); 3327742aa65SMarek Vasut goto done; 3337742aa65SMarek Vasut } 3347742aa65SMarek Vasut 3357742aa65SMarek Vasut /* Clean up the output in case it was sent */ 3367742aa65SMarek Vasut serial_putc('\b'); 3377742aa65SMarek Vasut ret = ('\b' != serial_getc()); 3387742aa65SMarek Vasut if (ret) { 3397742aa65SMarek Vasut s->loop(0); 3407742aa65SMarek Vasut goto done; 3417742aa65SMarek Vasut } 3427742aa65SMarek Vasut } 3437742aa65SMarek Vasut } 3447742aa65SMarek Vasut 3457742aa65SMarek Vasut /* Disable loop back */ 3467742aa65SMarek Vasut s->loop(0); 3477742aa65SMarek Vasut 3487742aa65SMarek Vasut /* XXX: There is no serial_stop() !? */ 3497742aa65SMarek Vasut if (s->stop) 3507742aa65SMarek Vasut s->stop(); 3517742aa65SMarek Vasut } 3527742aa65SMarek Vasut 3537742aa65SMarek Vasut done: 3547742aa65SMarek Vasut /* Restore previous serial state */ 3557742aa65SMarek Vasut serial_current = saved_dev; 3567742aa65SMarek Vasut bd->bi_baudrate = saved_baud; 3577742aa65SMarek Vasut serial_reinit_all(); 3587742aa65SMarek Vasut serial_setbrg(); 3597742aa65SMarek Vasut 3607742aa65SMarek Vasut return ret; 3617742aa65SMarek Vasut } 3627742aa65SMarek Vasut #endif 363