#![allow(dead_code)]
pub const BASE: usize = 0x3FF6_9800;
pub const DPORT_WIFI_CLK_EN_REG: usize = 0x3FF0_00CC;
pub const DPORT_WIFI_CLK_EMAC_EN: u32 = 1 << 14;
pub const IO_MUX_BASE: usize = 0x3FF4_9000;
pub const EX_CLKOUT_CONF: usize = 0x00;
pub const EX_OSCCLK_CONF: usize = 0x04;
pub const EX_CLK_CTRL: usize = 0x08;
pub const EX_PHYINF_CONF: usize = 0x0C;
pub const EX_PD_SEL: usize = 0x10;
pub mod clkout_conf {
pub const DIV_NUM_MASK: u32 = 0x0F;
pub const H_DIV_NUM_SHIFT: u32 = 4;
pub const H_DIV_NUM_MASK: u32 = 0x0F << 4;
pub const DLY_NUM_SHIFT: u32 = 8;
pub const DLY_NUM_MASK: u32 = 0x03 << 8;
}
pub mod oscclk_conf {
pub const DIV_NUM_10M_MASK: u32 = 0x3F;
pub const H_DIV_NUM_10M_SHIFT: u32 = 6;
pub const DIV_NUM_100M_SHIFT: u32 = 12;
pub const H_DIV_NUM_100M_SHIFT: u32 = 18;
pub const CLK_SEL: u32 = 1 << 24;
}
pub mod clk_ctrl {
pub const EXT_EN: u32 = 1 << 0;
pub const INT_EN: u32 = 1 << 1;
pub const RX_125_CLK_EN: u32 = 1 << 2;
pub const MII_CLK_TX_EN: u32 = 1 << 3;
pub const MII_CLK_RX_EN: u32 = 1 << 4;
pub const CLK_EN: u32 = 1 << 5;
}
pub mod phyinf_conf {
pub const PHY_INTF_SEL_SHIFT: u32 = 13;
pub const PHY_INTF_SEL_MASK: u32 = 0x07 << 13;
pub const PHY_INTF_MII: u32 = 0;
pub const PHY_INTF_RMII: u32 = 4;
pub const SBD_FLOWCTRL: u32 = 1 << 2;
pub const CORE_PHY_ADDR_SHIFT: u32 = 3;
pub const CORE_PHY_ADDR_MASK: u32 = 0x1F << 3;
}
pub mod pd_sel {
pub const RAM_PD_EN_MASK: u32 = 0x03;
}
#[inline(always)]
pub unsafe fn read(offset: usize) -> u32 {
core::ptr::read_volatile((BASE + offset) as *const u32)
}
#[inline(always)]
pub unsafe fn write(offset: usize, val: u32) {
core::ptr::write_volatile((BASE + offset) as *mut u32, val);
}
#[inline(always)]
pub unsafe fn set_bits(offset: usize, bits: u32) {
let val = read(offset);
write(offset, val | bits);
}
#[inline(always)]
pub unsafe fn clear_bits(offset: usize, bits: u32) {
let val = read(offset);
write(offset, val & !bits);
}
#[inline(always)]
pub fn enable_peripheral_clock() {
unsafe {
let cur = core::ptr::read_volatile(DPORT_WIFI_CLK_EN_REG as *const u32);
core::ptr::write_volatile(
DPORT_WIFI_CLK_EN_REG as *mut u32,
cur | DPORT_WIFI_CLK_EMAC_EN,
);
}
}
#[inline(always)]
pub fn enable_clocks() {
unsafe {
set_bits(
EX_CLK_CTRL,
clk_ctrl::MII_CLK_RX_EN | clk_ctrl::MII_CLK_TX_EN | clk_ctrl::CLK_EN,
);
}
}
#[inline(always)]
pub fn set_rmii_mode() {
unsafe {
let cur = read(EX_PHYINF_CONF);
let new_val = (cur & !phyinf_conf::PHY_INTF_SEL_MASK)
| (phyinf_conf::PHY_INTF_RMII << phyinf_conf::PHY_INTF_SEL_SHIFT);
write(EX_PHYINF_CONF, new_val);
}
}
#[inline(always)]
pub fn set_rmii_clock_external() {
unsafe {
let ctrl = read(EX_CLK_CTRL);
write(EX_CLK_CTRL, (ctrl | clk_ctrl::EXT_EN) & !clk_ctrl::INT_EN);
let osc = read(EX_OSCCLK_CONF);
write(EX_OSCCLK_CONF, osc | oscclk_conf::CLK_SEL);
}
}
#[inline(always)]
pub fn set_rmii_clock_internal() {
unsafe {
let ctrl = read(EX_CLK_CTRL);
write(EX_CLK_CTRL, (ctrl | clk_ctrl::INT_EN) & !clk_ctrl::EXT_EN);
let osc = read(EX_OSCCLK_CONF);
write(EX_OSCCLK_CONF, osc & !oscclk_conf::CLK_SEL);
let clkout = read(EX_CLKOUT_CONF);
write(
EX_CLKOUT_CONF,
clkout & !(clkout_conf::DIV_NUM_MASK | clkout_conf::H_DIV_NUM_MASK),
);
}
}
#[inline(always)]
pub fn power_up_ram() {
unsafe {
let cur = read(EX_PD_SEL);
write(EX_PD_SEL, cur & !pd_sel::RAM_PD_EN_MASK);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn base_address() {
assert_eq!(BASE, 0x3FF6_9800);
}
#[test]
fn register_offsets_within_block() {
let offsets = [
EX_CLKOUT_CONF,
EX_OSCCLK_CONF,
EX_CLK_CTRL,
EX_PHYINF_CONF,
EX_PD_SEL,
];
for off in offsets {
assert!(off < 0x100, "offset {:#x} exceeds EXT block size", off);
}
}
#[test]
fn clk_ctrl_bits_no_overlap() {
let bits = [
clk_ctrl::EXT_EN,
clk_ctrl::INT_EN,
clk_ctrl::RX_125_CLK_EN,
clk_ctrl::MII_CLK_TX_EN,
clk_ctrl::MII_CLK_RX_EN,
clk_ctrl::CLK_EN,
];
for i in 0..bits.len() {
for j in (i + 1)..bits.len() {
assert_eq!(
bits[i] & bits[j],
0,
"clk_ctrl bits {:#x} and {:#x} overlap",
bits[i],
bits[j]
);
}
}
}
#[test]
fn phyinf_rmii_value_fits_mask() {
let rmii_val = phyinf_conf::PHY_INTF_RMII << phyinf_conf::PHY_INTF_SEL_SHIFT;
assert_eq!(rmii_val & phyinf_conf::PHY_INTF_SEL_MASK, rmii_val);
}
#[test]
fn phyinf_mii_value_is_zero() {
assert_eq!(phyinf_conf::PHY_INTF_MII, 0);
}
#[test]
fn dport_emac_clock_bit_position() {
assert_eq!(DPORT_WIFI_CLK_EMAC_EN, 1 << 14);
assert_eq!(DPORT_WIFI_CLK_EMAC_EN, 0x4000);
}
#[test]
fn base_addresses_in_order() {
assert!(super::super::dma::BASE < BASE);
assert!(BASE < super::super::mac::BASE);
}
}