use core::{
fmt::Write,
ops::{Deref, DerefMut},
};
use bsp_define::console::ConsoleImpl;
use tock_registers::{
interfaces::{Readable, Writeable},
register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
use crate::{processor::cpu_relax, space::addr::Paddr};
register_bitfields! {
u32,
Data [
IO OFFSET(0) NUMBITS(32) []
],
Flags [
FR OFFSET(0) NUMBITS(32) [
TXFE = 0x80,
RXFF = 0x40,
TXFF = 0x20,
RXFE = 0x10,
BUSY = 0x08,
]
],
Baud [
BAUD OFFSET(0) NUMBITS(32) []
],
LineControl [
BRK OFFSET(0) NUMBITS(1) [],
PEN OFFSET(1) NUMBITS(1) [],
EPS OFFSET(2) NUMBITS(1) [],
STP2 OFFSET(3) NUMBITS(1) [],
FEN OFFSET(4) NUMBITS(1) [],
WLEN OFFSET(5) NUMBITS(2) [
WLEN_5 = 0,
WLEN_6 = 1,
WLEN_7 = 2,
WLEN_8 = 3,
],
SPS OFFSET(7) NUMBITS(1) [],
],
Control [
UARTEN OFFSET(0) NUMBITS(1) [],
SIREN OFFSET(1) NUMBITS(1) [],
IIRLP OFFSET(2) NUMBITS(1) [],
LPE OFFSET(7) NUMBITS(1) [],
TXE OFFSET(8) NUMBITS(1) [],
RXE OFFSET(9) NUMBITS(1) [],
DTR OFFSET(10) NUMBITS(1) [],
RTS OFFSET(11) NUMBITS(1) [],
OUT1 OFFSET(12) NUMBITS(1) [],
OUT2 OFFSET(13) NUMBITS(1) [],
RTSEN OFFSET(14) NUMBITS(1) [],
CTSEN OFFSET(15) NUMBITS(1) [],
]
}
register_structs! {
#[doc(hidden)]
pub Pl011Registers {
(0x00 => dr: WriteOnly<u32, Data::Register>),
(0x04 => _reserved),
(0x18 => fr: ReadOnly<u32, Flags::Register>),
(0x1c => _reserved2),
(0x24 => ibrd: ReadWrite<u32, Baud::Register>),
(0x28 => fbrd: ReadWrite<u32, Baud::Register>),
(0x2c => lcrh: ReadWrite<u32, LineControl::Register>),
(0x30 => cr: ReadWrite<u32, Control::Register>),
(0x34 => @END),
}
}
pub struct Pl011 {
regs: usize,
clock: u32,
baudrate: u32,
}
impl Pl011 {
pub const fn create(regs: Paddr, clock: u32, baudrate: u32) -> Self {
Self { regs: regs.to_io_const().to_value(), clock, baudrate }
}
fn ptr(&self) -> *mut Pl011Registers {
self.regs as *mut _
}
}
impl Pl011Registers {
#[inline]
fn putc(&self, c: u8) {
while self.fr.matches_all(Flags::FR::TXFF) {
cpu_relax();
}
self.dr.set(u32::from(c));
while self.fr.matches_all(Flags::FR::BUSY) {
cpu_relax();
}
}
}
impl Write for Pl011 {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
let buf = s.as_bytes();
let reg = &mut **self;
for &c in buf {
reg.putc(c);
}
Ok(())
}
}
impl ConsoleImpl for Pl011 {
fn init(&mut self) {
let mut temp = 16 * self.baudrate;
let divider = self.clock / temp;
let remainder = self.clock % temp;
temp = (8 * remainder) / self.baudrate;
let fraction = (temp >> 1) + (temp & 1);
let reg = &mut **self;
reg.cr.set(0);
reg.ibrd.set(divider);
reg.fbrd.set(fraction);
reg.lcrh.write(LineControl::WLEN::WLEN_8 + LineControl::FEN::SET);
reg.cr.write(
Control::UARTEN::SET + Control::TXE::SET + Control::RXE::SET + Control::RTS::SET,
);
}
}
impl Deref for Pl011 {
type Target = Pl011Registers;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr() }
}
}
impl DerefMut for Pl011 {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.ptr() }
}
}