1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
4 */
5
6 #include <dm.h>
7 #include <malloc.h>
8 #include <serial.h>
9
10 #include <asm/platform/simcall.h>
11
12 /**
13 * struct simc_serial_priv - Semihosting serial private data
14 * @counter: Counter used to fake pending every other call
15 */
16 struct simc_serial_priv {
17 unsigned int counter;
18 };
19
simc_serial_getc(struct udevice * dev)20 static int simc_serial_getc(struct udevice *dev)
21 {
22 char ch = 0;
23
24 simc_read(0, &ch, sizeof(ch));
25
26 return ch;
27 }
28
simc_serial_putc(struct udevice * dev,const char ch)29 static int simc_serial_putc(struct udevice *dev, const char ch)
30 {
31 char str[2] = {0};
32
33 str[0] = ch;
34 simc_write(1, str, 1);
35
36 return 0;
37 }
38
simc_serial_pending(struct udevice * dev,bool input)39 static int simc_serial_pending(struct udevice *dev, bool input)
40 {
41 struct simc_serial_priv *priv = dev_get_priv(dev);
42
43 if (input) {
44 int res = simc_poll(0);
45 return res < 0 ? priv->counter++ & 1 : res;
46 }
47
48 return false;
49 }
50
smh_serial_puts(struct udevice * dev,const char * s,size_t len)51 static ssize_t smh_serial_puts(struct udevice *dev, const char *s, size_t len)
52 {
53 int ret;
54
55 ret = simc_write(1, s, len);
56
57 return ret;
58 }
59
60 static const struct dm_serial_ops simc_serial_ops = {
61 .putc = simc_serial_putc,
62 .puts = smh_serial_puts,
63 .getc = simc_serial_getc,
64 .pending = simc_serial_pending,
65 };
66
67 U_BOOT_DRIVER(simc_serial) = {
68 .name = "serial_xtensa_semihosting",
69 .id = UCLASS_SERIAL,
70 .priv_auto = sizeof(struct simc_serial_priv),
71 .ops = &simc_serial_ops,
72 .flags = DM_FLAG_PRE_RELOC,
73 };
74
75 U_BOOT_DRVINFO(simc_serial) = {
76 .name = "serial_xtensa_semihosting",
77 };
78
79 #if CONFIG_IS_ENABLED(DEBUG_UART_XTENSA_SEMIHOSTING)
80 #include <debug_uart.h>
81
_debug_uart_init(void)82 static inline void _debug_uart_init(void)
83 {
84 }
85
_debug_uart_putc(int c)86 static inline void _debug_uart_putc(int c)
87 {
88 simc_serial_putc(NULL, c);
89 }
90
91 DEBUG_UART_FUNCS
92 #endif
93