aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpc-11xx/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpc-11xx/src/lib.rs')
-rw-r--r--drivers/gpc-11xx/src/lib.rs381
1 files changed, 381 insertions, 0 deletions
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
+ );
+ }
+ }
+}