pub use crate::chip::config::ccm::analog::*;
pub mod pll2 {
pub const FREQUENCY: u32 = 528_000_000;
pub const MIN_FRAC: u8 = super::pll3::MIN_FRAC;
pub const MAX_FRAC: u8 = super::pll3::MAX_FRAC;
}
pub mod pll3 {
pub const FREQUENCY: u32 = 480_000_000;
pub const MIN_FRAC: u8 = 12;
pub const MAX_FRAC: u8 = 35;
use crate::ral;
pub fn restart(ccm_analog: &mut ral::ccm_analog::CCM_ANALOG) {
loop {
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_USB1, ENABLE == 0) {
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_USB1_SET, ENABLE: 1);
continue;
}
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_USB1, POWER == 0) {
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_USB1_SET, POWER: 1);
continue;
}
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_USB1, LOCK == 0) {
continue;
}
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_USB1, BYPASS == 1) {
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_USB1_CLR, BYPASS: 1);
continue;
}
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_USB1, EN_USB_CLKS == 0) {
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_USB1_SET, EN_USB_CLKS: 1);
continue;
}
break;
}
}
}
pub mod pll4 {
pub const MIN_FRAC: u8 = 12;
pub const MAX_FRAC: u8 = 35;
use crate::{common::ccm, ral};
#[derive(PartialEq, Eq)]
pub enum PostDivider {
U1 = 1,
U2 = 2,
U4 = 4,
U8 = 8,
U16 = 16,
}
fn output_freq(div_select: u32, pll_num: u32, pll_denom: u32) -> u32 {
(((ccm::XTAL_OSCILLATOR_HZ * div_select) as u64)
+ ((ccm::XTAL_OSCILLATOR_HZ as u64) * (pll_num as u64)) / (pll_denom as u64))
as u32
}
pub fn reconfigure(
ccm_analog: &mut ral::ccm_analog::CCM_ANALOG,
div_select: u32,
pll_num: u32,
pll_denom: u32,
post_divider: PostDivider,
) {
assert!(
(27..=54).contains(&div_select),
"Audio PLL divider selection must be in range from 27 to 54 inclusive"
);
assert!(
pll_num <= pll_denom,
"PLL requires numerator be less than the denominator"
);
let out_freq: u32 = output_freq(div_select, pll_num, pll_denom);
assert!(
out_freq > 650_000_000 && out_freq <= 1_300_000_000,
"Maximum PLL4 output range is from 650MHz to 1.3GHz"
);
loop {
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO, BYPASS == 0) {
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO_SET, BYPASS: 1);
continue;
}
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO, ENABLE == 1) {
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO_CLR, ENABLE: 1);
continue;
}
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO, POWERDOWN == 0) {
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO_SET, POWERDOWN: 1);
continue;
}
break;
}
let (post_div, audio_div_msb, audio_div_lsb) = match post_divider {
PostDivider::U1 => (2, 0, 0),
PostDivider::U2 => (1, 0, 0),
PostDivider::U4 => (2, 1, 1),
PostDivider::U8 => (1, 1, 1),
PostDivider::U16 => (0, 1, 1),
};
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO_NUM, pll_num);
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO_DENOM, pll_denom);
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO, DIV_SELECT: div_select);
ral::modify_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO, POST_DIV_SELECT: post_div);
ral::modify_reg!(ral::ccm_analog, ccm_analog, MISC2, AUDIO_DIV_MSB: audio_div_msb, AUDIO_DIV_LSB: audio_div_lsb);
loop {
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO, ENABLE == 0) {
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO_SET, ENABLE: 1);
continue;
}
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO, POWERDOWN == 1) {
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO_CLR, POWERDOWN: 1);
continue;
}
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO, LOCK == 0) {
continue;
}
if ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO, BYPASS == 1) {
ral::write_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO_CLR, BYPASS: 1);
continue;
}
break;
}
}
pub fn frequency() -> u32 {
let ccm_analog = unsafe { ral::ccm_analog::CCM_ANALOG::instance() };
let div_select: u32 = ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO, DIV_SELECT);
let pll_num: u32 = ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO_NUM);
let pll_denom: u32 = ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO_DENOM);
let post_div_select: u32 = ral::read_reg!(ral::ccm_analog, ccm_analog, PLL_AUDIO_DENOM);
let (audio_div_msb, audio_div_lsb) = ral::read_reg!(
ral::ccm_analog,
ccm_analog,
MISC2,
AUDIO_DIV_MSB,
AUDIO_DIV_LSB
);
let post_div = match (post_div_select, audio_div_msb, audio_div_lsb) {
(2, 0, 0) => 1,
(1, 0, 0) => 2,
(2, 1, 1) => 4,
(1, 1, 1) => 8,
(0, 1, 1) => 16,
_ => panic!("Undefined match for post div to calculate pll4 clock rate"),
};
output_freq(div_select, pll_num, pll_denom) / post_div
}
}