use libregister::{RegisterR, RegisterRW}; use super::slcr::{crf_apb, crl_apb, common::SlcrRegisterBlock}; pub use super::slcr::crf_apb::ApuClkSource; pub mod source; use source::*; #[derive(Debug, Clone)] pub struct Clocks { /// ARM PLL: Recommended clock source for the APUs and the FPD interconnect pub apu: u32, /// DDR PLL: Recommended clock for the DDR DRAM controller and AXI_HP interfaces pub ddr: u32, /// Video PLL: Recommended clock for display port pub video: u32, /// I/O PLL: Recommended clock for I/O peripherals pub io: u32, /// RPU PLL: Recommended clock for RPUs and LPD interconnect pub rpu: u32, } impl Clocks { pub fn get() -> Self { let fpd_regs = crf_apb::RegisterBlock::slcr(); let lpd_regs = crl_apb::RegisterBlock::slcr(); Clocks { apu: ApuPll::freq(&mut fpd_regs.apu_pll_ctrl), ddr: DdrPll::freq(&mut fpd_regs.ddr_pll_ctrl), video: VideoPll::freq(&mut fpd_regs.video_pll_ctrl), io: IoPll::freq(&mut lpd_regs.io_pll_ctrl), rpu: RpuPll::freq(&mut lpd_regs.rpu_pll_ctrl), } } pub fn set_cpu_freq(target_freq: u32) { let fpd_regs = crf_apb::RegisterBlock::slcr(); let apu_pll = ApuPll::freq(&mut fpd_regs.apu_pll_ctrl); let mut div = 1u8; while div < 63 && apu_pll / u32::from(div) > target_freq { div += 1; } crf_apb::RegisterBlock::unlocked(|slcr| { slcr.apu_clk_ctrl.modify(|_, w| w .srcsel(ApuClkSource::ApuPll) .divisor0(div) ); }) } pub fn uart0_ref_clk(&self) -> u32 { let lpd_regs = crl_apb::RegisterBlock::slcr(); self.uart_ref_clk(&mut lpd_regs.uart0_clk_ctrl) } pub fn uart1_ref_clk(&self) -> u32 { let lpd_regs = crl_apb::RegisterBlock::slcr(); self.uart_ref_clk(&mut lpd_regs.uart1_clk_ctrl) } fn uart_ref_clk(&self, uart_regs: &mut crl_apb::UartClkCtrl) -> u32 { let uart_clk_ctrl = uart_regs.read(); let pll = match uart_clk_ctrl.srcsel() { crl_apb::IoClkSource::IoPll => self.io, crl_apb::IoClkSource::RpuPll => self.rpu, crl_apb::IoClkSource::DdrPllToLpd => { let fpd_regs = crf_apb::RegisterBlock::slcr(); let divisor = u32::from(fpd_regs.ddr_pll_to_lpd_ctrl.read().divisor0()); self.ddr / divisor } }; pll / (u32::from(uart_clk_ctrl.divisor0()) * u32::from(uart_clk_ctrl.divisor1())) } // pub fn sdio_ref_clk(&self) -> u32 { // let regs = slcr::RegisterBlock::slcr(); // let sdio_clk_ctrl = regs.sdio_clk_ctrl.read(); // let pll = match sdio_clk_ctrl.srcsel() { // slcr::PllSource::ArmPll => // self.arm, // slcr::PllSource::DdrPll => // self.ddr, // slcr::PllSource::IoPll => // self.io, // }; // pll / u32::from(sdio_clk_ctrl.divisor()) // } }