| 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); |