forked from M-Labs/zynq-rs
read clocks
This commit is contained in:
parent
1f9ad5ff62
commit
b8818863c4
92
src/clocks.rs
Normal file
92
src/clocks.rs
Normal 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())
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -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");
|
||||||
|
52
src/slcr.rs
52
src/slcr.rs
@ -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);
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user