litesata: use (some) settings from vivado 2015.1, try to follow all ug476 recommendations to initialize GTX (...), remove automatic reset on top.

Works fine @ 3Gbps, still not working @6.0Gbps
This commit is contained in:
Florent Kermarrec 2015-05-06 01:33:02 +02:00
parent 5d5d5edfe2
commit 7bdcbc94cd
7 changed files with 268 additions and 205 deletions

View file

@ -19,7 +19,6 @@ from misoclib.mem.litesata import LiteSATA
class _CRG(Module): class _CRG(Module):
def __init__(self, platform): def __init__(self, platform):
self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_sys = ClockDomain()
self.reset = Signal()
clk200 = platform.request("clk200") clk200 = platform.request("clk200")
clk200_se = Signal() clk200_se = Signal()
@ -49,7 +48,7 @@ class _CRG(Module):
p_CLKOUT4_DIVIDE=2, p_CLKOUT4_PHASE=0.0, #o_CLKOUT4= p_CLKOUT4_DIVIDE=2, p_CLKOUT4_PHASE=0.0, #o_CLKOUT4=
), ),
Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk), Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk),
AsyncResetSynchronizer(self.cd_sys, ~pll_locked | platform.request("cpu_reset") | self.reset), AsyncResetSynchronizer(self.cd_sys, ~pll_locked | platform.request("cpu_reset")),
] ]
@ -106,7 +105,6 @@ class BISTSoC(SoC, AutoCSR):
# SATA PHY/Core/Frontend # SATA PHY/Core/Frontend
self.submodules.sata_phy = LiteSATAPHY(platform.device, platform.request("sata"), "sata_gen2", clk_freq) self.submodules.sata_phy = LiteSATAPHY(platform.device, platform.request("sata"), "sata_gen2", clk_freq)
self.comb += self.crg.reset.eq(self.sata_phy.ctrl.need_reset) # XXX FIXME
self.submodules.sata = LiteSATA(self.sata_phy, with_bist=True, with_bist_csr=True) self.submodules.sata = LiteSATA(self.sata_phy, with_bist=True, with_bist_csr=True)
# Status Leds # Status Leds

View file

@ -191,7 +191,7 @@ if __name__ == "__main__":
print("sector={:d}({:d}MB) wr_speed={:4.2f}MB/s rd_speed={:4.2f}MB/s errors={:d} retry={:d}".format( print("sector={:d}({:d}MB) wr_speed={:4.2f}MB/s rd_speed={:4.2f}MB/s errors={:d} retry={:d}".format(
sector, sector,
run_sectors*logical_sector_size/MB, int(run_sectors*logical_sector_size/MB),
write_speed/MB, write_speed/MB,
read_speed/MB, read_speed/MB,
write_errors + read_errors, write_errors + read_errors,

View file

@ -7,6 +7,7 @@ class LiteSATAPHY(Module):
def __init__(self, device, pads, revision, clk_freq): def __init__(self, device, pads, revision, clk_freq):
self.pads = pads self.pads = pads
self.revision = revision self.revision = revision
# Transceiver / Clocks # Transceiver / Clocks
if device[:3] == "xc7": # Kintex 7 if device[:3] == "xc7": # Kintex 7
from misoclib.mem.litesata.phy.k7.trx import K7LiteSATAPHYTRX from misoclib.mem.litesata.phy.k7.trx import K7LiteSATAPHYTRX
@ -14,8 +15,7 @@ class LiteSATAPHY(Module):
self.submodules.trx = K7LiteSATAPHYTRX(pads, revision) self.submodules.trx = K7LiteSATAPHYTRX(pads, revision)
self.submodules.crg = K7LiteSATAPHYCRG(pads, self.trx, revision, clk_freq) self.submodules.crg = K7LiteSATAPHYCRG(pads, self.trx, revision, clk_freq)
else: else:
msg = "Device" + device + "not (yet) supported." raise NotImplementedError
raise NotImplementedError(msg)
# Control # Control
self.submodules.ctrl = LiteSATAPHYCtrl(self.trx, self.crg, clk_freq) self.submodules.ctrl = LiteSATAPHYCtrl(self.trx, self.crg, clk_freq)

View file

@ -1,15 +1,10 @@
from misoclib.mem.litesata.common import * from misoclib.mem.litesata.common import *
def us(t, clk_freq):
clk_period_us = 1000000/clk_freq
return math.ceil(t/clk_period_us)
class LiteSATAPHYCtrl(Module): class LiteSATAPHYCtrl(Module):
def __init__(self, trx, crg, clk_freq): def __init__(self, trx, crg, clk_freq):
self.clk_freq = clk_freq
self.ready = Signal() self.ready = Signal()
self.need_reset = Signal()
self.sink = sink = Sink(phy_description(32)) self.sink = sink = Sink(phy_description(32))
self.source = source = Source(phy_description(32)) self.source = source = Source(phy_description(32))
@ -20,47 +15,47 @@ class LiteSATAPHYCtrl(Module):
sink.ack.eq(1) sink.ack.eq(1)
] ]
retry_timeout = Timeout(us(10000, clk_freq)) retry_timeout = Timeout(self.us(10000))
align_timeout = Timeout(us(873, clk_freq)) align_timeout = Timeout(self.us(873))
self.submodules += align_timeout, retry_timeout self.submodules += align_timeout, retry_timeout
align_detect = Signal() align_detect = Signal()
non_align_cnt = Signal(4) non_align_cnt = Signal(4)
non_align_counter = Counter(4)
self.submodules += non_align_counter
self.fsm = fsm = FSM(reset_state="RESET") self.fsm = fsm = InsertReset(FSM(reset_state="RESET"))
self.submodules += fsm self.submodules += fsm
self.comb += fsm.reset.eq(retry_timeout.reached | align_timeout.reached)
fsm.act("RESET", fsm.act("RESET",
trx.tx_idle.eq(1), trx.tx_idle.eq(1),
retry_timeout.reset.eq(1), retry_timeout.reset.eq(1),
align_timeout.reset.eq(1), align_timeout.reset.eq(1),
non_align_counter.reset.eq(1),
If(crg.ready, If(crg.ready,
NextState("COMINIT") NextState("COMINIT")
), )
) )
fsm.act("COMINIT", fsm.act("COMINIT",
trx.tx_idle.eq(1), trx.tx_idle.eq(1),
trx.tx_cominit_stb.eq(1), trx.tx_cominit_stb.eq(1),
If(trx.tx_cominit_ack & ~trx.rx_cominit_stb, If(trx.tx_cominit_ack & ~trx.rx_cominit_stb,
NextState("AWAIT_COMINIT") NextState("AWAIT_COMINIT")
), )
) )
fsm.act("AWAIT_COMINIT", fsm.act("AWAIT_COMINIT",
trx.tx_idle.eq(1), trx.tx_idle.eq(1),
retry_timeout.ce.eq(1), retry_timeout.ce.eq(1),
If(trx.rx_cominit_stb, If(trx.rx_cominit_stb,
NextState("AWAIT_NO_COMINIT") NextState("AWAIT_NO_COMINIT")
).Else( )
If(retry_timeout.reached,
NextState("RESET")
)
),
) )
fsm.act("AWAIT_NO_COMINIT", fsm.act("AWAIT_NO_COMINIT",
trx.tx_idle.eq(1), trx.tx_idle.eq(1),
retry_timeout.reset.eq(1), retry_timeout.reset.eq(1),
If(~trx.rx_cominit_stb, If(~trx.rx_cominit_stb,
NextState("CALIBRATE") NextState("CALIBRATE")
), )
) )
fsm.act("CALIBRATE", fsm.act("CALIBRATE",
trx.tx_idle.eq(1), trx.tx_idle.eq(1),
@ -71,34 +66,31 @@ class LiteSATAPHYCtrl(Module):
trx.tx_comwake_stb.eq(1), trx.tx_comwake_stb.eq(1),
If(trx.tx_comwake_ack, If(trx.tx_comwake_ack,
NextState("AWAIT_COMWAKE") NextState("AWAIT_COMWAKE")
), )
) )
fsm.act("AWAIT_COMWAKE", fsm.act("AWAIT_COMWAKE",
trx.tx_idle.eq(1), trx.tx_idle.eq(1),
retry_timeout.ce.eq(1), retry_timeout.ce.eq(1),
If(trx.rx_comwake_stb, If(trx.rx_comwake_stb,
NextState("AWAIT_NO_COMWAKE") NextState("AWAIT_NO_COMWAKE")
).Else( )
If(retry_timeout.reached,
NextState("RESET")
)
),
) )
fsm.act("AWAIT_NO_COMWAKE", fsm.act("AWAIT_NO_COMWAKE",
trx.tx_idle.eq(1), trx.tx_idle.eq(1),
If(~trx.rx_comwake_stb, If(~trx.rx_comwake_stb,
NextState("AWAIT_NO_RX_IDLE") NextState("AWAIT_NO_RX_IDLE")
), )
) )
fsm.act("AWAIT_NO_RX_IDLE", fsm.act("AWAIT_NO_RX_IDLE",
trx.tx_idle.eq(0), trx.tx_idle.eq(0),
source.data.eq(0x4A4A4A4A), # D10.2 source.data.eq(0x4A4A4A4A), # D10.2
source.charisk.eq(0b0000), source.charisk.eq(0b0000),
align_timeout.ce.eq(1),
If(~trx.rx_idle, If(~trx.rx_idle,
NextState("AWAIT_ALIGN"), NextState("AWAIT_ALIGN"),
crg.reset.eq(1), crg.tx_reset.eq(1),
trx.pmarxreset.eq(1) crg.rx_reset.eq(1)
), )
) )
fsm.act("AWAIT_ALIGN", fsm.act("AWAIT_ALIGN",
trx.tx_idle.eq(0), trx.tx_idle.eq(0),
@ -108,47 +100,39 @@ class LiteSATAPHYCtrl(Module):
align_timeout.ce.eq(1), align_timeout.ce.eq(1),
If(align_detect & ~trx.rx_idle, If(align_detect & ~trx.rx_idle,
NextState("SEND_ALIGN") NextState("SEND_ALIGN")
).Elif(align_timeout.reached, )
NextState("RESET")
),
) )
fsm.act("SEND_ALIGN", fsm.act("SEND_ALIGN",
trx.tx_idle.eq(0), trx.tx_idle.eq(0),
trx.rx_align.eq(1), trx.rx_align.eq(1),
align_timeout.ce.eq(1),
source.data.eq(primitives["ALIGN"]), source.data.eq(primitives["ALIGN"]),
source.charisk.eq(0b0001), source.charisk.eq(0b0001),
If(non_align_cnt == 3, If(sink.stb,
NextState("READY") If(sink.data[0:8] == 0x7C,
non_align_counter.ce.eq(1)
).Else(
non_align_counter.reset.eq(1)
)
), ),
If(non_align_counter.value == 3,
NextState("READY")
)
) )
fsm.act("READY", fsm.act("READY",
trx.tx_idle.eq(0), trx.tx_idle.eq(0),
trx.rx_align.eq(1), trx.rx_align.eq(1),
source.data.eq(primitives["SYNC"]), source.data.eq(primitives["SYNC"]),
source.charisk.eq(0b0001), source.charisk.eq(0b0001),
If(trx.rx_idle,
NextState("RESET")
),
self.ready.eq(1), self.ready.eq(1),
If(trx.rx_idle,
NextState("RESET"),
)
) )
reset_timeout = Timeout(clk_freq//16) self.comb += align_detect.eq(self.sink.stb &
self.submodules += reset_timeout (self.sink.data == primitives["ALIGN"]))
self.comb += [
reset_timeout.ce.eq(~self.ready),
self.need_reset.eq(reset_timeout.reached)
]
self.comb += \ def us(self, t):
align_detect.eq(self.sink.stb & clk_period_us = 1000000/self.clk_freq
(self.sink.data == primitives["ALIGN"])) return math.ceil(t/clk_period_us)
self.sync += \
If(fsm.ongoing("SEND_ALIGN"),
If(sink.stb,
If(sink.data[0:8] == 0x7C,
non_align_cnt.eq(non_align_cnt + 1)
).Else(
non_align_cnt.eq(0)
)
)
)

View file

@ -8,7 +8,7 @@ class LiteSATAPHYDatapathRX(Module):
# # # # # #
# width convertion (16 to 32) and byte alignment # width convertion (16 to 32) and byte alignment
byte_alignment = Signal() byte_alignment = Signal()
last_charisk = Signal(2) last_charisk = Signal(2)
last_data = Signal(16) last_data = Signal(16)
@ -38,13 +38,13 @@ class LiteSATAPHYDatapathRX(Module):
converter.reset.eq(converter.source.charisk[2:] != 0) converter.reset.eq(converter.source.charisk[2:] != 0)
] ]
# clock domain crossing # clock domain crossing
# (sata_gen3) 300MHz sata_rx clk to sys_clk # (sata_gen3) 300MHz sata_rx clk to sys_clk
# (sata_gen2) 150MHz sata_rx clk to sys_clk # (sata_gen2) 150MHz sata_rx clk to sys_clk
# (sata_gen1) 75MHz sata_rx clk to sys_clk # (sata_gen1) 75MHz sata_rx clk to sys_clk
# requirements: # requirements:
# due to the convertion ratio of 2, sys_clk need to be > sata_rx/2 # due to the convertion ratio of 2, sys_clk need to be > sata_rx/2
# source destination is always able to accept data (ack always 1) # source destination is always able to accept data (ack always 1)
fifo = AsyncFIFO(phy_description(32), 4) fifo = AsyncFIFO(phy_description(32), 4)
fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"}) fifo = RenameClockDomains(fifo, {"write": "sata_rx", "read": "sys"})
self.submodules += fifo self.submodules += fifo
@ -61,18 +61,18 @@ class LiteSATAPHYDatapathTX(Module):
# # # # # #
# clock domain crossing # clock domain crossing
# (sata_gen3) sys_clk to 300MHz sata_tx clk # (sata_gen3) sys_clk to 300MHz sata_tx clk
# (sata_gen2) sys_clk to 150MHz sata_tx clk # (sata_gen2) sys_clk to 150MHz sata_tx clk
# (sata_gen1) sys_clk to 75MHz sata_tx clk # (sata_gen1) sys_clk to 75MHz sata_tx clk
# requirements: # requirements:
# source destination is always able to accept data (ack always 1) # source destination is always able to accept data (ack always 1)
fifo = AsyncFIFO(phy_description(32), 4) fifo = AsyncFIFO(phy_description(32), 4)
fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"}) fifo = RenameClockDomains(fifo, {"write": "sys", "read": "sata_tx"})
self.submodules += fifo self.submodules += fifo
self.comb += Record.connect(sink, fifo.sink) self.comb += Record.connect(sink, fifo.sink)
# width convertion (32 to 16) # width convertion (32 to 16)
converter = Converter(phy_description(32), converter = Converter(phy_description(32),
phy_description(16), phy_description(16),
reverse=False) reverse=False)
@ -143,7 +143,7 @@ class LiteSATAPHYDatapath(Module):
# # # # # #
# TX path # TX path
align_inserter = LiteSATAPHYAlignInserter(ctrl) align_inserter = LiteSATAPHYAlignInserter(ctrl)
mux = Multiplexer(phy_description(32), 2) mux = Multiplexer(phy_description(32), 2)
tx = LiteSATAPHYDatapathTX() tx = LiteSATAPHYDatapathTX()
@ -157,7 +157,7 @@ class LiteSATAPHYDatapath(Module):
Record.connect(tx.source, trx.sink) Record.connect(tx.source, trx.sink)
] ]
# RX path # RX path
rx = LiteSATAPHYDatapathRX() rx = LiteSATAPHYDatapathRX()
demux = Demultiplexer(phy_description(32), 2) demux = Demultiplexer(phy_description(32), 2)
align_remover = LiteSATAPHYAlignRemover() align_remover = LiteSATAPHYAlignRemover()

View file

@ -3,15 +3,17 @@ from misoclib.mem.litesata.common import *
class K7LiteSATAPHYCRG(Module): class K7LiteSATAPHYCRG(Module):
def __init__(self, pads, gtx, revision, clk_freq): def __init__(self, pads, gtx, revision, clk_freq):
self.reset = Signal() self.tx_reset = Signal()
self.rx_reset = Signal()
self.ready = Signal() self.ready = Signal()
self.clock_domains.cd_sata_tx = ClockDomain() self.clock_domains.cd_sata_tx = ClockDomain()
self.clock_domains.cd_sata_rx = ClockDomain() self.clock_domains.cd_sata_rx = ClockDomain()
# CPLL # CPLL
# (sata_gen3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps # (sata_gen3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps
# (sata_gen2 & sata_gen1) VCO still @ 3 GHz, Line rate is decreased with output dividers. # (sata_gen2 & sata_gen1) VCO still @ 3 GHz, Line rate is
# decreased with output dividers.
refclk = Signal() refclk = Signal()
self.specials += Instance("IBUFDS_GTE2", self.specials += Instance("IBUFDS_GTE2",
i_CEB=0, i_CEB=0,
@ -21,19 +23,19 @@ class K7LiteSATAPHYCRG(Module):
) )
self.comb += gtx.gtrefclk0.eq(refclk) self.comb += gtx.gtrefclk0.eq(refclk)
# TX clocking # TX clocking
# (sata_gen3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits) # (sata_gen3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits)
# (sata_gen2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits) # (sata_gen2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits)
# (sata_gen1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits) # (sata_gen1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits)
mmcm_reset = Signal() mmcm_reset = Signal()
mmcm_locked = Signal() mmcm_locked = Signal()
mmcm_fb = Signal() mmcm_fb = Signal()
mmcm_clk_i = Signal() mmcm_clk_i = Signal()
mmcm_clk0_o = Signal() mmcm_clk0_o = Signal()
mmcm_div_config = { mmcm_div_config = {
"sata_gen1": 16.0, "sata_gen1": 16.0,
"sata_gen2": 8.0, "sata_gen2": 8.0,
"sata_gen3": 4.0 "sata_gen3": 4.0
} }
mmcm_div = mmcm_div_config[revision] mmcm_div = mmcm_div_config[revision]
self.specials += [ self.specials += [
@ -60,10 +62,10 @@ class K7LiteSATAPHYCRG(Module):
gtx.txusrclk2.eq(self.cd_sata_tx.clk) gtx.txusrclk2.eq(self.cd_sata_tx.clk)
] ]
# RX clocking # RX clocking
# (sata_gen3) sata_rx recovered clk @ 300MHz from GTX RXOUTCLK # (sata_gen3) sata_rx recovered clk @ 300MHz from GTX RXOUTCLK
# (sata_gen2) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK # (sata_gen2) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
# (sata_gen1) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK # (sata_gen1) sata_rx recovered clk @ 150MHz from GTX RXOUTCLK
self.specials += [ self.specials += [
Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk), Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk),
] ]
@ -72,85 +74,154 @@ class K7LiteSATAPHYCRG(Module):
gtx.rxusrclk2.eq(self.cd_sata_rx.clk) gtx.rxusrclk2.eq(self.cd_sata_rx.clk)
] ]
# Configuration Reset # Configuration Reset
# After configuration, GTX's resets have to stay low for at least 500ns # After configuration, GTX's resets have to stay low for at least 500ns
# See AR43482 # See AR43482
reset_en = Signal() startup_cycles = math.ceil(500*clk_freq/1000000000)
clk_period_ns = 1000000000/clk_freq startup_wait = Timeout(startup_cycles)
reset_en_cnt_max = math.ceil(500/clk_period_ns) self.submodules += startup_wait
reset_en_cnt = Signal(max=reset_en_cnt_max, reset=reset_en_cnt_max-1) self.comb += [
self.sync += \ startup_wait.reset.eq(self.tx_reset | self.rx_reset),
If(self.reset, startup_wait.ce.eq(1)
reset_en_cnt.eq(reset_en_cnt.reset) ]
).Elif(~reset_en,
reset_en_cnt.eq(reset_en_cnt-1)
)
self.comb += reset_en.eq(reset_en_cnt == 0)
# TX Reset FSM # TX Startup FSM
tx_reset_fsm = InsertReset(FSM(reset_state="IDLE")) self.tx_ready = Signal()
self.submodules += tx_reset_fsm tx_startup_fsm = InsertReset(FSM(reset_state="IDLE"))
self.comb += tx_reset_fsm.reset.eq(self.reset) self.submodules += tx_startup_fsm
tx_reset_fsm.act("IDLE", # Wait 500ns of AR43482
If(reset_en, tx_startup_fsm.act("IDLE",
NextState("RESET_GTX"), If(startup_wait.reached,
NextState("RESET_ALL"),
) )
) )
tx_reset_fsm.act("RESET_GTX", # Reset CPLL, MMCM, GTX
tx_startup_fsm.act("RESET_ALL",
gtx.cpllreset.eq(1),
mmcm_reset.eq(1),
gtx.gttxreset.eq(1), gtx.gttxreset.eq(1),
If(gtx.cplllock & mmcm_locked, NextState("RELEASE_CPLL"),
)
# Release CPLL reset and wait for lock
tx_startup_fsm.act("RELEASE_CPLL",
mmcm_reset.eq(1),
gtx.gttxreset.eq(1),
If(gtx.cplllock,
NextState("RELEASE_MMCM"),
)
)
# Release MMCM reset and wait for lock
tx_startup_fsm.act("RELEASE_MMCM",
gtx.gttxreset.eq(1),
If(mmcm_locked,
NextState("RELEASE_GTX") NextState("RELEASE_GTX")
) )
) )
tx_reset_fsm.act("RELEASE_GTX", # Release GTX reset and wait for GTX resetdone
# (from UG476, GTX is reseted on falling edge
# of gttxreset)
tx_startup_fsm.act("RELEASE_GTX",
gtx.txuserrdy.eq(1), gtx.txuserrdy.eq(1),
If(gtx.txresetdone, If(gtx.txresetdone,
NextState("READY") NextState("READY")
) )
) )
tx_reset_fsm.act("READY", # Start Delay alignment (Pulse)
gtx.txuserrdy.eq(1) tx_startup_fsm.act("ALIGN",
gtx.txuserrdy.eq(1),
gtx.txdlyreset.eq(1),
NextState("WAIT_ALIGN")
) )
# Wait Delay alignment
# RX Reset FSM tx_startup_fsm.act("WAIT_ALIGN",
rx_reset_fsm = InsertReset(FSM(reset_state="IDLE")) gtx.txuserrdy.eq(1),
self.submodules += rx_reset_fsm If(gtx.txdlyresetdone,
self.comb += rx_reset_fsm.reset.eq(self.reset)
rx_reset_fsm.act("IDLE",
If(reset_en,
NextState("RESET_GTX"),
)
)
rx_reset_fsm.act("RESET_GTX",
gtx.gtrxreset.eq(1),
If(gtx.cplllock & mmcm_locked,
NextState("RELEASE_GTX")
)
)
rx_reset_fsm.act("RELEASE_GTX",
gtx.rxuserrdy.eq(1),
If(gtx.rxresetdone,
NextState("READY") NextState("READY")
) )
) )
rx_reset_fsm.act("READY", tx_startup_fsm.act("READY",
gtx.rxuserrdy.eq(1) gtx.txuserrdy.eq(1),
self.tx_ready.eq(1)
) )
# Ready tx_ready_timeout = Timeout(1*clk_freq//1000)
self.tx_ready = tx_reset_fsm.ongoing("READY") self.submodules += tx_ready_timeout
self.rx_ready = rx_reset_fsm.ongoing("READY") self.comb += [
tx_ready_timeout.reset.eq(self.tx_reset | self.tx_ready),
tx_ready_timeout.ce.eq(~self.tx_ready),
tx_startup_fsm.reset.eq(self.tx_reset | tx_ready_timeout.reached),
]
# RX Startup FSM
self.rx_ready = Signal()
rx_startup_fsm = InsertReset(FSM(reset_state="IDLE"))
self.submodules += rx_startup_fsm
cdr_stable = Timeout(2048)
self.submodules += cdr_stable
self.comb += cdr_stable.ce.eq(1),
# Wait 500ns of AR43482
rx_startup_fsm.act("IDLE",
cdr_stable.reset.eq(1),
If(startup_wait.reached,
NextState("RESET_GTX"),
)
)
# Reset GTX
rx_startup_fsm.act("RESET_GTX",
gtx.gtrxreset.eq(1),
NextState("WAIT_CPLL")
)
# Wait for CPLL lock
rx_startup_fsm.act("WAIT_CPLL",
gtx.gtrxreset.eq(1),
If(gtx.cplllock,
NextState("RELEASE_GTX"),
cdr_stable.reset.eq(1)
)
)
# Release GTX reset and wait for GTX resetdone
# (from UG476, GTX is reseted on falling edge
# of gttxreset)
rx_startup_fsm.act("RELEASE_GTX",
gtx.rxuserrdy.eq(1),
If(gtx.rxresetdone & cdr_stable.reached,
NextState("ALIGN")
)
)
# Start Delay alignment (Pulse)
rx_startup_fsm.act("ALIGN",
gtx.rxuserrdy.eq(1),
gtx.rxdlyreset.eq(1),
NextState("WAIT_ALIGN")
)
# Wait Delay alignment
rx_startup_fsm.act("WAIT_ALIGN",
gtx.rxuserrdy.eq(1),
If(gtx.rxdlyresetdone,
NextState("READY")
)
)
rx_startup_fsm.act("READY",
gtx.rxuserrdy.eq(1),
self.rx_ready.eq(1)
)
rx_ready_timeout = Timeout(1*clk_freq//1000)
self.submodules += rx_ready_timeout
self.comb += [
rx_ready_timeout.reset.eq(self.rx_reset | self.rx_ready),
rx_ready_timeout.ce.eq(~self.rx_ready),
rx_startup_fsm.reset.eq(self.rx_reset | rx_ready_timeout.reached),
]
# Ready
self.comb += self.ready.eq(self.tx_ready & self.rx_ready) self.comb += self.ready.eq(self.tx_ready & self.rx_ready)
# Reset PLL # Reset for SATA TX/RX clock domains
self.comb += gtx.cpllreset.eq(ResetSignal() | self.reset | ~reset_en)
# Reset MMCM
self.comb += mmcm_reset.eq(ResetSignal() | self.reset | ~gtx.cplllock)
# Reset for SATA TX/RX clock domains
self.specials += [ self.specials += [
AsyncResetSynchronizer(self.cd_sata_tx, ~self.tx_ready), AsyncResetSynchronizer(self.cd_sata_tx, ~(gtx.cplllock & mmcm_locked) | self.tx_reset),
AsyncResetSynchronizer(self.cd_sata_rx, ~self.rx_ready), AsyncResetSynchronizer(self.cd_sata_rx, ~gtx.cplllock | self.rx_reset),
] ]

View file

@ -21,23 +21,39 @@ class _RisingEdge(Module):
self.comb += o.eq(i & ~i_d) self.comb += o.eq(i & ~i_d)
class _LowPassFilter(Module):
def __init__(self, i, o, cycles):
i_d = Signal()
self.submodules.timeout = Timeout(cycles)
self.sync += [
i_d.eq(i),
If(self.timeout.reached,
o.eq(i_d)
)
]
self.comb += [
self.timeout.reset.eq(i != i_d),
self.timeout.ce.eq(1)
]
class K7LiteSATAPHYTRX(Module): class K7LiteSATAPHYTRX(Module):
def __init__(self, pads, revision): def __init__(self, pads, revision):
# Common signals # Common signals
# control # control
self.tx_idle = Signal() #i self.tx_idle = Signal() #i
self.tx_cominit_stb = Signal() #i self.tx_cominit_stb = Signal() #i
self.tx_cominit_ack = Signal() #o self.tx_cominit_ack = Signal() #o
self.tx_comwake_stb = Signal() #i self.tx_comwake_stb = Signal() #i
self.tx_comwake_ack = Signal() #o self.tx_comwake_ack = Signal() #o
self.rx_idle = Signal() #o self.rx_idle = Signal() #o
self.rx_align = Signal() #i self.rx_align = Signal() #i
self.rx_cominit_stb = Signal() #o self.rx_cominit_stb = Signal() #o
self.rx_comwake_stb = Signal() #o self.rx_comwake_stb = Signal() #o
# datapath # datapath
self.sink = Sink(phy_description(16)) self.sink = Sink(phy_description(16))
@ -53,15 +69,12 @@ class K7LiteSATAPHYTRX(Module):
# Receive Ports # Receive Ports
self.rxuserrdy = Signal() self.rxuserrdy = Signal()
self.rxalign = Signal()
# Receive Ports - 8b10b Decoder # Receive Ports - 8b10b Decoder
self.rxcharisk = Signal(2) self.rxcharisk = Signal(2)
self.rxdisperr = Signal(2)
# Receive Ports - RX Data Path interface # Receive Ports - RX Data Path interface
self.gtrxreset = Signal() self.gtrxreset = Signal()
self.pmarxreset = Signal()
self.rxdata = Signal(16) self.rxdata = Signal(16)
self.rxoutclk = Signal() self.rxoutclk = Signal()
self.rxusrclk = Signal() self.rxusrclk = Signal()
@ -72,6 +85,8 @@ class K7LiteSATAPHYTRX(Module):
# Receive Ports - RX PLL Ports # Receive Ports - RX PLL Ports
self.rxresetdone = Signal() self.rxresetdone = Signal()
self.rxdlyreset = Signal()
self.rxdlyresetdone = Signal()
# Receive Ports - RX Ports for SATA # Receive Ports - RX Ports for SATA
self.rxcominitdet = Signal() self.rxcominitdet = Signal()
@ -92,6 +107,8 @@ class K7LiteSATAPHYTRX(Module):
# Transmit Ports - TX PLL Ports # Transmit Ports - TX PLL Ports
self.txresetdone = Signal() self.txresetdone = Signal()
self.txdlyreset = Signal()
self.txdlyresetdone = Signal()
# Transmit Ports - TX Ports for PCI Express # Transmit Ports - TX Ports for PCI Express
self.txelecidle = Signal(reset=1) self.txelecidle = Signal(reset=1)
@ -100,8 +117,6 @@ class K7LiteSATAPHYTRX(Module):
self.txcomfinish = Signal() self.txcomfinish = Signal()
self.txcominit = Signal() self.txcominit = Signal()
self.txcomwake = Signal() self.txcomwake = Signal()
self.txrate = Signal(3)
self.rxcdrlock = Signal()
# Config at startup # Config at startup
div_config = { div_config = {
@ -125,7 +140,6 @@ class K7LiteSATAPHYTRX(Module):
self.tx_cominit_ack.eq(self.tx_cominit_stb & self.txcomfinish), self.tx_cominit_ack.eq(self.tx_cominit_stb & self.txcomfinish),
self.tx_comwake_ack.eq(self.tx_comwake_stb & self.txcomfinish), self.tx_comwake_ack.eq(self.tx_comwake_stb & self.txcomfinish),
self.rx_idle.eq(self.rxelecidle), self.rx_idle.eq(self.rxelecidle),
self.rxalign.eq(self.rx_align),
self.rx_cominit_stb.eq(self.rxcominitdet), self.rx_cominit_stb.eq(self.rxcominitdet),
self.rx_comwake_stb.eq(self.rxcomwakedet), self.rx_comwake_stb.eq(self.rxcomwakedet),
] ]
@ -150,16 +164,19 @@ class K7LiteSATAPHYTRX(Module):
txelecidle = Signal(reset=1) txelecidle = Signal(reset=1)
txcominit = Signal() txcominit = Signal()
txcomwake = Signal() txcomwake = Signal()
txrate = Signal(3) txdlyreset = Signal()
txdlyresetdone = Signal()
gttxreset = Signal()
self.specials += [ self.specials += [
MultiReg(self.txuserrdy, txuserrdy, "sata_tx"), MultiReg(self.txuserrdy, txuserrdy, "sata_tx"),
MultiReg(self.txelecidle, txelecidle, "sata_tx"), MultiReg(self.txelecidle, txelecidle, "sata_tx"),
MultiReg(self.txrate, txrate, "sata_tx") MultiReg(self.gttxreset, gttxreset, "sata_tx"),
] ]
self.submodules += [ self.submodules += [
_PulseSynchronizer(self.txcominit, "sys", txcominit, "sata_tx"), _PulseSynchronizer(self.txcominit, "sys", txcominit, "sata_tx"),
_PulseSynchronizer(self.txcomwake, "sys", txcomwake, "sata_tx"), _PulseSynchronizer(self.txcomwake, "sys", txcomwake, "sata_tx"),
_PulseSynchronizer(self.txdlyreset, "sys", txdlyreset, "sata_tx"),
] ]
# sata_tx clk --> sys clk # sata_tx clk --> sys clk
@ -168,6 +185,7 @@ class K7LiteSATAPHYTRX(Module):
self.specials += [ self.specials += [
MultiReg(txresetdone, self.txresetdone, "sys"), MultiReg(txresetdone, self.txresetdone, "sys"),
MultiReg(txdlyresetdone, self.txdlyresetdone, "sys"),
] ]
self.submodules += [ self.submodules += [
@ -176,43 +194,35 @@ class K7LiteSATAPHYTRX(Module):
# sys clk --> sata_rx clk # sys clk --> sata_rx clk
rxuserrdy = Signal() rxuserrdy = Signal()
rxdlyreset = Signal()
self.specials += [ self.specials += [
MultiReg(self.rxuserrdy, rxuserrdy, "sata_rx"), MultiReg(self.rxuserrdy, rxuserrdy, "sata_rx"),
] ]
self.submodules += [
_PulseSynchronizer(self.rxdlyreset, "sys", rxdlyreset, "sata_rx"),
]
# sata_rx clk --> sys clk # sata_rx clk --> sys clk
rxelecidle = Signal() rxelecidle = Signal()
rxelecidle_i = Signal() rxelecidle_i = Signal()
rxelecidle_cnt_i = Signal(9)
rxresetdone = Signal() rxresetdone = Signal()
rxcominitdet = Signal() rxcominitdet = Signal()
rxcomwakedet = Signal() rxcomwakedet = Signal()
rxratedone = Signal() rxratedone = Signal()
rxcdrlock = Signal() rxdlyresetdone = Signal()
self.specials += [ self.specials += [
MultiReg(rxelecidle, rxelecidle_i, "sys"), MultiReg(rxelecidle, rxelecidle_i, "sys"),
MultiReg(rxresetdone, self.rxresetdone, "sys"), MultiReg(rxresetdone, self.rxresetdone, "sys"),
MultiReg(rxcominitdet, self.rxcominitdet, "sys"), MultiReg(rxcominitdet, self.rxcominitdet, "sys"),
MultiReg(rxcomwakedet, self.rxcomwakedet, "sys"), MultiReg(rxcomwakedet, self.rxcomwakedet, "sys"),
MultiReg(rxcdrlock, self.rxcdrlock, "sys"), MultiReg(rxdlyresetdone, self.rxdlyresetdone, "sys"),
] ]
self.sync += [ rxelecidle_filter = _LowPassFilter(rxelecidle_i, self.rxelecidle, 256)
If(rxelecidle_i != self.rxelecidle, self.submodules += rxelecidle_filter
If(rxelecidle_cnt_i == 0,
self.rxelecidle.eq(rxelecidle_i),
rxelecidle_cnt_i.eq(255)
).Else(
rxelecidle_cnt_i.eq(rxelecidle_cnt_i-1)
)
).Else(
rxelecidle_cnt_i.eq(255)
)
]
self.rxbyteisaligned = Signal()
# QPLL input clock # QPLL input clock
self.qpllclk = Signal() self.qpllclk = Signal()
@ -230,7 +240,7 @@ class K7LiteSATAPHYTRX(Module):
# RX Byte and Word Alignment Attributes # RX Byte and Word Alignment Attributes
"p_ALIGN_COMMA_DOUBLE": "FALSE", "p_ALIGN_COMMA_DOUBLE": "FALSE",
"p_ALIGN_COMMA_ENABLE": ones(10), "p_ALIGN_COMMA_ENABLE": ones(10),
"p_ALIGN_COMMA_WORD": 2, "p_ALIGN_COMMA_WORD": 1,
"p_ALIGN_MCOMMA_DET": "TRUE", "p_ALIGN_MCOMMA_DET": "TRUE",
"p_ALIGN_MCOMMA_VALUE": 0b1010000011, "p_ALIGN_MCOMMA_VALUE": 0b1010000011,
"p_ALIGN_PCOMMA_DET": "TRUE", "p_ALIGN_PCOMMA_DET": "TRUE",
@ -263,9 +273,9 @@ class K7LiteSATAPHYTRX(Module):
"p_CLK_CORRECT_USE": "FALSE", "p_CLK_CORRECT_USE": "FALSE",
"p_CLK_COR_SEQ_2_ENABLE": ones(4), "p_CLK_COR_SEQ_2_ENABLE": ones(4),
"p_CLK_COR_SEQ_2_1": 0b0100000000, "p_CLK_COR_SEQ_2_1": 0b0100000000,
"p_CLK_COR_SEQ_2_2": 0, "p_CLK_COR_SEQ_2_2": 0b0000000000,
"p_CLK_COR_SEQ_2_3": 0, "p_CLK_COR_SEQ_2_3": 0b0000000000,
"p_CLK_COR_SEQ_2_4": 0, "p_CLK_COR_SEQ_2_4": 0b0000000000,
# RX Channel Bonding Attributes # RX Channel Bonding Attributes
"p_CHAN_BOND_KEEP_ALIGN": "FALSE", "p_CHAN_BOND_KEEP_ALIGN": "FALSE",
@ -314,7 +324,7 @@ class K7LiteSATAPHYTRX(Module):
"p_RX_CM_TRIM": 0b010, "p_RX_CM_TRIM": 0b010,
"p_RX_DEBUG_CFG": 0, "p_RX_DEBUG_CFG": 0,
"p_RX_OS_CFG": 0b10000000, "p_RX_OS_CFG": 0b10000000,
"p_TERM_RCAL_CFG": 0, "p_TERM_RCAL_CFG": 0b10000,
"p_TERM_RCAL_OVRD": 0, "p_TERM_RCAL_OVRD": 0,
"p_TST_RSV": 0, "p_TST_RSV": 0,
"p_RX_CLK25_DIV": 6, "p_RX_CLK25_DIV": 6,
@ -330,8 +340,8 @@ class K7LiteSATAPHYTRX(Module):
# RX Buffer Attributes # RX Buffer Attributes
"p_RXBUF_ADDR_MODE": "FAST", "p_RXBUF_ADDR_MODE": "FAST",
"p_RXBUF_EIDLE_HI_CNT": 0b1000, "p_RXBUF_EIDLE_HI_CNT": 0b1000,
"p_RXBUF_EIDLE_LO_CNT": 0, "p_RXBUF_EIDLE_LO_CNT": 0b0000,
"p_RXBUF_EN": "TRUE", "p_RXBUF_EN": "FALSE",
"p_RX_BUFFER_CFG": 0, "p_RX_BUFFER_CFG": 0,
"p_RXBUF_RESET_ON_CB_CHANGE": "TRUE", "p_RXBUF_RESET_ON_CB_CHANGE": "TRUE",
"p_RXBUF_RESET_ON_COMMAALIGN": "FALSE", "p_RXBUF_RESET_ON_COMMAALIGN": "FALSE",
@ -397,7 +407,7 @@ class K7LiteSATAPHYTRX(Module):
"p_TRANS_TIME_RATE": 0x0e, "p_TRANS_TIME_RATE": 0x0e,
# TX Buffer Attributes # TX Buffer Attributes
"p_TXBUF_EN": "TRUE", "p_TXBUF_EN": "FALSE",
"p_TXBUF_RESET_ON_RATE_CHANGE": "TRUE", "p_TXBUF_RESET_ON_RATE_CHANGE": "TRUE",
"p_TXDLY_CFG": 0x1f, "p_TXDLY_CFG": 0x1f,
"p_TXDLY_LCFG": 0x030, "p_TXDLY_LCFG": 0x030,
@ -405,7 +415,7 @@ class K7LiteSATAPHYTRX(Module):
"p_TXPH_CFG": 0x0780, "p_TXPH_CFG": 0x0780,
"p_TXPHDLY_CFG": 0x084020, "p_TXPHDLY_CFG": 0x084020,
"p_TXPH_MONITOR_SEL": 0, "p_TXPH_MONITOR_SEL": 0,
"p_TX_XCLK_SEL": "TXOUT", "p_TX_XCLK_SEL": "TXUSR",
# FPGA TX Interface Attributes # FPGA TX Interface Attributes
"p_TX_DATA_WIDTH": 20, "p_TX_DATA_WIDTH": 20,
@ -569,7 +579,7 @@ class K7LiteSATAPHYTRX(Module):
# Receive Ports - CDR Ports # Receive Ports - CDR Ports
i_RXCDRFREQRESET=0, i_RXCDRFREQRESET=0,
i_RXCDRHOLD=0, i_RXCDRHOLD=0,
o_RXCDRLOCK=rxcdrlock, #o_RXCDRLOCK=,
i_RXCDROVRDEN=0, i_RXCDROVRDEN=0,
i_RXCDRRESET=0, i_RXCDRRESET=0,
i_RXCDRRESETRSV=0, i_RXCDRRESETRSV=0,
@ -595,7 +605,7 @@ class K7LiteSATAPHYTRX(Module):
i_RXPRBSCNTRESET=0, i_RXPRBSCNTRESET=0,
# Receive Ports - RX Equalizer Ports # Receive Ports - RX Equalizer Ports
i_RXDFEXYDEN=0, i_RXDFEXYDEN=1,
i_RXDFEXYDHOLD=0, i_RXDFEXYDHOLD=0,
i_RXDFEXYDOVRDEN=0, i_RXDFEXYDOVRDEN=0,
@ -610,12 +620,12 @@ class K7LiteSATAPHYTRX(Module):
# Receive Ports - RX Buffer Bypass Ports # Receive Ports - RX Buffer Bypass Ports
i_RXBUFRESET=0, i_RXBUFRESET=0,
#o_RXBUFSTATUS=, #o_RXBUFSTATUS=,
i_RXDDIEN=0, i_RXDDIEN=1,
i_RXDLYBYPASS=1, i_RXDLYBYPASS=0,
i_RXDLYEN=0, i_RXDLYEN=0,
i_RXDLYOVRDEN=0, i_RXDLYOVRDEN=0,
i_RXDLYSRESET=0, i_RXDLYSRESET=rxdlyreset,
#o_RXDLYSRESETDONE=0, o_RXDLYSRESETDONE=rxdlyresetdone,
i_RXPHALIGN=0, i_RXPHALIGN=0,
#o_RXPHALIGNDONE=, #o_RXPHALIGNDONE=,
i_RXPHALIGNEN=0, i_RXPHALIGNEN=0,
@ -627,7 +637,7 @@ class K7LiteSATAPHYTRX(Module):
#o_RXSTATUS=, #o_RXSTATUS=,
# Receive Ports - RX Byte and Word Alignment Ports # Receive Ports - RX Byte and Word Alignment Ports
o_RXBYTEISALIGNED=self.rxbyteisaligned, #o_RXBYTEISALIGNED=,
#o_RXBYTEREALIGN=, #o_RXBYTEREALIGN=,
#o_RXCOMMADET=, #o_RXCOMMADET=,
i_RXCOMMADETEN=1, i_RXCOMMADETEN=1,
@ -651,7 +661,7 @@ class K7LiteSATAPHYTRX(Module):
i_RXDFEAGCOVRDEN=0, i_RXDFEAGCOVRDEN=0,
i_RXDFECM1EN=0, i_RXDFECM1EN=0,
i_RXDFELFHOLD=0, i_RXDFELFHOLD=0,
i_RXDFELFOVRDEN=1, i_RXDFELFOVRDEN=0,
i_RXDFELPMRESET=0, i_RXDFELPMRESET=0,
i_RXDFETAP2HOLD=0, i_RXDFETAP2HOLD=0,
i_RXDFETAP2OVRDEN=0, i_RXDFETAP2OVRDEN=0,
@ -699,7 +709,7 @@ class K7LiteSATAPHYTRX(Module):
i_GTRXRESET=self.gtrxreset, i_GTRXRESET=self.gtrxreset,
i_RXOOBRESET=0, i_RXOOBRESET=0,
i_RXPCSRESET=0, i_RXPCSRESET=0,
i_RXPMARESET=self.pmarxreset, i_RXPMARESET=0,
# Receive Ports - RX Margin Analysis ports # Receive Ports - RX Margin Analysis ports
i_RXLPMEN=0, i_RXLPMEN=0,
@ -750,7 +760,7 @@ class K7LiteSATAPHYTRX(Module):
# TX Initialization and Reset Ports # TX Initialization and Reset Ports
i_CFGRESET=0, i_CFGRESET=0,
i_GTTXRESET=self.gttxreset, i_GTTXRESET=gttxreset,
#o_PCSRSVDOUT=, #o_PCSRSVDOUT=,
i_TXUSERRDY=txuserrdy, i_TXUSERRDY=txuserrdy,
@ -769,19 +779,19 @@ class K7LiteSATAPHYTRX(Module):
# Transmit Ports - PCI Express Ports # Transmit Ports - PCI Express Ports
i_TXELECIDLE=txelecidle, i_TXELECIDLE=txelecidle,
i_TXMARGIN=0, i_TXMARGIN=0,
i_TXRATE=txrate, i_TXRATE=0,
i_TXSWING=0, i_TXSWING=0,
# Transmit Ports - Pattern Generator Ports # Transmit Ports - Pattern Generator Ports
i_TXPRBSFORCEERR=0, i_TXPRBSFORCEERR=0,
# Transmit Ports - TX Buffer Bypass Ports # Transmit Ports - TX Buffer Bypass Ports
i_TXDLYBYPASS=1, i_TXDLYBYPASS=0,
i_TXDLYEN=0, i_TXDLYEN=0,
i_TXDLYHOLD=0, i_TXDLYHOLD=0,
i_TXDLYOVRDEN=0, i_TXDLYOVRDEN=0,
i_TXDLYSRESET=0, i_TXDLYSRESET=txdlyreset,
#o_TXDLYSRESETDONE=, o_TXDLYSRESETDONE=txdlyresetdone,
i_TXDLYUPDOWN=0, i_TXDLYUPDOWN=0,
i_TXPHALIGN=0, i_TXPHALIGN=0,
#o_TXPHALIGNDONE=txphaligndone, #o_TXPHALIGNDONE=txphaligndone,
@ -815,7 +825,7 @@ class K7LiteSATAPHYTRX(Module):
o_TXOUTCLK=self.txoutclk, o_TXOUTCLK=self.txoutclk,
#o_TXOUTCLKFABRIC=, #o_TXOUTCLKFABRIC=,
#o_TXOUTCLKPCS=, #o_TXOUTCLKPCS=,
i_TXOUTCLKSEL=0b11, # ?? i_TXOUTCLKSEL=0b11,
#o_TXRATEDONE=, #o_TXRATEDONE=,
# Transmit Ports - TX Gearbox Ports # Transmit Ports - TX Gearbox Ports
i_TXCHARISK=self.txcharisk, i_TXCHARISK=self.txcharisk,