any_uart/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3use core::{
4    ptr::NonNull,
5    sync::atomic::{Ordering, fence},
6};
7
8#[cfg(feature = "alloc")]
9extern crate alloc;
10
11#[cfg(feature = "alloc")]
12mod api;
13
14pub use core::fmt::Write;
15pub use embedded_hal_nb::nb::block;
16pub use embedded_hal_nb::serial::ErrorKind;
17
18use aux_mini::AuxMini;
19pub use fdt_parser::Node;
20use fdt_parser::{Chosen, Fdt};
21use ns16550::Ns16550;
22use pl011::Pl011;
23
24mod aux_mini;
25mod ns16550;
26mod pl011;
27
28pub type Error = embedded_hal_nb::nb::Error<ErrorKind>;
29pub type FnPhysToVirt = fn(usize) -> *mut u8;
30
31pub struct Uart {
32    data: UartData,
33    pub tx: Option<Sender>,
34    pub rx: Option<Receiver>,
35    op: UartOp,
36}
37
38impl Uart {
39    fn _new<C: Console>(data: UartData) -> Self {
40        let op = C::to_op();
41
42        Self {
43            data,
44            tx: Some(Sender { uart: data, op }),
45            rx: Some(Receiver { uart: data, op }),
46            op,
47        }
48    }
49
50    pub fn new_by_fdt_node(node: &Node<'_>, f: FnPhysToVirt) -> Option<Self> {
51        let reg = node.reg()?.next()?;
52
53        let io_kind = IoKind::Mmio32;
54
55        // TODO: support io kind detect
56
57        let uart = UartData::new(reg.address, io_kind, f);
58
59        for c in node.compatibles() {
60            macro_rules! of_uart {
61                ($name:ty, $compatible:expr) => {
62                    for want in $compatible {
63                        if c.contains(want) {
64                            return Some(Uart::_new::<$name>(uart));
65                        }
66                    }
67                };
68            }
69
70            of_uart!(AuxMini, ["brcm,bcm2835-aux-uart"]);
71            of_uart!(Pl011, ["arm,pl011", "arm,primecell"]);
72            of_uart!(Ns16550, ["snps,dw-apb-uart"]);
73        }
74        None
75    }
76
77    pub fn set_irq_enable(&mut self, enable: bool) {
78        (self.op.set_irq_enable)(self.data, enable);
79    }
80
81    pub fn get_irq_enable(&mut self) -> bool {
82        (self.op.get_irq_enable)(self.data)
83    }
84
85    pub fn clean_irq_event(&mut self, event: IrqEvent) {
86        (self.op.clean_irq_event)(self.data, event);
87    }
88
89    pub fn get_irq_event(&mut self) -> IrqEvent {
90        (self.op.get_irq_event)(self.data)
91    }
92}
93
94#[derive(Debug, Clone, Copy, Default)]
95pub struct IrqEvent {
96    pub rx: bool,
97    pub tx: bool,
98}
99
100#[derive(Clone, Copy)]
101struct UartOp {
102    can_put: fn(UartData) -> bool,
103    put: fn(UartData, u8) -> Result<(), ErrorKind>,
104    can_get: fn(UartData) -> bool,
105    get: fn(UartData) -> Result<u8, ErrorKind>,
106    set_irq_enable: fn(UartData, bool),
107    get_irq_enable: fn(UartData) -> bool,
108    get_irq_event: fn(UartData) -> IrqEvent,
109    clean_irq_event: fn(UartData, IrqEvent),
110}
111
112pub struct Sender {
113    uart: UartData,
114    op: UartOp,
115}
116
117impl Sender {
118    pub fn write(&mut self, word: u8) -> Result<(), Error> {
119        if !self.can_write() {
120            return Err(Error::WouldBlock);
121        }
122        fence(Ordering::Release);
123        unsafe { self.write_uncheck(word)? };
124        Ok(())
125    }
126
127    pub fn can_write(&self) -> bool {
128        (self.op.can_put)(self.uart)
129    }
130
131    /// Write a byte to the UART.
132    ///
133    /// # Safety
134    ///
135    /// Need to check the UART status register before writing.
136    pub unsafe fn write_uncheck(&mut self, word: u8) -> Result<(), ErrorKind> {
137        (self.op.put)(self.uart, word)
138    }
139
140    pub fn write_str_blocking(&mut self, s: &str) -> core::fmt::Result {
141        for c in s.bytes() {
142            let _ = block!(self.write(c));
143        }
144        Ok(())
145    }
146
147    pub fn mmio(&self) -> usize {
148        self.uart.base
149    }
150}
151
152pub struct Receiver {
153    uart: UartData,
154    op: UartOp,
155}
156
157impl Receiver {
158    pub fn read(&mut self) -> Result<u8, Error> {
159        if !self.can_read() {
160            return Err(Error::WouldBlock);
161        }
162        fence(Ordering::Release);
163        let byte = unsafe { self.read_uncheck()? };
164        Ok(byte)
165    }
166
167    pub fn can_read(&self) -> bool {
168        (self.op.can_get)(self.uart)
169    }
170
171    /// Read a byte from the UART.
172    ///
173    /// # Safety
174    ///
175    /// Need to check the UART status register before reading.
176    pub unsafe fn read_uncheck(&mut self) -> Result<u8, ErrorKind> {
177        (self.op.get)(self.uart)
178    }
179}
180
181pub(crate) trait Console {
182    fn can_put(uart: UartData) -> bool;
183    fn put(uart: UartData, c: u8) -> Result<(), ErrorKind>;
184    fn can_get(uart: UartData) -> bool;
185    fn get(uart: UartData) -> Result<u8, ErrorKind>;
186    fn set_irq_enable(uart: UartData, enable: bool);
187    fn get_irq_enable(uart: UartData) -> bool;
188    fn get_irq_event(uart: UartData) -> IrqEvent;
189    fn clean_irq_event(uart: UartData, event: IrqEvent);
190
191    fn to_op() -> UartOp {
192        UartOp {
193            can_put: Self::can_put,
194            put: Self::put,
195            can_get: Self::can_get,
196            get: Self::get,
197            set_irq_enable: Self::set_irq_enable,
198            get_irq_enable: Self::get_irq_enable,
199            get_irq_event: Self::get_irq_event,
200            clean_irq_event: Self::clean_irq_event,
201        }
202    }
203}
204
205#[derive(Clone, Copy)]
206pub(crate) struct UartData {
207    pub base: usize,
208    pub io_kind: IoKind,
209}
210
211impl UartData {
212    fn new(base: u64, io_kind: IoKind, f: FnPhysToVirt) -> Self {
213        let mmio = f(base as _);
214
215        Self {
216            base: mmio as _,
217            io_kind,
218        }
219    }
220
221    pub fn reg_u8(&self, offset: usize) -> *mut u8 {
222        self.reg(offset)
223    }
224
225    pub fn reg<T: Sized>(&self, offset: usize) -> *mut T {
226        unsafe {
227            let ptr = self.base as *mut T;
228            ptr.add(offset)
229        }
230    }
231}
232
233pub fn init(fdt_addr: NonNull<u8>, fn_phys_to_virt: FnPhysToVirt) -> Option<Uart> {
234    let fdt = Fdt::from_ptr(fdt_addr).ok()?;
235
236    let chosen = fdt.chosen()?;
237
238    let mut io_kind = IoKind::Mmio32;
239    let node;
240    let mut is_8250 = false;
241
242    match chosen.stdout() {
243        Some(n) => node = n.node,
244        None => {
245            let (n, io) = fdt_bootargs_find_node(&chosen, &fdt)?;
246            node = n;
247            io_kind = io;
248            is_8250 = true;
249        }
250    };
251
252    let reg = node.reg()?.next()?;
253
254    let uart = UartData::new(reg.address, io_kind, fn_phys_to_virt);
255
256    if is_8250 {
257        return Some(Uart::_new::<Ns16550>(uart));
258    } else {
259        for c in node.compatibles() {
260            macro_rules! of_uart {
261                ($name:ty, $compatible:expr) => {
262                    for want in $compatible {
263                        if c.contains(want) {
264                            return Some(Uart::_new::<$name>(uart));
265                        }
266                    }
267                };
268            }
269
270            of_uart!(AuxMini, ["brcm,bcm2835-aux-uart"]);
271            of_uart!(Pl011, ["arm,pl011", "arm,primecell"]);
272            of_uart!(Ns16550, ["snps,dw-apb-uart"]);
273        }
274    }
275
276    None
277}
278
279#[derive(Clone, Copy)]
280pub enum IoKind {
281    Port,
282    Mmio,
283    Mmio16,
284    Mmio32,
285    Mmio32be,
286}
287
288impl IoKind {
289    pub fn width(&self) -> usize {
290        match self {
291            IoKind::Port => 1,
292            IoKind::Mmio => 4,
293            IoKind::Mmio16 => 2,
294            IoKind::Mmio32 => 4,
295            IoKind::Mmio32be => 4,
296        }
297    }
298}
299
300impl From<&str> for IoKind {
301    fn from(value: &str) -> Self {
302        match value {
303            "mmio" => IoKind::Mmio,
304            "mmio16" => IoKind::Mmio16,
305            "mmio32" => IoKind::Mmio32,
306            "mmio32be" => IoKind::Mmio32be,
307            "mmio32native" => {
308                if cfg!(target_endian = "little") {
309                    IoKind::Mmio32
310                } else {
311                    IoKind::Mmio32be
312                }
313            }
314            _ => IoKind::Port,
315        }
316    }
317}
318
319fn fdt_bootargs_find_node<'a>(chosen: &Chosen<'a>, fdt: &'a Fdt<'a>) -> Option<(Node<'a>, IoKind)> {
320    let bootargs = chosen.bootargs()?;
321
322    let earlycon = bootargs
323        .split_ascii_whitespace()
324        .find(|&arg| arg.contains("earlycon"))?;
325
326    let mut tmp = earlycon.split('=');
327    let _ = tmp.next()?;
328    let values = tmp.next()?;
329
330    let mut values = values.split(',');
331
332    let name = values.next()?;
333
334    if !name.contains("uart") {
335        return None;
336    }
337
338    let param2 = values.next()?;
339    let addr_str;
340    let io_kind = if param2.contains("0x") {
341        addr_str = param2;
342        IoKind::Mmio
343    } else {
344        addr_str = values.next()?;
345        IoKind::from(param2)
346    };
347
348    let mmio = u64::from_str_radix(addr_str.trim_start_matches("0x"), 16).ok()?;
349
350    for node in fdt.all_nodes() {
351        if let Some(regs) = node.reg() {
352            for reg in regs {
353                if reg.address.eq(&mmio) {
354                    return Some((node, io_kind));
355                }
356            }
357        }
358    }
359
360    None
361}
362
363#[cfg(test)]
364mod tests {
365    use super::*;
366
367    #[test]
368    fn test_uart_init() {
369        let fdt = include_bytes!("../../dtb/rk3568-firefly-roc-pc-se.dtb");
370        let fdt_addr = NonNull::new(fdt.as_ptr() as usize as _).unwrap();
371        let _ = init(fdt_addr, |r| r as _).unwrap();
372    }
373}