From 3194b772ae85623556d3c1d7cc9d5ad3ffbf513e Mon Sep 17 00:00:00 2001 From: mwojcik Date: Mon, 16 Jan 2023 18:14:56 +0800 Subject: [PATCH] move clocking to zynq_clocking add clock-switching FSM restore order --- src/gateware/kasli_soc.py | 58 ++++------------ src/gateware/zc706.py | 32 +++++---- src/gateware/zynq_clocking.py | 109 +++++++++++++++++++++++++++++++ src/runtime/src/rtio_clocking.rs | 13 ++-- 4 files changed, 146 insertions(+), 66 deletions(-) create mode 100644 src/gateware/zynq_clocking.py diff --git a/src/gateware/kasli_soc.py b/src/gateware/kasli_soc.py index c573274..2d533b7 100755 --- a/src/gateware/kasli_soc.py +++ b/src/gateware/kasli_soc.py @@ -24,46 +24,9 @@ import dma import analyzer import acpki import drtio_aux_controller +import zynq_clocking -class SYSCRG(Module, AutoCSR): - def __init__(self, platform, main_clk): - self.pll_locked = CSRStatus() - self.clock_domains.cd_sys = ClockDomain() - self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) - pll_locked = Signal() - sys_clk = Signal() - sys4x_clk = Signal() - fb_clk = Signal() - self.specials += [ - Instance("PLLE2_ADV", - p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, - p_BANDWIDTH="HIGH", - p_REF_JITTER1=0.001, - p_CLKIN1_PERIOD=8.0, - i_CLKIN1=main_clk, - i_CLKINSEL=1, - - # VCO @ 1.5GHz when using 125MHz input - p_CLKFBOUT_MULT=12, p_DIVCLK_DIVIDE=1, - i_CLKFBIN=fb_clk, - i_RST=0, - - o_CLKFBOUT=fb_clk, - - p_CLKOUT0_DIVIDE=3, p_CLKOUT0_PHASE=0.0, - o_CLKOUT0=sys4x_clk, - - p_CLKOUT1_DIVIDE=12, p_CLKOUT1_PHASE=0.0, - o_CLKOUT1=sys_clk), - Instance("BUFG", i_I=sys_clk, o_O=self.cd_sys.clk), - Instance("BUFG", i_I=sys4x_clk, o_O=self.cd_sys4x.clk), - - AsyncResetSynchronizer(self.cd_sys, ~pll_locked), - ] - self.comb += self.pll_locked.status.eq(pll_locked) - - eem_iostandard_dict = { 0: "LVDS_25", 1: "LVDS_25", @@ -129,7 +92,7 @@ class GenericStandalone(SoCCore): ] self.crg = self.ps7 # HACK for eem_7series to find the clock - self.submodules.sys_crg = SYSCRG(self.platform, clk_synth_se) + self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.ps7, clk_synth_se) self.csr_devices.append("sys_crg") # another hack since ps7 itself does not have cd_sys anymore self.crg.cd_sys = self.sys_crg.cd_sys @@ -149,7 +112,7 @@ class GenericStandalone(SoCCore): self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) self.rtio_channels.append(rtio.LogChannel()) - self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3) self.submodules.rtio_core = rtio.Core(self.rtio_tsc, self.rtio_channels) self.csr_devices.append("rtio_core") @@ -219,8 +182,10 @@ class GenericMaster(SoCCore): self.csr_devices.append("drtio_transceiver") self.crg = self.ps7 # HACK for eem_7series to find the clock - self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq) - self.csr_devices.append("rtio_crg") + self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.drtio_transceiver.gtps[0].txoutclk) + self.csr_devices.append("sys_crg") + # another hack since ps7 itself does not have cd_sys anymore + self.crg.cd_sys = self.sys_crg.cd_sys self.rustc_cfg["has_si5324"] = None self.rustc_cfg["si5324_soft_reset"] = None @@ -239,7 +204,7 @@ class GenericMaster(SoCCore): self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) self.rtio_channels.append(rtio.LogChannel()) - self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3) drtio_csr_group = [] drtioaux_csr_group = [] @@ -334,9 +299,8 @@ class GenericSatellite(SoCCore): platform.add_platform_command("set_input_jitter clk_fpga_0 0.24") self.crg = self.ps7 # HACK for eem_7series to find the clock - self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq) - self.csr_devices.append("rtio_crg") - self.rustc_cfg["has_rtio_crg"] = None + self.submodules.sys_crg = zynq_clocking.SYSCRG(self.platform, self.drtio_transceiver.gtps[0].txoutclk) + self.csr_devices.append("sys_crg") data_pads = [platform.request("sfp", i) for i in range(4)] @@ -360,7 +324,7 @@ class GenericSatellite(SoCCore): self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) self.rtio_channels.append(rtio.LogChannel()) - self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC(glbl_fine_ts_width=3) drtioaux_csr_group = [] drtioaux_memory_group = [] diff --git a/src/gateware/zc706.py b/src/gateware/zc706.py index dacf33d..095e47c 100755 --- a/src/gateware/zc706.py +++ b/src/gateware/zc706.py @@ -25,11 +25,14 @@ import dma import analyzer import acpki import drtio_aux_controller +import zynq_clocking class SYSCRG(Module, AutoCSR): - def __init__(self, platform, main_clk): + def __init__(self, platform, ps7, main_clk): self.pll_locked = CSRStatus() + self.pll_clksel = CSRStorage() + self.pll_reset = CSRStorage() self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) @@ -37,31 +40,35 @@ class SYSCRG(Module, AutoCSR): sys_clk = Signal() sys4x_clk = Signal() fb_clk = Signal() + fclk_buf = Signal() self.specials += [ + Instance("BUFG", i_I=ps7.fclk.clk[0], o_O=fclk_buf), Instance("PLLE2_ADV", p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + p_BANDWIDTH="HIGH", + p_REF_JITTER1=0.001, + p_CLKIN1_PERIOD=8.0, i_CLKIN1=main_clk, + p_CLKIN2_PERIOD=8.0, i_CLKIN2=fclk_buf, + i_CLKINSEL=self.pll_clksel.storage, - p_REF_JITTER1=0.01, - p_CLKIN1_PERIOD=8.0, - i_CLKIN1=main_clk, - i_CLKINSEL=1, - - # VCO @ 1GHz when using 125MHz input - p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, + # VCO @ 1.5GHz when using 125MHz input + p_CLKFBOUT_MULT=12, p_DIVCLK_DIVIDE=1, i_CLKFBIN=fb_clk, - i_RST=0, + i_RST=self.pll_reset.storage, o_CLKFBOUT=fb_clk, - p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, + p_CLKOUT0_DIVIDE=12, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=sys_clk, - p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, + p_CLKOUT1_DIVIDE=3, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=sys4x_clk), Instance("BUFG", i_I=sys_clk, o_O=self.cd_sys.clk), Instance("BUFG", i_I=sys4x_clk, o_O=self.cd_sys4x.clk), AsyncResetSynchronizer(self.cd_sys, ~pll_locked) ] self.comb += self.pll_locked.status.eq(pll_locked) + platform.add_period_constraint(fclk_buf, 8.) + platform.add_false_path_constraints(self.cd_sys.clk, fclk_buf, main_clk) class SMAClkinForward(Module): @@ -154,6 +161,7 @@ class ZC706(SoCCore): platform.add_period_constraint(si5324_out.p, 8.0) self.specials += [ Instance("IBUFDS_GTE2", + i_CEB=0, i_I=si5324_out.p, i_IB=si5324_out.n, o_O=cdr_clk, p_CLKCM_CFG="0b1", @@ -165,7 +173,7 @@ class ZC706(SoCCore): self.rustc_cfg["si5324_as_synthesizer"] = None self.rustc_cfg["si5324_soft_reset"] = None - self.submodules.sys_crg = SYSCRG(self.platform, cdr_clk_buf) + self.submodules.sys_crg = SYSCRG(self.platform, self.ps7, cdr_clk_buf) self.csr_devices.append("sys_crg") self.platform.add_period_constraint(self.sys_crg.cd_sys.clk, 8.) diff --git a/src/gateware/zynq_clocking.py b/src/gateware/zynq_clocking.py new file mode 100644 index 0000000..92b9c60 --- /dev/null +++ b/src/gateware/zynq_clocking.py @@ -0,0 +1,109 @@ +from migen import * +from migen.genlib.cdc import MultiReg +from migen.genlib.resetsync import AsyncResetSynchronizer +from misoc.interconnect.csr import * + + +class ClockSwitchFSM(Module): + def __init__(self): + self.i_clk_sw = Signal() + + self.o_clk_sw = Signal() + self.o_reset = Signal() + + ### + + i_switch = Signal() + o_switch = Signal() + reset = Signal() + + # at 125MHz bootstrap cd, will get around 0.5ms + delay_counter = Signal(16, reset=0xFFFF) + + # register to prevent glitches + self.sync.bootstrap += [ + self.o_clk_sw.eq(o_switch), + self.o_reset.eq(reset), + ] + + self.o_clk_sw.attr.add("no_retiming") + self.o_reset.attr.add("no_retiming") + self.i_clk_sw.attr.add("no_retiming") + i_switch.attr.add("no_retiming") + + self.specials += MultiReg(self.i_clk_sw, i_switch, "bootstrap") + + fsm = ClockDomainsRenamer("bootstrap")(FSM(reset_state="START")) + + self.submodules += fsm + + fsm.act("START", + If(i_switch & ~o_switch, + NextState("RESET_START")) + ) + + fsm.act("RESET_START", + reset.eq(1), + If(delay_counter == 0, + NextValue(delay_counter, 0xFFFF), + NextState("CLOCK_SWITCH") + ).Else( + NextValue(delay_counter, delay_counter-1), + ) + ) + + fsm.act("CLOCK_SWITCH", + reset.eq(1), + NextValue(o_switch, 1), + NextValue(delay_counter, delay_counter-1), + If(delay_counter == 0, + NextState("START")) + ) + + +class SYSCRG(Module, AutoCSR): + def __init__(self, platform, ps7, main_clk): + self.clock_switch = CSRStorage() + self.clock_domains.cd_bootstrap = ClockDomain(reset_less=True) + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) + + pll_locked = Signal() + sys_clk = Signal() + sys4x_clk = Signal() + fb_clk = Signal() + fclk_buf = Signal() + + self.submodules.clk_sw_fsm = ClockSwitchFSM() + + self.comb += self.clk_sw_fsm.i_clk_sw.eq(self.clock_switch.storage) + + self.specials += [ + Instance("BUFG", i_I=ps7.fclk.clk[0], o_O=self.cd_bootstrap.clk), + Instance("PLLE2_ADV", + p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + p_BANDWIDTH="HIGH", + p_REF_JITTER1=0.001, + p_CLKIN1_PERIOD=8.0, i_CLKIN1=main_clk, + p_CLKIN2_PERIOD=8.0, i_CLKIN2=self.cd_bootstrap.clk, + i_CLKINSEL=self.clk_sw_fsm.o_clk_sw, + + # VCO @ 1.5GHz when using 125MHz input + p_CLKFBOUT_MULT=12, p_DIVCLK_DIVIDE=1, + i_CLKFBIN=fb_clk, + i_RST=self.clk_sw_fsm.o_reset, + + o_CLKFBOUT=fb_clk, + + p_CLKOUT0_DIVIDE=3, p_CLKOUT0_PHASE=0.0, + o_CLKOUT0=sys4x_clk, + + p_CLKOUT1_DIVIDE=12, p_CLKOUT1_PHASE=0.0, + o_CLKOUT1=sys_clk), + Instance("BUFG", i_I=sys_clk, o_O=self.cd_sys.clk), + Instance("BUFG", i_I=sys4x_clk, o_O=self.cd_sys4x.clk), + + AsyncResetSynchronizer(self.cd_sys, ~pll_locked | ~ps7.fclk.reset_n[0]), + ] + platform.add_period_constraint(self.cd_bootstrap.clk, 8.) + platform.add_false_path_constraints(self.cd_sys.clk, self.cd_bootstrap.clk, main_clk) diff --git a/src/runtime/src/rtio_clocking.rs b/src/runtime/src/rtio_clocking.rs index 49a6c31..732ee32 100644 --- a/src/runtime/src/rtio_clocking.rs +++ b/src/runtime/src/rtio_clocking.rs @@ -68,17 +68,16 @@ fn get_rtio_clock_cfg(cfg: &Config) -> RtioClock { fn init_rtio(timer: &mut GlobalTimer, _clk: RtioClock) { - timer.delay_ms(1); - let locked = unsafe { pl::csr::sys_crg::pll_locked_read() != 0 }; - if locked { - info!("RTIO PLL locked"); - } else { - panic!("RTIO PLL failed to lock"); + info!("Switching SYS clocks..."); + unsafe { + pl::csr::sys_crg::clock_switch_write(1); } - + timer.delay_ms(2); unsafe { pl::csr::rtio_core::reset_phy_write(1); } + // if it's not locked, it will hang at the CSR. + info!("SYS PLL locked"); } #[cfg(has_drtio)]