From d55db1688bffdc94be304b2a069b9ed2a2839fa8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 23 Sep 2014 15:58:34 +0200 Subject: [PATCH] add SATAGTX with RX/TX clocking and reset (no DRP for now) --- lib/sata/k7satagtx.py | 139 ++++++++++++++++++++++++++++++++++++++++-- lib/sata/k7sataphy.py | 6 +- 2 files changed, 137 insertions(+), 8 deletions(-) diff --git a/lib/sata/k7satagtx.py b/lib/sata/k7satagtx.py index 102169a1..a5b9264f 100644 --- a/lib/sata/k7satagtx.py +++ b/lib/sata/k7satagtx.py @@ -848,8 +848,8 @@ class GTXE2_COMMON(Module): i_GTGREFCLK=0, i_GTNORTHREFCLK0=0, i_GTNORTHREFCLK1=0, - i_GTREFCLK0=, - i_GTREFCLK1=0, + i_GTREFCLK0=self.refclk0, + i_GTREFCLK1=self.refclk1, i_GTSOUTHREFCLK0=0, i_GTSOUTHREFCLK1=0, @@ -859,8 +859,8 @@ class GTXE2_COMMON(Module): #o_QPLLLOCK=, i_QPLLLOCKDETCLK=0, i_QPLLLOCKEN=1, - o_QPLLOUTCLK=, - o_QPLLOUTREFCLK=, + o_QPLLOUTCLK=self.qplloutclk, + o_QPLLOUTREFCLK=self.qplloutrefclk, i_QPLLOUTRESET=0, i_QPLLPD=0, #o_QPLLREFCLKLOST=, @@ -878,3 +878,134 @@ class GTXE2_COMMON(Module): i_PMARSVD=0, i_RCALENB=1 ) + +class SATAGTX(Module): + def __init__(self, pads): + self.reset = Signal() + self.transceiver_reset = Signal() + + self.cd_sata_tx = ClockDomain() + self.cd_sata_rx = ClockDomain() + + self.channel = GTXE2_CHANNEL(pads, "SATA_III") + self.common = GTXE2_COMMON(16) + + # TX clocking + refclk = Signal() + self.specials += Instance("IBUFDS_GTE2", + i_I=pads.refclk_p, + i_IB=pads.refclk_n, + o_O=refclk + ) + + # refclk--> BUFG-->MMCM-->BUFG-->SATA TX clock + mmcm_reset = Signal() + mmcm_locked = Signal() + mmcm_drp = DRP() + mmcm_fb = Signal() + mmcm_clk_i = Signal() + mmcm_clk_o = Signal() + self.specials += [ + Instance("BUFG", i_I=refclk, o_O=mmcm_clk_i), + Instance("MMCME2_ADV", + p_BANDWIDTH="HIGH", p_COMPENSATION="ZHOLD", i_RST=mmcm_reset, o_LOCKED=mmcm_locked, + + # DRP + i_DCLK=mmcm_drp.clk, i_DEN=mmcm_drp.den, o_DRDY=mmcm_drp.rdy, i_DWE=mmcm_drp.we, + i_DADDR=mmcm_drp.addr, i_DI=mmcm_drp.di, i_DO=mmcm_drp.do, + + # VCO + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=5.0, + p_CLKFBOUT_MULT_F=8.000, CLKFBOUT_PHASE=0.000, p_DIVCLK_DIVIDE=2, + i_CLKIN1=mmcm_clk_i, i_CLKFBIN=mmcm_fb, o_CLKFBOUT=mmcm_fb, + + # CLK0 + p_CLKOUT0_DIVIDE_F=4.000, p_CLKOUT0_PHASE=0.000, o_CLKOUT0=mmcm_clk_o, + ), + Instance("BUFG", i_I=mmcm_clk, o_O=self.cd_sata_tx.clk), + ] + + # refclk --> GTXE2_COMMON(QPLL)-->GTXE2_CHANNEL-->transceiver clock + self.comb += [ + self.common.refclk0.eq(refclk), + self.channel.qpllclk.eq(self.common.qplloutclk), + self.channel.qpllrefclk.eq(self.common.qplloutrefclk), + ] + + # RX clocking + self.specials += [ + Instance("BUFG", i_I=self.channel.rxoutclk, o_O=self.cd_sata_rx.clk), + ] + self.comb += [ + self.channel.RXUSRCLK.eq(self.cd_sata_rx.clk), + self.channel.RXUSRCLK2.eq(self.cd_sata_rx.clk) + ] + + # TX buffer bypass logic + self.comb += [ + self.txphdlyreset.eq(0), + self.txphalignen.eq(0), + self.txdlyen.eq(0), + self.txphalign.eq(0), + self.txphinit.eq(0) + ] + + # once channel TX is reseted, reset TX buffer + txbuffer_reseted = Signal() + self.sync += \ + If(self.channel.txresetdone, + If(~txbuffer_reseted, + self.channel.txdlyreset.eq(1), + txbuffer_reseted.eq(1) + ).Else( + self.channel.txdlyreset.eq(0) + ) + ) + + # RX buffer bypass logic + self.comb += [ + self.channel.rxphdlyreset.eq(0), + self.channel.rxdlyen.eq(0), + self.channel.rxphalign.eq(0), + self.channel.rxphalignen.eq(0), + ] + + # wait till CDR is locked + cdr_cnt = Signal(14, reset=0b10011100010000) + cdr_locked = Signal() + self.sync += \ + If(cdr_cnt != 0, + cdr_cnt.eq(cdr_cnt - 1) + ).Else( + cdr_locked.eq(1) + ) + + # once CDR is locked and channel RX reseted, reset RX buffer + rxbuffer_reseted = Signal() + self.sync += \ + If(cdr_locked & self.channel.rxresetdone, + If(~rxbuffer_reseted, + self.channel.rxdlyreset.eq(1), + rxbuffer_reseted.eq(1) + ).Else( + self.channel.rxdlyreset.eq(0) + ) + ) + + # Reset + self.comb += [ + # GTXE2 + self.channel.rxuserrdy.eq(self.channel.cplllock), + self.channel.txuserrdy.eq(self.channel.cplllock), + # TX + self.channel.gttxreset.eq(self.reset | self.transceiver_reset | ~self.channel.cplllock), + # RX + self.channel.gtrxreset.eq(self.reset | self.transceiver_reset | ~self.channel.cplllock), + # PLL + self.channel.pllreset.eq(self.reset) + ] + # SATA TX/RX clock domains + self.specials += [ + AsyncResetSynchronizer(self.cd_sata_tx, ~mmcm_locked | ~self.channel.txresetdone), + AsyncResetSynchronizer(self.cd_sata_rx, ~self.channel.cplllock | ~self.channel.rxphaligndone), + ] diff --git a/lib/sata/k7sataphy.py b/lib/sata/k7sataphy.py index d40bfb53..a2cb6c75 100644 --- a/lib/sata/k7sataphy.py +++ b/lib/sata/k7sataphy.py @@ -1,8 +1,6 @@ from migen.fhdl.std import * - -from lib.sata import GTXE2_CHANNEL, GTXE2_COMMON +from lib.sata.k7satagtx import SATAGTX class K7SATAPHY(Module): def __init__(self, pads): - self.submodules.gtxe2_channel = GTXE2_CHANNEL(pads, "SATA_III") - self.submodules.gtxe2_common = GTXE2_COMMON(16) + self.sata_gtx = SATAGTX(pads) -- 2.30.2