diff --git a/litex_boards/platforms/opalkelly_xem8320.py b/litex_boards/platforms/opalkelly_xem8320.py new file mode 100644 index 0000000..f80684e --- /dev/null +++ b/litex_boards/platforms/opalkelly_xem8320.py @@ -0,0 +1,156 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2022 Andrew Elbert Wilson +# SPDX-License-Identifier: BSD-2-Clause + +from litex.build.generic_platform import * +from litex.build.xilinx import XilinxPlatform, VivadoProgrammer + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + # Clk / Rst + ("sys_clk100", 0, + Subsignal("p", Pins("T24"), IOStandard("LVDS")), + Subsignal("n", Pins("U24"), IOStandard("LVDS")) + ), + + ("ddr_clk100", 0, + Subsignal("p", Pins("AD20"), IOStandard("LVDS")), + Subsignal("n", Pins("AE20"), IOStandard("LVDS")) + ), + #NO RESET, maybe use okHOST USB later + #("cpu_reset", 0, Pins("AN8"), IOStandard("LVCMOS18")), + + # Leds + ("user_led", 0, Pins("G19"), IOStandard("LVCMOS18")), + ("user_led", 1, Pins("B16"), IOStandard("LVCMOS18")), + ("user_led", 2, Pins("F22"), IOStandard("LVCMOS18")), + ("user_led", 3, Pins("E22"), IOStandard("LVCMOS18")), + ("user_led", 4, Pins("M24"), IOStandard("LVCMOS18")), + ("user_led", 5, Pins("G22"), IOStandard("LVCMOS18")), + + # Opal Kelly Host USBC interface + ("okHost", 0, # Uses the FrontPanel API + Subsignal("okAA", Pins("T19")), + Subsignal("okHU", Pins("U20 U26 T22")), + Subsignal("okUH", Pins("V23 T23 U22 U25 U21")), + Subsignal("okUHU", Pins("P26 P25 R26 R25 R23 R22 P21 P20", + "R21 R20 P23 N23 T25 N24 N22 V26", + "N19 V21 N21 W20 W26 W19 Y25 Y26", + "Y22 V22 W21 AA23 Y23 AA24 W25 AA25")), + Misc("SLEW=FAST"), + IOStandard("LVCMOS18"), + ), + + # TODO: Add SMA & SFP+ + + + # DDR4 SDRAM + ("ddram", 0, + Subsignal("a", Pins( + "AD18 AE17 AB17 AE18 AD19 AF17 Y17 AE16", + "AA17 AC17 AC19 AC16 AF20 AD16"), + IOStandard("SSTL12_DCI")), + Subsignal("ba", Pins("AC18 AF18"), IOStandard("SSTL12_DCI")), + Subsignal("bg", Pins("AB19"), IOStandard("SSTL12_DCI")), + Subsignal("ras_n", Pins("AA18"), IOStandard("SSTL12_DCI")), + Subsignal("cas_n", Pins("AF19"), IOStandard("SSTL12_DCI")), + Subsignal("we_n", Pins("AA19"), IOStandard("SSTL12_DCI")), + Subsignal("cs_n", Pins("AF22"), IOStandard("SSTL12_DCI")), + Subsignal("act_n", Pins("Y18"), IOStandard("SSTL12_DCI")), + Subsignal("dm", Pins("AE25 AE22"), + IOStandard("POD12_DCI")), + Subsignal("dq", Pins( + "AF24 AB25 AB26 AC24 AF25 AB24 AD24 AD25", + "AB21 AE21 AE23 AD23 AC23 AD21 AC22 AC21"), + IOStandard("POD12_DCI"), + Misc("PRE_EMPHASIS=RDRV_240"), + Misc("EQUALIZATION=EQ_LEVEL2")), + Subsignal("dqs_p", Pins("AC26 AA22"), + IOStandard("DIFF_POD12_DCI"), + Misc("PRE_EMPHASIS=RDRV_240"), + Misc("EQUALIZATION=EQ_LEVEL2")), + Subsignal("dqs_n", Pins("AD26 AB22"), + IOStandard("DIFF_POD12_DCI"), + Misc("PRE_EMPHASIS=RDRV_240"), + Misc("EQUALIZATION=EQ_LEVEL2")), + Subsignal("clk_p", Pins("Y20"), IOStandard("DIFF_SSTL12_DCI")), + Subsignal("clk_n", Pins("Y21"), IOStandard("DIFF_SSTL12_DCI")), + Subsignal("cke", Pins("AA20"), IOStandard("SSTL12_DCI")), + Subsignal("odt", Pins("AB20"), IOStandard("SSTL12_DCI")), + Subsignal("reset_n", Pins("AE26"), IOStandard("LVCMOS12")), + Misc("SLEW=FAST"), + ), +] + +# Connectors --------------------------------------------------------------------------------------- + +# TODO: SYZYGY Connectors & SYZYGY to PMODS! + + +_connectors = [ + ("pmod1", "AC14 AC13 AF15 AF14 AF13 AE13 H13 J13"), + ("pmod2", "AB15 AB16 W14 J14 AE15 W15 Y15 J15"), + ("pmod3", "G14 H14 W13 W12 AA13 Y13 H12 J12"), + ("pmod4", "AD14 AD13 W16 AD15 AB14 AA14 Y16 AA15"), +] + +def dvi_pmod_io(pmoda,pmodb): + return [ + ("dvi", 0, + Subsignal("clk", Pins(f"{pmodb}:1")), + Subsignal("de", Pins(f"{pmodb}:6")), + Subsignal("hsync", Pins(f"{pmodb}:3")), + Subsignal("vsync", Pins(f"{pmodb}:7")), + Subsignal("b", Pins(f"{pmoda}:5 {pmoda}:1 {pmoda}:4 {pmoda}:0")), + Subsignal("g", Pins(f"{pmoda}:7 {pmoda}:3 {pmoda}:6 {pmoda}:2")), + Subsignal("r", Pins(f"{pmodb}:2 {pmodb}:5 {pmodb}:4 {pmodb}:0")), + IOStandard("LVCMOS33"), + ) + ] + +_dvi_pmod_io = dvi_pmod_io("pmod2","pmod1") # SDCARD PMOD on JD. + +def sdcard_pmod_io(pmod): + return [ + # SDCard PMOD: + # - https://store.digilentinc.com/pmod-microsd-microsd-card-slot/ + # - https://github.com/antmicro/arty-expansion-board + ("spisdcard", 0, + Subsignal("clk", Pins(f"{pmod}:3")), + Subsignal("mosi", Pins(f"{pmod}:1"), Misc("PULLUP True")), + Subsignal("cs_n", Pins(f"{pmod}:0"), Misc("PULLUP True")), + Subsignal("miso", Pins(f"{pmod}:2"), Misc("PULLUP True")), + Misc("SLEW=FAST"), + IOStandard("LVCMOS33"), + ), + ("sdcard", 0, + Subsignal("data", Pins(f"{pmod}:2 {pmod}:4 {pmod}:5 {pmod}:0"), Misc("PULLUP True")), + Subsignal("cmd", Pins(f"{pmod}:1"), Misc("PULLUP True")), + Subsignal("clk", Pins(f"{pmod}:3")), + Subsignal("cd", Pins(f"{pmod}:6")), + Misc("SLEW=FAST"), + IOStandard("LVCMOS33"), + ), +] + +_sdcard_pmod_io = sdcard_pmod_io("pmod3") # SDCARD PMOD on JD. +# Platform ----------------------------------------------------------------------------------------- + +class Platform(XilinxPlatform): + default_clk_name = "sys_clk100" + default_clk_period = 1e9/100e6 + + def __init__(self, toolchain="vivado"): + XilinxPlatform.__init__(self, "xcau25p-ffvb676-2-e", _io, _connectors, toolchain=toolchain) + + def create_programmer(self): + return VivadoProgrammer() + + def do_finalize(self, fragment): + XilinxPlatform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request("sys_clk100", loose=True), 1e9/100e6) + self.add_period_constraint(self.lookup_request("ddr_clk100", loose=True), 1e9/100e6) + self.add_platform_command("set_property INTERNAL_VREF 0.84 [get_iobanks 64]") diff --git a/litex_boards/prog/openocd_xcau25p_ft323.cfg b/litex_boards/prog/openocd_xcau25p_ft323.cfg new file mode 100644 index 0000000..9f70cf2 --- /dev/null +++ b/litex_boards/prog/openocd_xcau25p_ft323.cfg @@ -0,0 +1,64 @@ +interface ftdi +ftdi_vid_pid 0x0403 0x6014 +ftdi_channel 0 +ftdi_layout_init 0x00e8 0x60eb +reset_config none + +#openocd missing support, added to local cfg file + +set CHIP XCAU25P + + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME xcu +} + +# The cvarious chips in the Ultrascale family have different IR length. +# Set $CHIP before including this file to determine the device. +array set _XCU_DATA { + XCAU25P {0x04A64093 6} +} + +if { ![info exists CHIP] } { + error "set CHIP to one of "[concat [array names _XCU_DATA]] +} + +if { ![llength [array names _XCU_DATA $CHIP]] } { + error "unknown CHIP: "$CHIP +} + +set _EXPID [lindex $_XCU_DATA($CHIP) 0] +set _IRLEN [lindex $_XCU_DATA($CHIP) 1] + +# the 4 top bits (28:31) are the die stepping/revisions. ignore it. +jtag newtap $_CHIPNAME tap -irlen $_IRLEN -ignore-version -expected-id $_EXPID + +pld device virtex2 $_CHIPNAME.tap 1 + +set XCU_JSHUTDOWN 0x0d +set XCU_JPROGRAM 0x0b +set XCU_JSTART 0x0c +set XCU_BYPASS 0x3f + +proc xcu_program {tap} { + global XCU_JSHUTDOWN XCU_JPROGRAM XCU_JSTART XCU_BYPASS + irscan $tap $XCU_JSHUTDOWN + irscan $tap $XCU_JPROGRAM + runtest 60000 + #JSTART prevents this from working... + #irscan $tap $XCU_JSTART + runtest 2000 + irscan $tap $XCU_BYPASS + runtest 2000 +} + +source [find cpld/jtagspi.cfg] +adapter_khz 25000 + + +proc fpga_program {} { + global _CHIPNAME + xc7_program $_CHIPNAME.tap +} \ No newline at end of file diff --git a/litex_boards/targets/opalkelly_xem8320.py b/litex_boards/targets/opalkelly_xem8320.py new file mode 100644 index 0000000..487fc26 --- /dev/null +++ b/litex_boards/targets/opalkelly_xem8320.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2022 Andrew Elbert Wilson +# SPDX-License-Identifier: BSD-2-Clause + +import os + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex_boards.platforms import opalkelly_xem8320 + +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 litex.soc.cores.video import VideoDVIPHY +from litedram.modules import MT40A512M16 +from litedram.phy import usddrphy + + + +# 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() + self.clock_domains.cd_idelay = ClockDomain() + self.clock_domains.cd_hdmi = ClockDomain() + self.clock_domains.cd_hdmi5x = ClockDomain() + + # # # + clk100 = platform.request("ddr_clk100") + + self.submodules.pll = pll = USMMCM(speedgrade=-2) + self.comb += pll.reset.eq(self.rst) + pll.register_clkin(clk100, 100e6) + pll.create_clkout(self.cd_sys, sys_clk_freq, with_reset=False) + pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq) #500 + pll.create_clkout(self.cd_hdmi, 25e6) + pll.create_clkout(self.cd_hdmi5x, 5*25e6) + + platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst. + + # #option for second MMCM for video clocks + # self.submodules.video_pll = video_pll = USMMCM(speedgrade=-2) + # video_pll.reset.eq(self.rst) + # video_pll.register_clkin(self.cd_sys.clk, sys_clk_freq) + # video_pll.create_clkout(self.cd_hdmi, 25e6) + # video_pll.create_clkout(self.cd_hdmi5x, 5*25e6) + + self.submodules.idelayctrl = USIDELAYCTRL(cd_ref=self.cd_sys4x, cd_sys=self.cd_sys) + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCCore): + def __init__(self, sys_clk_freq=int(125e6), with_ethernet=False, with_etherbone=False, + eth_ip="192.168.1.50", with_led_chaser=True, + **kwargs): + platform = opalkelly_xem8320.Platform() + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = _CRG(platform, sys_clk_freq) + + kwargs["uart_name"] = "jtag_uart" + + # TODO: add okHost FrontPanel API for UART, Data streaing, and Debug + + # SoCCore ---------------------------------------------------------------------------------- + SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on xem8320", **kwargs) + + # DDR4 SDRAM ------------------------------------------------------------------------------- + if not self.integrated_main_ram_size: + self.submodules.ddrphy = usddrphy.USPDDRPHY(platform.request("ddram"), + memtype = "DDR4", + sys_clk_freq = sys_clk_freq, + iodelay_clk_freq = 500e6) + self.add_sdram("sdram", + phy = self.ddrphy, + module = MT40A512M16(sys_clk_freq, "1:4"), + size = 0x40000000, + l2_cache_size = kwargs.get("l2_size", 8192) + ) + + # TODO: add SFP+ cages for ethernet + # Ethernet / Etherbone --------------------------------------------------------------------- + # if with_ethernet or with_etherbone: + # self.submodules.ethphy = KU_1000BASEX(self.crg.cd_eth.clk, + # data_pads = self.platform.request("sfp", 0), + # sys_clk_freq = self.clk_freq) + # self.comb += self.platform.request("sfp_tx_disable_n", 0).eq(1) + # self.platform.add_platform_command("set_property SEVERITY {{Warning}} [get_drc_checks REQP-1753]") + # if with_ethernet: + # self.add_ethernet(phy=self.ethphy) + # if with_etherbone: + # self.add_etherbone(phy=self.ethphy, ip_address=eth_ip) + + platform.add_extension(opalkelly_xem8320._dvi_pmod_io) + self.submodules.videophy = VideoDVIPHY(platform.request("dvi"), clock_domain="hdmi") + self.add_video_framebuffer(phy=self.videophy, timings="640x480@75Hz", clock_domain="hdmi") + + + # Leds ------------------------------------------------------------------------------------- + if with_led_chaser: + self.submodules.leds = LedChaser( + pads = platform.request_all("user_led"), + sys_clk_freq = sys_clk_freq) + +# Build -------------------------------------------------------------------------------------------- + +def main(): + from litex.soc.integration.soc import LiteXSoCArgumentParser + parser = LiteXSoCArgumentParser(description="LiteX SoC on XEM8320") + target_group = parser.add_argument_group(title="Target options") + target_group.add_argument("--build", action="store_true", help="Build design.") + target_group.add_argument("--load", action="store_true", help="Load bitstream.") + target_group.add_argument("--sys-clk-freq", default=125e6, help="System clock frequency.") + #ethopts = target_group.add_mutually_exclusive_group() + #ethopts.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support.") + builder_args(parser) + soc_core_args(parser) + args = parser.parse_args() + + soc = BaseSoC( + sys_clk_freq = int(float(args.sys_clk_freq)), + #with_ethernet = args.with_ethernet, + #with_etherbone = args.with_etherbone, + #eth_ip = args.eth_ip, + #with_pcie = args.with_pcie, + #with_sata = args.with_sata, + **soc_core_argdict(args) + ) + + soc.platform.add_extension(opalkelly_xem8320._sdcard_pmod_io) + soc.add_spi_sdcard() + + builder = Builder(soc, **builder_argdict(args)) + if args.build: + builder.build() + + if args.load: + prog = soc.platform.create_programmer() + prog.load_bitstream(builder.get_bitstream_filename(mode="sram")) + # TODO: add option for FrontPanel Programming + +if __name__ == "__main__": + main()