Support 16550 uarts for aarch64 debug output

This commit is contained in:
Jeremy Soller
2024-10-29 14:06:00 -06:00
parent 161e578f29
commit 939c9567ee
4 changed files with 90 additions and 23 deletions
+2 -2
View File
@@ -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<DebugDisplay>>,
#[cfg(feature = "serial_debug")]
serial: MutexGuard<'a, Option<SerialPort>>,
serial: MutexGuard<'a, Option<SerialKind>>,
}
impl<'a> Writer<'a> {
+76 -8
View File
@@ -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<Option<SerialPort>> = Mutex::new(None);
pub enum SerialKind {
Ns16550u8(&'static mut uart_16550::SerialPort<Mmio<u8>>),
Ns16550u32(&'static mut uart_16550::SerialPort<Mmio<u32>>),
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<Option<SerialKind>> = 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::<Mmio<u32>>::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
+1 -7
View File
@@ -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);
+11 -6
View File
@@ -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,