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