gateware: Add CSR Ctrl to PL's MMCM

- Generate 45 Degree Phase Shifted DDR Clock
- PLLE2_Base -> MMCM_ADV for ddr clock dynamic phase shift
- Add mmcm_rst, ddr_clk_ps, mmcm_locked status to CSR
- Generate dco2d rst signal from mmcm and connect to the related logic
This commit is contained in:
linuswck 2024-11-08 12:35:13 +08:00
parent e708696b5d
commit 6cef418756
2 changed files with 60 additions and 31 deletions

View File

@ -22,11 +22,12 @@ from migen.genlib.cdc import MultiReg
from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
class _CRG(Module): class CRG(Module):
def __init__(self, platform, dco_clk, dco_freq=200e6): def __init__(self, platform, dco_clk, dco_freq=200e6):
self.clock_domains.cd_dco = ClockDomain() self.clock_domains.cd_dco = ClockDomain()
self.clock_domains.cd_dco2x = ClockDomain() self.clock_domains.cd_dco2x = ClockDomain()
self.clock_domains.cd_dco2d = ClockDomain() self.clock_domains.cd_dco2d = ClockDomain()
self.clock_domains.cd_dco2d_45_degree = ClockDomain()
dco_clk_p, dco_clk_n = dco_clk dco_clk_p, dco_clk_n = dco_clk
dco_clk_buf = Signal() dco_clk_buf = Signal()
@ -41,59 +42,83 @@ class _CRG(Module):
clk_dco = Signal() clk_dco = Signal()
clk_dco2x = Signal() clk_dco2x = Signal()
clk_dco2d = Signal() clk_dco2d = Signal()
clk_dco2d_45_degree = Signal()
mmcm_ps_psdone = Signal()
self.locked = Signal() self.locked = Signal()
self.mmcm_rst = Signal()
self.ddr_clk_phase_shift_en = Signal()
self.ddr_clk_phase_incdec = Signal()
platform.add_period_constraint(dco_clk_p, 1e9 / dco_freq) platform.add_period_constraint(dco_clk_p, 1e9 / dco_freq)
self.specials += [ self.specials += [
Instance( Instance(
"PLLE2_BASE", "MMCME2_ADV",
p_BANDWIDTH="OPTIMIZED", p_BANDWIDTH="OPTIMIZED",
p_DIVCLK_DIVIDE=1, p_DIVCLK_DIVIDE=1,
p_CLKFBOUT_PHASE=0.0, p_CLKFBOUT_PHASE=0.0,
p_CLKFBOUT_MULT=4, # VCO @ 800 MHz p_CLKFBOUT_MULT_F=4, # VCO @ 800 MHz
p_CLKIN1_PERIOD=(1e9 / dco_freq), p_CLKIN1_PERIOD=(1e9 / dco_freq),
p_REF_JITTER1=0.01, p_REF_JITTER1=0.01,
p_STARTUP_WAIT="FALSE", p_STARTUP_WAIT="FALSE",
i_CLKIN1=dco_clk_buf, i_CLKIN1=dco_clk_buf,
i_PWRDWN=0, i_PWRDWN=0,
i_RST=ResetSignal("sys"), i_RST=ResetSignal("sys") | self.mmcm_rst,
i_CLKFBIN=clk_feedback_buf, i_CLKFBIN=clk_feedback_buf,
o_CLKFBOUT=clk_feedback, o_CLKFBOUT=clk_feedback,
p_CLKOUT0_DIVIDE=4,
p_CLKOUT0_PHASE=0.0, p_CLKOUT0_USE_FINE_PS="TRUE",
p_CLKOUT0_DIVIDE_F=8,
p_CLKOUT0_PHASE=45.0,
p_CLKOUT0_DUTY_CYCLE=0.5, p_CLKOUT0_DUTY_CYCLE=0.5,
o_CLKOUT0=clk_dco, # 200 MHz <- dco_clk o_CLKOUT0=clk_dco2d_45_degree, # 100 MHz <- dco_clk / 2 = 200 MHz / 2
o_LOCKED=self.locked,
p_CLKOUT1_DIVIDE=2, p_CLKOUT1_DIVIDE=2,
p_CLKOUT1_PHASE=0.0, p_CLKOUT1_PHASE=0.0,
p_CLKOUT1_DUTY_CYCLE=0.5, p_CLKOUT1_DUTY_CYCLE=0.5,
o_CLKOUT1=clk_dco2x, # 400 MHZ <- 2 * dco_clk = 2*200 MHz o_CLKOUT1=clk_dco2x, # 400 MHZ <- 2 * dco_clk = 2*200 MHz
p_CLKOUT2_DIVIDE=8, p_CLKOUT2_DIVIDE=8,
p_CLKOUT2_PHASE=0.0, p_CLKOUT2_PHASE=0.0,
p_CLKOUT2_DUTY_CYCLE=0.5, p_CLKOUT2_DUTY_CYCLE=0.5,
o_CLKOUT2=clk_dco2d, # 100 MHz <- dco_clk / 2 = 200 MHz / 2 o_CLKOUT2=clk_dco2d, # 100 MHz <- dco_clk / 2 = 200 MHz / 2
o_LOCKED=self.locked,
p_CLKOUT3_DIVIDE=4,
p_CLKOUT3_PHASE=0.0,
p_CLKOUT3_DUTY_CYCLE=0.5,
o_CLKOUT3=clk_dco, # 200 MHz <- dco_clk
i_PSCLK=ClockSignal(),
i_PSEN=self.ddr_clk_phase_shift_en,
i_PSINCDEC=self.ddr_clk_phase_incdec,
o_PSDONE=mmcm_ps_psdone,
) )
] ]
self.specials += Instance("BUFG", i_I=clk_feedback, o_O=clk_feedback_buf) self.specials += Instance("BUFG", i_I=clk_feedback, o_O=clk_feedback_buf)
self.specials += Instance("BUFG", i_I=clk_dco, o_O=self.cd_dco.clk) self.specials += Instance("BUFG", i_I=clk_dco, o_O=self.cd_dco.clk)
self.specials += Instance("BUFG", i_I=clk_dco2d, o_O=self.cd_dco2d.clk) self.specials += Instance("BUFG", i_I=clk_dco2d, o_O=self.cd_dco2d.clk)
self.specials += Instance("BUFG", i_I=clk_dco2d_45_degree, o_O=self.cd_dco2d_45_degree.clk)
self.specials += Instance("BUFG", i_I=clk_dco2x, o_O=self.cd_dco2x.clk) self.specials += Instance("BUFG", i_I=clk_dco2x, o_O=self.cd_dco2x.clk)
# Ignore dco2d to mmcm dco_clk path created by SoC's rst.
platform.add_false_path_constraints(self.cd_dco2d.clk, dco_clk_buf)
self.specials += Instance("FD", p_INIT=1, i_D=~self.locked, i_C=self.cd_dco2d.clk, o_Q=self.cd_dco2d.rst)
class ADC(Module, AutoCSR): class ADC(Module, AutoCSR):
def __init__(self, platform, dco_freq=200e6): def __init__(self, platform, dco_freq=200e6):
adc_pads = platform.request("adc") adc_pads = platform.request("adc")
afe_pads = platform.request("adc_afe") afe_pads = platform.request("adc_afe")
self.frame_csr = CSRStatus(4) self.frame_csr = CSRStatus(5)
self.data_ch0 = CSRStatus(16) self.data_ch0 = CSRStatus(16)
self.data_ch1 = CSRStatus(16) self.data_ch1 = CSRStatus(16)
self.tap_delay = CSRStorage(5) self.tap_delay = CSRStorage(5)
self.bitslip_csr = CSRStorage(1) self.bitslip_csr = CSRStorage(1)
self.afe_ctrl = CSRStorage(4) self.afe_ctrl = CSRStorage(7)
tap_delay_val = Signal(5) tap_delay_val = Signal(5)
bitslip = Signal() bitslip = Signal()
@ -117,11 +142,14 @@ class ADC(Module, AutoCSR):
# dco_clk.n.eq(adc_pads.dco_n), # dco_clk.n.eq(adc_pads.dco_n),
tap_delay_val.eq(self.tap_delay.storage), tap_delay_val.eq(self.tap_delay.storage),
Cat(ch1_gain_x10, ch2_gain_x10, ch1_shdn, ch2_shdn).eq( Cat(ch1_gain_x10, ch2_gain_x10, ch1_shdn, ch2_shdn).eq(
self.afe_ctrl.storage self.afe_ctrl.storage[0:4]
), ),
] ]
self.submodules._crg = _CRG(platform, dco_clk, dco_freq) self.submodules.crg = CRG(platform, dco_clk, dco_freq)
self.comb += self.afe_ctrl.storage[4].eq(self.crg.mmcm_rst)
self.comb += self.afe_ctrl.storage[5].eq(self.crg.ddr_clk_phase_shift_en)
self.comb += self.afe_ctrl.storage[6].eq(self.crg.ddr_clk_phase_incdec)
self.specials += MultiReg(self.bitslip_csr.re, bitslip_re_dco_2d, "dco2d") self.specials += MultiReg(self.bitslip_csr.re, bitslip_re_dco_2d, "dco2d")
self.sync.dco2d += [ self.sync.dco2d += [
@ -129,7 +157,8 @@ class ADC(Module, AutoCSR):
] ]
self.comb += [ self.comb += [
self.frame_csr.status.eq(self.s_frame), self.frame_csr.status[0:4].eq(self.s_frame[0:4]),
self.frame_csr.status[4].eq(self.crg.locked),
self.data_ch0.status.eq(self.data_out[0]), self.data_ch0.status.eq(self.data_out[0]),
self.data_ch1.status.eq(self.data_out[1]), self.data_ch1.status.eq(self.data_out[1]),
] ]
@ -146,7 +175,7 @@ class ADC(Module, AutoCSR):
self.specials += Instance( self.specials += Instance(
"LTC2195", "LTC2195",
i_rst_in=ResetSignal("sys"), i_rst_in=ResetSignal("dco2d"),
i_clk200=ClockSignal("idelay"), i_clk200=ClockSignal("idelay"),
i_DCO=ClockSignal("dco"), i_DCO=ClockSignal("dco"),
i_DCO_2D=ClockSignal("dco2d"), i_DCO_2D=ClockSignal("dco2d"),

View File

@ -42,7 +42,7 @@ class DAC(Module, AutoCSR):
self.comb += [ self.comb += [
Cat(manual_override, ch0_pd, ch1_pd).eq(self.dac_ctrl.storage), Cat(manual_override, ch0_pd, ch1_pd).eq(self.dac_ctrl.storage),
dac_pads.rst.eq(ResetSignal("sys")), dac_pads.rst.eq(ResetSignal("dco2d")),
dac_afe_pads.ch1_pd_n.eq(~ch0_pd), dac_afe_pads.ch1_pd_n.eq(~ch0_pd),
dac_afe_pads.ch2_pd_n.eq(~ch1_pd), dac_afe_pads.ch2_pd_n.eq(~ch1_pd),
output_data_ch0.eq( output_data_ch0.eq(
@ -53,22 +53,22 @@ class DAC(Module, AutoCSR):
), ),
] ]
# data self.specials += [
for lane in range(14): Instance("ODDR",
self.specials += DDROutput( i_C=ClockSignal("dco2d"),
i1 = output_data_ch0[lane], i_CE=~ResetSignal("dco2d"),
i2 = output_data_ch1[lane], i_D1=output_data_ch0[lane], # DDR CLK Rising Edge
o = dac_pads.data[lane], i_D2=output_data_ch1[lane], # DDR CLK Falling Edge
clk = ClockSignal("dco2d") o_Q=dac_pads.data[lane],
) p_DDR_CLK_EDGE="SAME_EDGE")
for lane in range(14)]
# clock forwarding self.specials += Instance("ODDR",
self.specials += DDROutput( i_C=ClockSignal("dco2d_45_degree"),
i1 = 0b0, i_CE=~ResetSignal("dco2d"),
i2 = 0b1, i_D1=0,
o = dac_pads.dclkio, i_D2=1,
clk = ClockSignal("dco2d"), o_Q=dac_pads.dclkio,
) p_DDR_CLK_EDGE="SAME_EDGE")
class AUX_DAC_CTRL(Module, AutoCSR): class AUX_DAC_CTRL(Module, AutoCSR):