1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
//! Types and definitions for PL011 UART.
//!
//! The official documentation: <https://developer.arm.com/documentation/ddi0183/latest>
use core::ptr::NonNull;
use tock_registers::{
interfaces::{Readable, Writeable},
register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
register_structs! {
/// Pl011 registers.
Pl011UartRegs {
/// Data Register.
(0x00 => dr: ReadWrite<u32>),
(0x04 => _reserved0),
/// Flag Register.
(0x18 => fr: ReadOnly<u32>),
(0x1c => _reserved1),
/// Control register.
(0x30 => cr: ReadWrite<u32>),
/// Interrupt FIFO Level Select Register.
(0x34 => ifls: ReadWrite<u32>),
/// Interrupt Mask Set Clear Register.
(0x38 => imsc: ReadWrite<u32>),
/// Raw Interrupt Status Register.
(0x3c => ris: ReadOnly<u32>),
/// Masked Interrupt Status Register.
(0x40 => mis: ReadOnly<u32>),
/// Interrupt Clear Register.
(0x44 => icr: WriteOnly<u32>),
(0x48 => @END),
}
}
/// The Pl011 Uart
///
/// The Pl011 Uart provides a programing interface for:
/// 1. Construct a new Pl011 UART instance
/// 2. Initialize the Pl011 UART
/// 3. Read a char from the UART
/// 4. Write a char to the UART
/// 5. Handle a UART IRQ
pub struct Pl011Uart {
base: NonNull<Pl011UartRegs>,
}
unsafe impl Send for Pl011Uart {}
unsafe impl Sync for Pl011Uart {}
impl Pl011Uart {
/// Constrcut a new Pl011 UART instance from the base address.
pub const fn new(base: *mut u8) -> Self {
Self {
base: NonNull::new(base).unwrap().cast(),
}
}
const fn regs(&self) -> &Pl011UartRegs {
unsafe { self.base.as_ref() }
}
/// Initializes the Pl011 UART.
///
/// It clears all irqs, sets fifo trigger level, enables rx interrupt, enables receives
pub fn init(&mut self) {
// clear all irqs
self.regs().icr.set(0x7ff);
// set fifo trigger level
self.regs().ifls.set(0); // 1/8 rxfifo, 1/8 txfifo.
// enable rx interrupt
self.regs().imsc.set(1 << 4); // rxim
// enable receive
self.regs().cr.set((1 << 0) | (1 << 8) | (1 << 9)); // tx enable, rx enable, uart enable
}
/// Output a char c to data register
pub fn putchar(&mut self, c: u8) {
while self.regs().fr.get() & (1 << 5) != 0 {}
self.regs().dr.set(c as u32);
}
/// Return a byte if pl011 has received, or it will return `None`.
pub fn getchar(&mut self) -> Option<u8> {
if self.regs().fr.get() & (1 << 4) == 0 {
Some(self.regs().dr.get() as u8)
} else {
None
}
}
/// Return true if pl011 has received an interrupt
pub fn is_receive_interrupt(&self) -> bool {
let pending = self.regs().mis.get();
pending & (1 << 4) != 0
}
/// Clear all interrupts
pub fn ack_interrupts(&mut self) {
self.regs().icr.set(0x7ff);
}
}