From: Florent Kermarrec Date: Sat, 27 Sep 2014 13:34:28 +0000 (+0200) Subject: reorganize code X-Git-Tag: 24jan2021_ls180~2572^2~191 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c27f24c4c09f23157c5950a3fbddd7c0414de433;p=litex.git reorganize code - use sys_clk of 166.66MHz and using it instead of sata clk. - rename clocking to CRG since it also handles resets. - create datapath and move code from gtx. --- diff --git a/lib/sata/k7sataphy/__init__.py b/lib/sata/k7sataphy/__init__.py index a268d0c7..d985b0cc 100644 --- a/lib/sata/k7sataphy/__init__.py +++ b/lib/sata/k7sataphy/__init__.py @@ -2,10 +2,11 @@ from migen.fhdl.std import * from migen.flow.actor import Sink, Source from lib.sata.k7sataphy.std import * -from lib.sata.k7sataphy.gtx import K7SATAPHYGTX, K7SATAPHYRXAlign -from lib.sata.k7sataphy.gtx import K7SATAPHYRXConvert, K7SATAPHYTXConvert -from lib.sata.k7sataphy.clocking import K7SATAPHYClocking +from lib.sata.k7sataphy.gtx import K7SATAPHYGTX +from lib.sata.k7sataphy.crg import K7SATAPHYCRG from lib.sata.k7sataphy.ctrl import K7SATAPHYHostCtrl, K7SATAPHYDeviceCtrl +from lib.sata.k7sataphy.datapath import K7SATAPHYRXAlign +from lib.sata.k7sataphy.datapath import K7SATAPHYRXConvert, K7SATAPHYTXConvert class K7SATAPHY(Module): def __init__(self, pads, clk_freq, host=True,): @@ -17,7 +18,7 @@ class K7SATAPHY(Module): gtx.rxrate.eq(0b000), gtx.txrate.eq(0b000), ] - clocking = K7SATAPHYClocking(pads, gtx, clk_freq) + clocking = K7SATAPHYCRG(pads, gtx, clk_freq) rxalign = K7SATAPHYRXAlign() rxconvert = K7SATAPHYRXConvert() txconvert = K7SATAPHYTXConvert() diff --git a/lib/sata/k7sataphy/clocking.py b/lib/sata/k7sataphy/clocking.py deleted file mode 100644 index 6a0497d5..00000000 --- a/lib/sata/k7sataphy/clocking.py +++ /dev/null @@ -1,184 +0,0 @@ -from math import ceil - -from migen.fhdl.std import * -from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.fsm import FSM, NextState - -from lib.sata.k7sataphy.std import * - -class K7SATAPHYReconfig(Module): - def __init__(self, channel_drp, mmcm_drp): - self.speed = Signal(3) - ### - speed_r = Signal(3) - speed_change = Signal() - self.sync += speed_r.eq(self.speed) - self.comb += speed_change.eq(self.speed != speed_r) - - drp_sel = Signal() - drp = DRPBus() - self.comb += \ - If(drp_sel, - drp.connect(mmcm_drp) - ).Else( - drp.connect(channel_drp) - ) - -class K7SATAPHYClocking(Module): - def __init__(self, pads, gtx, clk_freq): - self.reset = Signal() - - self.clock_domains.cd_sata = ClockDomain() - self.clock_domains.cd_sata_tx = ClockDomain() - self.clock_domains.cd_sata_rx = ClockDomain() - - # CPLL - # (SATA3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps - # (SATA2 & SATA1) VCO still @ 3 GHz, Line rate is decreased with output divivers. - # When changing rate, reconfiguration of the CPLL over DRP is needed to: - # - update the output divider - # - update the equalizer configuration (specific for each line rate). - refclk = Signal() - self.specials += Instance("IBUFDS_GTE2", - i_CEB=0, - i_I=pads.refclk_p, - i_IB=pads.refclk_n, - o_O=refclk - ) - self.comb += gtx.gtrefclk0.eq(refclk) - - # TX clocking - # (SATA3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits), sata clk @ 150MHz (32-bits) - # (SATA2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits), sata clk @ 75MHz (32-bits) - # (SATA1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits), sata clk @ 37.5MHz (32-bits) - # When changing rate, reconfiguration of the MMCM is needed to update the output divider. - mmcm_reset = Signal() - mmcm_locked = Signal() - mmcm_drp = DRPBus() - mmcm_fb = Signal() - mmcm_clk_i = Signal() - mmcm_clk0_o = Signal() - mmcm_clk1_o = Signal() - self.specials += [ - Instance("BUFG", i_I=gtx.txoutclk, 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.en, o_DRDY=mmcm_drp.rdy, i_DWE=mmcm_drp.we, - i_DADDR=mmcm_drp.addr, i_DI=mmcm_drp.di, o_DO=mmcm_drp.do, - - # VCO - p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=6.666, - p_CLKFBOUT_MULT_F=8.000, p_CLKFBOUT_PHASE=0.000, p_DIVCLK_DIVIDE=1, - 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_clk0_o, - - # CLK1 - p_CLKOUT1_DIVIDE=8, p_CLKOUT1_PHASE=0.000, o_CLKOUT1=mmcm_clk1_o, - ), - Instance("BUFG", i_I=mmcm_clk0_o, o_O=self.cd_sata_tx.clk), - Instance("BUFG", i_I=mmcm_clk1_o, o_O=self.cd_sata.clk), - ] - self.comb += [ - gtx.txusrclk.eq(self.cd_sata_tx.clk), - gtx.txusrclk2.eq(self.cd_sata_tx.clk) - ] - - # RX clocking - # (SATA3) sata_rx recovered clk @ 300MHz from CPLL RXOUTCLK - # (SATA2) sata_rx recovered clk @ 150MHz from CPLL RXOUTCLK - # (SATA1) sata_rx recovered clk @ 150MHz from CPLL RXOUTCLK - self.specials += [ - Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk), - ] - self.comb += [ - gtx.rxusrclk.eq(self.cd_sata_rx.clk), - gtx.rxusrclk2.eq(self.cd_sata_rx.clk) - ] - - # TX buffer bypass logic - self.comb += [ - gtx.txphdlyreset.eq(0), - gtx.txphalignen.eq(0), - gtx.txdlyen.eq(0), - gtx.txphalign.eq(0), - gtx.txphinit.eq(0) - ] - - # RX buffer bypass logic - self.comb += [ - gtx.rxphdlyreset.eq(0), - gtx.rxdlyen.eq(0), - gtx.rxphalign.eq(0), - gtx.rxphalignen.eq(0), - ] - - - # Configuration Reset - # After configuration, GTX resets can not be asserted for 500ns - # See AR43482 - reset_en = Signal() - clk_period_ns = 1000000000/clk_freq - reset_en_cnt_max = ceil(500/clk_period_ns) - reset_en_cnt = Signal(max=reset_en_cnt_max, reset=reset_en_cnt_max-1) - self.sync += If(~reset_en, reset_en_cnt.eq(reset_en_cnt-1)) - self.comb += reset_en.eq(reset_en_cnt == 0) - - - # once channel TX is reseted, reset TX buffer - txbuffer_reseted = Signal() - self.sync += \ - If(gtx.txresetdone, - If(~txbuffer_reseted, - gtx.txdlysreset.eq(1), - txbuffer_reseted.eq(1) - ).Else( - gtx.txdlysreset.eq(0) - ) - ) - - # once channel RX is reseted, reset RX buffer - rxbuffer_reseted = Signal() - self.sync += \ - If(gtx.rxresetdone, - If(~rxbuffer_reseted, - gtx.rxdlysreset.eq(1), - rxbuffer_reseted.eq(1) - ).Else( - gtx.rxdlysreset.eq(0) - ) - ) - - # Reset - # initial reset generation - rst_cnt = Signal(8) - rst_cnt_done = Signal() - self.sync += \ - If(~rst_cnt_done, - rst_cnt.eq(rst_cnt+1) - ) - self.comb += rst_cnt_done.eq(rst_cnt==255) - - self.comb += [ - # GTXE2 - gtx.rxuserrdy.eq(gtx.cplllock), - gtx.txuserrdy.eq(gtx.cplllock), - # TX - gtx.gttxreset.eq(reset_en & (self.reset | ~gtx.cplllock)), - # RX - gtx.gtrxreset.eq(reset_en & (self.reset | ~gtx.cplllock)), - # PLL - gtx.cpllreset.eq(self.reset | ~reset_en) - ] - # SATA TX/RX clock domains - self.specials += [ - AsyncResetSynchronizer(self.cd_sata_tx, ~mmcm_locked | ~gtx.txresetdone), - AsyncResetSynchronizer(self.cd_sata_rx, ~gtx.cplllock | ~gtx.rxphaligndone), - AsyncResetSynchronizer(self.cd_sata, ResetSignal("sata_tx") | ResetSignal("sata_rx")), - ] - - # Dynamic Reconfiguration - self.submodules.reconfig = K7SATAPHYReconfig(mmcm_drp, gtx.drp) diff --git a/lib/sata/k7sataphy/crg.py b/lib/sata/k7sataphy/crg.py new file mode 100644 index 00000000..df14b5f2 --- /dev/null +++ b/lib/sata/k7sataphy/crg.py @@ -0,0 +1,183 @@ +from math import ceil + +from migen.fhdl.std import * +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.fsm import FSM, NextState + +from lib.sata.k7sataphy.std import * + +class K7SATAPHYReconfig(Module): + def __init__(self, channel_drp, mmcm_drp): + self.speed = Signal(3) + ### + speed_r = Signal(3) + speed_change = Signal() + self.sync += speed_r.eq(self.speed) + self.comb += speed_change.eq(self.speed != speed_r) + + drp_sel = Signal() + drp = DRPBus() + self.comb += \ + If(drp_sel, + drp.connect(mmcm_drp) + ).Else( + drp.connect(channel_drp) + ) + +class K7SATAPHYCRG(Module): + def __init__(self, pads, gtx, clk_freq): + self.reset = Signal() + + self.clock_domains.cd_sata_tx = ClockDomain() + self.clock_domains.cd_sata_rx = ClockDomain() + + # CPLL + # (SATA3) 150MHz / VCO @ 3GHz / Line rate @ 6Gbps + # (SATA2 & SATA1) VCO still @ 3 GHz, Line rate is decreased with output divivers. + # When changing rate, reconfiguration of the CPLL over DRP is needed to: + # - update the output divider + # - update the equalizer configuration (specific for each line rate). + refclk = Signal() + self.specials += Instance("IBUFDS_GTE2", + i_CEB=0, + i_I=pads.refclk_p, + i_IB=pads.refclk_n, + o_O=refclk + ) + self.comb += gtx.gtrefclk0.eq(refclk) + + # TX clocking + # (SATA3) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 300MHz (16-bits), sata clk @ 150MHz (32-bits) + # (SATA2) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 150MHz (16-bits), sata clk @ 75MHz (32-bits) + # (SATA1) 150MHz from CPLL TXOUTCLK, sata_tx clk @ 75MHz (16-bits), sata clk @ 37.5MHz (32-bits) + # When changing rate, reconfiguration of the MMCM is needed to update the output divider. + mmcm_reset = Signal() + mmcm_locked = Signal() + mmcm_drp = DRPBus() + mmcm_fb = Signal() + mmcm_clk_i = Signal() + mmcm_clk0_o = Signal() + mmcm_clk1_o = Signal() + self.specials += [ + Instance("BUFG", i_I=gtx.txoutclk, 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.en, o_DRDY=mmcm_drp.rdy, i_DWE=mmcm_drp.we, + i_DADDR=mmcm_drp.addr, i_DI=mmcm_drp.di, o_DO=mmcm_drp.do, + + # VCO + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=6.666, + p_CLKFBOUT_MULT_F=8.000, p_CLKFBOUT_PHASE=0.000, p_DIVCLK_DIVIDE=1, + 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_clk0_o, + + # CLK1 + p_CLKOUT1_DIVIDE=8, p_CLKOUT1_PHASE=0.000, o_CLKOUT1=mmcm_clk1_o, + ), + Instance("BUFG", i_I=mmcm_clk0_o, o_O=self.cd_sata_tx.clk), + Instance("BUFG", i_I=mmcm_clk1_o, o_O=self.cd_sata.clk), + ] + self.comb += [ + gtx.txusrclk.eq(self.cd_sata_tx.clk), + gtx.txusrclk2.eq(self.cd_sata_tx.clk) + ] + + # RX clocking + # (SATA3) sata_rx recovered clk @ 300MHz from CPLL RXOUTCLK + # (SATA2) sata_rx recovered clk @ 150MHz from CPLL RXOUTCLK + # (SATA1) sata_rx recovered clk @ 150MHz from CPLL RXOUTCLK + self.specials += [ + Instance("BUFG", i_I=gtx.rxoutclk, o_O=self.cd_sata_rx.clk), + ] + self.comb += [ + gtx.rxusrclk.eq(self.cd_sata_rx.clk), + gtx.rxusrclk2.eq(self.cd_sata_rx.clk) + ] + + # TX buffer bypass logic + self.comb += [ + gtx.txphdlyreset.eq(0), + gtx.txphalignen.eq(0), + gtx.txdlyen.eq(0), + gtx.txphalign.eq(0), + gtx.txphinit.eq(0) + ] + + # RX buffer bypass logic + self.comb += [ + gtx.rxphdlyreset.eq(0), + gtx.rxdlyen.eq(0), + gtx.rxphalign.eq(0), + gtx.rxphalignen.eq(0), + ] + + + # Configuration Reset + # After configuration, GTX resets have to stay low for at least 500ns + # See AR43482 + reset_en = Signal() + clk_period_ns = 1000000000/clk_freq + reset_en_cnt_max = ceil(500/clk_period_ns) + reset_en_cnt = Signal(max=reset_en_cnt_max, reset=reset_en_cnt_max-1) + self.sync += If(~reset_en, reset_en_cnt.eq(reset_en_cnt-1)) + self.comb += reset_en.eq(reset_en_cnt == 0) + + + # once channel TX is reseted, reset TX buffer + txbuffer_reseted = Signal() + self.sync += \ + If(gtx.txresetdone, + If(~txbuffer_reseted, + gtx.txdlysreset.eq(1), + txbuffer_reseted.eq(1) + ).Else( + gtx.txdlysreset.eq(0) + ) + ) + + # once channel RX is reseted, reset RX buffer + rxbuffer_reseted = Signal() + self.sync += \ + If(gtx.rxresetdone, + If(~rxbuffer_reseted, + gtx.rxdlysreset.eq(1), + rxbuffer_reseted.eq(1) + ).Else( + gtx.rxdlysreset.eq(0) + ) + ) + + # Reset + # initial reset generation + rst_cnt = Signal(8) + rst_cnt_done = Signal() + self.sync += \ + If(~rst_cnt_done, + rst_cnt.eq(rst_cnt+1) + ) + self.comb += rst_cnt_done.eq(rst_cnt==255) + + self.comb += [ + # GTXE2 + gtx.rxuserrdy.eq(gtx.cplllock), + gtx.txuserrdy.eq(gtx.cplllock), + # TX + gtx.gttxreset.eq(reset_en & (self.reset | ~gtx.cplllock)), + # RX + gtx.gtrxreset.eq(reset_en & (self.reset | ~gtx.cplllock)), + # PLL + gtx.cpllreset.eq(self.reset | ~reset_en) + ] + # SATA TX/RX clock domains + self.specials += [ + AsyncResetSynchronizer(self.cd_sata_tx, ~mmcm_locked | ~gtx.txresetdone), + AsyncResetSynchronizer(self.cd_sata_rx, ~gtx.cplllock | ~gtx.rxphaligndone), + AsyncResetSynchronizer(self.cd_sata, ResetSignal("sata_tx") | ResetSignal("sata_rx")), + ] + + # Dynamic Reconfiguration + self.submodules.reconfig = K7SATAPHYReconfig(mmcm_drp, gtx.drp) diff --git a/lib/sata/k7sataphy/ctrl.py b/lib/sata/k7sataphy/ctrl.py index 5f705397..f5ab206f 100644 --- a/lib/sata/k7sataphy/ctrl.py +++ b/lib/sata/k7sataphy/ctrl.py @@ -119,7 +119,7 @@ class K7SATAPHYHostCtrl(Module): txcominit_d = Signal() txcomwake_d = Signal() - self.sync.sata += [ + self.sync += [ txcominit_d.eq(txcominit), txcomwake_d.eq(txcomwake), gtx.txcominit.eq(txcominit & ~txcominit_d), @@ -128,7 +128,7 @@ class K7SATAPHYHostCtrl(Module): self.comb += align_detect.eq(self.rxdata == ALIGN_VAL); align_timeout_cnt = Signal(16) - self.sync.sata += \ + self.sync += \ If(fsm.ongoing("RESET"), If(self.speed == 0b100, align_timeout_cnt.eq(us(873, "SATA3")) @@ -142,7 +142,7 @@ class K7SATAPHYHostCtrl(Module): ) self.comb += align_timeout.eq(align_timeout_cnt == 0) - self.sync.sata += \ + self.sync += \ If(fsm.ongoing("RESET") | fsm.ongoing("AWAIT_NO_COMINIT"), If(self.speed == 0b100, retry_cnt.eq(us(10000, "SATA3")) @@ -155,7 +155,7 @@ class K7SATAPHYHostCtrl(Module): retry_cnt.eq(retry_cnt-1) ) - self.sync.sata += \ + self.sync += \ If(fsm.ongoing("SEND_ALIGN"), If(self.rxdata[0:8] == K28_5, non_align_cnt.eq(non_align_cnt + 1) @@ -250,7 +250,7 @@ class K7SATAPHYDeviceCtrl(Module): txcominit_d = Signal() txcomwake_d = Signal() - self.sync.sata += [ + self.sync += [ txcominit_d.eq(txcominit), txcomwake_d.eq(txcomwake), gtx.txcominit.eq(txcominit & ~txcominit_d), @@ -259,7 +259,7 @@ class K7SATAPHYDeviceCtrl(Module): self.comb += align_detect.eq(self.rxdata == ALIGN_VAL); align_timeout_cnt = Signal(16) - self.sync.sata += \ + self.sync += \ If(fsm.ongoing("RESET"), If(self.speed == 0b100, align_timeout_cnt.eq(us(55, "SATA3")) diff --git a/lib/sata/k7sataphy/datapath.py b/lib/sata/k7sataphy/datapath.py new file mode 100644 index 00000000..95f115ba --- /dev/null +++ b/lib/sata/k7sataphy/datapath.py @@ -0,0 +1,103 @@ +from migen.fhdl.std import * +from migen.actorlib.fifo import AsyncFIFO +from migen.actorlib.structuring import Converter +from migen.flow.actor import Sink, Source + +from lib.sata.k7sataphy.std import * + +class K7SATAPHYRXAlign(Module): + def __init__(self, dw=16): + self.rxdata_i = Signal(dw) + self.rxcharisk_i = Signal(dw//8) + + self.rxdata_o = Signal(dw) + self.rxcharisk_o = Signal(dw//8) + + ### + + rxdata_r = Signal(dw) + rxcharisk_r = Signal(dw//8) + self.sync.sata_rx += [ + rxdata_r.eq(self.rxdata_i), + rxcharisk_r.eq(self.rxcharisk_i) + ] + cases = {} + cases[1<<0] = [ + self.rxdata_o.eq(rxdata_r[0:dw]), + self.rxcharisk_o.eq(rxcharisk_r[0:dw//8]) + ] + for i in range(1, dw//8): + cases[1<