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> 14*890fcefeSSimon Glass #include <dm.h> 15*890fcefeSSimon Glass #include <fdtdec.h> 167d95f2a3SSimon Glass #include <lcd.h> 177accb6eaSSimon Glass #include <os.h> 18cef46b77SMarek Vasut #include <serial.h> 19cef46b77SMarek Vasut #include <linux/compiler.h> 20ffb87905SSimon Glass #include <asm/state.h> 217accb6eaSSimon Glass 22*890fcefeSSimon Glass DECLARE_GLOBAL_DATA_PTR; 23*890fcefeSSimon Glass 24e101550aSTaylor Hutt /* 25e101550aSTaylor Hutt * 26e101550aSTaylor Hutt * serial_buf: A buffer that holds keyboard characters for the 27e101550aSTaylor Hutt * Sandbox U-boot. 28e101550aSTaylor Hutt * 29e101550aSTaylor Hutt * invariants: 30e101550aSTaylor Hutt * serial_buf_write == serial_buf_read -> empty buffer 31e101550aSTaylor Hutt * (serial_buf_write + 1) % 16 == serial_buf_read -> full buffer 32e101550aSTaylor Hutt */ 33e101550aSTaylor Hutt static char serial_buf[16]; 34e101550aSTaylor Hutt static unsigned int serial_buf_write; 35e101550aSTaylor Hutt static unsigned int serial_buf_read; 36e101550aSTaylor Hutt 37*890fcefeSSimon Glass static int sandbox_serial_probe(struct udevice *dev) 387accb6eaSSimon Glass { 39ffb87905SSimon Glass struct sandbox_state *state = state_get_current(); 40ffb87905SSimon Glass 41ffb87905SSimon Glass if (state->term_raw != STATE_TERM_COOKED) 42ffb87905SSimon Glass os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS); 43*890fcefeSSimon Glass 447accb6eaSSimon Glass return 0; 457accb6eaSSimon Glass } 467accb6eaSSimon Glass 47*890fcefeSSimon Glass static int sandbox_serial_putc(struct udevice *dev, const char ch) 487accb6eaSSimon Glass { 497accb6eaSSimon Glass os_write(1, &ch, 1); 507accb6eaSSimon Glass 51*890fcefeSSimon Glass return 0; 527accb6eaSSimon Glass } 537accb6eaSSimon Glass 54e101550aSTaylor Hutt static unsigned int increment_buffer_index(unsigned int index) 557accb6eaSSimon Glass { 56e101550aSTaylor Hutt return (index + 1) % ARRAY_SIZE(serial_buf); 577accb6eaSSimon Glass } 587accb6eaSSimon Glass 59*890fcefeSSimon Glass static int sandbox_serial_pending(struct udevice *dev, bool input) 607accb6eaSSimon Glass { 61e101550aSTaylor Hutt const unsigned int next_index = 62e101550aSTaylor Hutt increment_buffer_index(serial_buf_write); 63e101550aSTaylor Hutt ssize_t count; 64e101550aSTaylor Hutt 65*890fcefeSSimon Glass if (!input) 66*890fcefeSSimon Glass return 0; 67*890fcefeSSimon Glass 68e101550aSTaylor Hutt os_usleep(100); 697d95f2a3SSimon Glass #ifdef CONFIG_LCD 707d95f2a3SSimon Glass lcd_sync(); 717d95f2a3SSimon Glass #endif 72e101550aSTaylor Hutt if (next_index == serial_buf_read) 73e101550aSTaylor Hutt return 1; /* buffer full */ 74e101550aSTaylor Hutt 75e101550aSTaylor Hutt count = os_read_no_block(0, &serial_buf[serial_buf_write], 1); 76e101550aSTaylor Hutt if (count == 1) 77e101550aSTaylor Hutt serial_buf_write = next_index; 78*890fcefeSSimon Glass 79e101550aSTaylor Hutt return serial_buf_write != serial_buf_read; 80e101550aSTaylor Hutt } 81e101550aSTaylor Hutt 82*890fcefeSSimon Glass static int sandbox_serial_getc(struct udevice *dev) 83e101550aSTaylor Hutt { 84e101550aSTaylor Hutt int result; 85e101550aSTaylor Hutt 86*890fcefeSSimon Glass if (!sandbox_serial_pending(dev, true)) 87*890fcefeSSimon Glass return -EAGAIN; /* buffer empty */ 88e101550aSTaylor Hutt 89e101550aSTaylor Hutt result = serial_buf[serial_buf_read]; 90e101550aSTaylor Hutt serial_buf_read = increment_buffer_index(serial_buf_read); 91e101550aSTaylor Hutt return result; 927accb6eaSSimon Glass } 93cef46b77SMarek Vasut 94*890fcefeSSimon Glass static const struct dm_serial_ops sandbox_serial_ops = { 95cef46b77SMarek Vasut .putc = sandbox_serial_putc, 96*890fcefeSSimon Glass .pending = sandbox_serial_pending, 97cef46b77SMarek Vasut .getc = sandbox_serial_getc, 98cef46b77SMarek Vasut }; 99cef46b77SMarek Vasut 100*890fcefeSSimon Glass static const struct udevice_id sandbox_serial_ids[] = { 101*890fcefeSSimon Glass { .compatible = "sandbox,serial" }, 102*890fcefeSSimon Glass { } 103*890fcefeSSimon Glass }; 104cef46b77SMarek Vasut 105*890fcefeSSimon Glass U_BOOT_DRIVER(serial_sandbox) = { 106*890fcefeSSimon Glass .name = "serial_sandbox", 107*890fcefeSSimon Glass .id = UCLASS_SERIAL, 108*890fcefeSSimon Glass .of_match = sandbox_serial_ids, 109*890fcefeSSimon Glass .probe = sandbox_serial_probe, 110*890fcefeSSimon Glass .ops = &sandbox_serial_ops, 111*890fcefeSSimon Glass .flags = DM_FLAG_PRE_RELOC, 112*890fcefeSSimon Glass }; 113*890fcefeSSimon Glass 114*890fcefeSSimon Glass U_BOOT_DEVICE(serial_sandbox_non_fdt) = { 115*890fcefeSSimon Glass .name = "serial_sandbox", 116*890fcefeSSimon Glass }; 117