read clocks

This commit is contained in:
Astro 2019-08-17 02:55:56 +02:00
parent 1f9ad5ff62
commit b8818863c4
5 changed files with 152 additions and 27 deletions

92
src/clocks.rs Normal file
View File

@ -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())
}
}

View File

@ -1,6 +1,7 @@
use crate::regs::*; use crate::regs::*;
use crate::slcr; use crate::slcr;
use crate::println; use crate::println;
use crate::clocks::CpuClocks;
pub mod phy; pub mod phy;
mod regs; mod regs;
@ -9,7 +10,6 @@ pub mod tx;
/// Size of all the buffers /// Size of all the buffers
pub const MTU: usize = 1536; pub const MTU: usize = 1536;
pub const IO_PLL: u32 = 1_000;
pub struct Eth<RX, TX> { pub struct Eth<RX, TX> {
regs: &'static mut regs::RegisterBlock, regs: &'static mut regs::RegisterBlock,
@ -176,14 +176,15 @@ impl Eth<(), ()> {
impl<RX, TX> Eth<RX, TX> { impl<RX, TX> Eth<RX, TX> {
pub fn setup_gem0_clock(tx_clock: u32) { pub fn setup_gem0_clock(tx_clock: u32) {
let d0 = (IO_PLL / tx_clock).min(63); let io_pll = CpuClocks::get().io;
let d1 = (IO_PLL / tx_clock / d0).min(63); let d0 = (io_pll / tx_clock).min(63);
let d1 = (io_pll / tx_clock / d0).min(63);
slcr::RegisterBlock::unlocked(|slcr| { slcr::RegisterBlock::unlocked(|slcr| {
slcr.gem0_clk_ctrl.write( slcr.gem0_clk_ctrl.write(
// 0x0050_0801: 8, 5: 100 Mb/s // 0x0050_0801: 8, 5: 100 Mb/s
// ...: 8, 1: 1000 Mb/s // ...: 8, 1: 1000 Mb/s
slcr::ClkCtrl::zeroed() slcr::GemClkCtrl::zeroed()
.clkact(true) .clkact(true)
.srcsel(slcr::PllSource::IoPll) .srcsel(slcr::PllSource::IoPll)
.divisor(d0 as u8) .divisor(d0 as u8)
@ -199,12 +200,13 @@ impl<RX, TX> Eth<RX, TX> {
} }
pub fn setup_gem1_clock(tx_clock: u32) { pub fn setup_gem1_clock(tx_clock: u32) {
let d0 = (IO_PLL / tx_clock).min(63); let io_pll = CpuClocks::get().io;
let d1 = (IO_PLL / tx_clock / d0).min(63); let d0 = (io_pll / tx_clock).min(63);
let d1 = (io_pll / tx_clock / d0).min(63);
slcr::RegisterBlock::unlocked(|slcr| { slcr::RegisterBlock::unlocked(|slcr| {
slcr.gem1_clk_ctrl.write( slcr.gem1_clk_ctrl.write(
slcr::ClkCtrl::zeroed() slcr::GemClkCtrl::zeroed()
.clkact(true) .clkact(true)
.srcsel(slcr::PllSource::IoPll) .srcsel(slcr::PllSource::IoPll)
.divisor(d0 as u8) .divisor(d0 as u8)

View File

@ -15,6 +15,7 @@ use compiler_builtins as _;
mod regs; mod regs;
mod cortex_a9; mod cortex_a9;
mod clocks;
mod slcr; mod slcr;
mod uart; mod uart;
mod stdio; mod stdio;
@ -74,6 +75,13 @@ fn l1_cache_init() {
fn main() { fn main() {
println!("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]); let mut eth = eth::Eth::default([0x0, 0x17, 0xde, 0xea, 0xbe, 0xef]);
println!("Eth on"); println!("Eth on");

View File

@ -12,6 +12,13 @@ pub enum PllSource {
DdrPll = 0b11, DdrPll = 0b11,
} }
#[repr(u8)]
pub enum ArmPllSource {
ArmPll = 0b00,
DdrPll = 0b10,
IoPll = 0b11,
}
#[repr(C)] #[repr(C)]
pub struct RegisterBlock { pub struct RegisterBlock {
pub scl: RW<u32>, pub scl: RW<u32>,
@ -19,15 +26,15 @@ pub struct RegisterBlock {
pub slcr_unlock: SlcrUnlock, pub slcr_unlock: SlcrUnlock,
pub slcr_locksta: RO<u32>, pub slcr_locksta: RO<u32>,
reserved0: [u32; 60], reserved0: [u32; 60],
pub arm_pll_ctrl: RW<u32>, pub arm_pll_ctrl: PllCtrl,
pub ddr_pll_ctrl: RW<u32>, pub ddr_pll_ctrl: PllCtrl,
pub io_pll_ctrl: RW<u32>, pub io_pll_ctrl: PllCtrl,
pub pll_status: RO<u32>, pub pll_status: RO<u32>,
pub arm_pll_cfg: RW<u32>, pub arm_pll_cfg: RW<u32>,
pub ddr_pll_cfg: RW<u32>, pub ddr_pll_cfg: RW<u32>,
pub io_pll_cfg: RW<u32>, pub io_pll_cfg: RW<u32>,
reserved1: [u32; 1], reserved1: [u32; 1],
pub arm_clk_ctrl: RW<u32>, pub arm_clk_ctrl: ArmClkCtrl,
pub ddr_clk_ctrl: RW<u32>, pub ddr_clk_ctrl: RW<u32>,
pub dci_clk_ctrl: RW<u32>, pub dci_clk_ctrl: RW<u32>,
pub aper_clk_ctrl: AperClkCtrl, pub aper_clk_ctrl: AperClkCtrl,
@ -35,8 +42,8 @@ pub struct RegisterBlock {
pub usb1_clk_ctrl: RW<u32>, pub usb1_clk_ctrl: RW<u32>,
pub gem0_rclk_ctrl: RclkCtrl, pub gem0_rclk_ctrl: RclkCtrl,
pub gem1_rclk_ctrl: RclkCtrl, pub gem1_rclk_ctrl: RclkCtrl,
pub gem0_clk_ctrl: ClkCtrl, pub gem0_clk_ctrl: GemClkCtrl,
pub gem1_clk_ctrl: ClkCtrl, pub gem1_clk_ctrl: GemClkCtrl,
pub smc_clk_ctrl: RW<u32>, pub smc_clk_ctrl: RW<u32>,
pub lqspi_clk_ctrl: RW<u32>, pub lqspi_clk_ctrl: RW<u32>,
pub sdio_clk_ctrl: RW<u32>, pub sdio_clk_ctrl: RW<u32>,
@ -64,7 +71,7 @@ pub struct RegisterBlock {
pub fpga3_thr_cnt: RW<u32>, pub fpga3_thr_cnt: RW<u32>,
pub fpga3_thr_sta: RO<u32>, pub fpga3_thr_sta: RO<u32>,
reserved2: [u32; 5], reserved2: [u32; 5],
pub clk_621_true: RW<u32>, pub clk_621_true: Clk621True,
reserved3: [u32; 14], reserved3: [u32; 14],
pub pss_rst_ctrl: PssRstCtrl, pub pss_rst_ctrl: PssRstCtrl,
pub ddr_rst_ctrl: RW<u32>, pub ddr_rst_ctrl: RW<u32>,
@ -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!(aper_clk_ctrl, AperClkCtrl, RW, u32);
register_bit!(aper_clk_ctrl, uart1_cpu_1xclkact, 21); register_bit!(aper_clk_ctrl, uart1_cpu_1xclkact, 21);
register_bit!(aper_clk_ctrl, uart0_cpu_1xclkact, 20); register_bit!(aper_clk_ctrl, uart0_cpu_1xclkact, 20);
@ -260,17 +288,17 @@ register_bit!(rclk_ctrl,
/// false: MIO, true: EMIO /// false: MIO, true: EMIO
srcsel, 4); srcsel, 4);
register!(clk_ctrl, ClkCtrl, RW, u32); register!(gem_clk_ctrl, GemClkCtrl, RW, u32);
register_bits!(clk_ctrl, register_bits!(gem_clk_ctrl,
/// 2nd divisor for source clock /// 2nd divisor for source clock
divisor1, u8, 20, 25); divisor1, u8, 20, 25);
register_bits!(clk_ctrl, register_bits!(gem_clk_ctrl,
/// 1st divisor for source clock /// 1st divisor for source clock
divisor, u8, 8, 13); divisor, u8, 8, 13);
register_bits_typed!(clk_ctrl, register_bits_typed!(gem_clk_ctrl,
/// Source to generate the ref clock /// Source to generate the ref clock
srcsel, u8, PllSource, 4, 5); srcsel, u8, PllSource, 4, 5);
register_bit!(clk_ctrl, register_bit!(gem_clk_ctrl,
/// SMC reference clock control /// SMC reference clock control
clkact, 0); clkact, 0);

View File

@ -2,17 +2,11 @@ use core::fmt;
use crate::regs::*; use crate::regs::*;
use crate::slcr; use crate::slcr;
use crate::clocks::CpuClocks;
mod regs; mod regs;
mod baud_rate_gen; 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 { pub struct Uart {
regs: &'static mut regs::RegisterBlock, regs: &'static mut regs::RegisterBlock,
} }
@ -116,7 +110,8 @@ impl Uart {
self.disable_rx(); self.disable_rx();
self.disable_tx(); 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 // Enable controller
self.reset_rx(); self.reset_rx();