xref: /openbmc/qemu/rust/hw/char/pl011/src/device_class.rs (revision 93243319)
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 core::{
6     ffi::{c_int, c_void},
7     ptr::NonNull,
8 };
9 
10 use qemu_api::{
11     bindings::*, vmstate_clock, vmstate_fields, vmstate_int32, vmstate_subsections, vmstate_uint32,
12     vmstate_uint32_array, vmstate_unused, zeroable::Zeroable,
13 };
14 
15 use crate::device::{PL011State, PL011_FIFO_DEPTH};
16 
17 extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool {
18     unsafe {
19         debug_assert!(!opaque.is_null());
20         let state = NonNull::new_unchecked(opaque.cast::<PL011State>());
21         state.as_ref().migrate_clock
22     }
23 }
24 
25 /// Migration subsection for [`PL011State`] clock.
26 pub static VMSTATE_PL011_CLOCK: VMStateDescription = VMStateDescription {
27     name: c"pl011/clock".as_ptr(),
28     version_id: 1,
29     minimum_version_id: 1,
30     needed: Some(pl011_clock_needed),
31     fields: vmstate_fields! {
32         vmstate_clock!(clock, PL011State),
33     },
34     ..Zeroable::ZERO
35 };
36 
37 extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int {
38     unsafe {
39         debug_assert!(!opaque.is_null());
40         let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
41         let result = state.as_mut().post_load(version_id as u32);
42         if result.is_err() {
43             -1
44         } else {
45             0
46         }
47     }
48 }
49 
50 pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
51     name: c"pl011".as_ptr(),
52     version_id: 2,
53     minimum_version_id: 2,
54     post_load: Some(pl011_post_load),
55     fields: vmstate_fields! {
56         vmstate_unused!(core::mem::size_of::<u32>()),
57         vmstate_uint32!(flags, PL011State),
58         vmstate_uint32!(line_control, PL011State),
59         vmstate_uint32!(receive_status_error_clear, PL011State),
60         vmstate_uint32!(control, PL011State),
61         vmstate_uint32!(dmacr, PL011State),
62         vmstate_uint32!(int_enabled, PL011State),
63         vmstate_uint32!(int_level, PL011State),
64         vmstate_uint32_array!(read_fifo, PL011State, PL011_FIFO_DEPTH),
65         vmstate_uint32!(ilpr, PL011State),
66         vmstate_uint32!(ibrd, PL011State),
67         vmstate_uint32!(fbrd, PL011State),
68         vmstate_uint32!(ifl, PL011State),
69         vmstate_int32!(read_pos, PL011State),
70         vmstate_int32!(read_count, PL011State),
71         vmstate_int32!(read_trigger, PL011State),
72     },
73     subsections: vmstate_subsections! {
74         VMSTATE_PL011_CLOCK
75     },
76     ..Zeroable::ZERO
77 };
78 
79 qemu_api::declare_properties! {
80     PL011_PROPERTIES,
81     qemu_api::define_property!(
82         c"chardev",
83         PL011State,
84         char_backend,
85         unsafe { &qdev_prop_chr },
86         CharBackend
87     ),
88     qemu_api::define_property!(
89         c"migrate-clk",
90         PL011State,
91         migrate_clock,
92         unsafe { &qdev_prop_bool },
93         bool,
94         default = true
95     ),
96 }
97 
98 qemu_api::device_class_init! {
99     pl011_class_init,
100     props => PL011_PROPERTIES,
101     realize_fn => Some(pl011_realize),
102     legacy_reset_fn => Some(pl011_reset),
103     vmsd => VMSTATE_PL011,
104 }
105 
106 /// # Safety
107 ///
108 /// We expect the FFI user of this function to pass a valid pointer, that has
109 /// the same size as [`PL011State`]. We also expect the device is
110 /// readable/writeable from one thread at any time.
111 pub unsafe extern "C" fn pl011_realize(dev: *mut DeviceState, _errp: *mut *mut Error) {
112     unsafe {
113         assert!(!dev.is_null());
114         let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
115         state.as_mut().realize();
116     }
117 }
118 
119 /// # Safety
120 ///
121 /// We expect the FFI user of this function to pass a valid pointer, that has
122 /// the same size as [`PL011State`]. We also expect the device is
123 /// readable/writeable from one thread at any time.
124 pub unsafe extern "C" fn pl011_reset(dev: *mut DeviceState) {
125     unsafe {
126         assert!(!dev.is_null());
127         let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
128         state.as_mut().reset();
129     }
130 }
131