forked from arceos-org/arceos
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pl011.rs
107 lines (92 loc) · 2.95 KB
/
pl011.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//! Types and definitions for PL011 UART.
//!
//! The official documentation: <https://developer.arm.com/documentation/ddi0183/latest>
use core::ptr::NonNull;
use tock_registers::{
interfaces::{Readable, Writeable},
register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
register_structs! {
/// Pl011 registers.
Pl011UartRegs {
/// Data Register.
(0x00 => dr: ReadWrite<u32>),
(0x04 => _reserved0),
/// Flag Register.
(0x18 => fr: ReadOnly<u32>),
(0x1c => _reserved1),
/// Control register.
(0x30 => cr: ReadWrite<u32>),
/// Interrupt FIFO Level Select Register.
(0x34 => ifls: ReadWrite<u32>),
/// Interrupt Mask Set Clear Register.
(0x38 => imsc: ReadWrite<u32>),
/// Raw Interrupt Status Register.
(0x3c => ris: ReadOnly<u32>),
/// Masked Interrupt Status Register.
(0x40 => mis: ReadOnly<u32>),
/// Interrupt Clear Register.
(0x44 => icr: WriteOnly<u32>),
(0x48 => @END),
}
}
/// The Pl011 Uart
///
/// The Pl011 Uart provides a programing interface for:
/// 1. Construct a new Pl011 UART instance
/// 2. Initialize the Pl011 UART
/// 3. Read a char from the UART
/// 4. Write a char to the UART
/// 5. Handle a UART IRQ
pub struct Pl011Uart {
base: NonNull<Pl011UartRegs>,
}
unsafe impl Send for Pl011Uart {}
unsafe impl Sync for Pl011Uart {}
impl Pl011Uart {
/// Constrcut a new Pl011 UART instance from the base address.
pub const fn new(base: *mut u8) -> Self {
Self {
base: NonNull::new(base).unwrap().cast(),
}
}
const fn regs(&self) -> &Pl011UartRegs {
unsafe { self.base.as_ref() }
}
/// Initializes the Pl011 UART.
///
/// It clears all irqs, sets fifo trigger level, enables rx interrupt, enables receives
pub fn init(&mut self) {
// clear all irqs
self.regs().icr.set(0x7ff);
// set fifo trigger level
self.regs().ifls.set(0); // 1/8 rxfifo, 1/8 txfifo.
// enable rx interrupt
self.regs().imsc.set(1 << 4); // rxim
// enable receive
self.regs().cr.set((1 << 0) | (1 << 8) | (1 << 9)); // tx enable, rx enable, uart enable
}
/// Output a char c to data register
pub fn putchar(&mut self, c: u8) {
while self.regs().fr.get() & (1 << 5) != 0 {}
self.regs().dr.set(c as u32);
}
/// Return a byte if pl011 has received, or it will return `None`.
pub fn getchar(&mut self) -> Option<u8> {
if self.regs().fr.get() & (1 << 4) == 0 {
Some(self.regs().dr.get() as u8)
} else {
None
}
}
/// Return true if pl011 has received an interrupt
pub fn is_receive_interrupt(&self) -> bool {
let pending = self.regs().mis.get();
pending & (1 << 4) != 0
}
/// Clear all interrupts
pub fn ack_interrupts(&mut self) {
self.regs().icr.set(0x7ff);
}
}