xref: /openbmc/qemu/rust/hw/char/pl011/src/device_class.rs (revision 93243319)
137fdb2f5SManos Pitsidianakis // Copyright 2024, Linaro Limited
237fdb2f5SManos Pitsidianakis // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
337fdb2f5SManos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later
437fdb2f5SManos Pitsidianakis 
5*93243319SManos Pitsidianakis use core::{
6*93243319SManos Pitsidianakis     ffi::{c_int, c_void},
7*93243319SManos Pitsidianakis     ptr::NonNull,
8*93243319SManos Pitsidianakis };
937fdb2f5SManos Pitsidianakis 
10*93243319SManos Pitsidianakis use qemu_api::{
11*93243319SManos Pitsidianakis     bindings::*, vmstate_clock, vmstate_fields, vmstate_int32, vmstate_subsections, vmstate_uint32,
12*93243319SManos Pitsidianakis     vmstate_uint32_array, vmstate_unused, zeroable::Zeroable,
13*93243319SManos Pitsidianakis };
1437fdb2f5SManos Pitsidianakis 
15*93243319SManos Pitsidianakis use crate::device::{PL011State, PL011_FIFO_DEPTH};
1637fdb2f5SManos Pitsidianakis 
17*93243319SManos Pitsidianakis extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool {
18*93243319SManos Pitsidianakis     unsafe {
19*93243319SManos Pitsidianakis         debug_assert!(!opaque.is_null());
20*93243319SManos Pitsidianakis         let state = NonNull::new_unchecked(opaque.cast::<PL011State>());
21*93243319SManos Pitsidianakis         state.as_ref().migrate_clock
22*93243319SManos Pitsidianakis     }
23*93243319SManos Pitsidianakis }
24*93243319SManos Pitsidianakis 
25*93243319SManos Pitsidianakis /// Migration subsection for [`PL011State`] clock.
26*93243319SManos Pitsidianakis pub static VMSTATE_PL011_CLOCK: VMStateDescription = VMStateDescription {
27*93243319SManos Pitsidianakis     name: c"pl011/clock".as_ptr(),
28*93243319SManos Pitsidianakis     version_id: 1,
29*93243319SManos Pitsidianakis     minimum_version_id: 1,
30*93243319SManos Pitsidianakis     needed: Some(pl011_clock_needed),
31*93243319SManos Pitsidianakis     fields: vmstate_fields! {
32*93243319SManos Pitsidianakis         vmstate_clock!(clock, PL011State),
33*93243319SManos Pitsidianakis     },
34*93243319SManos Pitsidianakis     ..Zeroable::ZERO
35*93243319SManos Pitsidianakis };
36*93243319SManos Pitsidianakis 
37*93243319SManos Pitsidianakis extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int {
38*93243319SManos Pitsidianakis     unsafe {
39*93243319SManos Pitsidianakis         debug_assert!(!opaque.is_null());
40*93243319SManos Pitsidianakis         let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
41*93243319SManos Pitsidianakis         let result = state.as_mut().post_load(version_id as u32);
42*93243319SManos Pitsidianakis         if result.is_err() {
43*93243319SManos Pitsidianakis             -1
44*93243319SManos Pitsidianakis         } else {
45*93243319SManos Pitsidianakis             0
46*93243319SManos Pitsidianakis         }
47*93243319SManos Pitsidianakis     }
48*93243319SManos Pitsidianakis }
49*93243319SManos Pitsidianakis 
5037fdb2f5SManos Pitsidianakis pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
51*93243319SManos Pitsidianakis     name: c"pl011".as_ptr(),
52*93243319SManos Pitsidianakis     version_id: 2,
53*93243319SManos Pitsidianakis     minimum_version_id: 2,
54*93243319SManos Pitsidianakis     post_load: Some(pl011_post_load),
55*93243319SManos Pitsidianakis     fields: vmstate_fields! {
56*93243319SManos Pitsidianakis         vmstate_unused!(core::mem::size_of::<u32>()),
57*93243319SManos Pitsidianakis         vmstate_uint32!(flags, PL011State),
58*93243319SManos Pitsidianakis         vmstate_uint32!(line_control, PL011State),
59*93243319SManos Pitsidianakis         vmstate_uint32!(receive_status_error_clear, PL011State),
60*93243319SManos Pitsidianakis         vmstate_uint32!(control, PL011State),
61*93243319SManos Pitsidianakis         vmstate_uint32!(dmacr, PL011State),
62*93243319SManos Pitsidianakis         vmstate_uint32!(int_enabled, PL011State),
63*93243319SManos Pitsidianakis         vmstate_uint32!(int_level, PL011State),
64*93243319SManos Pitsidianakis         vmstate_uint32_array!(read_fifo, PL011State, PL011_FIFO_DEPTH),
65*93243319SManos Pitsidianakis         vmstate_uint32!(ilpr, PL011State),
66*93243319SManos Pitsidianakis         vmstate_uint32!(ibrd, PL011State),
67*93243319SManos Pitsidianakis         vmstate_uint32!(fbrd, PL011State),
68*93243319SManos Pitsidianakis         vmstate_uint32!(ifl, PL011State),
69*93243319SManos Pitsidianakis         vmstate_int32!(read_pos, PL011State),
70*93243319SManos Pitsidianakis         vmstate_int32!(read_count, PL011State),
71*93243319SManos Pitsidianakis         vmstate_int32!(read_trigger, PL011State),
72*93243319SManos Pitsidianakis     },
73*93243319SManos Pitsidianakis     subsections: vmstate_subsections! {
74*93243319SManos Pitsidianakis         VMSTATE_PL011_CLOCK
75*93243319SManos Pitsidianakis     },
766e50bde1SPaolo Bonzini     ..Zeroable::ZERO
7737fdb2f5SManos Pitsidianakis };
7837fdb2f5SManos Pitsidianakis 
7937fdb2f5SManos Pitsidianakis qemu_api::declare_properties! {
8037fdb2f5SManos Pitsidianakis     PL011_PROPERTIES,
8137fdb2f5SManos Pitsidianakis     qemu_api::define_property!(
8237fdb2f5SManos Pitsidianakis         c"chardev",
8337fdb2f5SManos Pitsidianakis         PL011State,
8437fdb2f5SManos Pitsidianakis         char_backend,
8537fdb2f5SManos Pitsidianakis         unsafe { &qdev_prop_chr },
8637fdb2f5SManos Pitsidianakis         CharBackend
8737fdb2f5SManos Pitsidianakis     ),
8837fdb2f5SManos Pitsidianakis     qemu_api::define_property!(
8937fdb2f5SManos Pitsidianakis         c"migrate-clk",
9037fdb2f5SManos Pitsidianakis         PL011State,
9137fdb2f5SManos Pitsidianakis         migrate_clock,
9237fdb2f5SManos Pitsidianakis         unsafe { &qdev_prop_bool },
93113c6688SPaolo Bonzini         bool,
94113c6688SPaolo Bonzini         default = true
9537fdb2f5SManos Pitsidianakis     ),
9637fdb2f5SManos Pitsidianakis }
9737fdb2f5SManos Pitsidianakis 
9837fdb2f5SManos Pitsidianakis qemu_api::device_class_init! {
9937fdb2f5SManos Pitsidianakis     pl011_class_init,
10037fdb2f5SManos Pitsidianakis     props => PL011_PROPERTIES,
10137fdb2f5SManos Pitsidianakis     realize_fn => Some(pl011_realize),
10237fdb2f5SManos Pitsidianakis     legacy_reset_fn => Some(pl011_reset),
10337fdb2f5SManos Pitsidianakis     vmsd => VMSTATE_PL011,
10437fdb2f5SManos Pitsidianakis }
10537fdb2f5SManos Pitsidianakis 
10637fdb2f5SManos Pitsidianakis /// # Safety
10737fdb2f5SManos Pitsidianakis ///
10837fdb2f5SManos Pitsidianakis /// We expect the FFI user of this function to pass a valid pointer, that has
10937fdb2f5SManos Pitsidianakis /// the same size as [`PL011State`]. We also expect the device is
11037fdb2f5SManos Pitsidianakis /// readable/writeable from one thread at any time.
11137fdb2f5SManos Pitsidianakis pub unsafe extern "C" fn pl011_realize(dev: *mut DeviceState, _errp: *mut *mut Error) {
11237fdb2f5SManos Pitsidianakis     unsafe {
11337fdb2f5SManos Pitsidianakis         assert!(!dev.is_null());
11437fdb2f5SManos Pitsidianakis         let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
11537fdb2f5SManos Pitsidianakis         state.as_mut().realize();
11637fdb2f5SManos Pitsidianakis     }
11737fdb2f5SManos Pitsidianakis }
11837fdb2f5SManos Pitsidianakis 
11937fdb2f5SManos Pitsidianakis /// # Safety
12037fdb2f5SManos Pitsidianakis ///
12137fdb2f5SManos Pitsidianakis /// We expect the FFI user of this function to pass a valid pointer, that has
12237fdb2f5SManos Pitsidianakis /// the same size as [`PL011State`]. We also expect the device is
12337fdb2f5SManos Pitsidianakis /// readable/writeable from one thread at any time.
12437fdb2f5SManos Pitsidianakis pub unsafe extern "C" fn pl011_reset(dev: *mut DeviceState) {
12537fdb2f5SManos Pitsidianakis     unsafe {
12637fdb2f5SManos Pitsidianakis         assert!(!dev.is_null());
12737fdb2f5SManos Pitsidianakis         let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
12837fdb2f5SManos Pitsidianakis         state.as_mut().reset();
12937fdb2f5SManos Pitsidianakis     }
13037fdb2f5SManos Pitsidianakis }
131