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