diff --git a/litex_boards/partner/platforms/camlink_4k.py b/litex_boards/partner/platforms/camlink_4k.py new file mode 100644 index 0000000..126d3e1 --- /dev/null +++ b/litex_boards/partner/platforms/camlink_4k.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +# This file is Copyright (c) 2019 Florent Kermarrec +# License: BSD + +# The Cam Link 4K PCB and IOs have been documented by @GregDavill and @ApertusOSCinema: +# https://wiki.apertus.org/index.php/Elgato_CAM_LINK_4K + +# The FX3 exploration tool (and FPGA loader) has been developed by @ktemkin: +# https://github.com/ktemkin/camlink-re + +from litex.build.generic_platform import * +from litex.build.lattice import LatticePlatform + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + ("clk27", 0, Pins("B11"), IOStandard("LVCMOS25")), + + ("led", 0, Pins("A6"), IOStandard("LVCMOS25")), + ("led", 1, Pins("A9"), IOStandard("LVCMOS25")), + + ("serial", 0, + Subsignal("tx", Pins("A6")), # led0 + Subsignal("rx", Pins("A9")), # led1 + IOStandard("LVCMOS25") + ), + + ("ddram", 0, + Subsignal("a", Pins( + "P2 L2 N1 P1 N5 M1 M3 N4", + "L3 L1 P5 N2 N3"), + IOStandard("SSTL135_I")), + Subsignal("ba", Pins("C4 A3 B4"), IOStandard("SSTL135_I")), + Subsignal("ras_n", Pins("D3"), IOStandard("SSTL135_I")), + Subsignal("cas_n", Pins("C3"), IOStandard("SSTL135_I")), + Subsignal("we_n", Pins("D5"), IOStandard("SSTL135_I")), + Subsignal("cs_n", Pins("B5"), IOStandard("SSTL135_I")), + Subsignal("dm", Pins("J4 H5"), IOStandard("SSTL135_I")), + Subsignal("dq", Pins( + "L5 F1 K4 G1 L4 H1 G2 J3", + "D1 C1 E2 C2 F3 A2 E1 B1"), + IOStandard("SSTL135_I"), + Misc("TERMINATION=75")), + Subsignal("dqs_p", Pins("K2 H4"), IOStandard("SSTL135D_I"), + Misc("TERMINATION=OFF"), Misc("DIFFRESISTOR=100")), + Subsignal("clk_p", Pins("A4"), IOStandard("SSTL135D_I")), + Subsignal("cke", Pins("E4"), IOStandard("SSTL135_I")), + Subsignal("odt", Pins("B3"), IOStandard("SSTL135_I")), + Subsignal("reset_n", Pins("C5"), IOStandard("SSTL135_I")), + Misc("SLEWRATE=FAST"), + ), +] + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(LatticePlatform): + default_clk_name = "clk27" + default_clk_period = 1e9/27e6 + + def __init__(self, **kwargs): + LatticePlatform.__init__(self, "LFE5U-25F-8BG381C", _io, **kwargs) diff --git a/litex_boards/partner/targets/camlink_4k.py b/litex_boards/partner/targets/camlink_4k.py new file mode 100755 index 0000000..5ef93ca --- /dev/null +++ b/litex_boards/partner/targets/camlink_4k.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 + +# This file is Copyright (c) 2019 Florent Kermarrec +# License: BSD + +import argparse +import sys + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex_boards.platforms import camlink_4k + +from litex.soc.cores.clock import * +from litex.soc.integration.soc_sdram import * +from litex.soc.integration.builder import * + +from litedram.modules import MT41K64M16 +from litedram.phy import ECP5DDRPHY + +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(Module): + def __init__(self, platform, sys_clk_freq): + self.clock_domains.cd_init = ClockDomain() + self.clock_domains.cd_por = ClockDomain(reset_less=True) + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys2x = ClockDomain() + self.clock_domains.cd_sys2x_i = ClockDomain(reset_less=True) + + # # # + + self.stop = Signal() + + # clk / rst + clk27 = platform.request("clk27") + platform.add_period_constraint(clk27, 1e9/27e6) + + # power on reset + por_count = Signal(16, reset=2**16-1) + por_done = Signal() + self.comb += self.cd_por.clk.eq(ClockSignal()) + self.comb += por_done.eq(por_count == 0) + self.sync.por += If(~por_done, por_count.eq(por_count - 1)) + + # pll + self.submodules.pll = pll = ECP5PLL() + pll.register_clkin(clk27, 27e6) + pll.create_clkout(self.cd_sys2x_i, 2*sys_clk_freq) + pll.create_clkout(self.cd_init, 27e6) + self.specials += [ + Instance("ECLKSYNCB", + i_ECLKI = self.cd_sys2x_i.clk, + i_STOP = self.stop, + o_ECLKO = self.cd_sys2x.clk), + Instance("CLKDIVF", + p_DIV = "2.0", + i_ALIGNWD = 0, + i_CLKI = self.cd_sys2x.clk, + i_RST = self.cd_sys2x.rst, + o_CDIVX = self.cd_sys.clk), + AsyncResetSynchronizer(self.cd_init, ~por_done | ~pll.locked), + AsyncResetSynchronizer(self.cd_sys, ~por_done | ~pll.locked) + ] + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCSDRAM): + def __init__(self, toolchain="diamond", **kwargs): + platform = camlink_4k.Platform(toolchain=toolchain) + sys_clk_freq = int(81e6) + + # SoCSDRAM --------------------------------------------------------------------------------- + SoCSDRAM.__init__(self, platform, clk_freq=sys_clk_freq, + integrated_rom_size=0x8000, + **kwargs) + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = _CRG(platform, sys_clk_freq) + + # DDR3 SDRAM ------------------------------------------------------------------------------- + if not self.integrated_main_ram_size: + self.submodules.ddrphy = ECP5DDRPHY( + platform.request("ddram"), + sys_clk_freq=sys_clk_freq) + self.add_csr("ddrphy") + self.add_constant("ECP5DDRPHY", None) + self.comb += self.crg.stop.eq(self.ddrphy.init.stop) + sdram_module = MT41K64M16(sys_clk_freq, "1:2") + self.register_sdram(self.ddrphy, + geom_settings = sdram_module.geom_settings, + timing_settings = sdram_module.timing_settings) + +# Build -------------------------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC on Cam Link 4K") + parser.add_argument("--gateware-toolchain", dest="toolchain", default="diamond", + help='gateware toolchain to use, diamond (default) or trellis') + builder_args(parser) + soc_sdram_args(parser) + args = parser.parse_args() + + soc = BaseSoC(toolchain=args.toolchain, **soc_sdram_argdict(args)) + builder = Builder(soc, **builder_argdict(args)) + builder.build(toolchain_path="/usr/local/diamond/3.10_x64/bin/lin64") + +if __name__ == "__main__": + main()