Files
lneto/phy/phy.go
T
2026-01-15 18:31:17 -03:00

94 lines
2.3 KiB
Go

// Package phy provides Ethernet PHY management via MDIO.
// It supports IEEE 802.3 Clause 22 and Clause 45 register access
// for configuring and monitoring physical layer transceivers.
package phy
import (
"errors"
"time"
)
// FindPHYs finds all regular non-clause45 PHYs on the MDIO bus and writes them to dst.
func FindPHYs(mdio MDIOBus, dst []uint8) (n int, err error) {
const maxAddr = 31
const regBasicStatus = 0x01
if len(dst) < 32 {
return -1, errors.New("require buffer length 32 for FindPHYs")
}
n = 0
for addr := uint8(0); addr <= maxAddr; addr++ {
// Future proofing for supported clause 45.
// Check PMA/PMD device (DEVAD 1), register 0 (control)
const devAddr = 1
var val uint16
val, err = mdio.Read(addr, devAddr, BMCRAddr)
if err != nil {
continue
}
// Basic status has some bits that must be zero and one, so if this check fails then we know its a bad address.
if val != 0xffff && val != 0x0000 {
dst[n] = addr
n++
}
time.Sleep(150 * time.Microsecond)
}
return n, err
}
type Device struct {
mdio MDIOBus
phyaddr uint8
// Is 1 for Clause 45 devices and 0 for clause 22 devices.
clause45 uint8
}
func (d *Device) BasicControl() (BMCR, error) {
ctl, err := d.rread(BMCRAddr)
return BMCR(ctl), err
}
func (d *Device) BasicStatus(phyaddr uint8) (BMSR, error) {
stat, err := d.rread(BMSRAddr)
return BMSR(stat), err
}
func (d *Device) ID1() (uint16, error) {
return d.rread(regPhyId1)
}
func (d *Device) ID2() (uint16, error) {
return d.rread(regPhyId2)
}
func (d *Device) Reset(phyaddr uint8) error {
err := d.rwrite(BMCRAddr, uint16(BMCRReset))
if err != nil {
return err
}
// Wait for reset to complete (bit self-clears).
// IEEE 802.3 allows up to 500ms.
const maxPolls = 50
const resetTimeout = 500 * time.Millisecond // As per standard.
for i := 0; i < maxPolls; i++ {
time.Sleep(resetTimeout / maxPolls)
ctl, err := d.BasicControl()
if err != nil {
continue
}
if ctl&BMCRReset == 0 {
return nil
}
}
return errors.New("PHY reset timeout")
}
// rwrite mdio register write.
func (d *Device) rwrite(addr uint16, value uint16) error {
return d.mdio.Write(d.phyaddr, d.clause45, addr, value)
}
// rread mdio register read.
func (d *Device) rread(addr uint16) (value uint16, _ error) {
return d.mdio.Read(d.phyaddr, d.clause45, addr)
}