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::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<RX, TX> {
|
||||
regs: &'static mut regs::RegisterBlock,
|
||||
@ -176,14 +176,15 @@ impl Eth<(), ()> {
|
||||
|
||||
impl<RX, TX> Eth<RX, TX> {
|
||||
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<RX, TX> Eth<RX, TX> {
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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");
|
||||
|
52
src/slcr.rs
52
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<u32>,
|
||||
@ -19,15 +26,15 @@ pub struct RegisterBlock {
|
||||
pub slcr_unlock: SlcrUnlock,
|
||||
pub slcr_locksta: RO<u32>,
|
||||
reserved0: [u32; 60],
|
||||
pub arm_pll_ctrl: RW<u32>,
|
||||
pub ddr_pll_ctrl: RW<u32>,
|
||||
pub io_pll_ctrl: RW<u32>,
|
||||
pub arm_pll_ctrl: PllCtrl,
|
||||
pub ddr_pll_ctrl: PllCtrl,
|
||||
pub io_pll_ctrl: PllCtrl,
|
||||
pub pll_status: RO<u32>,
|
||||
pub arm_pll_cfg: RW<u32>,
|
||||
pub ddr_pll_cfg: RW<u32>,
|
||||
pub io_pll_cfg: RW<u32>,
|
||||
reserved1: [u32; 1],
|
||||
pub arm_clk_ctrl: RW<u32>,
|
||||
pub arm_clk_ctrl: ArmClkCtrl,
|
||||
pub ddr_clk_ctrl: RW<u32>,
|
||||
pub dci_clk_ctrl: RW<u32>,
|
||||
pub aper_clk_ctrl: AperClkCtrl,
|
||||
@ -35,8 +42,8 @@ pub struct RegisterBlock {
|
||||
pub usb1_clk_ctrl: RW<u32>,
|
||||
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<u32>,
|
||||
pub lqspi_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_sta: RO<u32>,
|
||||
reserved2: [u32; 5],
|
||||
pub clk_621_true: RW<u32>,
|
||||
pub clk_621_true: Clk621True,
|
||||
reserved3: [u32; 14],
|
||||
pub pss_rst_ctrl: PssRstCtrl,
|
||||
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_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);
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user