use super::{
DPORT_WIFI_CLK_EMAC_EN, DPORT_WIFI_CLK_EN_REG, EXT_BASE, IO_MUX_BASE, IO_MUX_FUN_IE,
IO_MUX_GPIO0_FUNC_EMAC_TX_CLK, IO_MUX_GPIO0_OFFSET, IO_MUX_MCU_SEL_MASK, IO_MUX_MCU_SEL_SHIFT,
read_reg, reg_ro, reg_rw, write_reg,
};
pub const EX_CLKOUT_CONF_OFFSET: usize = 0x00;
pub const EX_OSCCLK_CONF_OFFSET: usize = 0x04;
pub const EX_CLK_CTRL_OFFSET: usize = 0x08;
pub const EX_PHYINF_CONF_OFFSET: usize = 0x0C;
pub const EX_PD_SEL_OFFSET: usize = 0x10;
pub const EX_DATE_OFFSET: usize = 0xFC;
pub const EX_RAM_PD_OFFSET: usize = EX_PD_SEL_OFFSET;
pub const EX_CLKOUT_DIV_NUM_MASK: u32 = 0x0F;
pub const EX_CLKOUT_H_DIV_NUM_SHIFT: u32 = 4;
pub const EX_CLKOUT_H_DIV_NUM_MASK: u32 = 0xF0;
pub const EX_CLKOUT_DLY_NUM_SHIFT: u32 = 8;
pub const EX_CLKOUT_DLY_NUM_MASK: u32 = 0x300;
pub const EX_OSCCLK_DIV_NUM_10M_MASK: u32 = 0x3F;
pub const EX_OSCCLK_H_DIV_NUM_10M_SHIFT: u32 = 6;
pub const EX_OSCCLK_DIV_NUM_100M_SHIFT: u32 = 12;
pub const EX_OSCCLK_H_DIV_NUM_100M_SHIFT: u32 = 18;
pub const EX_OSCCLK_CLK_SEL: u32 = 1 << 24;
pub const EX_CLK_EXT_EN: u32 = 1 << 0;
pub const EX_CLK_INT_EN: u32 = 1 << 1;
pub const EX_CLK_RX_125_CLK_EN: u32 = 1 << 2;
pub const EX_CLK_MII_CLK_TX_EN: u32 = 1 << 3;
pub const EX_CLK_MII_CLK_RX_EN: u32 = 1 << 4;
pub const EX_CLK_EN: u32 = 1 << 5;
pub const EX_PHYINF_INT_REVMII_RX_CLK_SEL: u32 = 1 << 0;
pub const EX_PHYINF_EXT_REVMII_RX_CLK_SEL: u32 = 1 << 1;
pub const EX_PHYINF_SBD_FLOWCTRL: u32 = 1 << 2;
pub const EX_PHYINF_CORE_PHY_ADDR_SHIFT: u32 = 3;
pub const EX_PHYINF_CORE_PHY_ADDR_MASK: u32 = 0x1F << 3;
pub const EX_PHYINF_REVMII_PHY_ADDR_SHIFT: u32 = 8;
pub const EX_PHYINF_REVMII_PHY_ADDR_MASK: u32 = 0x1F << 8;
pub const EX_PHYINF_PHY_INTF_SEL_SHIFT: u32 = 13;
pub const EX_PHYINF_PHY_INTF_SEL_MASK: u32 = 0x7 << 13;
pub const EX_PHYINF_PHY_INTF_MII: u32 = 0;
pub const EX_PHYINF_PHY_INTF_RMII: u32 = 4;
pub const EX_PD_SEL_RAM_PD_EN_MASK: u32 = 0x03;
pub struct ExtRegs;
impl ExtRegs {
#[inline(always)]
pub const fn base() -> usize {
EXT_BASE
}
reg_rw!(
osc_clk_conf,
set_osc_clk_conf,
EXT_BASE,
EX_OSCCLK_CONF_OFFSET,
"Oscillator Clock Configuration"
);
reg_rw!(
clk_ctrl,
set_clk_ctrl,
EXT_BASE,
EX_CLK_CTRL_OFFSET,
"Clock Control register"
);
reg_rw!(
phy_inf_conf,
set_phy_inf_conf,
EXT_BASE,
EX_PHYINF_CONF_OFFSET,
"PHY Interface Configuration"
);
reg_rw!(
pd_sel,
set_pd_sel,
EXT_BASE,
EX_PD_SEL_OFFSET,
"Power Down Select register"
);
reg_rw!(
ram_pd,
set_ram_pd,
EXT_BASE,
EX_RAM_PD_OFFSET,
"RAM Power Down register"
);
reg_ro!(
date,
EXT_BASE,
EX_DATE_OFFSET,
"Date register (version info)"
);
#[inline(always)]
pub fn enable_peripheral_clock() {
unsafe {
let current = read_reg(DPORT_WIFI_CLK_EN_REG);
#[cfg(feature = "defmt")]
defmt::debug!(
"DPORT WIFI_CLK_EN before: {:#010x} (EMAC_EN bit 14 = {})",
current,
(current >> 14) & 1
);
let new_val = current | DPORT_WIFI_CLK_EMAC_EN;
write_reg(DPORT_WIFI_CLK_EN_REG, new_val);
#[cfg(feature = "defmt")]
{
let readback = read_reg(DPORT_WIFI_CLK_EN_REG);
defmt::debug!(
"DPORT WIFI_CLK_EN after: {:#010x} (EMAC_EN bit 14 = {})",
readback,
(readback >> 14) & 1
);
}
}
}
#[inline(always)]
pub fn enable_clocks() {
unsafe {
let ctrl = read_reg(EXT_BASE + EX_CLK_CTRL_OFFSET);
write_reg(
EXT_BASE + EX_CLK_CTRL_OFFSET,
ctrl | EX_CLK_MII_CLK_RX_EN | EX_CLK_MII_CLK_TX_EN | EX_CLK_EN,
);
}
}
#[inline(always)]
pub fn disable_clocks() {
unsafe {
let ctrl = read_reg(EXT_BASE + EX_CLK_CTRL_OFFSET);
write_reg(
EXT_BASE + EX_CLK_CTRL_OFFSET,
ctrl & !(EX_CLK_MII_CLK_RX_EN | EX_CLK_MII_CLK_TX_EN | EX_CLK_EN),
);
}
}
#[inline(always)]
pub fn set_rmii_mode() {
unsafe {
let conf = read_reg(EXT_BASE + EX_PHYINF_CONF_OFFSET);
let new_val = (conf & !EX_PHYINF_PHY_INTF_SEL_MASK)
| (EX_PHYINF_PHY_INTF_RMII << EX_PHYINF_PHY_INTF_SEL_SHIFT);
write_reg(EXT_BASE + EX_PHYINF_CONF_OFFSET, new_val);
#[cfg(feature = "defmt")]
defmt::debug!("EX_PHYINF_CONF set RMII mode: {:#010x}", new_val);
}
}
#[inline(always)]
pub fn set_mii_mode() {
unsafe {
let conf = read_reg(EXT_BASE + EX_PHYINF_CONF_OFFSET);
let new_val = conf & !EX_PHYINF_PHY_INTF_SEL_MASK;
write_reg(EXT_BASE + EX_PHYINF_CONF_OFFSET, new_val);
}
}
#[inline(always)]
pub fn set_rmii_clock_external() {
unsafe {
let ctrl = read_reg(EXT_BASE + EX_CLK_CTRL_OFFSET);
let new_ctrl = (ctrl | EX_CLK_EXT_EN) & !EX_CLK_INT_EN;
write_reg(EXT_BASE + EX_CLK_CTRL_OFFSET, new_ctrl);
let osc = read_reg(EXT_BASE + EX_OSCCLK_CONF_OFFSET);
let new_osc = osc | EX_OSCCLK_CLK_SEL; write_reg(EXT_BASE + EX_OSCCLK_CONF_OFFSET, new_osc);
#[cfg(feature = "defmt")]
defmt::debug!(
"RMII external clock: CLK_CTRL={:#010x} OSCCLK_CONF={:#010x}",
new_ctrl,
new_osc
);
}
}
#[inline(always)]
pub fn configure_gpio0_rmii_clock_input() {
unsafe {
let addr = IO_MUX_BASE + IO_MUX_GPIO0_OFFSET;
let current = read_reg(addr);
let new_val = (current & !IO_MUX_MCU_SEL_MASK)
| (IO_MUX_GPIO0_FUNC_EMAC_TX_CLK << IO_MUX_MCU_SEL_SHIFT)
| IO_MUX_FUN_IE;
#[cfg(feature = "defmt")]
defmt::debug!(
"GPIO0 IO_MUX: addr={:#010x} before={:#010x} after={:#010x}",
addr,
current,
new_val
);
write_reg(addr, new_val);
#[cfg(feature = "defmt")]
{
let readback = read_reg(addr);
defmt::debug!("GPIO0 IO_MUX readback: {:#010x}", readback);
}
}
}
#[inline(always)]
pub fn set_rmii_clock_internal() {
unsafe {
let ctrl = read_reg(EXT_BASE + EX_CLK_CTRL_OFFSET);
let new_ctrl = (ctrl | EX_CLK_INT_EN) & !EX_CLK_EXT_EN;
write_reg(EXT_BASE + EX_CLK_CTRL_OFFSET, new_ctrl);
let osc = read_reg(EXT_BASE + EX_OSCCLK_CONF_OFFSET);
let new_osc = osc & !EX_OSCCLK_CLK_SEL; write_reg(EXT_BASE + EX_OSCCLK_CONF_OFFSET, new_osc);
let clkout = read_reg(EXT_BASE + EX_CLKOUT_CONF_OFFSET);
let new_clkout = clkout & !(EX_CLKOUT_DIV_NUM_MASK | EX_CLKOUT_H_DIV_NUM_MASK);
write_reg(EXT_BASE + EX_CLKOUT_CONF_OFFSET, new_clkout);
#[cfg(feature = "defmt")]
defmt::debug!(
"RMII internal clock: CLK_CTRL={:#010x} OSCCLK_CONF={:#010x} CLKOUT_CONF={:#010x}",
new_ctrl,
new_osc,
new_clkout
);
}
}
#[inline(always)]
pub fn power_up_ram() {
Self::set_ram_pd(0);
}
#[inline(always)]
pub fn power_down_ram() {
Self::set_ram_pd(0xFFFF_FFFF);
}
}