From b8818863c48d16b2b176f3cadda637392a159f7c Mon Sep 17 00:00:00 2001 From: Astro Date: Sat, 17 Aug 2019 02:55:56 +0200 Subject: [PATCH] read clocks --- src/clocks.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ src/eth/mod.rs | 16 +++++---- src/main.rs | 8 +++++ src/slcr.rs | 52 +++++++++++++++++++++------- src/uart/mod.rs | 11 ++---- 5 files changed, 152 insertions(+), 27 deletions(-) create mode 100644 src/clocks.rs diff --git a/src/clocks.rs b/src/clocks.rs new file mode 100644 index 00000000..a8bb0d5e --- /dev/null +++ b/src/clocks.rs @@ -0,0 +1,92 @@ +use crate::slcr; +use crate::regs::RegisterR; + +#[cfg(feature = "target_zc706")] +const PS_CLK: u32 = 33_333_333; +#[cfg(feature = "target_cora_z7_10")] +const PS_CLK: u32 = 50_000_000; + +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 { + let regs = slcr::RegisterBlock::new(); + if regs.clk_621_true.read().clk_621_true() { + CpuClockMode::C621 + } else { + CpuClockMode::C421 + } + } +} + +#[derive(Debug, Clone)] +pub struct CpuClocks { + /// 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 CpuClocks { + pub fn get() -> Self { + let regs = slcr::RegisterBlock::new(); + let arm = u32::from(regs.arm_pll_ctrl.read().pll_fdiv()) * PS_CLK; + let ddr = u32::from(regs.ddr_pll_ctrl.read().pll_fdiv()) * PS_CLK; + let io = u32::from(regs.io_pll_ctrl.read().pll_fdiv()) * PS_CLK; + CpuClocks { arm, ddr, io } + } + + pub fn cpu_6x4x(&self) -> u32 { + let regs = slcr::RegisterBlock::new(); + let arm_clk_ctrl = regs.arm_clk_ctrl.read(); + let pll = match arm_clk_ctrl.srcsel() { + slcr::ArmPllSource::ArmPll => self.arm, + slcr::ArmPllSource::DdrPll => self.ddr, + slcr::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 { + let regs = slcr::RegisterBlock::new(); + 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()) + } +} diff --git a/src/eth/mod.rs b/src/eth/mod.rs index bb804e81..01392a5a 100644 --- a/src/eth/mod.rs +++ b/src/eth/mod.rs @@ -1,6 +1,7 @@ use crate::regs::*; use crate::slcr; use crate::println; +use crate::clocks::CpuClocks; pub mod phy; mod regs; @@ -9,7 +10,6 @@ pub mod tx; /// Size of all the buffers pub const MTU: usize = 1536; -pub const IO_PLL: u32 = 1_000; pub struct Eth { regs: &'static mut regs::RegisterBlock, @@ -176,14 +176,15 @@ impl Eth<(), ()> { impl Eth { pub fn setup_gem0_clock(tx_clock: u32) { - let d0 = (IO_PLL / tx_clock).min(63); - let d1 = (IO_PLL / tx_clock / d0).min(63); + let io_pll = CpuClocks::get().io; + let d0 = (io_pll / tx_clock).min(63); + let d1 = (io_pll / tx_clock / d0).min(63); slcr::RegisterBlock::unlocked(|slcr| { slcr.gem0_clk_ctrl.write( // 0x0050_0801: 8, 5: 100 Mb/s // ...: 8, 1: 1000 Mb/s - slcr::ClkCtrl::zeroed() + slcr::GemClkCtrl::zeroed() .clkact(true) .srcsel(slcr::PllSource::IoPll) .divisor(d0 as u8) @@ -199,12 +200,13 @@ impl Eth { } pub fn setup_gem1_clock(tx_clock: u32) { - let d0 = (IO_PLL / tx_clock).min(63); - let d1 = (IO_PLL / tx_clock / d0).min(63); + let io_pll = CpuClocks::get().io; + let d0 = (io_pll / tx_clock).min(63); + let d1 = (io_pll / tx_clock / d0).min(63); slcr::RegisterBlock::unlocked(|slcr| { slcr.gem1_clk_ctrl.write( - slcr::ClkCtrl::zeroed() + slcr::GemClkCtrl::zeroed() .clkact(true) .srcsel(slcr::PllSource::IoPll) .divisor(d0 as u8) diff --git a/src/main.rs b/src/main.rs index d889cf03..b5455b0e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ use compiler_builtins as _; mod regs; mod cortex_a9; +mod clocks; mod slcr; mod uart; mod stdio; @@ -74,6 +75,13 @@ fn l1_cache_init() { fn main() { println!("Main."); + let clocks = clocks::CpuClocks::get(); + println!("Clocks: {:?}", clocks); + println!("CPU speeds: {}/{}/{}/{} MHz", + clocks.cpu_6x4x() / 1_000_000, + clocks.cpu_3x2x() / 1_000_000, + clocks.cpu_2x() / 1_000_000, + clocks.cpu_1x() / 1_000_000); let mut eth = eth::Eth::default([0x0, 0x17, 0xde, 0xea, 0xbe, 0xef]); println!("Eth on"); diff --git a/src/slcr.rs b/src/slcr.rs index f5d8341c..df714ec2 100644 --- a/src/slcr.rs +++ b/src/slcr.rs @@ -12,6 +12,13 @@ pub enum PllSource { DdrPll = 0b11, } +#[repr(u8)] +pub enum ArmPllSource { + ArmPll = 0b00, + DdrPll = 0b10, + IoPll = 0b11, +} + #[repr(C)] pub struct RegisterBlock { pub scl: RW, @@ -19,15 +26,15 @@ pub struct RegisterBlock { pub slcr_unlock: SlcrUnlock, pub slcr_locksta: RO, reserved0: [u32; 60], - pub arm_pll_ctrl: RW, - pub ddr_pll_ctrl: RW, - pub io_pll_ctrl: RW, + pub arm_pll_ctrl: PllCtrl, + pub ddr_pll_ctrl: PllCtrl, + pub io_pll_ctrl: PllCtrl, pub pll_status: RO, pub arm_pll_cfg: RW, pub ddr_pll_cfg: RW, pub io_pll_cfg: RW, reserved1: [u32; 1], - pub arm_clk_ctrl: RW, + pub arm_clk_ctrl: ArmClkCtrl, pub ddr_clk_ctrl: RW, pub dci_clk_ctrl: RW, pub aper_clk_ctrl: AperClkCtrl, @@ -35,8 +42,8 @@ pub struct RegisterBlock { pub usb1_clk_ctrl: RW, pub gem0_rclk_ctrl: RclkCtrl, pub gem1_rclk_ctrl: RclkCtrl, - pub gem0_clk_ctrl: ClkCtrl, - pub gem1_clk_ctrl: ClkCtrl, + pub gem0_clk_ctrl: GemClkCtrl, + pub gem1_clk_ctrl: GemClkCtrl, pub smc_clk_ctrl: RW, pub lqspi_clk_ctrl: RW, pub sdio_clk_ctrl: RW, @@ -64,7 +71,7 @@ pub struct RegisterBlock { pub fpga3_thr_cnt: RW, pub fpga3_thr_sta: RO, reserved2: [u32; 5], - pub clk_621_true: RW, + pub clk_621_true: Clk621True, reserved3: [u32; 14], pub pss_rst_ctrl: PssRstCtrl, pub ddr_rst_ctrl: RW, @@ -239,6 +246,27 @@ impl SlcrUnlock { } } +register!(pll_ctrl, PllCtrl, RW, u32); +register_bits!(pll_ctrl, pll_fdiv, u8, 12, 18); +register_bit!(pll_ctrl, pll_bypass_force, 4); +register_bit!(pll_ctrl, pll_bypass_qual, 3); +register_bit!(pll_ctrl, pll_pwrdwn, 1); +register_bit!(pll_ctrl, pll_reset, 0); + +register!(arm_clk_ctrl, ArmClkCtrl, RW, u32); +register_bit!(arm_clk_ctrl, + /// Clock active + cpu_peri_clkact, 28); +register_bit!(arm_clk_ctrl, cpu_1xclkact, 27); +register_bit!(arm_clk_ctrl, cpu_2xclkact, 26); +register_bit!(arm_clk_ctrl, cpu_3or2xclkact, 25); +register_bit!(arm_clk_ctrl, cpu_6or4xclkact, 24); +register_bits!(arm_clk_ctrl, divisor, u8, 8, 13); +register_bits_typed!(arm_clk_ctrl, srcsel, u8, ArmPllSource, 8, 13); + +register!(clk_621_true, Clk621True, RW, u32); +register_bit!(clk_621_true, clk_621_true, 0); + register!(aper_clk_ctrl, AperClkCtrl, RW, u32); register_bit!(aper_clk_ctrl, uart1_cpu_1xclkact, 21); register_bit!(aper_clk_ctrl, uart0_cpu_1xclkact, 20); @@ -260,17 +288,17 @@ register_bit!(rclk_ctrl, /// false: MIO, true: EMIO srcsel, 4); -register!(clk_ctrl, ClkCtrl, RW, u32); -register_bits!(clk_ctrl, +register!(gem_clk_ctrl, GemClkCtrl, RW, u32); +register_bits!(gem_clk_ctrl, /// 2nd divisor for source clock divisor1, u8, 20, 25); -register_bits!(clk_ctrl, +register_bits!(gem_clk_ctrl, /// 1st divisor for source clock divisor, u8, 8, 13); -register_bits_typed!(clk_ctrl, +register_bits_typed!(gem_clk_ctrl, /// Source to generate the ref clock srcsel, u8, PllSource, 4, 5); -register_bit!(clk_ctrl, +register_bit!(gem_clk_ctrl, /// SMC reference clock control clkact, 0); diff --git a/src/uart/mod.rs b/src/uart/mod.rs index 512f2a87..750597c3 100644 --- a/src/uart/mod.rs +++ b/src/uart/mod.rs @@ -2,17 +2,11 @@ use core::fmt; use crate::regs::*; use crate::slcr; +use crate::clocks::CpuClocks; mod regs; mod baud_rate_gen; -/// Determined through experimentation. Actually supposed to be -/// 1 GHz (IO PLL) / 0x14 (slcr.UART_CLK_CTRL[DIVISOR]) = 50 MHz. -#[cfg(feature = "target_zc706")] -const UART_REF_CLK: u32 = 50_000_000; -#[cfg(feature = "target_cora_z7_10")] -const UART_REF_CLK: u32 = 72_000_000; - pub struct Uart { regs: &'static mut regs::RegisterBlock, } @@ -116,7 +110,8 @@ impl Uart { self.disable_rx(); self.disable_tx(); - baud_rate_gen::configure(self.regs, UART_REF_CLK, baudrate); + let clocks = CpuClocks::get(); + baud_rate_gen::configure(self.regs, clocks.uart_ref_clk(), baudrate); // Enable controller self.reset_rx();