From 939c9567eebfbb21a29a245b3341c3149e56eca1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 29 Oct 2024 14:06:00 -0600 Subject: [PATCH] Support 16550 uarts for aarch64 debug output --- src/arch/aarch64/debug.rs | 4 +- src/arch/aarch64/device/serial.rs | 84 ++++++++++++++++++++++++--- src/arch/aarch64/device/uart_pl011.rs | 8 +-- src/dtb/mod.rs | 17 ++++-- 4 files changed, 90 insertions(+), 23 deletions(-) diff --git a/src/arch/aarch64/debug.rs b/src/arch/aarch64/debug.rs index f525c0428e..41926056b3 100644 --- a/src/arch/aarch64/debug.rs +++ b/src/arch/aarch64/debug.rs @@ -4,7 +4,7 @@ use spin::MutexGuard; use crate::log::{Log, LOG}; #[cfg(feature = "serial_debug")] -use super::device::{serial::COM1, uart_pl011::SerialPort}; +use super::device::serial::{COM1, SerialKind}; #[cfg(feature = "graphical_debug")] use crate::devices::graphical_debug::{DebugDisplay, DEBUG_DISPLAY}; @@ -13,7 +13,7 @@ pub struct Writer<'a> { #[cfg(feature = "graphical_debug")] display: MutexGuard<'a, Option>, #[cfg(feature = "serial_debug")] - serial: MutexGuard<'a, Option>, + serial: MutexGuard<'a, Option>, } impl<'a> Writer<'a> { diff --git a/src/arch/aarch64/device/serial.rs b/src/arch/aarch64/device/serial.rs index a9f6e9584e..b414581d82 100644 --- a/src/arch/aarch64/device/serial.rs +++ b/src/arch/aarch64/device/serial.rs @@ -1,20 +1,68 @@ use alloc::boxed::Box; use spin::Mutex; -use crate::{device::uart_pl011::SerialPort, interrupt::irq::trigger}; use crate::{ arch::device::irqchip::ic_for_chip, + device::uart_pl011, + devices::uart_16550, dtb::{ diag_uart_range, irqchip::{register_irq, InterruptHandler, IRQ_CHIP}, }, + interrupt::irq::trigger, + scheme::debug::{debug_input, debug_notify}, }; use byteorder::{ByteOrder, BE}; use fdt::Fdt; use log::{error, info}; +use syscall::Mmio; -pub static COM1: Mutex> = Mutex::new(None); +pub enum SerialKind { + Ns16550u8(&'static mut uart_16550::SerialPort>), + Ns16550u32(&'static mut uart_16550::SerialPort>), + Pl011(uart_pl011::SerialPort), +} + +impl SerialKind { + pub fn enable_irq(&mut self) { + //TODO: implement for NS16550 + match self { + Self::Ns16550u8(_) => {}, + Self::Ns16550u32(_) => {}, + Self::Pl011(inner) => inner.enable_irq(), + } + } + + pub fn receive(&mut self) { + //TODO: make PL011 receive work the same way as NS16550 + match self { + Self::Ns16550u8(inner) => { + while let Some(c) = inner.receive() { + debug_input(c); + } + debug_notify(); + }, + Self::Ns16550u32(inner) => { + while let Some(c) = inner.receive() { + debug_input(c); + } + debug_notify(); + }, + Self::Pl011(inner) => inner.receive(), + } + } + + pub fn write(&mut self, buf: &[u8]) { + match self { + Self::Ns16550u8(inner) => inner.write(buf), + Self::Ns16550u32(inner) => inner.write(buf), + Self::Pl011(inner) => inner.write(buf), + } + } +} + +pub static COM1: Mutex> = Mutex::new(None); pub struct Com1Irq {} @@ -35,18 +83,38 @@ pub unsafe fn init_early(dtb: &Fdt) { return; } - if let Some((phys, _size, skip_init, cts, _)) = diag_uart_range(dtb) { + if let Some((phys, size, skip_init, cts, compatible)) = diag_uart_range(dtb) { let virt = crate::PHYS_OFFSET + phys; - { - let mut serial_port = SerialPort::new(virt, skip_init, cts); - serial_port.init(false); - *COM1.lock() = Some(serial_port); + let serial_opt = if compatible.contains("arm,pl011") { + let mut serial_port = uart_pl011::SerialPort::new(virt, cts); + if !skip_init { + serial_port.init(false); + } + Some(SerialKind::Pl011(serial_port)) + } else if compatible.contains("ns16550a") || compatible.contains("snps,dw-apb-uart") { + //TODO: get actual register size from device tree + let serial_port = uart_16550::SerialPort::>::new(virt); + if !skip_init { + serial_port.init(); + } + Some(SerialKind::Ns16550u32(serial_port)) + } else { + None + }; + match serial_opt { + Some(serial) => { + info!("UART {:?} at {:#X} size {:#X}", compatible, virt, size); + *COM1.lock() = Some(serial); + }, + None => { + log::warn!("UART {:?} at {:#X} size {:#X}: no driver found", compatible, virt, size); + } } - info!("UART at {:X}", virt); } } pub unsafe fn init(fdt: &Fdt) { + //TODO: find actual serial device, not just any PL011 if let Some(node) = fdt.find_compatible(&["arm,pl011"]) { let interrupts = node.property("interrupts").unwrap(); let irq = interrupts diff --git a/src/arch/aarch64/device/uart_pl011.rs b/src/arch/aarch64/device/uart_pl011.rs index 69c91bb8cf..8e6c98a25b 100644 --- a/src/arch/aarch64/device/uart_pl011.rs +++ b/src/arch/aarch64/device/uart_pl011.rs @@ -106,12 +106,11 @@ pub struct SerialPort { dma_ctrl_reg: u8, ifls: u32, fifo_size: u32, - skip_init: bool, cts_event_walkaround: bool, } impl SerialPort { - pub const fn new(base: usize, skip_init: bool, cts_event_walkaround: bool) -> SerialPort { + pub const fn new(base: usize, cts_event_walkaround: bool) -> SerialPort { SerialPort { base: base, data_reg: 0x00, @@ -129,7 +128,6 @@ impl SerialPort { dma_ctrl_reg: 0x48, ifls: 0x12, // RX4_8 | TX4_8 fifo_size: 32, - skip_init: skip_init, cts_event_walkaround: cts_event_walkaround, } } @@ -145,10 +143,6 @@ impl SerialPort { } pub fn init(&mut self, with_irq: bool) { - if self.skip_init { - return; - } - //Disable UART first self.write_reg(self.ctrl_reg, 0x0); diff --git a/src/dtb/mod.rs b/src/dtb/mod.rs index 910993f322..408410c7b8 100644 --- a/src/dtb/mod.rs +++ b/src/dtb/mod.rs @@ -90,9 +90,14 @@ pub fn register_dev_memory_ranges(dt: &Fdt) { } } - let soc_node = dt.find_node("/soc").unwrap(); - let reg = soc_node.ranges().unwrap(); - + let Some(soc_node) = dt.find_node("/soc") else { + log::warn!("failed to find /soc in devicetree"); + return; + }; + let Some(reg) = soc_node.ranges() else { + log::warn!("devicetree /soc has no ranges"); + return; + }; for chunk in reg { log::debug!( "dev mem 0x{:08x} 0x{:08x} 0x{:08x} 0x{:08x}", @@ -133,12 +138,12 @@ pub fn diag_uart_range<'a>(dtb: &'a Fdt) -> Option<(usize, usize, bool, bool, &' .property("compatible") .and_then(NodeProperty::as_str)?; - let mut reg = uart_node.reg().unwrap(); - let memory = reg.nth(0).unwrap(); + let mut reg = uart_node.reg()?; + let memory = reg.nth(0)?; Some(( memory.starting_address as usize, - memory.size.unwrap(), + memory.size?, skip_init, cts_event_walkaround, compatible,