//! The Arm PL011 UART: QEMU virt's serial port, and the Pi 3's "UART0" //! (which the Pi wires to Bluetooth by default; the mini-UART is the other //! one). QEMU needs no setup at all; on real hardware the firmware has set //! the baud rate, so `init` only makes sure it's on, 8 bits, FIFOs on. use super::Uart; use crate::arch::aarch64::mmio; use core::sync::atomic::{AtomicUsize, Ordering}; const DR: usize = 0x00; // data register const FR: usize = 0x18; // flags const FR_TXFF: u32 = 1 << 5; // transmit FIFO full const LCRH: usize = 0x2c; // line control const CR: usize = 0x30; // control pub struct Pl011 { base: AtomicUsize, // physical address } impl Pl011 { pub const fn new(base: usize) -> Self { Pl011 { base: AtomicUsize::new(base) } } pub fn base(&self) -> usize { self.base.load(Ordering::Relaxed) } pub fn set_base(&self, base: usize) { self.base.store(base, Ordering::Relaxed); } /// 8N1 with FIFOs; transmit + receive + UART enable. pub fn init(&self) { let b = self.base(); mmio::write32(b + CR, 0); mmio::write32(b + LCRH, (3 << 5) | (1 << 4)); mmio::write32(b + CR, (1 << 9) | (1 << 8) | 1); } } impl Uart for Pl011 { fn putc(&self, byte: u8) { let b = self.base(); while mmio::read32(b + FR) & FR_TXFF != 0 { core::hint::spin_loop(); } mmio::write32(b + DR, byte as u32); } }