begin adding phy package

This commit is contained in:
soypat
2026-01-15 18:31:17 -03:00
parent 3d5999a9d8
commit 80b740827f
3 changed files with 170 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
package phy
// MDIOBus is a HAL for MDIO bus access supporting both Clause 22 and Clause 45 devices.
// Implementations should use devaddr to select the framing:
// - devaddr=0: Clause 22 framing (devaddr ignored in transaction)
// - devaddr>=1: Clause 45 framing (PMA/PMD=1, WIS=2, PCS=3, PHY XS=4, DTE XS=5, AN=7)
//
// Register address range: Clause 22 uses 0-31, Clause 45 uses 0-65535.
type MDIOBus interface {
// Read reads a 16-bit register from the PHY.
Read(phyAddr, devaddr uint8, regAddr uint16) (value uint16, err error)
// Write writes a 16-bit value to a PHY register.
Write(phyAddr, devaddr uint8, regAddr, value uint16) error
}
+93
View File
@@ -0,0 +1,93 @@
// 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)
}
+63
View File
@@ -0,0 +1,63 @@
package phy
// Registers 0..15 as defined by 802.3.
const (
// First two registers are BMCR and BMSR. See below.
regPhyId1 = 0x02
regPhyId2 = 0x03
regAutoNegotiationAdvertisement = 0x04
regAutoNegotiationLinkPartnerAbility = 0x05
regAutoNegotiationExpansion = 0x05
regModeControlStatus = 0x11
regSpecialModes = 0x12
regSymbolErorCounter = 0x1a
regSpecialControlStatusIndications = 0x1b
regIRQSourceFlag = 0x1d
regIRQMask = 0x1e
regPhySpecialScontrolStatus = 0x1f
)
// BMCR represents the Basic Mode Control Register at address 0x00.
// Reference: IEEE 802.3 Clause 22.2.4.1
type BMCR uint16
const (
BMCRAddr = 0x00
BMCRSpeed1000 BMCR = 0x0040 // MSB of Speed (1000Mbps)
BMCRCollision BMCR = 0x0080 // Collision test
BMCRFullDuplex BMCR = 0x0100 // Full duplex mode
BMCRANRestart BMCR = 0x0200 // Restart auto-negotiation
BMCRIsolate BMCR = 0x0400 // Isolate PHY from MII
BMCRPowerDown BMCR = 0x0800 // Power down PHY
BMCRANEnable BMCR = 0x1000 // Enable auto-negotiation
BMCRSpeed100 BMCR = 0x2000 // Select 100Mbps
BMCRLoopback BMCR = 0x4000 // Enable TXD loopback
BMCRReset BMCR = 0x8000 // Software reset (self-clearing)
)
// BMSR represents the Basic Mode Status Register at address 0x01.
// Reference: IEEE 802.3 Clause 22.2.4.2
type BMSR uint16
const (
BMSRAddr = 0x01
BMSRExtCap BMSR = 0x0001 // Extended register capability
BMSRJabber BMSR = 0x0002 // Jabber detected
BMSRLinkStatus BMSR = 0x0004 // Link status (1=up)
BMSRANCap BMSR = 0x0008 // Auto-negotiation capable
BMSRRemoteFault BMSR = 0x0010 // Remote fault detected
BMSRANComplete BMSR = 0x0020 // Auto-negotiation complete
BMSRNoPreamble BMSR = 0x0040 // Preamble suppression capable
BMSRExtStatus BMSR = 0x0100 // Extended status in register 15
BMSR100Half2 BMSR = 0x0200 // 100BASE-T2 half-duplex capable
BMSR100Full2 BMSR = 0x0400 // 100BASE-T2 full-duplex capable
BMSR10Half BMSR = 0x0800 // 10Mbps half-duplex capable
BMSR10Full BMSR = 0x1000 // 10Mbps full-duplex capable
BMSR100Half BMSR = 0x2000 // 100Mbps half-duplex capable
BMSR100Full BMSR = 0x4000 // 100Mbps full-duplex capable
BMSR100Base4 BMSR = 0x8000 // 100BASE-T4 capable
)