
Serial driver for the S3C24XX SoCs.
Signed-off-by: José Miguel Gonçalves jose.goncalves@inov.pt --- drivers/serial/Makefile | 1 + drivers/serial/s3c24xx_serial.c | 146 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 drivers/serial/s3c24xx_serial.c
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 65d0f23..2cbdaac 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -52,6 +52,7 @@ COBJS-$(CONFIG_PL011_SERIAL) += serial_pl01x.o COBJS-$(CONFIG_PXA_SERIAL) += serial_pxa.o COBJS-$(CONFIG_SA1100_SERIAL) += serial_sa1100.o COBJS-$(CONFIG_S3C24X0_SERIAL) += serial_s3c24x0.o +COBJS-$(CONFIG_S3C24XX_SERIAL) += s3c24xx_serial.o COBJS-$(CONFIG_S3C44B0_SERIAL) += serial_s3c44b0.o COBJS-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o COBJS-$(CONFIG_SANDBOX_SERIAL) += sandbox.o diff --git a/drivers/serial/s3c24xx_serial.c b/drivers/serial/s3c24xx_serial.c new file mode 100644 index 0000000..11f13a5 --- /dev/null +++ b/drivers/serial/s3c24xx_serial.c @@ -0,0 +1,146 @@ +/* + * (C) Copyright 2012 INOV - INESC Inovacao + * Jose Goncalves jose.goncalves@inov.pt + * + * Based on drivers/serial/s3c64xx.c + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + */ + +#include <common.h> +#include <asm/arch/s3c24xx_cpu.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_SERIAL0 +#define UART_NR S3C24XX_UART0 + +#elif defined(CONFIG_SERIAL1) +#define UART_NR S3C24XX_UART1 + +#elif defined(CONFIG_SERIAL2) +#define UART_NR S3C24XX_UART2 + +#elif defined(CONFIG_SERIAL3) +#define UART_NR S3C24XX_UART3 + +#else +#error "Bad: you didn't configure serial ..." +#endif + +#define barrier() asm volatile("" ::: "memory") + +/* + * The coefficient, used to calculate the baudrate on S3C24XX UARTs is + * calculated as C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT + * however, section 2.1.10 of the S3C2416 User's Manual doesn't recommend + * using 1 for 1, 3 for 2, ... (2^n - 1) for n, instead, they suggest using + * these constants: + */ +static const int udivslot[] = { + 0x0000, 0x0080, 0x0808, 0x0888, 0x2222, 0x4924, 0x4A52, 0x54AA, + 0x5555, 0xD555, 0xD5D5, 0xDDD5, 0xDDDD, 0xDFDD, 0xDFDF, 0xFFDF, +}; + +void serial_setbrg(void) +{ + s3c24xx_uart *const uart = s3c24xx_get_base_uart(UART_NR); + u32 pclk; + u32 baudrate; + int i; + + pclk = get_PCLK(); + baudrate = gd->baudrate; + + uart->ubrdiv = (pclk / baudrate / 16) - 1; + uart->udivslot = udivslot[(pclk / baudrate) % 16]; + + for (i = 0; i < 100; i++) + barrier(); +} + +/* + * 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(void) +{ + s3c24xx_uart *const uart = s3c24xx_get_base_uart(UART_NR); + + /* FIFO enable, Tx/Rx FIFO clear */ + uart->ufcon = 0x07; + uart->umcon = 0x00; + /* Normal mode, No parity, 1 stop bit, 8 data bits */ + uart->ulcon = 0x03; + /* Polling mode */ + uart->ucon = 0x005; + + serial_setbrg(); + + return 0; +} + +/* + * Read a single byte from the serial port. + */ +int serial_getc(void) +{ + s3c24xx_uart *const uart = s3c24xx_get_base_uart(UART_NR); + + /* Wait for character to arrive */ + while (!(uart->utrstat & 0x1)) ; + + return uart->urxh & 0xff; +} + +/* + * Output a single byte to the serial port. + */ +void serial_putc(const char c) +{ + s3c24xx_uart *const uart = s3c24xx_get_base_uart(UART_NR); + + /* Wait for room in the TX FIFO */ + while (!(uart->utrstat & 0x2)) ; + + uart->utxh = c; + + /* If \n, also do \r */ + if (c == '\n') + serial_putc('\r'); +} + +/* + * Test whether a character is in the RX buffer. + */ +int serial_tstc(void) +{ + s3c24xx_uart *const uart = s3c24xx_get_base_uart(UART_NR); + + return uart->utrstat & 0x1; +} + +/* + * Output a string to the serial port. + */ +void serial_puts(const char *s) +{ + while (*s) + serial_putc(*s++); +}