use core::num::NonZero; pub type Instance = ral_registers::Instance; #[repr(C)] #[allow(non_snake_case)] pub struct RegisterBlock { reserved_0: [u8; 512], pub ARM_PLL_CTRL: u32, reserved_1: [u8; 12], pub SYS_PLL3_CTRL: u32, reserved_2: [u8; 12], pub SYS_PLL3_UPDATE: u32, reserved_3: [u8; 12], pub SYS_PLL3_PFD: u32, reserved_4: [u8; 12], pub SYS_PLL2_CTRL: u32, reserved_5: [u8; 12], pub SYS_PLL2_UPDATE: u32, reserved_6: [u8; 12], pub SYS_PLL2_SS: u32, reserved_7: [u8; 12], pub SYS_PLL2_PFD: u32, reserved_8: [u8; 44], pub SYS_PLL2_MFD: u32, reserved_9: [u8; 12], pub SYS_PLL1_SS: u32, reserved_10: [u8; 12], pub SYS_PLL1_CTRL: u32, reserved_11: [u8; 12], pub SYS_PLL1_DENOMINATOR: u32, reserved_12: [u8; 12], pub SYS_PLL1_NUMERATOR: u32, reserved_13: [u8; 12], pub SYS_PLL1_DIV_SELECT: u32, reserved_14: [u8; 12], pub PLL_AUDIO_CTRL: u32, reserved_15: [u8; 12], pub PLL_AUDIO_SS: u32, reserved_16: [u8; 12], pub PLL_AUDIO_DENOMINATOR: u32, reserved_17: [u8; 12], pub PLL_AUDIO_NUMERATOR: u32, reserved_18: [u8; 12], pub PLL_AUDIO_DIV_SELECT: u32, reserved_19: [u8; 12], pub PLL_VIDEO_CTRL: u32, reserved_20: [u8; 12], pub PLL_VIDEO_SS: u32, reserved_21: [u8; 12], pub PLL_VIDEO_DENOMINATOR: u32, reserved_22: [u8; 12], pub PLL_VIDEO_NUMERATOR: u32, reserved_23: [u8; 12], pub PLL_VIDEO_DIV_SELECT: u32, } ral_registers::register! { #[doc = "SYS_PLL1_CTRL_REGISTER"] pub SYS_PLL1_CTRL RW [ #[doc = "ENABLE_CLK"] ENABLE_CLK start(13) width(1) RW {} #[doc = "SYS_PLL1_GATE"] SYS_PLL1_GATE start(14) width(1) RW {} #[doc = "SYS_PLL1_DIV2"] SYS_PLL1_DIV2 start(25) width(1) RW {} #[doc = "SYS_PLL1_DIV5"] SYS_PLL1_DIV5 start(26) width(1) RW {} #[doc = "SYS_PLL1_DIV5_CONTROL_MODE"] SYS_PLL1_DIV5_CONTROL_MODE start(27) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } #[doc = "SYS_PLL1_DIV2_CONTROL_MODE"] SYS_PLL1_DIV2_CONTROL_MODE start(28) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } #[doc = "SYS_PLL1_STABLE"] SYS_PLL1_STABLE start(29) width(1) RO {} #[doc = "SYS_PLL1_AI_BUSY"] SYS_PLL1_AI_BUSY start(30) width(1) RO {} #[doc = "SYS_PLL1_CONTROL_MODE"] SYS_PLL1_CONTROL_MODE start(31) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } ] } /// Manage all SYS_PLL1 clocks using setpoints. pub fn enable_sys_pll1_setpoints(pll: ral_registers::Instance) { ral_registers::modify_reg!(self, pll, SYS_PLL1_CTRL, SYS_PLL1_CONTROL_MODE: GPC, SYS_PLL1_DIV2_CONTROL_MODE: GPC, SYS_PLL1_DIV5_CONTROL_MODE: GPC, ); } ral_registers::register! { #[doc = "ARM_PLL_CTRL_REGISTER"] pub ARM_PLL_CTRL RW [ #[doc = "DIV_SELECT"] DIV_SELECT start(0) width(8) RW {} #[doc = "PLL Start up initialization"] HOLD_RING_OFF start(12) width(1) RW {} #[doc = "Powers up the PLL."] POWERUP start(13) width(1) RW {} #[doc = "Enable the clock output."] ENABLE_CLK start(14) width(1) RW {} #[doc = "POST_DIV_SEL"] POST_DIV_SEL start(15) width(2) RW { #[doc = "Divide by 2"] DIV2 = 0, #[doc = "Divide by 4"] DIV4 = 0x1, #[doc = "Divide by 8"] DIV8 = 0x2, #[doc = "Divide by 1"] DIV1 = 0x3, } #[doc = "Bypass the pll."] BYPASS start(17) width(1) RW {} #[doc = "ARM_PLL_STABLE"] ARM_PLL_STABLE start(29) width(1) RO {} #[doc = "ARM_PLL_GATE"] ARM_PLL_GATE start(30) width(1) RW {} #[doc = "pll_arm_control_mode"] ARM_PLL_CONTROL_MODE start(31) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } ] } /// Post divider for the ARM PLL. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u32)] pub enum ArmPllPostDiv { /// Divide by 2. Div2 = 0, /// Divide by 4. Div4 = 1, /// Divide by 8. Div8 = 2, /// Divide by 1. Div1 = 3, } impl ArmPllPostDiv { /// Return the divisor for this post divider. #[must_use] pub const fn divisor(self) -> u32 { match self { Self::Div2 => 2, Self::Div4 => 4, Self::Div8 => 8, Self::Div1 => 1, } } } /// The ARM PLL loop divider. /// /// This value is always clamped between 104 and 208. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(transparent)] pub struct ArmPllDivSelect(NonZero); impl ArmPllDivSelect { /// Construct a loop divider. /// /// The implementation clamps the value between 104 and 208. #[must_use] pub const fn new(div_select: u32) -> Option { if 104 <= div_select && div_select <= 208 { Some(Self(NonZero::new(div_select).unwrap())) } else { None } } /// Returns the divider as a raw value. #[must_use] #[inline] pub const fn get(self) -> u32 { self.0.get() } } /// Manage the ARM PLL with setpoints. /// /// `post_div` is the post divider selection applied when the /// PLL is enabled. Similarly `div_select` is the loop divider. /// Use [`arm_pll_frequency`] to understand the expected frequency /// affected by this call. pub fn enable_arm_pll_setpoints( pll: ral_registers::Instance, post_div: ArmPllPostDiv, div_select: ArmPllDivSelect, ) { ral_registers::modify_reg!(self, pll, ARM_PLL_CTRL, DIV_SELECT: div_select.get(), POST_DIV_SEL: post_div as u32, ARM_PLL_GATE: 1, ARM_PLL_CONTROL_MODE: GPC, ENABLE_CLK: 0, ); } /// Computes the expected ARM PLL frequency. pub const fn arm_pll_frequency(post_div: ArmPllPostDiv, div_select: ArmPllDivSelect) -> u32 { 24_000_000 / 2 / post_div.divisor() * div_select.get() } ral_registers::register! { #[doc = "SYS_PLL2_CTRL_REGISTER"] pub SYS_PLL2_CTRL RW [ #[doc = "Enable Internal PLL Regulator"] PLL_REG_EN start(3) width(1) RW {} #[doc = "PLL Start up initialization"] HOLD_RING_OFF start(11) width(1) RW {} #[doc = "Enable the clock output."] ENABLE_CLK start(13) width(1) RW {} #[doc = "Bypass the pll."] BYPASS start(16) width(1) RW {} #[doc = "DITHER_ENABLE"] DITHER_ENABLE start(17) width(1) RW {} #[doc = "PFD_OFFSET_EN"] PFD_OFFSET_EN start(18) width(1) RW {} #[doc = "PLL_DDR_OVERRIDE"] PLL_DDR_OVERRIDE start(19) width(1) RW {} #[doc = "Powers up the PLL."] POWERUP start(23) width(1) RW {} #[doc = "SYS_PLL2_STABLE"] SYS_PLL2_STABLE start(29) width(1) RO {} #[doc = "SYS_PLL2_GATE"] SYS_PLL2_GATE start(30) width(1) RW {} #[doc = "SYS_PLL2_control_mode"] SYS_PLL2_CONTROL_MODE start(31) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } ] } ral_registers::register! { #[doc = "SYS_PLL2_UPDATE_REGISTER"] pub SYS_PLL2_UPDATE RW [ #[doc = "PFD0_UPDATE"] PFD0_UPDATE start(1) width(1) RW {} #[doc = "PFD1_UPDATE"] PFD1_UPDATE start(2) width(1) RW {} #[doc = "PFD2_UPDATE"] PFD2_UPDATE start(3) width(1) RW {} #[doc = "PFD3_UPDATE"] PFD3_UPDATE start(4) width(1) RW {} #[doc = "pfd0_control_mode"] PFD0_CONTROL_MODE start(5) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } #[doc = "pfd1_control_mode"] PFD1_CONTROL_MODE start(6) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } #[doc = "pfd2_control_mode"] PFD2_CONTROL_MODE start(7) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } #[doc = "pfd3_control_mode"] PFD3_CONTROL_MODE start(8) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } ] } /// Manage SYS_PLL2 clocks and PFDs using setpoints. pub fn enable_sys_pll2_setpoints(pll: ral_registers::Instance) { ral_registers::modify_reg!(self, pll, SYS_PLL2_UPDATE, PFD3_CONTROL_MODE: GPC, PFD2_CONTROL_MODE: GPC, PFD1_CONTROL_MODE: GPC, PFD0_CONTROL_MODE: GPC, ); ral_registers::modify_reg!(self, pll, SYS_PLL2_CTRL, SYS_PLL2_CONTROL_MODE: GPC, SYS_PLL2_GATE: 1, ENABLE_CLK: 0, ); } ral_registers::register! { #[doc = "SYS_PLL3_CTRL_REGISTER"] pub SYS_PLL3_CTRL RW [ #[doc = "SYS PLL3 DIV2 gate"] SYS_PLL3_DIV2 start(3) width(1) RW {} #[doc = "Enable Internal PLL Regulator"] PLL_REG_EN start(4) width(1) RW {} #[doc = "PLL Start up initialization"] HOLD_RING_OFF start(11) width(1) RW {} #[doc = "Enable the clock output."] ENABLE_CLK start(13) width(1) RW {} #[doc = "BYPASS"] BYPASS start(16) width(1) RW {} #[doc = "Powers up the PLL."] POWERUP start(21) width(1) RW {} #[doc = "SYS_PLL3_DIV2_CONTROL_MODE"] SYS_PLL3_DIV2_CONTROL_MODE start(28) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } #[doc = "SYS_PLL3_STABLE"] SYS_PLL3_STABLE start(29) width(1) RO {} #[doc = "SYS_PLL3_GATE"] SYS_PLL3_GATE start(30) width(1) RW {} #[doc = "SYS_PLL3_control_mode"] SYS_PLL3_CONTROL_MODE start(31) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } ] } ral_registers::register! { #[doc = "SYS_PLL3_UPDATE_REGISTER"] pub SYS_PLL3_UPDATE RW [ #[doc = "PFD0_OVERRIDE"] PFD0_UPDATE start(1) width(1) RW {} #[doc = "PFD1_OVERRIDE"] PFD1_UPDATE start(2) width(1) RW {} #[doc = "PFD2_OVERRIDE"] PFD2_UPDATE start(3) width(1) RW {} #[doc = "PFD3_UPDATE"] PFD3_UPDATE start(4) width(1) RW {} #[doc = "pfd0_control_mode"] PFD0_CONTROL_MODE start(5) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } #[doc = "pfd1_control_mode"] PFD1_CONTROL_MODE start(6) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } #[doc = "pdf2_control_mode"] PFD2_CONTROL_MODE start(7) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } #[doc = "pfd3_control_mode"] PFD3_CONTROL_MODE start(8) width(1) RW { #[doc = "Software Mode (Default)"] SW = 0, #[doc = "GPC Mode"] GPC = 0x1, } ] } /// Manage SYS_PLL3 clocks and PFDs using setpoints. pub fn enable_sys_pll3_setpoints(pll: ral_registers::Instance) { ral_registers::modify_reg!(self, pll, SYS_PLL3_UPDATE, PFD3_CONTROL_MODE: GPC, PFD2_CONTROL_MODE: GPC, PFD1_CONTROL_MODE: GPC, PFD0_CONTROL_MODE: GPC, ); ral_registers::modify_reg!(self, pll, SYS_PLL3_CTRL, SYS_PLL3_CONTROL_MODE: GPC, SYS_PLL3_DIV2_CONTROL_MODE: GPC, SYS_PLL3_GATE: 1, ENABLE_CLK: 0, ); } ral_registers::register! { #[doc = "SYS_PLL3_PFD_REGISTER"] pub SYS_PLL3_PFD RW [ #[doc = "PFD0_FRAC"] PFD0_FRAC start(0) width(6) RW {} #[doc = "PFD0_STABLE"] PFD0_STABLE start(6) width(1) RO {} #[doc = "PFD0_DIV1_CLKGATE"] PFD0_DIV1_CLKGATE start(7) width(1) RW {} #[doc = "PFD1_FRAC"] PFD1_FRAC start(8) width(6) RW {} #[doc = "PFD1_STABLE"] PFD1_STABLE start(14) width(1) RO {} #[doc = "PFD1_DIV1_CLKGATE"] PFD1_DIV1_CLKGATE start(15) width(1) RW {} #[doc = "PFD2_FRAC"] PFD2_FRAC start(16) width(6) RW {} #[doc = "PFD2_STABLE"] PFD2_STABLE start(22) width(1) RO {} #[doc = "PFD2_DIV1_CLKGATE"] PFD2_DIV1_CLKGATE start(23) width(1) RW {} #[doc = "PFD3_FRAC"] PFD3_FRAC start(24) width(6) RW {} #[doc = "PFD3_STABLE"] PFD3_STABLE start(30) width(1) RO {} #[doc = "PFD3_DIV1_CLKGATE"] PFD3_DIV1_CLKGATE start(31) width(1) RW {} ] } ral_registers::register! { #[doc = "SYS_PLL2_PFD_REGISTER"] pub SYS_PLL2_PFD RW [ #[doc = "PFD0_FRAC"] PFD0_FRAC start(0) width(6) RW {} #[doc = "PFD0_STABLE"] PFD0_STABLE start(6) width(1) RO {} #[doc = "PFD0_DIV1_CLKGATE"] PFD0_DIV1_CLKGATE start(7) width(1) RW {} #[doc = "PFD1_FRAC"] PFD1_FRAC start(8) width(6) RW {} #[doc = "PFD1_STABLE"] PFD1_STABLE start(14) width(1) RO {} #[doc = "PFD1_DIV1_CLKGATE"] PFD1_DIV1_CLKGATE start(15) width(1) RW {} #[doc = "PFD2_FRAC"] PFD2_FRAC start(16) width(6) RW {} #[doc = "PFD2_STABLE"] PFD2_STABLE start(22) width(1) RO {} #[doc = "PFD2_DIV1_CLKGATE"] PFD2_DIV1_CLKGATE start(23) width(1) RW {} #[doc = "PFD3_FRAC"] PFD3_FRAC start(24) width(6) RW {} #[doc = "PFD3_STABLE"] PFD3_STABLE start(30) width(1) RO {} #[doc = "PFD3_DIV1_CLKGATE"] PFD3_DIV1_CLKGATE start(31) width(1) RW {} ] } /// A fractional divider for a PFD. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(transparent)] pub struct PfdFrac(NonZero); impl PfdFrac { /// Create a new PDF fractional divider. /// /// Returns `None` if `div` is not between 12 and 35. pub const fn new(div: u8) -> Option { // Safety: div is between 12 and 35. unsafe { if 12 <= div && div <= 35 { Some(Self(NonZero::new_unchecked(div))) } else { None } } } /// Similar to `new`, but this will automatically clamp /// the value between the 12 and 35. pub const fn clamp(div: u8) -> Self { // Safety: div is clamped between 12 and 35. unsafe { Self(NonZero::new_unchecked(if div < 12 { 12 } else if div > 35 { 35 } else { div })) } } /// Return the inner value. #[inline] pub const fn get(self) -> u8 { self.0.get() } } /// Returns the PLL3 PFD fractional dividers. /// /// If a divider is invalid, the implementation returns `None` /// for that divider. pub fn pll3_pfd_fracs(pll: ral_registers::Instance) -> [Option; 4] { let (pfd0, pfd1, pfd2, pfd3) = ral_registers::read_reg!( self, pll, SYS_PLL3_PFD, PFD0_FRAC, PFD1_FRAC, PFD2_FRAC, PFD3_FRAC ); [ PfdFrac::new(pfd0 as _), PfdFrac::new(pfd1 as _), PfdFrac::new(pfd2 as _), PfdFrac::new(pfd3 as _), ] } /// Set the PLL3 PFD fractional dividers. /// /// The call updates all four dividers without affecting the gating. /// However, it does not update the values. pub fn set_pll3_pfd_fracs(pll: ral_registers::Instance, pfds: [PfdFrac; 4]) { ral_registers::modify_reg!(self, pll, SYS_PLL3_PFD, PFD3_FRAC: pfds[3].get() as u32, PFD2_FRAC: pfds[2].get() as u32, PFD1_FRAC: pfds[1].get() as u32, PFD0_FRAC: pfds[0].get() as u32, ); } /// Update the PFD fractional divider values that were previously /// set. /// /// Only those that have a `true` update are updated. pub fn update_pll3_pfd_fracs(pll: ral_registers::Instance, update: [bool; 4]) { ral_registers::modify_reg!(self, pll, SYS_PLL3_UPDATE, PFD3_UPDATE: update[3] as u32, PFD2_UPDATE: update[2] as u32, PFD1_UPDATE: update[1] as u32, PFD0_UPDATE: update[0] as u32, ); ral_registers::modify_reg!(self, pll, SYS_PLL3_UPDATE, PFD3_UPDATE: false as u32, PFD2_UPDATE: false as u32, PFD1_UPDATE: false as u32, PFD0_UPDATE: false as u32, ); } /// Returns the PLL2 PFD fractional dividers. /// /// If a divider is invalid, the implementation returns `None` /// for that divider. pub fn pll2_pfd_fracs(pll: ral_registers::Instance) -> [Option; 4] { let (pfd0, pfd1, pfd2, pfd3) = ral_registers::read_reg!( self, pll, SYS_PLL2_PFD, PFD0_FRAC, PFD1_FRAC, PFD2_FRAC, PFD3_FRAC ); [ PfdFrac::new(pfd0 as _), PfdFrac::new(pfd1 as _), PfdFrac::new(pfd2 as _), PfdFrac::new(pfd3 as _), ] } /// Set the PLL2 PFD fractional dividers. /// /// The call updates all four dividers without affecting the gating. /// However, it does not update the values. pub fn set_pll2_pfd_fracs(pll: ral_registers::Instance, pfds: [PfdFrac; 4]) { ral_registers::modify_reg!(self, pll, SYS_PLL2_PFD, PFD3_FRAC: pfds[3].get() as u32, PFD2_FRAC: pfds[2].get() as u32, PFD1_FRAC: pfds[1].get() as u32, PFD0_FRAC: pfds[0].get() as u32, ); }