serial: serial_xen: print U-Boot banner and others
[platform/kernel/u-boot.git] / drivers / serial / serial_xen.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) 2018 NXP
4  * (C) 2020 EPAM Systems Inc.
5  */
6 #include <common.h>
7 #include <cpu_func.h>
8 #include <dm.h>
9 #include <serial.h>
10 #include <watchdog.h>
11
12 #include <linux/bug.h>
13
14 #include <xen/hvm.h>
15 #include <xen/events.h>
16
17 #include <xen/interface/sched.h>
18 #include <xen/interface/hvm/hvm_op.h>
19 #include <xen/interface/hvm/params.h>
20 #include <xen/interface/io/console.h>
21 #include <xen/interface/io/ring.h>
22
23 DECLARE_GLOBAL_DATA_PTR;
24
25 u32 console_evtchn;
26
27 /*
28  * struct xen_uart_priv - Structure representing a Xen UART info
29  * @intf:    Console I/O interface for Xen guest OSes
30  * @evtchn:  Console event channel
31  */
32 struct xen_uart_priv {
33         struct xencons_interface *intf;
34         u32 evtchn;
35 };
36
37 int xen_serial_setbrg(struct udevice *dev, int baudrate)
38 {
39         return 0;
40 }
41
42 static int xen_serial_probe(struct udevice *dev)
43 {
44         struct xen_uart_priv *priv = dev_get_priv(dev);
45         u64 val = 0;
46         unsigned long gfn;
47         int ret;
48
49         ret = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &val);
50         if (ret < 0 || val == 0)
51                 return ret;
52
53         priv->evtchn = val;
54         console_evtchn = val;
55
56         ret = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &val);
57         if (ret < 0)
58                 return ret;
59
60         if (!val)
61                 return -EINVAL;
62
63         gfn = val;
64         priv->intf = (struct xencons_interface *)(gfn << XEN_PAGE_SHIFT);
65
66         return 0;
67 }
68
69 static int xen_serial_pending(struct udevice *dev, bool input)
70 {
71         struct xen_uart_priv *priv = dev_get_priv(dev);
72         struct xencons_interface *intf = priv->intf;
73
74         if (!input || intf->in_cons == intf->in_prod)
75                 return 0;
76
77         return 1;
78 }
79
80 static int xen_serial_getc(struct udevice *dev)
81 {
82         struct xen_uart_priv *priv = dev_get_priv(dev);
83         struct xencons_interface *intf = priv->intf;
84         XENCONS_RING_IDX cons;
85         char c;
86
87         while (intf->in_cons == intf->in_prod)
88                 mb(); /* wait */
89
90         cons = intf->in_cons;
91         mb();                   /* get pointers before reading ring */
92
93         c = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
94
95         mb();                   /* read ring before consuming */
96         intf->in_cons = cons;
97
98         notify_remote_via_evtchn(priv->evtchn);
99
100         return c;
101 }
102
103 static int __write_console(struct udevice *dev, const char *data, int len)
104 {
105         struct xen_uart_priv *priv = dev_get_priv(dev);
106         struct xencons_interface *intf = priv->intf;
107         XENCONS_RING_IDX cons, prod;
108         int sent = 0;
109
110         cons = intf->out_cons;
111         prod = intf->out_prod;
112         mb(); /* Update pointer */
113
114         WARN_ON((prod - cons) > sizeof(intf->out));
115
116         while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
117                 intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
118
119         mb(); /* Update data before pointer */
120         intf->out_prod = prod;
121
122         if (sent)
123                 notify_remote_via_evtchn(priv->evtchn);
124
125         return sent;
126 }
127
128 static int write_console(struct udevice *dev, const char *data, int len)
129 {
130         /*
131          * Make sure the whole buffer is emitted, polling if
132          * necessary.  We don't ever want to rely on the hvc daemon
133          * because the most interesting console output is when the
134          * kernel is crippled.
135          */
136         while (len) {
137                 int sent = __write_console(dev, data, len);
138
139                 data += sent;
140                 len -= sent;
141
142                 if (unlikely(len))
143                         HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
144         }
145
146         return 0;
147 }
148
149 static int xen_serial_putc(struct udevice *dev, const char ch)
150 {
151         write_console(dev, &ch, 1);
152
153         return 0;
154 }
155
156 static const struct dm_serial_ops xen_serial_ops = {
157         .putc = xen_serial_putc,
158         .getc = xen_serial_getc,
159         .pending = xen_serial_pending,
160 };
161
162 #if CONFIG_IS_ENABLED(OF_CONTROL)
163 static const struct udevice_id xen_serial_ids[] = {
164         { .compatible = "xen,xen" },
165         { }
166 };
167 #endif
168
169 U_BOOT_DRIVER(serial_xen) = {
170         .name                   = "serial_xen",
171         .id                     = UCLASS_SERIAL,
172 #if CONFIG_IS_ENABLED(OF_CONTROL)
173         .of_match               = xen_serial_ids,
174 #endif
175         .priv_auto_alloc_size   = sizeof(struct xen_uart_priv),
176         .probe                  = xen_serial_probe,
177         .ops                    = &xen_serial_ops,
178         .flags                  = DM_FLAG_PRE_RELOC,
179 };
180