From 45a03dff53cef2fbeb748082c7ee0bf12532e02f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 16 Apr 2020 10:17:35 +0200 Subject: [PATCH] phy/init: add phytype to PhySettings and export more parameters to C header to simplify software. Also: - rename some paramters exported to software. - simplify wlevel registers on A7DDRPHY (add then even if not used). - move parameters computation in separate section. --- litedram/common.py | 2 +- litedram/init.py | 34 +++++++++++++++-- litedram/phy/ecp5ddrphy.py | 10 +++-- litedram/phy/gensdrphy.py | 1 + litedram/phy/s6ddrphy.py | 3 ++ litedram/phy/s7ddrphy.py | 75 ++++++++++++++++---------------------- litedram/phy/usddrphy.py | 27 +++++++------- 7 files changed, 87 insertions(+), 65 deletions(-) diff --git a/litedram/common.py b/litedram/common.py index 1d5751a..f949ced 100644 --- a/litedram/common.py +++ b/litedram/common.py @@ -109,7 +109,7 @@ class Settings: class PhySettings(Settings): - def __init__(self, memtype, databits, dfi_databits, + def __init__(self, phytype, memtype, databits, dfi_databits, nphases, rdphase, wrphase, rdcmdphase, wrcmdphase, diff --git a/litedram/init.py b/litedram/init.py index 62c08f2..bb76d35 100644 --- a/litedram/init.py +++ b/litedram/init.py @@ -397,8 +397,36 @@ def get_sdram_phy_c_header(phy_settings, timing_settings): r = "#ifndef __GENERATED_SDRAM_PHY_H\n#define __GENERATED_SDRAM_PHY_H\n" r += "#include \n#include \n#include \n\n" + phytype = phy_settings.phytype.upper() nphases = phy_settings.nphases - r += "#define DFII_NPHASES "+str(nphases)+"\n\n" + + # Define PHY type and number of phases + r += "#define SDRAM_PHY_"+phytype+"\n" + r += "#define SDRAM_PHY_PHASES "+str(nphases)+"\n" + + # Define Read/Write Leveling capability + if phytype in ["USDDRPHY", "USPDDRPHY", "K7DDRPHY", "V7DDRPHY"]: + r += "#define SDRAM_PHY_WRITE_LEVELING_CAPABLE\n" + if phytype in ["USDDRPHY", "USPDDRPHY"]: + r += "#define SDRAM_PHY_WRITE_LEVELING_REINIT\n" + if phytype in ["USDDRPHY", "USPDDRPHY", "A7DDRPHY", "K7DDRPHY", "V7DDRPHY", "ECP5DDRPHY"]: + r += "#define SDRAM_PHY_READ_LEVELING_CAPABLE\n" + + # Define number of modules/delays/bitslips + if phytype in ["USDDRPHY", "USPDDRPHY"]: + r += "#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2\n" + r += "#define SDRAM_PHY_DELAYS 512\n" + r += "#define SDRAM_PHY_BITSLIPS 8\n" + elif phytype in ["A7DDRPHY", "K7DDRPHY", "V7DDRPHY"]: + r += "#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2\n" + r += "#define SDRAM_PHY_DELAYS 32\n" + r += "#define SDRAM_PHY_BITSLIPS 8\n" + elif phytype in ["ECP5DDRPHY"]: + r += "#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/4\n" + r += "#define SDRAM_PHY_DELAYS 8\n" + r += "#define SDRAM_PHY_BITSLIPS 4\n" + + r += "\n" r += "static void cdelay(int i);\n" @@ -431,7 +459,7 @@ __attribute__((unused)) static void command_p{n}(int cmd) for n in range(nphases): sdram_dfii_pix_wrdata_addr.append("CSR_SDRAM_DFII_PI{n}_WRDATA_ADDR".format(n=n)) r += """ -const unsigned long sdram_dfii_pix_wrdata_addr[DFII_NPHASES] = {{ +const unsigned long sdram_dfii_pix_wrdata_addr[SDRAM_PHY_PHASES] = {{ \t{sdram_dfii_pix_wrdata_addr} }}; """.format(sdram_dfii_pix_wrdata_addr=",\n\t".join(sdram_dfii_pix_wrdata_addr)) @@ -440,7 +468,7 @@ const unsigned long sdram_dfii_pix_wrdata_addr[DFII_NPHASES] = {{ for n in range(nphases): sdram_dfii_pix_rddata_addr.append("CSR_SDRAM_DFII_PI{n}_RDDATA_ADDR".format(n=n)) r += """ -const unsigned long sdram_dfii_pix_rddata_addr[DFII_NPHASES] = {{ +const unsigned long sdram_dfii_pix_rddata_addr[SDRAM_PHY_PHASES] = {{ \t{sdram_dfii_pix_rddata_addr} }}; """.format(sdram_dfii_pix_rddata_addr=",\n\t".join(sdram_dfii_pix_rddata_addr)) diff --git a/litedram/phy/ecp5ddrphy.py b/litedram/phy/ecp5ddrphy.py index c85b0ef..8e10502 100644 --- a/litedram/phy/ecp5ddrphy.py +++ b/litedram/phy/ecp5ddrphy.py @@ -95,6 +95,11 @@ class ECP5DDRPHY(Module, AutoCSR): # Init ------------------------------------------------------------------------------------- self.submodules.init = ClockDomainsRenamer("init")(ECP5DDRPHYInit("sys2x")) + # Parameters ------------------------------------------------------------------------------- + cl, cwl = get_cl_cw(memtype, tck) + cl_sys_latency = get_sys_latency(nphases, cl) + cwl_sys_latency = get_sys_latency(nphases, cwl) + # Registers -------------------------------------------------------------------------------- self._dly_sel = CSRStorage(databits//8) @@ -110,13 +115,10 @@ class ECP5DDRPHY(Module, AutoCSR): self.datavalid = Signal(databits//8) # PHY settings ----------------------------------------------------------------------------- - cl, cwl = get_cl_cw(memtype, tck) - cl_sys_latency = get_sys_latency(nphases, cl) - cwl_sys_latency = get_sys_latency(nphases, cwl) - rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl) wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl) self.settings = PhySettings( + phytype = "ECP5DDRPHY", memtype = memtype, databits = databits, dfi_databits = 4*databits, diff --git a/litedram/phy/gensdrphy.py b/litedram/phy/gensdrphy.py index 56cab3a..f63a639 100644 --- a/litedram/phy/gensdrphy.py +++ b/litedram/phy/gensdrphy.py @@ -24,6 +24,7 @@ class GENSDRPHY(Module): # PHY settings ----------------------------------------------------------------------------- self.settings = PhySettings( + phytype = "GENSDRPHY", memtype = "SDR", databits = databits, dfi_databits = databits, diff --git a/litedram/phy/s6ddrphy.py b/litedram/phy/s6ddrphy.py index 9340e32..0f91e90 100644 --- a/litedram/phy/s6ddrphy.py +++ b/litedram/phy/s6ddrphy.py @@ -46,6 +46,7 @@ class S6HalfRateDDRPHY(Module): # PHY settings ----------------------------------------------------------------------------- if memtype == "DDR3": self.settings = PhySettings( + phytype = "S6HalfRateDDRPHY", memtype = "DDR3", databits = databits, dfi_databits = 2*databits, @@ -62,6 +63,7 @@ class S6HalfRateDDRPHY(Module): ) else: self.settings = PhySettings( + phytype = "S6HalfRateDDRPHY", memtype = memtype, databits = databits, dfi_databits = 2*databits, @@ -424,6 +426,7 @@ class S6QuarterRateDDRPHY(Module): # PHY settings ----------------------------------------------------------------------------- self.settings = PhySettings( + phytype = "S6QuarterRateDDRPHY", memtype = "DDR3", databits = databits, dfi_databits = 2*databits, diff --git a/litedram/phy/s7ddrphy.py b/litedram/phy/s7ddrphy.py index f7a7692..f12dee5 100644 --- a/litedram/phy/s7ddrphy.py +++ b/litedram/phy/s7ddrphy.py @@ -28,6 +28,7 @@ class S7DDRPHY(Module, AutoCSR): assert not (memtype == "DDR3" and nphases == 2) # FIXME: Needs BL8 support for nphases=2 assert interface_type in ["NETWORKING", "MEMORY"] assert not (interface_type == "MEMORY" and nphases == 2) + phytype = self.__class__.__name__ pads = PHYPadsCombiner(pads) tck = 2/(2*nphases*sys_clk_freq) addressbits = len(pads.a) @@ -37,20 +38,25 @@ class S7DDRPHY(Module, AutoCSR): nphases = nphases assert databits%8 == 0 + # Parameters ------------------------------------------------------------------------------- iodelay_tap_average = { 200e6: 78e-12, 300e6: 52e-12, 400e6: 39e-12, # Only valid for -3 and -2/2E speed grades } + half_sys8x_taps = math.floor(tck/(4*iodelay_tap_average[iodelay_clk_freq])) + + cl, cwl = get_cl_cw(memtype, tck) + cl_sys_latency = get_sys_latency(nphases, cl) + cwl = cwl + cmd_latency + cwl_sys_latency = get_sys_latency(nphases, cwl) # Registers -------------------------------------------------------------------------------- - self._dly_sel = CSRStorage(databits//8) - half_sys8x_taps = math.floor(tck/(4*iodelay_tap_average[iodelay_clk_freq])) + self._dly_sel = CSRStorage(databits//8) self._half_sys8x_taps = CSRStorage(5, reset=half_sys8x_taps) - if with_odelay: - self._wlevel_en = CSRStorage() - self._wlevel_strobe = CSR() + self._wlevel_en = CSRStorage() + self._wlevel_strobe = CSR() self._cdly_rst = CSR() self._cdly_inc = CSR() @@ -63,17 +69,12 @@ class S7DDRPHY(Module, AutoCSR): self._rdly_dq_bitslip = CSR() if with_odelay: - self._wdly_dq_rst = CSR() - self._wdly_dq_inc = CSR() - self._wdly_dqs_rst = CSR() - self._wdly_dqs_inc = CSR() + self._wdly_dq_rst = CSR() + self._wdly_dq_inc = CSR() + self._wdly_dqs_rst = CSR() + self._wdly_dqs_inc = CSR() # PHY settings ----------------------------------------------------------------------------- - cl, cwl = get_cl_cw(memtype, tck) - cl_sys_latency = get_sys_latency(nphases, cl) - cwl = cwl + cmd_latency - cwl_sys_latency = get_sys_latency(nphases, cwl) - rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl) wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl) iserdese2_latency = { @@ -81,6 +82,7 @@ class S7DDRPHY(Module, AutoCSR): "MEMORY": 1, } self.settings = PhySettings( + phytype = phytype, memtype = memtype, databits = databits, dfi_databits = 2*databits, @@ -93,7 +95,7 @@ class S7DDRPHY(Module, AutoCSR): cl = cl, cwl = cwl - cmd_latency, read_latency = 2 + cl_sys_latency + iserdese2_latency[interface_type] + 2, - write_latency = cwl_sys_latency + write_latency = cwl_sys_latency, ) # DFI Interface ---------------------------------------------------------------------------- @@ -291,18 +293,14 @@ class S7DDRPHY(Module, AutoCSR): dqs_serdes_pattern.eq(0b01010101), If(dqs_preamble | dqs_postamble, dqs_serdes_pattern.eq(0b0000000) + ), + If(self._wlevel_en.storage, + dqs_serdes_pattern.eq(0b00000000), + If(self._wlevel_strobe.re, + dqs_serdes_pattern.eq(0b00000001) + ) ) ] - if with_odelay: - self.comb += [ - If(self._wlevel_en.storage, - dqs_serdes_pattern.eq(0b00000000), - If(self._wlevel_strobe.re, - dqs_serdes_pattern.eq(0b00000001) - ) - ) - ] - for i in range(databits//8): dm_o_nodelay = Signal() self.specials += Instance("OSERDESE2", @@ -573,12 +571,7 @@ class S7DDRPHY(Module, AutoCSR): n_rddata_en = Signal() self.sync += n_rddata_en.eq(rddata_en) rddata_en = n_rddata_en - if with_odelay: - self.sync += [phase.rddata_valid.eq(rddata_en | self._wlevel_en.storage) - for phase in dfi.phases] - else: - self.sync += [phase.rddata_valid.eq(rddata_en) - for phase in dfi.phases] + self.sync += [phase.rddata_valid.eq(rddata_en | self._wlevel_en.storage) for phase in dfi.phases] # Write Control Path ----------------------------------------------------------------------- oe = Signal() @@ -589,19 +582,13 @@ class S7DDRPHY(Module, AutoCSR): last_wrdata_en[cwl_sys_latency + -1] | last_wrdata_en[cwl_sys_latency + 0] | last_wrdata_en[cwl_sys_latency + 1]) - if with_odelay: - self.sync += [ - If(self._wlevel_en.storage, - oe_dqs.eq(1), oe_dq.eq(0) - ).Else( - oe_dqs.eq(oe), oe_dq.eq(oe) - ) - ] - else: - self.sync += [ - oe_dqs.eq(oe), - oe_dq.eq(oe) - ] + self.sync += [ + If(self._wlevel_en.storage, + oe_dqs.eq(1), oe_dq.eq(0) + ).Else( + oe_dqs.eq(oe), oe_dq.eq(oe) + ) + ] # Write DQS Postamble/Preamble Control Path ------------------------------------------------ if memtype == "DDR2": diff --git a/litedram/phy/usddrphy.py b/litedram/phy/usddrphy.py index e98c604..29d90af 100644 --- a/litedram/phy/usddrphy.py +++ b/litedram/phy/usddrphy.py @@ -22,8 +22,9 @@ class USDDRPHY(Module, AutoCSR): memtype = "DDR3", sys_clk_freq = 100e6, iodelay_clk_freq = 200e6, - cmd_latency = 0, - device = "ULTRASCALE"): + cmd_latency = 0): + phytype = self.__class__.__name__ + device = {"USDDRPHY": "ULTRASCALE", "USPDDRPHY": "ULTRASCALE_PLUS"}[phytype] pads = PHYPadsCombiner(pads) tck = 2/(2*4*sys_clk_freq) addressbits = len(pads.a) @@ -34,15 +35,19 @@ class USDDRPHY(Module, AutoCSR): databits = len(pads.dq) nphases = 4 assert databits%8 == 0 - assert device in ["ULTRASCALE", "ULTRASCALE_PLUS"] - if device == "ULTRASCALE": - assert iodelay_clk_freq >= 200e6 - if device == "ULTRASCALE_PLUS": - assert iodelay_clk_freq >= 300e6 if hasattr(pads, "ten"): self.comb += pads.ten.eq(0) + # Parameters ------------------------------------------------------------------------------- + if phytype == "USDDRPHY": assert iodelay_clk_freq >= 200e6 + if phytype == "USPDDRPHY": assert iodelay_clk_freq >= 300e6 + + cl, cwl = get_cl_cw(memtype, tck) + cwl = cwl + cmd_latency + cl_sys_latency = get_sys_latency(nphases, cl) + cwl_sys_latency = get_sys_latency(nphases, cwl) + # Registers -------------------------------------------------------------------------------- self._en_vtc = CSRStorage(reset=1) @@ -68,14 +73,10 @@ class USDDRPHY(Module, AutoCSR): self._wdly_dqs_inc = CSR() # PHY settings ----------------------------------------------------------------------------- - cl, cwl = get_cl_cw(memtype, tck) - cwl = cwl + cmd_latency - cl_sys_latency = get_sys_latency(nphases, cl) - cwl_sys_latency = get_sys_latency(nphases, cwl) - rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl) wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl) self.settings = PhySettings( + phytype = phytype, memtype = memtype, databits = databits, dfi_databits = 2*databits, @@ -525,4 +526,4 @@ class USDDRPHY(Module, AutoCSR): class USPDDRPHY(USDDRPHY): def __init__(self, pads, **kwargs): - USDDRPHY.__init__(self, pads, device="ULTRASCALE_PLUS", **kwargs) + USDDRPHY.__init__(self, pads, **kwargs)