master
rs 781 lines 24.4 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 use std::{ffi::CStr, mem::size_of};
6
7 use bql::prelude::*;
8 use chardev::prelude::*;
9 use common::prelude::*;
10 use hwcore::{prelude::*, ClockEvent, IRQState};
11 use migration::{self, prelude::*};
12 use qom::prelude::*;
13 use system::prelude::*;
14 use util::prelude::*;
15
16 use crate::registers::{self, Interrupt, RegisterOffset};
17
18 ::trace::include_trace!("hw_char");
19
20 // TODO: You must disable the UART before any of the control registers are
21 // reprogrammed. When the UART is disabled in the middle of transmission or
22 // reception, it completes the current character before stopping
23
24 /// Integer Baud Rate Divider, `UARTIBRD`
25 const IBRD_MASK: u32 = 0xffff;
26
27 /// Fractional Baud Rate Divider, `UARTFBRD`
28 const FBRD_MASK: u32 = 0x3f;
29
30 /// QEMU sourced constant.
31 pub const PL011_FIFO_DEPTH: u32 = 16;
32
33 #[derive(Clone, Copy)]
34 struct DeviceId(&'static [u8; 8]);
35
36 impl std::ops::Index<hwaddr> for DeviceId {
37 type Output = u8;
38
39 fn index(&self, idx: hwaddr) -> &Self::Output {
40 &self.0[idx as usize]
41 }
42 }
43
44 // FIFOs use 32-bit indices instead of usize, for compatibility with
45 // the migration stream produced by the C version of this device.
46 #[repr(transparent)]
47 #[derive(Debug, Default)]
48 pub struct Fifo([registers::Data; PL011_FIFO_DEPTH as usize]);
49 impl_vmstate_forward!(Fifo);
50
51 impl Fifo {
52 const fn len(&self) -> u32 {
53 self.0.len() as u32
54 }
55 }
56
57 impl std::ops::IndexMut<u32> for Fifo {
58 fn index_mut(&mut self, idx: u32) -> &mut Self::Output {
59 &mut self.0[idx as usize]
60 }
61 }
62
63 impl std::ops::Index<u32> for Fifo {
64 type Output = registers::Data;
65
66 fn index(&self, idx: u32) -> &Self::Output {
67 &self.0[idx as usize]
68 }
69 }
70
71 #[repr(C)]
72 #[derive(Debug, Default)]
73 pub struct PL011Registers {
74 #[doc(alias = "fr")]
75 pub flags: registers::Flags,
76 #[doc(alias = "lcr")]
77 pub line_control: registers::LineControl,
78 #[doc(alias = "rsr")]
79 pub receive_status_error_clear: registers::ReceiveStatusErrorClear,
80 #[doc(alias = "cr")]
81 pub control: registers::Control,
82 pub dmacr: u32,
83 pub int_enabled: Interrupt,
84 pub int_level: Interrupt,
85 pub read_fifo: Fifo,
86 pub ilpr: u32,
87 pub ibrd: u32,
88 pub fbrd: u32,
89 pub ifl: u32,
90 pub read_pos: u32,
91 pub read_count: u32,
92 pub read_trigger: u32,
93 }
94
95 #[repr(C)]
96 #[derive(qom::Object, hwcore::Device)]
97 /// PL011 Device Model in QEMU
98 pub struct PL011State {
99 pub parent_obj: ParentField<SysBusDevice>,
100 pub iomem: MemoryRegion,
101 #[doc(alias = "chr")]
102 #[property(rename = "chardev")]
103 pub char_frontend: CharFrontend,
104 pub regs: BqlRefCell<PL011Registers>,
105 /// QEMU interrupts
106 ///
107 /// ```text
108 /// * sysbus MMIO region 0: device registers
109 /// * sysbus IRQ 0: `UARTINTR` (combined interrupt line)
110 /// * sysbus IRQ 1: `UARTRXINTR` (receive FIFO interrupt line)
111 /// * sysbus IRQ 2: `UARTTXINTR` (transmit FIFO interrupt line)
112 /// * sysbus IRQ 3: `UARTRTINTR` (receive timeout interrupt line)
113 /// * sysbus IRQ 4: `UARTMSINTR` (momem status interrupt line)
114 /// * sysbus IRQ 5: `UARTEINTR` (error interrupt line)
115 /// ```
116 #[doc(alias = "irq")]
117 pub interrupts: [InterruptSource; IRQMASK.len()],
118 #[doc(alias = "clk")]
119 pub clock: Owned<Clock>,
120 #[doc(alias = "migrate_clk")]
121 #[property(rename = "migrate-clk", default = true)]
122 pub migrate_clock: bool,
123 }
124
125 // Some C users of this device embed its state struct into their own
126 // structs, so the size of the Rust version must not be any larger
127 // than the size of the C one. If this assert triggers you need to
128 // expand the padding_for_rust[] array in the C PL011State struct.
129 static_assert!(size_of::<PL011State>() <= size_of::<crate::bindings::PL011State>());
130
131 qom_isa!(PL011State : SysBusDevice, DeviceState, Object);
132
133 #[repr(C)]
134 pub struct PL011Class {
135 parent_class: <SysBusDevice as ObjectType>::Class,
136 /// The byte string that identifies the device.
137 device_id: DeviceId,
138 }
139
140 trait PL011Impl: SysBusDeviceImpl + IsA<PL011State> {
141 const DEVICE_ID: DeviceId;
142 }
143
144 impl PL011Class {
145 fn class_init<T: PL011Impl>(&mut self) {
146 self.device_id = T::DEVICE_ID;
147 self.parent_class.class_init::<T>();
148 }
149 }
150
151 unsafe impl ObjectType for PL011State {
152 type Class = PL011Class;
153 const TYPE_NAME: &'static CStr = crate::TYPE_PL011;
154 }
155
156 impl PL011Impl for PL011State {
157 const DEVICE_ID: DeviceId = DeviceId(&[0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1]);
158 }
159
160 impl ObjectImpl for PL011State {
161 type ParentType = SysBusDevice;
162
163 const INSTANCE_INIT: Option<unsafe fn(ParentInit<Self>)> = Some(Self::init);
164 const INSTANCE_POST_INIT: Option<fn(&Self)> = Some(Self::post_init);
165 const CLASS_INIT: fn(&mut Self::Class) = Self::Class::class_init::<Self>;
166 }
167
168 impl DeviceImpl for PL011State {
169 const VMSTATE: Option<VMStateDescription<Self>> = Some(VMSTATE_PL011);
170 const REALIZE: Option<fn(&Self) -> util::Result<()>> = Some(Self::realize);
171 }
172
173 impl ResettablePhasesImpl for PL011State {
174 const HOLD: Option<fn(&Self, ResetType)> = Some(Self::reset_hold);
175 }
176
177 impl SysBusDeviceImpl for PL011State {}
178
179 impl PL011Registers {
180 pub(self) fn read(&mut self, offset: RegisterOffset) -> (bool, u32) {
181 use RegisterOffset::*;
182
183 let mut update = false;
184 let result = match offset {
185 DR => self.read_data_register(&mut update),
186 RSR => u32::from(self.receive_status_error_clear),
187 FR => u32::from(self.flags),
188 FBRD => self.fbrd,
189 ILPR => self.ilpr,
190 IBRD => self.ibrd,
191 LCR_H => u32::from(self.line_control),
192 CR => u32::from(self.control),
193 FLS => self.ifl,
194 IMSC => u32::from(self.int_enabled),
195 RIS => u32::from(self.int_level),
196 MIS => u32::from(self.int_level & self.int_enabled),
197 ICR => {
198 // "The UARTICR Register is the interrupt clear register and is write-only"
199 // Source: ARM DDI 0183G 3.3.13 Interrupt Clear Register, UARTICR
200 0
201 }
202 DMACR => self.dmacr,
203 };
204 (update, result)
205 }
206
207 pub(self) fn write(&mut self, offset: RegisterOffset, value: u32, device: &PL011State) -> bool {
208 use RegisterOffset::*;
209 match offset {
210 DR => return self.write_data_register(value),
211 RSR => {
212 self.receive_status_error_clear = 0.into();
213 }
214 FR => {
215 // flag writes are ignored
216 }
217 ILPR => {
218 self.ilpr = value;
219 }
220 IBRD => {
221 self.ibrd = value;
222 device.trace_baudrate_change(self.ibrd, self.fbrd);
223 }
224 FBRD => {
225 self.fbrd = value;
226 device.trace_baudrate_change(self.ibrd, self.fbrd);
227 }
228 LCR_H => {
229 let new_val: registers::LineControl = value.into();
230 // Reset the FIFO state on FIFO enable or disable
231 if self.line_control.fifos_enabled() != new_val.fifos_enabled() {
232 self.reset_rx_fifo();
233 self.reset_tx_fifo();
234 }
235 let update = (self.line_control.send_break() != new_val.send_break()) && {
236 let break_enable = new_val.send_break();
237 let _ = device.char_frontend.send_break(break_enable);
238 self.loopback_break(break_enable)
239 };
240 self.line_control = new_val;
241 self.set_read_trigger();
242 return update;
243 }
244 CR => {
245 // ??? Need to implement the enable bit.
246 self.control = value.into();
247 return self.loopback_mdmctrl();
248 }
249 FLS => {
250 self.ifl = value;
251 self.set_read_trigger();
252 }
253 IMSC => {
254 self.int_enabled = Interrupt::from(value);
255 return true;
256 }
257 RIS => {}
258 MIS => {}
259 ICR => {
260 self.int_level &= !Interrupt::from(value);
261 return true;
262 }
263 DMACR => {
264 self.dmacr = value;
265 if value & 3 > 0 {
266 log_mask_ln!(Log::Unimp, "pl011: DMA not implemented");
267 }
268 }
269 }
270 false
271 }
272
273 fn read_data_register(&mut self, update: &mut bool) -> u32 {
274 let depth = self.fifo_depth();
275 self.flags.set_receive_fifo_full(false);
276 let c = self.read_fifo[self.read_pos];
277
278 if self.read_count > 0 {
279 self.read_count -= 1;
280 self.read_pos = (self.read_pos + 1) & (depth - 1);
281 }
282 if self.read_count == 0 {
283 self.flags.set_receive_fifo_empty(true);
284 }
285 if self.read_count + 1 == self.read_trigger {
286 self.int_level &= !Interrupt::RX;
287 }
288 trace::trace_pl011_read_fifo(self.read_count, depth);
289 self.receive_status_error_clear.set_from_data(c);
290 *update = true;
291 u32::from(c)
292 }
293
294 fn write_data_register(&mut self, value: u32) -> bool {
295 if !self.control.enable_uart() {
296 log_mask_ln!(Log::GuestError, "PL011 data written to disabled UART");
297 }
298 if !self.control.enable_transmit() {
299 log_mask_ln!(Log::GuestError, "PL011 data written to disabled TX UART");
300 }
301 // interrupts always checked
302 let _ = self.loopback_tx(value.into());
303 self.int_level |= Interrupt::TX;
304 true
305 }
306
307 #[inline]
308 #[must_use]
309 fn loopback_tx(&mut self, value: registers::Data) -> bool {
310 // Caveat:
311 //
312 // In real hardware, TX loopback happens at the serial-bit level
313 // and then reassembled by the RX logics back into bytes and placed
314 // into the RX fifo. That is, loopback happens after TX fifo.
315 //
316 // Because the real hardware TX fifo is time-drained at the frame
317 // rate governed by the configured serial format, some loopback
318 // bytes in TX fifo may still be able to get into the RX fifo
319 // that could be full at times while being drained at software
320 // pace.
321 //
322 // In such scenario, the RX draining pace is the major factor
323 // deciding which loopback bytes get into the RX fifo, unless
324 // hardware flow-control is enabled.
325 //
326 // For simplicity, the above described is not emulated.
327 self.loopback_enabled() && self.fifo_rx_put(value)
328 }
329
330 #[must_use]
331 fn loopback_mdmctrl(&mut self) -> bool {
332 if !self.loopback_enabled() {
333 return false;
334 }
335
336 /*
337 * Loopback software-driven modem control outputs to modem status inputs:
338 * FR.RI <= CR.Out2
339 * FR.DCD <= CR.Out1
340 * FR.CTS <= CR.RTS
341 * FR.DSR <= CR.DTR
342 *
343 * The loopback happens immediately even if this call is triggered
344 * by setting only CR.LBE.
345 *
346 * CTS/RTS updates due to enabled hardware flow controls are not
347 * dealt with here.
348 */
349
350 self.flags.set_ring_indicator(self.control.out_2());
351 self.flags.set_data_carrier_detect(self.control.out_1());
352 self.flags.set_clear_to_send(self.control.request_to_send());
353 self.flags
354 .set_data_set_ready(self.control.data_transmit_ready());
355
356 // Change interrupts based on updated FR
357 let mut il = self.int_level;
358
359 il &= !Interrupt::MS;
360
361 if self.flags.data_set_ready() {
362 il |= Interrupt::DSR;
363 }
364 if self.flags.data_carrier_detect() {
365 il |= Interrupt::DCD;
366 }
367 if self.flags.clear_to_send() {
368 il |= Interrupt::CTS;
369 }
370 if self.flags.ring_indicator() {
371 il |= Interrupt::RI;
372 }
373 self.int_level = il;
374 true
375 }
376
377 fn loopback_break(&mut self, enable: bool) -> bool {
378 enable && self.loopback_tx(registers::Data::BREAK)
379 }
380
381 fn set_read_trigger(&mut self) {
382 self.read_trigger = 1;
383 }
384
385 pub fn reset(&mut self) {
386 self.line_control.reset();
387 self.receive_status_error_clear.reset();
388 self.dmacr = 0;
389 self.int_enabled = 0.into();
390 self.int_level = 0.into();
391 self.ilpr = 0;
392 self.ibrd = 0;
393 self.fbrd = 0;
394 self.read_trigger = 1;
395 self.ifl = 0x12;
396 self.control.reset();
397 self.flags.reset();
398 self.reset_rx_fifo();
399 self.reset_tx_fifo();
400 }
401
402 pub fn reset_rx_fifo(&mut self) {
403 self.read_count = 0;
404 self.read_pos = 0;
405
406 // Reset FIFO flags
407 self.flags.set_receive_fifo_full(false);
408 self.flags.set_receive_fifo_empty(true);
409 }
410
411 pub fn reset_tx_fifo(&mut self) {
412 // Reset FIFO flags
413 self.flags.set_transmit_fifo_full(false);
414 self.flags.set_transmit_fifo_empty(true);
415 }
416
417 #[inline]
418 pub fn fifo_enabled(&self) -> bool {
419 self.line_control.fifos_enabled() == registers::Mode::FIFO
420 }
421
422 #[inline]
423 pub fn loopback_enabled(&self) -> bool {
424 self.control.enable_loopback()
425 }
426
427 #[inline]
428 pub fn fifo_depth(&self) -> u32 {
429 // Note: FIFO depth is expected to be power-of-2
430 if self.fifo_enabled() {
431 return PL011_FIFO_DEPTH;
432 }
433 1
434 }
435
436 #[must_use]
437 pub fn fifo_rx_put(&mut self, value: registers::Data) -> bool {
438 let depth = self.fifo_depth();
439 assert!(depth > 0);
440 let slot = (self.read_pos + self.read_count) & (depth - 1);
441 self.read_fifo[slot] = value;
442 self.read_count += 1;
443 self.flags.set_receive_fifo_empty(false);
444 trace::trace_pl011_fifo_rx_put(value.into(), self.read_count, depth);
445 if self.read_count == depth {
446 trace::trace_pl011_fifo_rx_full();
447 self.flags.set_receive_fifo_full(true);
448 }
449
450 if self.read_count == self.read_trigger {
451 self.int_level |= Interrupt::RX;
452 return true;
453 }
454 false
455 }
456
457 pub fn post_load(&mut self) -> Result<(), migration::InvalidError> {
458 /* Sanity-check input state */
459 if self.read_pos >= self.read_fifo.len() || self.read_count > self.read_fifo.len() {
460 return Err(migration::InvalidError);
461 }
462
463 if !self.fifo_enabled() && self.read_count > 0 && self.read_pos > 0 {
464 // Older versions of PL011 didn't ensure that the single
465 // character in the FIFO in FIFO-disabled mode is in
466 // element 0 of the array; convert to follow the current
467 // code's assumptions.
468 self.read_fifo[0] = self.read_fifo[self.read_pos];
469 self.read_pos = 0;
470 }
471
472 self.ibrd &= IBRD_MASK;
473 self.fbrd &= FBRD_MASK;
474
475 Ok(())
476 }
477 }
478
479 impl PL011State {
480 /// Initializes a pre-allocated, uninitialized instance of `PL011State`.
481 ///
482 /// # Safety
483 ///
484 /// `self` must point to a correctly sized and aligned location for the
485 /// `PL011State` type. It must not be called more than once on the same
486 /// location/instance. All its fields are expected to hold uninitialized
487 /// values with the sole exception of `parent_obj`.
488 unsafe fn init(mut this: ParentInit<Self>) {
489 static PL011_OPS: MemoryRegionOps<PL011State> = MemoryRegionOpsBuilder::<PL011State>::new()
490 .read(&PL011State::read)
491 .write(&PL011State::write)
492 .little_endian()
493 .impl_sizes(4, 4)
494 .build();
495
496 // SAFETY: this and this.iomem are guaranteed to be valid at this point
497 MemoryRegion::init_io(
498 &mut uninit_field_mut!(*this, iomem),
499 &PL011_OPS,
500 "pl011",
501 0x1000,
502 );
503
504 uninit_field_mut!(*this, regs).write(Default::default());
505
506 let clock = DeviceState::init_clock_in(
507 &mut this,
508 "clk",
509 &Self::clock_update,
510 ClockEvent::ClockUpdate,
511 );
512 uninit_field_mut!(*this, clock).write(clock);
513 }
514
515 pub fn trace_baudrate_change(&self, ibrd: u32, fbrd: u32) {
516 let divider = 4.0 / f64::from(ibrd * (FBRD_MASK + 1) + fbrd);
517 let hz = self.clock.hz();
518 let rate = if ibrd == 0 {
519 0
520 } else {
521 ((hz as f64) * divider) as u32
522 };
523 trace::trace_pl011_baudrate_change(rate, hz, ibrd, fbrd);
524 }
525
526 fn clock_update(&self, _event: ClockEvent) {
527 let regs = self.regs.borrow();
528 let (ibrd, fbrd) = (regs.ibrd, regs.fbrd);
529 self.trace_baudrate_change(ibrd, fbrd)
530 }
531
532 pub fn clock_needed(&self) -> bool {
533 self.migrate_clock
534 }
535
536 fn post_init(&self) {
537 self.init_mmio(&self.iomem);
538 for irq in self.interrupts.iter() {
539 self.init_irq(irq);
540 }
541 }
542
543 fn read(&self, offset: hwaddr, _size: u32) -> u64 {
544 match RegisterOffset::try_from(offset) {
545 Err(v) if (0x3f8..0x400).contains(&(v >> 2)) => {
546 let device_id = self.get_class().device_id;
547 u64::from(device_id[(offset - 0xfe0) >> 2])
548 }
549 Err(_) => {
550 log_mask_ln!(Log::GuestError, "PL011State::read: Bad offset {offset}");
551 0
552 }
553 Ok(field) => {
554 let (update_irq, result) = self.regs.borrow_mut().read(field);
555 trace::trace_pl011_read(offset, result, c"");
556 if update_irq {
557 self.update();
558 self.char_frontend.accept_input();
559 }
560 result.into()
561 }
562 }
563 }
564
565 fn write(&self, offset: hwaddr, value: u64, _size: u32) {
566 let mut update_irq = false;
567 if let Ok(field) = RegisterOffset::try_from(offset) {
568 // qemu_chr_fe_write_all() calls into the can_receive
569 // callback, so handle writes before entering PL011Registers.
570 trace::trace_pl011_write(offset, value as u32, c"");
571 if field == RegisterOffset::DR {
572 // ??? Check if transmitter is enabled.
573 let ch: [u8; 1] = [value as u8];
574 // XXX this blocks entire thread. Rewrite to use
575 // qemu_chr_fe_write and background I/O callbacks
576 let _ = self.char_frontend.write_all(&ch);
577 }
578
579 update_irq = self.regs.borrow_mut().write(field, value as u32, self);
580 } else {
581 log_mask_ln!(
582 Log::GuestError,
583 "PL011State::write: Bad offset {offset} value {value}"
584 );
585 }
586 if update_irq {
587 self.update();
588 }
589 }
590
591 fn can_receive(&self) -> u32 {
592 let regs = self.regs.borrow();
593 let fifo_available = regs.fifo_depth() - regs.read_count;
594 trace::trace_pl011_can_receive(
595 regs.line_control.into(),
596 regs.read_count,
597 regs.fifo_depth(),
598 fifo_available,
599 );
600 fifo_available
601 }
602
603 fn receive(&self, buf: &[u8]) {
604 trace::trace_pl011_receive(buf.len());
605
606 let mut regs = self.regs.borrow_mut();
607 if regs.loopback_enabled() {
608 // In loopback mode, the RX input signal is internally disconnected
609 // from the entire receiving logics; thus, all inputs are ignored,
610 // and BREAK detection on RX input signal is also not performed.
611 return;
612 }
613
614 let mut update_irq = false;
615 for &c in buf {
616 let c: u32 = c.into();
617 update_irq |= regs.fifo_rx_put(c.into());
618 }
619
620 // Release the BqlRefCell before calling self.update()
621 drop(regs);
622 if update_irq {
623 self.update();
624 }
625 }
626
627 fn event(&self, event: Event) {
628 let mut update_irq = false;
629 let mut regs = self.regs.borrow_mut();
630 if event == Event::CHR_EVENT_BREAK && !regs.loopback_enabled() {
631 update_irq = regs.fifo_rx_put(registers::Data::BREAK);
632 }
633 // Release the BqlRefCell before calling self.update()
634 drop(regs);
635
636 if update_irq {
637 self.update()
638 }
639 }
640
641 fn realize(&self) -> util::Result<()> {
642 self.char_frontend
643 .enable_handlers(self, Self::can_receive, Self::receive, Self::event);
644 Ok(())
645 }
646
647 fn reset_hold(&self, _type: ResetType) {
648 self.regs.borrow_mut().reset();
649 }
650
651 fn update(&self) {
652 let regs = self.regs.borrow();
653 let flags = regs.int_level & regs.int_enabled;
654 trace::trace_pl011_irq_state(flags != 0);
655 for (irq, i) in self.interrupts.iter().zip(IRQMASK) {
656 irq.set(flags.any_set(i));
657 }
658 }
659
660 pub fn post_load(&self, _version_id: u8) -> Result<(), migration::InvalidError> {
661 self.regs.borrow_mut().post_load()
662 }
663 }
664
665 /// Which bits in the interrupt status matter for each outbound IRQ line ?
666 const IRQMASK: [Interrupt; 6] = [
667 Interrupt::all(),
668 Interrupt::RX,
669 Interrupt::TX,
670 Interrupt::RT,
671 Interrupt::MS,
672 Interrupt::E,
673 ];
674
675 /// # Safety
676 ///
677 /// We expect the FFI user of this function to pass a valid pointer for `chr`
678 /// and `irq`.
679 #[no_mangle]
680 pub unsafe extern "C" fn pl011_create(
681 addr: u64,
682 irq: *mut IRQState,
683 chr: *mut Chardev,
684 ) -> *mut DeviceState {
685 // SAFETY: The callers promise that they have owned references.
686 // They do not gift them to pl011_create, so use `Owned::from`.
687 let irq = unsafe { Owned::<IRQState>::from(&*irq) };
688
689 let dev = PL011State::new();
690 if !chr.is_null() {
691 let chr = unsafe { Owned::<Chardev>::from(&*chr) };
692 dev.prop_set_chr("chardev", &chr);
693 }
694 dev.sysbus_realize().unwrap_fatal();
695 dev.mmio_map(0, addr);
696 dev.connect_irq(0, &irq);
697
698 // The pointer is kept alive by the QOM tree; drop the owned ref
699 dev.as_mut_ptr()
700 }
701
702 #[repr(C)]
703 #[derive(qom::Object, hwcore::Device)]
704 /// PL011 Luminary device model.
705 pub struct PL011Luminary {
706 parent_obj: ParentField<PL011State>,
707 }
708
709 qom_isa!(PL011Luminary : PL011State, SysBusDevice, DeviceState, Object);
710
711 unsafe impl ObjectType for PL011Luminary {
712 type Class = <PL011State as ObjectType>::Class;
713 const TYPE_NAME: &'static CStr = crate::TYPE_PL011_LUMINARY;
714 }
715
716 impl ObjectImpl for PL011Luminary {
717 type ParentType = PL011State;
718
719 const CLASS_INIT: fn(&mut Self::Class) = Self::Class::class_init::<Self>;
720 }
721
722 impl PL011Impl for PL011Luminary {
723 const DEVICE_ID: DeviceId = DeviceId(&[0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1]);
724 }
725
726 impl DeviceImpl for PL011Luminary {}
727 impl ResettablePhasesImpl for PL011Luminary {}
728 impl SysBusDeviceImpl for PL011Luminary {}
729
730 /// Migration subsection for [`PL011State`] clock.
731 static VMSTATE_PL011_CLOCK: VMStateDescription<PL011State> =
732 VMStateDescriptionBuilder::<PL011State>::new()
733 .name(c"pl011/clock")
734 .version_id(1)
735 .minimum_version_id(1)
736 .needed(&PL011State::clock_needed)
737 .fields(vmstate_fields! {
738 vmstate_of!(PL011State, clock),
739 })
740 .build();
741
742 impl_vmstate_struct!(
743 PL011Registers,
744 VMStateDescriptionBuilder::<PL011Registers>::new()
745 .name(c"pl011/regs")
746 .version_id(2)
747 .minimum_version_id(2)
748 .fields(vmstate_fields! {
749 vmstate_of!(PL011Registers, flags),
750 vmstate_of!(PL011Registers, line_control),
751 vmstate_of!(PL011Registers, receive_status_error_clear),
752 vmstate_of!(PL011Registers, control),
753 vmstate_of!(PL011Registers, dmacr),
754 vmstate_of!(PL011Registers, int_enabled),
755 vmstate_of!(PL011Registers, int_level),
756 vmstate_of!(PL011Registers, read_fifo),
757 vmstate_of!(PL011Registers, ilpr),
758 vmstate_of!(PL011Registers, ibrd),
759 vmstate_of!(PL011Registers, fbrd),
760 vmstate_of!(PL011Registers, ifl),
761 vmstate_of!(PL011Registers, read_pos),
762 vmstate_of!(PL011Registers, read_count),
763 vmstate_of!(PL011Registers, read_trigger),
764 })
765 .build()
766 );
767
768 pub const VMSTATE_PL011: VMStateDescription<PL011State> =
769 VMStateDescriptionBuilder::<PL011State>::new()
770 .name(c"pl011")
771 .version_id(2)
772 .minimum_version_id(2)
773 .post_load(&PL011State::post_load)
774 .fields(vmstate_fields! {
775 vmstate_unused!(core::mem::size_of::<u32>()),
776 vmstate_of!(PL011State, regs),
777 })
778 .subsections(vmstate_subsections! {
779 VMSTATE_PL011_CLOCK
780 })
781 .build();