Fix regression in SMDK6400
[platform/kernel/u-boot.git] / drivers / serial / s3c64xx.c
1 /*
2  * (C) Copyright 2002
3  * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
4  *
5  * (C) Copyright 2008
6  * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include <common.h>
25
26 #include <asm/arch/s3c6400.h>
27
28 DECLARE_GLOBAL_DATA_PTR;
29
30 #ifdef CONFIG_SERIAL1
31 #define UART_NR S3C64XX_UART0
32
33 #elif defined(CONFIG_SERIAL2)
34 #define UART_NR S3C64XX_UART1
35
36 #elif defined(CONFIG_SERIAL3)
37 #define UART_NR S3C64XX_UART2
38
39 #else
40 #error "Bad: you didn't configure serial ..."
41 #endif
42
43 #define barrier() asm volatile("" ::: "memory")
44
45 /*
46  * The coefficient, used to calculate the baudrate on S3C6400 UARTs is
47  * calculated as
48  * C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT
49  * however, section 31.6.11 of the datasheet doesn't recomment using 1 for 1,
50  * 3 for 2, ... (2^n - 1) for n, instead, they suggest using these constants:
51  */
52 static const int udivslot[] = {
53         0,
54         0x0080,
55         0x0808,
56         0x0888,
57         0x2222,
58         0x4924,
59         0x4a52,
60         0x54aa,
61         0x5555,
62         0xd555,
63         0xd5d5,
64         0xddd5,
65         0xdddd,
66         0xdfdd,
67         0xdfdf,
68         0xffdf,
69 };
70
71 void serial_setbrg(void)
72 {
73         s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR);
74         u32 pclk = get_PCLK();
75         u32 baudrate = gd->baudrate;
76         int i;
77
78         i = (pclk / baudrate) % 16;
79
80         uart->UBRDIV = pclk / baudrate / 16 - 1;
81         uart->UDIVSLOT = udivslot[i];
82
83         for (i = 0; i < 100; i++)
84                 barrier();
85 }
86
87 /*
88  * Initialise the serial port with the given baudrate. The settings
89  * are always 8 data bits, no parity, 1 stop bit, no start bits.
90  */
91 int serial_init(void)
92 {
93         s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR);
94
95         /* reset and enable FIFOs, set triggers to the maximum */
96         uart->UFCON = 0xff;
97         uart->UMCON = 0;
98         /* 8N1 */
99         uart->ULCON = 3;
100         /* No interrupts, no DMA, pure polling */
101         uart->UCON = 5;
102
103         serial_setbrg();
104
105         return 0;
106 }
107
108 /*
109  * Read a single byte from the serial port. Returns 1 on success, 0
110  * otherwise. When the function is succesfull, the character read is
111  * written into its argument c.
112  */
113 int serial_getc(void)
114 {
115         s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR);
116
117         /* wait for character to arrive */
118         while (!(uart->UTRSTAT & 0x1));
119
120         return uart->URXH & 0xff;
121 }
122
123 #ifdef CONFIG_MODEM_SUPPORT
124 static int be_quiet;
125 void disable_putc(void)
126 {
127         be_quiet = 1;
128 }
129
130 void enable_putc(void)
131 {
132         be_quiet = 0;
133 }
134 #endif
135
136
137 /*
138  * Output a single byte to the serial port.
139  */
140 void serial_putc(const char c)
141 {
142         s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR);
143
144 #ifdef CONFIG_MODEM_SUPPORT
145         if (be_quiet)
146                 return;
147 #endif
148
149         /* wait for room in the tx FIFO */
150         while (!(uart->UTRSTAT & 0x2));
151
152         uart->UTXH = c;
153
154         /* If \n, also do \r */
155         if (c == '\n')
156                 serial_putc('\r');
157 }
158
159 /*
160  * Test whether a character is in the RX buffer
161  */
162 int serial_tstc(void)
163 {
164         s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR);
165
166         return uart->UTRSTAT & 0x1;
167 }
168
169 void serial_puts(const char *s)
170 {
171         while (*s)
172                 serial_putc(*s++);
173 }