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/Rtl8211Phy.lvt

namespace Livt.IO.Phy

using Livt.IO

/** RTL8211F Clause-22 manager. One MDIO owner; only 100BASE-TX full duplex.
 * Board supplies 25 MHz reference, reset and startupReady. Restart is a toggle.
 * RX delay enabled, TX delay disabled: board must supply TX clock/data skew.
 */
component Rtl8211Phy<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
	restart: bool
	seenRestart: bool
	linked: bool
	POLL_TICKS: uint
	public failed: out bool
	public stage: out byte
	public identifier1: out logic[16]
	public identifier2: out logic[16]
	public bmsr: out logic[16]
	public physicalStatus: out logic[16]

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

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

	process Manage()
	{
		var value: logic[16] = 0
		var status: logic[16] = 0
		var physical: logic[16] = 0
		var ticks: uint = 0
		var attempts: uint = 0
		state Initialize {
			linked = false
			failed = false
			seenRestart = restart
			stage = 1
			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) { goto Failed }
		identifier1 = value
		if (value != 0x001C) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 3, value) != EthernetResult.Success) { goto Failed }
		identifier2 = value
		if ((value & 0xFFF0) != 0xC910) { goto Failed }
		stage = 2
		if (mdio.Write(PHY_ADDRESS as byte, 0, 0x8000) != EthernetResult.Success) { goto Failed }
		attempts = 0
		state ResetWait {}
		if (mdio.Read(PHY_ADDRESS as byte, 0, value) != EthernetResult.Success) { goto Failed }
		if ((value & 0x8000) != 0) {
			attempts++
			if (attempts > 10000) { goto Failed }
			goto ResetWait
		}
		stage = 3
		// RTL8211F RGMII delay registers: TX page d08/reg11 bit8; RX reg15 bit3.
		if (mdio.Write(PHY_ADDRESS as byte, 31, 0x0D08) != EthernetResult.Success) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 17, value) != EthernetResult.Success) { goto Failed }
		value = value & 0xFEFF
		if (mdio.Write(PHY_ADDRESS as byte, 17, value) != EthernetResult.Success) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 17, value) != EthernetResult.Success || (value & 0x0100) != 0) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 21, value) != EthernetResult.Success) { goto Failed }
		value = value | 0x0008
		if (mdio.Write(PHY_ADDRESS as byte, 21, value) != EthernetResult.Success) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 21, value) != EthernetResult.Success || (value & 0x0008) == 0) { goto Failed }
		if (mdio.Write(PHY_ADDRESS as byte, 31, 0) != EthernetResult.Success) { goto Failed }
		stage = 4
		if (mdio.Write(PHY_ADDRESS as byte, 4, 0x0101) != EthernetResult.Success) { goto Failed }
		if (mdio.Write(PHY_ADDRESS as byte, 9, 0) != EthernetResult.Success) { goto Failed }
		// Disable EEE advertisement, MMD 7 register 3c.
		if (mdio.Write(PHY_ADDRESS as byte, 13, 7) != 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 {
			stage = 5
			if (!startupReady || restart != seenRestart) { goto Initialize }
		}
		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.Write(PHY_ADDRESS as byte, 31, 0x0A43) != EthernetResult.Success) { goto Failed }
		if (mdio.Read(PHY_ADDRESS as byte, 26, physical) != EthernetResult.Success) { goto Failed }
		if (mdio.Write(PHY_ADDRESS as byte, 31, 0) != EthernetResult.Success) { goto Failed }
		state Publish {
			bmsr = status
			physicalStatus = physical
			linked = (status & 0x0024) == 0x0024 && (physical & 0x003C) == 0x001C
			ticks = 0
		}
		state Delay {
			if (!startupReady || restart != seenRestart) { goto Initialize }
			if (ticks + 1 < POLL_TICKS) { ticks++; goto Delay }
			goto Poll
		}
		state Failed {
			linked = false
			failed = true
			ticks = 0
		}
		state Retry {
			if (restart != seenRestart) { goto Initialize }
			if (ticks + 1 < POLL_TICKS) { ticks++; goto Retry }
			goto Initialize
		}
	}
}