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