liteeth: add rgmii phy
This commit is contained in:
parent
c03ef526eb
commit
4b8d9b67f3
|
@ -16,6 +16,10 @@ def LiteEthPHY(clock_pads, pads, **kwargs):
|
|||
# This is a pure 1G PHY
|
||||
from misoclib.com.liteeth.phy.gmii import LiteEthPHYGMII
|
||||
return LiteEthPHYGMII(clock_pads, pads, **kwargs)
|
||||
elif hasattr(pads, "rx_ctl"):
|
||||
# This is a 10/100/1G RGMII PHY
|
||||
from misoclib.com.liteeth.phy.rgmii import LiteEthPHYRGMII
|
||||
return LiteEthPHYRGMII(clock_pads, pads, **kwargs)
|
||||
elif flen(pads.tx_data) == 4:
|
||||
# This is a MII PHY
|
||||
from misoclib.com.liteeth.phy.mii import LiteEthPHYMII
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
from migen.genlib.io import DDROutput
|
||||
from migen.genlib.misc import WaitTimer
|
||||
from migen.genlib.fsm import FSM, NextState
|
||||
|
||||
from misoclib.com.liteeth.common import *
|
||||
|
||||
|
||||
class LiteEthPHYRGMIITX(Module):
|
||||
def __init__(self, pads, pads_register=True):
|
||||
self.sink = sink = Sink(eth_phy_description(8))
|
||||
|
||||
# # #
|
||||
|
||||
self.specials += Instance("ODDR2",
|
||||
p_DDR_ALIGNMENT="C0", p_INIT=0, p_SRTYPE="ASYNC",
|
||||
i_C0=ClockSignal("eth_tx"), i_C1=~ClockSignal("eth_tx"),
|
||||
i_CE=1, i_S=0, i_R=0,
|
||||
i_D0=sink.stb, i_D1=sink.stb, o_Q=pads.tx_ctl,
|
||||
)
|
||||
for i in range(4):
|
||||
self.specials += Instance("ODDR2",
|
||||
p_DDR_ALIGNMENT="C0", p_INIT=0, p_SRTYPE="ASYNC",
|
||||
i_C0=ClockSignal("eth_tx"), i_C1=~ClockSignal("eth_tx"),
|
||||
i_CE=1, i_S=0, i_R=0,
|
||||
i_D0=sink.data[i], i_D1=sink.data[4+i], o_Q=pads.tx_data[i],
|
||||
)
|
||||
self.comb += sink.ack.eq(1)
|
||||
|
||||
|
||||
class LiteEthPHYRGMIIRX(Module):
|
||||
def __init__(self, pads):
|
||||
self.source = source = Source(eth_phy_description(8))
|
||||
|
||||
# # #
|
||||
|
||||
rx_ctl = Signal()
|
||||
rx_data = Signal(8)
|
||||
|
||||
self.specials += Instance("IDDR2",
|
||||
p_DDR_ALIGNMENT="C0", p_INIT_Q0=0, p_INIT_Q1=0, p_SRTYPE="ASYNC",
|
||||
i_C0=ClockSignal("eth_rx"), i_C1=~ClockSignal("eth_rx"),
|
||||
i_CE=1, i_S=0, i_R=0,
|
||||
i_D=pads.rx_ctl, o_Q1=rx_ctl,
|
||||
)
|
||||
for i in range(4):
|
||||
self.specials += Instance("IDDR2",
|
||||
p_DDR_ALIGNMENT="C0", p_INIT_Q0=0, p_INIT_Q1=0, p_SRTYPE="ASYNC",
|
||||
i_C0=ClockSignal("eth_rx"), i_C1=~ClockSignal("eth_rx"),
|
||||
i_CE=1, i_S=0, i_R=0,
|
||||
i_D=pads.rx_data[i], o_Q0=rx_data[4+i], o_Q1=rx_data[i],
|
||||
)
|
||||
|
||||
|
||||
rx_ctl_d = Signal()
|
||||
self.sync += rx_ctl_d.eq(rx_ctl)
|
||||
|
||||
sop = Signal()
|
||||
eop = Signal()
|
||||
self.comb += [
|
||||
sop.eq(rx_ctl & ~rx_ctl_d),
|
||||
eop.eq(~rx_ctl & rx_ctl_d)
|
||||
]
|
||||
self.sync += [
|
||||
source.stb.eq(rx_ctl),
|
||||
source.sop.eq(sop),
|
||||
source.data.eq(rx_data)
|
||||
]
|
||||
self.comb += source.eop.eq(eop)
|
||||
|
||||
|
||||
class LiteEthPHYRGMIICRG(Module, AutoCSR):
|
||||
def __init__(self, clock_pads, pads, with_hw_init_reset):
|
||||
self._reset = CSRStorage()
|
||||
|
||||
# # #
|
||||
|
||||
self.clock_domains.cd_eth_rx = ClockDomain()
|
||||
self.clock_domains.cd_eth_tx = ClockDomain()
|
||||
|
||||
|
||||
# RX
|
||||
dcm_reset = Signal()
|
||||
dcm_locked = Signal()
|
||||
|
||||
timer = WaitTimer(1024)
|
||||
fsm = FSM(reset_state="DCM_RESET")
|
||||
self.submodules += timer, fsm
|
||||
|
||||
fsm.act("DCM_RESET",
|
||||
dcm_reset.eq(1),
|
||||
timer.wait.eq(1),
|
||||
If(timer.done,
|
||||
timer.wait.eq(0),
|
||||
NextState("DCM_WAIT")
|
||||
)
|
||||
)
|
||||
fsm.act("DCM_WAIT",
|
||||
timer.wait.eq(1),
|
||||
If(timer.done,
|
||||
NextState("DCM_CHECK_LOCK")
|
||||
)
|
||||
)
|
||||
fsm.act("DCM_CHECK_LOCK",
|
||||
If(~dcm_locked,
|
||||
NextState("DCM_RESET")
|
||||
)
|
||||
)
|
||||
|
||||
clk90_rx = Signal()
|
||||
clk0_rx = Signal()
|
||||
clk0_rx_bufg = Signal()
|
||||
self.specials += Instance("DCM",
|
||||
i_CLKIN=clock_pads.rx,
|
||||
i_CLKFB=clk0_rx_bufg,
|
||||
o_CLK0=clk0_rx,
|
||||
o_CLK90=clk90_rx,
|
||||
o_LOCKED=dcm_locked,
|
||||
i_PSEN=0,
|
||||
i_PSCLK=0,
|
||||
i_PSINCDEC=0,
|
||||
i_RST=dcm_reset
|
||||
)
|
||||
|
||||
self.specials += Instance("BUFG", i_I=clk0_rx, o_O=clk0_rx_bufg)
|
||||
self.specials += Instance("BUFG", i_I=clk90_rx, o_O=self.cd_eth_rx.clk)
|
||||
|
||||
# TX
|
||||
self.specials += DDROutput(1, 0, clock_pads.tx, ClockSignal("eth_tx"))
|
||||
self.specials += Instance("BUFG", i_I=self.cd_eth_rx.clk, o_O=self.cd_eth_tx.clk)
|
||||
|
||||
# Reset
|
||||
if with_hw_init_reset:
|
||||
reset = Signal()
|
||||
counter_done = Signal()
|
||||
self.submodules.counter = counter = Counter(max=512)
|
||||
self.comb += [
|
||||
counter_done.eq(counter.value == 256),
|
||||
counter.ce.eq(~counter_done),
|
||||
reset.eq(~counter_done | self._reset.storage)
|
||||
]
|
||||
else:
|
||||
reset = self._reset.storage
|
||||
self.comb += pads.rst_n.eq(~reset)
|
||||
self.specials += [
|
||||
AsyncResetSynchronizer(self.cd_eth_tx, reset),
|
||||
AsyncResetSynchronizer(self.cd_eth_rx, reset),
|
||||
]
|
||||
|
||||
|
||||
class LiteEthPHYRGMII(Module, AutoCSR):
|
||||
def __init__(self, clock_pads, pads, with_hw_init_reset=True):
|
||||
self.dw = 8
|
||||
self.submodules.crg = LiteEthPHYRGMIICRG(clock_pads,
|
||||
pads,
|
||||
with_hw_init_reset)
|
||||
self.submodules.tx = RenameClockDomains(LiteEthPHYRGMIITX(pads),
|
||||
"eth_tx")
|
||||
self.submodules.rx = RenameClockDomains(LiteEthPHYRGMIIRX(pads),
|
||||
"eth_rx")
|
||||
self.sink, self.source = self.tx.sink, self.rx.source
|
Loading…
Reference in New Issue