7c7c5d945588cbfb1d55ffe36f9bb943d5e14e8b
[platform/kernel/u-boot.git] / drivers / serial / serial_semihosting.c
1 // 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  */
15 struct smh_serial_priv {
16         int infd;
17         int outfd;
18 };
19
20 #if CONFIG_IS_ENABLED(DM_SERIAL)
21 static 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
33 static int smh_serial_putc(struct udevice *dev, const char ch)
34 {
35         smh_putc(ch);
36         return 0;
37 }
38
39 static const struct dm_serial_ops smh_serial_ops = {
40         .putc = smh_serial_putc,
41         .getc = smh_serial_getc,
42 };
43
44 static int smh_serial_probe(struct udevice *dev)
45 {
46         struct smh_serial_priv *priv = dev_get_priv(dev);
47
48         priv->infd = smh_open(":tt", MODE_READ);
49         return 0;
50 }
51
52 U_BOOT_DRIVER(smh_serial) = {
53         .name   = "serial_semihosting",
54         .id     = UCLASS_SERIAL,
55         .probe  = smh_serial_probe,
56         .priv_auto = sizeof(struct smh_serial_priv),
57         .ops    = &smh_serial_ops,
58         .flags  = DM_FLAG_PRE_RELOC,
59 };
60
61 U_BOOT_DRVINFO(smh_serial) = {
62         .name = "serial_semihosting",
63 };
64 #else /* DM_SERIAL */
65 static int infd = -ENODEV;
66 static int outfd = -ENODEV;
67
68 static int smh_serial_start(void)
69 {
70         infd = smh_open(":tt", MODE_READ);
71         outfd = smh_open(":tt", MODE_WRITE);
72         return 0;
73 }
74
75 static int smh_serial_stop(void)
76 {
77         if (outfd >= 0)
78                 smh_close(outfd);
79         return 0;
80 }
81
82 static void smh_serial_setbrg(void)
83 {
84 }
85
86 static int smh_serial_getc(void)
87 {
88         char ch = 0;
89
90         if (infd < 0)
91                 return smh_getc();
92
93         smh_read(infd, &ch, sizeof(ch));
94         return ch;
95 }
96
97 static int smh_serial_tstc(void)
98 {
99         return 1;
100 }
101
102 static void smh_serial_puts(const char *s)
103 {
104         ulong unused;
105
106         if (outfd < 0)
107                 smh_puts(s);
108         else
109                 smh_write(outfd, s, strlen(s), &unused);
110 }
111
112 struct serial_device serial_smh_device = {
113         .name   = "serial_smh",
114         .start  = smh_serial_start,
115         .stop   = smh_serial_stop,
116         .setbrg = smh_serial_setbrg,
117         .getc   = smh_serial_getc,
118         .tstc   = smh_serial_tstc,
119         .putc   = smh_putc,
120         .puts   = smh_serial_puts,
121 };
122
123 void smh_serial_initialize(void)
124 {
125         serial_register(&serial_smh_device);
126 }
127
128 __weak struct serial_device *default_serial_console(void)
129 {
130         return &serial_smh_device;
131 }
132 #endif
133
134 #ifdef CONFIG_DEBUG_UART_SEMIHOSTING
135 #include <debug_uart.h>
136
137 static inline void _debug_uart_init(void)
138 {
139 }
140
141 static inline void _debug_uart_putc(int c)
142 {
143         smh_putc(c);
144 }
145
146 DEBUG_UART_FUNCS
147 #endif