#![no_std] pub mod cpu_mode_ctrl { pub type Instance = ral_registers::Instance; #[repr(C)] #[allow(non_snake_case)] pub struct RegisterBlock { reserved_0: [u8; 4], pub CM_AUTHEN_CTRL: u32, pub CM_INT_CTRL: u32, pub CM_MISC: u32, pub CM_MODE_CTRL: u32, pub CM_MODE_STAT: u32, reserved_1: [u8; 232], pub CM_IRQ_WAKEUP_MASK: [u32; 8], reserved_2: [u8; 32], pub CM_NON_IRQ_WAKEUP_MASK: u32, reserved_3: [u8; 12], pub CM_IRQ_WAKEUP_STAT: [u32; 8], reserved_4: [u8; 32], pub CM_NON_IRQ_WAKEUP_STAT: u32, reserved_5: [u8; 108], pub CM_SLEEP_SSAR_CTRL: u32, reserved_6: [u8; 4], pub CM_SLEEP_LPCG_CTRL: u32, reserved_7: [u8; 4], pub CM_SLEEP_PLL_CTRL: u32, reserved_8: [u8; 4], pub CM_SLEEP_ISO_CTRL: u32, reserved_9: [u8; 4], pub CM_SLEEP_RESET_CTRL: u32, reserved_10: [u8; 4], pub CM_SLEEP_POWER_CTRL: u32, reserved_11: [u8; 100], pub CM_WAKEUP_POWER_CTRL: u32, reserved_12: [u8; 4], pub CM_WAKEUP_RESET_CTRL: u32, reserved_13: [u8; 4], pub CM_WAKEUP_ISO_CTRL: u32, reserved_14: [u8; 4], pub CM_WAKEUP_PLL_CTRL: u32, reserved_15: [u8; 4], pub CM_WAKEUP_LPCG_CTRL: u32, reserved_16: [u8; 4], pub CM_WAKEUP_SSAR_CTRL: u32, reserved_17: [u8; 68], pub CM_SP_CTRL: u32, pub CM_SP_STAT: u32, reserved_18: [u8; 8], pub CM_RUN_MODE_MAPPING: u32, pub CM_WAIT_MODE_MAPPING: u32, pub CM_STOP_MODE_MAPPING: u32, pub CM_SUSPEND_MODE_MAPPING: u32, pub CM_SP_MAPPING: [u32; 16], reserved_19: [u8; 32], pub CM_STBY_CTRL: u32, } ral_registers::register! { #[doc = "CM Authentication Control"] pub CM_AUTHEN_CTRL RW [ #[doc = "Allow user mode access"] USER start(0) width(1) RW {} #[doc = "Allow non-secure mode access"] NONSECURE start(1) width(1) RW {} #[doc = "Lock NONSECURE and USER"] LOCK_SETTING start(4) width(1) RW {} #[doc = "Domain ID white list"] WHITE_LIST start(8) width(4) RW {} #[doc = "White list lock"] LOCK_LIST start(12) width(1) RW {} #[doc = "Configuration lock"] LOCK_CFG start(20) width(1) RW {} ] } ral_registers::register! { #[doc = "CM Interrupt Control"] pub CM_INT_CTRL RW [ #[doc = "sp_req_not_allowed_for_sleep interrupt enable"] SP_REQ_NOT_ALLOWED_SLEEP_INT_EN start(0) width(1) RW {} #[doc = "sp_req_not_allowed_for_wakeup interrupt enable"] SP_REQ_NOT_ALLOWED_WAKEUP_INT_EN start(1) width(1) RW {} #[doc = "sp_req_not_allowed_for_soft interrupt enable"] SP_REQ_NOT_ALLOWED_SOFT_INT_EN start(2) width(1) RW {} #[doc = "sp_req_not_allowed_for_sleep interrupt status and clear register"] SP_REQ_NOT_ALLOWED_SLEEP_INT start(16) width(1) RW {} #[doc = "sp_req_not_allowed_for_wakeup interrupt status and clear register"] SP_REQ_NOT_ALLOWED_WAKEUP_INT start(17) width(1) RW {} #[doc = "sp_req_not_allowed_for_soft interrupt status and clear register"] SP_REQ_NOT_ALLOWED_SOFT_INT start(18) width(1) RW {} ] } ral_registers::register! { #[doc = "Miscellaneous"] pub CM_MISC RW [ #[doc = "Non-masked interrupt status"] NMI_STAT start(0) width(1) RO {} #[doc = "Allow cpu_sleep_hold_req assert during CPU low power status"] SLEEP_HOLD_EN start(1) width(1) RW {} #[doc = "Status of cpu_sleep_hold_ack_b"] SLEEP_HOLD_STAT start(2) width(1) RO {} #[doc = "Master CPU"] MASTER_CPU start(4) width(1) RW {} ] } ral_registers::register! { #[doc = "CPU mode control"] pub CM_MODE_CTRL RW [ #[doc = "The CPU mode the CPU platform should transit to on next sleep event"] CPU_MODE_TARGET start(0) width(2) RW { #[doc = "Stay in RUN mode"] RUN = 0, #[doc = "Transit to WAIT mode"] WAIT = 0x1, #[doc = "Transit to STOP mode"] STOP = 0x2, #[doc = "Transit to SUSPEND mode"] SUSPEND = 0x3, } #[doc = "WFE assertion can be sleep event"] WFE_EN start(4) width(1) RW {} ] } ral_registers::register! { #[doc = "CM CPU mode Status"] pub CM_MODE_STAT RO [ #[doc = "Current CPU mode"] CPU_MODE_CURRENT start(0) width(2) RO { #[doc = "CPU is currently in RUN mode"] RUN = 0, #[doc = "CPU is currently in WAIT mode"] WAIT = 0x1, #[doc = "CPU is currently in STOP mode"] STOP = 0x2, #[doc = "CPU is currently in SUSPEND mode"] SUSPEND = 0x3, } #[doc = "Previous CPU mode"] CPU_MODE_PREVIOUS start(2) width(2) RO { #[doc = "CPU was previously in RUN mode"] RUN = 0, #[doc = "CPU was previously in WAIT mode"] WAIT = 0x1, #[doc = "CPU was previously in STOP mode"] STOP = 0x2, #[doc = "CPU was previously in SUSPEND mode"] SUSPEND = 0x3, } ] } ral_registers::register! { #[doc = "CM IRQ0~31 wakeup mask"] pub CM_IRQ_WAKEUP_MASK RW [] } ral_registers::register! { #[doc = "CM non-irq wakeup mask"] pub CM_NON_IRQ_WAKEUP_MASK RW [ #[doc = "There are 256 interrupts and 1 event as a wakeup source for GPC. This field masks the 1 event wakeup source."] EVENT_WAKEUP_MASK start(0) width(1) RW {} #[doc = "1 means the debug_wakeup_request cannot wakeup CPU platform"] DEBUG_WAKEUP_MASK start(1) width(1) RW {} ] } ral_registers::register! { #[doc = "CM IRQ0~31 wakeup status"] pub CM_IRQ_WAKEUP_STAT RO [] } ral_registers::register! { #[doc = "CM non-irq wakeup status"] pub CM_NON_IRQ_WAKEUP_STAT RO [ #[doc = "Event wakeup status"] EVENT_WAKEUP_STAT start(0) width(1) RO {} #[doc = "Debug wakeup status"] DEBUG_WAKEUP_STAT start(1) width(1) RO {} ] } ral_registers::register! { #[doc(hidden)] pub CM_SLEEP_WAKEUP_CTRL RW [ #[doc = "Step count, useage is depending on CNT_MODE."] STEP_CNT start(0) width(16) RW {} #[doc = "Count mode"] CNT_MODE start(28) width(2) RW { #[doc = "Counter disable mode: not use step counter, step completes once receiving step_done"] DISABLE = 0, #[doc = "Counter delay mode: delay after receiving step_done, delay cycle number is STEP_CNT"] DELAY = 0x1, #[doc = "Ignore step_done response, the counter starts to count once step begins, when counter reaches STEP_CNT value, the step completes"] IGNORE_STEP_DONE = 0x2, #[doc = "Time out mode, the counter starts to count once step begins, the step completes when either step_done received or counting to STEP_CNT value"] TIMEOUT = 0x3, } #[doc = "Disable this step"] DISABLE start(31) width(1) RW {} ] } use core::num::NonZeroU32; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_SLEEP_LPGC_CTRL; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_SLEEP_PLL_CTRL; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_SLEEP_ISO_CTRL; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_SLEEP_RESET_CTRL; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_SLEEP_POWER_CTRL; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_SLEEP_SSAR_CTRL; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_WAKEUP_LPGC_CTRL; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_WAKEUP_PLL_CTRL; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_WAKEUP_ISO_CTRL; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_WAKEUP_RESET_CTRL; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_WAKEUP_POWER_CTRL; #[doc(inline)] pub use CM_SLEEP_WAKEUP_CTRL as CM_WAKEUP_SSAR_CTRL; ral_registers::register! { #[doc = "CM Setpoint Control"] pub CM_SP_CTRL RW [ #[doc = "Request a Setpoint transition when this bit is set"] RUN_EN start(0) width(1) RW {} #[doc = "The Setpoint that CPU want the system to transit to when CPU_SP_RUN_EN is set"] RUN start(1) width(4) RW {} #[doc = "1 means enable Setpoint transition on next CPU platform sleep sequence"] SLEEP_EN start(5) width(1) RW {} #[doc = "The Setpoint that CPU want the system to transit to on next CPU platform sleep sequence"] SLEEP start(6) width(4) RW {} #[doc = "1 means enable Setpoint transition on next CPU platform wakeup sequence"] WAKEUP_EN start(10) width(1) RW {} #[doc = "The Setpoint that CPU want the system to transit to on next CPU platform wakeup sequence"] WAKEUP start(11) width(4) RW {} #[doc = "Select the Setpoint transiton on the next CPU platform wakeup sequence"] WAKEUP_SEL start(15) width(1) RW {} ] } ral_registers::register! { #[doc = "CM Setpoint Status"] pub CM_SP_STAT RO [ #[doc = "The current Setpoint of the system"] CURRENT start(0) width(4) RO {} #[doc = "The previous Setpoint of the system"] PREVIOUS start(4) width(4) RO {} #[doc = "The requested Setpoint from the CPU platform"] TARGET start(8) width(4) RO {} ] } ral_registers::register! { #[doc(hidden)] pub CM_MAPPING RW [ #[doc = "Defines which Setpoint is allowed when CPU enters this mode. Each bit stands for 1 Setpoint, locked by LOCK_CFG field"] CPU_MAPPING start(0) width(16) RW {} ] } #[doc(inline)] pub use CM_MAPPING as CM_RUN_MODE_MAPPING; #[doc(inline)] pub use CM_MAPPING as CM_WAIT_MODE_MAPPING; #[doc(inline)] pub use CM_MAPPING as CM_STOP_MODE_MAPPING; #[doc(inline)] pub use CM_MAPPING as CM_SUSUPEND_MODE_MAPPING; #[doc(inline)] pub use CM_MAPPING as CM_SP_MAPPING; ral_registers::register! { #[doc = "CM standby control"] pub CM_STBY_CTRL RW [ #[doc = "0x1: Request the chip into standby mode when CPU entering WAIT mode, locked by LOCK_CFG field."] WAIT start(0) width(1) RW {} #[doc = "0x1: Request the chip into standby mode when CPU entering STOP mode, locked by LOCK_CFG field."] STOP start(1) width(1) RW {} #[doc = "0x1: Request the chip into standby mode when CPU entering SUSPEND mode, locked by LOCK_CFG field."] SUSPEND start(2) width(1) RW {} #[doc = "Indicate the CPU is busy entering standby mode."] SLEEP_BUSY start(16) width(1) RO {} #[doc = "Indicate the CPU is busy exiting standby mode."] WAKEUP_BUSY start(17) width(1) RO {} ] } /// The wrapped setpoint is invalid. #[derive(Clone, Copy, PartialEq, Eq)] #[repr(transparent)] pub struct InvalidSetpointError(NonZeroU32); // Amenable to niche optimizations in a Result, Option. impl InvalidSetpointError { /// Returns the invalid setpoint that you specified. #[inline] #[must_use] pub const fn which(self) -> u32 { self.0.get() - 1 } /// Produce an error from a user-supplied invalid setpoint. #[must_use] #[inline] fn from_raw(setpoint: u32) -> Self { // Safety: any setpoint plus one is naturally // non-zero. Saturating add prevents wrap around, // ignoring the possibility that the user supplied // a very invalid setpoint. Self(unsafe { NonZeroU32::new_unchecked(setpoint.saturating_add(1)) }) } } /// Check if a setpoint is valid. pub fn check_setpoint(setpoint: u32) -> Result<(), InvalidSetpointError> { if setpoint < 16 { Ok(()) } else { Err(InvalidSetpointError::from_raw(setpoint)) } } impl core::fmt::Debug for InvalidSetpointError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("InvalidSetpointError") .field(&self.which()) .finish() } } impl core::fmt::Display for InvalidSetpointError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Invalid setpoint: {}", self.which()) } } /// Ask the GPC for a setpoint transition, blocking until /// the request concludes. /// /// Your setpoint must be less than 16. Otherwise, this call /// returns an error. pub fn request_setpoint_transition( gpc: Instance, setpoint: u32, ) -> Result<(), InvalidSetpointError> { check_setpoint(setpoint)?; ral_registers::modify_reg!(self, gpc, CM_SP_CTRL, RUN: setpoint as u32, RUN_EN: 1); while ral_registers::read_reg!(self, gpc, CM_SP_CTRL, RUN_EN == 1) {} Ok(()) } #[cfg(test)] mod tests { #[test] fn layout() { assert_eq!( core::mem::offset_of!(super::RegisterBlock, CM_SP_CTRL), 0x300 ); assert_eq!( core::mem::offset_of!(super::RegisterBlock, CM_STBY_CTRL), 0x380 ); } } }