phy/usddrphy: Avoid separate ODELAYE3 by avoiding software reset on DQS's ODELAYE3.
The fabric is now maintaining an increment counter for each DQS's ODELAY and software use it to revert total increments to 0 (equivalent to a reset). Avoiding the separate ODELAYE3 simplifies design constraints since it was often placed far from the DRAM pads and thus requiring a LOC constraint to avoid timing violations. The software has to use the following sdram_write_leveling_rst_delay function: static void sdram_write_leveling_rst_delay(int module) { /* Select module */ ddrphy_dly_sel_write(1 << module); /* Reset DQ delay */ ddrphy_wdly_dq_rst_write(1); /* Reset DQS delay */ while (ddrphy_wdly_dqs_inc_count_read() != 0) { ddrphy_wdly_dqs_inc_write(1); cdelay(100); } /* Un-select module */ ddrphy_dly_sel_write(0); }
This commit is contained in:
parent
541e2f1c57
commit
25b64c3374
|
@ -83,6 +83,7 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
self._wdly_dq_inc = CSR()
|
self._wdly_dq_inc = CSR()
|
||||||
self._wdly_dqs_rst = CSR()
|
self._wdly_dqs_rst = CSR()
|
||||||
self._wdly_dqs_inc = CSR()
|
self._wdly_dqs_inc = CSR()
|
||||||
|
self._wdly_dqs_inc_count = CSRStatus(9)
|
||||||
|
|
||||||
self._wdly_dq_bitslip_rst = CSR()
|
self._wdly_dq_bitslip_rst = CSR()
|
||||||
self._wdly_dq_bitslip = CSR()
|
self._wdly_dq_bitslip = CSR()
|
||||||
|
@ -126,18 +127,6 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
# tCK reference ----------------------------------------------------------------------------
|
|
||||||
self.specials += Instance("ODELAYE3",
|
|
||||||
p_SIM_DEVICE = device,
|
|
||||||
p_REFCLK_FREQUENCY = iodelay_clk_freq/1e6,
|
|
||||||
p_DELAY_FORMAT = "TIME",
|
|
||||||
p_DELAY_TYPE = "FIXED",
|
|
||||||
p_DELAY_VALUE = int(tck*1e12/4),
|
|
||||||
i_CLK = ClockSignal(),
|
|
||||||
i_EN_VTC = 1,
|
|
||||||
o_CNTVALUEOUT = self._half_sys8x_taps.status,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Iterate on pads groups -------------------------------------------------------------------
|
# Iterate on pads groups -------------------------------------------------------------------
|
||||||
for pads_group in range(len(pads.groups)):
|
for pads_group in range(len(pads.groups)):
|
||||||
pads.sel_group(pads_group)
|
pads.sel_group(pads_group)
|
||||||
|
@ -296,11 +285,9 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
p_IS_CLK_INVERTED = 0,
|
p_IS_CLK_INVERTED = 0,
|
||||||
p_IS_RST_INVERTED = 0,
|
p_IS_RST_INVERTED = 0,
|
||||||
p_DELAY_FORMAT = "TIME",
|
p_DELAY_FORMAT = "TIME",
|
||||||
p_DELAY_TYPE = "VAR_LOAD",
|
p_DELAY_TYPE = "VARIABLE",
|
||||||
p_DELAY_VALUE = 0,
|
p_DELAY_VALUE = int(tck*1e12/4),
|
||||||
i_RST = ResetSignal("ic") | self._rst.storage,
|
o_CNTVALUEOUT = self._half_sys8x_taps.status if (i == 0) and (j == 0) else Signal(),
|
||||||
i_LOAD = self._dly_sel.storage[i] & self._wdly_dqs_rst.re,
|
|
||||||
i_CNTVALUEIN = self._half_sys8x_taps.status,
|
|
||||||
i_CLK = ClockSignal(),
|
i_CLK = ClockSignal(),
|
||||||
i_EN_VTC = self._en_vtc.storage,
|
i_EN_VTC = self._en_vtc.storage,
|
||||||
i_CE = self._dly_sel.storage[i] & self._wdly_dqs_inc.re,
|
i_CE = self._dly_sel.storage[i] & self._wdly_dqs_inc.re,
|
||||||
|
@ -315,6 +302,9 @@ class USDDRPHY(Module, AutoCSR):
|
||||||
io_IOB = dqs_n,
|
io_IOB = dqs_n,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
wdly_dqs_inc_count = Signal(9)
|
||||||
|
self.sync += If(self._dly_sel.storage[i] & self._wdly_dqs_inc.re, wdly_dqs_inc_count.eq(wdly_dqs_inc_count + 1))
|
||||||
|
self.comb += If(self._dly_sel.storage[i], self._wdly_dqs_inc_count.status.eq(wdly_dqs_inc_count))
|
||||||
|
|
||||||
# DM ---------------------------------------------------------------------------------------
|
# DM ---------------------------------------------------------------------------------------
|
||||||
for i in range(databits//8):
|
for i in range(databits//8):
|
||||||
|
|
Loading…
Reference in New Issue