#![no_std]
use core::fmt;
use zerocopy::FromBytes;
use volatile::{Volatile, ReadOnly, WriteOnly};
use memory::{BorrowedMappedPages, Mutable, PhysicalAddress, PAGE_SIZE, map_frame_range, MMIO_FLAGS};
#[derive(Debug, FromBytes)]
#[repr(C)]
pub struct Pl011_Regs {
pub uartdr: Volatile<u32>,
pub uartrsr: Volatile<u32>,
reserved0: [u32; 4],
pub uartfr: ReadOnly<u32>,
reserved1: u32,
pub uartilpr: Volatile<u32>,
pub uartibrd: Volatile<u32>,
pub uartfbrd: Volatile<u32>,
pub uartlcr_h: Volatile<u32>,
pub uartcr: Volatile<u32>,
pub uartifls: Volatile<u32>,
pub uartimsc: Volatile<u32>,
pub uartris: ReadOnly<u32>,
pub uartmis: ReadOnly<u32>,
pub uarticr: WriteOnly<u32>,
pub uartdmacr: Volatile<u32>,
reserved2: [u32; 997],
pub uartperiphid0: ReadOnly<u32>,
pub uartperiphid1: ReadOnly<u32>,
pub uartperiphid2: ReadOnly<u32>,
pub uartperiphid3: ReadOnly<u32>,
pub uartpcellid0: ReadOnly<u32>,
pub uartpcellid1: ReadOnly<u32>,
pub uartpcellid2: ReadOnly<u32>,
pub uartpcellid3: ReadOnly<u32>,
}
const UARTIMSC_RXIM: u32 = 1 << 4;
const UARTUCR_RXIC: u32 = 1 << 4;
const UARTLCR_FEN: u32 = 1 << 4;
const UARTCR_RX_ENABLED: u32 = 1 << 9;
const UARTCR_TX_ENABLED: u32 = 1 << 8;
const UARTCR_UART_ENABLED: u32 = 1 << 0;
const UARTFR_RX_BUF_EMPTY: u32 = 1 << 4;
const UARTFR_TX_BUF_FULL: u32 = 1 << 5;
pub struct Pl011 {
regs: BorrowedMappedPages<Pl011_Regs, Mutable>
}
impl core::fmt::Debug for Pl011 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.regs.fmt(f)
}
}
impl Pl011 {
pub fn new(base: PhysicalAddress) -> Result<Self, &'static str> {
let mapped_pages = map_frame_range(base, PAGE_SIZE, MMIO_FLAGS)?;
let mut this = Self {
regs: mapped_pages.into_borrowed_mut(0).map_err(|(_, e)| e)?,
};
this.enable_rx_interrupt(true);
this.set_fifo_mode(false);
Ok(this)
}
pub fn enable_rx_interrupt(&mut self, enable: bool) {
let mut reg = self.regs.uartimsc.read();
match enable {
true => reg |= UARTIMSC_RXIM,
false => reg &= !UARTIMSC_RXIM,
};
self.regs.uartimsc.write(reg);
}
pub fn acknowledge_rx_interrupt(&mut self) {
self.regs.uarticr.write(UARTUCR_RXIC);
}
pub fn set_fifo_mode(&mut self, enable: bool) {
let mut reg = self.regs.uartlcr_h.read();
match enable {
true => reg |= UARTLCR_FEN,
false => reg &= !UARTLCR_FEN,
};
self.regs.uartlcr_h.write(reg);
}
pub fn log_status(&self) {
let reg = self.regs.uartcr.read();
log::info!("RX enabled: {}", (reg & UARTCR_RX_ENABLED) > 0);
log::info!("TX enabled: {}", (reg & UARTCR_TX_ENABLED) > 0);
log::info!("UART enabled: {}", (reg & UARTCR_UART_ENABLED) > 0);
}
pub fn has_incoming_data(&self) -> bool {
let uartfr = self.regs.uartfr.read();
uartfr & UARTFR_RX_BUF_EMPTY == 0
}
pub fn read_byte(&self) -> u8 {
while !self.has_incoming_data() {}
self.regs.uartdr.read() as u8
}
pub fn read_bytes(&self, bytes: &mut [u8]) -> usize {
let mut read = 0;
while read < bytes.len() && self.has_incoming_data() {
bytes[read] = self.read_byte();
read += 1;
}
read
}
pub fn is_writeable(&self) -> bool {
let uartfr = self.regs.uartfr.read();
uartfr & UARTFR_TX_BUF_FULL == 0
}
pub fn write_byte(&mut self, data: u8) {
while !self.is_writeable() {}
self.regs.uartdr.write(data as u32);
}
pub fn write_bytes(&mut self, bytes: &[u8]) {
for b in bytes {
self.write_byte(*b);
}
}
}
impl fmt::Write for Pl011 {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.write_bytes(s.as_bytes());
Ok(())
}
}