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> 19*3ade5bc4SSimon 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 28e101550aSTaylor Hutt * 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 */ 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 5972e98228SSimon Glass static void output_ansi_reset(void) 6072e98228SSimon Glass { 6172e98228SSimon Glass os_write(1, "\x1b[0m", 4); 6272e98228SSimon Glass } 6372e98228SSimon Glass 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 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 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 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 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); 118*3ade5bc4SSimon Glass video_sync_all(); 119e101550aSTaylor Hutt if (next_index == serial_buf_read) 120e101550aSTaylor Hutt return 1; /* buffer full */ 121e101550aSTaylor Hutt 122e101550aSTaylor Hutt count = os_read_no_block(0, &serial_buf[serial_buf_write], 1); 123e101550aSTaylor Hutt if (count == 1) 124e101550aSTaylor Hutt serial_buf_write = next_index; 125890fcefeSSimon Glass 126e101550aSTaylor Hutt return serial_buf_write != serial_buf_read; 127e101550aSTaylor Hutt } 128e101550aSTaylor Hutt 129890fcefeSSimon Glass static int sandbox_serial_getc(struct udevice *dev) 130e101550aSTaylor Hutt { 131e101550aSTaylor Hutt int result; 132e101550aSTaylor Hutt 133890fcefeSSimon Glass if (!sandbox_serial_pending(dev, true)) 134890fcefeSSimon Glass return -EAGAIN; /* buffer empty */ 135e101550aSTaylor Hutt 136e101550aSTaylor Hutt result = serial_buf[serial_buf_read]; 137e101550aSTaylor Hutt serial_buf_read = increment_buffer_index(serial_buf_read); 138e101550aSTaylor Hutt return result; 1397accb6eaSSimon Glass } 140cef46b77SMarek Vasut 14172e98228SSimon Glass static const char * const ansi_colour[] = { 14272e98228SSimon Glass "black", "red", "green", "yellow", "blue", "megenta", "cyan", 14372e98228SSimon Glass "white", 14472e98228SSimon Glass }; 14572e98228SSimon Glass 14672e98228SSimon Glass static int sandbox_serial_ofdata_to_platdata(struct udevice *dev) 14772e98228SSimon Glass { 14872e98228SSimon Glass struct sandbox_serial_platdata *plat = dev->platdata; 14972e98228SSimon Glass const char *colour; 15072e98228SSimon Glass int i; 15172e98228SSimon Glass 15272e98228SSimon Glass plat->colour = -1; 15372e98228SSimon Glass colour = fdt_getprop(gd->fdt_blob, dev->of_offset, 15472e98228SSimon Glass "sandbox,text-colour", NULL); 15572e98228SSimon Glass if (colour) { 15672e98228SSimon Glass for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) { 15772e98228SSimon Glass if (!strcmp(colour, ansi_colour[i])) { 15872e98228SSimon Glass plat->colour = i; 15972e98228SSimon Glass break; 16072e98228SSimon Glass } 16172e98228SSimon Glass } 16272e98228SSimon Glass } 16372e98228SSimon Glass 16472e98228SSimon Glass return 0; 16572e98228SSimon Glass } 16672e98228SSimon Glass 167890fcefeSSimon Glass static const struct dm_serial_ops sandbox_serial_ops = { 168cef46b77SMarek Vasut .putc = sandbox_serial_putc, 169890fcefeSSimon Glass .pending = sandbox_serial_pending, 170cef46b77SMarek Vasut .getc = sandbox_serial_getc, 171cef46b77SMarek Vasut }; 172cef46b77SMarek Vasut 173890fcefeSSimon Glass static const struct udevice_id sandbox_serial_ids[] = { 174890fcefeSSimon Glass { .compatible = "sandbox,serial" }, 175890fcefeSSimon Glass { } 176890fcefeSSimon Glass }; 177cef46b77SMarek Vasut 178890fcefeSSimon Glass U_BOOT_DRIVER(serial_sandbox) = { 179890fcefeSSimon Glass .name = "serial_sandbox", 180890fcefeSSimon Glass .id = UCLASS_SERIAL, 181890fcefeSSimon Glass .of_match = sandbox_serial_ids, 18272e98228SSimon Glass .ofdata_to_platdata = sandbox_serial_ofdata_to_platdata, 18372e98228SSimon Glass .platdata_auto_alloc_size = sizeof(struct sandbox_serial_platdata), 18472e98228SSimon Glass .priv_auto_alloc_size = sizeof(struct sandbox_serial_priv), 185890fcefeSSimon Glass .probe = sandbox_serial_probe, 18672e98228SSimon Glass .remove = sandbox_serial_remove, 187890fcefeSSimon Glass .ops = &sandbox_serial_ops, 188890fcefeSSimon Glass .flags = DM_FLAG_PRE_RELOC, 189890fcefeSSimon Glass }; 190890fcefeSSimon Glass 19172e98228SSimon Glass static const struct sandbox_serial_platdata platdata_non_fdt = { 19272e98228SSimon Glass .colour = -1, 19372e98228SSimon Glass }; 19472e98228SSimon Glass 195890fcefeSSimon Glass U_BOOT_DEVICE(serial_sandbox_non_fdt) = { 196890fcefeSSimon Glass .name = "serial_sandbox", 19772e98228SSimon Glass .platdata = &platdata_non_fdt, 198890fcefeSSimon Glass }; 199