blob: 2a07498c1ee9c063c4a4890c16551074936bd2bb [file] [log] [blame]
Wolfgang Denk1a459662013-07-08 09:37:19 +02001pyright 2002
2 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
3 * Marius Groeger <mgroeger@sysgo.de>
wdenk074cff02004-02-24 00:16:43 +00004 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * (C) Copyright 2002
6 * ght 2002-2004
wdenk074cff02004-02-24 00:16:43 +00007 * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
8 *
9 * (C) Copyright 2002
10 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
11 * Marius Groeger <mgroeger@sysgo.de>
12 *
13 * (C) Copyright 2002
14 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
15 * Alex Zuepke <azu@sysgo.de>
16 *
17 * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
18 *
Wolfgang Denk1a459662013-07-08 09:37:19 +020019 * SPDX-License-Identifier: GPL-2.0+
wdenk074cff02004-02-24 00:16:43 +000020 */
21
22#include <common.h>
23#include <asm/hardware.h>
24
Wolfgang Denkd87080b2006-03-31 18:32:53 +020025DECLARE_GLOBAL_DATA_PTR;
26
wdenk074cff02004-02-24 00:16:43 +000027/* flush serial input queue. returns 0 on success or negative error
28 * number otherwise
29 */
30static int serial_flush_input(void)
31{
32 volatile u32 tmp;
33
34 /* keep on reading as long as the receiver is not empty */
35 while(UTRSTAT0&0x01) {
36 tmp = REGB(URXH0);
37 }
38
39 return 0;
40}
41
42
43/* flush output queue. returns 0 on success or negative error number
44 * otherwise
45 */
46static int serial_flush_output(void)
47{
48 /* wait until the transmitter is no longer busy */
49 while(!(UTRSTAT0 & 0x02)) {
50 }
51
52 return 0;
53}
54
55
Marek Vasuteb507662012-09-14 22:39:19 +020056static void s3c44b0_serial_setbrg(void)
wdenk074cff02004-02-24 00:16:43 +000057{
wdenk074cff02004-02-24 00:16:43 +000058 u32 divisor = 0;
59
60 /* get correct divisor */
61 switch(gd->baudrate) {
62
63 case 1200:
64#if CONFIG_S3C44B0_CLOCK_SPEED==66
65 divisor = 3124;
66#elif CONFIG_S3C44B0_CLOCK_SPEED==75
67 divisor = 3905;
68#else
69# error CONFIG_S3C44B0_CLOCK_SPEED undefined
70#endif
71 break;
72
73 case 9600:
74#if CONFIG_S3C44B0_CLOCK_SPEED==66
75 divisor = 390;
76#elif CONFIG_S3C44B0_CLOCK_SPEED==75
77 divisor = 487;
78#else
79# error CONFIG_S3C44B0_CLOCK_SPEED undefined
80#endif
81 break;
82
83 case 19200:
84#if CONFIG_S3C44B0_CLOCK_SPEED==66
85 divisor = 194;
86#elif CONFIG_S3C44B0_CLOCK_SPEED==75
87 divisor = 243;
88#else
89# error CONFIG_S3C44B0_CLOCK_SPEED undefined
90#endif
91 break;
92
93 case 38400:
94#if CONFIG_S3C44B0_CLOCK_SPEED==66
95 divisor = 97;
96#elif CONFIG_S3C44B0_CLOCK_SPEED==75
97 divisor = 121;
98#else
99# error CONFIG_S3C44B0_CLOCK_SPEED undefined
wdenke86e5a02004-10-17 21:12:06 +0000100#endif /* break; */
wdenk074cff02004-02-24 00:16:43 +0000101
102 case 57600:
103#if CONFIG_S3C44B0_CLOCK_SPEED==66
104 divisor = 64;
105#elif CONFIG_S3C44B0_CLOCK_SPEED==75
106 divisor = 80;
107#else
108# error CONFIG_S3C44B0_CLOCK_SPEED undefined
wdenke86e5a02004-10-17 21:12:06 +0000109#endif /* break; */
wdenk074cff02004-02-24 00:16:43 +0000110
111 case 115200:
112#if CONFIG_S3C44B0_CLOCK_SPEED==66
113 divisor = 32;
114#elif CONFIG_S3C44B0_CLOCK_SPEED==75
115 divisor = 40;
116#else
117# error CONFIG_S3C44B0_CLOCK_SPEED undefined
wdenke86e5a02004-10-17 21:12:06 +0000118#endif /* break; */
wdenk074cff02004-02-24 00:16:43 +0000119 }
120
121 serial_flush_output();
122 serial_flush_input();
123 UFCON0 = 0x0;
124 ULCON0 = 0x03;
125 UCON0 = 0x05;
126 UBRDIV0 = divisor;
127
128 UFCON1 = 0x0;
129 ULCON1 = 0x03;
130 UCON1 = 0x05;
131 UBRDIV1 = divisor;
132
133 for(divisor=0; divisor<100; divisor++) {
134 /* NOP */
135 }
136}
137
138
139/*
140 * Initialise the serial port with the given baudrate. The settings
141 * are always 8 data bits, no parity, 1 stop bit, no start bits.
142 *
143 */
Marek Vasuteb507662012-09-14 22:39:19 +0200144static int s3c44b0_serial_init(void)
wdenk074cff02004-02-24 00:16:43 +0000145{
146 serial_setbrg ();
147
148 return (0);
149}
150
151
152/*
153 * Output a single byte to the serial port.
154 */
Marek Vasuteb507662012-09-14 22:39:19 +0200155static void s3c44b0_serial_putc(const char c)
wdenk074cff02004-02-24 00:16:43 +0000156{
157 /* wait for room in the transmit FIFO */
158 while(!(UTRSTAT0 & 0x02));
159
160 UTXH0 = (unsigned char)c;
161
162 /*
163 to be polite with serial console add a line feed
164 to the carriage return character
165 */
166 if (c=='\n')
167 serial_putc('\r');
168}
169
170/*
171 * Read a single byte from the serial port. Returns 1 on success, 0
172 * otherwise. When the function is succesfull, the character read is
173 * written into its argument c.
174 */
Marek Vasuteb507662012-09-14 22:39:19 +0200175static int s3c44b0_serial_tstc(void)
wdenk074cff02004-02-24 00:16:43 +0000176{
177 return (UTRSTAT0 & 0x01);
178}
179
180/*
181 * Read a single byte from the serial port. Returns 1 on success, 0
182 * otherwise. When the function is succesfull, the character read is
183 * written into its argument c.
184 */
Marek Vasuteb507662012-09-14 22:39:19 +0200185static int s3c44b0_serial_getc(void)
wdenk074cff02004-02-24 00:16:43 +0000186{
187 int rv;
188
189 for(;;) {
Marek Vasuteb507662012-09-14 22:39:19 +0200190 rv = s3c44b0_serial_tstc();
wdenk074cff02004-02-24 00:16:43 +0000191
192 if(rv > 0)
193 return URXH0;
194 }
195}
196
Marek Vasuteb507662012-09-14 22:39:19 +0200197static struct serial_device s3c44b0_serial_drv = {
198 .name = "s3c44b0_serial",
199 .start = s3c44b0_serial_init,
200 .stop = NULL,
201 .setbrg = s3c44b0_serial_setbrg,
202 .putc = s3c44b0_serial_putc,
Marek Vasutec3fd682012-10-06 14:07:02 +0000203 .puts = default_serial_puts,
Marek Vasuteb507662012-09-14 22:39:19 +0200204 .getc = s3c44b0_serial_getc,
205 .tstc = s3c44b0_serial_tstc,
206};
207
208void s3c44b0_serial_initialize(void)
209{
210 serial_register(&s3c44b0_serial_drv);
211}
212
213__weak struct serial_device *default_serial_console(void)
214{
215 return &s3c44b0_serial_drv;
216}