blob: d1b5777cecda13be6191404cefe6dcf82a92f564 [file] [log] [blame]
Simon Glass57d92752014-09-04 16:27:26 -06001/*
2 * Copyright (c) 2014 The Chromium OS Authors.
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <common.h>
8#include <dm.h>
Simon Glassad1b81c2014-10-29 13:09:03 -06009#include <environment.h>
Simon Glass57d92752014-09-04 16:27:26 -060010#include <errno.h>
11#include <fdtdec.h>
12#include <os.h>
13#include <serial.h>
14#include <stdio_dev.h>
Simon Glassc487fd42014-10-22 21:37:02 -060015#include <watchdog.h>
Simon Glass57d92752014-09-04 16:27:26 -060016#include <dm/lists.h>
17#include <dm/device-internal.h>
18
Simon Glassc487fd42014-10-22 21:37:02 -060019#include <ns16550.h>
20
Simon Glass57d92752014-09-04 16:27:26 -060021DECLARE_GLOBAL_DATA_PTR;
22
Simon Glassad1b81c2014-10-29 13:09:03 -060023/*
24 * Table with supported baudrates (defined in config_xyz.h)
25 */
26static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
27
Simon Glass57d92752014-09-04 16:27:26 -060028#ifndef CONFIG_SYS_MALLOC_F_LEN
29#error "Serial is required before relocation - define CONFIG_SYS_MALLOC_F_LEN to make this work"
30#endif
31
32static void serial_find_console_or_panic(void)
33{
Simon Glass469a5792014-11-10 18:00:20 -070034 struct udevice *dev;
35
Simon Glass59990bf2014-09-17 09:02:40 -060036#ifdef CONFIG_OF_CONTROL
Simon Glass57d92752014-09-04 16:27:26 -060037 int node;
38
39 /* Check for a chosen console */
40 node = fdtdec_get_chosen_node(gd->fdt_blob, "stdout-path");
41 if (node < 0)
Masahiro Yamada0bd4e392014-11-21 19:47:08 +090042 node = fdt_path_offset(gd->fdt_blob, "console");
Simon Glass469a5792014-11-10 18:00:20 -070043 if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, &dev)) {
44 gd->cur_serial_dev = dev;
Simon Glass57d92752014-09-04 16:27:26 -060045 return;
Simon Glass469a5792014-11-10 18:00:20 -070046 }
Simon Glass57d92752014-09-04 16:27:26 -060047
48 /*
49 * If the console is not marked to be bound before relocation, bind
50 * it anyway.
51 */
52 if (node > 0 &&
Simon Glass469a5792014-11-10 18:00:20 -070053 !lists_bind_fdt(gd->dm_root, gd->fdt_blob, node, &dev)) {
54 if (!device_probe(dev)) {
55 gd->cur_serial_dev = dev;
Simon Glass57d92752014-09-04 16:27:26 -060056 return;
Simon Glass469a5792014-11-10 18:00:20 -070057 }
Simon Glass57d92752014-09-04 16:27:26 -060058 }
Simon Glass59990bf2014-09-17 09:02:40 -060059#endif
Simon Glass57d92752014-09-04 16:27:26 -060060 /*
Simon Glass91155c62014-10-22 21:37:06 -060061 * Try to use CONFIG_CONS_INDEX if available (it is numbered from 1!).
62 *
Simon Glass57d92752014-09-04 16:27:26 -060063 * Failing that, get the device with sequence number 0, or in extremis
64 * just the first serial device we can find. But we insist on having
65 * a console (even if it is silent).
66 */
Simon Glass91155c62014-10-22 21:37:06 -060067#ifdef CONFIG_CONS_INDEX
68#define INDEX (CONFIG_CONS_INDEX - 1)
69#else
70#define INDEX 0
71#endif
Simon Glass469a5792014-11-10 18:00:20 -070072 if (uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &dev) &&
73 uclass_get_device(UCLASS_SERIAL, INDEX, &dev) &&
74 (uclass_first_device(UCLASS_SERIAL, &dev) || !dev))
Simon Glass57d92752014-09-04 16:27:26 -060075 panic("No serial driver found");
Simon Glass91155c62014-10-22 21:37:06 -060076#undef INDEX
Simon Glass469a5792014-11-10 18:00:20 -070077 gd->cur_serial_dev = dev;
Simon Glass57d92752014-09-04 16:27:26 -060078}
79
80/* Called prior to relocation */
81int serial_init(void)
82{
83 serial_find_console_or_panic();
84 gd->flags |= GD_FLG_SERIAL_READY;
85
86 return 0;
87}
88
89/* Called after relocation */
90void serial_initialize(void)
91{
92 serial_find_console_or_panic();
93}
94
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +090095static void _serial_putc(struct udevice *dev, char ch)
Simon Glass57d92752014-09-04 16:27:26 -060096{
Masahiro Yamadabac64462014-10-23 22:26:06 +090097 struct dm_serial_ops *ops = serial_get_ops(dev);
Simon Glass57d92752014-09-04 16:27:26 -060098 int err;
99
100 do {
Masahiro Yamadabac64462014-10-23 22:26:06 +0900101 err = ops->putc(dev, ch);
Simon Glass57d92752014-09-04 16:27:26 -0600102 } while (err == -EAGAIN);
103 if (ch == '\n')
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900104 _serial_putc(dev, '\r');
Simon Glass57d92752014-09-04 16:27:26 -0600105}
106
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900107static void _serial_puts(struct udevice *dev, const char *str)
Simon Glass57d92752014-09-04 16:27:26 -0600108{
109 while (*str)
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900110 _serial_putc(dev, *str++);
Simon Glass57d92752014-09-04 16:27:26 -0600111}
112
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900113static int _serial_getc(struct udevice *dev)
Simon Glass57d92752014-09-04 16:27:26 -0600114{
Simon Glassb8893322014-10-01 19:57:23 -0600115 struct dm_serial_ops *ops = serial_get_ops(dev);
Simon Glass57d92752014-09-04 16:27:26 -0600116 int err;
117
118 do {
Simon Glassb8893322014-10-01 19:57:23 -0600119 err = ops->getc(dev);
Simon Glassc487fd42014-10-22 21:37:02 -0600120 if (err == -EAGAIN)
121 WATCHDOG_RESET();
Simon Glass57d92752014-09-04 16:27:26 -0600122 } while (err == -EAGAIN);
123
124 return err >= 0 ? err : 0;
125}
126
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900127static int _serial_tstc(struct udevice *dev)
128{
129 struct dm_serial_ops *ops = serial_get_ops(dev);
130
131 if (ops->pending)
132 return ops->pending(dev, true);
133
134 return 1;
135}
136
137void serial_putc(char ch)
138{
Simon Glass469a5792014-11-10 18:00:20 -0700139 _serial_putc(gd->cur_serial_dev, ch);
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900140}
141
142void serial_puts(const char *str)
143{
Simon Glass469a5792014-11-10 18:00:20 -0700144 _serial_puts(gd->cur_serial_dev, str);
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900145}
146
Simon Glassb8893322014-10-01 19:57:23 -0600147int serial_getc(void)
148{
Simon Glass469a5792014-11-10 18:00:20 -0700149 return _serial_getc(gd->cur_serial_dev);
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900150}
151
152int serial_tstc(void)
153{
Simon Glass469a5792014-11-10 18:00:20 -0700154 return _serial_tstc(gd->cur_serial_dev);
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900155}
156
157void serial_setbrg(void)
158{
Simon Glass469a5792014-11-10 18:00:20 -0700159 struct dm_serial_ops *ops = serial_get_ops(gd->cur_serial_dev);
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900160
161 if (ops->setbrg)
Simon Glass469a5792014-11-10 18:00:20 -0700162 ops->setbrg(gd->cur_serial_dev, gd->baudrate);
Simon Glassb8893322014-10-01 19:57:23 -0600163}
164
Simon Glass57d92752014-09-04 16:27:26 -0600165void serial_stdio_init(void)
166{
167}
168
Simon Glass236f2bd2014-11-10 17:16:48 -0700169#ifdef CONFIG_DM_STDIO
Simon Glassb8893322014-10-01 19:57:23 -0600170static void serial_stub_putc(struct stdio_dev *sdev, const char ch)
Simon Glass57d92752014-09-04 16:27:26 -0600171{
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900172 _serial_putc(sdev->priv, ch);
Simon Glass57d92752014-09-04 16:27:26 -0600173}
Simon Glass236f2bd2014-11-10 17:16:48 -0700174#endif
Simon Glass57d92752014-09-04 16:27:26 -0600175
176void serial_stub_puts(struct stdio_dev *sdev, const char *str)
177{
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900178 _serial_puts(sdev->priv, str);
Simon Glass57d92752014-09-04 16:27:26 -0600179}
180
181int serial_stub_getc(struct stdio_dev *sdev)
182{
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900183 return _serial_getc(sdev->priv);
Simon Glass57d92752014-09-04 16:27:26 -0600184}
185
186int serial_stub_tstc(struct stdio_dev *sdev)
187{
Masahiro Yamadaeea5a4c2014-10-23 22:26:08 +0900188 return _serial_tstc(sdev->priv);
Simon Glass57d92752014-09-04 16:27:26 -0600189}
190
Simon Glassad1b81c2014-10-29 13:09:03 -0600191/**
192 * on_baudrate() - Update the actual baudrate when the env var changes
193 *
194 * This will check for a valid baudrate and only apply it if valid.
195 */
196static int on_baudrate(const char *name, const char *value, enum env_op op,
197 int flags)
198{
199 int i;
200 int baudrate;
201
202 switch (op) {
203 case env_op_create:
204 case env_op_overwrite:
205 /*
206 * Switch to new baudrate if new baudrate is supported
207 */
208 baudrate = simple_strtoul(value, NULL, 10);
209
210 /* Not actually changing */
211 if (gd->baudrate == baudrate)
212 return 0;
213
214 for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
215 if (baudrate == baudrate_table[i])
216 break;
217 }
218 if (i == ARRAY_SIZE(baudrate_table)) {
219 if ((flags & H_FORCE) == 0)
220 printf("## Baudrate %d bps not supported\n",
221 baudrate);
222 return 1;
223 }
224 if ((flags & H_INTERACTIVE) != 0) {
225 printf("## Switch baudrate to %d bps and press ENTER ...\n",
226 baudrate);
227 udelay(50000);
228 }
229
230 gd->baudrate = baudrate;
231
232 serial_setbrg();
233
234 udelay(50000);
235
236 if ((flags & H_INTERACTIVE) != 0)
237 while (1) {
238 if (getc() == '\r')
239 break;
240 }
241
242 return 0;
243 case env_op_delete:
244 printf("## Baudrate may not be deleted\n");
245 return 1;
246 default:
247 return 0;
248 }
249}
250U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
251
Simon Glass57d92752014-09-04 16:27:26 -0600252static int serial_post_probe(struct udevice *dev)
253{
Simon Glass57d92752014-09-04 16:27:26 -0600254 struct dm_serial_ops *ops = serial_get_ops(dev);
Simon Glass236f2bd2014-11-10 17:16:48 -0700255#ifdef CONFIG_DM_STDIO
Simon Glass57d92752014-09-04 16:27:26 -0600256 struct serial_dev_priv *upriv = dev->uclass_priv;
Simon Glass236f2bd2014-11-10 17:16:48 -0700257 struct stdio_dev sdev;
258#endif
Simon Glass57d92752014-09-04 16:27:26 -0600259 int ret;
260
261 /* Set the baud rate */
262 if (ops->setbrg) {
263 ret = ops->setbrg(dev, gd->baudrate);
264 if (ret)
265 return ret;
266 }
267
Simon Glass236f2bd2014-11-10 17:16:48 -0700268#ifdef CONFIG_DM_STDIO
Simon Glass57d92752014-09-04 16:27:26 -0600269 if (!(gd->flags & GD_FLG_RELOC))
270 return 0;
Simon Glass57d92752014-09-04 16:27:26 -0600271 memset(&sdev, '\0', sizeof(sdev));
272
273 strncpy(sdev.name, dev->name, sizeof(sdev.name));
274 sdev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
275 sdev.priv = dev;
276 sdev.putc = serial_stub_putc;
277 sdev.puts = serial_stub_puts;
278 sdev.getc = serial_stub_getc;
279 sdev.tstc = serial_stub_tstc;
280 stdio_register_dev(&sdev, &upriv->sdev);
Simon Glass236f2bd2014-11-10 17:16:48 -0700281#endif
Simon Glass57d92752014-09-04 16:27:26 -0600282 return 0;
283}
284
285static int serial_pre_remove(struct udevice *dev)
286{
287#ifdef CONFIG_SYS_STDIO_DEREGISTER
288 struct serial_dev_priv *upriv = dev->uclass_priv;
289
Hans de Goede4a742982014-10-10 18:30:17 +0200290 if (stdio_deregister_dev(upriv->sdev, 0))
Simon Glass57d92752014-09-04 16:27:26 -0600291 return -EPERM;
292#endif
293
294 return 0;
295}
296
297UCLASS_DRIVER(serial) = {
298 .id = UCLASS_SERIAL,
299 .name = "serial",
300 .post_probe = serial_post_probe,
301 .pre_remove = serial_pre_remove,
302 .per_device_auto_alloc_size = sizeof(struct serial_dev_priv),
303};