On Fri, Jul 31, 2015 at 11:31 PM, Simon Glass <[email protected]> wrote: > Add a serial driver which makes use of EFI's console in/out service. > > Signed-off-by: Simon Glass <[email protected]> > --- > > Changes in v2: > - Add a comment about special handling for backspace > - Add a comment as to why debug_uart_init() is empty > - Drop unused DECLARE_GLOBAL_DATA_PTR > - Rename CONFIG_ARCH_EFI to CONFIG_EFI_APP > - Rename EFI debug UART to EFI_CONSOLE > - Replace serial_s5p with serial_efi > > drivers/serial/Kconfig | 9 +++ > drivers/serial/Makefile | 1 + > drivers/serial/serial_efi.c | 157 > ++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 167 insertions(+) > create mode 100644 drivers/serial/serial_efi.c > > diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig > index 4829284..bfbf58f 100644 > --- a/drivers/serial/Kconfig > +++ b/drivers/serial/Kconfig > @@ -44,6 +44,15 @@ config DEBUG_UART_NS16550 > will need to provide parameters to make this work. The driver will > be available until the real driver model serial is running. > > +config DEBUG_EFI_CONSOLE > + bool "EFI" > + depends on EFI_APP > + help > + Select this to enable a debug console which calls back to EFI to > + output to the console. This can be useful for early debugging of > + U-Boot when running on top of EFI (Extensive Firmware Interface). > + This is a type of BIOS used by PCs. > + > endchoice > > config DEBUG_UART_BASE > diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile > index d183eed..1d1f036 100644 > --- a/drivers/serial/Makefile > +++ b/drivers/serial/Makefile > @@ -21,6 +21,7 @@ obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o > obj-$(CONFIG_ARM_DCC) += arm_dcc.o > obj-$(CONFIG_ATMEL_USART) += atmel_usart.o > obj-$(CONFIG_DW_SERIAL) += serial_dw.o > +obj-$(CONFIG_EFI_APP) += serial_efi.o > obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o > obj-$(CONFIG_MCFUART) += mcfuart.o > obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o > diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c > new file mode 100644 > index 0000000..cf57d89 > --- /dev/null > +++ b/drivers/serial/serial_efi.c > @@ -0,0 +1,157 @@ > +/* > + * Copyright (c) 2015 Google, Inc > + * Written by Simon Glass <[email protected]> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <debug_uart.h> > +#include <dm.h> > +#include <efi.h> > +#include <efi_api.h> > +#include <errno.h> > +#include <fdtdec.h> > +#include <linux/compiler.h> > +#include <asm/io.h> > +#include <serial.h> > + > +/* Information about the efi console */ > +struct serial_efi_priv { > + struct efi_simple_input_interface *con_in; > + struct efi_simple_text_output_protocol *con_out; > + struct efi_input_key key; > + bool have_key; > +}; > + > +int serial_efi_setbrg(struct udevice *dev, int baudrate) > +{ > + return 0; > +} > + > +static int serial_efi_get_key(struct serial_efi_priv *priv) > +{ > + int ret; > + > + if (priv->have_key) > + return 0; > + ret = priv->con_in->read_key_stroke(priv->con_in, &priv->key); > + if (ret == EFI_NOT_READY) > + return -EAGAIN; > + else if (ret != EFI_SUCCESS) > + return -EIO; > + > + priv->have_key = true; > + > + return 0; > +} > + > +static int serial_efi_getc(struct udevice *dev) > +{ > + struct serial_efi_priv *priv = dev_get_priv(dev); > + int ret, ch; > + > + ret = serial_efi_get_key(priv); > + if (ret) > + return ret; > + > + priv->have_key = false; > + ch = priv->key.unicode_char; > + > + /* > + * Unicode char 8 (for backspace) is never returned. Instead we get a > + * key scan code of 8. Handle this so that backspace works correctly > + * in the U-Boot command line. > + */ > + if (!ch && priv->key.scan_code == 8) > + ch = 8; > + debug(" [%x %x %x] ", ch, priv->key.unicode_char, > priv->key.scan_code); > + > + return ch; > +} > + > +static int serial_efi_putc(struct udevice *dev, const char ch) > +{ > + struct serial_efi_priv *priv = dev_get_priv(dev); > + uint16_t ucode[2]; > + int ret; > + > + ucode[0] = ch; > + ucode[1] = '\0'; > + ret = priv->con_out->output_string(priv->con_out, ucode); > + if (ret) > + return -EIO; > + > + return 0; > +} > + > +static int serial_efi_pending(struct udevice *dev, bool input) > +{ > + struct serial_efi_priv *priv = dev_get_priv(dev); > + int ret; > + > + /* We assume that EFI will stall if its output buffer fills up */ > + if (!input) > + return 0; > + > + ret = serial_efi_get_key(priv); > + if (ret == -EAGAIN) > + return 0; > + else if (ret) > + return ret; > + > + return 1; > +} > + > +/* > + * There is nothing to init here since the EFI console is already running by > + * the time we enter U-Boot. > + */ > +void debug_uart_init(void) > +{ > +} > + > +static inline void _debug_uart_putc(int ch) > +{ > + struct efi_system_table *sys_table = efi_get_sys_table(); > + uint16_t ucode[2]; > + > + ucode[0] = ch; > + ucode[1] = '\0'; > + sys_table->con_out->output_string(sys_table->con_out, ucode); > +} > + > +DEBUG_UART_FUNCS > + > +static int serial_efi_probe(struct udevice *dev) > +{ > + struct efi_system_table *table = efi_get_sys_table(); > + struct serial_efi_priv *priv = dev_get_priv(dev); > + > + priv->con_in = table->con_in; > + priv->con_out = table->con_out; > + > + return 0; > +} > + > +static const struct dm_serial_ops serial_efi_ops = { > + .putc = serial_efi_putc, > + .getc = serial_efi_getc, > + .pending = serial_efi_pending, > + .setbrg = serial_efi_setbrg, > +}; > + > +static const struct udevice_id serial_efi_ids[] = { > + { .compatible = "efi,uart" }, > + { } > +}; > + > +U_BOOT_DRIVER(serial_efi) = { > + .name = "serial_efi", > + .id = UCLASS_SERIAL, > + .of_match = serial_efi_ids, > + .priv_auto_alloc_size = sizeof(struct serial_efi_priv), > + .probe = serial_efi_probe, > + .ops = &serial_efi_ops, > + .flags = DM_FLAG_PRE_RELOC, > +}; > --
Reviewed-by: Bin Meng <[email protected]> Tested on Intel Crown Bay and QEMU Tested-by: Bin Meng <[email protected]> _______________________________________________ U-Boot mailing list [email protected] http://lists.denx.de/mailman/listinfo/u-boot

