Message ID | 1437580180-6405-21-git-send-email-sjg@chromium.org |
---|---|
State | Superseded |
Delegated to: | Simon Glass |
Headers | show |
Hi Simon, On Wed, Jul 22, 2015 at 11:49 PM, Simon Glass <sjg@chromium.org> wrote: > Add a serial driver which makes use of EFI's console in/out service. > > Signed-off-by: Simon Glass <sjg@chromium.org> > --- > > drivers/serial/Kconfig | 8 +++ > drivers/serial/Makefile | 1 + > drivers/serial/serial_efi.c | 149 ++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 158 insertions(+) > create mode 100644 drivers/serial/serial_efi.c > > diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig > index 4829284..f874837 100644 > --- a/drivers/serial/Kconfig > +++ b/drivers/serial/Kconfig > @@ -44,6 +44,14 @@ 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_UART_EFI This driver looks like a normal serial driver, except one debug uart api _debug_uart_putc(). Also it can not only support UART, but also support any console input/output devices that EFI supports. Should we rename it to: EFI_CONSOLE? > + bool "EFI" depends on EFI_APP? > + help > + Select this to enable a debug UART 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..92c3808 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_ARCH_EFI) += 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..15e541b > --- /dev/null > +++ b/drivers/serial/serial_efi.c > @@ -0,0 +1,149 @@ > +/* > + * Copyright (c) 2015 Google, Inc > + * Written by Simon Glass <sjg@chromium.org> > + * > + * 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> > + > +DECLARE_GLOBAL_DATA_PTR; Is this needed? I don't see gd is referenced. > + > +/* 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; What is 8 here? Can we add a comment here? > + 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; > +} > + > +void debug_uart_init(void) > +{ > +} Can we add come comments here to mention nothing needs to be done here for EFI? > + > +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_s5p) = { Should be serial_efi. > + .name = "serial_s5p", The same here. > + .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, > +}; > -- Regards, Bin
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 4829284..f874837 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -44,6 +44,14 @@ 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_UART_EFI + bool "EFI" + help + Select this to enable a debug UART 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..92c3808 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_ARCH_EFI) += 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..15e541b --- /dev/null +++ b/drivers/serial/serial_efi.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * 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> + +DECLARE_GLOBAL_DATA_PTR; + +/* 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; + 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; +} + +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_s5p) = { + .name = "serial_s5p", + .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, +};
Add a serial driver which makes use of EFI's console in/out service. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/serial/Kconfig | 8 +++ drivers/serial/Makefile | 1 + drivers/serial/serial_efi.c | 149 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 drivers/serial/serial_efi.c