mirror of
https://github.com/litex-hub/litex-boards.git
synced 2025-01-03 03:43:36 -05:00
Add initial Blackmagic Decklink Mini 4K support (with UART, DDR3, PCIe, Video Out).
Mini Monitor 4K and Mini Recorder 4K are almost the same hardware with just changes on the Video In/Out. For now tests have been done on the Mini Monitor 4K, but the aim is support both boards in the same platform/target in the future, thus the mini_4k naming. These boards could be used as affordable Artix7 dev boards for LiteX, to run Linux with LiteX (512MB of RAM + a Video Framebuffer) or to create custom systems like a fast software defined signal generator/recorder directly from a PC over PCIe, custom HDMI/SDI video cards, etc... lots of possibilities :)
This commit is contained in:
parent
026c623e17
commit
3bb84b0071
3 changed files with 288 additions and 0 deletions
|
@ -9,6 +9,7 @@ vendors = [
|
|||
"1bitsquared",
|
||||
"antmicro",
|
||||
"colorlight",
|
||||
"decklink",
|
||||
"digilent",
|
||||
"enclustra",
|
||||
"gsd",
|
||||
|
|
149
litex_boards/platforms/decklink_mini_4k.py
Normal file
149
litex_boards/platforms/decklink_mini_4k.py
Normal file
|
@ -0,0 +1,149 @@
|
|||
#
|
||||
# This file is part of LiteX-Boards.
|
||||
#
|
||||
# Copyright (c) 2021 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
from litex.build.generic_platform import *
|
||||
from litex.build.xilinx import XilinxPlatform
|
||||
from litex.build.openocd import OpenOCD
|
||||
|
||||
# IOs ----------------------------------------------------------------------------------------------
|
||||
|
||||
_io = [
|
||||
# Clk / Rst.
|
||||
("clk100", 0, Pins("P16"), IOStandard("LVCMOS25")),
|
||||
("clk24", 0, Pins("M21"), IOStandard("LVCMOS25")),
|
||||
|
||||
# Debug
|
||||
("debug", 0, Pins("R7"), IOStandard("LVCMOS25")),
|
||||
("debug", 1, Pins("R6"), IOStandard("LVCMOS25")),
|
||||
("debug", 2, Pins("T7"), IOStandard("LVCMOS25")),
|
||||
("debug", 3, Pins("T8"), IOStandard("LVCMOS25")),
|
||||
|
||||
# Fan
|
||||
("fan", 0, Pins("R18"), IOStandard("LVCMOS25")),
|
||||
|
||||
# Flash
|
||||
("flash_cs_n", 0, Pins("P18"), IOStandard("LVCMOS25")),
|
||||
("flash", 0,
|
||||
Subsignal("mosi", Pins("R14")),
|
||||
Subsignal("miso", Pins("R15")),
|
||||
Subsignal("vpp", Pins("P14")),
|
||||
Subsignal("hold", Pins("N14")),
|
||||
IOStandard("LVCMOS25")
|
||||
),
|
||||
|
||||
# Serial
|
||||
("serial", 0,
|
||||
Subsignal("tx", Pins("R7")), # debug0
|
||||
Subsignal("rx", Pins("R6")), # debug1
|
||||
IOStandard("LVCMOS25")
|
||||
),
|
||||
|
||||
# PCIe
|
||||
("pcie_x4", 0,
|
||||
Subsignal("rst_n", Pins("M19"), IOStandard("LVCMOS25"), Misc("PULLUP=TRUE")),
|
||||
Subsignal("clk_p", Pins("F11")),
|
||||
Subsignal("clk_n", Pins("E11")),
|
||||
Subsignal("rx_p", Pins("B11 D14 B13 D12")),
|
||||
Subsignal("rx_n", Pins("A11 C14 A13 C12")),
|
||||
Subsignal("tx_p", Pins("B7 D8 B9 D10")),
|
||||
Subsignal("tx_n", Pins("A7 C8 A9 C10"))
|
||||
),
|
||||
|
||||
# DDR3 SDRAM
|
||||
("ddram", 0,
|
||||
Subsignal("a", Pins(
|
||||
"K2 M5 M2 K1 N6 J1 P1 H2",
|
||||
"R1 M1 M6 N3 M7 H1"),
|
||||
IOStandard("SSTL15")),
|
||||
Subsignal("ba", Pins("K3 N2 L3"), IOStandard("SSTL15")),
|
||||
Subsignal("ras_n", Pins("L7"), IOStandard("SSTL15")),
|
||||
Subsignal("cas_n", Pins("L5"), IOStandard("SSTL15")),
|
||||
Subsignal("we_n", Pins("L2"), IOStandard("SSTL15")),
|
||||
Subsignal("cs_n", Pins("K5"), IOStandard("SSTL15")),
|
||||
Subsignal("dm", Pins("G8 J6 D5 A3"), IOStandard("SSTL15")),
|
||||
Subsignal("dq", Pins(
|
||||
"G6 H8 F7 F8 D6 H9 E6 H6",
|
||||
"J5 G4 L8 F4 K6 G5 K7 K8",
|
||||
"A4 D4 B4 E5 C4 F3 C3 D3",
|
||||
"G1 D1 G2 A2 E1 E2 F2 C2"),
|
||||
IOStandard("SSTL15"),
|
||||
Misc("IN_TERM=UNTUNED_SPLIT_40")),
|
||||
Subsignal("dqs_p", Pins("H7 J4 B5 C1"),
|
||||
IOStandard("DIFF_SSTL15"),
|
||||
Misc("IN_TERM=UNTUNED_SPLIT_40")),
|
||||
Subsignal("dqs_n", Pins("G7 H4 A5 B1"),
|
||||
IOStandard("DIFF_SSTL15"),
|
||||
Misc("IN_TERM=UNTUNED_SPLIT_40")),
|
||||
Subsignal("clk_p", Pins("P4"), IOStandard("DIFF_SSTL15")),
|
||||
Subsignal("clk_n", Pins("N4"), IOStandard("DIFF_SSTL15")),
|
||||
Subsignal("cke", Pins("N7"), IOStandard("SSTL15")),
|
||||
Subsignal("odt", Pins("J3"), IOStandard("SSTL15")),
|
||||
Subsignal("reset_n", Pins("N1"), IOStandard("SSTL15")),
|
||||
Misc("SLEW=FAST"),
|
||||
),
|
||||
|
||||
# SDI
|
||||
("sdi_refclk_sel", 0, Pins("AB26"), IOStandard("LVCMOS25")),
|
||||
("sdi_refclk", 0,
|
||||
Subsignal("p", Pins("AA13")),
|
||||
Subsignal("n", Pins("AB13")),
|
||||
),
|
||||
("sdi_refclk", 1,
|
||||
Subsignal("p", Pins("AA11")),
|
||||
Subsignal("n", Pins("AB11")),
|
||||
),
|
||||
("sdi_data", 0,
|
||||
Subsignal("txp", Pins("AC10")),
|
||||
Subsignal("txn", Pins("AD10")),
|
||||
Subsignal("rxp", Pins("AC12")),
|
||||
Subsignal("rxn", Pins("AD12")),
|
||||
),
|
||||
|
||||
# HDMI (through 75DP159)
|
||||
("hdmi_out", 0,
|
||||
Subsignal("clk_p", Pins("U14"), IOStandard("LVDS_25")),
|
||||
Subsignal("clk_n", Pins("V14"), IOStandard("LVDS_25")),
|
||||
Subsignal("data0_p", Pins("AE7")),
|
||||
Subsignal("data0_n", Pins("AF7")),
|
||||
Subsignal("data1_p", Pins("AC8")),
|
||||
Subsignal("data1_n", Pins("AD8")),
|
||||
Subsignal("data2_p", Pins("AE9")),
|
||||
Subsignal("data2_n", Pins("AD10")),
|
||||
# FIXME: Find a way to avoid RX pads.
|
||||
Subsignal("rx0_p", Pins("AE11")),
|
||||
Subsignal("rx0_n", Pins("AF11")),
|
||||
Subsignal("rx1_p", Pins("AC14")),
|
||||
Subsignal("rx1_n", Pins("AD14")),
|
||||
Subsignal("rx2_p", Pins("AE13")),
|
||||
Subsignal("rx2_n", Pins("AF13")),
|
||||
|
||||
),
|
||||
]
|
||||
|
||||
# Platform -----------------------------------------------------------------------------------------
|
||||
|
||||
class Platform(XilinxPlatform):
|
||||
default_clk_name = "clk100"
|
||||
default_clk_period = 1e9/100e6
|
||||
|
||||
def __init__(self):
|
||||
XilinxPlatform.__init__(self, "xc7a100t-fgg676-3", _io, toolchain="vivado")
|
||||
self.toolchain.bitstream_commands = \
|
||||
["set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]"]
|
||||
self.toolchain.additional_commands = \
|
||||
["write_cfgmem -force -format bin -interface spix4 -size 16 "
|
||||
"-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"]
|
||||
self.add_platform_command("set_property INTERNAL_VREF 0.750 [get_iobanks 34]")
|
||||
self.add_platform_command("set_property INTERNAL_VREF 0.750 [get_iobanks 35]")
|
||||
|
||||
def create_programmer(self):
|
||||
return OpenOCD("openocd_xc7_ft232.cfg", "bscan_spi_xc7a100t.bit")
|
||||
|
||||
def do_finalize(self, fragment):
|
||||
XilinxPlatform.do_finalize(self, fragment)
|
||||
from litex.build.xilinx import symbiflow
|
||||
self.add_period_constraint(self.lookup_request("clk100", loose=True), 1e9/100e6)
|
||||
self.add_period_constraint(self.lookup_request("clk24", loose=True), 1e9/24e6)
|
138
litex_boards/targets/decklink_mini_4k.py
Executable file
138
litex_boards/targets/decklink_mini_4k.py
Executable file
|
@ -0,0 +1,138 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# This file is Copyright (c) 2021 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
# License: BSD
|
||||
|
||||
import os
|
||||
import argparse
|
||||
|
||||
from migen import *
|
||||
|
||||
from litex_boards.platforms import mini_4k
|
||||
from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict
|
||||
|
||||
from litex.soc.cores.clock import *
|
||||
from litex.soc.integration.soc import SoCRegion
|
||||
from litex.soc.integration.soc_core import *
|
||||
from litex.soc.integration.builder import *
|
||||
from litex.soc.cores.video import VideoS7GTPHDMIPHY
|
||||
|
||||
from litedram.modules import MT41K128M16
|
||||
from litedram.phy import s7ddrphy
|
||||
|
||||
from litepcie.phy.s7pciephy import S7PCIEPHY
|
||||
from litepcie.software import generate_litepcie_software
|
||||
|
||||
# CRG ----------------------------------------------------------------------------------------------
|
||||
|
||||
class _CRG(Module):
|
||||
def __init__(self, platform, sys_clk_freq):
|
||||
self.rst = Signal()
|
||||
self.clock_domains.cd_sys = ClockDomain()
|
||||
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True)
|
||||
self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True)
|
||||
self.clock_domains.cd_idelay = ClockDomain()
|
||||
self.clock_domains.cd_hdmi = ClockDomain()
|
||||
|
||||
# # #
|
||||
|
||||
self.submodules.pll = pll = S7PLL(speedgrade=-1)
|
||||
self.comb += pll.reset.eq(self.rst)
|
||||
pll.register_clkin(platform.request("clk100"), 100e6)
|
||||
pll.create_clkout(self.cd_sys, sys_clk_freq)
|
||||
pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq)
|
||||
pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90)
|
||||
pll.create_clkout(self.cd_idelay, 200e6, margin=1e-1) # FIXME: Re-arrange clocking.
|
||||
pll.create_clkout(self.cd_hdmi, 148.5e6, margin=2e-2) # FIXME: Use a second PLL or move to clkout0 that has fractional support.
|
||||
platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst.
|
||||
|
||||
self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay)
|
||||
|
||||
platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk100_IBUF]")
|
||||
|
||||
# BaseSoC ------------------------------------------------------------------------------------------
|
||||
|
||||
class BaseSoC(SoCMini):
|
||||
def __init__(self, sys_clk_freq=int(100e6), with_pcie=False, with_video_terminal=False, with_video_framebuffer=False, **kwargs):
|
||||
if with_video_terminal or with_video_framebuffer:
|
||||
sys_clk_freq = int(148.5e6) # FIXME: For now requires sys_clk >= video_clk.
|
||||
platform = mini_4k.Platform()
|
||||
|
||||
# SoCCore ----------------------------------------------------------------------------------
|
||||
kwargs["uart_name"] = "jtag_uart"
|
||||
SoCCore.__init__(self, platform, sys_clk_freq,
|
||||
ident = "LiteX SoC on Blackmagic Declkink Mini 4K",
|
||||
ident_version = True,
|
||||
**kwargs)
|
||||
|
||||
# CRG --------------------------------------------------------------------------------------
|
||||
self.submodules.crg = _CRG(platform, sys_clk_freq)
|
||||
|
||||
# DDR3 SDRAM -------------------------------------------------------------------------------
|
||||
if not self.integrated_main_ram_size:
|
||||
self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"),
|
||||
memtype = "DDR3",
|
||||
nphases = 4,
|
||||
sys_clk_freq = sys_clk_freq)
|
||||
self.add_sdram("sdram",
|
||||
phy = self.ddrphy,
|
||||
module = MT41K128M16(sys_clk_freq, "1:4"),
|
||||
l2_cache_size = kwargs.get("l2_size", 8192)
|
||||
)
|
||||
|
||||
# PCIe -------------------------------------------------------------------------------------
|
||||
if with_pcie:
|
||||
self.submodules.pcie_phy = S7PCIEPHY(platform, platform.request("pcie_x4"),
|
||||
data_width = 128,
|
||||
bar0_size = 0x20000)
|
||||
self.add_pcie(phy=self.pcie_phy, ndmas=1)
|
||||
|
||||
# Video ------------------------------------------------------------------------------------
|
||||
if with_video_terminal or with_video_framebuffer:
|
||||
self.submodules.videophy = VideoS7GTPHDMIPHY(platform.request("hdmi_out"),
|
||||
sys_clk_freq = sys_clk_freq,
|
||||
clock_domain = "hdmi"
|
||||
)
|
||||
if with_video_terminal:
|
||||
self.add_video_terminal(phy=self.videophy, timings="1920x1080@60Hz", clock_domain="hdmi")
|
||||
if with_video_framebuffer:
|
||||
self.add_video_framebuffer(phy=self.videophy, timings="1920x1080@60Hz", clock_domain="hdmi")
|
||||
platform.add_platform_command("set_property SEVERITY {{Warning}} [get_drc_checks REQP-49]") # FIXME: Use GTP refclk.
|
||||
|
||||
# Build --------------------------------------------------------------------------------------------
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="LiteX SoC Blackmagic Decklink Mini 4K.")
|
||||
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=148.5e6, help="System clock frequency (default: 100MHz)")
|
||||
parser.add_argument("--with-pcie", action="store_true", help="Enable PCIe support")
|
||||
parser.add_argument("--driver", action="store_true", help="Generate PCIe driver")
|
||||
viopts = parser.add_mutually_exclusive_group()
|
||||
viopts.add_argument("--with-video-terminal", action="store_true", help="Enable Video Terminal (HDMI)")
|
||||
viopts.add_argument("--with-video-framebuffer", action="store_true", help="Enable Video Framebuffer (HDMI)")
|
||||
builder_args(parser)
|
||||
soc_core_args(parser)
|
||||
vivado_build_args(parser)
|
||||
args = parser.parse_args()
|
||||
|
||||
soc = BaseSoC(
|
||||
sys_clk_freq = int(float(args.sys_clk_freq)),
|
||||
with_pcie = args.with_pcie,
|
||||
with_video_terminal = args.with_video_terminal,
|
||||
with_video_framebuffer = args.with_video_framebuffer,
|
||||
**soc_core_argdict(args)
|
||||
)
|
||||
builder = Builder(soc, **builder_argdict(args))
|
||||
builder_kwargs = vivado_build_argdict(args)
|
||||
builder.build(**builder_kwargs, 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()
|
Loading…
Reference in a new issue