Skip to content

Commit e3b42cb

Browse files
committed
dockchannel_uart: Add Dockchannel UART as fallback for the hardware UART
Signed-off-by: Sven Peter <[email protected]>
1 parent 8e30c46 commit e3b42cb

7 files changed

Lines changed: 210 additions & 11 deletions

File tree

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ OBJECTS := \
134134
dcp_iboot.o \
135135
devicetree.o \
136136
display.o \
137+
dockchannel_uart.o \
137138
exception.o exception_asm.o \
138139
fb.o font.o font_retina.o \
139140
firmware.o \

src/dockchannel_uart.c

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/* SPDX-License-Identifier: MIT */
2+
3+
#include <stdarg.h>
4+
5+
#include "adt.h"
6+
#include "iodev.h"
7+
#include "types.h"
8+
#include "utils.h"
9+
#include "vsprintf.h"
10+
11+
#define DATA_TX8 0x4004
12+
#define DATA_TX_FREE 0x4014
13+
#define DATA_RX8 0x401c
14+
#define DATA_RX_COUNT 0x402c
15+
16+
static u64 uart_base = 0;
17+
18+
int dockchannel_uart_init(void)
19+
{
20+
int path[8];
21+
22+
if (adt_path_offset_trace(adt, "/arm-io/dockchannel-uart", path) < 0)
23+
return -1;
24+
25+
if (adt_get_reg(adt, path, "reg", 0, &uart_base, NULL)) {
26+
printf("!!! Failed to get dockchannel UART reg property!\n");
27+
return -1;
28+
}
29+
30+
printf("Initialized dockchannel UART at 0x%lx\n", uart_base);
31+
32+
return 0;
33+
}
34+
35+
void dockchannel_uart_putbyte(u8 c)
36+
{
37+
if (!uart_base)
38+
return;
39+
40+
while (read32(uart_base + DATA_TX_FREE) == 0)
41+
;
42+
43+
write32(uart_base + DATA_TX8, c);
44+
}
45+
46+
u8 dockchannel_uart_getbyte(void)
47+
{
48+
if (!uart_base)
49+
return 0;
50+
51+
while (read32(uart_base + DATA_RX_COUNT) == 0)
52+
;
53+
54+
return read32(uart_base + DATA_RX8) >> 8;
55+
}
56+
57+
void dockchannel_uart_putchar(u8 c)
58+
{
59+
if (c == '\n')
60+
dockchannel_uart_putbyte('\r');
61+
62+
dockchannel_uart_putbyte(c);
63+
}
64+
65+
u8 dockchannel_uart_getchar(void)
66+
{
67+
return dockchannel_uart_getbyte();
68+
}
69+
70+
void dockchannel_uart_puts(const char *s)
71+
{
72+
while (*s)
73+
dockchannel_uart_putchar(*(s++));
74+
75+
dockchannel_uart_putchar('\n');
76+
}
77+
78+
void dockchannel_uart_write(const void *buf, size_t count)
79+
{
80+
const u8 *p = buf;
81+
82+
while (count--)
83+
dockchannel_uart_putbyte(*p++);
84+
}
85+
86+
size_t dockchannel_uart_read(void *buf, size_t count)
87+
{
88+
u8 *p = buf;
89+
size_t recvd = 0;
90+
91+
while (count--) {
92+
*p++ = dockchannel_uart_getbyte();
93+
recvd++;
94+
}
95+
96+
return recvd;
97+
}
98+
99+
int dockchannel_uart_printf(const char *fmt, ...)
100+
{
101+
va_list args;
102+
char buffer[512];
103+
int i;
104+
105+
va_start(args, fmt);
106+
i = vsnprintf(buffer, sizeof(buffer), fmt, args);
107+
va_end(args);
108+
109+
dockchannel_uart_write(buffer, min(i, (int)(sizeof(buffer) - 1)));
110+
111+
return i;
112+
}
113+
114+
static bool dockchannel_uart_iodev_can_write(void *opaque)
115+
{
116+
UNUSED(opaque);
117+
118+
if (!uart_base)
119+
return false;
120+
121+
return read32(uart_base + DATA_TX_FREE) > 0;
122+
}
123+
124+
static ssize_t dockchannel_uart_iodev_can_read(void *opaque)
125+
{
126+
UNUSED(opaque);
127+
128+
if (!uart_base)
129+
return 0;
130+
131+
return read32(uart_base + DATA_RX_COUNT);
132+
}
133+
134+
static ssize_t dockchannel_uart_iodev_read(void *opaque, void *buf, size_t len)
135+
{
136+
UNUSED(opaque);
137+
return dockchannel_uart_read(buf, len);
138+
}
139+
140+
static ssize_t dockchannel_uart_iodev_write(void *opaque, const void *buf, size_t len)
141+
{
142+
UNUSED(opaque);
143+
dockchannel_uart_write(buf, len);
144+
return len;
145+
}
146+
147+
static struct iodev_ops iodev_dockchannel_uart_ops = {
148+
.can_read = dockchannel_uart_iodev_can_read,
149+
.can_write = dockchannel_uart_iodev_can_write,
150+
.read = dockchannel_uart_iodev_read,
151+
.write = dockchannel_uart_iodev_write,
152+
};
153+
154+
struct iodev iodev_dockchannel_uart = {
155+
.ops = &iodev_dockchannel_uart_ops,
156+
.usage = USAGE_CONSOLE | USAGE_UARTPROXY,
157+
.lock = SPINLOCK_INIT,
158+
};

src/dockchannel_uart.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/* SPDX-License-Identifier: MIT */
2+
3+
#ifndef DOCKCHANNEL_UART_H
4+
#define DOCKCHANNEL_UART_H
5+
6+
#include "types.h"
7+
8+
int dockchannel_uart_init(void);
9+
10+
void dockchannel_uart_putbyte(u8 c);
11+
u8 dockchannel_uart_getbyte(void);
12+
13+
void dockchannel_uart_putchar(u8 c);
14+
u8 dockchannel_uart_getchar(void);
15+
16+
void dockchannel_uart_write(const void *buf, size_t count);
17+
size_t dockchannel_uart_read(void *buf, size_t count);
18+
19+
void dockchannel_uart_puts(const char *s);
20+
int dockchannel_uart_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
21+
22+
#endif

src/iodev.c

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@
1717
#define CONSOLE_BUFFER_SIZE 8192
1818

1919
extern struct iodev iodev_uart;
20+
extern struct iodev iodev_dockchannel_uart;
2021
extern struct iodev iodev_fb;
2122
extern struct iodev iodev_log;
2223
extern struct iodev iodev_usb_vuart;
2324

25+
/* clang-format off */
2426
struct iodev *iodevs[IODEV_NUM] = {
2527
[IODEV_UART] = &iodev_uart,
28+
[IODEV_DOCKCHANNEL_UART] = &iodev_dockchannel_uart,
2629
[IODEV_FB] = &iodev_fb,
2730
[IODEV_USB_VUART] = &iodev_usb_vuart,
2831
[IODEV_LOG] = &iodev_log,
2932
};
33+
/* clang-format on */
3034

3135
char con_buf[CONSOLE_BUFFER_SIZE];
3236
size_t con_wp;
@@ -148,26 +152,34 @@ int in_iodev = 0;
148152

149153
static DECLARE_SPINLOCK(console_lock);
150154

155+
static void _iodev_console_write_helper(iodev_id_t iod, char prefix, const void *buf, size_t length)
156+
{
157+
if (!length)
158+
return;
159+
if (!(iodevs[iod]->usage & USAGE_CONSOLE))
160+
return;
161+
162+
iodevs[iod]->ops->write(iodevs[iod]->opaque, &prefix, 1);
163+
iodevs[iod]->ops->write(iodevs[iod]->opaque, buf, length);
164+
}
165+
151166
void iodev_console_write(const void *buf, size_t length)
152167
{
153168
bool do_lock = mmu_active();
154169

155170
if (!do_lock && !is_boot_cpu()) {
156-
if (length && iodevs[IODEV_UART]->usage & USAGE_CONSOLE) {
157-
iodevs[IODEV_UART]->ops->write(iodevs[IODEV_UART]->opaque, "*", 1);
158-
iodevs[IODEV_UART]->ops->write(iodevs[IODEV_UART]->opaque, buf, length);
159-
}
171+
_iodev_console_write_helper(IODEV_UART, '*', buf, length);
172+
_iodev_console_write_helper(IODEV_DOCKCHANNEL_UART, '*', buf, length);
160173
return;
161174
}
162175

163176
if (do_lock)
164177
spin_lock(&console_lock);
165178

166179
if (in_iodev) {
167-
if (length && iodevs[IODEV_UART]->usage & USAGE_CONSOLE) {
168-
iodevs[IODEV_UART]->ops->write(iodevs[IODEV_UART]->opaque, "+", 1);
169-
iodevs[IODEV_UART]->ops->write(iodevs[IODEV_UART]->opaque, buf, length);
170-
}
180+
_iodev_console_write_helper(IODEV_UART, '+', buf, length);
181+
_iodev_console_write_helper(IODEV_DOCKCHANNEL_UART, '+', buf, length);
182+
171183
if (do_lock)
172184
spin_unlock(&console_lock);
173185
return;

src/iodev.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
typedef enum _iodev_id_t {
1212
IODEV_UART,
13+
IODEV_DOCKCHANNEL_UART,
1314
IODEV_FB,
1415
IODEV_USB_VUART,
1516
IODEV_USB0,

src/startup.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "adt.h"
44
#include "chickens.h"
5+
#include "dockchannel_uart.h"
56
#include "exception.h"
67
#include "firmware.h"
78
#include "smp.h"
@@ -195,6 +196,9 @@ void _start_c(void *boot_args, void *base)
195196
debug_putc('!');
196197
}
197198

199+
/* Use Dockchannel as a secondary UART for now and ignore failure */
200+
dockchannel_uart_init();
201+
198202
uart_puts("Initializing");
199203
get_device_info();
200204

src/uartproxy.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,10 @@ int uartproxy_run(struct uartproxy_msg_start *start)
135135
UartRequest request;
136136
UartReply reply = {REQ_BOOT};
137137
if (!start) {
138-
// Startup notification only goes out via UART
138+
// Startup notification only goes out via UART and Dockchannel UART
139139
reply.checksum = checksum(&reply, REPLY_SIZE - 4);
140140
iodev_write(IODEV_UART, &reply, REPLY_SIZE);
141+
iodev_write(IODEV_DOCKCHANNEL_UART, &reply, REPLY_SIZE);
141142
} else {
142143
// Exceptions / hooks keep the current iodev
143144
iodev = uartproxy_iodev;
@@ -202,8 +203,8 @@ int uartproxy_run(struct uartproxy_msg_start *start)
202203
switch (request.type) {
203204
case REQ_NOP:
204205
enabled_features = request.features & PROXY_FEAT_ALL;
205-
if (iodev == IODEV_UART) {
206-
// Don't allow disabling checksums on UART
206+
if (iodev == IODEV_UART || iodev == IODEV_DOCKCHANNEL_UART) {
207+
// Don't allow disabling checksums on UART or Dockchannel UART
207208
enabled_features &= ~PROXY_FEAT_DISABLE_DATA_CSUMS;
208209
}
209210

0 commit comments

Comments
 (0)