sdram/phy/s6ddrphy: add S6QuarterRateDDRPHY to run DDR3 at higher frequencies.

Built on top of S6HalfRateDDRPHY, exposes a 4 phases DFI interface to the controller with a 2x slower clock.
Validated on the Numato Lab opsis board (50MHz sys_clk/ DDR400), should also work on the Novena laptop (same DDR3 module).
This commit is contained in:
Florent Kermarrec 2015-08-22 12:15:53 +02:00
parent 8bb30a8620
commit 50e857e99c
1 changed files with 96 additions and 1 deletions

View File

@ -1,4 +1,4 @@
# 1:2 frequency-ratio DDR / LPDDR / DDR2 PHY for Spartan-6
# 1:2 and 1:4 frequency-ratio DDR / LPDDR / DDR2 / DDR3 PHYs for Spartan-6
#
# Assert dfi_wrdata_en and present the data
# on dfi_wrdata_mask/dfi_wrdata in the same
@ -393,3 +393,98 @@ class S6HalfRateDDRPHY(Module):
phase.rddata.eq(d_dfi[n].rddata),
phase.rddata_valid.eq(rddata_sr[0]),
]
class S6QuarterRateDDRPHY(Module):
def __init__(self, pads, module, rd_bitslip, wr_bitslip, dqs_ddr_alignment):
if module.memtype not in ["DDR3"]:
raise NotImplementedError("S6QuarterRateDDRPHY only supports DDR3")
half_rate_phy = S6HalfRateDDRPHY(pads, module, rd_bitslip, wr_bitslip, dqs_ddr_alignment)
self.submodules += RenameClockDomains(half_rate_phy, {"sys" : "sys2x"})
addressbits = flen(pads.a)
bankbits = flen(pads.ba)
databits = flen(pads.dq)
nphases = 4
self.settings = sdram.PhySettings(
memtype="DDR3",
dfi_databits=2*databits,
nphases=nphases,
rdphase=0,
wrphase=1,
rdcmdphase=1,
wrcmdphase=0,
cl=5,
cwl=6,
read_latency=6//2+1,
write_latency=2//2
)
self.module = module
self.dfi = Interface(addressbits, bankbits, 2*databits, nphases)
self.clk8x_wr_strb = half_rate_phy.clk4x_wr_strb
self.clk8x_rd_strb = half_rate_phy.clk4x_rd_strb
# sys_clk : system clk, used for dfi interface
# sys2x_clk : half rate sys clk
sd_sys = getattr(self.sync, "sys")
sd_sys2x = getattr(self.sync, "sys2x")
# select active sys2x phase
# sys_clk ----____----____
# phase_sel 0 1 0 1
phase_sel = Signal()
phase_sys2x = Signal.like(phase_sel)
phase_sys = Signal.like(phase_sys2x)
sd_sys += phase_sys.eq(phase_sys2x)
sd_sys2x += [
If(phase_sys2x == phase_sys,
phase_sel.eq(0),
).Else(
phase_sel.eq(~phase_sel)
),
phase_sys2x.eq(~phase_sel)
]
# DFI adaptation
# Commands and writes
dfi_leave_out = set(["rddata", "rddata_valid", "wrdata_en"])
self.comb += [
If(~phase_sel,
Record.connect(self.dfi.phases[0], half_rate_phy.dfi.phases[0], leave_out=dfi_leave_out),
Record.connect(self.dfi.phases[1], half_rate_phy.dfi.phases[1], leave_out=dfi_leave_out),
).Else(
Record.connect(self.dfi.phases[2], half_rate_phy.dfi.phases[0], leave_out=dfi_leave_out),
Record.connect(self.dfi.phases[3], half_rate_phy.dfi.phases[1], leave_out=dfi_leave_out),
),
]
wr_data_en = self.dfi.phases[self.settings.wrphase].wrdata_en & ~phase_sel
wr_data_en_d = Signal()
sd_sys2x += wr_data_en_d.eq(wr_data_en)
self.comb += half_rate_phy.dfi.phases[half_rate_phy.settings.wrphase].wrdata_en.eq(wr_data_en | wr_data_en_d)
# Reads
rddata = Array(Signal(2*databits) for i in range(2))
rddata_valid = Signal(2)
for i in range(2):
sd_sys2x += [
rddata_valid[i].eq(half_rate_phy.dfi.phases[i].rddata_valid),
rddata[i].eq(half_rate_phy.dfi.phases[i].rddata)
]
sd_sys += [
self.dfi.phases[0].rddata.eq(rddata[0]),
self.dfi.phases[0].rddata_valid.eq(rddata_valid[0]),
self.dfi.phases[1].rddata.eq(rddata[1]),
self.dfi.phases[1].rddata_valid.eq(rddata_valid[1]),
self.dfi.phases[2].rddata.eq(half_rate_phy.dfi.phases[0].rddata),
self.dfi.phases[2].rddata_valid.eq(half_rate_phy.dfi.phases[0].rddata_valid),
self.dfi.phases[3].rddata.eq(half_rate_phy.dfi.phases[1].rddata),
self.dfi.phases[3].rddata_valid.eq(half_rate_phy.dfi.phases[1].rddata_valid)
]