Skip to main content

esp_p4_eth/
lib.rs

1//! `#![no_std]` async Ethernet MAC driver for ESP32-P4 RMII designs,
2//! plug-in compatible with [`embassy-net`](https://crates.io/crates/embassy-net).
3//!
4//! See the crate-level `README.md` for the project status, hardware support
5//! matrix, quick-start instructions, and the mandatory build invariants
6//! (linker `RAM_DMA` section below `0x4FF80000`, workspace `opt-level = 1`).
7//!
8//! # Architecture
9//!
10//! The crate is split into a few narrow layers:
11//!
12//! - [`regs`] exposes raw MMIO register addresses and bit fields.
13//! - [`clock`] and [`pins`] program the P4 clock tree and IO_MUX for RMII.
14//! - [`board`] groups pin maps, reference-clock pad, and PHY MDIO address
15//!   into a single [`BoardConfig`]; [`BoardConfig::WAVESHARE_P4_ETH`] is the
16//!   built-in default for the Waveshare ESP32-P4-ETH dev board.
17//! - [`descriptors`] owns DMA descriptor/ring state and packet buffers.
18//! - [`dma`] handles cache synchronization, DMA reset/init, and interrupt status.
19//! - [`phy`] provides Clause 22 MDIO access plus an IP101-oriented PHY model.
20//! - [`Ethernet`] composes all of the above into a device that can be driven
21//!   directly or through [`ch`] / `embassy-net-driver-channel`.
22//!
23//! # Bring-up
24//!
25//! Two constructor families are provided:
26//!
27//! - [`new_from_static_resources`] / [`Ethernet::try_new`] — Waveshare
28//!   ESP32-P4-ETH default pin map (back-compat, zero-config).
29//! - [`eth::new_from_static_resources_with_board`] /
30//!   [`Ethernet::try_new_with_board`] — accept an explicit [`BoardConfig`]
31//!   for any other RMII layout.
32//!
33//! # ESP32-P4 specifics
34//!
35//! ESP32-P4 needs a few hardware-specific invariants that are easy to miss:
36//!
37//! - DMA descriptors and packet buffers must stay cache-line aligned. This crate
38//!   uses 128-byte alignment to match the P4 L2 cache line.
39//! - DMA-shared statics must live below `0x4FF80000` — the upper 256 KB of HP
40//!   SRAM is the L2 cache backing region and is not accessible to bus masters.
41//! - CPU writes must be synchronized to memory before DMA sees them, and DMA
42//!   writes must be invalidated out of cache before the CPU reads them. The
43//!   cache sync helpers in [`dma`] handle that requirement.
44//! - `DMA_OP_MODE.RSF` (Receive Store and Forward) **must stay 0** — the P4
45//!   RX FIFO is too small to hold a full Ethernet frame and `RSF = 1` silently
46//!   drops everything larger than the FIFO. This crate uses cut-through
47//!   receive by default; do not re-enable RSF.
48//! - RMII pin routing is not implicit. The bring-up path applies the supplied
49//!   [`BoardConfig`] through [`pins::configure_rmii_pin_set`],
50//!   [`pins::configure_mdio_pin_set`], and [`clock::configure_clock_ext_in`].
51//!
52//! The examples use [`StaticDmaResources`] as the preferred safe way to own the
53//! backing DMA memory in `'static` storage; `#[link_section = ".dma_bss"]`
54//! places that storage inside the linker's `RAM_DMA` region.
55#![no_std]
56
57#[cfg(test)]
58extern crate std;
59
60pub use embassy_net_driver_channel as ch;
61
62pub mod board;
63pub mod eth;
64pub use board::BoardConfig;
65pub mod clic;
66pub mod systimer;
67#[cfg(all(target_arch = "riscv32", feature = "p4-time-driver"))]
68pub mod time_driver;
69#[cfg(all(target_arch = "riscv32", feature = "p4-time-driver-irq"))]
70pub mod time_driver_irq;
71pub mod time_driver_irq_logic;
72
73pub use eth::{clock, descriptors, dma, phy, pins, regs};
74#[cfg(target_arch = "riscv32")]
75pub use eth::{ethernet_task, wake_rx_task, wake_tx_task};
76pub use eth::{
77    new, new_from_static_resources, Device, Duplex, Ethernet, MacError, Runner, CHANNEL_RX_COUNT,
78    CHANNEL_TX_COUNT, MTU,
79};
80
81pub use clock::{
82    configure_clock_ext_in, configure_clock_mpll_out, configure_speed_divider,
83    disable_emac_clock_tree,
84};
85pub use clock::{MpllClockOutPin, RefClockPin};
86pub use descriptors::{
87    zeroed_rx_descriptors, zeroed_tx_descriptors, BufferTooLarge, DescriptorError, DmaBuffers,
88    OwnedBy, RDes, RDesRing, RxRingStats, StaticDmaResources, TDes, TDesRing, TxRingStats,
89    BUF_SIZE, MIN_RX_FRAME_SIZE, RX_DESC_COUNT, TX_DESC_COUNT,
90};
91
92/// Diagnostic counters and last-frame snapshots exposed for observability and
93/// debugging. **The contents of this module are intentionally not part of
94/// the crate's stable API** — atomics may be added, removed, or renamed in
95/// any release. Build dashboards on top of them at your own risk and pin a
96/// specific `esp-p4-eth` version if you do.
97pub mod diag {
98    #[cfg(target_arch = "riscv32")]
99    pub use crate::descriptors::{
100        CPU_DESC0_SNAPSHOT, TX_LAST_BUF_ADDR, TX_LAST_DESC_ADDR, TX_LAST_TDES0, TX_LAST_TDES1,
101    };
102    pub use crate::descriptors::{
103        RX_ERROR_FRAMES_TOTAL, RX_LARGE_FRAMES, RX_LAST_FRAME_LEN, RX_LAST_RDES0,
104        RX_OVERSIZED_FRAMES_TOTAL, RX_RUNT_FRAMES_TOTAL,
105    };
106    pub use crate::dma::{CACHE_INV_CALLS, CACHE_INV_TICKS, CACHE_WB_CALLS, CACHE_WB_TICKS};
107    #[cfg(target_arch = "riscv32")]
108    pub use crate::dma::{LAST_INVALIDATE_RC, LAST_WRITEBACK_RC};
109    pub use crate::eth::RX_DESC_STRIDE;
110    #[cfg(target_arch = "riscv32")]
111    pub use crate::eth::{
112        RX_ARP, RX_BUF_REQUESTED, RX_DESC_BASE, RX_DHCP_FRAMES, RX_FRAMES, RX_ICMP, RX_IPV4,
113        RX_LAST_DHCP_FRAME, RX_LAST_DST_MAC_HI, RX_LAST_ETHERTYPE, RX_LAST_LARGE_FRAME,
114        RX_LAST_LARGE_FRAME_LEN, TX_BUF_REQUESTED, TX_FRAMES, TX_LAST_DST_MAC_HI,
115        TX_LAST_ETHERTYPE, TX_LAST_LEN, TX_LAST_SRC_MAC_HI,
116    };
117}
118pub use dma::{Dma, DmaError, DmaInterruptStatus};
119pub use phy::{
120    anlpar, bmcr, bmsr, mdio_read, mdio_write, Ip101, LinkState, Phy, PhyError, Speed, ANAR,
121    ANLPAR, BMCR, BMSR, PHYIDR1, PHYIDR2,
122};
123pub use pins::{
124    configure_rmii_pins, release_phy_reset_pin, release_waveshare_phy_reset, PhyResetPinConfig,
125};