serial.c 6.7 KB
Newer Older
W
wdenk 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * (C) Copyright 2004
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
 * 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 <serial.h>
26
#include <stdio_dev.h>
27 28
#include <post.h>
#include <linux/compiler.h>
W
wdenk 已提交
29

30 31
DECLARE_GLOBAL_DATA_PTR;

32 33
static struct serial_device *serial_devices;
static struct serial_device *serial_current;
W
wdenk 已提交
34

35
void serial_register(struct serial_device *dev)
W
wdenk 已提交
36
{
37
#ifdef CONFIG_NEEDS_MANUAL_RELOC
W
wdenk 已提交
38 39 40 41 42 43
	dev->init += gd->reloc_off;
	dev->setbrg += gd->reloc_off;
	dev->getc += gd->reloc_off;
	dev->tstc += gd->reloc_off;
	dev->putc += gd->reloc_off;
	dev->puts += gd->reloc_off;
44
#endif
W
wdenk 已提交
45 46 47 48 49

	dev->next = serial_devices;
	serial_devices = dev;
}

50
void serial_initialize(void)
W
wdenk 已提交
51 52
{
#if defined(CONFIG_8xx_CONS_SMC1) || defined(CONFIG_8xx_CONS_SMC2)
53
	serial_register(&serial_smc_device);
W
wdenk 已提交
54
#endif
55 56 57
#if	defined(CONFIG_8xx_CONS_SCC1) || defined(CONFIG_8xx_CONS_SCC2) || \
	defined(CONFIG_8xx_CONS_SCC3) || defined(CONFIG_8xx_CONS_SCC4)
	serial_register(&serial_scc_device);
W
wdenk 已提交
58 59
#endif

60 61
#if defined(CONFIG_SYS_NS16550_SERIAL)
#if defined(CONFIG_SYS_NS16550_COM1)
62 63
	serial_register(&eserial1_device);
#endif
64
#if defined(CONFIG_SYS_NS16550_COM2)
65 66
	serial_register(&eserial2_device);
#endif
67
#if defined(CONFIG_SYS_NS16550_COM3)
68 69
	serial_register(&eserial3_device);
#endif
70
#if defined(CONFIG_SYS_NS16550_COM4)
71 72
	serial_register(&eserial4_device);
#endif
73
#endif /* CONFIG_SYS_NS16550_SERIAL */
74
#if defined(CONFIG_FFUART)
75 76
	serial_register(&serial_ffuart_device);
#endif
77
#if defined(CONFIG_BTUART)
78 79
	serial_register(&serial_btuart_device);
#endif
80
#if defined(CONFIG_STUART)
81
	serial_register(&serial_stuart_device);
82 83 84 85 86
#endif
#if defined(CONFIG_S3C2410)
	serial_register(&s3c24xx_serial0_device);
	serial_register(&s3c24xx_serial1_device);
	serial_register(&s3c24xx_serial2_device);
M
Minkyu Kang 已提交
87
#endif
88
#if defined(CONFIG_S5P)
89 90 91 92
	serial_register(&s5p_serial0_device);
	serial_register(&s5p_serial1_device);
	serial_register(&s5p_serial2_device);
	serial_register(&s5p_serial3_device);
93 94 95 96 97 98 99 100 101 102 103 104 105 106
#endif
#if defined(CONFIG_MPC512X)
#if defined(CONFIG_SYS_PSC1)
	serial_register(&serial1_device);
#endif
#if defined(CONFIG_SYS_PSC3)
	serial_register(&serial3_device);
#endif
#if defined(CONFIG_SYS_PSC4)
	serial_register(&serial4_device);
#endif
#if defined(CONFIG_SYS_PSC6)
	serial_register(&serial6_device);
#endif
107 108 109
#endif
#if defined(CONFIG_SYS_BFIN_UART)
	serial_register_bfin_uart();
110
#endif
111 112 113 114 115 116 117 118 119 120 121 122 123 124
#if defined(CONFIG_XILINX_UARTLITE)
# ifdef XILINX_UARTLITE_BASEADDR
	serial_register(&uartlite_serial0_device);
# endif /* XILINX_UARTLITE_BASEADDR */
# ifdef XILINX_UARTLITE_BASEADDR1
	serial_register(&uartlite_serial1_device);
# endif /* XILINX_UARTLITE_BASEADDR1 */
# ifdef XILINX_UARTLITE_BASEADDR2
	serial_register(&uartlite_serial2_device);
# endif /* XILINX_UARTLITE_BASEADDR2 */
# ifdef XILINX_UARTLITE_BASEADDR3
	serial_register(&uartlite_serial3_device);
# endif /* XILINX_UARTLITE_BASEADDR3 */
#endif /* CONFIG_XILINX_UARTLITE */
125
	serial_assign(default_serial_console()->name);
W
wdenk 已提交
126 127
}

128
void serial_stdio_init(void)
W
wdenk 已提交
129
{
130
	struct stdio_dev dev;
W
wdenk 已提交
131 132
	struct serial_device *s = serial_devices;

W
wdenk 已提交
133
	while (s) {
134
		memset(&dev, 0, sizeof(dev));
W
wdenk 已提交
135

136
		strcpy(dev.name, s->name);
W
wdenk 已提交
137 138 139
		dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;

		dev.start = s->init;
140
		dev.stop = s->uninit;
W
wdenk 已提交
141 142 143 144 145
		dev.putc = s->putc;
		dev.puts = s->puts;
		dev.getc = s->getc;
		dev.tstc = s->tstc;

146
		stdio_register(&dev);
W
wdenk 已提交
147 148 149 150 151

		s = s->next;
	}
}

152
int serial_assign(const char *name)
W
wdenk 已提交
153 154 155
{
	struct serial_device *s;

W
wdenk 已提交
156
	for (s = serial_devices; s; s = s->next) {
157
		if (strcmp(s->name, name) == 0) {
W
wdenk 已提交
158 159 160 161 162 163 164 165
			serial_current = s;
			return 0;
		}
	}

	return 1;
}

166
void serial_reinit_all(void)
W
wdenk 已提交
167 168 169
{
	struct serial_device *s;

170 171
	for (s = serial_devices; s; s = s->next)
		s->init();
W
wdenk 已提交
172 173
}

174
static struct serial_device *get_current(void)
W
wdenk 已提交
175
{
176
	struct serial_device *dev;
W
wdenk 已提交
177

178 179 180 181 182 183 184 185 186 187
	if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
		dev = default_serial_console();

		/* We must have a console device */
		if (!dev)
			panic("Cannot find console");
	} else
		dev = serial_current;
	return dev;
}
W
wdenk 已提交
188

189 190 191
int serial_init(void)
{
	return get_current()->init();
W
wdenk 已提交
192 193
}

194
void serial_setbrg(void)
W
wdenk 已提交
195
{
196
	get_current()->setbrg();
W
wdenk 已提交
197 198
}

199
int serial_getc(void)
W
wdenk 已提交
200
{
201
	return get_current()->getc();
W
wdenk 已提交
202 203
}

204
int serial_tstc(void)
W
wdenk 已提交
205
{
206
	return get_current()->tstc();
W
wdenk 已提交
207 208
}

209
void serial_putc(const char c)
W
wdenk 已提交
210
{
211
	get_current()->putc(c);
W
wdenk 已提交
212 213
}

214
void serial_puts(const char *s)
W
wdenk 已提交
215
{
216
	get_current()->puts(s);
W
wdenk 已提交
217
}
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305

#if CONFIG_POST & CONFIG_SYS_POST_UART
static const int bauds[] = CONFIG_SYS_BAUDRATE_TABLE;

/* Mark weak until post/cpu/.../uart.c migrate over */
__weak
int uart_post_test(int flags)
{
	unsigned char c;
	int ret, saved_baud, b;
	struct serial_device *saved_dev, *s;
	bd_t *bd = gd->bd;

	/* Save current serial state */
	ret = 0;
	saved_dev = serial_current;
	saved_baud = bd->bi_baudrate;

	for (s = serial_devices; s; s = s->next) {
		/* If this driver doesn't support loop back, skip it */
		if (!s->loop)
			continue;

		/* Test the next device */
		serial_current = s;

		ret = serial_init();
		if (ret)
			goto done;

		/* Consume anything that happens to be queued */
		while (serial_tstc())
			serial_getc();

		/* Enable loop back */
		s->loop(1);

		/* Test every available baud rate */
		for (b = 0; b < ARRAY_SIZE(bauds); ++b) {
			bd->bi_baudrate = bauds[b];
			serial_setbrg();

			/*
			 * Stick to printable chars to avoid issues:
			 *  - terminal corruption
			 *  - serial program reacting to sequences and sending
			 *    back random extra data
			 *  - most serial drivers add in extra chars (like \r\n)
			 */
			for (c = 0x20; c < 0x7f; ++c) {
				/* Send it out */
				serial_putc(c);

				/* Make sure it's the same one */
				ret = (c != serial_getc());
				if (ret) {
					s->loop(0);
					goto done;
				}

				/* Clean up the output in case it was sent */
				serial_putc('\b');
				ret = ('\b' != serial_getc());
				if (ret) {
					s->loop(0);
					goto done;
				}
			}
		}

		/* Disable loop back */
		s->loop(0);

		/* XXX: There is no serial_uninit() !? */
		if (s->uninit)
			s->uninit();
	}

 done:
	/* Restore previous serial state */
	serial_current = saved_dev;
	bd->bi_baudrate = saved_baud;
	serial_reinit_all();
	serial_setbrg();

	return ret;
}
#endif