sylveos

Toy Operating System
Log | Files | Refs

commit c4a1d1ddeedb1078b6b1a9401d5f11dd289c5878
parent de71629ce95ed08bd9c6d124e22db286fd3be1e6
Author: Sylvia Ivory <git@sivory.net>
Date:   Tue,  3 Mar 2026 13:22:59 -0800

Add polled I/O

Diffstat:
Mpi/spi.zig | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 105 insertions(+), 5 deletions(-)

diff --git a/pi/spi.zig b/pi/spi.zig @@ -34,7 +34,7 @@ const MasterControlStatus = packed struct(u32) { }; pub const ChipSelectPolarity = enum(u1) { - SelectActoveLow = 0, + SelectActiveLow = 0, SelectActiveHigh = 1, }; @@ -57,7 +57,11 @@ const MasterControlStatus = packed struct(u32) { clock_phase: ClockPhase = .Middle, clock_polarity: ClockPolarity = .Low, clear_fifo_clear: FiFoClear = .{ .clear_tx = false, .clear_rx = false }, - chip_select_polarity: ChipSelectPolarity = .SelectActoveLow, + // elinux bcm2835 errata: + // "There is a CSPOL bit described here, wereas there are also CSPOL[0,1,2] + // described on page 153. How do these combine???" + // Linux sets both this and chip_select_N together + chip_select_polarity: ChipSelectPolarity = .SelectActiveLow, transfer_active: bool = false, dma_enable: bool = false, interrupt_on_done: bool = false, @@ -72,9 +76,9 @@ const MasterControlStatus = packed struct(u32) { txd_has_space: bool = true, rxr_is_full: bool = false, rxf_is_full: bool = false, - chip_select_0: ChipSelectPolarity = .SelectActoveLow, - chip_select_1: ChipSelectPolarity = .SelectActoveLow, - chip_select_2: ChipSelectPolarity = .SelectActoveLow, + chip_select_0: ChipSelectPolarity = .SelectActiveLow, + chip_select_1: ChipSelectPolarity = .SelectActiveLow, + chip_select_2: ChipSelectPolarity = .SelectActiveLow, dma_enable_lossi: bool = false, lossi_write_u32: bool = false, _reserved_31_26: u6, @@ -114,3 +118,99 @@ const Dc = packed struct(u32) { // reading bytes from SPI_FIFO(FiFo) until all data is written // 3. Poll DONE(transfer_progress) until it goes to 1 // 4. Set TA(transfer_active) = 0 +pub const SPIConfig = struct { + chip_select: MasterControlStatus.ChipSelect, + chip_select_polarity: MasterControlStatus.ChipSelectPolarity, + clock_polarity: MasterControlStatus.ClockPolarity, + clock_phase: MasterControlStatus.ClockPhase, +}; + +pub fn set_config(config: SPIConfig) void { + const cs: MasterControlStatus = .{ + .chip_select = config.chip_select, + .chip_select_polarity = config.chip_select_polarity, + .clock_polarity = config.clock_polarity, + .clock_phase = config.clock_phase, + }; + + switch (config.chip_select) { + .@"0" => cs.chip_select_0 = config.chip_select, + .@"1" => cs.chip_select_1 = config.chip_select, + .@"2" => cs.chip_select_2 = config.chip_select, + } + + CS.set(cs); +} + +pub fn write_polled(bytes: []const u8) void { + { + var cs = CS.get(); + cs.transfer_active = true; + CS.set(cs); + } + + for (bytes) |byte| { + while (!CS.get().txd_has_space) {} + FIFO.set(@as(u32, byte)); + } + + // We need to flush before clearing TA + flush(); + + { + var cs = CS.get(); + cs.transfer_active = false; + CS.set(cs); + } +} + +pub fn read_polled(dst: []u8) void { + for (0..dst.len) |i| { + while (!CS.get().rxd_contains_data) {} + dst[i] = @truncate(FIFO.get()); + } +} + +pub fn flush() void { + while (CS.get().transfer_progress == .InProgress) {} +} + +fn writer_drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) !usize { + // We don't care about getting the "parent" + _ = io_w; + _ = splat; + + write_polled(data[0]); + + return data[0].len; +} + +fn writer_flush(io_w: *std.Io.Writer) !void { + // We don't care about getting the "parent" + _ = io_w; + + flush(); +} + +const writer_vtable: std.Io.Writer.VTable = .{ .drain = writer_drain, .flush = writer_flush }; +pub var writer = std.Io.Writer{ .buffer = undefined, .vtable = &writer_vtable }; + +fn stream(io_r: *std.Io.Reader, io_w: *std.Io.Writer, limit: std.Io.Limit) !usize { + // We don't care about getting the "parent" + _ = io_r; + + if (limit.toInt()) |max| { + for (0..max) |_| { + var buffer: [1]u8 = .{0}; + read_polled(&buffer); + try io_w.writeByte(buffer[0]); + } + + return max; + } else { + return std.Io.Reader.StreamError.ReadFailed; + } +} + +const reader_vtable: std.Io.Reader.VTable = .{ .stream = stream }; +pub var reader = std.Io.Reader{ .buffer = undefined, .seek = 0, .end = 0, .vtable = &reader_vtable };