aboutsummaryrefslogtreecommitdiff
path: root/src/uart.zig
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-05-18 10:58:01 +0200
committerHimbeer <himbeer@disroot.org>2024-05-18 10:58:01 +0200
commit573f58487f899563e1ae08fd829eb4053a1f10ac (patch)
treee051c2169533aea52885c1cd12e0636afe468399 /src/uart.zig
parent71a8c414d0ffcb6426f440542ea97e54133034f6 (diff)
logging: Use UART directly if available
Some SBIs don't implement the Debug Console extension. Using the UART is one solution, supporting the SBI Legacy extension might work too if it exists.
Diffstat (limited to 'src/uart.zig')
-rw-r--r--src/uart.zig58
1 files changed, 58 insertions, 0 deletions
diff --git a/src/uart.zig b/src/uart.zig
new file mode 100644
index 0000000..3a15a6c
--- /dev/null
+++ b/src/uart.zig
@@ -0,0 +1,58 @@
+// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+const std = @import("std");
+
+const fdt = @import("fdt.zig");
+const paging = @import("paging.zig");
+
+pub var default: ?Port = null;
+
+pub const Error = error{
+ NoSocNode,
+};
+
+pub const Port = struct {
+ reg: []volatile u8,
+ reg_shift: u6,
+
+ const lsr_temt = 1 << 5;
+
+ pub const Writer = std.io.Writer(Port, error{}, write);
+
+ fn isWriteReady(self: Port) bool {
+ return self.reg[@as(usize, 5) << self.reg_shift] & lsr_temt != 0;
+ }
+
+ pub fn write(self: Port, bytes: []const u8) !usize {
+ for (bytes) |byte| {
+ while (!self.isWriteReady()) {}
+ self.reg[0] = byte;
+ }
+
+ return bytes.len;
+ }
+
+ pub fn writer(port: Port) Writer {
+ return .{ .context = port };
+ }
+};
+
+pub fn init(kmem: *paging.Table, dt: *const fdt.Tree, allocator: std.mem.Allocator) !void {
+ var soc = fdt.findPathExact(dt, "/soc") orelse return Error.NoSocNode;
+
+ const compatible = fdt.findCompatible(&soc, &[_][]const u8{ "ns16550", "snps,dw-apb-uart" }, 1);
+
+ const node = if (compatible.len > 0) compatible[0] else return;
+
+ const regs = try node.reg(allocator);
+ defer regs.deinit();
+
+ try kmem.mapDevice(regs.items[0]);
+
+ const reg_shift_bytes = node.props.get("reg-shift");
+ const reg_shift = if (reg_shift_bytes) |bytes| std.mem.readInt(u32, bytes[0..4], .big) else 0;
+
+ default = .{ .reg = regs.items[0].slice(u8), .reg_shift = @intCast(reg_shift) };
+}