diff options
Diffstat (limited to 'src/uart.zig')
-rw-r--r-- | src/uart.zig | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/src/uart.zig b/src/uart.zig new file mode 100644 index 0000000..02032da --- /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_thre = 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_thre != 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(); + + const reg = 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 = reg.slice(u8), .reg_shift = @intCast(reg_shift) }; +} |