Livt packages

Livt.IO

Version 1.8.1

Memory, UART, I2C, SPI, and Ethernet input/output components for Livt hardware designs.

Published files (126)

src/ethernet/phy/Rtl8201Phy.lvt

namespace Livt.IO.Phy

using Livt.IO

/**
 * RTL8201F-VB management in the MAC context, after board reset/clock startup.
 * Advertises only 100BASE-TX full duplex. Hardware reset belongs to the board.
 * MDIO is borrowed exclusively; loss/failure clears readiness and retries setup.
 */
component Rtl8201Phy<PHY_ADDRESS: int = 1, POLL: Time = 10ms> : IEthernetLinkStatus
{
	static assert PHY_ADDRESS >= 0 && PHY_ADDRESS <= 31, "Clause 22 address required"
	static assert POLL >= 1us, "Polling interval must be positive"
	mdio: IMdioController
	startupReady: bool
	POLL_TICKS: uint
	public failed: out bool
	linked: bool
	failedState: bool

	new(mdio: IMdioController, startupReady: bool)
	{
		POLL_TICKS = this.context.TicksFor(POLL)
		this.mdio = mdio
		this.startupReady = startupReady
	}

	process Status[]()
	{
		this.ready = linked && startupReady
		this.failed = failedState
		this.speed = EthernetSpeed.Unknown
		if (this.ready) { this.speed = EthernetSpeed.Mbps100 }
	}

	process Manage()
	{
		var value: logic[16] = 0
		var status: logic[16] = 0
		var partner: logic[16] = 0
		var ticks: uint = 0
		state Initialize {
			linked = false
			
			failedState = false
			if (!startupReady) { goto Initialize }
		}
		if (mdio.Write(PHY_ADDRESS as byte, 31, 0) != EthernetResult.Success) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 2, value) != EthernetResult.Success || value != 0x001C) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 3, value) != EthernetResult.Success) { goto Failed }
		var identifier = value & 0xFFF0
		if (identifier != 0xC810) { goto Failed }
		if (mdio.Write(PHY_ADDRESS as byte, 31, 7) != EthernetResult.Success) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 16, value) != EthernetResult.Success) { goto Failed }
		// Preserve reserved/delay fields, output REF_CLK, standard CRS_DV, RMII.
		value = (value & 0xEFFB) | 0x0008
		if (mdio.Write(PHY_ADDRESS as byte, 16, value) != EthernetResult.Success) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 16, value) != EthernetResult.Success) { goto Failed }
		var mode = value & 0x100C
		if (mode != 0x0008) { goto Failed }
		if (mdio.Write(PHY_ADDRESS as byte, 31, 0) != EthernetResult.Success) { goto Failed }
		// IEEE selector + 100 full only; no half duplex, pause or 10M advertisement.
		if (mdio.Write(PHY_ADDRESS as byte, 4, 0x0101) != EthernetResult.Success) { goto Failed }
		// Disable EEE advertisement through the standard MMD register window.
		if (mdio.Write(PHY_ADDRESS as byte, 13, 0x0007) != EthernetResult.Success) { goto Failed }
		if (mdio.Write(PHY_ADDRESS as byte, 14, 0x003C) != EthernetResult.Success) { goto Failed }
		if (mdio.Write(PHY_ADDRESS as byte, 13, 0x4007) != EthernetResult.Success) { goto Failed }
		if (mdio.Write(PHY_ADDRESS as byte, 14, 0) != EthernetResult.Success) { goto Failed }
		if (mdio.Write(PHY_ADDRESS as byte, 0, 0x1200) != EthernetResult.Success) { goto Failed }
		state Poll {
			if (!startupReady) { goto Initialize }
		}
		// BMSR link status is latch-low: read twice before deciding current state.
		if (mdio.Read(PHY_ADDRESS as byte, 1, status) != EthernetResult.Success) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 1, status) != EthernetResult.Success) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 5, partner) != EthernetResult.Success) { goto Failed }
		state Publish {
			var stateBits = status & 0x0034
			var partnerBits = partner & 0x611F
			linked = startupReady && stateBits == 0x0024 && partnerBits == 0x4101
			
			
			ticks = 0
		}
		state Delay {
			if (!startupReady) { goto Initialize }
			if (ticks + 1 < POLL_TICKS) { ticks++; goto Delay }
			goto Poll
		}
		state Failed {
			linked = false
			
			failedState = true
			ticks = 0
		}
		state Retry {
			if (ticks + 1 < POLL_TICKS) { ticks++; goto Retry }
			goto Initialize
		}
	}
}