Support 16550 uarts for aarch64 debug output
This commit is contained in:
@@ -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> {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user