forked from M-Labs/zynq-rs
90 lines
3.0 KiB
Rust
90 lines
3.0 KiB
Rust
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())
|
|
// }
|
|
}
|