157d92753SSimon Glass /* 257d92753SSimon Glass * Copyright (c) 2014 The Chromium OS Authors. 357d92753SSimon Glass * 457d92753SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 557d92753SSimon Glass */ 657d92753SSimon Glass 757d92753SSimon Glass #include <common.h> 857d92753SSimon Glass #include <dm.h> 957d92753SSimon Glass #include <errno.h> 1057d92753SSimon Glass #include <fdtdec.h> 1157d92753SSimon Glass #include <os.h> 1257d92753SSimon Glass #include <serial.h> 1357d92753SSimon Glass #include <stdio_dev.h> 14*c487fd47SSimon Glass #include <watchdog.h> 1557d92753SSimon Glass #include <dm/lists.h> 1657d92753SSimon Glass #include <dm/device-internal.h> 1757d92753SSimon Glass 18*c487fd47SSimon Glass #include <ns16550.h> 19*c487fd47SSimon Glass 2057d92753SSimon Glass DECLARE_GLOBAL_DATA_PTR; 2157d92753SSimon Glass 2257d92753SSimon Glass /* The currently-selected console serial device */ 2357d92753SSimon Glass struct udevice *cur_dev __attribute__ ((section(".data"))); 2457d92753SSimon Glass 2557d92753SSimon Glass #ifndef CONFIG_SYS_MALLOC_F_LEN 2657d92753SSimon Glass #error "Serial is required before relocation - define CONFIG_SYS_MALLOC_F_LEN to make this work" 2757d92753SSimon Glass #endif 2857d92753SSimon Glass 2957d92753SSimon Glass static void serial_find_console_or_panic(void) 3057d92753SSimon Glass { 3159990bf0SSimon Glass #ifdef CONFIG_OF_CONTROL 3257d92753SSimon Glass int node; 3357d92753SSimon Glass 3457d92753SSimon Glass /* Check for a chosen console */ 3557d92753SSimon Glass node = fdtdec_get_chosen_node(gd->fdt_blob, "stdout-path"); 3657d92753SSimon Glass if (node < 0) 3757d92753SSimon Glass node = fdtdec_get_alias_node(gd->fdt_blob, "console"); 3857d92753SSimon Glass if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, &cur_dev)) 3957d92753SSimon Glass return; 4057d92753SSimon Glass 4157d92753SSimon Glass /* 4257d92753SSimon Glass * If the console is not marked to be bound before relocation, bind 4357d92753SSimon Glass * it anyway. 4457d92753SSimon Glass */ 4557d92753SSimon Glass if (node > 0 && 4657d92753SSimon Glass !lists_bind_fdt(gd->dm_root, gd->fdt_blob, node, &cur_dev)) { 4757d92753SSimon Glass if (!device_probe(cur_dev)) 4857d92753SSimon Glass return; 4957d92753SSimon Glass cur_dev = NULL; 5057d92753SSimon Glass } 5159990bf0SSimon Glass #endif 5257d92753SSimon Glass /* 5357d92753SSimon Glass * Failing that, get the device with sequence number 0, or in extremis 5457d92753SSimon Glass * just the first serial device we can find. But we insist on having 5557d92753SSimon Glass * a console (even if it is silent). 5657d92753SSimon Glass */ 5757d92753SSimon Glass if (uclass_get_device_by_seq(UCLASS_SERIAL, 0, &cur_dev) && 5857d92753SSimon Glass (uclass_first_device(UCLASS_SERIAL, &cur_dev) || !cur_dev)) 5957d92753SSimon Glass panic("No serial driver found"); 6057d92753SSimon Glass } 6157d92753SSimon Glass 6257d92753SSimon Glass /* Called prior to relocation */ 6357d92753SSimon Glass int serial_init(void) 6457d92753SSimon Glass { 6557d92753SSimon Glass serial_find_console_or_panic(); 6657d92753SSimon Glass gd->flags |= GD_FLG_SERIAL_READY; 6757d92753SSimon Glass 6857d92753SSimon Glass return 0; 6957d92753SSimon Glass } 7057d92753SSimon Glass 7157d92753SSimon Glass /* Called after relocation */ 7257d92753SSimon Glass void serial_initialize(void) 7357d92753SSimon Glass { 7457d92753SSimon Glass serial_find_console_or_panic(); 7557d92753SSimon Glass } 7657d92753SSimon Glass 77b8893327SSimon Glass static void serial_putc_dev(struct udevice *dev, char ch) 7857d92753SSimon Glass { 7957d92753SSimon Glass struct dm_serial_ops *ops = serial_get_ops(cur_dev); 8057d92753SSimon Glass int err; 8157d92753SSimon Glass 8257d92753SSimon Glass do { 8357d92753SSimon Glass err = ops->putc(cur_dev, ch); 8457d92753SSimon Glass } while (err == -EAGAIN); 8557d92753SSimon Glass if (ch == '\n') 8657d92753SSimon Glass serial_putc('\r'); 8757d92753SSimon Glass } 8857d92753SSimon Glass 89b8893327SSimon Glass void serial_putc(char ch) 90b8893327SSimon Glass { 91b8893327SSimon Glass serial_putc_dev(cur_dev, ch); 92b8893327SSimon Glass } 93b8893327SSimon Glass 9457d92753SSimon Glass void serial_setbrg(void) 9557d92753SSimon Glass { 9657d92753SSimon Glass struct dm_serial_ops *ops = serial_get_ops(cur_dev); 9757d92753SSimon Glass 9857d92753SSimon Glass if (ops->setbrg) 9957d92753SSimon Glass ops->setbrg(cur_dev, gd->baudrate); 10057d92753SSimon Glass } 10157d92753SSimon Glass 10257d92753SSimon Glass void serial_puts(const char *str) 10357d92753SSimon Glass { 10457d92753SSimon Glass while (*str) 10557d92753SSimon Glass serial_putc(*str++); 10657d92753SSimon Glass } 10757d92753SSimon Glass 10857d92753SSimon Glass int serial_tstc(void) 10957d92753SSimon Glass { 11057d92753SSimon Glass struct dm_serial_ops *ops = serial_get_ops(cur_dev); 11157d92753SSimon Glass 11257d92753SSimon Glass if (ops->pending) 11357d92753SSimon Glass return ops->pending(cur_dev, true); 11457d92753SSimon Glass 11557d92753SSimon Glass return 1; 11657d92753SSimon Glass } 11757d92753SSimon Glass 118b8893327SSimon Glass static int serial_getc_dev(struct udevice *dev) 11957d92753SSimon Glass { 120b8893327SSimon Glass struct dm_serial_ops *ops = serial_get_ops(dev); 12157d92753SSimon Glass int err; 12257d92753SSimon Glass 12357d92753SSimon Glass do { 124b8893327SSimon Glass err = ops->getc(dev); 125*c487fd47SSimon Glass if (err == -EAGAIN) 126*c487fd47SSimon Glass WATCHDOG_RESET(); 12757d92753SSimon Glass } while (err == -EAGAIN); 12857d92753SSimon Glass 12957d92753SSimon Glass return err >= 0 ? err : 0; 13057d92753SSimon Glass } 13157d92753SSimon Glass 132b8893327SSimon Glass int serial_getc(void) 133b8893327SSimon Glass { 134b8893327SSimon Glass return serial_getc_dev(cur_dev); 135b8893327SSimon Glass } 136b8893327SSimon Glass 13757d92753SSimon Glass void serial_stdio_init(void) 13857d92753SSimon Glass { 13957d92753SSimon Glass } 14057d92753SSimon Glass 141b8893327SSimon Glass static void serial_stub_putc(struct stdio_dev *sdev, const char ch) 14257d92753SSimon Glass { 14357d92753SSimon Glass struct udevice *dev = sdev->priv; 14457d92753SSimon Glass 145b8893327SSimon Glass serial_putc_dev(dev, ch); 14657d92753SSimon Glass } 14757d92753SSimon Glass 14857d92753SSimon Glass void serial_stub_puts(struct stdio_dev *sdev, const char *str) 14957d92753SSimon Glass { 15057d92753SSimon Glass while (*str) 15157d92753SSimon Glass serial_stub_putc(sdev, *str++); 15257d92753SSimon Glass } 15357d92753SSimon Glass 15457d92753SSimon Glass int serial_stub_getc(struct stdio_dev *sdev) 15557d92753SSimon Glass { 15657d92753SSimon Glass struct udevice *dev = sdev->priv; 15757d92753SSimon Glass 158b8893327SSimon Glass return serial_getc_dev(dev); 15957d92753SSimon Glass } 16057d92753SSimon Glass 16157d92753SSimon Glass int serial_stub_tstc(struct stdio_dev *sdev) 16257d92753SSimon Glass { 16357d92753SSimon Glass struct udevice *dev = sdev->priv; 16457d92753SSimon Glass struct dm_serial_ops *ops = serial_get_ops(dev); 16557d92753SSimon Glass 16657d92753SSimon Glass if (ops->pending) 16757d92753SSimon Glass return ops->pending(dev, true); 16857d92753SSimon Glass 16957d92753SSimon Glass return 1; 17057d92753SSimon Glass } 17157d92753SSimon Glass 17257d92753SSimon Glass static int serial_post_probe(struct udevice *dev) 17357d92753SSimon Glass { 17457d92753SSimon Glass struct stdio_dev sdev; 17557d92753SSimon Glass struct dm_serial_ops *ops = serial_get_ops(dev); 17657d92753SSimon Glass struct serial_dev_priv *upriv = dev->uclass_priv; 17757d92753SSimon Glass int ret; 17857d92753SSimon Glass 17957d92753SSimon Glass /* Set the baud rate */ 18057d92753SSimon Glass if (ops->setbrg) { 18157d92753SSimon Glass ret = ops->setbrg(dev, gd->baudrate); 18257d92753SSimon Glass if (ret) 18357d92753SSimon Glass return ret; 18457d92753SSimon Glass } 18557d92753SSimon Glass 18657d92753SSimon Glass if (!(gd->flags & GD_FLG_RELOC)) 18757d92753SSimon Glass return 0; 18857d92753SSimon Glass 18957d92753SSimon Glass memset(&sdev, '\0', sizeof(sdev)); 19057d92753SSimon Glass 19157d92753SSimon Glass strncpy(sdev.name, dev->name, sizeof(sdev.name)); 19257d92753SSimon Glass sdev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT; 19357d92753SSimon Glass sdev.priv = dev; 19457d92753SSimon Glass sdev.putc = serial_stub_putc; 19557d92753SSimon Glass sdev.puts = serial_stub_puts; 19657d92753SSimon Glass sdev.getc = serial_stub_getc; 19757d92753SSimon Glass sdev.tstc = serial_stub_tstc; 19857d92753SSimon Glass stdio_register_dev(&sdev, &upriv->sdev); 19957d92753SSimon Glass 20057d92753SSimon Glass return 0; 20157d92753SSimon Glass } 20257d92753SSimon Glass 20357d92753SSimon Glass static int serial_pre_remove(struct udevice *dev) 20457d92753SSimon Glass { 20557d92753SSimon Glass #ifdef CONFIG_SYS_STDIO_DEREGISTER 20657d92753SSimon Glass struct serial_dev_priv *upriv = dev->uclass_priv; 20757d92753SSimon Glass 2084a74298cSHans de Goede if (stdio_deregister_dev(upriv->sdev, 0)) 20957d92753SSimon Glass return -EPERM; 21057d92753SSimon Glass #endif 21157d92753SSimon Glass 21257d92753SSimon Glass return 0; 21357d92753SSimon Glass } 21457d92753SSimon Glass 21557d92753SSimon Glass UCLASS_DRIVER(serial) = { 21657d92753SSimon Glass .id = UCLASS_SERIAL, 21757d92753SSimon Glass .name = "serial", 21857d92753SSimon Glass .post_probe = serial_post_probe, 21957d92753SSimon Glass .pre_remove = serial_pre_remove, 22057d92753SSimon Glass .per_device_auto_alloc_size = sizeof(struct serial_dev_priv), 22157d92753SSimon Glass }; 222