1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2011 The Chromium OS Authors.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun /*
8*4882a593Smuzhiyun * This provide a test serial port. It provides an emulated serial port where
9*4882a593Smuzhiyun * a test program and read out the serial output and inject serial input for
10*4882a593Smuzhiyun * U-Boot.
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <common.h>
14*4882a593Smuzhiyun #include <dm.h>
15*4882a593Smuzhiyun #include <fdtdec.h>
16*4882a593Smuzhiyun #include <lcd.h>
17*4882a593Smuzhiyun #include <os.h>
18*4882a593Smuzhiyun #include <serial.h>
19*4882a593Smuzhiyun #include <video.h>
20*4882a593Smuzhiyun #include <linux/compiler.h>
21*4882a593Smuzhiyun #include <asm/state.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun /*
26*4882a593Smuzhiyun *
27*4882a593Smuzhiyun * serial_buf: A buffer that holds keyboard characters for the
28*4882a593Smuzhiyun * Sandbox U-Boot.
29*4882a593Smuzhiyun *
30*4882a593Smuzhiyun * invariants:
31*4882a593Smuzhiyun * serial_buf_write == serial_buf_read -> empty buffer
32*4882a593Smuzhiyun * (serial_buf_write + 1) % 16 == serial_buf_read -> full buffer
33*4882a593Smuzhiyun */
34*4882a593Smuzhiyun static char serial_buf[16];
35*4882a593Smuzhiyun static unsigned int serial_buf_write;
36*4882a593Smuzhiyun static unsigned int serial_buf_read;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun struct sandbox_serial_platdata {
39*4882a593Smuzhiyun int colour; /* Text colour to use for output, -1 for none */
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun struct sandbox_serial_priv {
43*4882a593Smuzhiyun bool start_of_line;
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /**
47*4882a593Smuzhiyun * output_ansi_colour() - Output an ANSI colour code
48*4882a593Smuzhiyun *
49*4882a593Smuzhiyun * @colour: Colour to output (0-7)
50*4882a593Smuzhiyun */
output_ansi_colour(int colour)51*4882a593Smuzhiyun static void output_ansi_colour(int colour)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun char ansi_code[] = "\x1b[1;3Xm";
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun ansi_code[5] = '0' + colour;
56*4882a593Smuzhiyun os_write(1, ansi_code, sizeof(ansi_code) - 1);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
output_ansi_reset(void)59*4882a593Smuzhiyun static void output_ansi_reset(void)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun os_write(1, "\x1b[0m", 4);
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
sandbox_serial_probe(struct udevice * dev)64*4882a593Smuzhiyun static int sandbox_serial_probe(struct udevice *dev)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun struct sandbox_state *state = state_get_current();
67*4882a593Smuzhiyun struct sandbox_serial_priv *priv = dev_get_priv(dev);
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun if (state->term_raw != STATE_TERM_COOKED)
70*4882a593Smuzhiyun os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
71*4882a593Smuzhiyun priv->start_of_line = 0;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun return 0;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
sandbox_serial_remove(struct udevice * dev)76*4882a593Smuzhiyun static int sandbox_serial_remove(struct udevice *dev)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun struct sandbox_serial_platdata *plat = dev->platdata;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun if (plat->colour != -1)
81*4882a593Smuzhiyun output_ansi_reset();
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun return 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
sandbox_serial_putc(struct udevice * dev,const char ch)86*4882a593Smuzhiyun static int sandbox_serial_putc(struct udevice *dev, const char ch)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun struct sandbox_serial_priv *priv = dev_get_priv(dev);
89*4882a593Smuzhiyun struct sandbox_serial_platdata *plat = dev->platdata;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (priv->start_of_line && plat->colour != -1) {
92*4882a593Smuzhiyun priv->start_of_line = false;
93*4882a593Smuzhiyun output_ansi_colour(plat->colour);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun os_write(1, &ch, 1);
97*4882a593Smuzhiyun if (ch == '\n')
98*4882a593Smuzhiyun priv->start_of_line = true;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
increment_buffer_index(unsigned int index)103*4882a593Smuzhiyun static unsigned int increment_buffer_index(unsigned int index)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun return (index + 1) % ARRAY_SIZE(serial_buf);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
sandbox_serial_pending(struct udevice * dev,bool input)108*4882a593Smuzhiyun static int sandbox_serial_pending(struct udevice *dev, bool input)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun const unsigned int next_index =
111*4882a593Smuzhiyun increment_buffer_index(serial_buf_write);
112*4882a593Smuzhiyun ssize_t count;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun if (!input)
115*4882a593Smuzhiyun return 0;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun os_usleep(100);
118*4882a593Smuzhiyun #ifndef CONFIG_SPL_BUILD
119*4882a593Smuzhiyun video_sync_all();
120*4882a593Smuzhiyun #endif
121*4882a593Smuzhiyun if (next_index == serial_buf_read)
122*4882a593Smuzhiyun return 1; /* buffer full */
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun count = os_read_no_block(0, &serial_buf[serial_buf_write], 1);
125*4882a593Smuzhiyun if (count == 1)
126*4882a593Smuzhiyun serial_buf_write = next_index;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun return serial_buf_write != serial_buf_read;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
sandbox_serial_getc(struct udevice * dev)131*4882a593Smuzhiyun static int sandbox_serial_getc(struct udevice *dev)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun int result;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun if (!sandbox_serial_pending(dev, true))
136*4882a593Smuzhiyun return -EAGAIN; /* buffer empty */
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun result = serial_buf[serial_buf_read];
139*4882a593Smuzhiyun serial_buf_read = increment_buffer_index(serial_buf_read);
140*4882a593Smuzhiyun return result;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun static const char * const ansi_colour[] = {
144*4882a593Smuzhiyun "black", "red", "green", "yellow", "blue", "megenta", "cyan",
145*4882a593Smuzhiyun "white",
146*4882a593Smuzhiyun };
147*4882a593Smuzhiyun
sandbox_serial_ofdata_to_platdata(struct udevice * dev)148*4882a593Smuzhiyun static int sandbox_serial_ofdata_to_platdata(struct udevice *dev)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun struct sandbox_serial_platdata *plat = dev->platdata;
151*4882a593Smuzhiyun const char *colour;
152*4882a593Smuzhiyun int i;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun plat->colour = -1;
155*4882a593Smuzhiyun colour = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
156*4882a593Smuzhiyun "sandbox,text-colour", NULL);
157*4882a593Smuzhiyun if (colour) {
158*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) {
159*4882a593Smuzhiyun if (!strcmp(colour, ansi_colour[i])) {
160*4882a593Smuzhiyun plat->colour = i;
161*4882a593Smuzhiyun break;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun return 0;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun static const struct dm_serial_ops sandbox_serial_ops = {
170*4882a593Smuzhiyun .putc = sandbox_serial_putc,
171*4882a593Smuzhiyun .pending = sandbox_serial_pending,
172*4882a593Smuzhiyun .getc = sandbox_serial_getc,
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun static const struct udevice_id sandbox_serial_ids[] = {
176*4882a593Smuzhiyun { .compatible = "sandbox,serial" },
177*4882a593Smuzhiyun { }
178*4882a593Smuzhiyun };
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun U_BOOT_DRIVER(serial_sandbox) = {
181*4882a593Smuzhiyun .name = "serial_sandbox",
182*4882a593Smuzhiyun .id = UCLASS_SERIAL,
183*4882a593Smuzhiyun .of_match = sandbox_serial_ids,
184*4882a593Smuzhiyun .ofdata_to_platdata = sandbox_serial_ofdata_to_platdata,
185*4882a593Smuzhiyun .platdata_auto_alloc_size = sizeof(struct sandbox_serial_platdata),
186*4882a593Smuzhiyun .priv_auto_alloc_size = sizeof(struct sandbox_serial_priv),
187*4882a593Smuzhiyun .probe = sandbox_serial_probe,
188*4882a593Smuzhiyun .remove = sandbox_serial_remove,
189*4882a593Smuzhiyun .ops = &sandbox_serial_ops,
190*4882a593Smuzhiyun .flags = DM_FLAG_PRE_RELOC,
191*4882a593Smuzhiyun };
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun static const struct sandbox_serial_platdata platdata_non_fdt = {
194*4882a593Smuzhiyun .colour = -1,
195*4882a593Smuzhiyun };
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun U_BOOT_DEVICE(serial_sandbox_non_fdt) = {
198*4882a593Smuzhiyun .name = "serial_sandbox",
199*4882a593Smuzhiyun .platdata = &platdata_non_fdt,
200*4882a593Smuzhiyun };
201