#![no_std]
#![no_main]
use core::fmt::{self, Write};
use core::hint::spin_loop;
use core::ptr::{read_volatile, write_volatile};
use core::sync::atomic::{fence, Ordering};
use panic_halt as _;
use riscv_rt::entry;
use esp_p4_eth::{
configure_clock_ext_in, configure_rmii_pins, pins, release_waveshare_phy_reset, RefClockPin,
};
const UART0_BASE: usize = 0x500C_A000;
const UART_FIFO_REG: *mut u32 = UART0_BASE as *mut u32;
const UART_STATUS_REG: *const u32 = (UART0_BASE + 0x1C) as *const u32;
const UART_TXFIFO_CNT_SHIFT: u32 = 16;
const UART_TXFIFO_CNT_MASK: u32 = 0xFF << UART_TXFIFO_CNT_SHIFT;
const UART_TXFIFO_CAPACITY: u32 = 128;
struct Uart0;
impl Uart0 {
fn write_byte(&mut self, byte: u8) {
while txfifo_count() >= UART_TXFIFO_CAPACITY {
spin_loop();
}
unsafe {
write_volatile(UART_FIFO_REG, byte as u32);
}
}
}
impl Write for Uart0 {
fn write_str(&mut self, s: &str) -> fmt::Result {
for byte in s.bytes() {
if byte == b'\n' {
self.write_byte(b'\r');
}
self.write_byte(byte);
}
Ok(())
}
}
fn txfifo_count() -> u32 {
let status = unsafe { read_volatile(UART_STATUS_REG) };
(status & UART_TXFIFO_CNT_MASK) >> UART_TXFIFO_CNT_SHIFT
}
fn delay_cycles(spins: usize) {
for _ in 0..spins {
spin_loop();
}
}
#[inline(never)]
fn safe_read32(addr: usize) -> u32 {
fence(Ordering::SeqCst);
delay_cycles(64);
let value = unsafe { read_volatile(addr as *const u32) };
fence(Ordering::SeqCst);
delay_cycles(64);
value
}
fn flush_uart() {
while txfifo_count() != 0 {
spin_loop();
}
delay_cycles(50_000);
}
fn dump_named(uart: &mut Uart0, name: &str, addr: usize) {
let _ = writeln!(uart, " read {:18} @ 0x{:08X} ...", name, addr);
flush_uart();
let value = safe_read32(addr);
let _ = writeln!(uart, " {:18} = 0x{:08X}", name, value);
flush_uart();
}
fn dump_clock_section(uart: &mut Uart0, label: &str) {
let _ = writeln!(uart, "--- clock-tree dump ({}) ---", label);
flush_uart();
dump_named(uart, "SOC_CLK_CTRL1", 0x500E_6018);
dump_named(uart, "REF_CLK_CTRL0", 0x500E_6024);
dump_named(uart, "REF_CLK_CTRL1", 0x500E_6028);
dump_named(uart, "PERI_CLK_CTRL00", 0x500E_6030);
dump_named(uart, "PERI_CLK_CTRL01", 0x500E_6034);
dump_named(uart, "LP_HP_CLK_CTRL", 0x5011_1040);
dump_named(uart, "LP_EMAC_RST_CTRL", 0x5011_104C);
dump_named(uart, "SYS_GMAC_CTRL0", 0x500E_514C);
}
fn dump_emac_section(uart: &mut Uart0, label: &str) {
let _ = writeln!(uart, "--- EMAC core dump ({}) ---", label);
flush_uart();
dump_named(uart, "MAC_CONFIG", 0x5009_8000);
dump_named(uart, "MAC_FRAME_FILTER", 0x5009_8004);
dump_named(uart, "MII_ADDR", 0x5009_8010);
dump_named(uart, "MII_DATA", 0x5009_8014);
dump_named(uart, "MAC_VERSION", 0x5009_8020);
dump_named(uart, "DMA_BUS_MODE", 0x5009_9000);
dump_named(uart, "DMA_OP_MODE", 0x5009_9018);
dump_named(uart, "DMA_STATUS", 0x5009_9014);
}
#[entry]
fn main() -> ! {
let mut uart = Uart0;
let _ = writeln!(uart, "\r\n=== clk_dump alive ===");
flush_uart();
dump_clock_section(&mut uart, "before init");
let _ = writeln!(uart, "release_waveshare_phy_reset()");
flush_uart();
release_waveshare_phy_reset();
delay_cycles(3_000_000);
let _ = writeln!(uart, "configure_rmii_pins()");
flush_uart();
configure_rmii_pins();
let _ = writeln!(uart, "configure_mdio_pins()");
flush_uart();
pins::configure_mdio_pins();
let _ = writeln!(uart, "configure_clock_ext_in(Gpio50)");
flush_uart();
configure_clock_ext_in(RefClockPin::Gpio50);
dump_clock_section(&mut uart, "after configure_clock_ext_in");
dump_emac_section(&mut uart, "after configure_clock_ext_in");
let _ = writeln!(uart, "=== clk_dump done ===");
flush_uart();
loop {
spin_loop();
}
}