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