Skip to content

Commit

Permalink
liteeth: add rgmii phy
Browse files Browse the repository at this point in the history
  • Loading branch information
enjoy-digital committed Aug 4, 2015
1 parent c03ef52 commit 4b8d9b6
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 0 deletions.
4 changes: 4 additions & 0 deletions misoclib/com/liteeth/phy/__init__.py
Expand Up @@ -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
Expand Down
160 changes: 160 additions & 0 deletions misoclib/com/liteeth/phy/rgmii.py
@@ -0,0 +1,160 @@
from migen.genlib.io import DDROutput

This comment has been minimized.

Copy link
@sbourdeauducq

sbourdeauducq Aug 5, 2015

Member

What FPGA is that for, Spartan-6?

This comment has been minimized.

Copy link
@enjoy-digital

enjoy-digital Aug 5, 2015

Author Contributor

Yes a Spartan6. I'll add a comment or eventually rename it to s6rgmii.py (not sure it will be easy to have something generic for rgmii). Thanks.

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

0 comments on commit 4b8d9b6

Please sign in to comment.