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::{
6 os::raw::{c_int, c_void},
7 ptr::NonNull,
8 };
9
10 use qemu_api::{
11 bindings::{qdev_prop_bool, qdev_prop_chr},
12 c_str,
13 prelude::*,
14 vmstate::VMStateDescription,
15 vmstate_clock, vmstate_fields, vmstate_of, vmstate_struct, vmstate_subsections, vmstate_unused,
16 zeroable::Zeroable,
17 };
18
19 use crate::device::{PL011Registers, PL011State};
20
pl011_clock_needed(opaque: *mut c_void) -> bool21 extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool {
22 let state = NonNull::new(opaque).unwrap().cast::<PL011State>();
23 unsafe { state.as_ref().migrate_clock }
24 }
25
26 /// Migration subsection for [`PL011State`] clock.
27 static VMSTATE_PL011_CLOCK: VMStateDescription = VMStateDescription {
28 name: c_str!("pl011/clock").as_ptr(),
29 version_id: 1,
30 minimum_version_id: 1,
31 needed: Some(pl011_clock_needed),
32 fields: vmstate_fields! {
33 vmstate_clock!(PL011State, clock),
34 },
35 ..Zeroable::ZERO
36 };
37
pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int38 extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int {
39 let state = NonNull::new(opaque).unwrap().cast::<PL011State>();
40 let result = unsafe { state.as_ref().post_load(version_id as u32) };
41 if result.is_err() {
42 -1
43 } else {
44 0
45 }
46 }
47
48 static VMSTATE_PL011_REGS: VMStateDescription = VMStateDescription {
49 name: c_str!("pl011/regs").as_ptr(),
50 version_id: 2,
51 minimum_version_id: 2,
52 fields: vmstate_fields! {
53 vmstate_of!(PL011Registers, flags),
54 vmstate_of!(PL011Registers, line_control),
55 vmstate_of!(PL011Registers, receive_status_error_clear),
56 vmstate_of!(PL011Registers, control),
57 vmstate_of!(PL011Registers, dmacr),
58 vmstate_of!(PL011Registers, int_enabled),
59 vmstate_of!(PL011Registers, int_level),
60 vmstate_of!(PL011Registers, read_fifo),
61 vmstate_of!(PL011Registers, ilpr),
62 vmstate_of!(PL011Registers, ibrd),
63 vmstate_of!(PL011Registers, fbrd),
64 vmstate_of!(PL011Registers, ifl),
65 vmstate_of!(PL011Registers, read_pos),
66 vmstate_of!(PL011Registers, read_count),
67 vmstate_of!(PL011Registers, read_trigger),
68 },
69 ..Zeroable::ZERO
70 };
71
72 pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
73 name: c_str!("pl011").as_ptr(),
74 version_id: 2,
75 minimum_version_id: 2,
76 post_load: Some(pl011_post_load),
77 fields: vmstate_fields! {
78 vmstate_unused!(core::mem::size_of::<u32>()),
79 vmstate_struct!(PL011State, regs, &VMSTATE_PL011_REGS, BqlRefCell<PL011Registers>),
80 },
81 subsections: vmstate_subsections! {
82 VMSTATE_PL011_CLOCK
83 },
84 ..Zeroable::ZERO
85 };
86
87 qemu_api::declare_properties! {
88 PL011_PROPERTIES,
89 qemu_api::define_property!(
90 c_str!("chardev"),
91 PL011State,
92 char_backend,
93 unsafe { &qdev_prop_chr },
94 CharBackend
95 ),
96 qemu_api::define_property!(
97 c_str!("migrate-clk"),
98 PL011State,
99 migrate_clock,
100 unsafe { &qdev_prop_bool },
101 bool,
102 default = true
103 ),
104 }
105