blob: 62b1b2241b3fe2063a8fe21fd8250c385efd98fa [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>
8#include <serial.h>
9#include <semihosting.h>
10
11/**
12 * struct smh_serial_priv - Semihosting serial private data
13 * @infd: stdin file descriptor (or error)
14 */
15struct smh_serial_priv {
16 int infd;
17 int outfd;
18};
19
20#if CONFIG_IS_ENABLED(DM_SERIAL)
21static int smh_serial_getc(struct udevice *dev)
22{
23 char ch = 0;
24 struct smh_serial_priv *priv = dev_get_priv(dev);
25
26 if (priv->infd < 0)
27 return smh_getc();
28
29 smh_read(priv->infd, &ch, sizeof(ch));
30 return ch;
31}
32
33static int smh_serial_putc(struct udevice *dev, const char ch)
34{
35 smh_putc(ch);
36 return 0;
37}
38
39static const struct dm_serial_ops smh_serial_ops = {
40 .putc = smh_serial_putc,
41 .getc = smh_serial_getc,
42};
43
Sean Anderson5ac1ec72022-03-22 16:59:32 -040044static int smh_serial_bind(struct udevice *dev)
45{
46 if (semihosting_enabled())
47 return 0;
48 return -ENOENT;
49}
50
Sean Andersond4f131a2022-03-22 16:59:24 -040051static int smh_serial_probe(struct udevice *dev)
52{
53 struct smh_serial_priv *priv = dev_get_priv(dev);
54
55 priv->infd = smh_open(":tt", MODE_READ);
56 return 0;
57}
58
59U_BOOT_DRIVER(smh_serial) = {
60 .name = "serial_semihosting",
61 .id = UCLASS_SERIAL,
Sean Anderson5ac1ec72022-03-22 16:59:32 -040062 .bind = smh_serial_bind,
Sean Andersond4f131a2022-03-22 16:59:24 -040063 .probe = smh_serial_probe,
64 .priv_auto = sizeof(struct smh_serial_priv),
65 .ops = &smh_serial_ops,
66 .flags = DM_FLAG_PRE_RELOC,
67};
68
69U_BOOT_DRVINFO(smh_serial) = {
70 .name = "serial_semihosting",
71};
72#else /* DM_SERIAL */
73static int infd = -ENODEV;
74static int outfd = -ENODEV;
75
76static int smh_serial_start(void)
77{
78 infd = smh_open(":tt", MODE_READ);
79 outfd = smh_open(":tt", MODE_WRITE);
80 return 0;
81}
82
83static int smh_serial_stop(void)
84{
85 if (outfd >= 0)
86 smh_close(outfd);
87 return 0;
88}
89
90static void smh_serial_setbrg(void)
91{
92}
93
94static int smh_serial_getc(void)
95{
96 char ch = 0;
97
98 if (infd < 0)
99 return smh_getc();
100
101 smh_read(infd, &ch, sizeof(ch));
102 return ch;
103}
104
105static int smh_serial_tstc(void)
106{
107 return 1;
108}
109
110static void smh_serial_puts(const char *s)
111{
112 ulong unused;
113
114 if (outfd < 0)
115 smh_puts(s);
116 else
117 smh_write(outfd, s, strlen(s), &unused);
118}
119
120struct serial_device serial_smh_device = {
121 .name = "serial_smh",
122 .start = smh_serial_start,
123 .stop = smh_serial_stop,
124 .setbrg = smh_serial_setbrg,
125 .getc = smh_serial_getc,
126 .tstc = smh_serial_tstc,
127 .putc = smh_putc,
128 .puts = smh_serial_puts,
129};
130
131void smh_serial_initialize(void)
132{
Sean Anderson5ac1ec72022-03-22 16:59:32 -0400133 if (semihosting_enabled())
134 serial_register(&serial_smh_device);
Sean Andersond4f131a2022-03-22 16:59:24 -0400135}
136
137__weak struct serial_device *default_serial_console(void)
138{
139 return &serial_smh_device;
140}
141#endif
142
143#ifdef CONFIG_DEBUG_UART_SEMIHOSTING
144#include <debug_uart.h>
145
146static inline void _debug_uart_init(void)
147{
148}
149
150static inline void _debug_uart_putc(int c)
151{
152 smh_putc(c);
153}
154
155DEBUG_UART_FUNCS
156#endif