diff options
| author | Ian McIntyre <me@mciantyre.dev> | 2025-11-30 18:52:34 -0500 |
|---|---|---|
| committer | Ian McIntyre <me@mciantyre.dev> | 2025-11-30 19:10:51 -0500 |
| commit | 76199f21616ad86cf68f3b063c1ce23c6fc5a52f (patch) | |
| tree | 4c076d0afd649803a2bd9a5ed5cbb1f1c74fb459 /drivers/gpc-11xx | |
First commit
Diffstat (limited to 'drivers/gpc-11xx')
| -rw-r--r-- | drivers/gpc-11xx/Cargo.toml | 7 | ||||
| -rw-r--r-- | drivers/gpc-11xx/src/lib.rs | 381 |
2 files changed, 388 insertions, 0 deletions
diff --git a/drivers/gpc-11xx/Cargo.toml b/drivers/gpc-11xx/Cargo.toml new file mode 100644 index 0000000..65ded0f --- /dev/null +++ b/drivers/gpc-11xx/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "imxrt-drivers-gpc-11xx" +version = "0.1.0" +edition = "2024" + +[dependencies] +ral-registers = { workspace = true } diff --git a/drivers/gpc-11xx/src/lib.rs b/drivers/gpc-11xx/src/lib.rs new file mode 100644 index 0000000..847bb50 --- /dev/null +++ b/drivers/gpc-11xx/src/lib.rs @@ -0,0 +1,381 @@ +#![no_std] + +pub mod cpu_mode_ctrl { + pub type Instance = ral_registers::Instance<RegisterBlock>; + + #[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<u32> 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<u32> 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<u32> 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<u32> 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<u32> 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<u32> RW [] + } + + ral_registers::register! { + #[doc = "CM non-irq wakeup mask"] + pub CM_NON_IRQ_WAKEUP_MASK<u32> 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<u32> RO [] + } + + ral_registers::register! { + #[doc = "CM non-irq wakeup status"] + pub CM_NON_IRQ_WAKEUP_STAT<u32> 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<u32> 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<u32> 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<u32> 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<u32> 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<u32> 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 + ); + } + } +} |
