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*718e255fSPaolo Bonzini use core::ptr::NonNull;
6*718e255fSPaolo Bonzini use std::os::raw::{c_int, c_void};
737fdb2f5SManos Pitsidianakis
893243319SManos Pitsidianakis use qemu_api::{
9*718e255fSPaolo Bonzini bindings::*, c_str, vmstate_clock, vmstate_fields, vmstate_int32, vmstate_subsections,
10*718e255fSPaolo Bonzini vmstate_uint32, vmstate_uint32_array, vmstate_unused, zeroable::Zeroable,
1193243319SManos Pitsidianakis };
1237fdb2f5SManos Pitsidianakis
1393243319SManos Pitsidianakis use crate::device::{PL011State, PL011_FIFO_DEPTH};
1437fdb2f5SManos Pitsidianakis
pl011_clock_needed(opaque: *mut c_void) -> bool1593243319SManos Pitsidianakis extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool {
1693243319SManos Pitsidianakis unsafe {
1793243319SManos Pitsidianakis debug_assert!(!opaque.is_null());
1893243319SManos Pitsidianakis let state = NonNull::new_unchecked(opaque.cast::<PL011State>());
1993243319SManos Pitsidianakis state.as_ref().migrate_clock
2093243319SManos Pitsidianakis }
2193243319SManos Pitsidianakis }
2293243319SManos Pitsidianakis
2393243319SManos Pitsidianakis /// Migration subsection for [`PL011State`] clock.
2493243319SManos Pitsidianakis pub static VMSTATE_PL011_CLOCK: VMStateDescription = VMStateDescription {
25*718e255fSPaolo Bonzini name: c_str!("pl011/clock").as_ptr(),
2693243319SManos Pitsidianakis version_id: 1,
2793243319SManos Pitsidianakis minimum_version_id: 1,
2893243319SManos Pitsidianakis needed: Some(pl011_clock_needed),
2993243319SManos Pitsidianakis fields: vmstate_fields! {
3093243319SManos Pitsidianakis vmstate_clock!(clock, PL011State),
3193243319SManos Pitsidianakis },
3293243319SManos Pitsidianakis ..Zeroable::ZERO
3393243319SManos Pitsidianakis };
3493243319SManos Pitsidianakis
pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int3593243319SManos Pitsidianakis extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c_int {
3693243319SManos Pitsidianakis unsafe {
3793243319SManos Pitsidianakis debug_assert!(!opaque.is_null());
3893243319SManos Pitsidianakis let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
3993243319SManos Pitsidianakis let result = state.as_mut().post_load(version_id as u32);
4093243319SManos Pitsidianakis if result.is_err() {
4193243319SManos Pitsidianakis -1
4293243319SManos Pitsidianakis } else {
4393243319SManos Pitsidianakis 0
4493243319SManos Pitsidianakis }
4593243319SManos Pitsidianakis }
4693243319SManos Pitsidianakis }
4793243319SManos Pitsidianakis
4837fdb2f5SManos Pitsidianakis pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
49*718e255fSPaolo Bonzini name: c_str!("pl011").as_ptr(),
5093243319SManos Pitsidianakis version_id: 2,
5193243319SManos Pitsidianakis minimum_version_id: 2,
5293243319SManos Pitsidianakis post_load: Some(pl011_post_load),
5393243319SManos Pitsidianakis fields: vmstate_fields! {
5493243319SManos Pitsidianakis vmstate_unused!(core::mem::size_of::<u32>()),
5593243319SManos Pitsidianakis vmstate_uint32!(flags, PL011State),
5693243319SManos Pitsidianakis vmstate_uint32!(line_control, PL011State),
5793243319SManos Pitsidianakis vmstate_uint32!(receive_status_error_clear, PL011State),
5893243319SManos Pitsidianakis vmstate_uint32!(control, PL011State),
5993243319SManos Pitsidianakis vmstate_uint32!(dmacr, PL011State),
6093243319SManos Pitsidianakis vmstate_uint32!(int_enabled, PL011State),
6193243319SManos Pitsidianakis vmstate_uint32!(int_level, PL011State),
6293243319SManos Pitsidianakis vmstate_uint32_array!(read_fifo, PL011State, PL011_FIFO_DEPTH),
6393243319SManos Pitsidianakis vmstate_uint32!(ilpr, PL011State),
6493243319SManos Pitsidianakis vmstate_uint32!(ibrd, PL011State),
6593243319SManos Pitsidianakis vmstate_uint32!(fbrd, PL011State),
6693243319SManos Pitsidianakis vmstate_uint32!(ifl, PL011State),
6793243319SManos Pitsidianakis vmstate_int32!(read_pos, PL011State),
6893243319SManos Pitsidianakis vmstate_int32!(read_count, PL011State),
6993243319SManos Pitsidianakis vmstate_int32!(read_trigger, PL011State),
7093243319SManos Pitsidianakis },
7193243319SManos Pitsidianakis subsections: vmstate_subsections! {
7293243319SManos Pitsidianakis VMSTATE_PL011_CLOCK
7393243319SManos Pitsidianakis },
746e50bde1SPaolo Bonzini ..Zeroable::ZERO
7537fdb2f5SManos Pitsidianakis };
7637fdb2f5SManos Pitsidianakis
7737fdb2f5SManos Pitsidianakis qemu_api::declare_properties! {
7837fdb2f5SManos Pitsidianakis PL011_PROPERTIES,
7937fdb2f5SManos Pitsidianakis qemu_api::define_property!(
80*718e255fSPaolo Bonzini c_str!("chardev"),
8137fdb2f5SManos Pitsidianakis PL011State,
8237fdb2f5SManos Pitsidianakis char_backend,
8337fdb2f5SManos Pitsidianakis unsafe { &qdev_prop_chr },
8437fdb2f5SManos Pitsidianakis CharBackend
8537fdb2f5SManos Pitsidianakis ),
8637fdb2f5SManos Pitsidianakis qemu_api::define_property!(
87*718e255fSPaolo Bonzini c_str!("migrate-clk"),
8837fdb2f5SManos Pitsidianakis PL011State,
8937fdb2f5SManos Pitsidianakis migrate_clock,
9037fdb2f5SManos Pitsidianakis unsafe { &qdev_prop_bool },
91113c6688SPaolo Bonzini bool,
92113c6688SPaolo Bonzini default = true
9337fdb2f5SManos Pitsidianakis ),
9437fdb2f5SManos Pitsidianakis }
9537fdb2f5SManos Pitsidianakis
9637fdb2f5SManos Pitsidianakis qemu_api::device_class_init! {
9737fdb2f5SManos Pitsidianakis pl011_class_init,
9837fdb2f5SManos Pitsidianakis props => PL011_PROPERTIES,
9937fdb2f5SManos Pitsidianakis realize_fn => Some(pl011_realize),
10037fdb2f5SManos Pitsidianakis legacy_reset_fn => Some(pl011_reset),
10137fdb2f5SManos Pitsidianakis vmsd => VMSTATE_PL011,
10237fdb2f5SManos Pitsidianakis }
10337fdb2f5SManos Pitsidianakis
10437fdb2f5SManos Pitsidianakis /// # Safety
10537fdb2f5SManos Pitsidianakis ///
10637fdb2f5SManos Pitsidianakis /// We expect the FFI user of this function to pass a valid pointer, that has
10737fdb2f5SManos Pitsidianakis /// the same size as [`PL011State`]. We also expect the device is
10837fdb2f5SManos Pitsidianakis /// readable/writeable from one thread at any time.
pl011_realize(dev: *mut DeviceState, _errp: *mut *mut Error)10937fdb2f5SManos Pitsidianakis pub unsafe extern "C" fn pl011_realize(dev: *mut DeviceState, _errp: *mut *mut Error) {
11037fdb2f5SManos Pitsidianakis unsafe {
11137fdb2f5SManos Pitsidianakis assert!(!dev.is_null());
11237fdb2f5SManos Pitsidianakis let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
11337fdb2f5SManos Pitsidianakis state.as_mut().realize();
11437fdb2f5SManos Pitsidianakis }
11537fdb2f5SManos Pitsidianakis }
11637fdb2f5SManos Pitsidianakis
11737fdb2f5SManos Pitsidianakis /// # Safety
11837fdb2f5SManos Pitsidianakis ///
11937fdb2f5SManos Pitsidianakis /// We expect the FFI user of this function to pass a valid pointer, that has
12037fdb2f5SManos Pitsidianakis /// the same size as [`PL011State`]. We also expect the device is
12137fdb2f5SManos Pitsidianakis /// readable/writeable from one thread at any time.
pl011_reset(dev: *mut DeviceState)12237fdb2f5SManos Pitsidianakis pub unsafe extern "C" fn pl011_reset(dev: *mut DeviceState) {
12337fdb2f5SManos Pitsidianakis unsafe {
12437fdb2f5SManos Pitsidianakis assert!(!dev.is_null());
12537fdb2f5SManos Pitsidianakis let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
12637fdb2f5SManos Pitsidianakis state.as_mut().reset();
12737fdb2f5SManos Pitsidianakis }
12837fdb2f5SManos Pitsidianakis }
129