use log::debug;
use tock_registers::register_bitfields;
use crate::{err::DError, mac::Mac, osal::wait_for};
const PHY_CONTROL: u32 = 0;
const PHY_STATUS: u32 = 1;
register_bitfields! {
u16,
PCTRL [
RESET OFFSET(15) NUMBITS(1) [
Normal = 0,
Reset = 1
],
LOOPBACK OFFSET(14) NUMBITS(1) [
Disable = 0,
Enable = 1
],
SPEED_SELECTION_LSB OFFSET(13) NUMBITS(1) [],
AUTO_NEGOTIATION_ENABLE OFFSET(12) NUMBITS(1) [
Disable = 0,
Enable = 1
],
POWER_DOWN OFFSET(11) NUMBITS(1) [
Normal = 0,
PowerDown = 1
],
ISOLATE OFFSET(10) NUMBITS(1) [
Normal = 0,
Isolate = 1
],
RESTART_AUTO_NEGOTIATION OFFSET(9) NUMBITS(1) [
Normal = 0,
Restart = 1
],
DUPLEX_MODE OFFSET(8) NUMBITS(1) [
Half = 0,
Full = 1
],
COLLISION_TEST OFFSET(7) NUMBITS(1) [
Disable = 0,
Enable = 1
],
SPEED_SELECTION_MSB OFFSET(6) NUMBITS(1) [],
RESERVED OFFSET(0) NUMBITS(6) []
]
}
register_bitfields! {
u16,
PSTATUS [
CAPABILITY_100BASE_T4 OFFSET(15) NUMBITS(1) [
NotCapable = 0,
Capable = 1
],
CAPABILITY_100BASE_TX_FD OFFSET(14) NUMBITS(1) [
NotCapable = 0,
Capable = 1
],
CAPABILITY_100BASE_TX_HD OFFSET(13) NUMBITS(1) [
NotCapable = 0,
Capable = 1
],
CAPABILITY_10BASE_T_FD OFFSET(12) NUMBITS(1) [
NotCapable = 0,
Capable = 1
],
CAPABILITY_10BASE_T_HD OFFSET(11) NUMBITS(1) [
NotCapable = 0,
Capable = 1
],
CAPABILITY_100BASE_T2_FD OFFSET(10) NUMBITS(1) [
NotCapable = 0,
Capable = 1
],
CAPABILITY_100BASE_T2_HD OFFSET(9) NUMBITS(1) [
NotCapable = 0,
Capable = 1
],
EXTENDED_STATUS OFFSET(8) NUMBITS(1) [
NoExtended = 0,
Extended = 1
],
RESERVED_7 OFFSET(7) NUMBITS(1) [],
MF_PREAMBLE_SUPPRESSION OFFSET(6) NUMBITS(1) [
NotAccept = 0,
Accept = 1
],
AUTO_NEGOTIATION_COMPLETE OFFSET(5) NUMBITS(1) [
NotComplete = 0,
Complete = 1
],
REMOTE_FAULT OFFSET(4) NUMBITS(1) [
NoFault = 0,
Fault = 1
],
AUTO_NEGOTIATION_ABILITY OFFSET(3) NUMBITS(1) [
NotCapable = 0,
Capable = 1
],
LINK_STATUS OFFSET(2) NUMBITS(1) [
Down = 0,
Up = 1
],
JABBER_DETECT OFFSET(1) NUMBITS(1) [
NoJabber = 0,
Jabber = 1
],
EXTENDED_CAPABILITY OFFSET(0) NUMBITS(1) [
Basic = 0,
Extended = 1
]
]
}
pub struct Phy {
mac: Mac,
addr: u32,
}
impl Phy {
pub fn new(mac: Mac) -> Self {
Self { mac, addr: 1 }
}
pub fn read_mdic(&mut self, offset: u32) -> Result<u16, DError> {
self.mac.read_mdic(self.addr, offset)
}
pub fn write_mdic(&mut self, offset: u32, data: u16) -> Result<(), DError> {
self.mac.write_mdic(self.addr, offset, data)
}
pub fn power_up(&mut self) -> Result<(), DError> {
let mut mii_reg = self.read_mdic(PHY_CONTROL)?;
mii_reg &= !PCTRL::POWER_DOWN::SET.value;
self.write_mdic(PHY_CONTROL, mii_reg)
}
pub fn read_status(&mut self) -> Result<u16, DError> {
self.read_mdic(PHY_STATUS)
}
pub fn wait_for_auto_negotiation_complete(&mut self) -> Result<(), DError> {
let interval = core::time::Duration::from_millis(100);
let try_count = 30;
wait_for(
|| self.is_auto_negotiation_complete().unwrap_or(false),
interval,
Some(try_count),
)
}
pub fn is_auto_negotiation_complete(&mut self) -> Result<bool, DError> {
let status = self.read_status()?;
Ok(status & PSTATUS::AUTO_NEGOTIATION_COMPLETE::Complete.value != 0)
}
pub fn enable_auto_negotiation(&mut self) -> Result<(), DError> {
debug!("Enabling auto-negotiation for PHY at address {}", self.addr);
let mut control = self.read_mdic(PHY_CONTROL)?;
control |= PCTRL::AUTO_NEGOTIATION_ENABLE::Enable.value
| PCTRL::RESTART_AUTO_NEGOTIATION::Restart.value;
self.write_mdic(PHY_CONTROL, control)
}
}