blob: 2561414e40f8f866d7328c46f3b5a34327afa934 [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);
Sean Anderson537cf082022-04-22 14:50:23 -040057 if (!buf)
58 return -ENOMEM;
59
Sean Anderson760089a2022-04-04 14:18:00 -040060 smh_puts(buf);
61 free(buf);
62 return len;
63 }
64
65 ret = smh_write(priv->outfd, s, len, &written);
66 if (written)
67 return written;
68 return ret;
69}
70
Sean Andersond4f131a2022-03-22 16:59:24 -040071static const struct dm_serial_ops smh_serial_ops = {
72 .putc = smh_serial_putc,
Sean Anderson760089a2022-04-04 14:18:00 -040073 .puts = smh_serial_puts,
Sean Andersond4f131a2022-03-22 16:59:24 -040074 .getc = smh_serial_getc,
75};
76
Sean Anderson5ac1ec72022-03-22 16:59:32 -040077static int smh_serial_bind(struct udevice *dev)
78{
79 if (semihosting_enabled())
80 return 0;
81 return -ENOENT;
82}
83
Sean Andersond4f131a2022-03-22 16:59:24 -040084static int smh_serial_probe(struct udevice *dev)
85{
86 struct smh_serial_priv *priv = dev_get_priv(dev);
87
88 priv->infd = smh_open(":tt", MODE_READ);
Sean Anderson760089a2022-04-04 14:18:00 -040089 priv->outfd = smh_open(":tt", MODE_WRITE);
Sean Andersond4f131a2022-03-22 16:59:24 -040090 return 0;
91}
92
93U_BOOT_DRIVER(smh_serial) = {
94 .name = "serial_semihosting",
95 .id = UCLASS_SERIAL,
Sean Anderson5ac1ec72022-03-22 16:59:32 -040096 .bind = smh_serial_bind,
Sean Andersond4f131a2022-03-22 16:59:24 -040097 .probe = smh_serial_probe,
98 .priv_auto = sizeof(struct smh_serial_priv),
99 .ops = &smh_serial_ops,
100 .flags = DM_FLAG_PRE_RELOC,
101};
102
103U_BOOT_DRVINFO(smh_serial) = {
104 .name = "serial_semihosting",
105};
106#else /* DM_SERIAL */
107static int infd = -ENODEV;
108static int outfd = -ENODEV;
109
110static int smh_serial_start(void)
111{
112 infd = smh_open(":tt", MODE_READ);
113 outfd = smh_open(":tt", MODE_WRITE);
114 return 0;
115}
116
117static int smh_serial_stop(void)
118{
119 if (outfd >= 0)
120 smh_close(outfd);
121 return 0;
122}
123
124static void smh_serial_setbrg(void)
125{
126}
127
128static int smh_serial_getc(void)
129{
130 char ch = 0;
131
132 if (infd < 0)
133 return smh_getc();
134
135 smh_read(infd, &ch, sizeof(ch));
136 return ch;
137}
138
139static int smh_serial_tstc(void)
140{
141 return 1;
142}
143
144static void smh_serial_puts(const char *s)
145{
146 ulong unused;
147
148 if (outfd < 0)
149 smh_puts(s);
150 else
151 smh_write(outfd, s, strlen(s), &unused);
152}
153
154struct serial_device serial_smh_device = {
155 .name = "serial_smh",
156 .start = smh_serial_start,
157 .stop = smh_serial_stop,
158 .setbrg = smh_serial_setbrg,
159 .getc = smh_serial_getc,
160 .tstc = smh_serial_tstc,
161 .putc = smh_putc,
162 .puts = smh_serial_puts,
163};
164
165void smh_serial_initialize(void)
166{
Sean Anderson5ac1ec72022-03-22 16:59:32 -0400167 if (semihosting_enabled())
168 serial_register(&serial_smh_device);
Sean Andersond4f131a2022-03-22 16:59:24 -0400169}
170
171__weak struct serial_device *default_serial_console(void)
172{
173 return &serial_smh_device;
174}
175#endif
176
177#ifdef CONFIG_DEBUG_UART_SEMIHOSTING
178#include <debug_uart.h>
179
180static inline void _debug_uart_init(void)
181{
182}
183
184static inline void _debug_uart_putc(int c)
185{
186 smh_putc(c);
187}
188
189DEBUG_UART_FUNCS
190#endif