//! PS UART register module. use arbitrary_int::u6; pub const UART_0_BASE: usize = 0xE000_0000; pub const UART_1_BASE: usize = 0xE000_1000; #[bitbybit::bitenum(u3, exhaustive = true)] pub enum Parity { Even = 0b000, Odd = 0b001, /// Forced to 0 (Space) ForcedTo0 = 0b010, /// Forced to 1 (Mark) ForcedTo1 = 0b011, NoParity = 0b100, NoParityAlt0 = 0b101, NoParityAlt1 = 0b110, NoParityAlt2 = 0b111, } #[bitbybit::bitenum(u2, exhaustive = true)] #[derive(Default, Debug, PartialEq, Eq)] pub enum Chrl { SixBits = 0b11, SevenBits = 0b10, #[default] EightBits = 0b00, EightBitsAlt = 0b01, } #[bitbybit::bitenum(u1, exhaustive = true)] #[derive(Default, Debug, PartialEq, Eq)] pub enum ClkSel { #[default] UartRefClk = 0b0, UartRefClkDiv8 = 0b1, } #[bitbybit::bitenum(u2)] #[derive(Default, Debug, PartialEq, Eq)] pub enum Stopbits { #[default] One = 0b00, OnePointFive = 0b01, Two = 0b10, } #[bitbybit::bitenum(u2, exhaustive = true)] #[derive(Debug, Default)] pub enum ChMode { #[default] Normal = 0b00, AutoEcho = 0b01, LocalLoopback = 0b10, RemoteLoopback = 0b11, } #[bitbybit::bitfield(u32)] #[derive(Debug)] pub struct Ctrl { /// Stop transmitter break. #[bit(8, rw)] stopbrk: bool, /// Start transmitter break. #[bit(7, rw)] startbrk: bool, /// Restart receiver timeout counter. #[bit(6, rw)] rstto: bool, /// TX disable. If this is 1, TX is disabled, regardless of TXEN. #[bit(5, rw)] tx_dis: bool, /// TX enable. TX will be enabled if this bit is 1 and the TXDIS is 0. #[bit(4, rw)] tx_en: bool, /// RX disable. If this is 1, RX is disabled, regardless of RXEN. #[bit(3, rw)] rx_dis: bool, /// RX enable. RX will be enabled if this bit is 1 and the RXDIS is 0. #[bit(2, rw)] rx_en: bool, /// TX soft reset. #[bit(1, rw)] tx_rst: bool, /// RX soft reset. #[bit(0, rw)] rx_rst: bool, } #[bitbybit::bitfield(u32, default = 0x0)] #[derive(Debug)] pub struct Mode { #[bits(8..=9, rw)] chmode: ChMode, #[bits(6..=7, rw)] nbstop: Option, #[bits(3..=5, rw)] par: Parity, /// Char length. #[bits(1..=2, rw)] chrl: Chrl, #[bit(0, rw)] clksel: ClkSel, } #[bitbybit::bitfield(u32, default = 0x0)] #[derive(Debug)] pub struct Baudgen { #[bits(0..=15, rw)] cd: u16, } #[bitbybit::bitfield(u32, default = 0x0)] #[derive(Debug)] pub struct BaudRateDiv { #[bits(0..=7, rw)] bdiv: u8, } #[bitbybit::bitfield(u32)] #[derive(Debug)] pub struct Fifo { #[bits(0..=7, rw)] fifo: u8, } #[bitbybit::bitenum(u1, exhaustive = true)] pub enum Ttrig { LessThanTTrig = 0b0, GreaterEqualTTrig = 0b1, } #[bitbybit::bitfield(u32)] #[derive(Debug)] pub struct Status { #[bit(14, r)] tx_near_full: bool, #[bit(13, r)] tx_trig: Ttrig, #[bit(12, r)] flowdel: bool, /// Transmitter state machine active. #[bit(11, r)] tx_active: bool, /// Receiver state machine active. #[bit(10, r)] rx_active: bool, #[bit(4, r)] tx_full: bool, #[bit(3, r)] tx_empty: bool, #[bit(2, r)] rx_full: bool, #[bit(1, r)] rx_empty: bool, /// RX FIFO trigger level was reached. #[bit(0, r)] rx_trg: bool, } #[bitbybit::bitfield(u32, default = 0x0)] #[derive(Debug)] pub struct InterruptControl { #[bit(12, w)] tx_over: bool, #[bit(11, w)] tx_near_full: bool, #[bit(10, w)] tx_trig: bool, #[bit(9, w)] rx_dms: bool, /// Receiver timeout error interrupt. #[bit(8, w)] rx_timeout: bool, #[bit(7, w)] rx_parity: bool, #[bit(6, w)] rx_framing: bool, #[bit(5, w)] rx_over: bool, #[bit(4, w)] tx_full: bool, #[bit(3, w)] tx_empty: bool, #[bit(2, w)] rx_full: bool, #[bit(1, w)] rx_empty: bool, #[bit(0, w)] rx_trg: bool, } #[bitbybit::bitfield(u32)] #[derive(Debug)] pub struct FifoTrigger { #[bits(0..=5, rw)] trig: u6, } #[bitbybit::bitfield(u32)] #[derive(Debug)] pub struct InterruptMask { #[bit(12, r)] tx_over: bool, #[bit(11, r)] tx_near_full: bool, #[bit(10, r)] tx_trig: bool, #[bit(9, r)] rx_dms: bool, /// Receiver timeout error interrupt. #[bit(8, r)] rx_timeout: bool, #[bit(7, r)] rx_parity: bool, #[bit(6, r)] rx_framing: bool, #[bit(5, r)] rx_over: bool, #[bit(4, r)] tx_full: bool, #[bit(3, r)] tx_empty: bool, #[bit(2, r)] rx_full: bool, #[bit(1, r)] rx_empty: bool, /// RX FIFO trigger level reached. #[bit(0, r)] rx_trg: bool, } #[bitbybit::bitfield(u32, default = 0x0)] #[derive(Debug)] pub struct InterruptStatus { #[bit(12, rw)] tx_over: bool, #[bit(11, rw)] tx_near_full: bool, #[bit(10, rw)] tx_trig: bool, #[bit(9, rw)] rx_dms: bool, /// Receiver timeout error interrupt. #[bit(8, rw)] rx_timeout: bool, #[bit(7, rw)] rx_parity: bool, #[bit(6, rw)] rx_framing: bool, #[bit(5, rw)] rx_over: bool, #[bit(4, rw)] tx_full: bool, #[bit(3, rw)] tx_empty: bool, #[bit(2, rw)] rx_full: bool, #[bit(1, rw)] rx_empty: bool, /// RX FIFO trigger level reached. #[bit(0, rw)] rx_trg: bool, } impl InterruptStatus { pub fn new_for_clearing_rx_errors() -> Self { Self::builder() .with_tx_over(false) .with_tx_near_full(false) .with_tx_trig(false) .with_rx_dms(false) .with_rx_timeout(false) .with_rx_parity(true) .with_rx_framing(true) .with_rx_over(true) .with_tx_full(false) .with_tx_empty(false) .with_rx_full(false) .with_rx_empty(false) .with_rx_trg(false) .build() } } #[derive(derive_mmio::Mmio)] #[repr(C)] pub struct Uart { /// Control Register cr: Ctrl, /// Mode register mr: Mode, /// Interrupt enable register #[mmio(Write)] ier: InterruptControl, /// Interrupt disable register #[mmio(Write)] idr: InterruptControl, /// Interrupt mask register, showing enabled interrupts. #[mmio(PureRead)] imr: InterruptMask, /// Interrupt status register #[mmio(PureRead, Write)] isr: InterruptStatus, /// Baudgen register baudgen: Baudgen, /// RX timeout register rx_tout: u32, /// RX FIFO trigger level register rx_fifo_trigger: FifoTrigger, /// Modem control register modem_cr: u32, /// Modem status register modem_sr: u32, /// Channel status register #[mmio(PureRead)] sr: Status, /// FIFO register #[mmio(Read, Write)] fifo: Fifo, /// Baud rate divider register baud_rate_div: BaudRateDiv, /// Flow control delay register flow_delay: u32, _reserved: [u32; 2], /// TX fifo trigger level tx_fifo_trigger: FifoTrigger, } static_assertions::const_assert_eq!(core::mem::size_of::(), 0x48); impl Uart { /// Create a new UART MMIO instance for uart0 at address 0xE000_0000. /// /// # Safety /// /// This API can be used to potentially create a driver to the same peripheral structure /// from multiple threads. The user must ensure that concurrent accesses are safe and do not /// interfere with each other. pub const unsafe fn new_mmio_fixed_0() -> MmioUart<'static> { unsafe { Self::new_mmio_at(UART_0_BASE) } } /// Create a new UART MMIO instance for uart1 at address 0xE000_1000. /// /// # Safety /// /// This API can be used to potentially create a driver to the same peripheral structure /// from multiple threads. The user must ensure that concurrent accesses are safe and do not /// interfere with each other. pub const unsafe fn new_mmio_fixed_1() -> MmioUart<'static> { unsafe { Self::new_mmio_at(UART_1_BASE) } } }