Compare commits
13 Commits
master
...
feature/zc
Author | SHA1 | Date |
---|---|---|
Brad Bondurant | 188954ddc7 | |
Brad Bondurant | 0f2376410f | |
Brad Bondurant | 2e5f7ec2f7 | |
Brad Bondurant | c2455b1cda | |
Brad Bondurant | 1e50f68f41 | |
Brad Bondurant | 70489132fb | |
Brad Bondurant | c3273a6ff8 | |
Brad Bondurant | 20784803f0 | |
Brad Bondurant | 79a0d72976 | |
Brad Bondurant | 2b3045b46c | |
Brad Bondurant | 2c179841be | |
Brad Bondurant | 508fac66e8 | |
Brad Bondurant | 3a6517b8db |
|
@ -107,6 +107,22 @@ dependencies = [
|
|||
"volatile-register",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libboard_zynq_us"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"embedded-hal",
|
||||
"libasync",
|
||||
"libboard_zynq",
|
||||
"libregister",
|
||||
"log",
|
||||
"nb 0.1.3",
|
||||
"smoltcp",
|
||||
"void",
|
||||
"volatile-register",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libconfig"
|
||||
version = "0.1.0"
|
||||
|
|
|
@ -8,6 +8,7 @@ members = [
|
|||
"libconfig",
|
||||
"experiments",
|
||||
"szl",
|
||||
"libboard_zynq_us",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
|
|
|
@ -5,8 +5,8 @@ use libregister::*;
|
|||
use super::slcr;
|
||||
use super::clocks::Clocks;
|
||||
|
||||
mod regs;
|
||||
mod baud_rate_gen;
|
||||
pub mod regs;
|
||||
pub mod baud_rate_gen;
|
||||
|
||||
pub struct Uart {
|
||||
regs: &'static mut regs::RegisterBlock,
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
[package]
|
||||
name = "libboard_zynq_us"
|
||||
description = "Drivers for peripherals in the Zynq UltraScale+ PS"
|
||||
version = "0.0.0"
|
||||
authors = ["M-Labs"]
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
target_zcu111 = []
|
||||
ipv6 = [ "smoltcp/proto-ipv6" ]
|
||||
default = [ "target_zcu111" ]
|
||||
|
||||
[dependencies]
|
||||
volatile-register = "0.2"
|
||||
bit_field = "0.10"
|
||||
embedded-hal = "0.2"
|
||||
nb = "0.1"
|
||||
void = { version = "1", default-features = false }
|
||||
log = "0.4"
|
||||
libregister = { path = "../libregister" }
|
||||
# libcortex_a9 = { path = "../libcortex_a9" }
|
||||
libasync = { path = "../libasync" }
|
||||
libboard_zynq = { path = "../libboard_zynq" }
|
||||
|
||||
[dependencies.smoltcp]
|
||||
version = "0.7"
|
||||
features = ["ethernet", "proto-ipv4", "socket-tcp"]
|
||||
default-features = false
|
|
@ -0,0 +1,89 @@
|
|||
use libregister::{RegisterR, RegisterRW};
|
||||
use super::slcr::{crf_apb, crl_apb, common::SlcrRegisterBlock};
|
||||
pub use super::slcr::crf_apb::ApuClkSource;
|
||||
|
||||
pub mod source;
|
||||
use source::*;
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Clocks {
|
||||
/// ARM PLL: Recommended clock source for the APUs and the FPD interconnect
|
||||
pub apu: u32,
|
||||
/// DDR PLL: Recommended clock for the DDR DRAM controller and AXI_HP interfaces
|
||||
pub ddr: u32,
|
||||
/// Video PLL: Recommended clock for display port
|
||||
pub video: u32,
|
||||
/// I/O PLL: Recommended clock for I/O peripherals
|
||||
pub io: u32,
|
||||
/// RPU PLL: Recommended clock for RPUs and LPD interconnect
|
||||
pub rpu: u32,
|
||||
}
|
||||
|
||||
impl Clocks {
|
||||
pub fn get() -> Self {
|
||||
let fpd_regs = crf_apb::RegisterBlock::slcr();
|
||||
let lpd_regs = crl_apb::RegisterBlock::slcr();
|
||||
Clocks {
|
||||
apu: ApuPll::freq(&mut fpd_regs.apu_pll_ctrl),
|
||||
ddr: DdrPll::freq(&mut fpd_regs.ddr_pll_ctrl),
|
||||
video: VideoPll::freq(&mut fpd_regs.video_pll_ctrl),
|
||||
io: IoPll::freq(&mut lpd_regs.io_pll_ctrl),
|
||||
rpu: RpuPll::freq(&mut lpd_regs.rpu_pll_ctrl),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_cpu_freq(target_freq: u32) {
|
||||
let fpd_regs = crf_apb::RegisterBlock::slcr();
|
||||
let apu_pll = ApuPll::freq(&mut fpd_regs.apu_pll_ctrl);
|
||||
let mut div = 1u8;
|
||||
while div < 63 && apu_pll / u32::from(div) > target_freq {
|
||||
div += 1;
|
||||
}
|
||||
|
||||
crf_apb::RegisterBlock::unlocked(|slcr| {
|
||||
slcr.apu_clk_ctrl.modify(|_, w| w
|
||||
.srcsel(ApuClkSource::ApuPll)
|
||||
.divisor0(div)
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn uart0_ref_clk(&self) -> u32 {
|
||||
let lpd_regs = crl_apb::RegisterBlock::slcr();
|
||||
self.uart_ref_clk(&mut lpd_regs.uart0_clk_ctrl)
|
||||
}
|
||||
|
||||
pub fn uart1_ref_clk(&self) -> u32 {
|
||||
let lpd_regs = crl_apb::RegisterBlock::slcr();
|
||||
self.uart_ref_clk(&mut lpd_regs.uart1_clk_ctrl)
|
||||
}
|
||||
|
||||
fn uart_ref_clk(&self, uart_regs: &mut crl_apb::UartClkCtrl) -> u32 {
|
||||
let uart_clk_ctrl = uart_regs.read();
|
||||
let pll = match uart_clk_ctrl.srcsel() {
|
||||
crl_apb::IoClkSource::IoPll => self.io,
|
||||
crl_apb::IoClkSource::RpuPll => self.rpu,
|
||||
crl_apb::IoClkSource::DdrPllToLpd => {
|
||||
let fpd_regs = crf_apb::RegisterBlock::slcr();
|
||||
let divisor = u32::from(fpd_regs.ddr_pll_to_lpd_ctrl.read().divisor0());
|
||||
self.ddr / divisor
|
||||
}
|
||||
};
|
||||
pll / (u32::from(uart_clk_ctrl.divisor0()) * u32::from(uart_clk_ctrl.divisor1()))
|
||||
}
|
||||
|
||||
// pub fn sdio_ref_clk(&self) -> u32 {
|
||||
// let regs = slcr::RegisterBlock::slcr();
|
||||
// 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())
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
use crate::slcr::common::{PllCfg, PllCtrl, PllFracCfg, SlcrRegisterBlock};
|
||||
use crate::slcr::{crf_apb, crl_apb};
|
||||
use libregister::{RegisterR, RegisterRW};
|
||||
use log::debug;
|
||||
|
||||
pub const PS_CLK: u32 = 33_333_000;
|
||||
|
||||
// DS926 Table: PS PLL Switching Characteristics (same for both speed grades)
|
||||
// const PS_PLL_MAX_LOCK_TIME: f32 = 100e-6; // 100 us
|
||||
const PS_PLL_MAX_OUT_FREQ: u32 = 1_600_000_000;
|
||||
const PS_PLL_MIN_OUT_FREQ: u32 = 750_000_000;
|
||||
// const PS_PLL_MAX_VCO_FREQ: u32 = 3_000_000_000;
|
||||
const PS_PLL_MIN_VCO_FREQ: u32 = 1_500_000_000;
|
||||
|
||||
/// UG1085 table 37-1
|
||||
/// (pll_fdiv_max, (pll_cp, pll_res, lfhf, lock_dly, lock_cnt))
|
||||
const PLL_FDIV_LOCK_PARAM: &[(u8, (u8, u8, u8, u8, u16))] = &[
|
||||
(25, (3, 10, 3, 63, 1000)),
|
||||
(26, (3, 10, 3, 63, 1000)),
|
||||
(27, (4, 6, 3, 63, 1000)),
|
||||
(28, (4, 6, 3, 63, 1000)),
|
||||
(29, (4, 6, 3, 63, 1000)),
|
||||
(30, (4, 6, 3, 63, 1000)),
|
||||
(31, (6, 1, 3, 63, 1000)),
|
||||
(32, (6, 1, 3, 63, 1000)),
|
||||
(33, (4, 10, 3, 63, 1000)),
|
||||
(34, (5, 6, 3, 63, 1000)),
|
||||
(35, (5, 6, 3, 63, 1000)),
|
||||
(36, (5, 6, 3, 63, 1000)),
|
||||
(37, (5, 6, 3, 63, 1000)),
|
||||
(38, (5, 6, 3, 63, 975)),
|
||||
(39, (3, 12, 3, 63, 950)),
|
||||
(40, (3, 12, 3, 63, 925)),
|
||||
(41, (3, 12, 3, 63, 900)),
|
||||
(42, (3, 12, 3, 63, 875)),
|
||||
(43, (3, 12, 3, 63, 850)),
|
||||
(44, (3, 12, 3, 63, 850)),
|
||||
(45, (3, 12, 3, 63, 825)),
|
||||
(46, (3, 12, 3, 63, 800)),
|
||||
(47, (3, 12, 3, 63, 775)),
|
||||
(48, (3, 12, 3, 63, 775)),
|
||||
(49, (3, 12, 3, 63, 750)),
|
||||
(50, (3, 12, 3, 63, 750)),
|
||||
(51, (3, 2, 3, 63, 725)),
|
||||
(52, (3, 2, 3, 63, 700)),
|
||||
(53, (3, 2, 3, 63, 700)),
|
||||
(54, (3, 2, 3, 63, 675)),
|
||||
(55, (3, 2, 3, 63, 675)),
|
||||
(56, (3, 2, 3, 63, 650)),
|
||||
(57, (3, 2, 3, 63, 650)),
|
||||
(58, (3, 2, 3, 63, 625)),
|
||||
(59, (3, 2, 3, 63, 625)),
|
||||
(60, (3, 2, 3, 63, 625)),
|
||||
(82, (3, 2, 3, 63, 600)), // 61-82
|
||||
(102, (4, 2, 3, 63, 600)), // 83-102
|
||||
(103, (5, 2, 3, 63, 600)),
|
||||
(104, (5, 2, 3, 63, 600)),
|
||||
(105, (5, 2, 3, 63, 600)),
|
||||
(106, (5, 2, 3, 63, 600)),
|
||||
(125, (3, 4, 3, 63, 600)), // 107-125
|
||||
];
|
||||
|
||||
pub trait ClockSource<T: SlcrRegisterBlock> {
|
||||
/// picks this ClockSource's registers from the SLCR block
|
||||
fn pll_ctrl_regs(slcr: &mut T) -> (&mut PllCtrl, &mut PllCfg, &mut PllFracCfg);
|
||||
|
||||
/// query PLL lock status
|
||||
fn pll_locked() -> bool;
|
||||
|
||||
// todo: is there any situation in which we'll actually want to use fractional mode?
|
||||
/// query fraction mode enable bit
|
||||
fn frac_enabled(pll_frac_cfg: &mut PllFracCfg) -> bool {
|
||||
bool::from(pll_frac_cfg.read().enabled())
|
||||
}
|
||||
|
||||
/// get configured frequency
|
||||
fn freq(pll_ctrl: &mut PllCtrl) -> u32 {
|
||||
// todo: take into account fractional part (if enabled)
|
||||
u32::from(pll_ctrl.read().pll_fdiv()) * PS_CLK
|
||||
}
|
||||
|
||||
fn name() -> &'static str;
|
||||
|
||||
// UG1085 Chapter 37: PS Clock Subsystem
|
||||
fn setup(target_freq: u32) {
|
||||
assert!(target_freq >= PS_PLL_MIN_OUT_FREQ && target_freq <= PS_PLL_MAX_OUT_FREQ);
|
||||
let div2 = target_freq < PS_PLL_MIN_VCO_FREQ;
|
||||
let divisor = u32::from(div2) + 1;
|
||||
let fdiv = (target_freq * divisor / PS_CLK).min(125) as u8;
|
||||
let (pll_cp, pll_res, lfhf, lock_dly, lock_cnt) = PLL_FDIV_LOCK_PARAM
|
||||
.iter()
|
||||
.filter(|(fdiv_max, _)| fdiv <= *fdiv_max)
|
||||
.nth(0)
|
||||
.expect("PLL_FDIV_LOCK_PARAM")
|
||||
.1
|
||||
.clone();
|
||||
|
||||
debug!("Set {} to {} Hz", Self::name(), target_freq);
|
||||
T::unlocked(|slcr| {
|
||||
let (pll_ctrl, pll_cfg, _) = Self::pll_ctrl_regs(slcr);
|
||||
|
||||
// Write fdiv, div2
|
||||
pll_ctrl.modify(|_, w| w.pll_fdiv(fdiv).pll_div2(div2));
|
||||
// Configure
|
||||
// no need to zero as we're writing every field
|
||||
pll_cfg.modify(|_, w| {
|
||||
w.lock_dly(lock_dly)
|
||||
.lock_cnt(lock_cnt)
|
||||
.lfhf(lfhf)
|
||||
.pll_cp(pll_cp)
|
||||
.pll_res(pll_res)
|
||||
});
|
||||
// Bypass
|
||||
pll_ctrl.modify(|_, w| w.pll_bypass_force(true));
|
||||
// Reset
|
||||
pll_ctrl.modify(|_, w| w.pll_reset(true));
|
||||
pll_ctrl.modify(|_, w| w.pll_reset(false));
|
||||
// Wait for PLL lock
|
||||
// todo: add timeout here according to the 100 us spec?
|
||||
while !Self::pll_locked() {}
|
||||
// Remove bypass
|
||||
pll_ctrl.modify(|_, w| w.pll_bypass_force(false));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// APU PLL: Recommended clock source for the APUs and the FPD interconnect
|
||||
pub struct ApuPll;
|
||||
|
||||
impl ClockSource<crf_apb::RegisterBlock> for ApuPll {
|
||||
#[inline]
|
||||
fn pll_ctrl_regs(
|
||||
slcr: &mut crf_apb::RegisterBlock,
|
||||
) -> (&mut PllCtrl, &mut PllCfg, &mut PllFracCfg) {
|
||||
(
|
||||
&mut slcr.apu_pll_ctrl,
|
||||
&mut slcr.apu_pll_cfg,
|
||||
&mut slcr.apu_pll_frac_cfg,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pll_locked() -> bool {
|
||||
let slcr = crf_apb::RegisterBlock::slcr();
|
||||
slcr.pll_status.read().apu_pll_lock()
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
&"APU_PLL"
|
||||
}
|
||||
}
|
||||
|
||||
/// DDR PLL: Recommended clock for the DDR DRAM controller and AXI_HP interfaces
|
||||
pub struct DdrPll;
|
||||
|
||||
impl ClockSource<crf_apb::RegisterBlock> for DdrPll {
|
||||
#[inline]
|
||||
fn pll_ctrl_regs(
|
||||
slcr: &mut crf_apb::RegisterBlock,
|
||||
) -> (&mut PllCtrl, &mut PllCfg, &mut PllFracCfg) {
|
||||
(
|
||||
&mut slcr.ddr_pll_ctrl,
|
||||
&mut slcr.ddr_pll_cfg,
|
||||
&mut slcr.ddr_pll_frac_cfg,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pll_locked() -> bool {
|
||||
let slcr = crf_apb::RegisterBlock::slcr();
|
||||
slcr.pll_status.read().ddr_pll_lock()
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
&"DDR_PLL"
|
||||
}
|
||||
}
|
||||
|
||||
/// Video PLL: Recommended clock for DisplayPort
|
||||
pub struct VideoPll;
|
||||
|
||||
impl ClockSource<crf_apb::RegisterBlock> for VideoPll {
|
||||
#[inline]
|
||||
fn pll_ctrl_regs(
|
||||
slcr: &mut crf_apb::RegisterBlock,
|
||||
) -> (&mut PllCtrl, &mut PllCfg, &mut PllFracCfg) {
|
||||
(
|
||||
&mut slcr.video_pll_ctrl,
|
||||
&mut slcr.video_pll_cfg,
|
||||
&mut slcr.video_pll_frac_cfg,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pll_locked() -> bool {
|
||||
let slcr = crf_apb::RegisterBlock::slcr();
|
||||
slcr.pll_status.read().video_pll_lock()
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
&"VIDEO_PLL"
|
||||
}
|
||||
}
|
||||
|
||||
/// I/O PLL: Recommended clock for I/O peripherals
|
||||
pub struct IoPll;
|
||||
|
||||
impl ClockSource<crl_apb::RegisterBlock> for IoPll {
|
||||
#[inline]
|
||||
fn pll_ctrl_regs(
|
||||
slcr: &mut crl_apb::RegisterBlock,
|
||||
) -> (&mut PllCtrl, &mut PllCfg, &mut PllFracCfg) {
|
||||
(
|
||||
&mut slcr.io_pll_ctrl,
|
||||
&mut slcr.io_pll_cfg,
|
||||
&mut slcr.io_pll_frac_cfg,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pll_locked() -> bool {
|
||||
let slcr = crl_apb::RegisterBlock::slcr();
|
||||
slcr.pll_status.read().io_pll_lock()
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
&"IO_PLL"
|
||||
}
|
||||
}
|
||||
|
||||
/// RPU PLL: Recommended clock for RPUs and LPD interconnect
|
||||
pub struct RpuPll;
|
||||
|
||||
impl ClockSource<crl_apb::RegisterBlock> for RpuPll {
|
||||
#[inline]
|
||||
fn pll_ctrl_regs(
|
||||
slcr: &mut crl_apb::RegisterBlock,
|
||||
) -> (&mut PllCtrl, &mut PllCfg, &mut PllFracCfg) {
|
||||
(
|
||||
&mut slcr.io_pll_ctrl,
|
||||
&mut slcr.io_pll_cfg,
|
||||
&mut slcr.io_pll_frac_cfg,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn pll_locked() -> bool {
|
||||
let slcr = crl_apb::RegisterBlock::slcr();
|
||||
slcr.pll_status.read().rpu_pll_lock()
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
&"RPU_PLL"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
/// Re-export so that dependents can always use the same version
|
||||
pub use libboard_zynq::smoltcp;
|
||||
|
||||
pub mod slcr;
|
||||
pub mod clocks;
|
|
@ -0,0 +1,29 @@
|
|||
///! Type definitions for re-use across SLCR blocks
|
||||
|
||||
use libregister::{register, register_bit, register_bits};
|
||||
|
||||
pub trait SlcrRegisterBlock {
|
||||
fn unlocked<F: FnMut(&mut Self) -> R, R>(f: F) -> R;
|
||||
}
|
||||
|
||||
register!(wprot, WProt, RW, u32);
|
||||
register_bit!(wprot, active, 0);
|
||||
|
||||
register!(pll_ctrl, PllCtrl, RW, u32);
|
||||
register_bits!(pll_ctrl, pll_post_src, u8, 24, 26);
|
||||
register_bits!(pll_ctrl, pll_pre_src, u8, 20, 22);
|
||||
register_bit!(pll_ctrl, pll_div2, 16);
|
||||
register_bits!(pll_ctrl, pll_fdiv, u8, 8, 14);
|
||||
register_bit!(pll_ctrl, pll_bypass_force, 3);
|
||||
register_bit!(pll_ctrl, pll_reset, 0);
|
||||
|
||||
register!(pll_cfg, PllCfg, RW, u32);
|
||||
register_bits!(pll_cfg, lock_dly, u8, 25, 31);
|
||||
register_bits!(pll_cfg, lock_cnt, u16, 13, 22);
|
||||
register_bits!(pll_cfg, lfhf, u8, 10, 11);
|
||||
register_bits!(pll_cfg, pll_cp, u8, 5, 8);
|
||||
register_bits!(pll_cfg, pll_res, u8, 0, 3);
|
||||
|
||||
register!(pll_frac_cfg, PllFracCfg, RW, u32);
|
||||
register_bit!(pll_frac_cfg, enabled, 31);
|
||||
register_bits!(pll_frac_cfg, data, u16, 0, 15);
|
|
@ -0,0 +1,100 @@
|
|||
///! FPD clock and reset control
|
||||
|
||||
use volatile_register::{RO, RW, WO};
|
||||
use libregister::{
|
||||
register, register_at,
|
||||
register_bit, register_bits, register_bits_typed,
|
||||
RegisterW,
|
||||
};
|
||||
|
||||
use super::common::{SlcrRegisterBlock, WProt, PllCfg, PllCtrl, PllFracCfg};
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum ApuClkSource {
|
||||
ApuPll = 0b00,
|
||||
DdrPll = 0b10,
|
||||
VideoPll = 0b11,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
// CRF_APB
|
||||
pub err_ctrl: RW<u32>,
|
||||
pub ir_status: RW<u32>, // todo: WTC LSB
|
||||
pub ir_mask: RO<u32>,
|
||||
pub ir_enable: WO<u32>,
|
||||
pub ir_disable: WO<u32>,
|
||||
pub crf_wprot: WProt,
|
||||
pub apu_pll_ctrl: PllCtrl,
|
||||
pub apu_pll_cfg: PllCfg,
|
||||
pub apu_pll_frac_cfg: PllFracCfg,
|
||||
pub ddr_pll_ctrl: PllCtrl,
|
||||
pub ddr_pll_cfg: PllCfg,
|
||||
pub ddr_pll_frac_cfg: PllFracCfg,
|
||||
pub video_pll_ctrl: PllCtrl,
|
||||
pub video_pll_cfg: PllCfg,
|
||||
pub video_pll_frac_cfg: PllFracCfg,
|
||||
pub pll_status: PllStatus,
|
||||
pub apu_pll_to_lpd_ctrl: PllToLpdCtrl,
|
||||
pub ddr_pll_to_lpd_ctrl: PllToLpdCtrl,
|
||||
pub video_pll_to_lpd_ctrl: PllToLpdCtrl,
|
||||
reserved1: [u32; 3],
|
||||
pub apu_clk_ctrl: ApuClkCtrl,
|
||||
pub dbg_trace_clk_ctrl: RW<u32>,
|
||||
pub dbg_fpd_clk_ctrl: RW<u32>,
|
||||
reserved2: [u32; 1],
|
||||
pub dp_video_clk_ctrl: RW<u32>,
|
||||
pub dp_audio_clk_ctrl: RW<u32>,
|
||||
reserved3: [u32; 1],
|
||||
pub dp_sys_clk_ctrl: RW<u32>,
|
||||
pub ddr_clk_ctrl: DdrClkCtrl,
|
||||
pub gpu_clk_ctrl: RW<u32>,
|
||||
reserved4: [u32; 6],
|
||||
pub sata_clk_ctrl: RW<u32>,
|
||||
reserved5: [u32; 4],
|
||||
pub pcie_clk_ctrl: RW<u32>,
|
||||
pub fpd_dma_clk_ctrl: RW<u32>,
|
||||
pub dp_dma_clk_ctrl: RW<u32>,
|
||||
pub topsw_main_clk_ctrl: RW<u32>,
|
||||
pub topsw_lsbus_clk_ctrl: RW<u32>,
|
||||
reserved6: [u32; 8],
|
||||
pub dbg_tstmp_clk_ctrl: RW<u32>,
|
||||
reserved7: [u32; 1],
|
||||
pub rst_fpd_top: RW<u32>,
|
||||
pub rst_fpd_apu: RW<u32>,
|
||||
pub rst_ddr_ss: RW<u32>,
|
||||
}
|
||||
register_at!(RegisterBlock, 0xFD1A_0000, slcr);
|
||||
|
||||
impl SlcrRegisterBlock for RegisterBlock {
|
||||
fn unlocked<F: FnMut(&mut Self) -> R, R>(mut f: F) -> R {
|
||||
let mut self_ = Self::slcr();
|
||||
self_.crf_wprot.write(WProt::zeroed().active(false));
|
||||
let r = f(&mut self_);
|
||||
self_.crf_wprot.write(WProt::zeroed().active(true));
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
register!(pll_status, PllStatus, RO, u32);
|
||||
register_bit!(pll_status, video_pll_stable, 5);
|
||||
register_bit!(pll_status, ddr_pll_stable, 4);
|
||||
register_bit!(pll_status, apu_pll_stable, 3);
|
||||
register_bit!(pll_status, video_pll_lock, 2);
|
||||
register_bit!(pll_status, ddr_pll_lock, 1);
|
||||
register_bit!(pll_status, apu_pll_lock, 0);
|
||||
|
||||
register!(pll_to_lpd_ctrl, PllToLpdCtrl, RW, u32);
|
||||
register_bits!(pll_to_lpd_ctrl, divisor0, u8, 8, 13);
|
||||
|
||||
register!(apu_clk_ctrl, ApuClkCtrl, RW, u32);
|
||||
register_bit!(apu_clk_ctrl, clkact_half, 25);
|
||||
register_bit!(apu_clk_ctrl, clkact_full, 24);
|
||||
register_bits!(apu_clk_ctrl, divisor0, u8, 8, 13);
|
||||
register_bits_typed!(apu_clk_ctrl, srcsel, u8, ApuClkSource, 0, 2);
|
||||
|
||||
register!(ddr_clk_ctrl, DdrClkCtrl, RW, u32);
|
||||
register_bits!(ddr_clk_ctrl, divisor0, u8, 8, 13);
|
||||
// 000: DDR PLL
|
||||
// 001: Video PLL
|
||||
register_bits!(ddr_clk_ctrl, srcsel, u8, 0, 2);
|
|
@ -0,0 +1,315 @@
|
|||
///! FPD clock and reset control
|
||||
|
||||
use volatile_register::{RO, RW, WO};
|
||||
use libregister::{
|
||||
register, register_at,
|
||||
register_bit, register_bits, register_bits_typed,
|
||||
};
|
||||
|
||||
use super::common::{SlcrRegisterBlock, WProt, PllCfg, PllCtrl, PllFracCfg};
|
||||
|
||||
/// Clock source selection for IO-type devices
|
||||
#[repr(u8)]
|
||||
pub enum IoClkSource {
|
||||
IoPll = 0b00,
|
||||
RpuPll = 0b10,
|
||||
DdrPllToLpd = 0b11,
|
||||
}
|
||||
|
||||
/// Clock source selection for RPU and related (e.g. LPD interconnect) devices
|
||||
#[repr(u8)]
|
||||
pub enum RpuClkSource {
|
||||
RpuPll = 0b00,
|
||||
IoPll = 0b10,
|
||||
DdrPllToLpd = 0b11,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
pub err_ctrl: RW<u32>,
|
||||
pub ir_status: RW<u32>, // todo: WTC LSB
|
||||
pub ir_mask: RO<u32>,
|
||||
pub ir_enable: WO<u32>,
|
||||
pub ir_disable: WO<u32>,
|
||||
reserved1: [u32; 2],
|
||||
pub crl_wprot: WProt,
|
||||
pub io_pll_ctrl: PllCtrl,
|
||||
pub io_pll_cfg: PllCfg,
|
||||
pub io_pll_frac_cfg: PllFracCfg,
|
||||
reserved2: [u32; 1],
|
||||
pub rpu_pll_ctrl: PllCtrl,
|
||||
pub rpu_pll_cfg: PllCfg,
|
||||
pub rpu_pll_frac_cfg: PllFracCfg,
|
||||
reserved3: [u32; 1],
|
||||
pub pll_status: PllStatus,
|
||||
pub io_pll_to_fpd_ctrl: PllToFpdCtrl,
|
||||
pub rpu_pll_to_fpd_ctrl: PllToFpdCtrl,
|
||||
pub usb3_clk_ctrl: UsbClkCtrl,
|
||||
pub gem0_clk_ctrl: GemClkCtrl,
|
||||
pub gem1_clk_ctrl: GemClkCtrl,
|
||||
pub gem2_clk_ctrl: GemClkCtrl,
|
||||
pub gem3_clk_ctrl: GemClkCtrl,
|
||||
pub usb0_bus_clk_ctrl: UsbClkCtrl,
|
||||
pub usb1_bus_clk_ctrl: UsbClkCtrl,
|
||||
pub qspi_clk_ctrl: QSpiClkCtrl,
|
||||
pub sdio0_clk_ctrl: SdioClkCtrl,
|
||||
pub sdio1_clk_ctrl: SdioClkCtrl,
|
||||
pub uart0_clk_ctrl: UartClkCtrl,
|
||||
pub uart1_clk_ctrl: UartClkCtrl,
|
||||
pub spi0_clk_ctrl: SpiClkCtrl,
|
||||
pub spi1_clk_ctrl: SpiClkCtrl,
|
||||
pub can0_clk_ctrl: CanClkCtrl,
|
||||
pub can1_clk_ctrl: CanClkCtrl,
|
||||
reserved4: [u32; 1],
|
||||
pub rpu_clk_ctrl: RpuClkCtrl,
|
||||
reserved5: [u32; 2],
|
||||
pub iou_switch_clk_ctrl: IouSwitchClkCtrl,
|
||||
pub csu_clk_ctrl: CsuPllCtrl,
|
||||
pub pcap_clk_ctrl: PcapClkCtrl,
|
||||
pub lpd_switch_clk_ctrl: LpdSwitchClkCtrl,
|
||||
pub lpd_lsbus_clk_ctrl: LpdLsbusClkCtrl,
|
||||
pub dbg_lpd_clk_ctrl: DbgLpdClkCtrl,
|
||||
pub nand_clk_ctrl: NandClkCtrl,
|
||||
pub lpd_dma_clk_ctrl: LpdDmaClkCtrl,
|
||||
reserved6: [u32; 1],
|
||||
pub pl0_clk_ctrl: PlClkCtrl,
|
||||
pub pl1_clk_ctrl: PlClkCtrl,
|
||||
pub pl2_clk_ctrl: PlClkCtrl,
|
||||
pub pl3_clk_ctrl: PlClkCtrl,
|
||||
pub pl0_thr_ctrl: PlThrCtrl,
|
||||
pub pl0_thr_cnt: PlThrCnt,
|
||||
pub pl1_thr_ctrl: PlThrCtrl,
|
||||
pub pl1_thr_cnt: PlThrCnt,
|
||||
pub pl2_thr_ctrl: PlThrCtrl,
|
||||
pub pl2_thr_cnt: PlThrCnt,
|
||||
pub pl3_thr_ctrl: PlThrCtrl,
|
||||
reserved7: [u32; 4],
|
||||
pub pl3_thr_cnt: PlThrCnt,
|
||||
pub gem_tsu_clk_ctrl: GemTsuClkCtrl,
|
||||
pub dll_clk_ctrl: DllClkCtrl,
|
||||
pub ps_sysmon_clk_ctrl: PsSysmonClkCtrl,
|
||||
reserved8: [u32; 5],
|
||||
pub i2c0_clk_ctrl: I2cClkCtrl,
|
||||
pub i2c1_clk_ctrl: I2cClkCtrl,
|
||||
pub timestamp_clk_ctrl: TimestampClkCtrl,
|
||||
reserved9: [u32; 1],
|
||||
pub safety_chk: RW<u32>,
|
||||
reserved10: [u32; 3],
|
||||
pub clkmon_status: RW<u32>,
|
||||
pub clkmon_mask: RO<u32>,
|
||||
pub clkmon_enable: WO<u32>,
|
||||
pub clkmon_disable: WO<u32>,
|
||||
pub clkmon_trigger: WO<u32>,
|
||||
reserved11: [u32; 3],
|
||||
pub chkr0_clka_upper: RW<u32>,
|
||||
pub chkr0_clka_lower: RW<u32>,
|
||||
pub chkr0_clkb_cnt: RW<u32>,
|
||||
pub chkr0_ctrl: RW<u32>,
|
||||
pub chkr1_clka_upper: RW<u32>,
|
||||
pub chkr1_clka_lower: RW<u32>,
|
||||
pub chkr1_clkb_cnt: RW<u32>,
|
||||
pub chkr1_ctrl: RW<u32>,
|
||||
pub chkr2_clka_upper: RW<u32>,
|
||||
pub chkr2_clka_lower: RW<u32>,
|
||||
pub chkr2_clkb_cnt: RW<u32>,
|
||||
pub chkr2_ctrl: RW<u32>,
|
||||
pub chkr3_clka_upper: RW<u32>,
|
||||
pub chkr3_clka_lower: RW<u32>,
|
||||
pub chkr3_clkb_cnt: RW<u32>,
|
||||
pub chkr3_ctrl: RW<u32>,
|
||||
pub chkr4_clka_upper: RW<u32>,
|
||||
pub chkr4_clka_lower: RW<u32>,
|
||||
pub chkr4_clkb_cnt: RW<u32>,
|
||||
pub chkr4_ctrl: RW<u32>,
|
||||
pub chkr5_clka_upper: RW<u32>,
|
||||
pub chkr5_clka_lower: RW<u32>,
|
||||
pub chkr5_clkb_cnt: RW<u32>,
|
||||
pub chkr5_ctrl: RW<u32>,
|
||||
pub chkr6_clka_upper: RW<u32>,
|
||||
pub chkr6_clka_lower: RW<u32>,
|
||||
pub chkr6_clkb_cnt: RW<u32>,
|
||||
pub chkr6_ctrl: RW<u32>,
|
||||
pub chkr7_clka_upper: RW<u32>,
|
||||
pub chkr7_clka_lower: RW<u32>,
|
||||
pub chkr7_clkb_cnt: RW<u32>,
|
||||
pub chkr7_ctrl: RW<u32>,
|
||||
reserved12: [u32; 8],
|
||||
pub boot_mode_user: RW<u32>,
|
||||
pub boot_mode: BootMode,
|
||||
reserved13: [u32; 4],
|
||||
pub reset_ctrl: RW<u32>,
|
||||
pub blockonly_rst: RW<u32>, // todo: WTC LSB
|
||||
pub reset_reason: RW<u32>, // todo: WTC 0:6
|
||||
reserved14: [u32; 3],
|
||||
pub gem_rst_ctrl: GemRstCtrl,
|
||||
reserved15: [u32; 1],
|
||||
pub peri_rst_ctrl: PeriRstCtrl,
|
||||
pub rst_lpd_top: RstLpdTop,
|
||||
pub rst_lpd_dbg: RW<u32>,
|
||||
reserved16: [u32; 3],
|
||||
pub boot_pin_ctrl: RW<u32>, // todo: RO 4:7
|
||||
reserved17: [u32; 7],
|
||||
pub bank3_drive0: RW<u32>,
|
||||
pub bank3_drive1: RW<u32>,
|
||||
pub bank3_input_ctrl: RW<u32>,
|
||||
pub bank3_pull_ctrl: RW<u32>,
|
||||
pub bank3_pull_enable: RW<u32>,
|
||||
pub bank3_slew_ctrl: RW<u32>,
|
||||
pub bank3_status: RO<u32>,
|
||||
}
|
||||
register_at!(RegisterBlock, 0xFF5E_0000, slcr);
|
||||
|
||||
impl SlcrRegisterBlock for RegisterBlock {
|
||||
// Dummy definition (CRL_APB has no WProt) for consistency with CRF_APB
|
||||
fn unlocked<F: FnMut(&mut Self) -> R, R>(mut f: F) -> R {
|
||||
let mut self_ = Self::slcr();
|
||||
f(&mut self_)
|
||||
}
|
||||
}
|
||||
|
||||
register!(pll_status, PllStatus, RO, u32);
|
||||
register_bit!(pll_status, rpu_pll_stable, 4);
|
||||
register_bit!(pll_status, io_pll_stable, 3);
|
||||
register_bit!(pll_status, rpu_pll_lock, 1);
|
||||
register_bit!(pll_status, io_pll_lock, 0);
|
||||
|
||||
|
||||
register!(pll_to_fpd_ctrl, PllToFpdCtrl, RW, u32);
|
||||
register_bits!(pll_to_fpd_ctrl, divisor0, u8, 8, 13);
|
||||
|
||||
register!(gem_clk_ctrl, GemClkCtrl, RW, u32);
|
||||
register_bit!(gem_clk_ctrl, rx_clkact, 26);
|
||||
register_bit!(gem_clk_ctrl, clkact, 25);
|
||||
register_bits!(gem_clk_ctrl, divisor1, u8, 16, 21);
|
||||
register_bits!(gem_clk_ctrl, divisor0, u8, 8, 13);
|
||||
register_bits_typed!(gem_clk_ctrl, srcsel, u8, IoClkSource, 0, 2);
|
||||
|
||||
|
||||
register!(usb_clk_ctrl, UsbClkCtrl, RW, u32);
|
||||
register_bit!(usb_clk_ctrl, clkact, 25);
|
||||
register_bits!(usb_clk_ctrl, divisor1, u8, 16, 21);
|
||||
register_bits!(usb_clk_ctrl, divisor0, u8, 8, 13);
|
||||
register_bits_typed!(usb_clk_ctrl, srcsel, u8, IoClkSource, 0, 2);
|
||||
|
||||
|
||||
macro_rules! dual_div_clk_reg {
|
||||
($mod_name: ident, $struct_name: ident, $srcsel_type: ident) => {
|
||||
register!($mod_name, $struct_name, RW, u32);
|
||||
register_bit!($mod_name, clkact, 24);
|
||||
register_bits!($mod_name, divisor1, u8, 16, 21);
|
||||
register_bits!($mod_name, divisor0, u8, 8, 13);
|
||||
register_bits_typed!($mod_name, srcsel, u8, $srcsel_type, 0, 2);
|
||||
};
|
||||
}
|
||||
|
||||
dual_div_clk_reg!(qspi_clk_ctrl, QSpiClkCtrl, IoClkSource);
|
||||
dual_div_clk_reg!(sdio_clk_ctrl, SdioClkCtrl, IoClkSource);
|
||||
dual_div_clk_reg!(uart_clk_ctrl, UartClkCtrl, IoClkSource);
|
||||
dual_div_clk_reg!(spi_clk_ctrl, SpiClkCtrl, IoClkSource);
|
||||
dual_div_clk_reg!(can_clk_ctrl, CanClkCtrl, IoClkSource);
|
||||
dual_div_clk_reg!(nand_clk_ctrl, NandClkCtrl, IoClkSource);
|
||||
dual_div_clk_reg!(pl_clk_ctrl, PlClkCtrl, IoClkSource);
|
||||
dual_div_clk_reg!(gem_tsu_clk_ctrl, GemTsuClkCtrl, IoClkSource);
|
||||
dual_div_clk_reg!(ps_sysmon_clk_ctrl, PsSysmonClkCtrl, RpuClkSource);
|
||||
dual_div_clk_reg!(i2c_clk_ctrl, I2cClkCtrl, IoClkSource);
|
||||
|
||||
|
||||
register!(rpu_clk_ctrl, RpuClkCtrl, RW, u32);
|
||||
register_bit!(rpu_clk_ctrl, clkact_core, 25);
|
||||
register_bit!(rpu_clk_ctrl, clkact, 24);
|
||||
register_bits!(rpu_clk_ctrl, divisor0, u8, 8, 13);
|
||||
register_bits_typed!(rpu_clk_ctrl, srcsel, u8, RpuClkSource, 0, 2);
|
||||
|
||||
|
||||
macro_rules! single_div_clk_reg {
|
||||
// default to RpuClkSource
|
||||
($mod_name: ident, $struct_name: ident, $srcsel_type: ident) => {
|
||||
register!($mod_name, $struct_name, RW, u32);
|
||||
register_bit!($mod_name, clkact, 24);
|
||||
register_bits!($mod_name, divisor1, u8, 16, 21);
|
||||
register_bits!($mod_name, divisor0, u8, 8, 13);
|
||||
register_bits_typed!($mod_name, srcsel, u8, $srcsel_type, 0, 2);
|
||||
};
|
||||
}
|
||||
|
||||
single_div_clk_reg!(iou_switch_clk_ctrl, IouSwitchClkCtrl, RpuClkSource);
|
||||
single_div_clk_reg!(csu_clk_ctrl, CsuPllCtrl, IoClkSource);
|
||||
single_div_clk_reg!(pcap_clk_ctrl, PcapClkCtrl, IoClkSource);
|
||||
single_div_clk_reg!(lpd_switch_clk_ctrl, LpdSwitchClkCtrl, RpuClkSource);
|
||||
single_div_clk_reg!(lpd_lsbus_clk_ctrl, LpdLsbusClkCtrl, RpuClkSource);
|
||||
single_div_clk_reg!(dbg_lpd_clk_ctrl, DbgLpdClkCtrl, RpuClkSource);
|
||||
single_div_clk_reg!(lpd_dma_clk_ctrl, LpdDmaClkCtrl, RpuClkSource);
|
||||
// todo: timestamp clk can also run directly from PS_REF_CLK (0b1xx)
|
||||
single_div_clk_reg!(timestamp_clk_ctrl, TimestampClkCtrl, IoClkSource);
|
||||
|
||||
|
||||
register!(pl_thr_ctrl, PlThrCtrl, RW, u32);
|
||||
register_bits!(pl_thr_ctrl, curr_val, u16, 16, 31, RO);
|
||||
register_bit!(pl_thr_ctrl, running, 15, RO);
|
||||
register_bit!(pl_thr_ctrl, cpu_start, 1);
|
||||
register_bit!(pl_thr_ctrl, cnt_rst, 0);
|
||||
|
||||
|
||||
register!(pl_thr_cnt, PlThrCnt, RW, u32);
|
||||
register_bits!(pl_thr_cnt, last_cnt, u16, 0, 15);
|
||||
|
||||
|
||||
register!(dll_clk_ctrl, DllClkCtrl, RW, u32);
|
||||
register_bits!(dll_clk_ctrl, srcsel, u8, 0, 2);
|
||||
|
||||
// boot mode pin values read after POR and "triplicated for security"
|
||||
register!(boot_mode, BootMode, RO, u32);
|
||||
register_bits!(boot_mode, boot_mode2, u8, 8, 11);
|
||||
register_bits!(boot_mode, boot_mode1, u8, 4, 7);
|
||||
register_bits!(boot_mode, boot_mode0, u8, 0, 3);
|
||||
|
||||
register!(gem_rst_ctrl, GemRstCtrl, RW, u32);
|
||||
register_bit!(gem_rst_ctrl, gem3_rst, 3);
|
||||
register_bit!(gem_rst_ctrl, gem2_rst, 2);
|
||||
register_bit!(gem_rst_ctrl, gem1_rst, 1);
|
||||
register_bit!(gem_rst_ctrl, gem0_rst, 0);
|
||||
|
||||
|
||||
register!(peri_rst_ctrl, PeriRstCtrl, RW, u32);
|
||||
register_bit!(peri_rst_ctrl, timestamp_rst, 20);
|
||||
register_bit!(peri_rst_ctrl, iou_cc_rst, 19);
|
||||
register_bit!(peri_rst_ctrl, gpio_rst, 18);
|
||||
register_bit!(peri_rst_ctrl, lpd_dma_rst, 17);
|
||||
register_bit!(peri_rst_ctrl, nand_rst, 16);
|
||||
register_bit!(peri_rst_ctrl, swdt_rst, 15);
|
||||
register_bit!(peri_rst_ctrl, ttc3_rst, 14);
|
||||
register_bit!(peri_rst_ctrl, ttc2_rst, 13);
|
||||
register_bit!(peri_rst_ctrl, ttc1_rst, 12);
|
||||
register_bit!(peri_rst_ctrl, ttc0_rst, 11);
|
||||
register_bit!(peri_rst_ctrl, i2c1_rst, 10);
|
||||
register_bit!(peri_rst_ctrl, i2c0_rst, 9);
|
||||
register_bit!(peri_rst_ctrl, can1_rst, 8);
|
||||
register_bit!(peri_rst_ctrl, can0_rst, 7);
|
||||
register_bit!(peri_rst_ctrl, sdio1_rst, 6);
|
||||
register_bit!(peri_rst_ctrl, sdio0_rst, 5);
|
||||
register_bit!(peri_rst_ctrl, spi1_rst, 4);
|
||||
register_bit!(peri_rst_ctrl, spi0_rst, 3);
|
||||
register_bit!(peri_rst_ctrl, uart1_rst, 2);
|
||||
register_bit!(peri_rst_ctrl, uart0_rst, 1);
|
||||
register_bit!(peri_rst_ctrl, qspi_rst, 0);
|
||||
|
||||
|
||||
register!(rst_lpd_top, RstLpdTop, RW, u32);
|
||||
register_bit!(rst_lpd_top, fpd_rst, 23);
|
||||
register_bit!(rst_lpd_top, lpd_swdt_rst, 20);
|
||||
register_bit!(rst_lpd_top, s_axi_lpd_rst, 19);
|
||||
register_bit!(rst_lpd_top, sysmon_rst, 17);
|
||||
register_bit!(rst_lpd_top, rtc_rst, 16);
|
||||
register_bit!(rst_lpd_top, apm_rst, 15);
|
||||
register_bit!(rst_lpd_top, ipi_rst, 14);
|
||||
register_bit!(rst_lpd_top, usb1_apb_rst, 11);
|
||||
register_bit!(rst_lpd_top, usb0_apb_rst, 10);
|
||||
register_bit!(rst_lpd_top, usb1_hiber_rst, 9);
|
||||
register_bit!(rst_lpd_top, usb0_hiber_rst, 8);
|
||||
register_bit!(rst_lpd_top, usb1_core_rst, 7);
|
||||
register_bit!(rst_lpd_top, usb0_core_rst, 6);
|
||||
register_bit!(rst_lpd_top, rpu_pge_rst, 4);
|
||||
register_bit!(rst_lpd_top, ocm_rst, 3);
|
||||
register_bit!(rst_lpd_top, rpu_amba_rst, 2);
|
||||
register_bit!(rst_lpd_top, rpu_core1_rst, 1);
|
||||
register_bit!(rst_lpd_top, rpu_core0_rst, 0);
|
|
@ -0,0 +1,124 @@
|
|||
///! IOU SLCR for MIO pin configuration
|
||||
|
||||
use volatile_register::{RO, RW, WO};
|
||||
use libregister::{
|
||||
register, register_at,
|
||||
register_bit, register_bits,
|
||||
};
|
||||
|
||||
use super::common::SlcrRegisterBlock;
|
||||
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
pub mio_pin: [MioPin; 78],
|
||||
pub bank0_drive0: BankDriveCtrl,
|
||||
pub bank0_drive1: BankDriveCtrl,
|
||||
pub bank0_input_ctrl: BankInputCtrl,
|
||||
pub bank0_pull_ctrl: BankPullCtrl,
|
||||
pub bank0_pull_enable: BankPullEnable,
|
||||
pub bank0_slew_ctrl: BankSlewCtrl,
|
||||
pub bank0_status: BankStatus,
|
||||
pub bank1_drive0: BankDriveCtrl,
|
||||
pub bank1_drive1: BankDriveCtrl,
|
||||
pub bank1_input_ctrl: BankInputCtrl,
|
||||
pub bank1_pull_ctrl: BankPullCtrl,
|
||||
pub bank1_pull_enable: BankPullEnable,
|
||||
pub bank1_slew_ctrl: BankSlewCtrl,
|
||||
pub bank1_status: BankStatus,
|
||||
pub bank2_drive0: BankDriveCtrl,
|
||||
pub bank2_drive1: BankDriveCtrl,
|
||||
pub bank2_input_ctrl: BankInputCtrl,
|
||||
pub bank2_pull_ctrl: BankPullCtrl,
|
||||
pub bank2_pull_enable: BankPullEnable,
|
||||
pub bank2_slew_ctrl: BankSlewCtrl,
|
||||
pub bank2_status: BankStatus,
|
||||
reserved1: [u32; 5],
|
||||
pub mio_loopback: RW<u32>,
|
||||
pub mio_mst_tri0: RW<u32>,
|
||||
pub mio_mst_tri1: RW<u32>,
|
||||
pub mio_mst_tri2: RW<u32>,
|
||||
pub wdt_clk_sel: RW<u32>, // 0 = internal APB clock, 1 = external
|
||||
pub can_mio_ctrl: RW<u32>,
|
||||
pub gem_clk_ctrl: RW<u32>,
|
||||
pub sdio_clk_ctrl: RW<u32>,
|
||||
pub ctrl_reg_sd: RW<u32>,
|
||||
pub sd_itap_dly: RW<u32>,
|
||||
pub sd_otap_dly_sel: RW<u32>,
|
||||
pub sd_cfg1: RW<u32>,
|
||||
pub sd_cfg2: RW<u32>,
|
||||
pub sd_cfg3: RW<u32>,
|
||||
pub sd_init_preset: RW<u32>,
|
||||
pub sd_speed_preset: RW<u32>,
|
||||
pub sd_hspeed_preset: RW<u32>,
|
||||
pub sd_sdr12_preset: RW<u32>,
|
||||
pub sd_sdr25_preset: RW<u32>,
|
||||
pub sd_sdr50_preset: RW<u32>,
|
||||
reserved2: [u32; 1],
|
||||
pub sd_sdr104_preset: RW<u32>,
|
||||
pub sd_ddr50_preset: RW<u32>,
|
||||
pub sd_max_cur_18: RW<u32>,
|
||||
pub sd_max_cur_30: RW<u32>,
|
||||
pub sd_max_cur_33: RW<u32>,
|
||||
pub sd_dll_ctrl: RW<u32>,
|
||||
pub sd_cdn_ctrl: RW<u32>,
|
||||
pub gem_ctrl: RW<u32>,
|
||||
reserved3: [u32; 7],
|
||||
pub iou_ttc_apb_clk: RW<u32>,
|
||||
reserved4: [u32; 3],
|
||||
pub iou_tapdly_bypass: RW<u32>,
|
||||
reserved5: [u32; 3],
|
||||
pub iou_coherent_ctrl: RW<u32>,
|
||||
pub video_pss_clk_sel: RW<u32>,
|
||||
pub iou_interconnect_route: RW<u32>,
|
||||
reserved6: [u32; 125],
|
||||
pub ctrl: RW<u32>,
|
||||
reserved7: [u32; 63],
|
||||
pub isr: RW<u32>, // todo: WTC LSB
|
||||
pub imr: RO<u32>,
|
||||
pub ier: WO<u32>,
|
||||
pub idr: WO<u32>,
|
||||
pub itr: WO<u32>,
|
||||
}
|
||||
register_at!(RegisterBlock, 0xFF18_0000, slcr);
|
||||
|
||||
impl SlcrRegisterBlock for RegisterBlock {
|
||||
// Dummy definition for consistency
|
||||
fn unlocked<F: FnMut(&mut Self) -> R, R>(mut f: F) -> R {
|
||||
let mut self_ = Self::slcr();
|
||||
f(&mut self_)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
register!(mio_pin, MioPin, RW, u32);
|
||||
register_bits!(mio_pin, l3_sel, u8, 5, 7);
|
||||
register_bits!(mio_pin, l2_sel, u8, 3, 4);
|
||||
register_bit!(mio_pin, l1_sel, 2);
|
||||
register_bit!(mio_pin, l0_sel, 1);
|
||||
|
||||
register!(bank_drive_ctrl, BankDriveCtrl, RW, u32);
|
||||
register_bits!(bank_drive_ctrl, drive, u32, 0, 25);
|
||||
|
||||
// 0 = CMOS, 1 = Schmitt
|
||||
register!(bank_input_ctrl, BankInputCtrl, RW, u32);
|
||||
register_bits!(bank_input_ctrl, schmitt, u32, 0, 25);
|
||||
|
||||
// 0 = down, 1 = up
|
||||
register!(bank_pull_ctrl, BankPullCtrl, RW, u32);
|
||||
register_bits!(bank_pull_ctrl, pull_up, u32, 0, 25);
|
||||
|
||||
register!(bank_pull_enable, BankPullEnable, RW, u32);
|
||||
register_bits!(bank_pull_enable, pull_enable, u32, 0, 25);
|
||||
|
||||
// 0 = fast, 1 = slow
|
||||
register!(bank_slew_ctrl, BankSlewCtrl, RW, u32);
|
||||
register_bits!(bank_slew_ctrl, slow_slew, u32, 0, 25);
|
||||
|
||||
// 0 = 2.5 or 3.3V, 1 = 1.8V
|
||||
register!(bank_status, BankStatus, RO, u32);
|
||||
register_bit!(bank_status, voltage_mode, 0);
|
||||
|
||||
|
||||
// todo: impl for MioPin (or RegisterBlock?) to make drive ctrl less obnoxious
|
||||
// might as well toss in convenience functions for pull up/down, etc.
|
|
@ -0,0 +1,15 @@
|
|||
///! Register definitions for UltraScale+ System Level Control
|
||||
pub mod common;
|
||||
pub mod crf_apb;
|
||||
// APU
|
||||
// FPD_SLCR
|
||||
// FPD_SLCR_SECURE
|
||||
pub mod iou_slcr;
|
||||
// IOU_SECURE_SLCR
|
||||
// IOU_SCNTRS
|
||||
// LPD_SLCR
|
||||
// LPD_SLCR_SECURE
|
||||
pub mod crl_apb;
|
||||
// RPU
|
||||
// CCI_GPV
|
||||
// FPD_GPV
|
|
@ -0,0 +1,7 @@
|
|||
use libregister::register_at;
|
||||
|
||||
use libboard_zynq::uart::baud_rate_gen;
|
||||
use libboard_zync::uart::regs::RegisterBlock;
|
||||
|
||||
register_at!(RegisterBlock, 0xFF000000, uart0);
|
||||
register_at!(RegisterBlock, 0xFF010000, uart1); // note: PS_UART1 is not connected on ZCU111
|
|
@ -290,6 +290,19 @@ macro_rules! register_bits {
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
($mod_name: ident, $(#[$outer:meta])* $name: ident, $type: ty, $bit_begin: expr, $bit_end: expr, RO) => (
|
||||
impl $mod_name::Read {
|
||||
#[allow(unused)]
|
||||
#[inline]
|
||||
$(#[$outer])*
|
||||
pub fn $name(&self) -> $type {
|
||||
use bit_field::BitField;
|
||||
|
||||
self.inner.get_bits($bit_begin..=$bit_end) as $type
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// Define a multi-bit field of a register, coerced to a certain type
|
||||
|
|
Loading…
Reference in New Issue