blob: 4328b3dac5b7f9b2dfa64e5325f63f5f6739bea6 [file] [log] [blame]
Sean Andersond4f131a2022-03-22 16:59:24 -04001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
4 */
5
6#include <common.h>
7#include <dm.h>
Sean Anderson760089a2022-04-04 14:18:00 -04008#include <malloc.h>
Sean Andersond4f131a2022-03-22 16:59:24 -04009#include <serial.h>
10#include <semihosting.h>
11
12/**
13 * struct smh_serial_priv - Semihosting serial private data
14 * @infd: stdin file descriptor (or error)
Sean Anderson760089a2022-04-04 14:18:00 -040015 * @outfd: stdout file descriptor (or error)
Sean Andersond4f131a2022-03-22 16:59:24 -040016 */
17struct smh_serial_priv {
18 int infd;
19 int outfd;
20};
21
22#if CONFIG_IS_ENABLED(DM_SERIAL)
23static int smh_serial_getc(struct udevice *dev)
24{
25 char ch = 0;
26 struct smh_serial_priv *priv = dev_get_priv(dev);
27
28 if (priv->infd < 0)
29 return smh_getc();
30
31 smh_read(priv->infd, &ch, sizeof(ch));
32 return ch;
33}
34
35static int smh_serial_putc(struct udevice *dev, const char ch)
36{
37 smh_putc(ch);
38 return 0;
39}
40
Sean Anderson760089a2022-04-04 14:18:00 -040041static ssize_t smh_serial_puts(struct udevice *dev, const char *s, size_t len)
42{
43 int ret;
44 struct smh_serial_priv *priv = dev_get_priv(dev);
45 unsigned long written;
46
47 if (priv->outfd < 0) {
48 char *buf;
49
50 /* Try and avoid a copy if we can */
51 if (!s[len + 1]) {
52 smh_puts(s);
53 return len;
54 }
55
56 buf = strndup(s, len);
57 smh_puts(buf);
58 free(buf);
59 return len;
60 }
61
62 ret = smh_write(priv->outfd, s, len, &written);
63 if (written)
64 return written;
65 return ret;
66}
67
Sean Andersond4f131a2022-03-22 16:59:24 -040068static const struct dm_serial_ops smh_serial_ops = {
69 .putc = smh_serial_putc,
Sean Anderson760089a2022-04-04 14:18:00 -040070 .puts = smh_serial_puts,
Sean Andersond4f131a2022-03-22 16:59:24 -040071 .getc = smh_serial_getc,
72};
73
Sean Anderson5ac1ec72022-03-22 16:59:32 -040074static int smh_serial_bind(struct udevice *dev)
75{
76 if (semihosting_enabled())
77 return 0;
78 return -ENOENT;
79}
80
Sean Andersond4f131a2022-03-22 16:59:24 -040081static int smh_serial_probe(struct udevice *dev)
82{
83 struct smh_serial_priv *priv = dev_get_priv(dev);
84
85 priv->infd = smh_open(":tt", MODE_READ);
Sean Anderson760089a2022-04-04 14:18:00 -040086 priv->outfd = smh_open(":tt", MODE_WRITE);
Sean Andersond4f131a2022-03-22 16:59:24 -040087 return 0;
88}
89
90U_BOOT_DRIVER(smh_serial) = {
91 .name = "serial_semihosting",
92 .id = UCLASS_SERIAL,
Sean Anderson5ac1ec72022-03-22 16:59:32 -040093 .bind = smh_serial_bind,
Sean Andersond4f131a2022-03-22 16:59:24 -040094 .probe = smh_serial_probe,
95 .priv_auto = sizeof(struct smh_serial_priv),
96 .ops = &smh_serial_ops,
97 .flags = DM_FLAG_PRE_RELOC,
98};
99
100U_BOOT_DRVINFO(smh_serial) = {
101 .name = "serial_semihosting",
102};
103#else /* DM_SERIAL */
104static int infd = -ENODEV;
105static int outfd = -ENODEV;
106
107static int smh_serial_start(void)
108{
109 infd = smh_open(":tt", MODE_READ);
110 outfd = smh_open(":tt", MODE_WRITE);
111 return 0;
112}
113
114static int smh_serial_stop(void)
115{
116 if (outfd >= 0)
117 smh_close(outfd);
118 return 0;
119}
120
121static void smh_serial_setbrg(void)
122{
123}
124
125static int smh_serial_getc(void)
126{
127 char ch = 0;
128
129 if (infd < 0)
130 return smh_getc();
131
132 smh_read(infd, &ch, sizeof(ch));
133 return ch;
134}
135
136static int smh_serial_tstc(void)
137{
138 return 1;
139}
140
141static void smh_serial_puts(const char *s)
142{
143 ulong unused;
144
145 if (outfd < 0)
146 smh_puts(s);
147 else
148 smh_write(outfd, s, strlen(s), &unused);
149}
150
151struct serial_device serial_smh_device = {
152 .name = "serial_smh",
153 .start = smh_serial_start,
154 .stop = smh_serial_stop,
155 .setbrg = smh_serial_setbrg,
156 .getc = smh_serial_getc,
157 .tstc = smh_serial_tstc,
158 .putc = smh_putc,
159 .puts = smh_serial_puts,
160};
161
162void smh_serial_initialize(void)
163{
Sean Anderson5ac1ec72022-03-22 16:59:32 -0400164 if (semihosting_enabled())
165 serial_register(&serial_smh_device);
Sean Andersond4f131a2022-03-22 16:59:24 -0400166}
167
168__weak struct serial_device *default_serial_console(void)
169{
170 return &serial_smh_device;
171}
172#endif
173
174#ifdef CONFIG_DEBUG_UART_SEMIHOSTING
175#include <debug_uart.h>
176
177static inline void _debug_uart_init(void)
178{
179}
180
181static inline void _debug_uart_putc(int c)
182{
183 smh_putc(c);
184}
185
186DEBUG_UART_FUNCS
187#endif