forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-02-19 1c055e55a242a33e574e48be530e06770a210dcd
kernel/drivers/tty/hvc/hvc_dcc.c
....@@ -1,16 +1,54 @@
11 // SPDX-License-Identifier: GPL-2.0
22 /* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved. */
33
4
+#include <linux/console.h>
45 #include <linux/init.h>
6
+#include <linux/kfifo.h>
7
+#include <linux/moduleparam.h>
8
+#include <linux/serial.h>
9
+#include <linux/serial_core.h>
10
+#include <linux/spinlock.h>
511
612 #include <asm/dcc.h>
713 #include <asm/processor.h>
814
915 #include "hvc_console.h"
1016
17
+/*
18
+ * Disable DCC driver at runtime. Want driver enabled for GKI, but some devices
19
+ * do not support the registers and crash when driver pokes the registers
20
+ */
21
+static bool enable;
22
+module_param(enable, bool, 0444);
23
+
1124 /* DCC Status Bits */
1225 #define DCC_STATUS_RX (1 << 30)
1326 #define DCC_STATUS_TX (1 << 29)
27
+
28
+static void dcc_uart_console_putchar(struct uart_port *port, int ch)
29
+{
30
+ while (__dcc_getstatus() & DCC_STATUS_TX)
31
+ cpu_relax();
32
+
33
+ __dcc_putchar(ch);
34
+}
35
+
36
+static void dcc_early_write(struct console *con, const char *s, unsigned n)
37
+{
38
+ struct earlycon_device *dev = con->data;
39
+
40
+ uart_console_write(&dev->port, s, n, dcc_uart_console_putchar);
41
+}
42
+
43
+static int __init dcc_early_console_setup(struct earlycon_device *device,
44
+ const char *opt)
45
+{
46
+ device->con->write = dcc_early_write;
47
+
48
+ return 0;
49
+}
50
+
51
+EARLYCON_DECLARE(dcc, dcc_early_console_setup);
1452
1553 static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
1654 {
....@@ -39,31 +77,186 @@
3977 return i;
4078 }
4179
80
+/*
81
+ * Check if the DCC is enabled. If CONFIG_HVC_DCC_SERIALIZE_SMP is enabled,
82
+ * then we assume then this function will be called first on core 0. That
83
+ * way, dcc_core0_available will be true only if it's available on core 0.
84
+ */
4285 static bool hvc_dcc_check(void)
4386 {
4487 unsigned long time = jiffies + (HZ / 10);
88
+
89
+#ifdef CONFIG_HVC_DCC_SERIALIZE_SMP
90
+ static bool dcc_core0_available;
91
+
92
+ /*
93
+ * If we're not on core 0, but we previously confirmed that DCC is
94
+ * active, then just return true.
95
+ */
96
+ if (smp_processor_id() && dcc_core0_available)
97
+ return true;
98
+#endif
4599
46100 /* Write a test character to check if it is handled */
47101 __dcc_putchar('\n');
48102
49103 while (time_is_after_jiffies(time)) {
50
- if (!(__dcc_getstatus() & DCC_STATUS_TX))
104
+ if (!(__dcc_getstatus() & DCC_STATUS_TX)) {
105
+#ifdef CONFIG_HVC_DCC_SERIALIZE_SMP
106
+ dcc_core0_available = true;
107
+#endif
51108 return true;
109
+ }
52110 }
53111
54112 return false;
55113 }
114
+
115
+#ifdef CONFIG_HVC_DCC_SERIALIZE_SMP
116
+
117
+static void dcc_put_work_fn(struct work_struct *work);
118
+static void dcc_get_work_fn(struct work_struct *work);
119
+static DECLARE_WORK(dcc_pwork, dcc_put_work_fn);
120
+static DECLARE_WORK(dcc_gwork, dcc_get_work_fn);
121
+static DEFINE_SPINLOCK(dcc_lock);
122
+static DEFINE_KFIFO(inbuf, unsigned char, 128);
123
+static DEFINE_KFIFO(outbuf, unsigned char, 1024);
124
+
125
+/*
126
+ * Workqueue function that writes the output FIFO to the DCC on core 0.
127
+ */
128
+static void dcc_put_work_fn(struct work_struct *work)
129
+{
130
+ unsigned char ch;
131
+ unsigned long irqflags;
132
+
133
+ spin_lock_irqsave(&dcc_lock, irqflags);
134
+
135
+ /* While there's data in the output FIFO, write it to the DCC */
136
+ while (kfifo_get(&outbuf, &ch))
137
+ hvc_dcc_put_chars(0, &ch, 1);
138
+
139
+ /* While we're at it, check for any input characters */
140
+ while (!kfifo_is_full(&inbuf)) {
141
+ if (!hvc_dcc_get_chars(0, &ch, 1))
142
+ break;
143
+ kfifo_put(&inbuf, ch);
144
+ }
145
+
146
+ spin_unlock_irqrestore(&dcc_lock, irqflags);
147
+}
148
+
149
+/*
150
+ * Workqueue function that reads characters from DCC and puts them into the
151
+ * input FIFO.
152
+ */
153
+static void dcc_get_work_fn(struct work_struct *work)
154
+{
155
+ unsigned char ch;
156
+ unsigned long irqflags;
157
+
158
+ /*
159
+ * Read characters from DCC and put them into the input FIFO, as
160
+ * long as there is room and we have characters to read.
161
+ */
162
+ spin_lock_irqsave(&dcc_lock, irqflags);
163
+
164
+ while (!kfifo_is_full(&inbuf)) {
165
+ if (!hvc_dcc_get_chars(0, &ch, 1))
166
+ break;
167
+ kfifo_put(&inbuf, ch);
168
+ }
169
+ spin_unlock_irqrestore(&dcc_lock, irqflags);
170
+}
171
+
172
+/*
173
+ * Write characters directly to the DCC if we're on core 0 and the FIFO
174
+ * is empty, or write them to the FIFO if we're not.
175
+ */
176
+static int hvc_dcc0_put_chars(uint32_t vt, const char *buf,
177
+ int count)
178
+{
179
+ int len;
180
+ unsigned long irqflags;
181
+
182
+ spin_lock_irqsave(&dcc_lock, irqflags);
183
+ if (smp_processor_id() || (!kfifo_is_empty(&outbuf))) {
184
+ len = kfifo_in(&outbuf, buf, count);
185
+ spin_unlock_irqrestore(&dcc_lock, irqflags);
186
+ /*
187
+ * We just push data to the output FIFO, so schedule the
188
+ * workqueue that will actually write that data to DCC.
189
+ */
190
+ schedule_work_on(0, &dcc_pwork);
191
+ return len;
192
+ }
193
+
194
+ /*
195
+ * If we're already on core 0, and the FIFO is empty, then just
196
+ * write the data to DCC.
197
+ */
198
+ len = hvc_dcc_put_chars(vt, buf, count);
199
+ spin_unlock_irqrestore(&dcc_lock, irqflags);
200
+
201
+ return len;
202
+}
203
+
204
+/*
205
+ * Read characters directly from the DCC if we're on core 0 and the FIFO
206
+ * is empty, or read them from the FIFO if we're not.
207
+ */
208
+static int hvc_dcc0_get_chars(uint32_t vt, char *buf, int count)
209
+{
210
+ int len;
211
+ unsigned long irqflags;
212
+
213
+ spin_lock_irqsave(&dcc_lock, irqflags);
214
+
215
+ if (smp_processor_id() || (!kfifo_is_empty(&inbuf))) {
216
+ len = kfifo_out(&inbuf, buf, count);
217
+ spin_unlock_irqrestore(&dcc_lock, irqflags);
218
+
219
+ /*
220
+ * If the FIFO was empty, there may be characters in the DCC
221
+ * that we haven't read yet. Schedule a workqueue to fill
222
+ * the input FIFO, so that the next time this function is
223
+ * called, we'll have data.
224
+ */
225
+ if (!len)
226
+ schedule_work_on(0, &dcc_gwork);
227
+
228
+ return len;
229
+ }
230
+
231
+ /*
232
+ * If we're already on core 0, and the FIFO is empty, then just
233
+ * read the data from DCC.
234
+ */
235
+ len = hvc_dcc_get_chars(vt, buf, count);
236
+ spin_unlock_irqrestore(&dcc_lock, irqflags);
237
+
238
+ return len;
239
+}
240
+
241
+static const struct hv_ops hvc_dcc_get_put_ops = {
242
+ .get_chars = hvc_dcc0_get_chars,
243
+ .put_chars = hvc_dcc0_put_chars,
244
+};
245
+
246
+#else
56247
57248 static const struct hv_ops hvc_dcc_get_put_ops = {
58249 .get_chars = hvc_dcc_get_chars,
59250 .put_chars = hvc_dcc_put_chars,
60251 };
61252
253
+#endif
254
+
62255 static int __init hvc_dcc_console_init(void)
63256 {
64257 int ret;
65258
66
- if (!hvc_dcc_check())
259
+ if (!enable || !hvc_dcc_check())
67260 return -ENODEV;
68261
69262 /* Returns -1 if error */
....@@ -77,7 +270,7 @@
77270 {
78271 struct hvc_struct *p;
79272
80
- if (!hvc_dcc_check())
273
+ if (!enable || !hvc_dcc_check())
81274 return -ENODEV;
82275
83276 p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);