diff --git a/litex_boards/platforms/rcs_arctic_tern_bmc_card.py b/litex_boards/platforms/rcs_arctic_tern_bmc_card.py new file mode 100644 index 0000000..8272e72 --- /dev/null +++ b/litex_boards/platforms/rcs_arctic_tern_bmc_card.py @@ -0,0 +1,249 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2022 Raptor Engineering, LLC +# SPDX-License-Identifier: BSD-2-Clause + +from litex.build.generic_platform import * +from litex.build.lattice import LatticePlatform +from litex.build.lattice.programmer import OpenOCDJTAGProgrammer + +import os + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + # Clk / Rst (module) + ("clk125", 0, Pins("B6"), IOStandard("LVCMOS33")), + ("rst_n", 0, Pins("T3"), IOStandard("LVCMOS33")), + + # BMC serial (module) + ("serial", 0, + Subsignal("rx", Pins("A7"), IOStandard("LVCMOS33")), + Subsignal("tx", Pins("B8"), IOStandard("LVCMOS33")), + ), + + # Host serial (module) + ("serial", 1, + Subsignal("rx", Pins("C1"), IOStandard("LVCMOS33")), + Subsignal("tx", Pins("C2"), IOStandard("LVCMOS33")), + Subsignal("rts", Pins("C8"), IOStandard("LVCMOS33")), + Subsignal("cts", Pins("D8"), IOStandard("LVCMOS33")), + ), + + # DDR3 SDRAM (module) + ("ddram", 0, + Subsignal("a", Pins( + "J1 K1 G2 H2 F1 G1 J4 J3 J5 K3 K2 H1 M5 K4 L4"), + IOStandard("SSTL135_I")), + Subsignal("ba", Pins("K5 L5 M1"), IOStandard("SSTL135_I")), + Subsignal("ras_n", Pins("L2"), IOStandard("SSTL135_I")), + Subsignal("cas_n", Pins("N2"), IOStandard("SSTL135_I")), + Subsignal("we_n", Pins("N1"), IOStandard("SSTL135_I")), + Subsignal("cs_n", Pins("P5"), IOStandard("SSTL135_I")), + Subsignal("dm", Pins("R20 N18 F20 E18"), IOStandard("SSTL135_I")), + Subsignal("dq", Pins( + "T20 U17 T18 U16 U19 T17 U20 U18", + "L19 M18 L17 L16 L20 M19 L18 M20", + "J20 K18 F19 K19 J19 J18 G20 K20", + "G16 H18 H16 F18 J16 E17 J17 H17"), + IOStandard("SSTL135_I"), + Misc("TERMINATION=75")), + Subsignal("dqs_p", Pins("T19 N16 G19 F17"), IOStandard("SSTL135D_I"), + Misc("TERMINATION=OFF"), + Misc("DIFFRESISTOR=100")), + Subsignal("clk_p", Pins("P19 E16"), IOStandard("SSTL135D_I")), + Subsignal("cke", Pins("N5"), IOStandard("SSTL135_I")), + Subsignal("odt", Pins("M3"), IOStandard("SSTL135_I")), + Subsignal("reset_n", Pins("L1"), IOStandard("SSTL135_I")), + Misc("SLEWRATE=FAST"), + ), + + # PCIe (module) + ("pcie_x1", 0, + Subsignal("clk_p", Pins("Y11")), + Subsignal("clk_n", Pins("Y12")), + Subsignal("rx_p", Pins("Y5")), + Subsignal("rx_n", Pins("Y6")), + Subsignal("tx_p", Pins("W4")), + Subsignal("tx_n", Pins("W5")), + Subsignal("perst", Pins("A6"), IOStandard("LVCMOS33")), + ), + + # Inter-module SERDES (module) + ("serdes_x2", 0, + Subsignal("clk_p", Pins("Y19")), + Subsignal("clk_n", Pins("W20")), + Subsignal("rx_p", Pins("Y14 Y16")), + Subsignal("rx_n", Pins("Y15 Y17")), + Subsignal("tx_p", Pins("W13 W17")), + Subsignal("tx_n", Pins("W14 W18")), + Subsignal("perst", Pins("A6"), IOStandard("LVCMOS33")), + ), + + # Bitstream Flash device (module) + # Contains FPGA bistream, USRMCLK block required for clock output + ("fpgaspiflash4x", 0, + Subsignal("cs_n", Pins("R2")), + Subsignal("dq", Pins("W2 V2 Y2 W1")), + IOStandard("LVCMOS33"), + Misc("SLEWRATE=SLOW"), + Misc("DRIVE=16"), + ), + + # BMC firmware Flash device (carrier card) + ("bmcspiflash4x", 0, + Subsignal("cs_n", Pins("G5")), + Subsignal("clk", Pins("E5")), + Subsignal("dq", Pins("E3 F5 D2 H4")), + IOStandard("LVCMOS33"), + Misc("SLEWRATE=SLOW"), + Misc("DRIVE=16"), + ), + + # Host Flash device (carrier card) + ("hostspiflash4x", 0, + Subsignal("cs_n", Pins("E2")), + Subsignal("clk", Pins("G3")), + Subsignal("dq", Pins("F2 F3 D1 A2")), + IOStandard("LVCMOS33"), + Misc("SLEWRATE=SLOW"), + Misc("DRIVE=16"), + ), + + # I2C bus 1 + # 3-pin header (carrier card) + ("i2c_master", 0, + Subsignal("sda", Pins("E4"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + Subsignal("scl", Pins("D5"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + ), + + # I2C bus 2 + # 3-pin header (carrier card) + ("i2c_master", 1, + Subsignal("sda", Pins("B1"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + Subsignal("scl", Pins("B2"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + ), + + # I2C bus 3 + # 3-pin header (carrier card) + ("i2c_master", 2, + Subsignal("sda", Pins("C7"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + Subsignal("scl", Pins("E8"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + ), + + # I2C bus 4 + # GPIO expander 1 (module) + ("i2c_master", 3, + Subsignal("sda", Pins("U1"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + Subsignal("scl", Pins("R1"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + ), + + # I2C bus 5 + # GPIO expander 2 (module) + ("i2c_master", 4, + Subsignal("sda", Pins("A12"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + Subsignal("scl", Pins("E12"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + ), + + # I2C bus 9 + ("i2c_master", 5, + Subsignal("sda", Pins("R3"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + Subsignal("scl", Pins("U2"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + ), + + # I2C bus 12 + # RTC + digital video + temperature sensor (module) + # Clock generator + PMBus (carrier card) + ("i2c_master", 6, + Subsignal("sda", Pins("V1"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + Subsignal("scl", Pins("T1"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + ), + + # Host LPC interface (module) + ("hostlpcslave", 0, + Subsignal("frame_n", Pins("D3"), Misc("PULLMODE=UP")), + Subsignal("reset_n", Pins("C3"), Misc("PULLMODE=UP")), + Subsignal("addrdata", Pins("C4 A3 B4 B3"), Misc("PULLMODE=UP")), + Subsignal("serirq", Pins("F4"), Misc("PULLMODE=UP")), + Subsignal("clk", Pins("H5"), Misc("PULLMODE=NONE")), + IOStandard("LVCMOS33"), + Misc("SLEWRATE=SLOW"), + Misc("DRIVE=16"), + ), + + # FSI (carrier card) + ("openfsi_master", 0, + Subsignal("clock", Pins("A18"), IOStandard("LVCMOS33")), + Subsignal("data", Pins("B18"), IOStandard("LVCMOS33")), + Subsignal("data_direction", Pins("T2"), IOStandard("LVCMOS33")), + ), + + # RGMII Ethernet (module) + ("eth_clocks", 0, + Subsignal("tx", Pins("C11")), + Subsignal("rx", Pins("A9")), + IOStandard("LVCMOS33") + ), + ("eth", 0, + # Reset is available on GPIO expander 2 + Subsignal("mdio", Pins("D9")), + Subsignal("mdc", Pins("E6")), + Subsignal("rx_ctl", Pins("A8")), + Subsignal("rx_data", Pins("E9 C9 D10 E10")), + Subsignal("tx_ctl", Pins("C10")), + Subsignal("tx_data", Pins("B10 A10 B11 A11")), + IOStandard("LVCMOS33") + ), + + # Digital video (module) + ("dvo", 0, + Subsignal("r", Pins( + "C14 E14 D14 E13 D13 C13 E11 C12")), + Subsignal("g", Pins( + "B19 B20 C17 C16 C15 D16 D15 E15")), + Subsignal("b", Pins( + "A14 A15 B15 A16 B16 A17 A19 B17")), + Subsignal("de", Pins("A13")), + Subsignal("hsync_n", Pins("B13")), + Subsignal("vsync_n", Pins("B12")), + Subsignal("clk", Pins("D11")), + IOStandard("LVCMOS33") + ), + + # 4-pin fan headers (carrier card) + ("pwm_tach_pads", 0, + Subsignal("pwm1", Pins("C5"), IOStandard("LVCMOS33")), + Subsignal("pwm2", Pins("E1"), IOStandard("LVCMOS33")), + Subsignal("pwm3", Pins("H3"), IOStandard("LVCMOS33")), + Subsignal("pwm4", Pins("A5"), IOStandard("LVCMOS33")), + Subsignal("tach1", Pins("C6"), IOStandard("LVCMOS33")), + Subsignal("tach2", Pins("E7"), IOStandard("LVCMOS33")), + Subsignal("tach3", Pins("D6"), IOStandard("LVCMOS33")), + Subsignal("tach4", Pins("A4"), IOStandard("LVCMOS33")), + ), +] + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(LatticePlatform): + default_clk_name = "clk125" + default_clk_period = 1e9/125e6 + + def __init__(self, device="LFE5UM5G", speed_grade="6", toolchain="trellis", **kwargs): + assert device in ["LFE5UM5G", "LFE5UM"] + if device is "LFE5UM5G": + speed_grade = "8" + LatticePlatform.__init__(self, device + "-85F-" + speed_grade + "CABGA381", _io, toolchain=toolchain, **kwargs) + + def request(self, *args, **kwargs): + return LatticePlatform.request(self, *args, **kwargs) + + def create_programmer(self): + return OpenOCDJTAGProgrammer("openocd_evn_ecp5.cfg") + + def do_finalize(self, fragment): + LatticePlatform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request("clk125", loose=True), 1e9/125e6) + self.add_period_constraint(self.lookup_request("eth_clocks:rx", 0, loose=True), 1e9/125e6) + self.add_period_constraint(self.lookup_request("eth_clocks:rx", 1, loose=True), 1e9/125e6) diff --git a/litex_boards/targets/rcs_arctic_tern_bmc_card.py b/litex_boards/targets/rcs_arctic_tern_bmc_card.py new file mode 100755 index 0000000..693cdab --- /dev/null +++ b/litex_boards/targets/rcs_arctic_tern_bmc_card.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2019 Arnaud Durand +# Copyright (c) 2022 Martin Hubacek @hubmartin (Twitter) +# Copyright (c) 2022 Raptor Engineering, LLC +# SPDX-License-Identifier: BSD-2-Clause + +import os +import argparse + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex_boards.platforms import versa_ecp5 + +from litex.build.lattice.trellis import trellis_args, trellis_argdict + +from litex_boards.platforms import rcs_arctic_tern_bmc_card + +from litex.soc.cores.clock import * +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * +from litex.soc.integration.soc import SoCRegion + +from litedram.modules import MT41J256M16 +from litedram.phy import ECP5DDRPHY +from liteeth.phy.ecp5rgmii import LiteEthPHYRGMII +from litex.soc.cores.video import VideoGenericPHY + +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(Module): + def __init__(self, platform, sys_clk_freq): + self.rst = Signal() + 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.clock_domains.cd_sys2x_eb = ClockDomain(reset_less=True) + self.clock_domains.cd_dvo = ClockDomain(reset_less=True) + + # # # + self.stop = Signal() + self.reset = Signal() + + # Clk / Rst + clk125 = platform.request("clk125") + rst_n = platform.request("rst_n") + + self.clk_inv_alignwd = Signal() + self.sys_inv_clk_bridge = Signal() + self.sys_inv_clk_syncb = Signal() + + # Power on reset + por_count = Signal(16, reset=2**16-1) + por_done = Signal() + self.comb += por_done.eq(por_count == 0) + self.sync.por += If(~por_done, por_count.eq(por_count - 1)) + + # PLL + sys2x_clk_ecsout = Signal() + self.submodules.pll = pll = ECP5PLL() + self.comb += pll.reset.eq(~por_done | ~rst_n | self.rst) + pll.register_clkin(clk125, 125e6) + pll.create_clkout(self.cd_sys2x_i, 2*sys_clk_freq) + pll.create_clkout(self.cd_init, 24e6) + self.specials += [ + Instance("OSCG", + p_DIV = 128, # 2.4MHz + o_OSC = self.cd_por.clk), + Instance("ECLKBRIDGECS", + i_CLK0 = self.cd_sys2x_i.clk, + i_SEL = 0, + o_ECSOUT = sys2x_clk_ecsout), + Instance("ECLKSYNCB", + i_ECLKI = sys2x_clk_ecsout, + 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.reset, + o_CDIVX = self.cd_sys.clk), + AsyncResetSynchronizer(self.cd_sys, ~pll.locked | self.reset), + AsyncResetSynchronizer(self.cd_sys2x, ~pll.locked | self.reset), + ] + + # Generate DVO clock + pll.create_clkout(self.cd_dvo, 40e6) # 800x600@60 + #pll.create_clkout(self.cd_dvo, 148.35e6) # 1920x1080@60 + #pll.create_clkout(self.cd_dvo, 148.2e6) # 1920x1200@60 + + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCCore): + def __init__(self, sys_clk_freq=int(50e6), toolchain="trellis", + with_video_colorbars = False, + with_video_terminal = True, + with_video_framebuffer = False, + with_ethernet = False, + with_etherbone = False, + eth_ip = "192.168.1.50", + **kwargs): + platform = rcs_arctic_tern_bmc_card.Platform(toolchain=toolchain) + + #bios_flash_offset = 0x400000 + + # Set CPU variant / reset address + #kwargs["cpu_reset_address"] = self.mem_map["spiflash"] + bios_flash_offset + kwargs["integrated_rom_size"] = 0x10000 + + # SoCCore ---------------------------------------------------------------------------------- + SoCCore.__init__(self, platform, irq_n_irqs=16, clk_freq=sys_clk_freq, + ident = "LiteX SoC on Arctic Tern (BMC card carrier)", + #integrated_main_ram_size = 0x40000, + #integrated_main_ram_size = 0, + **kwargs) + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = _CRG(platform, sys_clk_freq) + + # DDR3 SDRAM ------------------------------------------------------------------------------- + self.submodules.ddrphy = ECP5DDRPHY( + platform.request("ddram"), + sys_clk_freq=sys_clk_freq) + self.comb += self.crg.stop.eq(self.ddrphy.init.stop) + self.comb += self.crg.reset.eq(self.ddrphy.init.reset) + self.add_sdram("sdram", + phy = self.ddrphy, + module = MT41J256M16(sys_clk_freq, "1:2"), # Not MT41J256M16, but the AS4C256M16D3C in use has similar specifications + l2_cache_size = kwargs.get("l2_size", 8192), + ) + + # Ethernet / Etherbone --------------------------------------------------------------------- + if with_ethernet or with_etherbone: + self.submodules.ethphy = LiteEthPHYRGMII( + clock_pads = self.platform.request("eth_clocks", 0), + pads = self.platform.request("eth", 0), + tx_delay = 0e-9, + rx_delay = 0e-9) + if with_ethernet: + self.add_ethernet(phy=self.ethphy) + if with_etherbone: + self.add_etherbone(phy=self.ethphy, ip_address=eth_ip) + + # Video Output ----------------------------------------------------------------------------- + if with_video_colorbars or with_video_terminal or with_video_framebuffer: + dvo_pads = platform.request("dvo") + self.submodules.videophy = VideoGenericPHY(dvo_pads, clock_domain="dvo", with_clk_ddr_output=False) + if with_video_terminal: + #self.add_video_terminal(phy=self.videophy, timings="1920x1080@60Hz", clock_domain="dvo") + #self.add_video_terminal(phy=self.videophy, timings="1920x1200@60Hz", clock_domain="dvo") + self.add_video_terminal(phy=self.videophy, timings="800x600@60Hz", clock_domain="dvo") + elif with_video_framebuffer: + #self.add_video_framebuffer(phy=self.videophy, timings="1920x1080@60Hz", clock_domain="dvo") + #self.add_video_framebuffer(phy=self.videophy, timings="1920x1200@60Hz", clock_domain="dvo") + self.add_video_framebuffer(phy=self.videophy, timings="800x600@60Hz", clock_domain="dvo") + else: + self.add_video_colorbars(phy=self.videophy, timings="800x600@60Hz", clock_domain="dvo") + +# Build -------------------------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC on Arctic Tern (BMC card carrier)") + parser.add_argument("--build", action="store_true", help="Build bitstream") + parser.add_argument("--load", action="store_true", help="Load bitstream") + parser.add_argument("--toolchain", default="trellis", help="FPGA toolchain: trellis (default) or diamond") + parser.add_argument("--sys-clk-freq", default=60e6, help="System clock frequency (default: 60MHz)") + ethopts = parser.add_mutually_exclusive_group() + ethopts.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support.") + ethopts.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support.") + parser.add_argument("--eth-ip", default="192.168.1.50", type=str, help="Ethernet/Etherbone IP address.") + builder_args(parser) + soc_core_args(parser) + trellis_args(parser) + args = parser.parse_args() + + soc = BaseSoC( + toolchain = args.toolchain, + sys_clk_freq = int(float(args.sys_clk_freq)), + with_ethernet = args.with_ethernet, + with_etherbone = args.with_etherbone, + eth_ip = args.eth_ip, + **soc_core_argdict(args)) + builder = Builder(soc, **builder_argdict(args)) + builder_kargs = trellis_argdict(args) if args.toolchain == "trellis" else {} + builder.build(run=args.build) + + if args.load: + prog = soc.platform.create_programmer() + prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".svf")) + +if __name__ == "__main__": + main()