uboot/drivers/serial/serial_s3c24x0.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2002
   3 * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 *
  19 */
  20
  21#include <common.h>
  22#include <linux/compiler.h>
  23#include <asm/arch/s3c24x0_cpu.h>
  24
  25DECLARE_GLOBAL_DATA_PTR;
  26
  27#ifdef CONFIG_SERIAL1
  28#define UART_NR S3C24X0_UART0
  29
  30#elif defined(CONFIG_SERIAL2)
  31#define UART_NR S3C24X0_UART1
  32
  33#elif defined(CONFIG_SERIAL3)
  34#define UART_NR S3C24X0_UART2
  35
  36#else
  37#error "Bad: you didn't configure serial ..."
  38#endif
  39
  40#include <asm/io.h>
  41
  42#if defined(CONFIG_SERIAL_MULTI)
  43#include <serial.h>
  44
  45/* Multi serial device functions */
  46#define DECLARE_S3C_SERIAL_FUNCTIONS(port) \
  47        int s3serial##port##_init(void) \
  48        { \
  49                return serial_init_dev(port); \
  50        } \
  51        void s3serial##port##_setbrg(void) \
  52        { \
  53                serial_setbrg_dev(port); \
  54        } \
  55        int s3serial##port##_getc(void) \
  56        { \
  57                return serial_getc_dev(port); \
  58        } \
  59        int s3serial##port##_tstc(void) \
  60        { \
  61                return serial_tstc_dev(port); \
  62        } \
  63        void s3serial##port##_putc(const char c) \
  64        { \
  65                serial_putc_dev(port, c); \
  66        } \
  67        void s3serial##port##_puts(const char *s) \
  68        { \
  69                serial_puts_dev(port, s); \
  70        }
  71
  72#define INIT_S3C_SERIAL_STRUCTURE(port, name) { \
  73        name, \
  74        s3serial##port##_init, \
  75        NULL,\
  76        s3serial##port##_setbrg, \
  77        s3serial##port##_getc, \
  78        s3serial##port##_tstc, \
  79        s3serial##port##_putc, \
  80        s3serial##port##_puts, \
  81}
  82
  83#endif /* CONFIG_SERIAL_MULTI */
  84
  85#ifdef CONFIG_HWFLOW
  86static int hwflow;
  87#endif
  88
  89void _serial_setbrg(const int dev_index)
  90{
  91        struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
  92        unsigned int reg = 0;
  93        int i;
  94
  95        /* value is calculated so : (int)(PCLK/16./baudrate) -1 */
  96        reg = get_PCLK() / (16 * gd->baudrate) - 1;
  97
  98        writel(reg, &uart->ubrdiv);
  99        for (i = 0; i < 100; i++)
 100                /* Delay */ ;
 101}
 102
 103#if defined(CONFIG_SERIAL_MULTI)
 104static inline void serial_setbrg_dev(unsigned int dev_index)
 105{
 106        _serial_setbrg(dev_index);
 107}
 108#else
 109void serial_setbrg(void)
 110{
 111        _serial_setbrg(UART_NR);
 112}
 113#endif
 114
 115
 116/* Initialise the serial port. The settings are always 8 data bits, no parity,
 117 * 1 stop bit, no start bits.
 118 */
 119static int serial_init_dev(const int dev_index)
 120{
 121        struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
 122
 123#ifdef CONFIG_HWFLOW
 124        hwflow = 0;     /* turned off by default */
 125#endif
 126
 127        /* FIFO enable, Tx/Rx FIFO clear */
 128        writel(0x07, &uart->ufcon);
 129        writel(0x0, &uart->umcon);
 130
 131        /* Normal,No parity,1 stop,8 bit */
 132        writel(0x3, &uart->ulcon);
 133        /*
 134         * tx=level,rx=edge,disable timeout int.,enable rx error int.,
 135         * normal,interrupt or polling
 136         */
 137        writel(0x245, &uart->ucon);
 138
 139#ifdef CONFIG_HWFLOW
 140        writel(0x1, &uart->umcon);      /* rts up */
 141#endif
 142
 143        /* FIXME: This is sooooooooooooooooooo ugly */
 144#if defined(CONFIG_ARCH_GTA02_v1) || defined(CONFIG_ARCH_GTA02_v2)
 145        /* we need auto hw flow control on the gsm and gps port */
 146        if (dev_index == 0 || dev_index == 1)
 147                writel(0x10, &uart->umcon);
 148#endif
 149        _serial_setbrg(dev_index);
 150
 151        return (0);
 152}
 153
 154#if !defined(CONFIG_SERIAL_MULTI)
 155/* Initialise the serial port. The settings are always 8 data bits, no parity,
 156 * 1 stop bit, no start bits.
 157 */
 158int serial_init(void)
 159{
 160        return serial_init_dev(UART_NR);
 161}
 162#endif
 163
 164/*
 165 * Read a single byte from the serial port. Returns 1 on success, 0
 166 * otherwise. When the function is succesfull, the character read is
 167 * written into its argument c.
 168 */
 169int _serial_getc(const int dev_index)
 170{
 171        struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
 172
 173        while (!(readl(&uart->utrstat) & 0x1))
 174                /* wait for character to arrive */ ;
 175
 176        return readb(&uart->urxh) & 0xff;
 177}
 178
 179#if defined(CONFIG_SERIAL_MULTI)
 180static inline int serial_getc_dev(unsigned int dev_index)
 181{
 182        return _serial_getc(dev_index);
 183}
 184#else
 185int serial_getc(void)
 186{
 187        return _serial_getc(UART_NR);
 188}
 189#endif
 190
 191#ifdef CONFIG_HWFLOW
 192int hwflow_onoff(int on)
 193{
 194        switch (on) {
 195        case 0:
 196        default:
 197                break;          /* return current */
 198        case 1:
 199                hwflow = 1;     /* turn on */
 200                break;
 201        case -1:
 202                hwflow = 0;     /* turn off */
 203                break;
 204        }
 205        return hwflow;
 206}
 207#endif
 208
 209#ifdef CONFIG_MODEM_SUPPORT
 210static int be_quiet = 0;
 211void disable_putc(void)
 212{
 213        be_quiet = 1;
 214}
 215
 216void enable_putc(void)
 217{
 218        be_quiet = 0;
 219}
 220#endif
 221
 222
 223/*
 224 * Output a single byte to the serial port.
 225 */
 226void _serial_putc(const char c, const int dev_index)
 227{
 228        struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
 229#ifdef CONFIG_MODEM_SUPPORT
 230        if (be_quiet)
 231                return;
 232#endif
 233
 234        while (!(readl(&uart->utrstat) & 0x2))
 235                /* wait for room in the tx FIFO */ ;
 236
 237#ifdef CONFIG_HWFLOW
 238        while (hwflow && !(readl(&uart->umstat) & 0x1))
 239                /* Wait for CTS up */ ;
 240#endif
 241
 242        writeb(c, &uart->utxh);
 243
 244        /* If \n, also do \r */
 245        if (c == '\n')
 246                serial_putc('\r');
 247}
 248
 249#if defined(CONFIG_SERIAL_MULTI)
 250static inline void serial_putc_dev(unsigned int dev_index, const char c)
 251{
 252        _serial_putc(c, dev_index);
 253}
 254#else
 255void serial_putc(const char c)
 256{
 257        _serial_putc(c, UART_NR);
 258}
 259#endif
 260
 261
 262/*
 263 * Test whether a character is in the RX buffer
 264 */
 265int _serial_tstc(const int dev_index)
 266{
 267        struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
 268
 269        return readl(&uart->utrstat) & 0x1;
 270}
 271
 272#if defined(CONFIG_SERIAL_MULTI)
 273static inline int serial_tstc_dev(unsigned int dev_index)
 274{
 275        return _serial_tstc(dev_index);
 276}
 277#else
 278int serial_tstc(void)
 279{
 280        return _serial_tstc(UART_NR);
 281}
 282#endif
 283
 284void _serial_puts(const char *s, const int dev_index)
 285{
 286        while (*s) {
 287                _serial_putc(*s++, dev_index);
 288        }
 289}
 290
 291#if defined(CONFIG_SERIAL_MULTI)
 292static inline void serial_puts_dev(int dev_index, const char *s)
 293{
 294        _serial_puts(s, dev_index);
 295}
 296#else
 297void serial_puts(const char *s)
 298{
 299        _serial_puts(s, UART_NR);
 300}
 301#endif
 302
 303#if defined(CONFIG_SERIAL_MULTI)
 304DECLARE_S3C_SERIAL_FUNCTIONS(0);
 305struct serial_device s3c24xx_serial0_device =
 306INIT_S3C_SERIAL_STRUCTURE(0, "s3ser0");
 307DECLARE_S3C_SERIAL_FUNCTIONS(1);
 308struct serial_device s3c24xx_serial1_device =
 309INIT_S3C_SERIAL_STRUCTURE(1, "s3ser1");
 310DECLARE_S3C_SERIAL_FUNCTIONS(2);
 311struct serial_device s3c24xx_serial2_device =
 312INIT_S3C_SERIAL_STRUCTURE(2, "s3ser2");
 313
 314__weak struct serial_device *default_serial_console(void)
 315{
 316#if defined(CONFIG_SERIAL1)
 317        return &s3c24xx_serial0_device;
 318#elif defined(CONFIG_SERIAL2)
 319        return &s3c24xx_serial1_device;
 320#elif defined(CONFIG_SERIAL3)
 321        return &s3c24xx_serial2_device;
 322#else
 323#error "CONFIG_SERIAL? missing."
 324#endif
 325}
 326#endif /* CONFIG_SERIAL_MULTI */
 327