esp_emac/regs/mac.rs
1// SPDX-License-Identifier: GPL-2.0-or-later OR Apache-2.0
2// Copyright (c) Viacheslav Bocharov <v@baodeep.com> and JetHome (r)
3
4//! MAC core register definitions.
5//!
6//! The MAC core handles frame transmission and reception per IEEE 802.3.
7//! Base address: `0x3FF6_A000`.
8
9#![allow(dead_code)]
10
11// =============================================================================
12// Base Address
13// =============================================================================
14
15/// MAC register block base address (ESP32).
16pub const BASE: usize = 0x3FF6_A000;
17
18// =============================================================================
19// Register Offsets
20// =============================================================================
21
22/// GMAC Configuration Register.
23pub const GMACCONFIG: usize = 0x00;
24/// GMAC Frame Filter Register.
25pub const GMACFF: usize = 0x04;
26/// GMAC Hash Table High Register.
27pub const GMACHASTH: usize = 0x08;
28/// GMAC Hash Table Low Register.
29pub const GMACHASTL: usize = 0x0C;
30/// GMAC MII Address Register.
31pub const GMACMIIADDR: usize = 0x10;
32/// GMAC MII Data Register.
33pub const GMACMIIDATA: usize = 0x14;
34/// GMAC Flow Control Register.
35pub const GMACFC: usize = 0x18;
36/// GMAC VLAN Tag Register.
37pub const GMACVLAN: usize = 0x1C;
38/// GMAC Debug Register (read-only).
39pub const GMACDEBUG: usize = 0x24;
40/// GMAC Interrupt Status Register.
41pub const GMACINTS: usize = 0x38;
42/// GMAC Interrupt Mask Register.
43pub const GMACINTMASK: usize = 0x3C;
44/// GMAC Address 0 High Register (upper 16 bits of primary MAC).
45pub const GMACADDR0H: usize = 0x40;
46/// GMAC Address 0 Low Register (lower 32 bits of primary MAC).
47pub const GMACADDR0L: usize = 0x44;
48
49// =============================================================================
50// GMACCONFIG bits
51// =============================================================================
52
53/// Bit-field constants for the GMAC Configuration Register.
54pub mod config {
55 /// Receiver Enable.
56 pub const RX_ENABLE: u32 = 1 << 2;
57 /// Transmitter Enable.
58 pub const TX_ENABLE: u32 = 1 << 3;
59 /// Automatic Pad/CRC Stripping.
60 pub const AUTO_PAD_CRC_STRIP: u32 = 1 << 7;
61 /// Link Up/Down (ESP32-specific).
62 pub const LINK_UP: u32 = 1 << 8;
63 /// Retry Disable.
64 pub const RETRY_DISABLE: u32 = 1 << 9;
65 /// Checksum Offload (IPC).
66 pub const CHECKSUM_OFFLOAD: u32 = 1 << 10;
67 /// Duplex Mode: 1 = full duplex.
68 pub const DUPLEX_FULL: u32 = 1 << 11;
69 /// Speed: 1 = 100 Mbps, 0 = 10 Mbps.
70 pub const SPEED_100: u32 = 1 << 14;
71 /// Port Select: must be 1 for MII/RMII.
72 pub const PORT_SELECT: u32 = 1 << 15;
73 /// Inter-Frame Gap shift (3-bit field at bits 19:17).
74 pub const IFG_SHIFT: u32 = 17;
75 /// Inter-Frame Gap mask.
76 pub const IFG_MASK: u32 = 0x07 << 17;
77 /// Jumbo Frame Enable.
78 pub const JUMBO_FRAME: u32 = 1 << 20;
79 /// Frame Burst Enable.
80 pub const FRAME_BURST: u32 = 1 << 21;
81 /// Jabber Disable.
82 pub const JABBER_DISABLE: u32 = 1 << 22;
83 /// Watchdog Disable.
84 pub const WATCHDOG_DISABLE: u32 = 1 << 23;
85}
86
87// =============================================================================
88// GMACFF bits
89// =============================================================================
90
91/// Bit-field constants for the GMAC Frame Filter Register.
92pub mod frame_filter {
93 /// Promiscuous Mode.
94 pub const PROMISCUOUS: u32 = 1 << 0;
95 /// Hash Unicast.
96 pub const HASH_UNICAST: u32 = 1 << 1;
97 /// Hash Multicast.
98 pub const HASH_MULTICAST: u32 = 1 << 2;
99 /// DA Inverse Filtering.
100 pub const DA_INVERSE: u32 = 1 << 3;
101 /// Pass All Multicast.
102 pub const PASS_ALL_MULTICAST: u32 = 1 << 4;
103 /// Disable Broadcast Frames.
104 pub const DISABLE_BROADCAST: u32 = 1 << 5;
105 /// Receive All.
106 pub const RECEIVE_ALL: u32 = 1 << 31;
107}
108
109// =============================================================================
110// GMACMIIADDR bits
111// =============================================================================
112
113/// Bit-field constants for the GMAC MII Address Register.
114///
115/// Also used by `mdio.rs` (which has its own private copies).
116/// This module provides the complete reference.
117pub mod miiaddr {
118 /// Physical Layer Address shift (5-bit field at bits 15:11).
119 pub const PA_SHIFT: u32 = 11;
120 /// Physical Layer Address mask.
121 pub const PA_MASK: u32 = 0x1F << 11;
122 /// MII Register Address shift (5-bit field at bits 10:6).
123 pub const GR_SHIFT: u32 = 6;
124 /// MII Register Address mask.
125 pub const GR_MASK: u32 = 0x1F << 6;
126 /// CSR Clock Range shift (4-bit field at bits 5:2).
127 pub const CR_SHIFT: u32 = 2;
128 /// CSR Clock Range mask.
129 pub const CR_MASK: u32 = 0x0F << 2;
130 /// MII Write.
131 pub const GW: u32 = 1 << 1;
132 /// MII Busy.
133 pub const GB: u32 = 1 << 0;
134}
135
136// =============================================================================
137// GMACFC bits
138// =============================================================================
139
140/// Bit-field constants for the GMAC Flow Control Register.
141pub mod flow_control {
142 /// Flow Control Busy / Backpressure Activate.
143 pub const FCB_BPA: u32 = 1 << 0;
144 /// Transmit Flow Control Enable.
145 pub const TX_ENABLE: u32 = 1 << 1;
146 /// Receive Flow Control Enable.
147 pub const RX_ENABLE: u32 = 1 << 2;
148 /// Unicast PAUSE Frame Detect.
149 pub const UNICAST_PAUSE: u32 = 1 << 3;
150 /// PAUSE Low Threshold shift (2-bit field at bits 5:4).
151 pub const PLT_SHIFT: u32 = 4;
152 /// PAUSE Low Threshold mask.
153 pub const PLT_MASK: u32 = 0x03 << 4;
154 /// Zero-Quanta PAUSE Disable.
155 pub const ZERO_QUANTA_DISABLE: u32 = 1 << 7;
156 /// PAUSE Time shift (16-bit field at bits 31:16).
157 pub const PT_SHIFT: u32 = 16;
158 /// PAUSE Time mask.
159 pub const PT_MASK: u32 = 0xFFFF << 16;
160}
161
162// =============================================================================
163// Register access helpers
164// =============================================================================
165
166/// Read a MAC register at `offset` from BASE.
167///
168/// # Safety
169/// Caller must ensure the EMAC peripheral clock is enabled and
170/// `offset` is a valid register offset within this block.
171#[inline(always)]
172pub unsafe fn read(offset: usize) -> u32 {
173 // SAFETY: caller guarantees address validity.
174 core::ptr::read_volatile((BASE + offset) as *const u32)
175}
176
177/// Write a MAC register at `offset` from BASE.
178///
179/// # Safety
180/// Caller must ensure the EMAC peripheral clock is enabled and
181/// `offset` is a valid register offset within this block.
182#[inline(always)]
183pub unsafe fn write(offset: usize, val: u32) {
184 // SAFETY: caller guarantees address validity.
185 core::ptr::write_volatile((BASE + offset) as *mut u32, val);
186}
187
188/// Read-modify-write: set bits in a MAC register.
189///
190/// # Safety
191/// Same requirements as [`read`] and [`write`].
192#[inline(always)]
193pub unsafe fn set_bits(offset: usize, bits: u32) {
194 let val = read(offset);
195 write(offset, val | bits);
196}
197
198/// Read-modify-write: clear bits in a MAC register.
199///
200/// # Safety
201/// Same requirements as [`read`] and [`write`].
202#[inline(always)]
203pub unsafe fn clear_bits(offset: usize, bits: u32) {
204 let val = read(offset);
205 write(offset, val & !bits);
206}
207
208// =============================================================================
209// Composite operations (formerly ph_esp32_mac::unsafe_registers::MacRegs)
210// =============================================================================
211
212/// Read the GMAC Configuration register.
213#[inline(always)]
214pub fn config() -> u32 {
215 // SAFETY: GMACCONFIG is a known-valid 32-bit memory-mapped register.
216 unsafe { read(GMACCONFIG) }
217}
218
219/// Write the GMAC Configuration register.
220#[inline(always)]
221pub fn set_config(val: u32) {
222 // SAFETY: GMACCONFIG is a known-valid 32-bit memory-mapped register.
223 unsafe { write(GMACCONFIG, val) }
224}
225
226/// Write the GMAC Frame Filter register.
227#[inline(always)]
228pub fn set_frame_filter(val: u32) {
229 // SAFETY: GMACFF is a known-valid 32-bit memory-mapped register.
230 unsafe { write(GMACFF, val) }
231}
232
233/// Write the 64-bit hash filter table (low → `GMACHASTL`, high → `GMACHASTH`).
234#[inline(always)]
235pub fn set_hash_table(value: u64) {
236 // SAFETY: both registers are known-valid 32-bit memory-mapped registers.
237 unsafe {
238 write(GMACHASTL, value as u32);
239 write(GMACHASTH, (value >> 32) as u32);
240 }
241}
242
243/// Apply the 100 Mbps / 10 Mbps speed setting (RMW on `GMACCONFIG.FES`).
244#[inline(always)]
245pub fn set_speed_100mbps(is_100: bool) {
246 // SAFETY: GMACCONFIG is a known-valid 32-bit memory-mapped register.
247 unsafe {
248 if is_100 {
249 set_bits(GMACCONFIG, config::SPEED_100);
250 } else {
251 clear_bits(GMACCONFIG, config::SPEED_100);
252 }
253 }
254}
255
256/// Apply the full / half duplex setting (RMW on `GMACCONFIG.DM`).
257#[inline(always)]
258pub fn set_duplex_full(full: bool) {
259 // SAFETY: GMACCONFIG is a known-valid 32-bit memory-mapped register.
260 unsafe {
261 if full {
262 set_bits(GMACCONFIG, config::DUPLEX_FULL);
263 } else {
264 clear_bits(GMACCONFIG, config::DUPLEX_FULL);
265 }
266 }
267}
268
269/// Programme the primary MAC address into ADDR0H / ADDR0L (with AE bit).
270///
271/// The Synopsys DesignWare GMAC core latches the filter address on the
272/// write to **ADDR0L** (the low half). Therefore the high half (with the
273/// `AE` bit) MUST be written first, then the low half. Writing in the
274/// opposite order leaves the internal filter latched with the stale
275/// reset/efuse value while register read-back happily shows the new
276/// address — and unicast RX dies silently.
277pub fn set_mac_address(addr: &[u8; 6]) {
278 let high = (addr[4] as u32) | ((addr[5] as u32) << 8) | (1u32 << 31);
279 let low = (addr[0] as u32)
280 | ((addr[1] as u32) << 8)
281 | ((addr[2] as u32) << 16)
282 | ((addr[3] as u32) << 24);
283 // SAFETY: ADDR0H/ADDR0L are valid 32-bit MAC registers; caller has
284 // already enabled the EMAC peripheral clock by the time `init()`
285 // reaches this step.
286 unsafe {
287 write(GMACADDR0H, high);
288 write(GMACADDR0L, low);
289 }
290}
291
292// =============================================================================
293// Tests
294// =============================================================================
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299
300 #[test]
301 fn base_address() {
302 assert_eq!(BASE, 0x3FF6_A000);
303 }
304
305 #[test]
306 fn register_offsets_within_block() {
307 // MAC register block is 0x1000 (4 KiB)
308 let offsets = [
309 GMACCONFIG,
310 GMACFF,
311 GMACHASTH,
312 GMACHASTL,
313 GMACMIIADDR,
314 GMACMIIDATA,
315 GMACFC,
316 GMACVLAN,
317 GMACDEBUG,
318 GMACINTS,
319 GMACINTMASK,
320 GMACADDR0H,
321 GMACADDR0L,
322 ];
323 for off in offsets {
324 assert!(off < 0x1000, "offset {:#x} exceeds MAC block size", off);
325 }
326 }
327
328 #[test]
329 fn config_bits_no_overlap() {
330 let bits = [
331 config::RX_ENABLE,
332 config::TX_ENABLE,
333 config::RETRY_DISABLE,
334 config::CHECKSUM_OFFLOAD,
335 config::DUPLEX_FULL,
336 config::SPEED_100,
337 config::PORT_SELECT,
338 config::JUMBO_FRAME,
339 config::FRAME_BURST,
340 config::JABBER_DISABLE,
341 config::WATCHDOG_DISABLE,
342 config::LINK_UP,
343 config::AUTO_PAD_CRC_STRIP,
344 ];
345 for i in 0..bits.len() {
346 for j in (i + 1)..bits.len() {
347 assert_eq!(
348 bits[i] & bits[j],
349 0,
350 "config bits {:#x} and {:#x} overlap",
351 bits[i],
352 bits[j]
353 );
354 }
355 }
356 }
357
358 #[test]
359 fn miiaddr_fields_no_overlap() {
360 // Single-bit fields
361 assert_eq!(miiaddr::GB & miiaddr::GW, 0);
362 // Mask fields should not overlap each other
363 assert_eq!(miiaddr::CR_MASK & miiaddr::GR_MASK, 0);
364 assert_eq!(miiaddr::GR_MASK & miiaddr::PA_MASK, 0);
365 assert_eq!(miiaddr::CR_MASK & miiaddr::PA_MASK, 0);
366 }
367
368 #[test]
369 fn flow_control_bits_no_overlap() {
370 let bits = [
371 flow_control::FCB_BPA,
372 flow_control::TX_ENABLE,
373 flow_control::RX_ENABLE,
374 flow_control::UNICAST_PAUSE,
375 flow_control::ZERO_QUANTA_DISABLE,
376 ];
377 for i in 0..bits.len() {
378 for j in (i + 1)..bits.len() {
379 assert_eq!(
380 bits[i] & bits[j],
381 0,
382 "flow_control bits {:#x} and {:#x} overlap",
383 bits[i],
384 bits[j]
385 );
386 }
387 }
388 }
389
390 #[test]
391 fn frame_filter_bits_no_overlap() {
392 let bits = [
393 frame_filter::PROMISCUOUS,
394 frame_filter::HASH_UNICAST,
395 frame_filter::HASH_MULTICAST,
396 frame_filter::DA_INVERSE,
397 frame_filter::PASS_ALL_MULTICAST,
398 frame_filter::DISABLE_BROADCAST,
399 frame_filter::RECEIVE_ALL,
400 ];
401 for i in 0..bits.len() {
402 for j in (i + 1)..bits.len() {
403 assert_eq!(
404 bits[i] & bits[j],
405 0,
406 "frame_filter bits {:#x} and {:#x} overlap",
407 bits[i],
408 bits[j]
409 );
410 }
411 }
412 }
413}