blob: f6ac3d228526a6cd59994e26f47deabb3a51cead [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass7accb6e2011-10-03 19:26:46 +00002/*
3 * Copyright (c) 2011 The Chromium OS Authors.
Simon Glass7accb6e2011-10-03 19:26:46 +00004 */
5
6/*
7 * This provide a test serial port. It provides an emulated serial port where
8 * a test program and read out the serial output and inject serial input for
9 * U-Boot.
10 */
11
12#include <common.h>
Joe Hershberger82a115f2018-07-02 20:06:49 -050013#include <console.h>
Simon Glass890fcef2014-09-04 16:27:27 -060014#include <dm.h>
Simon Glass7accb6e2011-10-03 19:26:46 +000015#include <os.h>
Marek Vasutcef46b72012-09-14 22:33:21 +020016#include <serial.h>
Simon Glass3ade5bc2016-01-18 19:52:25 -070017#include <video.h>
Simon Glass401d1c42020-10-30 21:38:53 -060018#include <asm/global_data.h>
Marek Vasutcef46b72012-09-14 22:33:21 +020019#include <linux/compiler.h>
Simon Glassbfae6cc2020-12-19 10:39:53 -070020#include <asm/serial.h>
Simon Glassffb87902014-02-27 13:26:22 -070021#include <asm/state.h>
Simon Glass7accb6e2011-10-03 19:26:46 +000022
Simon Glass890fcef2014-09-04 16:27:27 -060023DECLARE_GLOBAL_DATA_PTR;
24
Sean Anderson679190c2022-04-04 14:17:59 -040025static size_t _sandbox_serial_written = 1;
26static bool sandbox_serial_enabled = true;
27
28size_t sandbox_serial_written(void)
29{
30 return _sandbox_serial_written;
31}
32
33void sandbox_serial_endisable(bool enabled)
34{
35 sandbox_serial_enabled = enabled;
36}
37
Simon Glass72e98222014-09-04 16:27:28 -060038/**
39 * output_ansi_colour() - Output an ANSI colour code
40 *
41 * @colour: Colour to output (0-7)
42 */
43static void output_ansi_colour(int colour)
44{
45 char ansi_code[] = "\x1b[1;3Xm";
46
47 ansi_code[5] = '0' + colour;
48 os_write(1, ansi_code, sizeof(ansi_code) - 1);
49}
50
51static void output_ansi_reset(void)
52{
53 os_write(1, "\x1b[0m", 4);
54}
55
Simon Glass890fcef2014-09-04 16:27:27 -060056static int sandbox_serial_probe(struct udevice *dev)
Simon Glass7accb6e2011-10-03 19:26:46 +000057{
Simon Glassffb87902014-02-27 13:26:22 -070058 struct sandbox_state *state = state_get_current();
Simon Glass72e98222014-09-04 16:27:28 -060059 struct sandbox_serial_priv *priv = dev_get_priv(dev);
Simon Glassffb87902014-02-27 13:26:22 -070060
61 if (state->term_raw != STATE_TERM_COOKED)
62 os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
Simon Glass72e98222014-09-04 16:27:28 -060063 priv->start_of_line = 0;
64
Joe Hershberger82a115f2018-07-02 20:06:49 -050065 if (state->term_raw != STATE_TERM_RAW)
66 disable_ctrlc(1);
Simon Glass21f90752020-11-08 20:36:50 -070067 membuff_init(&priv->buf, priv->serial_buf, sizeof(priv->serial_buf));
Joe Hershberger82a115f2018-07-02 20:06:49 -050068
Simon Glass72e98222014-09-04 16:27:28 -060069 return 0;
70}
71
72static int sandbox_serial_remove(struct udevice *dev)
73{
Simon Glass0fd3d912020-12-22 19:30:28 -070074 struct sandbox_serial_plat *plat = dev_get_plat(dev);
Simon Glass72e98222014-09-04 16:27:28 -060075
76 if (plat->colour != -1)
77 output_ansi_reset();
Simon Glass890fcef2014-09-04 16:27:27 -060078
Simon Glass7accb6e2011-10-03 19:26:46 +000079 return 0;
80}
81
Sean Andersonefa51f22022-04-04 14:17:58 -040082static void sandbox_print_color(struct udevice *dev)
Simon Glass7accb6e2011-10-03 19:26:46 +000083{
Simon Glass72e98222014-09-04 16:27:28 -060084 struct sandbox_serial_priv *priv = dev_get_priv(dev);
Simon Glass0fd3d912020-12-22 19:30:28 -070085 struct sandbox_serial_plat *plat = dev_get_plat(dev);
Simon Glass72e98222014-09-04 16:27:28 -060086
Walter Lozanoe3e24702020-06-25 01:10:04 -030087 /* With of-platdata we don't real the colour correctly, so disable it */
88 if (!CONFIG_IS_ENABLED(OF_PLATDATA) && priv->start_of_line &&
89 plat->colour != -1) {
Simon Glass72e98222014-09-04 16:27:28 -060090 priv->start_of_line = false;
91 output_ansi_colour(plat->colour);
92 }
Sean Andersonefa51f22022-04-04 14:17:58 -040093}
Simon Glass72e98222014-09-04 16:27:28 -060094
Sean Andersonefa51f22022-04-04 14:17:58 -040095static int sandbox_serial_putc(struct udevice *dev, const char ch)
96{
97 struct sandbox_serial_priv *priv = dev_get_priv(dev);
98
Simon Glass72e98222014-09-04 16:27:28 -060099 if (ch == '\n')
100 priv->start_of_line = true;
Simon Glass7accb6e2011-10-03 19:26:46 +0000101
Sean Anderson679190c2022-04-04 14:17:59 -0400102 if (sandbox_serial_enabled) {
103 sandbox_print_color(dev);
104 os_write(1, &ch, 1);
105 }
106 _sandbox_serial_written += 1;
Simon Glass890fcef2014-09-04 16:27:27 -0600107 return 0;
Simon Glass7accb6e2011-10-03 19:26:46 +0000108}
109
Sean Andersonefa51f22022-04-04 14:17:58 -0400110static ssize_t sandbox_serial_puts(struct udevice *dev, const char *s,
111 size_t len)
112{
113 struct sandbox_serial_priv *priv = dev_get_priv(dev);
Sean Anderson679190c2022-04-04 14:17:59 -0400114 ssize_t ret;
Sean Andersonefa51f22022-04-04 14:17:58 -0400115
Andrew Scull337b26e2022-05-30 10:00:01 +0000116 if (len && s[len - 1] == '\n')
Sean Andersonefa51f22022-04-04 14:17:58 -0400117 priv->start_of_line = true;
118
Sean Anderson679190c2022-04-04 14:17:59 -0400119 if (sandbox_serial_enabled) {
120 sandbox_print_color(dev);
121 ret = os_write(1, s, len);
122 if (ret < 0)
123 return ret;
124 } else {
125 ret = len;
126 }
127 _sandbox_serial_written += ret;
128 return ret;
Sean Andersonefa51f22022-04-04 14:17:58 -0400129}
130
Simon Glass890fcef2014-09-04 16:27:27 -0600131static int sandbox_serial_pending(struct udevice *dev, bool input)
Simon Glass7accb6e2011-10-03 19:26:46 +0000132{
Simon Glass21f90752020-11-08 20:36:50 -0700133 struct sandbox_serial_priv *priv = dev_get_priv(dev);
Taylor Hutte1015502013-02-24 17:33:13 +0000134 ssize_t count;
Simon Glass21f90752020-11-08 20:36:50 -0700135 char *data;
136 int avail;
Taylor Hutte1015502013-02-24 17:33:13 +0000137
Simon Glass890fcef2014-09-04 16:27:27 -0600138 if (!input)
139 return 0;
140
Taylor Hutte1015502013-02-24 17:33:13 +0000141 os_usleep(100);
Simon Glassb86986c2022-10-18 07:46:31 -0600142 if (IS_ENABLED(CONFIG_VIDEO) && !IS_ENABLED(CONFIG_SPL_BUILD))
Simon Glassc5ea0162020-11-08 20:36:48 -0700143 video_sync_all();
Simon Glass21f90752020-11-08 20:36:50 -0700144 avail = membuff_putraw(&priv->buf, 100, false, &data);
145 if (!avail)
Taylor Hutte1015502013-02-24 17:33:13 +0000146 return 1; /* buffer full */
147
Simon Glass21f90752020-11-08 20:36:50 -0700148 count = os_read(0, data, avail);
149 if (count > 0)
150 membuff_putraw(&priv->buf, count, true, &data);
Simon Glass890fcef2014-09-04 16:27:27 -0600151
Simon Glass21f90752020-11-08 20:36:50 -0700152 return membuff_avail(&priv->buf);
Taylor Hutte1015502013-02-24 17:33:13 +0000153}
154
Simon Glass890fcef2014-09-04 16:27:27 -0600155static int sandbox_serial_getc(struct udevice *dev)
Taylor Hutte1015502013-02-24 17:33:13 +0000156{
Simon Glass21f90752020-11-08 20:36:50 -0700157 struct sandbox_serial_priv *priv = dev_get_priv(dev);
Taylor Hutte1015502013-02-24 17:33:13 +0000158
Simon Glass890fcef2014-09-04 16:27:27 -0600159 if (!sandbox_serial_pending(dev, true))
160 return -EAGAIN; /* buffer empty */
Taylor Hutte1015502013-02-24 17:33:13 +0000161
Simon Glass21f90752020-11-08 20:36:50 -0700162 return membuff_getbyte(&priv->buf);
Simon Glass7accb6e2011-10-03 19:26:46 +0000163}
Marek Vasutcef46b72012-09-14 22:33:21 +0200164
Simon Glassee441762018-10-01 11:55:15 -0600165#ifdef CONFIG_DEBUG_UART_SANDBOX
166
167#include <debug_uart.h>
168
169static inline void _debug_uart_init(void)
170{
171}
172
173static inline void _debug_uart_putc(int ch)
174{
175 os_putc(ch);
176}
177
178DEBUG_UART_FUNCS
179
180#endif /* CONFIG_DEBUG_UART_SANDBOX */
181
Andy Shevchenkoac7f5db2018-11-20 23:52:32 +0200182static int sandbox_serial_getconfig(struct udevice *dev, uint *serial_config)
183{
184 uint config = SERIAL_DEFAULT_CONFIG;
185
186 if (!serial_config)
187 return -EINVAL;
188
189 *serial_config = config;
190
191 return 0;
192}
193
Patrice Chotardd7c09682018-08-03 15:07:41 +0200194static int sandbox_serial_setconfig(struct udevice *dev, uint serial_config)
195{
196 u8 parity = SERIAL_GET_PARITY(serial_config);
197 u8 bits = SERIAL_GET_BITS(serial_config);
198 u8 stop = SERIAL_GET_STOP(serial_config);
199
200 if (bits != SERIAL_8_BITS || stop != SERIAL_ONE_STOP ||
201 parity != SERIAL_PAR_NONE)
202 return -ENOTSUPP; /* not supported in driver*/
203
204 return 0;
205}
206
Andy Shevchenkod5bb4f82018-11-20 23:52:33 +0200207static int sandbox_serial_getinfo(struct udevice *dev,
208 struct serial_device_info *serial_info)
209{
210 struct serial_device_info info = {
211 .type = SERIAL_CHIP_UNKNOWN,
212 .addr_space = SERIAL_ADDRESS_SPACE_IO,
213 .addr = SERIAL_DEFAULT_ADDRESS,
214 .reg_width = 1,
215 .reg_offset = 0,
216 .reg_shift = 0,
Andy Shevchenkobf4661bc2020-02-27 17:21:54 +0200217 .clock = SERIAL_DEFAULT_CLOCK,
Andy Shevchenkod5bb4f82018-11-20 23:52:33 +0200218 };
219
220 if (!serial_info)
221 return -EINVAL;
222
223 *serial_info = info;
224
225 return 0;
226}
227
Simon Glass72e98222014-09-04 16:27:28 -0600228static const char * const ansi_colour[] = {
229 "black", "red", "green", "yellow", "blue", "megenta", "cyan",
230 "white",
231};
232
Simon Glassd1998a92020-12-03 16:55:21 -0700233static int sandbox_serial_of_to_plat(struct udevice *dev)
Simon Glass72e98222014-09-04 16:27:28 -0600234{
Simon Glass0fd3d912020-12-22 19:30:28 -0700235 struct sandbox_serial_plat *plat = dev_get_plat(dev);
Simon Glass72e98222014-09-04 16:27:28 -0600236 const char *colour;
237 int i;
238
Simon Glassea147782019-09-25 08:55:53 -0600239 if (CONFIG_IS_ENABLED(OF_PLATDATA))
240 return 0;
Simon Glass72e98222014-09-04 16:27:28 -0600241 plat->colour = -1;
Simon Glass1bf0a402020-11-08 20:36:49 -0700242 colour = dev_read_string(dev, "sandbox,text-colour");
Simon Glass72e98222014-09-04 16:27:28 -0600243 if (colour) {
244 for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) {
245 if (!strcmp(colour, ansi_colour[i])) {
246 plat->colour = i;
247 break;
248 }
249 }
250 }
251
252 return 0;
253}
254
Simon Glass890fcef2014-09-04 16:27:27 -0600255static const struct dm_serial_ops sandbox_serial_ops = {
256 .putc = sandbox_serial_putc,
Sean Andersonefa51f22022-04-04 14:17:58 -0400257 .puts = sandbox_serial_puts,
Simon Glass890fcef2014-09-04 16:27:27 -0600258 .pending = sandbox_serial_pending,
259 .getc = sandbox_serial_getc,
Andy Shevchenkoac7f5db2018-11-20 23:52:32 +0200260 .getconfig = sandbox_serial_getconfig,
Patrice Chotardd7c09682018-08-03 15:07:41 +0200261 .setconfig = sandbox_serial_setconfig,
Andy Shevchenkod5bb4f82018-11-20 23:52:33 +0200262 .getinfo = sandbox_serial_getinfo,
Marek Vasutcef46b72012-09-14 22:33:21 +0200263};
264
Simon Glass890fcef2014-09-04 16:27:27 -0600265static const struct udevice_id sandbox_serial_ids[] = {
266 { .compatible = "sandbox,serial" },
267 { }
268};
Marek Vasutcef46b72012-09-14 22:33:21 +0200269
Walter Lozanoe3e24702020-06-25 01:10:04 -0300270U_BOOT_DRIVER(sandbox_serial) = {
271 .name = "sandbox_serial",
Simon Glass890fcef2014-09-04 16:27:27 -0600272 .id = UCLASS_SERIAL,
273 .of_match = sandbox_serial_ids,
Simon Glassd1998a92020-12-03 16:55:21 -0700274 .of_to_plat = sandbox_serial_of_to_plat,
Simon Glass8a8d24b2020-12-03 16:55:23 -0700275 .plat_auto = sizeof(struct sandbox_serial_plat),
Simon Glass41575d82020-12-03 16:55:17 -0700276 .priv_auto = sizeof(struct sandbox_serial_priv),
Simon Glass890fcef2014-09-04 16:27:27 -0600277 .probe = sandbox_serial_probe,
Simon Glass72e98222014-09-04 16:27:28 -0600278 .remove = sandbox_serial_remove,
Simon Glass890fcef2014-09-04 16:27:27 -0600279 .ops = &sandbox_serial_ops,
280 .flags = DM_FLAG_PRE_RELOC,
281};
282
Sean Andersoneaf73852023-10-14 16:47:46 -0400283#if CONFIG_IS_ENABLED(OF_REAL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
Simon Glass8a8d24b2020-12-03 16:55:23 -0700284static const struct sandbox_serial_plat platdata_non_fdt = {
Simon Glass72e98222014-09-04 16:27:28 -0600285 .colour = -1,
286};
287
Simon Glass20e442a2020-12-28 20:34:54 -0700288U_BOOT_DRVINFO(serial_sandbox_non_fdt) = {
Walter Lozanoe3e24702020-06-25 01:10:04 -0300289 .name = "sandbox_serial",
Simon Glasscaa4daa2020-12-03 16:55:18 -0700290 .plat = &platdata_non_fdt,
Simon Glass890fcef2014-09-04 16:27:27 -0600291};
Simon Glassc1473292020-10-03 11:31:23 -0600292#endif