From 400af2c582316b7f94e442ed4eaeb74a95ae1275 Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Tue, 15 Dec 2020 17:55:59 +0800 Subject: [PATCH] sayma: use QPLL for 1GSPS JESD204B TX * requires jesd204b changes as in https://github.com/HarryMakes/jesd204b/tree/gth --- artiq/firmware/libboard_artiq/ad9154.rs | 24 +++++- artiq/gateware/jesd204_tools.py | 106 ++++++++++++++++++++---- artiq/gateware/targets/sayma_amc.py | 8 +- 3 files changed, 118 insertions(+), 20 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index f671e2660..388c8ac9a 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -87,7 +87,7 @@ const JESD_SETTINGS: JESDSettings = JESDSettings { np: 16, f: 2, s: 2, - k: 16, + k: 32, cs: 0, subclassv: 1, @@ -349,6 +349,28 @@ pub fn setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { write(ad9154_reg::GENERAL_JRX_CTRL_0, 0x1*ad9154_reg::LINK_EN | 0*ad9154_reg::LINK_PAGE | 0*ad9154_reg::LINK_MODE | 0*ad9154_reg::CHECKSUM_MODE); + + // JESD Checks + let jesd_checks = read(ad9154_reg::JESD_CHECKS); + if jesd_checks & ad9154_reg::ERR_DLYOVER == ad9154_reg::ERR_DLYOVER { + error!("LMFC_Delay > JESD_K Parameter") + } + if jesd_checks & ad9154_reg::ERR_WINLIMIT == ad9154_reg::ERR_WINLIMIT { + error!("Unsupported Window Limit") + } + if jesd_checks & ad9154_reg::ERR_JESDBAD == ad9154_reg::ERR_JESDBAD { + error!("Unsupported M/L/S/F Selection") + } + if jesd_checks & ad9154_reg::ERR_KUNSUPP == ad9154_reg::ERR_KUNSUPP { + error!("Unsupported K Values") + } + if jesd_checks & ad9154_reg::ERR_SUBCLASS == ad9154_reg::ERR_SUBCLASS { + error!("Unsupported SUBCLASSV Value") + } + if jesd_checks & ad9154_reg::ERR_INTSUPP == ad9154_reg::ERR_INTSUPP { + error!("Unsupported Interpolation Factor") + } + info!(" ...done"); Ok(()) } diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 8cd8e9872..6baa07f15 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -8,7 +8,11 @@ from misoc.interconnect.csr import * from jesd204b.common import (JESD204BTransportSettings, JESD204BPhysicalSettings, JESD204BSettings) -from jesd204b.phy.gth import GTHChannelPLL as JESD204BGTHChannelPLL +from jesd204b.phy.gth import (GTHChannelPLL as JESD204BGTHChannelPLL, + GTHQuadPLL as JESD204BGTHQuadPLL, + GTHTransmitter as JESD204BGTHTransmitter, + GTHInit as JESD204BGTHInit, + GTHTransmitterInterconnect as JESD204BGTHTransmitterInterconnect) from jesd204b.phy import JESD204BPhyTX from jesd204b.core import JESD204BCoreTX from jesd204b.core import JESD204BCoreTXControl @@ -16,6 +20,7 @@ from jesd204b.core import JESD204BCoreTXControl class UltrascaleCRG(Module, AutoCSR): linerate = int(10e9) # linerate = 20*data_rate*4/8 = data_rate*10 + # data_rate = dac_rate/interp_factor refclk_freq = int(250e6) fabric_freq = int(125e6) @@ -41,30 +46,99 @@ PhyPads = namedtuple("PhyPads", "txp txn") class UltrascaleTX(Module, AutoCSR): - def __init__(self, platform, sys_crg, jesd_crg, dac): + def __init__(self, platform, sys_crg, jesd_crg, dac, pll_type="cpll", tx_half=False): + # Note: In general, the choice between channel and quad PLLs can be made based on the "nominal operating ranges", which are (see UG576, Ch.2): + # CPLL: 2.0 - 6.25 GHz + # QPLL0: 9.8 - 16.375 GHz + # QPLL1: 8.0 - 13.0 GHz + # However, the exact frequency and/or linerate range should be checked according to the model and speed grade from their corresponding datasheets. + pll_cls = { + "cpll": JESD204BGTHChannelPLL, + "qpll": JESD204BGTHQuadPLL + }[pll_type] ps = JESD204BPhysicalSettings(l=8, m=4, n=16, np=16) - ts = JESD204BTransportSettings(f=2, s=2, k=16, cs=0) + ts = JESD204BTransportSettings(f=2, s=2, k=32, cs=0) settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) jesd_pads = platform.request("dac_jesd", dac) + plls = [] phys = [] for i in range(len(jesd_pads.txp)): - cpll = JESD204BGTHChannelPLL( - jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate) - self.submodules += cpll + pll = pll_cls( + jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate) + self.submodules += pll + plls.append(pll) + # QPLL quads + if pll_type == "qpll": + gthe3_common_cfgs = [] + for i in range(0, len(plls), 4): + # GTHE3_COMMON common signals + qpll_clk = Signal() + qpll_refclk = Signal() + qpll_reset = Signal() + qpll_lock = Signal() + # GTHE3_COMMON + self.specials += pll_cls.get_gthe3_common( + jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate, + qpll_clk, qpll_refclk, qpll_reset, qpll_lock) + gthe3_common_cfgs.append({ + "clk": qpll_clk, + "refclk": qpll_refclk, + "reset": qpll_reset, + "lock": qpll_lock + }) + # Per-channel PLL phys + for i, pll in enumerate(plls): + # PhyTX phy = JESD204BPhyTX( - cpll, PhyPads(jesd_pads.txp[i], jesd_pads.txn[i]), - jesd_crg.fabric_freq, transceiver="gth") - platform.add_period_constraint(phy.transmitter.cd_tx.clk, - 40*1e9/jesd_crg.linerate) - platform.add_false_path_constraints( - sys_crg.cd_sys.clk, - jesd_crg.cd_jesd.clk, - phy.transmitter.cd_tx.clk) + pll, jesd_crg.refclk, PhyPads(jesd_pads.txp[i], jesd_pads.txn[i]), + jesd_crg.fabric_freq, transceiver="gth", tx_half=tx_half) phys.append(phy) + if tx_half: + platform.add_period_constraint(phy.transmitter.cd_tx_half.clk, + 80*1e9/jesd_crg.linerate) + platform.add_false_path_constraints( + sys_crg.cd_sys.clk, + jesd_crg.cd_jesd.clk, + phy.transmitter.cd_tx_half.clk) + else: + platform.add_period_constraint(phy.transmitter.cd_tx.clk, + 40*1e9/jesd_crg.linerate) + platform.add_false_path_constraints( + sys_crg.cd_sys.clk, + jesd_crg.cd_jesd.clk, + phy.transmitter.cd_tx.clk) + # CHANNEL & init interconnects + for i, (pll, phy) in enumerate(zip(plls, phys)): + # CPLLs: 1 init per channel + if pll_type == "cpll": + phy_channel_cfg = {} + # Connect reset/lock to init + pll_reset = pll.reset + pll_lock = pll.lock + self.submodules += JESD204BGTHTransmitterInterconnect( + pll_reset, pll_lock, phy.transmitter, phy.transmitter.init) + # QPLL: 4 inits and 4 channels per quad + elif pll_type == "qpll": + # Connect clk/refclk to CHANNEL + phy_cfg = gthe3_common_cfgs[int(i//4)] + phy_channel_cfg = { + "qpll_clk": phy_cfg["clk"], + "qpll_refclk": phy_cfg["refclk"] + } + # Connect reset/lock to init + pll_reset = phy_cfg["reset"] + pll_lock = phy_cfg["lock"] + if i % 4 == 0: + self.submodules += JESD204BGTHTransmitterInterconnect( + pll_reset, pll_lock, phy.transmitter, + [phys[j].transmitter.init for j in range(i, min(len(phys), i+4))]) + # GTHE3_CHANNEL + self.specials += JESD204BGTHTransmitter.get_gthe3_channel( + pll, phy.transmitter, **phy_channel_cfg) self.submodules.core = JESD204BCoreTX( - phys, settings, converter_data_width=128) + phys, settings, converter_data_width=128, tx_half=tx_half) self.submodules.control = JESD204BCoreTXControl(self.core) self.core.register_jsync(platform.request("dac_sync", dac)) @@ -111,7 +185,7 @@ class DDMTD(Module, AutoCSR): i_RST=self.reset.storage, o_LOCKED=helper_locked, - # VCO at 1200MHz with 150MHz RTIO frequency + # VCO at 1000MHz/1200MHz with 125MHz/150MHz RTIO frequency p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 841e28b89..868c4f1f4 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -190,8 +190,10 @@ class SatelliteBase(MiniSoC): # JESD204 DAC Channel Group class JDCGSAWG(Module, AutoCSR): def __init__(self, platform, sys_crg, jesd_crg, dac): + # Kintex Ultrascale GTH, speed grade -1C: + # QPLL0 linerate (D=1): 9.8 - 12.5 Gb/s self.submodules.jesd = jesd204_tools.UltrascaleTX( - platform, sys_crg, jesd_crg, dac) + platform, sys_crg, jesd_crg, dac, pll_type="qpll", tx_half=True) self.submodules.sawgs = [sawg.Channel(width=16, parallelism=8) for i in range(4)] @@ -203,7 +205,7 @@ class JDCGSAWG(Module, AutoCSR): class JDCGPattern(Module, AutoCSR): def __init__(self, platform, sys_crg, jesd_crg, dac): self.submodules.jesd = jesd204_tools.UltrascaleTX( - platform, sys_crg, jesd_crg, dac) + platform, sys_crg, jesd_crg, dac, pll_type="qpll", tx_half=True) self.sawgs = [] @@ -243,7 +245,7 @@ class JDCGPattern(Module, AutoCSR): class JDCGSyncDDS(Module, AutoCSR): def __init__(self, platform, sys_crg, jesd_crg, dac): self.submodules.jesd = jesd204_tools.UltrascaleTX( - platform, sys_crg, jesd_crg, dac) + platform, sys_crg, jesd_crg, dac, pll_type="qpll", tx_half=True) self.coarse_ts = Signal(32) self.sawgs = []