X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=gram%2Fphy%2Fecp5ddrphy.py;h=394e6522ea9e92751058d6cb0e309b09b8296669;hb=7e26291bb304c0a0594665e7b45a33a3fcdcac95;hp=ea5d58c9290e29d3c5b758f4e1ab96712ce42ab7;hpb=c2cdda0f973a81910bdaed2a4fdc26d6158bd1c4;p=gram.git diff --git a/gram/phy/ecp5ddrphy.py b/gram/phy/ecp5ddrphy.py index ea5d58c..394e652 100644 --- a/gram/phy/ecp5ddrphy.py +++ b/gram/phy/ecp5ddrphy.py @@ -40,13 +40,12 @@ class ECP5DDRPHYInit(Elaboratable): _lock = Signal() delay = Signal() m.submodules += Instance("DDRDLLA", - i_CLK=ClockSignal("sync2x"), - i_RST=ResetSignal("init"), - i_UDDCNTLN=~update, - i_FREEZE=freeze, - o_DDRDEL=delay, - o_LOCK=_lock - ) + i_CLK=ClockSignal("sync2x"), + i_RST=ResetSignal("init"), + i_UDDCNTLN=~update, + i_FREEZE=freeze, + o_DDRDEL=delay, + o_LOCK=_lock) lock = Signal() lock_d = Signal() m.submodules += FFSynchronizer(_lock, lock, o_domain="init") @@ -91,15 +90,11 @@ class ECP5DDRPHY(Peripheral, Elaboratable): # CSR bank = self.csr_bank() - self._dly_sel = bank.csr(databits//8, "rw") + self.burstdet = bank.csr(databits//8, "rw") - self._rdly_dq_rst = bank.csr(1, "rw") - self._rdly_dq_inc = bank.csr(1, "rw") - self._rdly_dq_bitslip_rst = bank.csr(1, "rw") - self._rdly_dq_bitslip = bank.csr(1, "rw") - - self._burstdet_clr = bank.csr(1, "rw") - self._burstdet_seen = bank.csr(databits//8, "r") + self.rdly = [] + self.rdly += [bank.csr(3, "rw", name="rdly_p0")] + self.rdly += [bank.csr(3, "rw", name="rdly_p1")] self._bridge = self.bridge(data_width=32, granularity=8, alignment=2) self.bus = self._bridge.bus @@ -111,7 +106,7 @@ class ECP5DDRPHY(Peripheral, Elaboratable): self.dfi = Interface(addressbits, bankbits, nranks, 4*databits, 4) # PHY settings ----------------------------------------------------------------------------- - tck = 2/(2*2*self._sys_clk_freq) + tck = 1/(2*self._sys_clk_freq) nphases = 2 databits = len(self.pads.dq.io) nranks = 1 if not hasattr(self.pads, "cs") else len(self.pads.cs.o0) @@ -142,10 +137,17 @@ class ECP5DDRPHY(Peripheral, Elaboratable): m.submodules.bridge = self._bridge - tck = 2/(2*2*self._sys_clk_freq) + tck = 1/(2*self._sys_clk_freq) nphases = 2 databits = len(self.pads.dq.io) + burstdet_reg = Signal(databits//8) + m.d.comb += self.burstdet.r_data.eq(burstdet_reg) + + # Burstdet clear + with m.If(self.burstdet.w_stb): + m.d.sync += burstdet_reg.eq(0) + # Init ------------------------------------------------------------------------------------- m.submodules.init = init = ECP5DDRPHYInit() @@ -197,6 +199,7 @@ class ECP5DDRPHY(Peripheral, Elaboratable): self.pads.ba.o3[i].eq(dfi.phases[1].bank[i]), ] + # Control pins controls = ["ras", "cas", "we", "clk_en", "odt"] if hasattr(self.pads, "reset"): controls.append("reset") @@ -217,6 +220,7 @@ class ECP5DDRPHY(Peripheral, Elaboratable): # DQ --------------------------------------------------------------------------------------- dq_oe = Signal() + dqs_re = Signal() dqs_oe = Signal() dqs_postamble = Signal() dqs_preamble = Signal() @@ -228,67 +232,63 @@ class ECP5DDRPHY(Peripheral, Elaboratable): dqsw = Signal() rdpntr = Signal(3) wrpntr = Signal(3) - rdly = Signal(7) burstdet = Signal() m.submodules += Instance("DQSBUFM", - p_DQS_LI_DEL_ADJ="MINUS", - p_DQS_LI_DEL_VAL=1, - p_DQS_LO_DEL_ADJ="MINUS", - p_DQS_LO_DEL_VAL=4, - - # Delay - i_DYNDELAY0=0, - i_DYNDELAY1=0, - i_DYNDELAY2=0, - i_DYNDELAY3=0, - i_DYNDELAY4=0, - i_DYNDELAY5=0, - i_DYNDELAY6=0, - i_DYNDELAY7=0, - - # Clocks / Reset - i_SCLK=ClockSignal("sync"), - i_ECLK=ClockSignal("sync2x"), - i_RST=ResetSignal("dramsync"), - i_DDRDEL=init.delay, - i_PAUSE=init.pause | self._dly_sel.w_data[i], - - # Control - # Assert LOADNs to use DDRDEL control - i_RDLOADN=0, - i_RDMOVE=0, - i_RDDIRECTION=1, - i_WRLOADN=0, - i_WRMOVE=0, - i_WRDIRECTION=1, - - # Reads (generate shifted DQS clock for reads) - i_READ0=1, - i_READ1=1, - i_READCLKSEL0=rdly[0], - i_READCLKSEL1=rdly[1], - i_READCLKSEL2=rdly[2], - i_DQSI=dqs_i, - o_DQSR90=dqsr90, - o_RDPNTR0=rdpntr[0], - o_RDPNTR1=rdpntr[1], - o_RDPNTR2=rdpntr[2], - o_WRPNTR0=wrpntr[0], - o_WRPNTR1=wrpntr[1], - o_WRPNTR2=wrpntr[2], - o_DATAVALID=self.datavalid[i], - o_BURSTDET=burstdet, - - # Writes (generate shifted ECLK clock for writes) - o_DQSW270=dqsw270, - o_DQSW=dqsw) - burstdet_d = Signal() - m.d.sync += burstdet_d.eq(burstdet) - with m.If(self._burstdet_clr.w_stb): - m.d.sync += self._burstdet_seen.r_data[i].eq(0) - with m.If(burstdet & ~burstdet_d): - m.d.sync += self._burstdet_seen.r_data[i].eq(1) + p_DQS_LI_DEL_ADJ="MINUS", + p_DQS_LI_DEL_VAL=1, + p_DQS_LO_DEL_ADJ="MINUS", + p_DQS_LO_DEL_VAL=4, + + # Delay + i_DYNDELAY0=0, + i_DYNDELAY1=0, + i_DYNDELAY2=0, + i_DYNDELAY3=0, + i_DYNDELAY4=0, + i_DYNDELAY5=0, + i_DYNDELAY6=0, + i_DYNDELAY7=0, + + # Clocks / Reset + i_SCLK=ClockSignal("sync"), + i_ECLK=ClockSignal("sync2x"), + i_RST=ResetSignal("dramsync"), + i_DDRDEL=init.delay, + i_PAUSE=init.pause | self.rdly[i].w_stb, + + # Control + # Assert LOADNs to use DDRDEL control + i_RDLOADN=0, + i_RDMOVE=0, + i_RDDIRECTION=1, + i_WRLOADN=0, + i_WRMOVE=0, + i_WRDIRECTION=1, + + # Reads (generate shifted DQS clock for reads) + i_READ0=dqs_re, + i_READ1=dqs_re, + i_READCLKSEL0=self.rdly[i].w_data[0], + i_READCLKSEL1=self.rdly[i].w_data[1], + i_READCLKSEL2=self.rdly[i].w_data[2], + i_DQSI=dqs_i, + o_DQSR90=dqsr90, + o_RDPNTR0=rdpntr[0], + o_RDPNTR1=rdpntr[1], + o_RDPNTR2=rdpntr[2], + o_WRPNTR0=wrpntr[0], + o_WRPNTR1=wrpntr[1], + o_WRPNTR2=wrpntr[2], + o_DATAVALID=self.datavalid[i], + o_BURSTDET=burstdet, + + # Writes (generate shifted ECLK clock for writes) + o_DQSW270=dqsw270, + o_DQSW=dqsw) + + with m.If(burstdet): + m.d.sync += burstdet_reg[i].eq(1) # DQS and DM --------------------------------------------------------------------------- dm_o_data = Signal(8) @@ -312,49 +312,43 @@ class ECP5DDRPHY(Peripheral, Elaboratable): with m.Else(): m.d.sync += dm_o_data_muxed.eq(dm_o_data[:4]) - dm_o_data_muxed_d = Signal(4) - m.d.sync += dm_o_data_muxed_d.eq(dm_o_data_muxed) - m.submodules += Instance("ODDRX2DQA", i_RST=ResetSignal("dramsync"), i_ECLK=ClockSignal("sync2x"), i_SCLK=ClockSignal("dramsync"), i_DQSW270=dqsw270, - i_D2=dm_o_data_muxed[0], - i_D3=dm_o_data_muxed[1], - i_D0=dm_o_data_muxed_d[2], - i_D1=dm_o_data_muxed_d[3], + i_D0=dm_o_data_muxed[0], + i_D1=dm_o_data_muxed[1], + i_D2=dm_o_data_muxed[2], + i_D3=dm_o_data_muxed[3], o_Q=self.pads.dm.o[i]) dqs = Signal() dqs_oe_n = Signal() m.submodules += [ Instance("ODDRX2DQSB", - i_RST=ResetSignal("dramsync"), - i_ECLK=ClockSignal("sync2x"), - i_SCLK=ClockSignal(), - i_DQSW=dqsw, - i_D0=0, - i_D1=1, - i_D2=0, - i_D3=1, - o_Q=dqs - ), + i_RST=ResetSignal("dramsync"), + i_ECLK=ClockSignal("sync2x"), + i_SCLK=ClockSignal(), + i_DQSW=dqsw, + i_D0=0, + i_D1=1, + i_D2=0, + i_D3=1, + o_Q=dqs), Instance("TSHX2DQSA", - i_RST=ResetSignal("dramsync"), - i_ECLK=ClockSignal("sync2x"), - i_SCLK=ClockSignal(), - i_DQSW=dqsw, - i_T0=~(dqs_oe | dqs_postamble), - i_T1=~(dqs_oe | dqs_postamble), - o_Q=dqs_oe_n - ), + i_RST=ResetSignal("dramsync"), + i_ECLK=ClockSignal("sync2x"), + i_SCLK=ClockSignal(), + i_DQSW=dqsw, + i_T0=~(dqs_oe | dqs_postamble), + i_T1=~(dqs_oe | dqs_preamble), + o_Q=dqs_oe_n), Instance("BB", i_I=dqs, i_T=dqs_oe_n, o_O=dqs_i, - io_B=self.pads.dqs.io[i] - ) + io_B=self.pads.dqs.io[i]), ] for j in range(8*i, 8*(i+1)): @@ -378,69 +372,60 @@ class ECP5DDRPHY(Peripheral, Elaboratable): ) m.d.sync += dq_o_data_d.eq(dq_o_data) - with m.Switch(bl8_chunk): - with m.Case(0): - m.d.sync += dq_o_data_muxed.eq(dq_o_data[:4]) - with m.Case(1): - m.d.sync += dq_o_data_muxed.eq(dq_o_data_d[4:]) - - dq_o_data_muxed_d = Signal.like(dq_o_data_muxed) - m.d.sync += dq_o_data_muxed_d.eq(dq_o_data_muxed) + with m.If(bl8_chunk): + m.d.sync += dq_o_data_muxed.eq(dq_o_data_d[4:]) + with m.Else(): + m.d.sync += dq_o_data_muxed.eq(dq_o_data[:4]) m.submodules += [ Instance("ODDRX2DQA", - i_RST=ResetSignal("dramsync"), - i_ECLK=ClockSignal("sync2x"), - i_SCLK=ClockSignal(), - i_DQSW270=dqsw270, - i_D0=dq_o_data_muxed_d[2], - i_D1=dq_o_data_muxed_d[3], - i_D2=dq_o_data_muxed[0], - i_D3=dq_o_data_muxed[1], - o_Q=dq_o - ), + i_RST=ResetSignal("dramsync"), + i_ECLK=ClockSignal("sync2x"), + i_SCLK=ClockSignal(), + i_DQSW270=dqsw270, + i_D0=dq_o_data_muxed[0], + i_D1=dq_o_data_muxed[1], + i_D2=dq_o_data_muxed[2], + i_D3=dq_o_data_muxed[3], + o_Q=dq_o), Instance("DELAYF", - p_DEL_MODE="DQS_ALIGNED_X2", - i_LOADN=1, - i_MOVE=0, - i_DIRECTION=0, - i_A=dq_i, - o_Z=dq_i_delayed - ), + p_DEL_MODE="DQS_ALIGNED_X2", + i_LOADN=1, + i_MOVE=0, + i_DIRECTION=0, + i_A=dq_i, + o_Z=dq_i_delayed), Instance("IDDRX2DQA", - i_RST=ResetSignal("dramsync"), - i_ECLK=ClockSignal("sync2x"), - i_SCLK=ClockSignal(), - i_DQSR90=dqsr90, - i_RDPNTR0=rdpntr[0], - i_RDPNTR1=rdpntr[1], - i_RDPNTR2=rdpntr[2], - i_WRPNTR0=wrpntr[0], - i_WRPNTR1=wrpntr[1], - i_WRPNTR2=wrpntr[2], - i_D=dq_i_delayed, - o_Q0=dq_i_data[0], - o_Q1=dq_i_data[1], - o_Q2=dq_i_data[2], - o_Q3=dq_i_data[3], - ), + i_RST=ResetSignal("dramsync"), + i_ECLK=ClockSignal("sync2x"), + i_SCLK=ClockSignal(), + i_DQSR90=dqsr90, + i_RDPNTR0=rdpntr[0], + i_RDPNTR1=rdpntr[1], + i_RDPNTR2=rdpntr[2], + i_WRPNTR0=wrpntr[0], + i_WRPNTR1=wrpntr[1], + i_WRPNTR2=wrpntr[2], + i_D=dq_i_delayed, + o_Q0=dq_i_data[0], + o_Q1=dq_i_data[1], + o_Q2=dq_i_data[2], + o_Q3=dq_i_data[3]), ] m.submodules += [ Instance("TSHX2DQA", - i_RST=ResetSignal("dramsync"), - i_ECLK=ClockSignal("sync2x"), - i_SCLK=ClockSignal(), - i_DQSW270=dqsw270, - i_T0=~dq_oe, - i_T1=~dq_oe, - o_Q=dq_oe_n, - ), + i_RST=ResetSignal("dramsync"), + i_ECLK=ClockSignal("sync2x"), + i_SCLK=ClockSignal(), + i_DQSW270=dqsw270, + i_T0=~dq_oe, + i_T1=~dq_oe, + o_Q=dq_oe_n), Instance("BB", i_I=dq_o, i_T=dq_oe_n, o_O=dq_i, - io_B=self.pads.dq.io[j] - ) + io_B=self.pads.dq.io[j]) ] m.d.sync += [ dfi.phases[1].rddata[j].eq(dq_i_data[0]), @@ -467,6 +452,7 @@ class ECP5DDRPHY(Peripheral, Elaboratable): m.d.comb += rddata_en.eq(Cat(dfi.phases[self.settings.rdphase].rddata_en, rddata_en_last)) m.d.sync += rddata_en_last.eq(rddata_en) m.d.sync += [phase.rddata_valid.eq(rddata_en[-1]) for phase in dfi.phases] + m.d.comb += dqs_re.eq(rddata_en[cl_sys_latency + 0] | rddata_en[cl_sys_latency + 1] | rddata_en[cl_sys_latency + 2]) # Write Control Path ----------------------------------------------------------------------- # Creates a shift register of write commands coming from the DFI interface. This shift register @@ -475,19 +461,19 @@ class ECP5DDRPHY(Peripheral, Elaboratable): # 2x for DDR, 2x for halfrate) but DDR3 requires a burst of 8 datas (BL8) for best efficiency. # Writes are then performed in 2 sys_clk cycles and data needs to be selected for each cycle. # FIXME: understand +2 - wrdata_en = Signal(cwl_sys_latency + 5) + wrdata_en = Signal(cwl_sys_latency + 4) wrdata_en_last = Signal.like(wrdata_en) m.d.comb += wrdata_en.eq(Cat(dfi.phases[self.settings.wrphase].wrdata_en, wrdata_en_last)) m.d.sync += wrdata_en_last.eq(wrdata_en) m.d.comb += dq_oe.eq(wrdata_en[cwl_sys_latency + 1] | wrdata_en[cwl_sys_latency + 2]) m.d.comb += bl8_chunk.eq(wrdata_en[cwl_sys_latency + 1]) - m.d.comb += dqs_oe.eq(dq_oe | wrdata_en[cwl_sys_latency + 3]) + m.d.comb += dqs_oe.eq(dq_oe) # Write DQS Postamble/Preamble Control Path ------------------------------------------------ # Generates DQS Preamble 1 cycle before the first write and Postamble 1 cycle after the last # write. During writes, DQS tristate is configured as output for at least 4 sys_clk cycles: # 1 for Preamble, 2 for the Write and 1 for the Postamble. m.d.comb += dqs_preamble.eq(wrdata_en[cwl_sys_latency + 0] & ~wrdata_en[cwl_sys_latency + 1]) - m.d.comb += dqs_postamble.eq(wrdata_en[cwl_sys_latency + 4] & ~wrdata_en[cwl_sys_latency + 3]) + m.d.comb += dqs_postamble.eq(wrdata_en[cwl_sys_latency + 3] & ~wrdata_en[cwl_sys_latency + 2]) return m