So now we can stop to use the efi-stdio as this driver print on the Framebuffer and the serial at the same time. This is specially usefull if we want to use the framebuffer via efi-gop for something else. Do not forget to disable the efi-stdio device before enabling the console otherwise you will get double printing. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@xxxxxxxxxxxx> --- drivers/serial/Kconfig | 4 + drivers/serial/Makefile | 1 + drivers/serial/serial_efi.c | 241 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 drivers/serial/serial_efi.c diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ced30530a..cfddc2ee9 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -21,6 +21,10 @@ config DRIVER_SERIAL_AR933X If you have an Atheros AR933X SOC based board and want to use the built-in UART of the SoC, say Y to this option. +config DRIVER_SERIAL_EFI + bool "EFI serial" + depends on EFI_BOOTUP + config DRIVER_SERIAL_IMX depends on ARCH_IMX default y diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 7d1bae195..3d9f735ed 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_DRIVER_SERIAL_ARM_DCC) += arm_dcc.o obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o obj-$(CONFIG_DRIVER_SERIAL_AR933X) += serial_ar933x.o +obj-$(CONFIG_DRIVER_SERIAL_EFI) += serial_efi.o obj-$(CONFIG_DRIVER_SERIAL_IMX) += serial_imx.o obj-$(CONFIG_DRIVER_SERIAL_STM378X) += stm-serial.o obj-$(CONFIG_DRIVER_SERIAL_ATMEL) += atmel.o diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c new file mode 100644 index 000000000..35387bfd5 --- /dev/null +++ b/drivers/serial/serial_efi.c @@ -0,0 +1,241 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@xxxxxxxxxxxxx. + * + * (C) Copyright 2004 + * ARM Ltd. + * Philippe Robin, <philippe.robin@xxxxxxx> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */ + +#include <common.h> +#include <driver.h> +#include <init.h> +#include <malloc.h> +#include <efi.h> +#include <efi/efi.h> +#include <efi/efi-device.h> + +// +// define for Control bits, grouped by read only, write only, and read write +// +// +// Read Only +// +#define EFI_SERIAL_CLEAR_TO_SEND 0x00000010 +#define EFI_SERIAL_DATA_SET_READY 0x00000020 +#define EFI_SERIAL_RING_INDICATE 0x00000040 +#define EFI_SERIAL_CARRIER_DETECT 0x00000080 +#define EFI_SERIAL_INPUT_BUFFER_EMPTY 0x00000100 +#define EFI_SERIAL_OUTPUT_BUFFER_EMPTY 0x00000200 + +// +// Write Only +// +#define EFI_SERIAL_REQUEST_TO_SEND 0x00000002 +#define EFI_SERIAL_DATA_TERMINAL_READY 0x00000001 + +// +// Read Write +// +#define EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE 0x00001000 +#define EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE 0x00002000 +#define EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE 0x00004000 + +typedef enum { + DefaultParity, + NoParity, + EvenParity, + OddParity, + MarkParity, + SpaceParity +} efi_parity_type; + +typedef enum { + DefaultStopBits, + OneStopBit, + OneFiveStopBits, + TwoStopBits +} efi_stop_bits_type; + +struct efi_serial_io_mode { + uint32_t controlmask; + uint32_t timeout; + uint64_t baudrate; + uint32_t receivefifodepth; + uint32_t databits; + uint32_t parity; + uint32_t stopbits; +}; + +struct efi_serial_io_protocol { + uint32_t revision; + + efi_status_t (EFIAPI *reset) (struct efi_serial_io_protocol *This); + efi_status_t (EFIAPI *set_attributes) (struct efi_serial_io_protocol *This, + uint64_t baudrate, uint32_t receivefifodepth, + uint32_t timeout, efi_parity_type parity, + uint8_t databits, efi_stop_bits_type stopbits); + efi_status_t (EFIAPI *setcontrol) (struct efi_serial_io_protocol *This, + uint32_t control); + efi_status_t (EFIAPI *getcontrol) (struct efi_serial_io_protocol *This, + uint32_t *control); + efi_status_t (EFIAPI *write) (struct efi_serial_io_protocol *This, + unsigned long *buffersize, void *buffer); + efi_status_t (EFIAPI *read) (struct efi_serial_io_protocol *This, + unsigned long *buffersize, void *buffer); + + struct efi_serial_io_mode *mode; +}; + +/* + * We wrap our port structure around the generic console_device. + */ +struct efi_serial_port { + struct efi_serial_io_protocol *serial; + struct console_device uart; /* uart */ + struct efi_device *efidev; +}; + +static inline struct efi_serial_port * +to_efi_serial_port(struct console_device *uart) +{ + return container_of(uart, struct efi_serial_port, uart); +} + +static int efi_serial_setbaudrate(struct console_device *cdev, int baudrate) +{ + struct efi_serial_port *uart = to_efi_serial_port(cdev); + struct efi_serial_io_protocol *serial = uart->serial; + efi_status_t efiret; + + efiret = serial->set_attributes(serial, baudrate, 0, 0, NoParity, 8, + OneStopBit); + if (EFI_ERROR(efiret)) + return -efi_errno(efiret); + + return 0; +} + +static void efi_serial_putc(struct console_device *cdev, char c) +{ + struct efi_serial_port *uart = to_efi_serial_port(cdev); + struct efi_serial_io_protocol *serial = uart->serial; + uint32_t control; + efi_status_t efiret; + unsigned long buffersize = sizeof(char); + + do { + efiret = serial->getcontrol(serial, &control); + if (EFI_ERROR(efiret)) + return; + + } while(!(control & EFI_SERIAL_CLEAR_TO_SEND)); + + serial->write(serial, &buffersize, &c); +} + +static int efi_serial_puts(struct console_device *cdev, const char *s) +{ + struct efi_serial_port *uart = to_efi_serial_port(cdev); + struct efi_serial_io_protocol *serial = uart->serial; + uint32_t control; + efi_status_t efiret; + unsigned long buffersize = strlen(s) * sizeof(char); + + do { + efiret = serial->getcontrol(serial, &control); + if (EFI_ERROR(efiret)) + return 0; + + } while(!(control & EFI_SERIAL_CLEAR_TO_SEND)); + + serial->write(serial, &buffersize, (void*)s); + + return strlen(s); +} + +static int efi_serial_getc(struct console_device *cdev) +{ + struct efi_serial_port *uart = to_efi_serial_port(cdev); + struct efi_serial_io_protocol *serial = uart->serial; + uint32_t control; + efi_status_t efiret; + unsigned long buffersize = sizeof(char); + char c; + + do { + efiret = serial->getcontrol(serial, &control); + if (EFI_ERROR(efiret)) + return (int)-1; + + } while(!(control & EFI_SERIAL_DATA_SET_READY)); + + serial->read(serial, &buffersize, &c); + + return (int)c; +} + +static int efi_serial_tstc(struct console_device *cdev) +{ + struct efi_serial_port *uart = to_efi_serial_port(cdev); + struct efi_serial_io_protocol *serial = uart->serial; + uint32_t control; + efi_status_t efiret; + + efiret = serial->getcontrol(serial, &control); + if (EFI_ERROR(efiret)) + return 0; + + return !(control & EFI_SERIAL_INPUT_BUFFER_EMPTY); +} + +static int efi_serial_probe(struct efi_device *efidev) +{ + struct efi_serial_port *uart; + struct console_device *cdev; + + uart = xzalloc(sizeof(struct efi_serial_port)); + + cdev = &uart->uart; + cdev->dev = &efidev->dev; + cdev->tstc = efi_serial_tstc; + cdev->putc = efi_serial_putc; + cdev->puts = efi_serial_puts; + cdev->getc = efi_serial_getc; + cdev->setbrg = efi_serial_setbaudrate; + + uart->serial = efidev->protocol; + + uart->serial->reset(uart->serial); + + /* Enable UART */ + + console_register(cdev); + + return 0; +} + +static struct efi_driver efi_serial_driver = { + .driver = { + .name = "efi-serial", + }, + .probe = efi_serial_probe, + .guid = EFI_SERIAL_IO_PROTOCOL_GUID, +}; +device_efi_driver(efi_serial_driver); -- 2.11.0 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox