blob: ec0068e33d34696db5416cf2912ec0f9f5387d1b [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass479349a2011-10-03 19:26:46 +00002/*
3 * Copyright (c) 2011 The Chromium OS Authors.
Simon Glass479349a2011-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
Joe Hershbergerb3eff9b2018-07-02 20:06:49 -050012#include <console.h>
Simon Glasse5870692014-09-04 16:27:27 -060013#include <dm.h>
Simon Glass479349a2011-10-03 19:26:46 +000014#include <os.h>
Marek Vasut289c3002012-09-14 22:33:21 +020015#include <serial.h>
Simon Glass38a2ae22016-01-18 19:52:25 -070016#include <video.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060017#include <asm/global_data.h>
Marek Vasut289c3002012-09-14 22:33:21 +020018#include <linux/compiler.h>
Simon Glass2bfb7ef2020-12-19 10:39:53 -070019#include <asm/serial.h>
Simon Glass678ef472014-02-27 13:26:22 -070020#include <asm/state.h>
Simon Glass479349a2011-10-03 19:26:46 +000021
Simon Glasse5870692014-09-04 16:27:27 -060022DECLARE_GLOBAL_DATA_PTR;
23
Sean Andersonb2711612022-04-04 14:17:59 -040024static size_t _sandbox_serial_written = 1;
25static bool sandbox_serial_enabled = true;
26
27size_t sandbox_serial_written(void)
28{
29 return _sandbox_serial_written;
30}
31
32void sandbox_serial_endisable(bool enabled)
33{
34 sandbox_serial_enabled = enabled;
35}
36
Simon Glass1a823a92014-09-04 16:27:28 -060037/**
38 * output_ansi_colour() - Output an ANSI colour code
39 *
40 * @colour: Colour to output (0-7)
41 */
42static void output_ansi_colour(int colour)
43{
44 char ansi_code[] = "\x1b[1;3Xm";
45
46 ansi_code[5] = '0' + colour;
47 os_write(1, ansi_code, sizeof(ansi_code) - 1);
48}
49
50static void output_ansi_reset(void)
51{
52 os_write(1, "\x1b[0m", 4);
53}
54
Simon Glasse5870692014-09-04 16:27:27 -060055static int sandbox_serial_probe(struct udevice *dev)
Simon Glass479349a2011-10-03 19:26:46 +000056{
Simon Glass678ef472014-02-27 13:26:22 -070057 struct sandbox_state *state = state_get_current();
Simon Glass1a823a92014-09-04 16:27:28 -060058 struct sandbox_serial_priv *priv = dev_get_priv(dev);
Simon Glass678ef472014-02-27 13:26:22 -070059
60 if (state->term_raw != STATE_TERM_COOKED)
61 os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
Simon Glass1a823a92014-09-04 16:27:28 -060062 priv->start_of_line = 0;
Simon Glass479349a2011-10-03 19:26:46 +000063
Joe Hershbergerb3eff9b2018-07-02 20:06:49 -050064 if (state->term_raw != STATE_TERM_RAW)
65 disable_ctrlc(1);
Simon Glass54209572020-11-08 20:36:50 -070066 membuff_init(&priv->buf, priv->serial_buf, sizeof(priv->serial_buf));
Joe Hershbergerb3eff9b2018-07-02 20:06:49 -050067
Simon Glasse5870692014-09-04 16:27:27 -060068 return 0;
Simon Glass479349a2011-10-03 19:26:46 +000069}
70
Simon Glass1a823a92014-09-04 16:27:28 -060071static int sandbox_serial_remove(struct udevice *dev)
72{
Simon Glass95588622020-12-22 19:30:28 -070073 struct sandbox_serial_plat *plat = dev_get_plat(dev);
Simon Glass1a823a92014-09-04 16:27:28 -060074
75 if (plat->colour != -1)
76 output_ansi_reset();
77
78 return 0;
79}
80
Sean Anderson85898852022-04-04 14:17:58 -040081static void sandbox_print_color(struct udevice *dev)
Simon Glass479349a2011-10-03 19:26:46 +000082{
Simon Glass1a823a92014-09-04 16:27:28 -060083 struct sandbox_serial_priv *priv = dev_get_priv(dev);
Simon Glass95588622020-12-22 19:30:28 -070084 struct sandbox_serial_plat *plat = dev_get_plat(dev);
Simon Glass1a823a92014-09-04 16:27:28 -060085
Walter Lozano2901ac62020-06-25 01:10:04 -030086 /* With of-platdata we don't real the colour correctly, so disable it */
87 if (!CONFIG_IS_ENABLED(OF_PLATDATA) && priv->start_of_line &&
88 plat->colour != -1) {
Simon Glass1a823a92014-09-04 16:27:28 -060089 priv->start_of_line = false;
90 output_ansi_colour(plat->colour);
91 }
Sean Anderson85898852022-04-04 14:17:58 -040092}
Simon Glass1a823a92014-09-04 16:27:28 -060093
Sean Anderson85898852022-04-04 14:17:58 -040094static int sandbox_serial_putc(struct udevice *dev, const char ch)
95{
96 struct sandbox_serial_priv *priv = dev_get_priv(dev);
97
Simon Glass1a823a92014-09-04 16:27:28 -060098 if (ch == '\n')
99 priv->start_of_line = true;
Simon Glass479349a2011-10-03 19:26:46 +0000100
Sean Andersonb2711612022-04-04 14:17:59 -0400101 if (sandbox_serial_enabled) {
102 sandbox_print_color(dev);
103 os_write(1, &ch, 1);
104 }
105 _sandbox_serial_written += 1;
Simon Glasse5870692014-09-04 16:27:27 -0600106 return 0;
Simon Glass479349a2011-10-03 19:26:46 +0000107}
108
Sean Anderson85898852022-04-04 14:17:58 -0400109static ssize_t sandbox_serial_puts(struct udevice *dev, const char *s,
110 size_t len)
111{
112 struct sandbox_serial_priv *priv = dev_get_priv(dev);
Sean Andersonb2711612022-04-04 14:17:59 -0400113 ssize_t ret;
Sean Anderson85898852022-04-04 14:17:58 -0400114
Andrew Scull18065772022-05-30 10:00:01 +0000115 if (len && s[len - 1] == '\n')
Sean Anderson85898852022-04-04 14:17:58 -0400116 priv->start_of_line = true;
117
Sean Andersonb2711612022-04-04 14:17:59 -0400118 if (sandbox_serial_enabled) {
119 sandbox_print_color(dev);
120 ret = os_write(1, s, len);
121 if (ret < 0)
122 return ret;
123 } else {
124 ret = len;
125 }
126 _sandbox_serial_written += ret;
127 return ret;
Sean Anderson85898852022-04-04 14:17:58 -0400128}
129
Simon Glasse5870692014-09-04 16:27:27 -0600130static int sandbox_serial_pending(struct udevice *dev, bool input)
Simon Glass479349a2011-10-03 19:26:46 +0000131{
Simon Glass54209572020-11-08 20:36:50 -0700132 struct sandbox_serial_priv *priv = dev_get_priv(dev);
Mike Frysingerd174fd92011-10-26 00:21:01 +0000133 ssize_t count;
Simon Glass54209572020-11-08 20:36:50 -0700134 char *data;
135 int avail;
Simon Glass479349a2011-10-03 19:26:46 +0000136
Simon Glasse5870692014-09-04 16:27:27 -0600137 if (!input)
138 return 0;
139
Taylor Hutt868aa3a2013-02-24 17:33:13 +0000140 os_usleep(100);
Simon Glass52cb5042022-10-18 07:46:31 -0600141 if (IS_ENABLED(CONFIG_VIDEO) && !IS_ENABLED(CONFIG_SPL_BUILD))
Simon Glass0b8ffa72020-11-08 20:36:48 -0700142 video_sync_all();
Simon Glass54209572020-11-08 20:36:50 -0700143 avail = membuff_putraw(&priv->buf, 100, false, &data);
144 if (!avail)
Taylor Hutt868aa3a2013-02-24 17:33:13 +0000145 return 1; /* buffer full */
146
Simon Glass54209572020-11-08 20:36:50 -0700147 count = os_read(0, data, avail);
148 if (count > 0)
149 membuff_putraw(&priv->buf, count, true, &data);
Simon Glasse5870692014-09-04 16:27:27 -0600150
Simon Glass54209572020-11-08 20:36:50 -0700151 return membuff_avail(&priv->buf);
Simon Glass479349a2011-10-03 19:26:46 +0000152}
153
Simon Glasse5870692014-09-04 16:27:27 -0600154static int sandbox_serial_getc(struct udevice *dev)
Simon Glass479349a2011-10-03 19:26:46 +0000155{
Simon Glass54209572020-11-08 20:36:50 -0700156 struct sandbox_serial_priv *priv = dev_get_priv(dev);
Taylor Hutt868aa3a2013-02-24 17:33:13 +0000157
Simon Glasse5870692014-09-04 16:27:27 -0600158 if (!sandbox_serial_pending(dev, true))
159 return -EAGAIN; /* buffer empty */
Taylor Hutt868aa3a2013-02-24 17:33:13 +0000160
Simon Glass54209572020-11-08 20:36:50 -0700161 return membuff_getbyte(&priv->buf);
Simon Glass479349a2011-10-03 19:26:46 +0000162}
Marek Vasut289c3002012-09-14 22:33:21 +0200163
Simon Glasse3057f32018-10-01 11:55:15 -0600164#ifdef CONFIG_DEBUG_UART_SANDBOX
165
166#include <debug_uart.h>
167
168static inline void _debug_uart_init(void)
169{
170}
171
172static inline void _debug_uart_putc(int ch)
173{
174 os_putc(ch);
175}
176
177DEBUG_UART_FUNCS
178
179#endif /* CONFIG_DEBUG_UART_SANDBOX */
180
Andy Shevchenko08e98792018-11-20 23:52:32 +0200181static int sandbox_serial_getconfig(struct udevice *dev, uint *serial_config)
182{
183 uint config = SERIAL_DEFAULT_CONFIG;
184
185 if (!serial_config)
186 return -EINVAL;
187
188 *serial_config = config;
189
190 return 0;
191}
192
Patrice Chotard70ed0ea2018-08-03 15:07:41 +0200193static int sandbox_serial_setconfig(struct udevice *dev, uint serial_config)
194{
195 u8 parity = SERIAL_GET_PARITY(serial_config);
196 u8 bits = SERIAL_GET_BITS(serial_config);
197 u8 stop = SERIAL_GET_STOP(serial_config);
198
199 if (bits != SERIAL_8_BITS || stop != SERIAL_ONE_STOP ||
200 parity != SERIAL_PAR_NONE)
201 return -ENOTSUPP; /* not supported in driver*/
202
203 return 0;
204}
205
Andy Shevchenko44f21da2018-11-20 23:52:33 +0200206static int sandbox_serial_getinfo(struct udevice *dev,
207 struct serial_device_info *serial_info)
208{
209 struct serial_device_info info = {
210 .type = SERIAL_CHIP_UNKNOWN,
211 .addr_space = SERIAL_ADDRESS_SPACE_IO,
212 .addr = SERIAL_DEFAULT_ADDRESS,
213 .reg_width = 1,
214 .reg_offset = 0,
215 .reg_shift = 0,
Andy Shevchenko106930e2020-02-27 17:21:54 +0200216 .clock = SERIAL_DEFAULT_CLOCK,
Andy Shevchenko44f21da2018-11-20 23:52:33 +0200217 };
218
219 if (!serial_info)
220 return -EINVAL;
221
222 *serial_info = info;
223
224 return 0;
225}
226
Simon Glass1a823a92014-09-04 16:27:28 -0600227static const char * const ansi_colour[] = {
228 "black", "red", "green", "yellow", "blue", "megenta", "cyan",
229 "white",
230};
231
Simon Glassaad29ae2020-12-03 16:55:21 -0700232static int sandbox_serial_of_to_plat(struct udevice *dev)
Simon Glass1a823a92014-09-04 16:27:28 -0600233{
Simon Glass95588622020-12-22 19:30:28 -0700234 struct sandbox_serial_plat *plat = dev_get_plat(dev);
Simon Glass1a823a92014-09-04 16:27:28 -0600235 const char *colour;
236 int i;
237
Simon Glassa91e48b2019-09-25 08:55:53 -0600238 if (CONFIG_IS_ENABLED(OF_PLATDATA))
239 return 0;
Simon Glass1a823a92014-09-04 16:27:28 -0600240 plat->colour = -1;
Simon Glassfb6268d2020-11-08 20:36:49 -0700241 colour = dev_read_string(dev, "sandbox,text-colour");
Simon Glass1a823a92014-09-04 16:27:28 -0600242 if (colour) {
243 for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) {
244 if (!strcmp(colour, ansi_colour[i])) {
245 plat->colour = i;
246 break;
247 }
248 }
249 }
250
251 return 0;
252}
253
Simon Glasse5870692014-09-04 16:27:27 -0600254static const struct dm_serial_ops sandbox_serial_ops = {
255 .putc = sandbox_serial_putc,
Sean Anderson85898852022-04-04 14:17:58 -0400256 .puts = sandbox_serial_puts,
Simon Glasse5870692014-09-04 16:27:27 -0600257 .pending = sandbox_serial_pending,
258 .getc = sandbox_serial_getc,
Andy Shevchenko08e98792018-11-20 23:52:32 +0200259 .getconfig = sandbox_serial_getconfig,
Patrice Chotard70ed0ea2018-08-03 15:07:41 +0200260 .setconfig = sandbox_serial_setconfig,
Andy Shevchenko44f21da2018-11-20 23:52:33 +0200261 .getinfo = sandbox_serial_getinfo,
Marek Vasut289c3002012-09-14 22:33:21 +0200262};
263
Simon Glasse5870692014-09-04 16:27:27 -0600264static const struct udevice_id sandbox_serial_ids[] = {
265 { .compatible = "sandbox,serial" },
266 { }
267};
Marek Vasut289c3002012-09-14 22:33:21 +0200268
Walter Lozano2901ac62020-06-25 01:10:04 -0300269U_BOOT_DRIVER(sandbox_serial) = {
270 .name = "sandbox_serial",
Simon Glasse5870692014-09-04 16:27:27 -0600271 .id = UCLASS_SERIAL,
272 .of_match = sandbox_serial_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700273 .of_to_plat = sandbox_serial_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700274 .plat_auto = sizeof(struct sandbox_serial_plat),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700275 .priv_auto = sizeof(struct sandbox_serial_priv),
Simon Glasse5870692014-09-04 16:27:27 -0600276 .probe = sandbox_serial_probe,
Simon Glass1a823a92014-09-04 16:27:28 -0600277 .remove = sandbox_serial_remove,
Simon Glasse5870692014-09-04 16:27:27 -0600278 .ops = &sandbox_serial_ops,
279 .flags = DM_FLAG_PRE_RELOC,
280};
281
Sean Anderson7bf2f8c2023-10-14 16:47:46 -0400282#if CONFIG_IS_ENABLED(OF_REAL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
Simon Glassb75b15b2020-12-03 16:55:23 -0700283static const struct sandbox_serial_plat platdata_non_fdt = {
Simon Glass1a823a92014-09-04 16:27:28 -0600284 .colour = -1,
285};
286
Simon Glass1d8364a2020-12-28 20:34:54 -0700287U_BOOT_DRVINFO(serial_sandbox_non_fdt) = {
Walter Lozano2901ac62020-06-25 01:10:04 -0300288 .name = "sandbox_serial",
Simon Glass71fa5b42020-12-03 16:55:18 -0700289 .plat = &platdata_non_fdt,
Simon Glasse5870692014-09-04 16:27:27 -0600290};
Simon Glasscb90bd32020-10-03 11:31:23 -0600291#endif