summaryrefslogtreecommitdiffstats
path: root/drivers/serial
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2017-03-13 08:16:43 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2017-03-13 08:16:43 +0100
commit93c55ce0986a47f5b6774a81443e9b3a15fc727c (patch)
tree06860f7e46e7a08b7ecd08ba105a8101a900f037 /drivers/serial
parent12b6a916d608200a511611c4dfbe84cf4cde8add (diff)
parent534c1fac3e684eefcd9d0372dbf26745a84719ad (diff)
downloadbarebox-93c55ce0986a47f5b6774a81443e9b3a15fc727c.tar.gz
Merge branch 'for-next/efi'
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/Kconfig6
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/efi-stdio.c2
-rw-r--r--drivers/serial/serial_efi.c221
4 files changed, 228 insertions, 2 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 4eab437..cfddc2e 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
@@ -46,7 +50,7 @@ config DRIVER_SERIAL_LINUX_CONSOLE
bool "linux console driver"
config DRIVER_SERIAL_EFI_STDIO
- depends on ARCH_EFI
+ depends on EFI_BOOTUP
bool "EFI stdio driver"
config DRIVER_SERIAL_MPC5XXX
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 7d1bae1..3d9f735 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/efi-stdio.c b/drivers/serial/efi-stdio.c
index 5ab9173..0703f72 100644
--- a/drivers/serial/efi-stdio.c
+++ b/drivers/serial/efi-stdio.c
@@ -25,7 +25,7 @@
#include <efi.h>
#include <readkey.h>
#include <linux/ctype.h>
-#include <mach/efi.h>
+#include <efi/efi.h>
#define EFI_SHIFT_STATE_VALID 0x80000000
#define EFI_RIGHT_CONTROL_PRESSED 0x00000004
diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c
new file mode 100644
index 0000000..f0a2b22
--- /dev/null
+++ b/drivers/serial/serial_efi.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2017 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2 Only
+ */
+
+#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);