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