uboot/drivers/serial/serial_efi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2015 Google, Inc
   4 * Written by Simon Glass <sjg@chromium.org>
   5 */
   6
   7#include <common.h>
   8#include <debug_uart.h>
   9#include <dm.h>
  10#include <efi.h>
  11#include <efi_api.h>
  12#include <errno.h>
  13#include <fdtdec.h>
  14#include <linux/compiler.h>
  15#include <asm/io.h>
  16#include <serial.h>
  17
  18/* Information about the efi console */
  19struct serial_efi_priv {
  20        struct efi_simple_text_input_protocol *con_in;
  21        struct efi_simple_text_output_protocol *con_out;
  22        struct efi_input_key key;
  23        bool have_key;
  24};
  25
  26int serial_efi_setbrg(struct udevice *dev, int baudrate)
  27{
  28        return 0;
  29}
  30
  31static int serial_efi_get_key(struct serial_efi_priv *priv)
  32{
  33        int ret;
  34
  35        if (priv->have_key)
  36                return 0;
  37        ret = priv->con_in->read_key_stroke(priv->con_in, &priv->key);
  38        if (ret == EFI_NOT_READY)
  39                return -EAGAIN;
  40        else if (ret != EFI_SUCCESS)
  41                return -EIO;
  42
  43        priv->have_key = true;
  44
  45        return 0;
  46}
  47
  48static int serial_efi_getc(struct udevice *dev)
  49{
  50        struct serial_efi_priv *priv = dev_get_priv(dev);
  51        int ret, ch;
  52
  53        ret = serial_efi_get_key(priv);
  54        if (ret)
  55                return ret;
  56
  57        priv->have_key = false;
  58        ch = priv->key.unicode_char;
  59
  60        /*
  61         * Unicode char 8 (for backspace) is never returned. Instead we get a
  62         * key scan code of 8. Handle this so that backspace works correctly
  63         * in the U-Boot command line.
  64         */
  65        if (!ch && priv->key.scan_code == 8)
  66                ch = 8;
  67        debug(" [%x %x %x] ", ch, priv->key.unicode_char, priv->key.scan_code);
  68
  69        return ch;
  70}
  71
  72static int serial_efi_putc(struct udevice *dev, const char ch)
  73{
  74        struct serial_efi_priv *priv = dev_get_priv(dev);
  75        uint16_t ucode[2];
  76        int ret;
  77
  78        ucode[0] = ch;
  79        ucode[1] = '\0';
  80        ret = priv->con_out->output_string(priv->con_out, ucode);
  81        if (ret)
  82                return -EIO;
  83
  84        return 0;
  85}
  86
  87static int serial_efi_pending(struct udevice *dev, bool input)
  88{
  89        struct serial_efi_priv *priv = dev_get_priv(dev);
  90        int ret;
  91
  92        /* We assume that EFI will stall if its output buffer fills up */
  93        if (!input)
  94                return 0;
  95
  96        ret = serial_efi_get_key(priv);
  97        if (ret == -EAGAIN)
  98                return 0;
  99        else if (ret)
 100                return ret;
 101
 102        return 1;
 103}
 104
 105/*
 106 * There is nothing to init here since the EFI console is already running by
 107 * the time we enter U-Boot.
 108 */
 109static inline void _debug_uart_init(void)
 110{
 111}
 112
 113static inline void _debug_uart_putc(int ch)
 114{
 115        struct efi_system_table *sys_table = efi_get_sys_table();
 116        uint16_t ucode[2];
 117
 118        ucode[0] = ch;
 119        ucode[1] = '\0';
 120        sys_table->con_out->output_string(sys_table->con_out, ucode);
 121}
 122
 123DEBUG_UART_FUNCS
 124
 125static int serial_efi_probe(struct udevice *dev)
 126{
 127        struct efi_system_table *table = efi_get_sys_table();
 128        struct serial_efi_priv *priv = dev_get_priv(dev);
 129
 130        priv->con_in = table->con_in;
 131        priv->con_out = table->con_out;
 132
 133        return 0;
 134}
 135
 136static const struct dm_serial_ops serial_efi_ops = {
 137        .putc = serial_efi_putc,
 138        .getc = serial_efi_getc,
 139        .pending = serial_efi_pending,
 140        .setbrg = serial_efi_setbrg,
 141};
 142
 143static const struct udevice_id serial_efi_ids[] = {
 144        { .compatible = "efi,uart" },
 145        { }
 146};
 147
 148U_BOOT_DRIVER(serial_efi) = {
 149        .name   = "serial_efi",
 150        .id     = UCLASS_SERIAL,
 151        .of_match = serial_efi_ids,
 152        .priv_auto_alloc_size = sizeof(struct serial_efi_priv),
 153        .probe = serial_efi_probe,
 154        .ops    = &serial_efi_ops,
 155};
 156