From 5f8560bf693bcb5ccdb641b5840886155fa86676 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 24 Jun 2021 19:47:58 +0200 Subject: [PATCH] Add initial Decklink Quad HDMI Recorder support (with documented PCIe/HDMI In). LitePCIe Gen3 X4 enumerating correctly. --- .../platforms/decklink_quad_hdmi_recorder.py | 112 ++++++++++++++++++ .../targets/decklink_quad_hdmi_recorder.py | 93 +++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 litex_boards/platforms/decklink_quad_hdmi_recorder.py create mode 100755 litex_boards/targets/decklink_quad_hdmi_recorder.py diff --git a/litex_boards/platforms/decklink_quad_hdmi_recorder.py b/litex_boards/platforms/decklink_quad_hdmi_recorder.py new file mode 100644 index 0000000..393d759 --- /dev/null +++ b/litex_boards/platforms/decklink_quad_hdmi_recorder.py @@ -0,0 +1,112 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2021 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +from litex.build.generic_platform import * +from litex.build.xilinx import XilinxPlatform, VivadoProgrammer + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + # Clk / Rst (SI5338A). + + # TODO (We'll use the 100MHz PCIe Clock for now). + + # SPIFlash (MX25L25645GSXDI). + + # TODO (Probably similar to KCU105). + + # PCIe + ("pcie_x1", 0, + #Subsignal("rst_n", Pins(""), IOStandard("")), + Subsignal("clk_p", Pins("AB6")), + Subsignal("clk_n", Pins("AB5")), + Subsignal("rx_p", Pins("AB2")), + Subsignal("rx_n", Pins("AB1")), + Subsignal("tx_p", Pins("AC4")), + Subsignal("tx_n", Pins("AC3")) + ), + ("pcie_x2", 0, + #Subsignal("rst_n", Pins(""), IOStandard("")), + Subsignal("clk_p", Pins("AB6")), + Subsignal("clk_n", Pins("AB5")), + Subsignal("rx_p", Pins("AB2 AD2")), + Subsignal("rx_n", Pins("AB1 AD1")), + Subsignal("tx_p", Pins("AC4 AE4")), + Subsignal("tx_n", Pins("AC3 AE3")) + ), + ("pcie_x4", 0, + #Subsignal("rst_n", Pins(""), IOStandard("")), + Subsignal("clk_p", Pins("AB6")), + Subsignal("clk_n", Pins("AB5")), + Subsignal("rx_p", Pins("AB2 AD2 AF2 AH2")), + Subsignal("rx_n", Pins("AB1 AD1 AF1 AH1")), + Subsignal("tx_p", Pins("AC4 AE4 AG4 AH6")), + Subsignal("tx_n", Pins("AC3 AE3 AG3 AH5")) + ), + ("pcie_x8", 0, + #Subsignal("rst_n", Pins(""), IOStandard("")), + Subsignal("clk_p", Pins("AB6")), + Subsignal("clk_n", Pins("AB5")), + Subsignal("rx_p", Pins("AB2 AD2 AF2 AH2 AJ4 AK2 AM2 AP2")), + Subsignal("rx_n", Pins("AB1 AD1 AF1 AH1 AJ3 AK1 AM1 AP1")), + Subsignal("tx_p", Pins("AC4 AE4 AG4 AH6 AK6 AL4 AM6 AN4")), + Subsignal("tx_n", Pins("AC3 AE3 AG3 AH5 AK5 AL3 AM5 AN3")) + ), + + # HDMI (through PI3HDX1204) + ("hdmi_in", 0, # PCIe Edge Side. + #Subsignal("clk_p", Pins(""), IOStandard("")), + #Subsignal("clk_n", Pins(""), IOStandard("")), + Subsignal("data0_p", Pins("Y2")), + Subsignal("data0_n", Pins("Y1")), + Subsignal("data1_p", Pins("V2")), + Subsignal("data1_n", Pins("V1")), + Subsignal("data2_p", Pins("T2")), + Subsignal("data2_n", Pins("T1")), + ), + ("hdmi_in", 1, + #Subsignal("clk_p", Pins(""), IOStandard("")), + #Subsignal("clk_n", Pins(""), IOStandard("")), + Subsignal("data0_p", Pins("P2")), + Subsignal("data0_n", Pins("P1")), + Subsignal("data1_p", Pins("M2")), + Subsignal("data1_n", Pins("M1")), + Subsignal("data2_p", Pins("K2")), + Subsignal("data2_n", Pins("K1")), + ), + ("hdmi_in", 2, + #Subsignal("clk_p", Pins(""), IOStandard("")), + #Subsignal("clk_n", Pins(""), IOStandard("")), + Subsignal("data0_p", Pins("H2")), + Subsignal("data0_n", Pins("H1")), + Subsignal("data1_p", Pins("F2")), + Subsignal("data1_n", Pins("F1")), + Subsignal("data2_p", Pins("E4")), + Subsignal("data2_n", Pins("E3")), + ), + ("hdmi_in", 3, + #Subsignal("clk_p", Pins(""), IOStandard("")), + #Subsignal("clk_n", Pins(""), IOStandard("")), + Subsignal("data0_p", Pins("D2")), + Subsignal("data0_n", Pins("D1")), + Subsignal("data1_p", Pins("B2")), + Subsignal("data1_n", Pins("B1")), + Subsignal("data2_p", Pins("B4")), + Subsignal("data2_n", Pins("B3")), + ), +] + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(XilinxPlatform): + def __init__(self): + XilinxPlatform.__init__(self, "xcku040-ffva1156-2-e", _io, toolchain="vivado") + + def create_programmer(self): + return VivadoProgrammer() + + def do_finalize(self, fragment): + XilinxPlatform.do_finalize(self, fragment) diff --git a/litex_boards/targets/decklink_quad_hdmi_recorder.py b/litex_boards/targets/decklink_quad_hdmi_recorder.py new file mode 100755 index 0000000..d9f5b47 --- /dev/null +++ b/litex_boards/targets/decklink_quad_hdmi_recorder.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2021 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os +import argparse + +from migen import * + +from litex_boards.platforms import quad_hdmi_recorder + +from litex.soc.cores.clock import * +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * + +from litepcie.phy.uspciephy import USPCIEPHY +from litepcie.software import generate_litepcie_software + +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(Module): + def __init__(self, platform, sys_clk_freq): + self.clock_domains.cd_sys = ClockDomain() + + # # # + + self.submodules.pll = pll = USMMCM(speedgrade=-2) + self.comb += pll.reset.eq(ResetSignal("pcie")) + pll.register_clkin(ClockSignal("pcie"), 250e6) + pll.create_clkout(self.cd_sys, sys_clk_freq) + platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst. + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCCore): + def __init__(self, sys_clk_freq=int(200e6), with_pcie=False, **kwargs): + platform = quad_hdmi_recorder.Platform() + + # SoCCore ---------------------------------------------------------------------------------- + kwargs["uart_name"] = "crossover" + SoCCore.__init__(self, platform, sys_clk_freq, + ident = "LiteX SoC on Blackmagic Decklink Quad HDMI Recorder", + ident_version = True, + **kwargs) + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = _CRG(platform, sys_clk_freq) + + # PCIe ------------------------------------------------------------------------------------- + if with_pcie: + self.submodules.pcie_phy = USPCIEPHY(platform, platform.request("pcie_x4"), + speed = "gen3", + data_width = 128, + bar0_size = 0x20000) + self.add_pcie(phy=self.pcie_phy, ndmas=1) + # False Paths (FIXME: Improve integration). + platform.toolchain.pre_placement_commands.append("set_false_path -from [get_clocks main_clkout_1] -to [get_clocks pcie_clk_1]") + platform.toolchain.pre_placement_commands.append("set_false_path -from [get_clocks pcie_clk_1] -to [get_clocks main_clkout_1]") + +# Build -------------------------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC on Blackmagic Decklink Quad HDMI Recorder") + parser.add_argument("--build", action="store_true", help="Build bitstream") + parser.add_argument("--load", action="store_true", help="Load bitstream") + parser.add_argument("--sys-clk-freq", default=200e6, help="System clock frequency (default: 200MHz)") + parser.add_argument("--with-pcie", action="store_true", help="Enable PCIe support") + parser.add_argument("--driver", action="store_true", help="Generate PCIe driver") + builder_args(parser) + soc_core_args(parser) + args = parser.parse_args() + + soc = BaseSoC( + sys_clk_freq = int(float(args.sys_clk_freq)), + with_pcie = args.with_pcie, + **soc_core_argdict(args) + ) + builder = Builder(soc, **builder_argdict(args)) + builder.build(run=args.build) + + if args.driver: + generate_litepcie_software(soc, os.path.join(builder.output_dir, "driver")) + + if args.load: + prog = soc.platform.create_programmer() + prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".bit")) + +if __name__ == "__main__": + main()