xref: /rk3399_rockchip-uboot/drivers/serial/sandbox.c (revision 21342d4aed6c77a4aa7a5b2579b3c23e21aea31a)
17accb6eaSSimon Glass /*
27accb6eaSSimon Glass  * Copyright (c) 2011 The Chromium OS Authors.
37accb6eaSSimon Glass  *
41a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
57accb6eaSSimon Glass  */
67accb6eaSSimon Glass 
77accb6eaSSimon Glass /*
87accb6eaSSimon Glass  * This provide a test serial port. It provides an emulated serial port where
97accb6eaSSimon Glass  * a test program and read out the serial output and inject serial input for
107accb6eaSSimon Glass  * U-Boot.
117accb6eaSSimon Glass  */
127accb6eaSSimon Glass 
137accb6eaSSimon Glass #include <common.h>
14890fcefeSSimon Glass #include <dm.h>
15890fcefeSSimon Glass #include <fdtdec.h>
167d95f2a3SSimon Glass #include <lcd.h>
177accb6eaSSimon Glass #include <os.h>
18cef46b77SMarek Vasut #include <serial.h>
193ade5bc4SSimon Glass #include <video.h>
20cef46b77SMarek Vasut #include <linux/compiler.h>
21ffb87905SSimon Glass #include <asm/state.h>
227accb6eaSSimon Glass 
23890fcefeSSimon Glass DECLARE_GLOBAL_DATA_PTR;
24890fcefeSSimon Glass 
25e101550aSTaylor Hutt /*
26e101550aSTaylor Hutt  *
27e101550aSTaylor Hutt  *   serial_buf: A buffer that holds keyboard characters for the
28a187559eSBin Meng  *		 Sandbox U-Boot.
29e101550aSTaylor Hutt  *
30e101550aSTaylor Hutt  * invariants:
31e101550aSTaylor Hutt  *   serial_buf_write		 == serial_buf_read -> empty buffer
32e101550aSTaylor Hutt  *   (serial_buf_write + 1) % 16 == serial_buf_read -> full buffer
33e101550aSTaylor Hutt  */
34e101550aSTaylor Hutt static char serial_buf[16];
35e101550aSTaylor Hutt static unsigned int serial_buf_write;
36e101550aSTaylor Hutt static unsigned int serial_buf_read;
37e101550aSTaylor Hutt 
3872e98228SSimon Glass struct sandbox_serial_platdata {
3972e98228SSimon Glass 	int colour;	/* Text colour to use for output, -1 for none */
4072e98228SSimon Glass };
4172e98228SSimon Glass 
4272e98228SSimon Glass struct sandbox_serial_priv {
4372e98228SSimon Glass 	bool start_of_line;
4472e98228SSimon Glass };
4572e98228SSimon Glass 
4672e98228SSimon Glass /**
4772e98228SSimon Glass  * output_ansi_colour() - Output an ANSI colour code
4872e98228SSimon Glass  *
4972e98228SSimon Glass  * @colour: Colour to output (0-7)
5072e98228SSimon Glass  */
output_ansi_colour(int colour)5172e98228SSimon Glass static void output_ansi_colour(int colour)
5272e98228SSimon Glass {
5372e98228SSimon Glass 	char ansi_code[] = "\x1b[1;3Xm";
5472e98228SSimon Glass 
5572e98228SSimon Glass 	ansi_code[5] = '0' + colour;
5672e98228SSimon Glass 	os_write(1, ansi_code, sizeof(ansi_code) - 1);
5772e98228SSimon Glass }
5872e98228SSimon Glass 
output_ansi_reset(void)5972e98228SSimon Glass static void output_ansi_reset(void)
6072e98228SSimon Glass {
6172e98228SSimon Glass 	os_write(1, "\x1b[0m", 4);
6272e98228SSimon Glass }
6372e98228SSimon Glass 
sandbox_serial_probe(struct udevice * dev)64890fcefeSSimon Glass static int sandbox_serial_probe(struct udevice *dev)
657accb6eaSSimon Glass {
66ffb87905SSimon Glass 	struct sandbox_state *state = state_get_current();
6772e98228SSimon Glass 	struct sandbox_serial_priv *priv = dev_get_priv(dev);
68ffb87905SSimon Glass 
69ffb87905SSimon Glass 	if (state->term_raw != STATE_TERM_COOKED)
70ffb87905SSimon Glass 		os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
7172e98228SSimon Glass 	priv->start_of_line = 0;
7272e98228SSimon Glass 
7372e98228SSimon Glass 	return 0;
7472e98228SSimon Glass }
7572e98228SSimon Glass 
sandbox_serial_remove(struct udevice * dev)7672e98228SSimon Glass static int sandbox_serial_remove(struct udevice *dev)
7772e98228SSimon Glass {
7872e98228SSimon Glass 	struct sandbox_serial_platdata *plat = dev->platdata;
7972e98228SSimon Glass 
8072e98228SSimon Glass 	if (plat->colour != -1)
8172e98228SSimon Glass 		output_ansi_reset();
82890fcefeSSimon Glass 
837accb6eaSSimon Glass 	return 0;
847accb6eaSSimon Glass }
857accb6eaSSimon Glass 
sandbox_serial_putc(struct udevice * dev,const char ch)86890fcefeSSimon Glass static int sandbox_serial_putc(struct udevice *dev, const char ch)
877accb6eaSSimon Glass {
8872e98228SSimon Glass 	struct sandbox_serial_priv *priv = dev_get_priv(dev);
8972e98228SSimon Glass 	struct sandbox_serial_platdata *plat = dev->platdata;
9072e98228SSimon Glass 
9172e98228SSimon Glass 	if (priv->start_of_line && plat->colour != -1) {
9272e98228SSimon Glass 		priv->start_of_line = false;
9372e98228SSimon Glass 		output_ansi_colour(plat->colour);
9472e98228SSimon Glass 	}
9572e98228SSimon Glass 
967accb6eaSSimon Glass 	os_write(1, &ch, 1);
9772e98228SSimon Glass 	if (ch == '\n')
9872e98228SSimon Glass 		priv->start_of_line = true;
997accb6eaSSimon Glass 
100890fcefeSSimon Glass 	return 0;
1017accb6eaSSimon Glass }
1027accb6eaSSimon Glass 
increment_buffer_index(unsigned int index)103e101550aSTaylor Hutt static unsigned int increment_buffer_index(unsigned int index)
1047accb6eaSSimon Glass {
105e101550aSTaylor Hutt 	return (index + 1) % ARRAY_SIZE(serial_buf);
1067accb6eaSSimon Glass }
1077accb6eaSSimon Glass 
sandbox_serial_pending(struct udevice * dev,bool input)108890fcefeSSimon Glass static int sandbox_serial_pending(struct udevice *dev, bool input)
1097accb6eaSSimon Glass {
110e101550aSTaylor Hutt 	const unsigned int next_index =
111e101550aSTaylor Hutt 		increment_buffer_index(serial_buf_write);
112e101550aSTaylor Hutt 	ssize_t count;
113e101550aSTaylor Hutt 
114890fcefeSSimon Glass 	if (!input)
115890fcefeSSimon Glass 		return 0;
116890fcefeSSimon Glass 
117e101550aSTaylor Hutt 	os_usleep(100);
1180110f509SSimon Glass #ifndef CONFIG_SPL_BUILD
1193ade5bc4SSimon Glass 	video_sync_all();
1200110f509SSimon Glass #endif
121e101550aSTaylor Hutt 	if (next_index == serial_buf_read)
122e101550aSTaylor Hutt 		return 1;	/* buffer full */
123e101550aSTaylor Hutt 
124e101550aSTaylor Hutt 	count = os_read_no_block(0, &serial_buf[serial_buf_write], 1);
125e101550aSTaylor Hutt 	if (count == 1)
126e101550aSTaylor Hutt 		serial_buf_write = next_index;
127890fcefeSSimon Glass 
128e101550aSTaylor Hutt 	return serial_buf_write != serial_buf_read;
129e101550aSTaylor Hutt }
130e101550aSTaylor Hutt 
sandbox_serial_getc(struct udevice * dev)131890fcefeSSimon Glass static int sandbox_serial_getc(struct udevice *dev)
132e101550aSTaylor Hutt {
133e101550aSTaylor Hutt 	int result;
134e101550aSTaylor Hutt 
135890fcefeSSimon Glass 	if (!sandbox_serial_pending(dev, true))
136890fcefeSSimon Glass 		return -EAGAIN;	/* buffer empty */
137e101550aSTaylor Hutt 
138e101550aSTaylor Hutt 	result = serial_buf[serial_buf_read];
139e101550aSTaylor Hutt 	serial_buf_read = increment_buffer_index(serial_buf_read);
140e101550aSTaylor Hutt 	return result;
1417accb6eaSSimon Glass }
142cef46b77SMarek Vasut 
14372e98228SSimon Glass static const char * const ansi_colour[] = {
14472e98228SSimon Glass 	"black", "red", "green", "yellow", "blue", "megenta", "cyan",
14572e98228SSimon Glass 	"white",
14672e98228SSimon Glass };
14772e98228SSimon Glass 
sandbox_serial_ofdata_to_platdata(struct udevice * dev)14872e98228SSimon Glass static int sandbox_serial_ofdata_to_platdata(struct udevice *dev)
14972e98228SSimon Glass {
15072e98228SSimon Glass 	struct sandbox_serial_platdata *plat = dev->platdata;
15172e98228SSimon Glass 	const char *colour;
15272e98228SSimon Glass 	int i;
15372e98228SSimon Glass 
15472e98228SSimon Glass 	plat->colour = -1;
155*e160f7d4SSimon Glass 	colour = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
15672e98228SSimon Glass 			     "sandbox,text-colour", NULL);
15772e98228SSimon Glass 	if (colour) {
15872e98228SSimon Glass 		for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) {
15972e98228SSimon Glass 			if (!strcmp(colour, ansi_colour[i])) {
16072e98228SSimon Glass 				plat->colour = i;
16172e98228SSimon Glass 				break;
16272e98228SSimon Glass 			}
16372e98228SSimon Glass 		}
16472e98228SSimon Glass 	}
16572e98228SSimon Glass 
16672e98228SSimon Glass 	return 0;
16772e98228SSimon Glass }
16872e98228SSimon Glass 
169890fcefeSSimon Glass static const struct dm_serial_ops sandbox_serial_ops = {
170cef46b77SMarek Vasut 	.putc = sandbox_serial_putc,
171890fcefeSSimon Glass 	.pending = sandbox_serial_pending,
172cef46b77SMarek Vasut 	.getc = sandbox_serial_getc,
173cef46b77SMarek Vasut };
174cef46b77SMarek Vasut 
175890fcefeSSimon Glass static const struct udevice_id sandbox_serial_ids[] = {
176890fcefeSSimon Glass 	{ .compatible = "sandbox,serial" },
177890fcefeSSimon Glass 	{ }
178890fcefeSSimon Glass };
179cef46b77SMarek Vasut 
180890fcefeSSimon Glass U_BOOT_DRIVER(serial_sandbox) = {
181890fcefeSSimon Glass 	.name	= "serial_sandbox",
182890fcefeSSimon Glass 	.id	= UCLASS_SERIAL,
183890fcefeSSimon Glass 	.of_match = sandbox_serial_ids,
18472e98228SSimon Glass 	.ofdata_to_platdata = sandbox_serial_ofdata_to_platdata,
18572e98228SSimon Glass 	.platdata_auto_alloc_size = sizeof(struct sandbox_serial_platdata),
18672e98228SSimon Glass 	.priv_auto_alloc_size = sizeof(struct sandbox_serial_priv),
187890fcefeSSimon Glass 	.probe = sandbox_serial_probe,
18872e98228SSimon Glass 	.remove = sandbox_serial_remove,
189890fcefeSSimon Glass 	.ops	= &sandbox_serial_ops,
190890fcefeSSimon Glass 	.flags = DM_FLAG_PRE_RELOC,
191890fcefeSSimon Glass };
192890fcefeSSimon Glass 
19372e98228SSimon Glass static const struct sandbox_serial_platdata platdata_non_fdt = {
19472e98228SSimon Glass 	.colour = -1,
19572e98228SSimon Glass };
19672e98228SSimon Glass 
197890fcefeSSimon Glass U_BOOT_DEVICE(serial_sandbox_non_fdt) = {
198890fcefeSSimon Glass 	.name = "serial_sandbox",
19972e98228SSimon Glass 	.platdata = &platdata_non_fdt,
200890fcefeSSimon Glass };
201