From a834985e00514fd7a2f1975cfe3c24342a66e207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Tue, 30 Mar 2021 14:44:15 +0200 Subject: [PATCH] Add target for LPDDR4 Test Board --- litex_boards/platforms/lpddr4_test_board.py | 114 +++++++++++++ litex_boards/prog/openocd_xc7_ft4232.cfg | 14 ++ litex_boards/targets/lpddr4_test_board.py | 167 ++++++++++++++++++++ test/test_targets.py | 3 + 4 files changed, 298 insertions(+) create mode 100644 litex_boards/platforms/lpddr4_test_board.py create mode 100644 litex_boards/prog/openocd_xc7_ft4232.cfg create mode 100755 litex_boards/targets/lpddr4_test_board.py diff --git a/litex_boards/platforms/lpddr4_test_board.py b/litex_boards/platforms/lpddr4_test_board.py new file mode 100644 index 0000000..866ac30 --- /dev/null +++ b/litex_boards/platforms/lpddr4_test_board.py @@ -0,0 +1,114 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2021 Antmicro +# 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 = [ + ("clk100", 0, Pins("L19"), IOStandard("LVCMOS33")), + + ("user_led", 0, Pins("F8"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("C8"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("A8"), IOStandard("LVCMOS33")), + ("user_led", 3, Pins("D9"), IOStandard("LVCMOS33")), + ("user_led", 4, Pins("F9"), IOStandard("LVCMOS33")), + + ("user_btn", 0, Pins("E8"), IOStandard("LVCMOS33")), + ("user_btn", 1, Pins("B9"), IOStandard("LVCMOS33")), + ("user_btn", 2, Pins("C9"), IOStandard("LVCMOS33")), + ("user_btn", 3, Pins("E9"), IOStandard("LVCMOS33")), + + ("serial", 0, + Subsignal("tx", Pins("AB18")), + Subsignal("rx", Pins("AA18")), + IOStandard("LVCMOS33") + ), + ("serial", 1, + Subsignal("tx", Pins("AA20")), + Subsignal("rx", Pins("AB20")), + IOStandard("LVCMOS33") + ), + + # LPDDR4 (not 1.2V, uses 1.1V or 0.6V depending on J10 jumper) + ("lpddr4", 0, + Subsignal("clk_p", Pins("Y3"), IOStandard("DIFF_SSTL12")), + Subsignal("clk_n", Pins("Y2"), IOStandard("DIFF_SSTL12")), + Subsignal("cke", Pins("N4"), IOStandard("SSTL12")), + Subsignal("odt", Pins("N5"), IOStandard("SSTL12")), + Subsignal("reset_n", Pins("P4"), IOStandard("SSTL12")), + Subsignal("cs", Pins("N3"), IOStandard("SSTL12")), + Subsignal("ca", Pins("L3 L5 AA4 AA3 AB3 AB2"), IOStandard("SSTL12")), + Subsignal("dq", Pins( + "L1 K2 K1 K3 R1 P2 P1 N2", + "W2 Y1 AA1 AB1 R2 T1 T3 U1"), + IOStandard("SSTL12_T_DCI")), + Subsignal("dqs_p", Pins("M2 U2"), IOStandard("DIFF_SSTL12")), + Subsignal("dqs_n", Pins("M1 V2"), IOStandard("DIFF_SSTL12")), + Subsignal("dmi", Pins("M3 W1"), IOStandard("SSTL12_T_DCI")), + Misc("SLEW=FAST"), + ), + + # RGMII Ethernet + ("eth_ref_clk", 0, Pins("C12"), IOStandard("LVCMOS33")), + ("eth_clocks", 0, + Subsignal("tx", Pins("E17")), + Subsignal("rx", Pins("C17")), + IOStandard("LVCMOS33") + ), + ("eth", 0, + Subsignal("rst_n", Pins("E16"), IOStandard("LVCMOS33")), + Subsignal("mdio", Pins("C14"), IOStandard("LVCMOS33")), + Subsignal("mdc", Pins("B17"), IOStandard("LVCMOS33")), + Subsignal("rx_ctl", Pins("A16"), IOStandard("LVCMOS33")), + Subsignal("rx_data", Pins("B16 A15 B15 A14"), IOStandard("LVCMOS33")), + Subsignal("tx_ctl", Pins("A13"), IOStandard("LVCMOS33")), + Subsignal("tx_data", Pins("B21 B20 A19 A18"), IOStandard("LVCMOS33")), + ), + + # HyperRAM + ("hyperram", 0, + Subsignal("clk", Pins("AB15")), # clk_n AB16 + Subsignal("rst_n", Pins("V17")), + Subsignal("dq", Pins("W15 AA15 AA14 W14 Y14 V15 Y16 W17")), + Subsignal("cs_n", Pins("AA16")), + Subsignal("rwds", Pins("Y17")), + IOStandard("LVCMOS33") + ), + + # SD Card + ("sdcard", 0, + Subsignal("data", Pins("D20 D19 C22 D21"), Misc("PULLUP True")), + Subsignal("cmd", Pins("C20"), Misc("PULLUP True")), + Subsignal("clk", Pins("D22")), + Subsignal("cd", Pins("B22")), + Misc("SLEW=FAST"), + IOStandard("LVCMOS33"), + ), +] + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(XilinxPlatform): + default_clk_name = "clk100" + default_clk_period = 1e9/100e6 + + def __init__(self, device="xc7k70tfbg484-1"): + XilinxPlatform.__init__(self, device, _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"] + + def create_programmer(self): + return OpenOCD("openocd_xc7_ft4232.cfg", "bscan_spi_xc7k70t.bit") + + def do_finalize(self, fragment): + XilinxPlatform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request("clk100", loose=True), 1e9/100e6) diff --git a/litex_boards/prog/openocd_xc7_ft4232.cfg b/litex_boards/prog/openocd_xc7_ft4232.cfg new file mode 100644 index 0000000..b551495 --- /dev/null +++ b/litex_boards/prog/openocd_xc7_ft4232.cfg @@ -0,0 +1,14 @@ +interface ftdi +ftdi_vid_pid 0x0403 0x6011 +ftdi_channel 0 +ftdi_layout_init 0x00e8 0x60eb +reset_config none + +source [find cpld/xilinx-xc7.cfg] +source [find cpld/jtagspi.cfg] +adapter_khz 25000 + +proc fpga_program {} { + global _CHIPNAME + xc7_program $_CHIPNAME.tap +} diff --git a/litex_boards/targets/lpddr4_test_board.py b/litex_boards/targets/lpddr4_test_board.py new file mode 100755 index 0000000..cf63b97 --- /dev/null +++ b/litex_boards/targets/lpddr4_test_board.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2021 Antmicro +# SPDX-License-Identifier: BSD-2-Clause + +import os +import argparse + +from migen import * + +from litex_boards.platforms import lpddr4_test_board +from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict + +from litex.soc.cores.clock import * +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * +from litex.soc.cores.led import LedChaser + +from litedram.modules import MT53E256M16D1 +from litedram.phy import lpddr4 + +from liteeth.phy import LiteEthS7PHYRGMII +from litehyperbus.core.hyperbus import HyperRAM + +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(Module): + def __init__(self, platform, sys_clk_freq, iodelay_clk_freq): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys2x = ClockDomain(reset_less=True) + self.clock_domains.cd_sys8x = ClockDomain(reset_less=True) + self.clock_domains.cd_idelay = ClockDomain() + + # # # + + self.submodules.pll = pll = S7PLL(speedgrade=-1) + pll.register_clkin(platform.request("clk100"), 100e6) + pll.create_clkout(self.cd_sys, sys_clk_freq) + pll.create_clkout(self.cd_sys2x, 2 * sys_clk_freq) + pll.create_clkout(self.cd_sys8x, 8 * sys_clk_freq) + pll.create_clkout(self.cd_idelay, iodelay_clk_freq) + + self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay) + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCCore): + mem_map = { + "hyperram": 0x20000000, + } + mem_map.update(SoCCore.mem_map) + + def __init__(self, *, sys_clk_freq=int(50e6), iodelay_clk_freq=200e6, + with_ethernet=False, with_etherbone=False, eth_ip="192.168.1.50", eth_dynamic_ip=False, + with_hyperram=False, with_sdcard=False, with_jtagbone=True, with_uartbone=False, + ident_version=True, **kwargs): + platform = lpddr4_test_board.Platform() + + # SoCCore ---------------------------------------------------------------------------------- + SoCCore.__init__(self, platform, sys_clk_freq, + ident = "LiteX SoC on LPDDR4 Test Board", + ident_version = ident_version, + **kwargs) + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = _CRG(platform, sys_clk_freq, iodelay_clk_freq=iodelay_clk_freq) + + # LDDR4 SDRAM ------------------------------------------------------------------------------ + if not self.integrated_main_ram_size: + self.submodules.ddrphy = lpddr4.K7LPDDR4PHY(platform.request("lpddr4"), + iodelay_clk_freq = iodelay_clk_freq, + sys_clk_freq = sys_clk_freq, + ) + self.add_sdram("sdram", + phy = self.ddrphy, + module = MT53E256M16D1(sys_clk_freq, "1:8"), + l2_cache_size = kwargs.get("l2_size", 8192), + l2_cache_min_data_width = 256, + ) + + # HyperRAM --------------------------------------------------------------------------------- + if with_hyperram: + self.submodules.hyperram = HyperRAM(platform.request("hyperram")) + self.register_mem("hyperram", self.mem_map["hyperram"], self.hyperram.bus, 8*1024*1024) + + # SD Card ---------------------------------------------------------------------------------- + if with_sdcard: + self.add_sdcard() + + # Ethernet / Etherbone --------------------------------------------------------------------- + if with_ethernet or with_etherbone: + self.submodules.ethphy = LiteEthS7PHYRGMII( + clock_pads = self.platform.request("eth_clocks"), + pads = self.platform.request("eth")) + if with_ethernet: + self.add_ethernet(phy=self.ethphy, dynamic_ip=eth_dynamic_ip) + if with_etherbone: + self.add_etherbone(phy=self.ethphy, ip_address=eth_ip) + + # Jtagbone --------------------------------------------------------------------------------- + if with_jtagbone: + self.add_jtagbone() + + # UartBone --------------------------------------------------------------------------------- + if with_uartbone: + self.add_uartbone("serial", baudrate=1e6) + + # Leds ------------------------------------------------------------------------------------- + self.submodules.leds = LedChaser( + pads = platform.request_all("user_led"), + sys_clk_freq = sys_clk_freq) + +# Build -------------------------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC on LPDDR4 Test Board") + target = parser.add_argument_group(title="Target options") + target.add_argument("--build", action="store_true", help="Build bitstream") + target.add_argument("--load", action="store_true", help="Load bitstream") + target.add_argument("--flash", action="store_true", help="Flash bitstream") + target.add_argument("--sys-clk-freq", default=50e6, help="System clock frequency") + target.add_argument("--iodelay-clk-freq", default=200e6, help="IODELAYCTRL frequency") + ethopts = target.add_mutually_exclusive_group() + ethopts.add_argument("--with-ethernet", action="store_true", help="Add Ethernet") + ethopts.add_argument("--with-etherbone", action="store_true", help="Add EtherBone") + target.add_argument("--eth-ip", default="192.168.1.50", help="Ethernet/Etherbone IP address") + target.add_argument("--eth-dynamic-ip", action="store_true", help="Enable dynamic Ethernet IP addresses setting") + target.add_argument("--with-hyperram", action="store_true", help="Add HyperRAM") + target.add_argument("--with-sdcard", action="store_true", help="Add SDCard") + target.add_argument("--with-jtagbone", action="store_true", help="Add JTAGBone") + target.add_argument("--with-uartbone", action="store_true", help="Add UartBone on 2nd serial") + parser.add_argument("--no-ident-version", action="store_false", help="Disable build time output") + builder_args(parser) + soc_core_args(parser) + vivado_build_args(parser) + args = parser.parse_args() + + assert not (args.with_etherbone and args.eth_dynamic_ip) + + soc = BaseSoC( + sys_clk_freq = int(float(args.sys_clk_freq)), + iodelay_clk_freq = int(float(args.iodelay_clk_freq)), + with_ethernet = args.with_ethernet, + with_etherbone = args.with_etherbone, + eth_ip = args.eth_ip, + eth_dynamic_ip = args.eth_dynamic_ip, + with_hyperram = args.with_hyperram, + with_sdcard = args.with_sdcard, + with_jtagbone = args.with_jtagbone, + with_uartbone = args.with_uartbone, + ident_version = args.no_ident_version, + **soc_core_argdict(args)) + builder = Builder(soc, **builder_argdict(args)) + vns = builder.build(**vivado_build_argdict(args), run=args.build) + + if args.load: + prog = soc.platform.create_programmer() + prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".bit")) + + if args.flash: + prog = soc.platform.create_programmer() + prog.flash(0, os.path.join(builder.gateware_dir, soc.build_name + ".bin")) + +if __name__ == "__main__": + main() diff --git a/test/test_targets.py b/test/test_targets.py index 27860f0..03b62ab 100644 --- a/test/test_targets.py +++ b/test/test_targets.py @@ -126,6 +126,9 @@ class TestTargets(unittest.TestCase): # Microsemi PolarFire platforms.append("avalanche") + # LPDDR4 Test Board + platforms.append("lpddr4_test_board") + for name in platforms: with self.subTest(platform=name): cmd = """\