use core::{num::NonZeroU32, ptr::NonNull};
use rdif_serial::{
BSerial, InterfaceRaw, SerialDyn, SetBackError, TIrqHandler, TSender, TransBytesError,
TransferError,
};
use tock_registers::{interfaces::*, register_bitfields, register_structs, registers::*};
use crate::{
Config, ConfigError, DataBits, InterruptMask, Parity, RawReciever, RawSender, StopBits,
};
register_bitfields! [
u32,
UARTDR [
DATA OFFSET(0) NUMBITS(8) [],
FE OFFSET(8) NUMBITS(1) [],
PE OFFSET(9) NUMBITS(1) [],
BE OFFSET(10) NUMBITS(1) [],
OE OFFSET(11) NUMBITS(1) []
],
UARTRSR_ECR [
FE OFFSET(0) NUMBITS(1) [],
PE OFFSET(1) NUMBITS(1) [],
BE OFFSET(2) NUMBITS(1) [],
OE OFFSET(3) NUMBITS(1) []
],
UARTFR [
CTS OFFSET(0) NUMBITS(1) [],
DSR OFFSET(1) NUMBITS(1) [],
DCD OFFSET(2) NUMBITS(1) [],
BUSY OFFSET(3) NUMBITS(1) [],
RXFE OFFSET(4) NUMBITS(1) [],
TXFF OFFSET(5) NUMBITS(1) [],
RXFF OFFSET(6) NUMBITS(1) [],
TXFE OFFSET(7) NUMBITS(1) [],
RI OFFSET(8) NUMBITS(1) []
],
UARTIBRD [
BAUD_DIVINT OFFSET(0) NUMBITS(16) []
],
UARTFBRD [
BAUD_DIVFRAC OFFSET(0) NUMBITS(6) []
],
UARTLCR_H [
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) [
FiveBit = 0,
SixBit = 1,
SevenBit = 2,
EightBit = 3
],
SPS OFFSET(7) NUMBITS(1) []
],
UARTCR [
UARTEN OFFSET(0) NUMBITS(1) [],
SIREN OFFSET(1) NUMBITS(1) [],
SIRLP OFFSET(2) NUMBITS(1) [],
LBE 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) []
],
UARTIFLS [
TXIFLSEL OFFSET(0) NUMBITS(3) [],
RXIFLSEL OFFSET(3) NUMBITS(3) []
],
UARTIS [
RIM OFFSET(0) NUMBITS(1) [],
CTSM OFFSET(1) NUMBITS(1) [],
DCDM OFFSET(2) NUMBITS(1) [],
DSRM OFFSET(3) NUMBITS(1) [],
RX OFFSET(4) NUMBITS(1) [],
TX OFFSET(5) NUMBITS(1) [],
RT OFFSET(6) NUMBITS(1) [],
FE OFFSET(7) NUMBITS(1) [],
PE OFFSET(8) NUMBITS(1) [],
BE OFFSET(9) NUMBITS(1) [],
OE OFFSET(10) NUMBITS(1) []
],
UARTDMACR [
RXDMAE OFFSET(0) NUMBITS(1) [],
TXDMAE OFFSET(1) NUMBITS(1) [],
DMAONERR OFFSET(2) NUMBITS(1) []
]
];
register_structs! {
pub Pl011Registers {
(0x000 => uartdr: ReadWrite<u32, UARTDR::Register>), (0x004 => uartrsr_ecr: ReadWrite<u32, UARTRSR_ECR::Register>), (0x008 => _reserved1), (0x018 => uartfr: ReadOnly<u32, UARTFR::Register>), (0x01c => _reserved2), (0x020 => uartilpr: ReadWrite<u32>), (0x024 => uartibrd: ReadWrite<u32, UARTIBRD::Register>), (0x028 => uartfbrd: ReadWrite<u32, UARTFBRD::Register>), (0x02c => uartlcr_h: ReadWrite<u32, UARTLCR_H::Register>), (0x030 => uartcr: ReadWrite<u32, UARTCR::Register>), (0x034 => uartifls: ReadWrite<u32, UARTIFLS::Register>), (0x038 => uartimsc: ReadWrite<u32, UARTIS::Register>), (0x03c => uartris: ReadOnly<u32, UARTIS::Register>), (0x040 => uartmis: ReadOnly<u32, UARTIS::Register>), (0x044 => uarticr: WriteOnly<u32, UARTIS::Register>), (0x048 => uartdmacr: ReadWrite<u32, UARTDMACR::Register>), (0x04c => _reserved3), (0x1000 => @END),
}
}
unsafe impl Sync for Pl011Registers {}
pub struct Pl011 {
base: Reg,
clock_freq: u32,
tx: Option<Pl011Sender>,
rx: Option<Pl011Reciever>,
irq: Option<Pl011IrqHandler>,
}
impl Pl011 {
pub fn new_no_clock(base: NonNull<u8>) -> Self {
let clock_freq = Self::detect_clock_frequency(base.as_ptr() as usize);
Self::new(base, clock_freq)
}
pub fn new(base: NonNull<u8>, clock_freq: u32) -> Self {
let base = Reg(base.cast());
Self {
base,
clock_freq,
tx: Some(Pl011Sender { base }),
rx: Some(Pl011Reciever { base }),
irq: Some(Pl011IrqHandler { base }),
}
}
pub fn new_boxed(base: NonNull<u8>, clock_freq: u32) -> BSerial {
let mut serial = Self::new(base, clock_freq);
serial.open();
SerialDyn::new_boxed(serial)
}
fn registers(&self) -> &Pl011Registers {
unsafe { &*self.base.0.as_ptr() }
}
fn detect_clock_frequency(base: usize) -> u32 {
let registers = unsafe { &*(base as *const Pl011Registers) };
use tock_registers::interfaces::Readable;
let ibrd = registers.uartibrd.read(UARTIBRD::BAUD_DIVINT);
if ibrd > 0 && ibrd <= 0xFFFF {
let estimated_clock = 16 * ibrd * 115200;
if (1_000_000..=100_000_000).contains(&estimated_clock) {
return estimated_clock;
}
}
24_000_000
}
fn set_baudrate_internal(&self, baudrate: u32) -> Result<(), ConfigError> {
let bauddiv = self.clock_freq / (16 * baudrate);
let remainder = self.clock_freq % (16 * baudrate);
let fbrd = (remainder * 64 + (16 * baudrate / 2)) / (16 * baudrate);
if bauddiv == 0 || bauddiv > 0xFFFF {
return Err(ConfigError::InvalidBaudrate);
}
self.registers()
.uartibrd
.write(UARTIBRD::BAUD_DIVINT.val(bauddiv));
self.registers()
.uartfbrd
.write(UARTFBRD::BAUD_DIVFRAC.val(fbrd));
Ok(())
}
fn set_data_bits_internal(&self, bits: DataBits) -> Result<(), ConfigError> {
let wlen = match bits {
DataBits::Five => UARTLCR_H::WLEN::FiveBit,
DataBits::Six => UARTLCR_H::WLEN::SixBit,
DataBits::Seven => UARTLCR_H::WLEN::SevenBit,
DataBits::Eight => UARTLCR_H::WLEN::EightBit,
};
self.registers().uartlcr_h.modify(wlen);
Ok(())
}
fn set_stop_bits_internal(&self, bits: StopBits) -> Result<(), ConfigError> {
match bits {
StopBits::One => self.registers().uartlcr_h.modify(UARTLCR_H::STP2::CLEAR),
StopBits::Two => self.registers().uartlcr_h.modify(UARTLCR_H::STP2::SET),
}
Ok(())
}
fn set_parity_internal(&self, parity: Parity) -> Result<(), ConfigError> {
match parity {
Parity::None => {
self.registers().uartlcr_h.modify(UARTLCR_H::PEN::CLEAR);
}
Parity::Odd => {
self.registers()
.uartlcr_h
.modify(UARTLCR_H::PEN::SET + UARTLCR_H::EPS::CLEAR + UARTLCR_H::SPS::CLEAR);
}
Parity::Even => {
self.registers()
.uartlcr_h
.modify(UARTLCR_H::PEN::SET + UARTLCR_H::EPS::SET + UARTLCR_H::SPS::CLEAR);
}
Parity::Mark => {
self.registers()
.uartlcr_h
.modify(UARTLCR_H::PEN::SET + UARTLCR_H::EPS::CLEAR + UARTLCR_H::SPS::SET);
}
Parity::Space => {
self.registers()
.uartlcr_h
.modify(UARTLCR_H::PEN::SET + UARTLCR_H::EPS::SET + UARTLCR_H::SPS::SET);
}
}
Ok(())
}
fn init(&self) {
self.registers().uartcr.modify(UARTCR::UARTEN::CLEAR);
while self.registers().uartfr.is_set(UARTFR::BUSY) {
core::hint::spin_loop();
}
self.registers().uartlcr_h.modify(UARTLCR_H::FEN::CLEAR);
self.registers().uartlcr_h.modify(UARTLCR_H::FEN::SET);
#[cfg(debug_assertions)]
{
let ifls = self.registers().uartifls.get();
let lcr_h = self.registers().uartlcr_h.get();
log::debug!("UART IFLS: 0x{:02x}, LCR_H: 0x{:02x}", ifls, lcr_h);
log::debug!(" FIFO enabled: {}", lcr_h & (1 << 4) != 0);
log::debug!(" RX trigger level: 1/8");
log::debug!(" TX trigger level: 1/2");
}
self.registers().uartimsc.set(0); self.registers()
.uartcr
.modify(UARTCR::UARTEN::SET + UARTCR::TXE::SET + UARTCR::RXE::SET);
}
pub fn task_tx(&mut self) -> Option<crate::Sender> {
self.tx.take().map(crate::Sender::Pl011Sender)
}
pub fn task_rx(&mut self) -> Option<crate::Reciever> {
self.rx.take().map(crate::Reciever::Pl011Reciever)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
struct Reg(NonNull<Pl011Registers>);
unsafe impl Send for Reg {}
impl Reg {
fn registers(&self) -> &Pl011Registers {
unsafe { self.0.as_ref() }
}
}
pub struct Pl011Sender {
base: Reg,
}
impl TSender for Pl011Sender {
fn write_byte(&mut self, byte: u8) -> bool {
RawSender::write_byte(self, byte)
}
}
impl RawSender for Pl011Sender {
fn write_byte(&mut self, byte: u8) -> bool {
if self.base.registers().uartfr.is_set(UARTFR::TXFF) {
return false;
}
self.base.registers().uartdr.set(byte as _);
true
}
}
pub struct Pl011Reciever {
base: Reg,
}
impl RawReciever for Pl011Reciever {
fn read_byte(&mut self) -> Option<Result<u8, TransferError>> {
if self.base.registers().uartfr.is_set(UARTFR::RXFE) {
return None;
}
let dr = self.base.registers().uartdr.extract();
let data = dr.read(UARTDR::DATA) as u8;
if dr.is_set(UARTDR::FE) {
return Some(Err(TransferError::Framing));
}
if dr.is_set(UARTDR::PE) {
return Some(Err(TransferError::Parity));
}
if dr.is_set(UARTDR::OE) {
return Some(Err(TransferError::Overrun(data)));
}
if dr.is_set(UARTDR::BE) {
return Some(Err(TransferError::Break));
}
Some(Ok(data))
}
fn read_bytes(&mut self, bytes: &mut [u8]) -> Result<usize, TransBytesError> {
let mut count = 0;
let mut overrun_data = None;
for byte in bytes.iter_mut() {
match self.read_byte() {
Some(Ok(b)) => {
*byte = b;
}
Some(Err(TransferError::Overrun(b))) => {
overrun_data = Some(b);
*byte = b;
}
Some(Err(e)) => {
return Err(TransBytesError {
bytes_transferred: count,
kind: e,
});
}
None => {
if let Some(data) = overrun_data {
count = count.saturating_sub(1);
return Err(TransBytesError {
bytes_transferred: count,
kind: TransferError::Overrun(data),
});
}
break;
}
}
count += 1;
}
Ok(count)
}
}
pub struct Pl011IrqHandler {
base: Reg,
}
unsafe impl Sync for Pl011IrqHandler {}
impl TIrqHandler for Pl011IrqHandler {
fn clean_interrupt_status(&self) -> InterruptMask {
let mis = self.base.registers().uartmis.extract();
let mut mask = InterruptMask::empty();
if mis.is_set(UARTIS::RX) {
mask |= InterruptMask::RX_AVAILABLE;
}
if mis.is_set(UARTIS::TX) {
mask |= InterruptMask::TX_EMPTY;
}
self.base.registers().uarticr.set(mis.get());
mask
}
}
impl InterfaceRaw for Pl011 {
type IrqHandler = Pl011IrqHandler;
type Sender = crate::Sender;
type Reciever = crate::Reciever;
fn name(&self) -> &str {
"PL011 UART"
}
fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
use tock_registers::interfaces::Readable;
let original_enable = self.registers().uartcr.is_set(UARTCR::UARTEN); self.registers().uartcr.modify(UARTCR::UARTEN::CLEAR);
while self.registers().uartfr.is_set(UARTFR::BUSY) {
core::hint::spin_loop();
}
self.registers().uartlcr_h.modify(UARTLCR_H::FEN::CLEAR);
if let Some(baudrate) = config.baudrate {
self.set_baudrate_internal(baudrate)?;
}
if let Some(data_bits) = config.data_bits {
self.set_data_bits_internal(data_bits)?;
}
if let Some(stop_bits) = config.stop_bits {
self.set_stop_bits_internal(stop_bits)?;
}
if let Some(parity) = config.parity {
self.set_parity_internal(parity)?;
}
self.registers().uartlcr_h.modify(UARTLCR_H::FEN::SET);
if original_enable {
self.registers().uartcr.modify(UARTCR::UARTEN::SET); }
Ok(())
}
fn baudrate(&self) -> u32 {
let ibrd = self.registers().uartibrd.read(UARTIBRD::BAUD_DIVINT);
let fbrd = self.registers().uartfbrd.read(UARTFBRD::BAUD_DIVFRAC);
let divisor = ibrd * 64 + fbrd;
if divisor == 0 {
return 0;
}
self.clock_freq * 64 / (16 * divisor)
}
fn data_bits(&self) -> DataBits {
let wlen = self.registers().uartlcr_h.read(UARTLCR_H::WLEN);
match wlen {
0 => DataBits::Five,
1 => DataBits::Six,
2 => DataBits::Seven,
3 => DataBits::Eight,
_ => DataBits::Eight, }
}
fn stop_bits(&self) -> StopBits {
if self.registers().uartlcr_h.is_set(UARTLCR_H::STP2) {
StopBits::Two
} else {
StopBits::One
}
}
fn parity(&self) -> Parity {
if !self.registers().uartlcr_h.is_set(UARTLCR_H::PEN) {
Parity::None
} else if self.registers().uartlcr_h.is_set(UARTLCR_H::SPS) {
if self.registers().uartlcr_h.is_set(UARTLCR_H::EPS) {
Parity::Space
} else {
Parity::Mark
}
} else {
if self.registers().uartlcr_h.is_set(UARTLCR_H::EPS) {
Parity::Even
} else {
Parity::Odd
}
}
}
fn open(&mut self) {
self.init()
}
fn close(&mut self) {
self.registers().uartcr.modify(UARTCR::UARTEN::CLEAR);
}
fn clock_freq(&self) -> Option<NonZeroU32> {
self.clock_freq.try_into().ok()
}
fn enable_loopback(&mut self) {
self.registers().uartcr.modify(UARTCR::LBE::SET);
}
fn disable_loopback(&mut self) {
self.registers().uartcr.modify(UARTCR::LBE::CLEAR);
}
fn is_loopback_enabled(&self) -> bool {
self.registers().uartcr.is_set(UARTCR::LBE)
}
fn set_irq_mask(&mut self, mask: InterruptMask) {
let mut imsc = 0;
if mask.contains(InterruptMask::RX_AVAILABLE) {
imsc += UARTIS::RX::SET.value;
}
if mask.contains(InterruptMask::TX_EMPTY) {
imsc += UARTIS::TX::SET.value;
}
self.registers().uartimsc.set(imsc);
}
fn get_irq_mask(&self) -> InterruptMask {
let imsc = self.registers().uartimsc.extract();
let mut mask = InterruptMask::empty();
if imsc.is_set(UARTIS::RX) {
mask |= InterruptMask::RX_AVAILABLE;
}
if imsc.is_set(UARTIS::TX) {
mask |= InterruptMask::TX_EMPTY;
}
mask
}
fn base_addr(&self) -> usize {
self.base.0.as_ptr() as usize
}
fn irq_handler(&mut self) -> Option<Self::IrqHandler> {
self.irq.take()
}
fn take_tx(&mut self) -> Option<Self::Sender> {
self.task_tx()
}
fn take_rx(&mut self) -> Option<Self::Reciever> {
self.task_rx()
}
fn set_tx(&mut self, tx: Self::Sender) -> Result<(), SetBackError> {
let tx = match tx {
crate::Sender::Pl011Sender(s) => s,
_ => {
return Err(SetBackError::new(
self.base.0.as_ptr() as _,
0, ));
}
};
if self.base != tx.base {
return Err(SetBackError::new(
self.base.0.as_ptr() as _,
tx.base.0.as_ptr() as _,
));
}
self.tx = Some(tx);
Ok(())
}
fn set_rx(&mut self, rx: Self::Reciever) -> Result<(), SetBackError> {
let rx = match rx {
crate::Reciever::Pl011Reciever(r) => r,
_ => {
return Err(SetBackError::new(
self.base.0.as_ptr() as _,
0, ));
}
};
if self.base != rx.base {
return Err(SetBackError::new(
self.base.0.as_ptr() as _,
rx.base.0.as_ptr() as _,
));
}
self.rx = Some(rx);
Ok(())
}
}
impl Pl011 {
pub fn enable_fifo(&self, enable: bool) {
if enable {
self.registers().uartlcr_h.modify(UARTLCR_H::FEN::SET);
} else {
self.registers().uartlcr_h.modify(UARTLCR_H::FEN::CLEAR);
}
}
pub fn set_fifo_trigger_level(&self, rx_level: u8, tx_level: u8) {
let rx_iflsel = match rx_level {
0..=2 => 0b000, 3..=4 => 0b001, 5..=8 => 0b010, 9..=12 => 0b011, _ => 0b100, };
let tx_iflsel = match tx_level {
0..=2 => 0b000, 3..=4 => 0b001, 5..=8 => 0b010, 9..=12 => 0b011, _ => 0b100, };
self.registers()
.uartifls
.write(UARTIFLS::RXIFLSEL.val(rx_iflsel) + UARTIFLS::TXIFLSEL.val(tx_iflsel));
}
}