master
rs 347 lines 9.82 KB
Raw
1 // Copyright 2024, Linaro Limited
2 // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4
5 //! Device registers exposed as typed structs which are backed by arbitrary
6 //! integer bitmaps. [`Data`], [`Control`], [`LineControl`], etc.
7
8 // rustc prefers "constant-like" enums to use upper case names, but that
9 // is inconsistent in its own way.
10 #![allow(non_upper_case_globals)]
11
12 // For more detail see the PL011 Technical Reference Manual DDI0183:
13 // https://developer.arm.com/documentation/ddi0183/latest/
14
15 use bitfield_struct::bitfield;
16 use bits::bits;
17 use migration::impl_vmstate_forward;
18
19 /// Offset of each register from the base memory address of the device.
20 #[doc(alias = "offset")]
21 #[allow(non_camel_case_types)]
22 #[repr(u64)]
23 #[derive(Debug, Eq, PartialEq, common::TryInto)]
24 pub enum RegisterOffset {
25 /// Data Register
26 ///
27 /// A write to this register initiates the actual data transmission
28 #[doc(alias = "UARTDR")]
29 DR = 0x000,
30 /// Receive Status Register or Error Clear Register
31 #[doc(alias = "UARTRSR")]
32 #[doc(alias = "UARTECR")]
33 RSR = 0x004,
34 /// Flag Register
35 ///
36 /// A read of this register shows if transmission is complete
37 #[doc(alias = "UARTFR")]
38 FR = 0x018,
39 /// Fractional Baud Rate Register
40 ///
41 /// responsible for baud rate speed
42 #[doc(alias = "UARTFBRD")]
43 FBRD = 0x028,
44 /// `IrDA` Low-Power Counter Register
45 #[doc(alias = "UARTILPR")]
46 ILPR = 0x020,
47 /// Integer Baud Rate Register
48 ///
49 /// Responsible for baud rate speed
50 #[doc(alias = "UARTIBRD")]
51 IBRD = 0x024,
52 /// line control register (data frame format)
53 #[doc(alias = "UARTLCR_H")]
54 LCR_H = 0x02C,
55 /// Toggle UART, transmission or reception
56 #[doc(alias = "UARTCR")]
57 CR = 0x030,
58 /// Interrupt FIFO Level Select Register
59 #[doc(alias = "UARTIFLS")]
60 FLS = 0x034,
61 /// Interrupt Mask Set/Clear Register
62 #[doc(alias = "UARTIMSC")]
63 IMSC = 0x038,
64 /// Raw Interrupt Status Register
65 #[doc(alias = "UARTRIS")]
66 RIS = 0x03C,
67 /// Masked Interrupt Status Register
68 #[doc(alias = "UARTMIS")]
69 MIS = 0x040,
70 /// Interrupt Clear Register
71 #[doc(alias = "UARTICR")]
72 ICR = 0x044,
73 /// DMA control Register
74 #[doc(alias = "UARTDMACR")]
75 DMACR = 0x048,
76 ///// Reserved, offsets `0x04C` to `0x07C`.
77 //Reserved = 0x04C,
78 }
79
80 /// Receive Status Register / Data Register common error bits
81 ///
82 /// The `UARTRSR` register is updated only when a read occurs
83 /// from the `UARTDR` register with the same status information
84 /// that can also be obtained by reading the `UARTDR` register
85 #[bitfield(u8)]
86 pub struct Errors {
87 pub framing_error: bool,
88 pub parity_error: bool,
89 pub break_error: bool,
90 pub overrun_error: bool,
91 #[bits(4)]
92 _reserved_unpredictable: u8,
93 }
94
95 impl Errors {
96 pub const BREAK: Self = Errors::new().with_break_error(true);
97 }
98
99 /// Data Register, `UARTDR`
100 ///
101 /// The `UARTDR` register is the data register; write for TX and
102 /// read for RX. It is a 12-bit register, where bits 7..0 are the
103 /// character and bits 11..8 are error bits.
104 #[bitfield(u32)]
105 #[doc(alias = "UARTDR")]
106 pub struct Data {
107 pub data: u8,
108 #[bits(8)]
109 pub errors: Errors,
110 _reserved: u16,
111 }
112 impl_vmstate_forward!(Data);
113
114 impl Data {
115 pub const BREAK: Self = Self::new().with_errors(Errors::BREAK);
116 }
117
118 /// Receive Status Register / Error Clear Register, `UARTRSR/UARTECR`
119 ///
120 /// This register provides a different way to read the four receive
121 /// status error bits that can be found in bits 11..8 of the UARTDR
122 /// on a read. It gets updated when the guest reads UARTDR, and the
123 /// status bits correspond to that character that was just read.
124 ///
125 /// The TRM confusingly describes this offset as UARTRSR for reads
126 /// and UARTECR for writes, but really it's a single error status
127 /// register where writing anything to the register clears the error
128 /// bits.
129 #[bitfield(u32)]
130 pub struct ReceiveStatusErrorClear {
131 #[bits(8)]
132 pub errors: Errors,
133 #[bits(24)]
134 _reserved_unpredictable: u32,
135 }
136 impl_vmstate_forward!(ReceiveStatusErrorClear);
137
138 impl ReceiveStatusErrorClear {
139 pub fn set_from_data(&mut self, data: Data) {
140 self.set_errors(data.errors());
141 }
142
143 pub fn reset(&mut self) {
144 // All the bits are cleared to 0 on reset.
145 *self = Self::default();
146 }
147 }
148
149 #[bitfield(u32, default = false)]
150 /// Flag Register, `UARTFR`
151 ///
152 /// This has the usual inbound RS232 modem-control signals, plus flags
153 /// for RX and TX FIFO fill levels and a BUSY flag.
154 #[doc(alias = "UARTFR")]
155 pub struct Flags {
156 /// CTS: Clear to send
157 pub clear_to_send: bool,
158 /// DSR: Data set ready
159 pub data_set_ready: bool,
160 /// DCD: Data carrier detect
161 pub data_carrier_detect: bool,
162 /// BUSY: UART busy. In real hardware, set while the UART is
163 /// busy transmitting data. QEMU's implementation never sets BUSY.
164 pub busy: bool,
165 /// RXFE: Receive FIFO empty
166 pub receive_fifo_empty: bool,
167 /// TXFF: Transmit FIFO full
168 pub transmit_fifo_full: bool,
169 /// RXFF: Receive FIFO full
170 pub receive_fifo_full: bool,
171 /// TXFE: Transmit FIFO empty
172 pub transmit_fifo_empty: bool,
173 /// RI: Ring indicator
174 pub ring_indicator: bool,
175 #[bits(23)]
176 _reserved_zero_no_modify: u32,
177 }
178 impl_vmstate_forward!(Flags);
179
180 impl Flags {
181 pub fn reset(&mut self) {
182 *self = Self::default();
183 }
184 }
185
186 impl Default for Flags {
187 fn default() -> Self {
188 // After reset TXFF, RXFF, and BUSY are 0, and TXFE and RXFE are 1
189 Self::from(0)
190 .with_receive_fifo_empty(true)
191 .with_transmit_fifo_empty(true)
192 }
193 }
194
195 #[bitfield(u32)]
196 /// Line Control Register, `UARTLCR_H`
197 #[doc(alias = "UARTLCR_H")]
198 pub struct LineControl {
199 /// BRK: Send break
200 pub send_break: bool,
201 /// PEN: Parity enable
202 pub parity_enabled: bool,
203 /// EPS: Even parity select
204 #[bits(1)]
205 pub parity: Parity,
206 /// STP2: Two stop bits select
207 pub two_stops_bits: bool,
208 /// FEN: Enable FIFOs
209 #[bits(1)]
210 pub fifos_enabled: Mode,
211 /// WLEN: Word length in bits
212 /// b11 = 8 bits
213 /// b10 = 7 bits
214 /// b01 = 6 bits
215 /// b00 = 5 bits.
216 #[bits(2)]
217 pub word_length: WordLength,
218 /// SPS Stick parity select
219 pub sticky_parity: bool,
220 /// 31:8 - Reserved, do not modify, read as zero.
221 #[bits(24)]
222 _reserved_zero_no_modify: u32,
223 }
224 impl_vmstate_forward!(LineControl);
225
226 impl LineControl {
227 pub fn reset(&mut self) {
228 // All the bits are cleared to 0 when reset.
229 *self = Self::default();
230 }
231 }
232
233 /// `EPS` "Even parity select", field of [Line Control
234 /// register](LineControl).
235 #[repr(u8)]
236 #[derive(Clone, Copy, Debug, Eq, PartialEq, common::TryInto)]
237 pub enum Parity {
238 Odd = 0,
239 Even = 1,
240 }
241
242 #[repr(u8)]
243 #[derive(Clone, Copy, Debug, Eq, PartialEq, common::TryInto)]
244 /// `FEN` "Enable FIFOs" or Device mode, field of [Line Control
245 /// register](LineControl).
246 pub enum Mode {
247 /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become
248 /// 1-byte-deep holding registers
249 Character = 0,
250 /// 1 = transmit and receive FIFO buffers are enabled (FIFO mode).
251 FIFO = 1,
252 }
253
254 #[repr(u8)]
255 #[derive(Clone, Copy, Debug, Eq, PartialEq, common::TryInto)]
256 #[allow(clippy::enum_variant_names)]
257 /// `WLEN` Word length, field of [Line Control register](LineControl).
258 ///
259 /// These bits indicate the number of data bits transmitted or received in a
260 /// frame as follows:
261 pub enum WordLength {
262 /// b11 = 8 bits
263 _8Bits = 0b11,
264 /// b10 = 7 bits
265 _7Bits = 0b10,
266 /// b01 = 6 bits
267 _6Bits = 0b01,
268 /// b00 = 5 bits.
269 _5Bits = 0b00,
270 }
271
272 /// Control Register, `UARTCR`
273 ///
274 /// The `UARTCR` register is the control register. It contains various
275 /// enable bits, and the bits to write to set the usual outbound RS232
276 /// modem control signals. All bits reset to 0 except TXE and RXE.
277 #[bitfield(u32, default = false)]
278 #[doc(alias = "UARTCR")]
279 pub struct Control {
280 /// `UARTEN` UART enable: 0 = UART is disabled.
281 pub enable_uart: bool,
282 /// `SIREN` `SIR` enable: disable or enable IrDA SIR ENDEC.
283 /// QEMU does not model this.
284 pub enable_sir: bool,
285 /// `SIRLP` SIR low-power IrDA mode. QEMU does not model this.
286 pub sir_lowpower_irda_mode: bool,
287 /// Reserved, do not modify, read as zero.
288 #[bits(4)]
289 _reserved_zero_no_modify: u8,
290 /// `LBE` Loopback enable: feed UART output back to the input
291 pub enable_loopback: bool,
292 /// `TXE` Transmit enable
293 pub enable_transmit: bool,
294 /// `RXE` Receive enable
295 pub enable_receive: bool,
296 /// `DTR` Data transmit ready
297 pub data_transmit_ready: bool,
298 /// `RTS` Request to send
299 pub request_to_send: bool,
300 /// `Out1` UART Out1 signal; can be used as DCD
301 pub out_1: bool,
302 /// `Out2` UART Out2 signal; can be used as RI
303 pub out_2: bool,
304 /// `RTSEn` RTS hardware flow control enable
305 pub rts_hardware_flow_control_enable: bool,
306 /// `CTSEn` CTS hardware flow control enable
307 pub cts_hardware_flow_control_enable: bool,
308 /// 31:16 - Reserved, do not modify, read as zero.
309 _reserved_zero_no_modify2: u16,
310 }
311 impl_vmstate_forward!(Control);
312
313 impl Control {
314 pub fn reset(&mut self) {
315 *self = Self::default();
316 }
317 }
318
319 impl Default for Control {
320 fn default() -> Self {
321 Self::from(0)
322 .with_enable_receive(true)
323 .with_enable_transmit(true)
324 }
325 }
326
327 bits! {
328 /// Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC
329 #[derive(Default)]
330 pub struct Interrupt(u32) {
331 OE = 1 << 10,
332 BE = 1 << 9,
333 PE = 1 << 8,
334 FE = 1 << 7,
335 RT = 1 << 6,
336 TX = 1 << 5,
337 RX = 1 << 4,
338 DSR = 1 << 3,
339 DCD = 1 << 2,
340 CTS = 1 << 1,
341 RI = 1 << 0,
342
343 E = bits!(Self as u32: OE | BE | PE | FE),
344 MS = bits!(Self as u32: RI | DSR | DCD | CTS),
345 }
346 }
347 impl_vmstate_forward!(Interrupt);