Merge pull request #189 from daveshah1/ddr4_rdimm_init

Add support for DDR4 RDIMMs
This commit is contained in:
enjoy-digital 2020-05-15 21:34:43 +02:00 committed by GitHub
commit b2a5685396
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 101 additions and 11 deletions

View File

@ -173,6 +173,7 @@ class PhySettings(Settings):
cl, read_latency, write_latency, nranks=1, cwl=None):
self.set_attributes(locals())
self.cwl = cl if cwl is None else cwl
self.is_rdimm = False
# Optional DDR3/DDR4 electrical settings:
# rtt_nom: Non-Writes on-die termination impedance
@ -182,6 +183,11 @@ class PhySettings(Settings):
assert self.memtype in ["DDR3", "DDR4"]
self.set_attributes(locals())
# Optional RDIMM configuration
def set_rdimm(self, tck, rcd_pll_bypass, rcd_ca_cs_drive, rcd_odt_cke_drive, rcd_clk_drive):
assert self.memtype == "DDR4"
self.is_rdimm = True
self.set_attributes(locals())
class GeomSettings(Settings):
def __init__(self, bankbits, rowbits, colbits):

View File

@ -364,9 +364,62 @@ def get_ddr4_phy_init_sequence(phy_settings, timing_settings):
mr5 = 0
mr6 = format_mr6(4) # FIXME: tCCD
rdimm_init = []
if phy_settings.is_rdimm:
def get_coarse_speed(tck, pll_bypass):
# JESD82-31A page 78
f_to_coarse_speed = {
1600e6: 0,
1866e6: 1,
2133e6: 2,
2400e6: 3,
2666e6: 4,
2933e6: 5,
3200e6: 6,
}
if pll_bypass:
return 7
else:
for f, speed in f_to_coarse_speed.items():
if tck >= 2/f:
return speed
raise ValueError
def get_fine_speed(tck):
# JESD82-31A page 83
freq = 2/tck
fine_speed = (freq - 1240e6) // 20e6
fine_speed = max(fine_speed, 0)
fine_speed = min(fine_speed, 0b1100001)
return fine_speed
coarse_speed = get_coarse_speed(phy_settings.tck, phy_settings.rcd_pll_bypass)
fine_speed = get_fine_speed(phy_settings.tck)
rcd_reset = 0x060 | 0x0 # F0RC06: command space control; 0: reset RCD
f0rc0f = 0x0F0 | 0x4 # F0RC05: 0 nCK latency adder
f0rc03 = 0x030 | phy_settings.rcd_ca_cs_drive # F0RC03: CA/CS drive strength
f0rc04 = 0x040 | phy_settings.rcd_odt_cke_drive # F0RC04: ODT/CKE drive strength
f0rc05 = 0x050 | phy_settings.rcd_clk_drive # F0RC04: ODT/CKE drive strength
f0rc0a = 0x0A0 | coarse_speed # F0RC0A: coarse speed selection and PLL bypass
f0rc3x = 0x300 | fine_speed # F0RC3x: fine speed selection
rdimm_init = [
("Reset RCD", rcd_reset, 7, cmds["MODE_REGISTER"], 50000),
("Load RCD F0RC0F", f0rc0f, 7, cmds["MODE_REGISTER"], 100),
("Load RCD F0RC03", f0rc03, 7, cmds["MODE_REGISTER"], 100),
("Load RCD F0RC04", f0rc04, 7, cmds["MODE_REGISTER"], 100),
("Load RCD F0RC05", f0rc05, 7, cmds["MODE_REGISTER"], 100),
("Load RCD F0RC0A", f0rc0a, 7, cmds["MODE_REGISTER"], 100),
("Load RCD F0RC3X", f0rc3x, 7, cmds["MODE_REGISTER"], 100),
]
init_sequence = [
("Release reset", 0x0000, 0, cmds["UNRESET"], 50000),
("Bring CKE high", 0x0000, 0, cmds["CKE"], 10000),
] + rdimm_init + [
("Load Mode Register 3", mr3, 3, cmds["MODE_REGISTER"], 0),
("Load Mode Register 6", mr6, 6, cmds["MODE_REGISTER"], 0),
("Load Mode Register 5", mr5, 5, cmds["MODE_REGISTER"], 0),
@ -426,6 +479,10 @@ def get_sdram_phy_c_header(phy_settings, timing_settings):
r += "#define SDRAM_PHY_DELAYS 8\n"
r += "#define SDRAM_PHY_BITSLIPS 4\n"
if phy_settings.is_rdimm:
assert phy_settings.memtype == "DDR4"
r += "#define SDRAM_PHY_DDR4_RDIMM\n"
r += "\n"
r += "static void cdelay(int i);\n"
@ -482,16 +539,32 @@ const unsigned long sdram_dfii_pix_rddata_addr[SDRAM_PHY_PHASES] = {{
r += "static void init_sequence(void)\n{\n"
for comment, a, ba, cmd, delay in init_sequence:
r += "\t/* {0} */\n".format(comment)
r += "\tsdram_dfii_pi0_address_write({0:#x});\n".format(a)
r += "\tsdram_dfii_pi0_baddress_write({0:d});\n".format(ba)
if cmd[:12] == "DFII_CONTROL":
r += "\tsdram_dfii_control_write({0});\n".format(cmd)
else:
r += "\tcommand_p0({0});\n".format(cmd)
if delay:
r += "\tcdelay({0:d});\n".format(delay)
r += "\n"
invert_masks = [(0, 0), ]
if phy_settings.is_rdimm:
assert phy_settings.memtype == "DDR4"
# JESD82-31A page 38
#
# B-side chips have certain usually-inconsequential address and BA
# bits inverted by the RCD to reduce SSO current. For mode register
# writes, however, we must compensate for this. BG[1] also directs
# writes either to the A side (BG[1]=0) or B side (BG[1]=1)
#
# The 'ba != 7' is because we don't do this to writes to the RCD
# itself.
if ba != 7:
invert_masks.append((0b10101111111000, 0b1111))
for a_inv, ba_inv in invert_masks:
r += "\t/* {0} */\n".format(comment)
r += "\tsdram_dfii_pi0_address_write({0:#x});\n".format(a ^ a_inv)
r += "\tsdram_dfii_pi0_baddress_write({0:d});\n".format(ba ^ ba_inv)
if cmd[:12] == "DFII_CONTROL":
r += "\tsdram_dfii_control_write({0});\n".format(cmd)
else:
r += "\tcommand_p0({0});\n".format(cmd)
if delay:
r += "\tcdelay({0:d});\n".format(delay)
r += "\n"
r += "}\n"
r += "#endif\n"

View File

@ -22,7 +22,8 @@ class USDDRPHY(Module, AutoCSR):
memtype = "DDR3",
sys_clk_freq = 100e6,
iodelay_clk_freq = 200e6,
cmd_latency = 0):
cmd_latency = 0,
is_rdimm = False):
phytype = self.__class__.__name__
device = {"USDDRPHY": "ULTRASCALE", "USPDDRPHY": "ULTRASCALE_PLUS"}[phytype]
pads = PHYPadsCombiner(pads)
@ -90,6 +91,16 @@ class USDDRPHY(Module, AutoCSR):
write_latency = cwl_sys_latency
)
if is_rdimm:
# All drive settings for an 8-chip load
self.settings.set_rdimm(
tck = tck,
rcd_pll_bypass = False,
rcd_ca_cs_drive = 0x5,
rcd_odt_cke_drive = 0x5,
rcd_clk_drive = 0x5
)
# DFI Interface ----------------------------------------------------------------------------
self.dfi = dfi = Interface(addressbits, bankbits, nranks, 2*databits, nphases)
if memtype == "DDR4":