uboot/drivers/serial/serial-uclass.c
<<
>>
Prefs
   1/*
   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>
   9#include <environment.h>
  10#include <errno.h>
  11#include <fdtdec.h>
  12#include <os.h>
  13#include <serial.h>
  14#include <stdio_dev.h>
  15#include <watchdog.h>
  16#include <dm/lists.h>
  17#include <dm/device-internal.h>
  18
  19DECLARE_GLOBAL_DATA_PTR;
  20
  21/*
  22 * Table with supported baudrates (defined in config_xyz.h)
  23 */
  24static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
  25
  26#ifndef CONFIG_SYS_MALLOC_F_LEN
  27#error "Serial is required before relocation - define CONFIG_SYS_MALLOC_F_LEN to make this work"
  28#endif
  29
  30static void serial_find_console_or_panic(void)
  31{
  32        const void *blob = gd->fdt_blob;
  33        struct udevice *dev;
  34        int node;
  35
  36        if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
  37                uclass_first_device(UCLASS_SERIAL, &dev);
  38                if (dev) {
  39                        gd->cur_serial_dev = dev;
  40                        return;
  41                }
  42        } else if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) {
  43                /* Check for a chosen console */
  44                node = fdtdec_get_chosen_node(blob, "stdout-path");
  45                if (node < 0) {
  46                        const char *str, *p, *name;
  47
  48                        /*
  49                         * Deal with things like
  50                         *      stdout-path = "serial0:115200n8";
  51                         *
  52                         * We need to look up the alias and then follow it to
  53                         * the correct node.
  54                         */
  55                        str = fdtdec_get_chosen_prop(blob, "stdout-path");
  56                        if (str) {
  57                                p = strchr(str, ':');
  58                                name = fdt_get_alias_namelen(blob, str,
  59                                                p ? p - str : strlen(str));
  60                                if (name)
  61                                        node = fdt_path_offset(blob, name);
  62                        }
  63                }
  64                if (node < 0)
  65                        node = fdt_path_offset(blob, "console");
  66                if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node,
  67                                                    &dev)) {
  68                        gd->cur_serial_dev = dev;
  69                        return;
  70                }
  71
  72                /*
  73                 * If the console is not marked to be bound before relocation,
  74                 * bind it anyway.
  75                 */
  76                if (node > 0 &&
  77                    !lists_bind_fdt(gd->dm_root, blob, node, &dev)) {
  78                        if (!device_probe(dev)) {
  79                                gd->cur_serial_dev = dev;
  80                                return;
  81                        }
  82                }
  83        }
  84        if (!SPL_BUILD || !CONFIG_IS_ENABLED(OF_CONTROL) || !blob) {
  85                /*
  86                 * Try to use CONFIG_CONS_INDEX if available (it is numbered
  87                 * from 1!).
  88                 *
  89                 * Failing that, get the device with sequence number 0, or in
  90                 * extremis just the first serial device we can find. But we
  91                 * insist on having a console (even if it is silent).
  92                 */
  93#ifdef CONFIG_CONS_INDEX
  94#define INDEX (CONFIG_CONS_INDEX - 1)
  95#else
  96#define INDEX 0
  97#endif
  98                if (!uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &dev) ||
  99                    !uclass_get_device(UCLASS_SERIAL, INDEX, &dev) ||
 100                    (!uclass_first_device(UCLASS_SERIAL, &dev) && dev)) {
 101                        gd->cur_serial_dev = dev;
 102                        return;
 103                }
 104#undef INDEX
 105        }
 106
 107#ifdef CONFIG_REQUIRE_SERIAL_CONSOLE
 108        panic_str("No serial driver found");
 109#endif
 110}
 111
 112/* Called prior to relocation */
 113int serial_init(void)
 114{
 115        serial_find_console_or_panic();
 116        gd->flags |= GD_FLG_SERIAL_READY;
 117
 118        return 0;
 119}
 120
 121/* Called after relocation */
 122void serial_initialize(void)
 123{
 124        serial_init();
 125}
 126
 127static void _serial_putc(struct udevice *dev, char ch)
 128{
 129        struct dm_serial_ops *ops = serial_get_ops(dev);
 130        int err;
 131
 132        if (ch == '\n')
 133                _serial_putc(dev, '\r');
 134
 135        do {
 136                err = ops->putc(dev, ch);
 137        } while (err == -EAGAIN);
 138}
 139
 140static void _serial_puts(struct udevice *dev, const char *str)
 141{
 142        while (*str)
 143                _serial_putc(dev, *str++);
 144}
 145
 146static int _serial_getc(struct udevice *dev)
 147{
 148        struct dm_serial_ops *ops = serial_get_ops(dev);
 149        int err;
 150
 151        do {
 152                err = ops->getc(dev);
 153                if (err == -EAGAIN)
 154                        WATCHDOG_RESET();
 155        } while (err == -EAGAIN);
 156
 157        return err >= 0 ? err : 0;
 158}
 159
 160static int _serial_tstc(struct udevice *dev)
 161{
 162        struct dm_serial_ops *ops = serial_get_ops(dev);
 163
 164        if (ops->pending)
 165                return ops->pending(dev, true);
 166
 167        return 1;
 168}
 169
 170void serial_putc(char ch)
 171{
 172        if (gd->cur_serial_dev)
 173                _serial_putc(gd->cur_serial_dev, ch);
 174}
 175
 176void serial_puts(const char *str)
 177{
 178        if (gd->cur_serial_dev)
 179                _serial_puts(gd->cur_serial_dev, str);
 180}
 181
 182int serial_getc(void)
 183{
 184        if (!gd->cur_serial_dev)
 185                return 0;
 186
 187        return _serial_getc(gd->cur_serial_dev);
 188}
 189
 190int serial_tstc(void)
 191{
 192        if (!gd->cur_serial_dev)
 193                return 0;
 194
 195        return _serial_tstc(gd->cur_serial_dev);
 196}
 197
 198void serial_setbrg(void)
 199{
 200        struct dm_serial_ops *ops;
 201
 202        if (!gd->cur_serial_dev)
 203                return;
 204
 205        ops = serial_get_ops(gd->cur_serial_dev);
 206        if (ops->setbrg)
 207                ops->setbrg(gd->cur_serial_dev, gd->baudrate);
 208}
 209
 210void serial_stdio_init(void)
 211{
 212}
 213
 214#if defined(CONFIG_DM_STDIO) && CONFIG_IS_ENABLED(SERIAL_PRESENT)
 215static void serial_stub_putc(struct stdio_dev *sdev, const char ch)
 216{
 217        _serial_putc(sdev->priv, ch);
 218}
 219#endif
 220
 221void serial_stub_puts(struct stdio_dev *sdev, const char *str)
 222{
 223        _serial_puts(sdev->priv, str);
 224}
 225
 226int serial_stub_getc(struct stdio_dev *sdev)
 227{
 228        return _serial_getc(sdev->priv);
 229}
 230
 231int serial_stub_tstc(struct stdio_dev *sdev)
 232{
 233        return _serial_tstc(sdev->priv);
 234}
 235
 236/**
 237 * on_baudrate() - Update the actual baudrate when the env var changes
 238 *
 239 * This will check for a valid baudrate and only apply it if valid.
 240 */
 241static int on_baudrate(const char *name, const char *value, enum env_op op,
 242        int flags)
 243{
 244        int i;
 245        int baudrate;
 246
 247        switch (op) {
 248        case env_op_create:
 249        case env_op_overwrite:
 250                /*
 251                 * Switch to new baudrate if new baudrate is supported
 252                 */
 253                baudrate = simple_strtoul(value, NULL, 10);
 254
 255                /* Not actually changing */
 256                if (gd->baudrate == baudrate)
 257                        return 0;
 258
 259                for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
 260                        if (baudrate == baudrate_table[i])
 261                                break;
 262                }
 263                if (i == ARRAY_SIZE(baudrate_table)) {
 264                        if ((flags & H_FORCE) == 0)
 265                                printf("## Baudrate %d bps not supported\n",
 266                                       baudrate);
 267                        return 1;
 268                }
 269                if ((flags & H_INTERACTIVE) != 0) {
 270                        printf("## Switch baudrate to %d bps and press ENTER ...\n",
 271                               baudrate);
 272                        udelay(50000);
 273                }
 274
 275                gd->baudrate = baudrate;
 276
 277                serial_setbrg();
 278
 279                udelay(50000);
 280
 281                if ((flags & H_INTERACTIVE) != 0)
 282                        while (1) {
 283                                if (getc() == '\r')
 284                                        break;
 285                        }
 286
 287                return 0;
 288        case env_op_delete:
 289                printf("## Baudrate may not be deleted\n");
 290                return 1;
 291        default:
 292                return 0;
 293        }
 294}
 295U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
 296
 297#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
 298static int serial_post_probe(struct udevice *dev)
 299{
 300        struct dm_serial_ops *ops = serial_get_ops(dev);
 301#ifdef CONFIG_DM_STDIO
 302        struct serial_dev_priv *upriv = dev_get_uclass_priv(dev);
 303        struct stdio_dev sdev;
 304#endif
 305        int ret;
 306
 307#if defined(CONFIG_NEEDS_MANUAL_RELOC)
 308        if (ops->setbrg)
 309                ops->setbrg += gd->reloc_off;
 310        if (ops->getc)
 311                ops->getc += gd->reloc_off;
 312        if (ops->putc)
 313                ops->putc += gd->reloc_off;
 314        if (ops->pending)
 315                ops->pending += gd->reloc_off;
 316        if (ops->clear)
 317                ops->clear += gd->reloc_off;
 318#if CONFIG_POST & CONFIG_SYS_POST_UART
 319        if (ops->loop)
 320                ops->loop += gd->reloc_off
 321#endif
 322#endif
 323        /* Set the baud rate */
 324        if (ops->setbrg) {
 325                ret = ops->setbrg(dev, gd->baudrate);
 326                if (ret)
 327                        return ret;
 328        }
 329
 330#ifdef CONFIG_DM_STDIO
 331        if (!(gd->flags & GD_FLG_RELOC))
 332                return 0;
 333        memset(&sdev, '\0', sizeof(sdev));
 334
 335        strncpy(sdev.name, dev->name, sizeof(sdev.name));
 336        sdev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
 337        sdev.priv = dev;
 338        sdev.putc = serial_stub_putc;
 339        sdev.puts = serial_stub_puts;
 340        sdev.getc = serial_stub_getc;
 341        sdev.tstc = serial_stub_tstc;
 342        stdio_register_dev(&sdev, &upriv->sdev);
 343#endif
 344        return 0;
 345}
 346
 347static int serial_pre_remove(struct udevice *dev)
 348{
 349#if CONFIG_IS_ENABLED(SYS_STDIO_DEREGISTER)
 350        struct serial_dev_priv *upriv = dev_get_uclass_priv(dev);
 351
 352        if (stdio_deregister_dev(upriv->sdev, 0))
 353                return -EPERM;
 354#endif
 355
 356        return 0;
 357}
 358
 359UCLASS_DRIVER(serial) = {
 360        .id             = UCLASS_SERIAL,
 361        .name           = "serial",
 362        .flags          = DM_UC_FLAG_SEQ_ALIAS,
 363        .post_probe     = serial_post_probe,
 364        .pre_remove     = serial_pre_remove,
 365        .per_device_auto_alloc_size = sizeof(struct serial_dev_priv),
 366};
 367#endif
 368