2020-01-31 06:18:14 +08:00
|
|
|
use libregister::{RegisterR, RegisterRW};
|
2020-01-24 05:44:10 +08:00
|
|
|
use super::slcr;
|
|
|
|
pub use slcr::ArmPllSource;
|
|
|
|
|
|
|
|
pub mod source;
|
|
|
|
use source::*;
|
|
|
|
|
|
|
|
enum CpuClockMode {
|
|
|
|
/// Clocks run in 4:2:2:1 mode
|
|
|
|
C421,
|
|
|
|
/// Clocks run in 6:3:2:1 mode
|
|
|
|
C621,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CpuClockMode {
|
|
|
|
pub fn get() -> Self {
|
2020-08-13 13:39:04 +08:00
|
|
|
let regs = slcr::RegisterBlock::slcr();
|
2020-01-24 05:44:10 +08:00
|
|
|
if regs.clk_621_true.read().clk_621_true() {
|
|
|
|
CpuClockMode::C621
|
|
|
|
} else {
|
|
|
|
CpuClockMode::C421
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Clocks {
|
|
|
|
/// ARM PLL: Recommended clock source for the CPUs and the interconnect
|
|
|
|
pub arm: u32,
|
|
|
|
/// DDR PLL: Recommended clock for the DDR DRAM controller and AXI_HP interfaces
|
|
|
|
pub ddr: u32,
|
|
|
|
/// I/O PLL: Recommended clock for I/O peripherals
|
|
|
|
pub io: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Clocks {
|
|
|
|
pub fn get() -> Self {
|
|
|
|
Clocks {
|
|
|
|
arm: ArmPll::freq(),
|
|
|
|
ddr: DdrPll::freq(),
|
|
|
|
io: IoPll::freq(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_cpu_freq(target_freq: u32) {
|
|
|
|
let arm_pll = ArmPll::freq();
|
|
|
|
// 1 and 3 cannot be used
|
|
|
|
let mut div = 2u8;
|
|
|
|
while div == 3 || (div < 63 && arm_pll / u32::from(div) > target_freq) {
|
|
|
|
div += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
slcr::RegisterBlock::unlocked(|slcr| {
|
|
|
|
slcr.arm_clk_ctrl.modify(|_, w| w
|
|
|
|
.srcsel(ArmPllSource::ArmPll)
|
|
|
|
.divisor(div)
|
|
|
|
);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cpu_6x4x(&self) -> u32 {
|
2020-08-13 13:39:04 +08:00
|
|
|
let slcr = slcr::RegisterBlock::slcr();
|
2020-01-24 05:44:10 +08:00
|
|
|
let arm_clk_ctrl = slcr.arm_clk_ctrl.read();
|
|
|
|
let pll = match arm_clk_ctrl.srcsel() {
|
|
|
|
ArmPllSource::ArmPll => self.arm,
|
|
|
|
ArmPllSource::DdrPll => self.ddr,
|
|
|
|
ArmPllSource::IoPll => self.io,
|
|
|
|
};
|
|
|
|
pll / u32::from(arm_clk_ctrl.divisor())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cpu_3x2x(&self) -> u32 {
|
|
|
|
self.cpu_6x4x() / 2
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cpu_2x(&self) -> u32 {
|
|
|
|
match CpuClockMode::get() {
|
|
|
|
CpuClockMode::C421 =>
|
|
|
|
self.cpu_6x4x() / 2,
|
|
|
|
CpuClockMode::C621 =>
|
|
|
|
self.cpu_6x4x() / 3,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cpu_1x(&self) -> u32 {
|
|
|
|
match CpuClockMode::get() {
|
|
|
|
CpuClockMode::C421 =>
|
|
|
|
self.cpu_6x4x() / 4,
|
|
|
|
CpuClockMode::C621 =>
|
|
|
|
self.cpu_6x4x() / 6,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn uart_ref_clk(&self) -> u32 {
|
2020-08-13 13:39:04 +08:00
|
|
|
let regs = slcr::RegisterBlock::slcr();
|
2020-01-24 05:44:10 +08:00
|
|
|
let uart_clk_ctrl = regs.uart_clk_ctrl.read();
|
|
|
|
let pll = match uart_clk_ctrl.srcsel() {
|
|
|
|
slcr::PllSource::ArmPll =>
|
|
|
|
self.arm,
|
|
|
|
slcr::PllSource::DdrPll =>
|
|
|
|
self.ddr,
|
|
|
|
slcr::PllSource::IoPll =>
|
|
|
|
self.io,
|
|
|
|
};
|
|
|
|
pll / u32::from(uart_clk_ctrl.divisor())
|
|
|
|
}
|
2020-06-05 11:47:06 +08:00
|
|
|
|
|
|
|
pub fn sdio_ref_clk(&self) -> u32 {
|
2020-08-13 13:39:04 +08:00
|
|
|
let regs = slcr::RegisterBlock::slcr();
|
2020-06-05 11:47:06 +08:00
|
|
|
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())
|
|
|
|
}
|
2020-01-24 05:44:10 +08:00
|
|
|
}
|