serial: smh: Initialize serial only if semihosting is enabled
[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_bind(struct udevice *dev)
45 {
46         if (semihosting_enabled())
47                 return 0;
48         return -ENOENT;
49 }
50
51 static 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
59 U_BOOT_DRIVER(smh_serial) = {
60         .name   = "serial_semihosting",
61         .id     = UCLASS_SERIAL,
62         .bind   = smh_serial_bind,
63         .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
69 U_BOOT_DRVINFO(smh_serial) = {
70         .name = "serial_semihosting",
71 };
72 #else /* DM_SERIAL */
73 static int infd = -ENODEV;
74 static int outfd = -ENODEV;
75
76 static 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
83 static int smh_serial_stop(void)
84 {
85         if (outfd >= 0)
86                 smh_close(outfd);
87         return 0;
88 }
89
90 static void smh_serial_setbrg(void)
91 {
92 }
93
94 static 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
105 static int smh_serial_tstc(void)
106 {
107         return 1;
108 }
109
110 static 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
120 struct 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
131 void smh_serial_initialize(void)
132 {
133         if (semihosting_enabled())
134                 serial_register(&serial_smh_device);
135 }
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
146 static inline void _debug_uart_init(void)
147 {
148 }
149
150 static inline void _debug_uart_putc(int c)
151 {
152         smh_putc(c);
153 }
154
155 DEBUG_UART_FUNCS
156 #endif