1use core::task::Context;
6
7use crate::ethernet::{
8 mac::{Duplex, LinkState, Speed},
9 phy::{
10 ANAR,
11 ANLPAR,
12 BMCR,
13 BMSR,
14 EXSR,
15 GBCR,
16 GBSR,
17 MdioBus,
18 PHYIDR1,
19 PHYIDR2,
20 Phy,
21 PhyError,
22 an,
23 bmcr,
24 bmsr,
25 exsr,
26 gbcr,
27 gbsr,
28 },
29};
30
31const RESET_POLL_LIMIT: u32 = 500_000; const YT8531_ID: (u16, u16) = (0x4F51, 0xE91B);
36
37const REG_EXT_ADDR: u8 = 0x1E;
39const REG_EXT_DATA: u8 = 0x1F;
41
42const EXT_CHIP_CFG: u16 = 0xA001;
44const RXC_DLY_EN: u16 = 1 << 8;
45
46const EXT_RGMII_CFG1: u16 = 0xA003;
49const RGMII_TX_DLY_MASK: u16 = 0x00FF;
50const RGMII_DLY_2NS: u16 = 13;
51
52fn ext_read<M: MdioBus>(mdio: &mut M, addr: u8, ext: u16) -> u16 {
53 mdio.write(addr, REG_EXT_ADDR, ext);
54 mdio.read(addr, REG_EXT_DATA)
55}
56
57fn ext_write<M: MdioBus>(mdio: &mut M, addr: u8, ext: u16, val: u16) {
58 mdio.write(addr, REG_EXT_ADDR, ext);
59 mdio.write(addr, REG_EXT_DATA, val);
60}
61
62#[derive(Clone, Copy, Debug)]
73pub struct GenericPhy {
74 addr: Option<u8>,
76}
77
78impl GenericPhy {
79 pub const fn new(addr: u8) -> Self {
81 Self { addr: Some(addr) }
82 }
83
84 pub const fn new_auto() -> Self {
89 Self { addr: None }
90 }
91
92 fn discover<M: MdioBus>(mdio: &mut M) -> Option<u8> {
98 for _ in 0..3 {
99 for addr in 0..32_u8 {
100 let id = mdio.read(addr, PHYIDR1);
101 if id != 0x0000 && id != 0xFFFF {
102 debug!("phy found at addr {} - id: {:x}", addr, id);
103 return Some(addr);
104 }
105 }
106 }
107 None
108 }
109
110 fn limit_advertisement<M: MdioBus>(mdio: &mut M, addr: u8, max_speed: Speed) -> bool {
117 let mut changed = false;
118
119 if max_speed != Speed::_1000M {
120 let gbcr_val = mdio.read(addr, GBCR);
121 if gbcr_val != 0xFFFF {
122 let limited = gbcr_val & !(gbcr::ADV_1000_FULL | gbcr::ADV_1000_HALF);
123 if limited != gbcr_val {
124 mdio.write(addr, GBCR, limited);
125 changed = true;
126 }
127 }
128 }
129
130 if max_speed == Speed::_10M {
131 let anar_val = mdio.read(addr, ANAR);
132 let limited = anar_val & !(an::BASE_100_FULL | an::BASE_100_HALF);
133 if limited != anar_val {
134 mdio.write(addr, ANAR, limited);
135 changed = true;
136 }
137 }
138
139 changed
140 }
141
142 fn init_yt8531<M: MdioBus>(mdio: &mut M, addr: u8) {
148 let chip = ext_read(mdio, addr, EXT_CHIP_CFG);
149 ext_write(mdio, addr, EXT_CHIP_CFG, chip | RXC_DLY_EN);
150
151 let mut rgmii = ext_read(mdio, addr, EXT_RGMII_CFG1);
152 rgmii = (rgmii & !RGMII_TX_DLY_MASK) | (RGMII_DLY_2NS << 4) | RGMII_DLY_2NS;
153 ext_write(mdio, addr, EXT_RGMII_CFG1, rgmii);
154
155 let ctrl = mdio.read(addr, BMCR);
157 mdio.write(addr, BMCR, ctrl | bmcr::RESTART_AN);
158 }
159}
160
161impl Phy for GenericPhy {
162 fn address(&self) -> u8 {
163 self.addr
164 .expect("GenericPhy address not yet resolved — call init() first")
165 }
166
167 fn init<M: MdioBus>(&mut self, mdio: &mut M, max_speed: Speed) -> Result<(), PhyError> {
168 if self.addr.is_none() {
170 self.addr = Some(Self::discover(mdio).ok_or(PhyError::NotFound)?);
171 }
172 let addr = self.addr.unwrap();
173
174 let ctrl = mdio.read(addr, BMCR);
178 if ctrl & bmcr::POWER_DOWN != 0 {
179 mdio.write(addr, BMCR, ctrl & !bmcr::POWER_DOWN);
180 for _ in 0..RESET_POLL_LIMIT {
181 if mdio.read(addr, BMCR) & bmcr::POWER_DOWN == 0 {
182 break;
183 }
184 crate::rom::ets_delay_us(1);
185 }
186 }
187
188 mdio.write(addr, BMCR, bmcr::RESET);
189 for _ in 0..RESET_POLL_LIMIT {
190 if mdio.read(addr, BMCR) & bmcr::RESET == 0 {
191 let ctrl = mdio.read(addr, BMCR);
194 if ctrl & bmcr::ANEN == 0 {
195 mdio.write(addr, BMCR, (ctrl & !bmcr::POWER_DOWN) | bmcr::ANEN);
196 }
197
198 let restart_an = Self::limit_advertisement(mdio, addr, max_speed);
199
200 let id = (mdio.read(addr, PHYIDR1), mdio.read(addr, PHYIDR2));
201 if id == YT8531_ID {
202 Self::init_yt8531(mdio, addr);
204 } else if restart_an {
205 let ctrl = mdio.read(addr, BMCR);
206 mdio.write(addr, BMCR, ctrl | bmcr::RESTART_AN);
207 }
208
209 return Ok(());
210 }
211 crate::rom::ets_delay_us(1);
212 }
213
214 Err(PhyError::Timeout)
215 }
216
217 fn poll_link<M: MdioBus>(&mut self, mdio: &mut M, cx: Option<&mut Context<'_>>) -> LinkState {
218 const LINK_STATE_DOWN: LinkState = LinkState {
219 up: false,
220 speed: Speed::_100M,
221 duplex: Duplex::Full,
222 };
223
224 if let Some(cx) = cx {
228 cx.waker().wake_by_ref();
229 }
230
231 let Some(addr) = self.addr else {
232 debug!("poll_link called before init");
233 return LINK_STATE_DOWN;
234 };
235
236 let _ = mdio.read(addr, BMSR);
239 let bmsr_val = mdio.read(addr, BMSR);
240
241 trace!("bmsr_val: {:x}", bmsr_val);
242
243 if bmsr_val & bmsr::LINK_STATUS == 0 {
247 return LINK_STATE_DOWN;
248 }
249
250 let bmcr_val = mdio.read(addr, BMCR);
251 if bmcr_val & bmcr::ANEN == 0 {
252 let speed = if bmcr_val & bmcr::SPEED_1000 != 0 {
253 Speed::_1000M
254 } else if bmcr_val & bmcr::SPEED_100 != 0 {
255 Speed::_100M
256 } else {
257 Speed::_10M
258 };
259 let duplex = if bmcr_val & bmcr::FULL_DUPLEX != 0 {
260 Duplex::Full
261 } else {
262 Duplex::Half
263 };
264 return LinkState {
265 up: true,
266 speed,
267 duplex,
268 };
269 }
270
271 if bmsr_val & bmsr::EXTENDED_STATUS != 0 {
272 let exsr_val = mdio.read(addr, EXSR);
273 if exsr_val != 0xFFFF && (exsr_val & (exsr::BASE1000_T_HD | exsr::BASE1000_T_FD) != 0) {
274 let gbcr_val = mdio.read(addr, GBCR);
275 let gbsr_val = mdio.read(addr, GBSR);
276 if gbcr_val != 0xFFFF && gbsr_val != 0xFFFF {
277 if gbcr_val & gbcr::ADV_1000_FULL != 0 && gbsr_val & gbsr::LP_1000_FULL != 0 {
278 return LinkState {
279 up: true,
280 speed: Speed::_1000M,
281 duplex: Duplex::Full,
282 };
283 }
284 if gbcr_val & gbcr::ADV_1000_HALF != 0 && gbsr_val & gbsr::LP_1000_HALF != 0 {
285 return LinkState {
286 up: true,
287 speed: Speed::_1000M,
288 duplex: Duplex::Half,
289 };
290 }
291 }
292 }
293 }
294
295 let anar_val = mdio.read(addr, ANAR);
297 let anlpar_val = mdio.read(addr, ANLPAR);
298 let common = anar_val & anlpar_val;
299 let (speed, duplex) = if common & an::BASE_100_FULL != 0 {
300 (Speed::_100M, Duplex::Full)
301 } else if common & an::BASE_100_HALF != 0 {
302 (Speed::_100M, Duplex::Half)
303 } else if common & an::BASE_10_FULL != 0 {
304 (Speed::_10M, Duplex::Full)
305 } else if common & an::BASE_10_HALF != 0 {
306 (Speed::_10M, Duplex::Half)
307 } else {
308 (Speed::_100M, Duplex::Full)
309 };
310
311 LinkState {
312 up: true,
313 speed,
314 duplex,
315 }
316 }
317}