blob: 77a1558db688f15d7a231a50f0fbc47e7729e210 [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 Glass54209572020-11-08 20:36:50 -0700141 avail = membuff_putraw(&priv->buf, 100, false, &data);
142 if (!avail)
Taylor Hutt868aa3a2013-02-24 17:33:13 +0000143 return 1; /* buffer full */
144
Simon Glass54209572020-11-08 20:36:50 -0700145 count = os_read(0, data, avail);
146 if (count > 0)
147 membuff_putraw(&priv->buf, count, true, &data);
Simon Glasse5870692014-09-04 16:27:27 -0600148
Simon Glass54209572020-11-08 20:36:50 -0700149 return membuff_avail(&priv->buf);
Simon Glass479349a2011-10-03 19:26:46 +0000150}
151
Simon Glasse5870692014-09-04 16:27:27 -0600152static int sandbox_serial_getc(struct udevice *dev)
Simon Glass479349a2011-10-03 19:26:46 +0000153{
Simon Glass54209572020-11-08 20:36:50 -0700154 struct sandbox_serial_priv *priv = dev_get_priv(dev);
Taylor Hutt868aa3a2013-02-24 17:33:13 +0000155
Simon Glasse5870692014-09-04 16:27:27 -0600156 if (!sandbox_serial_pending(dev, true))
157 return -EAGAIN; /* buffer empty */
Taylor Hutt868aa3a2013-02-24 17:33:13 +0000158
Simon Glass54209572020-11-08 20:36:50 -0700159 return membuff_getbyte(&priv->buf);
Simon Glass479349a2011-10-03 19:26:46 +0000160}
Marek Vasut289c3002012-09-14 22:33:21 +0200161
Simon Glasse3057f32018-10-01 11:55:15 -0600162#ifdef CONFIG_DEBUG_UART_SANDBOX
163
164#include <debug_uart.h>
165
166static inline void _debug_uart_init(void)
167{
168}
169
170static inline void _debug_uart_putc(int ch)
171{
172 os_putc(ch);
173}
174
175DEBUG_UART_FUNCS
176
177#endif /* CONFIG_DEBUG_UART_SANDBOX */
178
Andy Shevchenko08e98792018-11-20 23:52:32 +0200179static int sandbox_serial_getconfig(struct udevice *dev, uint *serial_config)
180{
181 uint config = SERIAL_DEFAULT_CONFIG;
182
183 if (!serial_config)
184 return -EINVAL;
185
186 *serial_config = config;
187
188 return 0;
189}
190
Patrice Chotard70ed0ea2018-08-03 15:07:41 +0200191static int sandbox_serial_setconfig(struct udevice *dev, uint serial_config)
192{
193 u8 parity = SERIAL_GET_PARITY(serial_config);
194 u8 bits = SERIAL_GET_BITS(serial_config);
195 u8 stop = SERIAL_GET_STOP(serial_config);
196
197 if (bits != SERIAL_8_BITS || stop != SERIAL_ONE_STOP ||
198 parity != SERIAL_PAR_NONE)
199 return -ENOTSUPP; /* not supported in driver*/
200
201 return 0;
202}
203
Andy Shevchenko44f21da2018-11-20 23:52:33 +0200204static int sandbox_serial_getinfo(struct udevice *dev,
205 struct serial_device_info *serial_info)
206{
207 struct serial_device_info info = {
208 .type = SERIAL_CHIP_UNKNOWN,
209 .addr_space = SERIAL_ADDRESS_SPACE_IO,
210 .addr = SERIAL_DEFAULT_ADDRESS,
211 .reg_width = 1,
212 .reg_offset = 0,
213 .reg_shift = 0,
Andy Shevchenko106930e2020-02-27 17:21:54 +0200214 .clock = SERIAL_DEFAULT_CLOCK,
Andy Shevchenko44f21da2018-11-20 23:52:33 +0200215 };
216
217 if (!serial_info)
218 return -EINVAL;
219
220 *serial_info = info;
221
222 return 0;
223}
224
Simon Glass1a823a92014-09-04 16:27:28 -0600225static const char * const ansi_colour[] = {
226 "black", "red", "green", "yellow", "blue", "megenta", "cyan",
227 "white",
228};
229
Simon Glassaad29ae2020-12-03 16:55:21 -0700230static int sandbox_serial_of_to_plat(struct udevice *dev)
Simon Glass1a823a92014-09-04 16:27:28 -0600231{
Simon Glass95588622020-12-22 19:30:28 -0700232 struct sandbox_serial_plat *plat = dev_get_plat(dev);
Simon Glass1a823a92014-09-04 16:27:28 -0600233 const char *colour;
234 int i;
235
Simon Glassa91e48b2019-09-25 08:55:53 -0600236 if (CONFIG_IS_ENABLED(OF_PLATDATA))
237 return 0;
Simon Glass1a823a92014-09-04 16:27:28 -0600238 plat->colour = -1;
Simon Glassfb6268d2020-11-08 20:36:49 -0700239 colour = dev_read_string(dev, "sandbox,text-colour");
Simon Glass1a823a92014-09-04 16:27:28 -0600240 if (colour) {
241 for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) {
242 if (!strcmp(colour, ansi_colour[i])) {
243 plat->colour = i;
244 break;
245 }
246 }
247 }
248
249 return 0;
250}
251
Simon Glasse5870692014-09-04 16:27:27 -0600252static const struct dm_serial_ops sandbox_serial_ops = {
253 .putc = sandbox_serial_putc,
Sean Anderson85898852022-04-04 14:17:58 -0400254 .puts = sandbox_serial_puts,
Simon Glasse5870692014-09-04 16:27:27 -0600255 .pending = sandbox_serial_pending,
256 .getc = sandbox_serial_getc,
Andy Shevchenko08e98792018-11-20 23:52:32 +0200257 .getconfig = sandbox_serial_getconfig,
Patrice Chotard70ed0ea2018-08-03 15:07:41 +0200258 .setconfig = sandbox_serial_setconfig,
Andy Shevchenko44f21da2018-11-20 23:52:33 +0200259 .getinfo = sandbox_serial_getinfo,
Marek Vasut289c3002012-09-14 22:33:21 +0200260};
261
Simon Glasse5870692014-09-04 16:27:27 -0600262static const struct udevice_id sandbox_serial_ids[] = {
263 { .compatible = "sandbox,serial" },
264 { }
265};
Marek Vasut289c3002012-09-14 22:33:21 +0200266
Walter Lozano2901ac62020-06-25 01:10:04 -0300267U_BOOT_DRIVER(sandbox_serial) = {
268 .name = "sandbox_serial",
Simon Glasse5870692014-09-04 16:27:27 -0600269 .id = UCLASS_SERIAL,
270 .of_match = sandbox_serial_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700271 .of_to_plat = sandbox_serial_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700272 .plat_auto = sizeof(struct sandbox_serial_plat),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700273 .priv_auto = sizeof(struct sandbox_serial_priv),
Simon Glasse5870692014-09-04 16:27:27 -0600274 .probe = sandbox_serial_probe,
Simon Glass1a823a92014-09-04 16:27:28 -0600275 .remove = sandbox_serial_remove,
Simon Glasse5870692014-09-04 16:27:27 -0600276 .ops = &sandbox_serial_ops,
277 .flags = DM_FLAG_PRE_RELOC,
278};
279
Sean Anderson7bf2f8c2023-10-14 16:47:46 -0400280#if CONFIG_IS_ENABLED(OF_REAL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
Simon Glassb75b15b2020-12-03 16:55:23 -0700281static const struct sandbox_serial_plat platdata_non_fdt = {
Simon Glass1a823a92014-09-04 16:27:28 -0600282 .colour = -1,
283};
284
Simon Glass1d8364a2020-12-28 20:34:54 -0700285U_BOOT_DRVINFO(serial_sandbox_non_fdt) = {
Walter Lozano2901ac62020-06-25 01:10:04 -0300286 .name = "sandbox_serial",
Simon Glass71fa5b42020-12-03 16:55:18 -0700287 .plat = &platdata_non_fdt,
Simon Glasse5870692014-09-04 16:27:27 -0600288};
Simon Glasscb90bd32020-10-03 11:31:23 -0600289#endif