X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fserial%2Fserial_s5p.c;h=98c62b4c147ef185d8a9cabb0290be854a38b892;hb=64f41212d880f3d00c6994d973aadeec5bda1b65;hp=e0d4e8004dd01886b940933ea8551788fdef6f28;hpb=3df4f46f3209c067dcadc969ed02d27c97fa3632;p=u-boot diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index e0d4e8004d..98c62b4c14 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -5,36 +5,38 @@ * * based on drivers/serial/s3c64xx.c * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * SPDX-License-Identifier: GPL-2.0+ */ #include +#include +#include #include #include #include #include +DECLARE_GLOBAL_DATA_PTR; + +#define RX_FIFO_COUNT_MASK 0xff +#define RX_FIFO_FULL_MASK (1 << 8) +#define TX_FIFO_FULL_MASK (1 << 24) + +/* Information about a serial port */ +struct fdt_serial { + u32 base_addr; /* address of registers in physical memory */ + u8 port_id; /* uart port number */ + u8 enabled; /* 1 if enabled, 0 if disabled */ +} config __attribute__ ((section(".data"))); + static inline struct s5p_uart *s5p_get_base_uart(int dev_index) { +#ifdef CONFIG_OF_CONTROL + return (struct s5p_uart *)(config.base_addr); +#else u32 offset = dev_index * sizeof(struct s5p_uart); - - if (cpu_is_s5pc100()) - return (struct s5p_uart *)(S5PC100_UART_BASE + offset); - else - return (struct s5p_uart *)(S5PC110_UART_BASE + offset); + return (struct s5p_uart *)(samsung_get_base_uart() + offset); +#endif } /* @@ -63,30 +65,43 @@ static const int udivslot[] = { 0xffdf, }; -void serial_setbrg_dev(const int dev_index) +static void serial_setbrg_dev(const int dev_index) { - DECLARE_GLOBAL_DATA_PTR; struct s5p_uart *const uart = s5p_get_base_uart(dev_index); - u32 pclk = get_pclk(); + u32 uclk = get_uart_clk(dev_index); u32 baudrate = gd->baudrate; u32 val; - val = pclk / baudrate; +#if defined(CONFIG_SILENT_CONSOLE) && \ + defined(CONFIG_OF_CONTROL) && \ + !defined(CONFIG_SPL_BUILD) + if (fdtdec_get_config_int(gd->fdt_blob, "silent_console", 0)) + gd->flags |= GD_FLG_SILENT; +#endif + + if (!config.enabled) + return; + + val = uclk / baudrate; writel(val / 16 - 1, &uart->ubrdiv); - writew(udivslot[val % 16], &uart->udivslot); + + if (s5p_uart_divslot()) + writew(udivslot[val % 16], &uart->rest.slot); + else + writeb(val % 16, &uart->rest.value); } /* * Initialise the serial port with the given baudrate. The settings * are always 8 data bits, no parity, 1 stop bit, no start bits. */ -int serial_init_dev(const int dev_index) +static int serial_init_dev(const int dev_index) { struct s5p_uart *const uart = s5p_get_base_uart(dev_index); - /* reset and enable FIFOs, set triggers to the maximum */ - writel(0, &uart->ufcon); + /* enable FIFOs, auto clear Rx FIFO */ + writel(0x3, &uart->ufcon); writel(0, &uart->umcon); /* 8N1 */ writel(0x3, &uart->ulcon); @@ -123,12 +138,16 @@ static int serial_err_check(const int dev_index, int op) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ -int serial_getc_dev(const int dev_index) +static int serial_getc_dev(const int dev_index) { struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + if (!config.enabled) + return 0; + /* wait for character to arrive */ - while (!(readl(&uart->utrstat) & 0x1)) { + while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK | + RX_FIFO_FULL_MASK))) { if (serial_err_check(dev_index, 0)) return 0; } @@ -139,12 +158,15 @@ int serial_getc_dev(const int dev_index) /* * Output a single byte to the serial port. */ -void serial_putc_dev(const char c, const int dev_index) +static void serial_putc_dev(const char c, const int dev_index) { struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + if (!config.enabled) + return; + /* wait for room in the tx FIFO */ - while (!(readl(&uart->utrstat) & 0x2)) { + while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) { if (serial_err_check(dev_index, 1)) return; } @@ -159,14 +181,17 @@ void serial_putc_dev(const char c, const int dev_index) /* * Test whether a character is in the RX buffer */ -int serial_tstc_dev(const int dev_index) +static int serial_tstc_dev(const int dev_index) { struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + if (!config.enabled) + return 0; + return (int)(readl(&uart->utrstat) & 0x1); } -void serial_puts_dev(const char *s, const int dev_index) +static void serial_puts_dev(const char *s, const int dev_index) { while (*s) serial_putc_dev(*s++, dev_index); @@ -174,33 +199,103 @@ void serial_puts_dev(const char *s, const int dev_index) /* Multi serial device functions */ #define DECLARE_S5P_SERIAL_FUNCTIONS(port) \ -int s5p_serial##port##_init(void) { return serial_init_dev(port); } \ -void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \ -int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \ -int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \ -void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \ -void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); } - -#define INIT_S5P_SERIAL_STRUCTURE(port, name, bus) { \ - name, \ - bus, \ - s5p_serial##port##_init, \ - NULL, \ - s5p_serial##port##_setbrg, \ - s5p_serial##port##_getc, \ - s5p_serial##port##_tstc, \ - s5p_serial##port##_putc, \ - s5p_serial##port##_puts, } +static int s5p_serial##port##_init(void) { return serial_init_dev(port); } \ +static void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \ +static int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \ +static int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \ +static void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \ +static void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); } + +#define INIT_S5P_SERIAL_STRUCTURE(port, __name) { \ + .name = __name, \ + .start = s5p_serial##port##_init, \ + .stop = NULL, \ + .setbrg = s5p_serial##port##_setbrg, \ + .getc = s5p_serial##port##_getc, \ + .tstc = s5p_serial##port##_tstc, \ + .putc = s5p_serial##port##_putc, \ + .puts = s5p_serial##port##_puts, \ +} DECLARE_S5P_SERIAL_FUNCTIONS(0); struct serial_device s5p_serial0_device = - INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0", "S5PUART0"); + INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0"); DECLARE_S5P_SERIAL_FUNCTIONS(1); struct serial_device s5p_serial1_device = - INIT_S5P_SERIAL_STRUCTURE(1, "s5pser1", "S5PUART1"); + INIT_S5P_SERIAL_STRUCTURE(1, "s5pser1"); DECLARE_S5P_SERIAL_FUNCTIONS(2); struct serial_device s5p_serial2_device = - INIT_S5P_SERIAL_STRUCTURE(2, "s5pser2", "S5PUART2"); + INIT_S5P_SERIAL_STRUCTURE(2, "s5pser2"); DECLARE_S5P_SERIAL_FUNCTIONS(3); struct serial_device s5p_serial3_device = - INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3", "S5PUART3"); + INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3"); + +#ifdef CONFIG_OF_CONTROL +int fdtdec_decode_console(int *index, struct fdt_serial *uart) +{ + const void *blob = gd->fdt_blob; + int node; + + node = fdt_path_offset(blob, "console"); + if (node < 0) + return node; + + uart->base_addr = fdtdec_get_addr(blob, node, "reg"); + if (uart->base_addr == FDT_ADDR_T_NONE) + return -FDT_ERR_NOTFOUND; + + uart->port_id = fdtdec_get_int(blob, node, "id", -1); + uart->enabled = fdtdec_get_is_enabled(blob, node); + + return 0; +} +#endif + +__weak struct serial_device *default_serial_console(void) +{ +#ifdef CONFIG_OF_CONTROL + int index = 0; + + if ((!config.base_addr) && (fdtdec_decode_console(&index, &config))) { + debug("Cannot decode default console node\n"); + return NULL; + } + + switch (config.port_id) { + case 0: + return &s5p_serial0_device; + case 1: + return &s5p_serial1_device; + case 2: + return &s5p_serial2_device; + case 3: + return &s5p_serial3_device; + default: + debug("Unknown config.port_id: %d", config.port_id); + break; + } + + return NULL; +#else + config.enabled = 1; +#if defined(CONFIG_SERIAL0) + return &s5p_serial0_device; +#elif defined(CONFIG_SERIAL1) + return &s5p_serial1_device; +#elif defined(CONFIG_SERIAL2) + return &s5p_serial2_device; +#elif defined(CONFIG_SERIAL3) + return &s5p_serial3_device; +#else +#error "CONFIG_SERIAL? missing." +#endif +#endif +} + +void s5p_serial_initialize(void) +{ + serial_register(&s5p_serial0_device); + serial_register(&s5p_serial1_device); + serial_register(&s5p_serial2_device); + serial_register(&s5p_serial3_device); +}