1#![no_std]
8#![deny(clippy::undocumented_unsafe_blocks)]
9#![deny(unsafe_op_in_unsafe_fn)]
10
11#[cfg(feature = "embedded-io")]
12mod embedded_io;
13pub mod registers;
14
15use crate::registers::{Fcr, Lcr, Lsr, Registers, Usr};
16use core::{fmt, hint::spin_loop};
17use safe_mmio::{UniqueMmioPointer, field, field_shared};
18use thiserror::Error;
19
20pub struct SynopsysUart<'a> {
22 registers: UniqueMmioPointer<'a, Registers>,
23}
24
25impl<'a> SynopsysUart<'a> {
26 pub const fn new(registers: UniqueMmioPointer<'a, Registers>) -> Self {
28 Self { registers }
29 }
30
31 pub fn configure(&mut self, baud_rate: u32, serial_clock: u32) {
37 while field_shared!(self.registers, usr)
39 .read()
40 .contains(Usr::BUSY)
41 {
42 spin_loop();
43 }
44
45 field!(self.registers, lcr).write(Lcr::DLAB);
47
48 let divisor = serial_clock / (16 * baud_rate);
50 let fractional = (serial_clock % (16 * baud_rate)) / baud_rate;
51 field!(self.registers, dlf).write(fractional);
52 field!(self.registers, rbr_thr_dll).write(divisor & 0xff);
53 field!(self.registers, dlh_ier).write(divisor >> 8);
54
55 field!(self.registers, lcr).write(Lcr::DLS_8);
57
58 field!(self.registers, iir_fcr).write(Fcr::FIFOE.bits());
60 }
61
62 pub fn is_tx_fifo_full(&self) -> bool {
66 !field_shared!(self.registers, usr)
67 .read()
68 .contains(Usr::TFNF)
69 }
70
71 pub fn write_word(&mut self, byte: u8) {
76 while self.is_tx_fifo_full() {
78 spin_loop();
79 }
80
81 field!(self.registers, rbr_thr_dll).write(byte.into());
82 }
83
84 pub fn flush(&self) {
86 while !field_shared!(self.registers, usr).read().contains(Usr::TFE) {
87 spin_loop();
88 }
89 }
90
91 pub fn is_rx_fifo_empty(&self) -> bool {
95 !field_shared!(self.registers, usr)
96 .read()
97 .contains(Usr::RFNE)
98 }
99
100 pub fn read_word(&mut self) -> Result<Option<u8>, UartError> {
105 let lsr = field!(self.registers, lsr).read();
106
107 if lsr.contains(Lsr::BI) {
110 Err(UartError::Break)
111 } else if lsr.contains(Lsr::FE) {
112 Err(UartError::Framing)
113 } else if lsr.contains(Lsr::PE) {
114 Err(UartError::Parity)
115 } else if lsr.contains(Lsr::OE) {
116 Err(UartError::Overrun)
117 } else if !lsr.contains(Lsr::DR) {
118 Ok(None)
119 } else {
120 Ok(Some(field!(self.registers, rbr_thr_dll).read() as u8))
121 }
122 }
123}
124
125unsafe impl Sync for SynopsysUart<'_> {}
128
129impl fmt::Write for SynopsysUart<'_> {
130 fn write_str(&mut self, s: &str) -> fmt::Result {
131 for byte in s.as_bytes() {
132 self.write_word(*byte);
133 }
134 Ok(())
135 }
136}
137
138#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
140pub enum UartError {
141 #[error("Framing error")]
143 Framing,
144 #[error("Parity error")]
146 Parity,
147 #[error("Overrun")]
149 Overrun,
150 #[error("Break")]
152 Break,
153}