esp_hal/ethernet/phy/
generic.rs1use core::task::Context;
6
7use crate::ethernet::{
8 mac::{Duplex, LinkState, Speed},
9 phy::{ANAR, ANLPAR, BMCR, BMSR, MdioBus, PHYIDR1, Phy, PhyError, an, bmcr, bmsr},
10};
11
12const RESET_POLL_LIMIT: u32 = 500_000; #[derive(Clone, Copy, Debug)]
22pub struct GenericPhy {
23 addr: Option<u8>,
25}
26
27impl GenericPhy {
28 pub const fn new(addr: u8) -> Self {
30 Self { addr: Some(addr) }
31 }
32
33 pub const fn new_auto() -> Self {
38 Self { addr: None }
39 }
40
41 fn discover<M: MdioBus>(mdio: &mut M) -> Option<u8> {
47 for _ in 0..3 {
48 for addr in 0..32_u8 {
49 let id = mdio.read(addr, PHYIDR1);
50 if id != 0x0000 && id != 0xFFFF {
51 debug!("phy found at addr {} - id: {:x}", addr, id);
52 return Some(addr);
53 }
54 }
55 }
56 None
57 }
58}
59
60impl Phy for GenericPhy {
61 fn address(&self) -> u8 {
62 self.addr
63 .expect("GenericPhy address not yet resolved — call init() first")
64 }
65
66 fn init<M: MdioBus>(&mut self, mdio: &mut M) -> Result<(), PhyError> {
67 if self.addr.is_none() {
69 self.addr = Some(Self::discover(mdio).ok_or(PhyError::NotFound)?);
70 }
71 let addr = self.addr.unwrap();
72
73 mdio.write(addr, BMCR, bmcr::RESET);
74
75 for _ in 0..RESET_POLL_LIMIT {
77 if mdio.read(addr, BMCR) & bmcr::RESET == 0 {
78 let adv =
80 an::BASE_10_HALF | an::BASE_10_FULL | an::BASE_100_HALF | an::BASE_100_FULL;
81 mdio.write(addr, ANAR, adv | 0x0001); let ctrl = mdio.read(addr, BMCR);
85 mdio.write(addr, BMCR, ctrl | bmcr::ANEN | bmcr::RESTART_AN);
86
87 return Ok(());
88 }
89 crate::rom::ets_delay_us(1);
90 }
91
92 Err(PhyError::Timeout)
93 }
94
95 fn poll_link<M: MdioBus>(&mut self, mdio: &mut M, cx: Option<&mut Context<'_>>) -> LinkState {
96 const LINK_STATE_DOWN: LinkState = LinkState {
97 up: false,
98 speed: Speed::_100M,
99 duplex: Duplex::Full,
100 };
101
102 if let Some(cx) = cx {
103 cx.waker().wake_by_ref();
104 }
105
106 let Some(addr) = self.addr else {
107 debug!("poll_link called before init");
108 return LINK_STATE_DOWN;
109 };
110
111 let _ = mdio.read(addr, BMSR);
114 let bmsr_val = mdio.read(addr, BMSR);
115
116 trace!("bmsr_val: {:x}", bmsr_val);
117
118 if bmsr_val & bmsr::LINK_STATUS == 0 {
119 return LINK_STATE_DOWN;
120 }
121
122 if bmsr_val & bmsr::AN_COMPLETE == 0 {
123 return LINK_STATE_DOWN;
124 }
125
126 let anlpar_val = mdio.read(addr, ANLPAR);
130 let speed = if anlpar_val & an::BASE_100_FULL != 0 || anlpar_val & an::BASE_100_HALF != 0 {
131 Speed::_100M
132 } else {
133 Speed::_10M
134 };
135 let duplex = if anlpar_val & an::BASE_10_FULL != 0 || anlpar_val & an::BASE_100_FULL != 0 {
136 Duplex::Full
137 } else {
138 Duplex::Half
139 };
140
141 LinkState {
142 up: true,
143 speed,
144 duplex,
145 }
146 }
147}