1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
10 #include <semihosting.h>
13 * struct smh_serial_priv - Semihosting serial private data
14 * @infd: stdin file descriptor (or error)
15 * @outfd: stdout file descriptor (or error)
16 * @counter: Counter used to fake pending every other call
18 struct smh_serial_priv {
24 #if CONFIG_IS_ENABLED(DM_SERIAL)
25 static int smh_serial_getc(struct udevice *dev)
28 struct smh_serial_priv *priv = dev_get_priv(dev);
33 smh_read(priv->infd, &ch, sizeof(ch));
37 static int smh_serial_putc(struct udevice *dev, const char ch)
43 static ssize_t smh_serial_puts(struct udevice *dev, const char *s, size_t len)
46 struct smh_serial_priv *priv = dev_get_priv(dev);
47 unsigned long written;
49 if (priv->outfd < 0) {
52 /* Try and avoid a copy if we can */
58 buf = strndup(s, len);
67 ret = smh_write(priv->outfd, s, len, &written);
73 static int smh_serial_pending(struct udevice *dev, bool input)
75 struct smh_serial_priv *priv = dev_get_priv(dev);
78 return priv->counter++ & 1;
82 static const struct dm_serial_ops smh_serial_ops = {
83 .putc = smh_serial_putc,
84 .puts = smh_serial_puts,
85 .getc = smh_serial_getc,
86 .pending = smh_serial_pending,
89 static int smh_serial_bind(struct udevice *dev)
91 if (semihosting_enabled())
96 static int smh_serial_probe(struct udevice *dev)
98 struct smh_serial_priv *priv = dev_get_priv(dev);
100 priv->infd = smh_open(":tt", MODE_READ);
101 priv->outfd = smh_open(":tt", MODE_WRITE);
105 U_BOOT_DRIVER(smh_serial) = {
106 .name = "serial_semihosting",
108 .bind = smh_serial_bind,
109 .probe = smh_serial_probe,
110 .priv_auto = sizeof(struct smh_serial_priv),
111 .ops = &smh_serial_ops,
112 .flags = DM_FLAG_PRE_RELOC,
115 U_BOOT_DRVINFO(smh_serial) = {
116 .name = "serial_semihosting",
118 #else /* DM_SERIAL */
119 static int infd = -ENODEV;
120 static int outfd = -ENODEV;
121 static unsigned counter = 1;
123 static int smh_serial_start(void)
125 infd = smh_open(":tt", MODE_READ);
126 outfd = smh_open(":tt", MODE_WRITE);
130 static int smh_serial_stop(void)
137 static void smh_serial_setbrg(void)
141 static int smh_serial_getc(void)
148 smh_read(infd, &ch, sizeof(ch));
152 static int smh_serial_tstc(void)
154 return counter++ & 1;
157 static void smh_serial_puts(const char *s)
164 smh_write(outfd, s, strlen(s), &unused);
167 struct serial_device serial_smh_device = {
168 .name = "serial_smh",
169 .start = smh_serial_start,
170 .stop = smh_serial_stop,
171 .setbrg = smh_serial_setbrg,
172 .getc = smh_serial_getc,
173 .tstc = smh_serial_tstc,
175 .puts = smh_serial_puts,
178 void smh_serial_initialize(void)
180 if (semihosting_enabled())
181 serial_register(&serial_smh_device);
184 __weak struct serial_device *default_serial_console(void)
186 return &serial_smh_device;
190 #ifdef CONFIG_DEBUG_UART_SEMIHOSTING
191 #include <debug_uart.h>
193 static inline void _debug_uart_init(void)
197 static inline void _debug_uart_putc(int c)