//! System Level Control Registers (slcr) //! //! Writing any of these registers required unlocking the SLCR first. use arbitrary_int::{u3, u4}; pub use clocks::{ClockControl, MmioClockControl}; pub use reset::{MmioResetControl, ResetControl}; const SLCR_BASE_ADDR: usize = 0xF8000000; const CLOCK_CONTROL_OFFSET: usize = 0x100; const RESET_BLOCK_OFFSET: usize = 0x200; const GPIOB_OFFSET: usize = 0xB00; const DDRIOB_OFFSET: usize = 0xB40; pub mod clocks; pub mod mio; pub mod reset; #[derive(derive_mmio::Mmio)] #[repr(C)] pub struct DdrIoB { ddriob_addr0: u32, ddriob_addr1: u32, ddriob_data0: u32, ddriob_data1: u32, ddriob_diff0: u32, ddriob_diff1: u32, ddriob_clock: u32, ddriob_drive_slew_addr: u32, ddriob_drive_slew_data: u32, ddriob_drive_slew_diff: u32, ddriob_drive_slew_clock: u32, ddriob_ddr_ctrl: u32, ddriob_dci_ctrl: u32, ddriob_dci_status: u32, } impl DdrIoB { /// Create a new handle to this peripheral. /// /// Writing to this register requires unlocking the SLCR registers first. /// /// # Safety /// /// If you create multiple instances of this handle at the same time, you are responsible for /// ensuring that there are no read-modify-write races on any of the registers. pub unsafe fn new_mmio_fixed() -> MmioDdrIoB<'static> { unsafe { Self::new_mmio_at(SLCR_BASE_ADDR + DDRIOB_OFFSET) } } } static_assertions::const_assert_eq!(core::mem::size_of::(), 0x38); #[bitbybit::bitenum(u3, exhaustive = false)] pub enum VrefSel { Disabled = 0b000, Vref0_9V = 0b001, } #[bitbybit::bitfield(u32)] #[derive(Debug)] pub struct GpiobControl { #[bit(11, rw)] vref_sw_en: bool, #[bits(4..=6, rw)] vref_sel: Option, #[bit(0, rw)] vref_en: bool, } #[derive(derive_mmio::Mmio)] #[repr(C)] pub struct GpiobRegisters { ctrl: GpiobControl, cfg_cmos18: u32, cfg_cmos25: u32, cfg_cmos33: u32, _gap17: u32, cfg_hstl: u32, drvr_bias_ctrl: u32, } impl GpiobRegisters { /// Create a new handle to this peripheral. /// /// Writing to this register requires unlocking the SLCR registers first. /// /// # Safety /// /// If you create multiple instances of this handle at the same time, you are responsible for /// ensuring that there are no read-modify-write races on any of the registers. pub unsafe fn new_mmio_fixed() -> MmioGpiobRegisters<'static> { unsafe { Self::new_mmio_at(SLCR_BASE_ADDR + GPIOB_OFFSET) } } } #[bitbybit::bitfield(u32)] #[derive(Debug)] pub struct BootModeRegister { #[bit(4, r)] pll_bypass: bool, #[bits(0..=3, r)] boot_mode: u4, } #[bitbybit::bitenum(u4)] #[derive(Debug, PartialEq, Eq)] pub enum LevelShifterConfig { DisableAll = 0x00, EnablePsToPl = 0xA, EnableAll = 0xF, } #[bitbybit::bitfield(u32)] pub struct LevelShifterReg { #[bits(0..=3, rw)] user_lvl_shftr_en: Option, } /// System Level Control Registers #[derive(derive_mmio::Mmio)] #[repr(C)] pub struct Slcr { /// Secure configuration lock. scl: u32, /// SLCR write protection lock lock: u32, /// SLCR write protection unlock unlock: u32, /// SLCR write protection status lock_status: u32, _gap0: [u32; 0x3C], #[mmio(inner)] clk_ctrl: ClockControl, _gap1: [u32; 0x0E], #[mmio(inner)] reset_ctrl: ResetControl, _gap2: [u32; 0x02], reboot_status: u32, boot_mode: BootModeRegister, _gap3: [u32; 0x28], apu_ctrl: u32, wdt_clk_set: u32, _gap4: [u32; 0x4E], tz_dma_ns: u32, tz_dma_irq_ns: u32, tz_dma_periph_ns: u32, _gap5: [u32; 0x39], pss_idcode: u32, _gap6: [u32; 0x33], ddr_urgent: u32, _gap7: [u32; 0x02], ddr_cal_start: u32, _gap8: u32, ddr_ref_start: u32, ddr_cmd_status: u32, ddr_urgent_sel: u32, ddr_dfi_status: u32, _gap9: [u32; 0x37], mio_pins: [mio::Config; 0x36], _gap10: [u32; 0x0B], mio_loopback: u32, _gap11: u32, mio_mst_tri_0: u32, mio_mst_tri_1: u32, _gap12: [u32; 7], sd_0_wp_cd_sel: u32, sd_1_wp_cd_sel: u32, _gap13: [u32; 0x32], lvl_shftr_en: LevelShifterReg, _gap14: [u32; 0x03], ocm_cfg: u32, _gap15: [u32; 0x42], reserved: u32, _gap16: [u32; 0x38], _gap18: [u32; 0x09], #[mmio(inner)] gpiob: GpiobRegisters, #[mmio(inner)] ddriob: DdrIoB, } static_assertions::const_assert_eq!(core::mem::size_of::(), 0xB78); impl Slcr { /// Create a new handle to this peripheral. /// /// Writing to this register requires unlocking the SLCR registers first. /// /// # Safety /// /// If you create multiple instances of this handle at the same time, you are responsible for /// ensuring that there are no read-modify-write races on any of the registers. pub unsafe fn new_mmio_fixed() -> MmioSlcr<'static> { unsafe { Self::new_mmio_at(SLCR_BASE_ADDR) } } }