phy/s7ddrphy: compute phy settings automatically (based on tck) and add DDR3-1066/1333/1600 support.

This commit is contained in:
Florent Kermarrec 2018-06-28 16:20:07 +02:00
parent ba16ebfb22
commit d9da7c54ee
1 changed files with 71 additions and 26 deletions

View File

@ -1,5 +1,6 @@
# 1:4 frequency-ratio DDR3 PHYs for Series7
# tCK=2.5ns CL=7 CWL=6
# 1:4 frequency-ratio DDR3 PHY for Xilinx's Series7
import math
from migen import *
@ -9,13 +10,37 @@ from litedram.common import PhySettings
from litedram.phy.dfi import *
def get_sys_latency(cas_latency):
return math.ceil(cas_latency/4)
def get_sys_phases(sys_latency, cas_latency, write=False):
cmd_phase = 0
dat_phase = 0
diff_phase = 0
while (diff_phase + cas_latency) != sys_latency*4:
dat_phase += 1
if dat_phase == 4:
dat_phase = 0
cmd_phase += 1
if write:
diff_phase = dat_phase - cmd_phase
else:
diff_phase = cmd_phase - dat_phase
return cmd_phase, dat_phase
class S7DDRPHY(Module, AutoCSR):
def __init__(self, pads, with_odelay):
def __init__(self, pads, with_odelay, sys_clk_freq=100e6):
tck = 2/(8*sys_clk_freq)
addressbits = len(pads.a)
bankbits = len(pads.ba)
databits = len(pads.dq)
nphases = 4
half_sys8x_taps = math.floor(tck/(4*78e-12))
self._half_sys8x_taps = CSRStorage(4, reset=half_sys8x_taps)
if with_odelay:
self._wlevel_en = CSRStorage()
self._wlevel_strobe = CSR()
@ -32,18 +57,35 @@ class S7DDRPHY(Module, AutoCSR):
self._wdly_dqs_rst = CSR()
self._wdly_dqs_inc = CSR()
# compute phy settings
if tck >= 1.875e-9: # ddr3-1066
cl = 7
cwl = 6
elif tck >= 1.5e-9: # ddr3-1333
cl = 10
cwl = 7
elif tck >= 1.25e-9: # ddr3-1600
cl = 11
cwl = 8
cl_sys_latency = get_sys_latency(cl)
cwl_sys_latency = get_sys_latency(cwl)
rdcmdphase, rdphase = get_sys_phases(cl_sys_latency, cl)
wrcmdphase, wrphase = get_sys_phases(cwl_sys_latency, cwl, write=True)
self.settings = PhySettings(
memtype="DDR3",
dfi_databits=2*databits,
nphases=nphases,
rdphase=0,
wrphase=2,
rdcmdphase=1,
wrcmdphase=0,
cl=7,
cwl=6,
read_latency=6,
write_latency=2
rdphase=rdphase,
wrphase=wrphase,
rdcmdphase=rdcmdphase,
wrcmdphase=wrcmdphase,
cl=cl,
cwl=cwl,
read_latency=2 + cl_sys_latency + 2,
write_latency=cwl_sys_latency
)
self.dfi = Interface(addressbits, bankbits, 2*databits, nphases)
@ -183,7 +225,7 @@ class S7DDRPHY(Module, AutoCSR):
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
p_SERDES_MODE="MASTER",
o_OFB=dqs_nodelay if with_odelay else Signal(),
o_OFB=dqs_nodelay if with_odelay else Signal(),
o_OQ=Signal() if with_odelay else dqs_nodelay,
o_TQ=dqs_t,
i_OCE=1, i_TCE=1,
@ -200,7 +242,7 @@ class S7DDRPHY(Module, AutoCSR):
Instance("ODELAYE2",
p_DELAY_SRC="ODATAIN", p_SIGNAL_PATTERN="DATA",
p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0,
p_PIPE_SEL="FALSE", p_ODELAY_TYPE="VARIABLE", p_ODELAY_VALUE=6,
p_PIPE_SEL="FALSE", p_ODELAY_TYPE="VARIABLE", p_ODELAY_VALUE=half_sys8x_taps,
i_C=ClockSignal(),
i_LD=self._dly_sel.storage[i] & self._wdly_dqs_rst.re,
@ -278,7 +320,7 @@ class S7DDRPHY(Module, AutoCSR):
Instance("IDELAYE2",
p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA",
p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", p_REFCLK_FREQUENCY=200.0,
p_PIPE_SEL="FALSE", p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=6,
p_PIPE_SEL="FALSE", p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=0,
i_C=ClockSignal(),
i_LD=self._dly_sel.storage[i//8] & self._rdly_dq_rst.re,
@ -295,12 +337,12 @@ class S7DDRPHY(Module, AutoCSR):
# Flow control
#
# total read latency = 6:
# total read latency:
# 2 cycles through OSERDESE2
# 2 cycles CAS
# cl_sys_latency cycles CAS
# 2 cycles through ISERDESE2
rddata_en = self.dfi.phases[self.settings.rdphase].rddata_en
for i in range(6-1):
for i in range(self.settings.read_latency-1):
n_rddata_en = Signal()
self.sync += n_rddata_en.eq(rddata_en)
rddata_en = n_rddata_en
@ -312,10 +354,13 @@ class S7DDRPHY(Module, AutoCSR):
for phase in self.dfi.phases]
oe = Signal()
last_wrdata_en = Signal(4)
last_wrdata_en = Signal(cwl_sys_latency+2)
wrphase = self.dfi.phases[self.settings.wrphase]
self.sync += last_wrdata_en.eq(Cat(wrphase.wrdata_en, last_wrdata_en[:3]))
self.comb += oe.eq(last_wrdata_en[1] | last_wrdata_en[2] | last_wrdata_en[3])
self.sync += last_wrdata_en.eq(Cat(wrphase.wrdata_en, last_wrdata_en[:-1]))
self.comb += oe.eq(
last_wrdata_en[cwl_sys_latency-1] |
last_wrdata_en[cwl_sys_latency] |
last_wrdata_en[cwl_sys_latency+1])
if with_odelay:
self.sync += \
If(self._wlevel_en.storage,
@ -331,14 +376,14 @@ class S7DDRPHY(Module, AutoCSR):
class V7DDRPHY(S7DDRPHY):
def __init__(self, pads):
S7DDRPHY.__init__(self, pads, with_odelay=True)
def __init__(self, pads, **kwargs):
S7DDRPHY.__init__(self, pads, with_odelay=True, **kwargs)
class K7DDRPHY(S7DDRPHY):
def __init__(self, pads):
S7DDRPHY.__init__(self, pads, with_odelay=True)
def __init__(self, pads, **kwargs):
S7DDRPHY.__init__(self, pads, with_odelay=True, **kwargs)
class A7DDRPHY(S7DDRPHY):
def __init__(self, pads):
S7DDRPHY.__init__(self, pads, with_odelay=False)
def __init__(self, pads, **kwargs):
S7DDRPHY.__init__(self, pads, with_odelay=False, **kwargs)