From a0fd3e75369d28d7fe1e90f8c0b5e76a6c6d53b7 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 12 Jan 2023 18:49:45 +0100 Subject: [PATCH] Add initial OCP-TAP TimeCard support with PCIe/SPIFlash/Leds/Buttons/DNA/XADC (Compiles but untested). --- README.md | 1 + litex_boards/platforms/ocp_tap_timecard.py | 105 +++++++++++++++ litex_boards/targets/ocp_tap_timecard.py | 146 +++++++++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 litex_boards/platforms/ocp_tap_timecard.py create mode 100755 litex_boards/targets/ocp_tap_timecard.py diff --git a/README.md b/README.md index 7c6c9d8..335bade 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,7 @@ Some of the suported boards, see yours? Give LiteX-Boards a try! ├── numato_mimas_a7 ├── numato_nereid ├── numato_tagus + ├── ocp_tap_timecard ├── pano_logic_g2 ├── qmtech_10cl006 ├── qmtech_5cefa2 diff --git a/litex_boards/platforms/ocp_tap_timecard.py b/litex_boards/platforms/ocp_tap_timecard.py new file mode 100644 index 0000000..c245f9f --- /dev/null +++ b/litex_boards/platforms/ocp_tap_timecard.py @@ -0,0 +1,105 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2023 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +# TimeCard project: +# https://opencomputeproject.github.io/Time-Appliance-Project/docs/time-card/introduction + +# FPGA SoM: +# http://www.alinx.vip:81/ug_en/AC7100B_User_Manual.pdf + +from litex.build.generic_platform import * +from litex.build.xilinx import Xilinx7SeriesPlatform, VivadoProgrammer +from litex.build.openocd import OpenOCD + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + # Clk / Rst. + ("clk125", 0, + Subsignal("p", Pins("F6"), IOStandard("DIFF_SSTL15")), + Subsignal("n", Pins("E6"), IOStandard("DIFF_SSTL15")) + ), + ("clk200", 0, + Subsignal("p", Pins("R4"), IOStandard("DIFF_SSTL15")), + Subsignal("n", Pins("T4"), IOStandard("DIFF_SSTL15")) + ), + ("rst_n", 0, Pins("T6"), IOStandard("LVCMOS15")), + + # Leds. + ("user_led", 0, Pins("B13"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("C13"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("D14"), IOStandard("LVCMOS33")), + ("user_led", 3, Pins("D15"), IOStandard("LVCMOS33")), + + # Buttons. + ("user_btn", 0, Pins("J21"), IOStandard("LVCMOS33")), + ("user_btn", 1, Pins("E13"), IOStandard("LVCMOS33")), + + # SPIFlash. + ("flash_cs_n", 0, Pins("T19"), IOStandard("LVCMOS33")), + ("flash", 0, + Subsignal("mosi", Pins("P22")), + Subsignal("miso", Pins("R22")), + Subsignal("wp", Pins("P21")), + Subsignal("hold", Pins("R21")), + IOStandard("LVCMOS33") + ), + + # PCIe. + ("pcie_x1", 0, + Subsignal("rst_n", Pins("J20"), IOStandard("LVCMOS33"), Misc("PULLUP=TRUE")), + Subsignal("clk_p", Pins("F10")), + Subsignal("clk_n", Pins("E10")), + Subsignal("rx_p", Pins("D11")), + Subsignal("rx_n", Pins("C11")), + Subsignal("tx_p", Pins("D5")), + Subsignal("tx_n", Pins("C5")), + ), +] + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(Xilinx7SeriesPlatform): + default_clk_name = "clk200" + default_clk_period = 1e9/200e6 + + def __init__(self,toolchain="vivado"): + Xilinx7SeriesPlatform.__init__(self, "xc7a100t-fgg484-2", _io, toolchain=toolchain) + + self.toolchain.bitstream_commands = [ + "set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]", + "set_property BITSTREAM.CONFIG.CONFIGRATE 16 [current_design]", + "set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]", + "set_property CFGBVS VCCO [current_design]", + "set_property CONFIG_VOLTAGE 3.3 [current_design]", + ] + + self.toolchain.additional_commands = [ + # Non-Multiboot SPI-Flash bitstream generation. + "write_cfgmem -force -format bin -interface spix4 -size 16 -loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin", + + # Multiboot SPI-Flash Operational bitstream generation. + "set_property BITSTREAM.CONFIG.TIMER_CFG 0x0001fbd0 [current_design]", + "set_property BITSTREAM.CONFIG.CONFIGFALLBACK Enable [current_design]", + "write_bitstream -force {build_name}_operational.bit ", + "write_cfgmem -force -format bin -interface spix4 -size 16 -loadbit \"up 0x0 {build_name}_operational.bit\" -file {build_name}_operational.bin", + + # Multiboot SPI-Flash Fallback bitstream generation. + "set_property BITSTREAM.CONFIG.NEXT_CONFIG_ADDR 0x00400000 [current_design]", + "write_bitstream -force {build_name}_fallback.bit ", + "write_cfgmem -force -format bin -interface spix4 -size 16 -loadbit \"up 0x0 {build_name}_fallback.bit\" -file {build_name}_fallback.bin" + ] + + def create_programmer(self, name='openocd'): + if name == 'openocd': + return OpenOCD("openocd_xc7_ft232.cfg", "bscan_spi_xc7a200t.bit") + elif name == 'vivado': + # TODO: some board versions may have s25fl128s + return VivadoProgrammer(flash_part='s25fl256sxxxxxx0-spi-x1_x2_x4') + + def do_finalize(self, fragment): + Xilinx7SeriesPlatform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request("clk200", loose=True), 1e9/200e6) diff --git a/litex_boards/targets/ocp_tap_timecard.py b/litex_boards/targets/ocp_tap_timecard.py new file mode 100755 index 0000000..0d194a9 --- /dev/null +++ b/litex_boards/targets/ocp_tap_timecard.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2023 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +# Build/Use ---------------------------------------------------------------------------------------- +# Build/Load bitstream: +# ./ocp_tap_timecard.py --uart-name=crossover --with-pcie --build --driver --load (or --flash) +# +#.Build the kernel and load it: +# cd build//driver/kernel +# make +# sudo ./init.sh +# +# Test userspace utilities: +# cd build//driver/user +# make +# ./litepcie_util info +# ./litepcie_util scratch_test +# ./litepcie_util dma_test +# ./litepcie_util uart_test + +import os + +from migen import * + +from litex.gen import LiteXModule + +from litex_boards.platforms import ocp_tap_timecard + +from litex.soc.interconnect.csr import * +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * + +from litex.soc.cores.clock import * +from litex.soc.cores.led import LedChaser +from litex.soc.cores.xadc import XADC +from litex.soc.cores.dna import DNA + +from litepcie.phy.s7pciephy import S7PCIEPHY +from litepcie.software import generate_litepcie_software + +# CRG ---------------------------------------------------------------------------------------------- + +class CRG(LiteXModule): + def __init__(self, platform, sys_clk_freq): + self.rst = Signal() + self.cd_sys = ClockDomain() + + # Clk/Rst + clk200 = platform.request("clk200") + + # PLL + self.pll = pll = S7PLL() + self.comb += pll.reset.eq(self.rst) + pll.register_clkin(clk200, 200e6) + pll.create_clkout(self.cd_sys, sys_clk_freq) + platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst. + +# BaseSoC ----------------------------------------------------------------------------------------- + +class BaseSoC(SoCCore): + def __init__(self, sys_clk_freq=100e6, + with_led_chaser = True, + with_pcie = False, + **kwargs): + platform = ocp_tap_timecard.Platform() + + # CRG -------------------------------------------------------------------------------------- + self.crg = CRG(platform, sys_clk_freq) + + # SoCCore ---------------------------------------------------------------------------------- + SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on OCP-TAP TimeCard", **kwargs) + + # XADC ------------------------------------------------------------------------------------- + self.xadc = XADC() + + # DNA -------------------------------------------------------------------------------------- + self.dna = DNA() + self.dna.add_timing_constraints(platform, sys_clk_freq, self.crg.cd_sys.clk) + + # PCIe ------------------------------------------------------------------------------------- + if with_pcie: + self.pcie_phy = S7PCIEPHY(platform, platform.request("pcie_x1"), + data_width = 64, + bar0_size = 0x20000) + self.add_pcie(phy=self.pcie_phy, ndmas=1, address_width=64) + # FIXME: Apply it to all targets (integrate it in LitePCIe?). + platform.add_period_constraint(self.crg.cd_sys.clk, 1e9/sys_clk_freq) + + # ICAP (For FPGA reload over PCIe). + from litex.soc.cores.icap import ICAP + self.icap = ICAP() + self.icap.add_reload() + self.icap.add_timing_constraints(platform, sys_clk_freq, self.crg.cd_sys.clk) + + # Flash (For SPIFlash update over PCIe). + from litex.soc.cores.gpio import GPIOOut + from litex.soc.cores.spi_flash import S7SPIFlash + self.flash_cs_n = GPIOOut(platform.request("flash_cs_n")) + self.flash = S7SPIFlash(platform.request("flash"), sys_clk_freq, 25e6) + + # Leds ------------------------------------------------------------------------------------- + if with_led_chaser: + self.leds = LedChaser( + pads = platform.request_all("user_led"), + sys_clk_freq = sys_clk_freq + ) + +# Build -------------------------------------------------------------------------------------------- + +def main(): + from litex.build.parser import LiteXArgumentParser + parser = LiteXArgumentParser(platform=ocp_tap_timecard.Platform, description="LiteX SoC on OCP-TAP TimeCard.") + parser.add_target_argument("--flash", action="store_true", help="Flash bitstream.") + parser.add_target_argument("--sys-clk-freq", default=100e6, type=float, help="System clock frequency.") + parser.add_target_argument("--with-pcie", action="store_true", help="Enable PCIe support.") + parser.add_target_argument("--driver", action="store_true", help="Generate PCIe driver.") + args = parser.parse_args() + + soc = BaseSoC( + sys_clk_freq = args.sys_clk_freq, + with_pcie = args.with_pcie, + **parser.soc_argdict + ) + + builder = Builder(soc, **parser.builder_argdict) + if args.build: + builder.build(**parser.toolchain_argdict) + + 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(builder.get_bitstream_filename(mode="sram")) + + if args.flash: + prog = soc.platform.create_programmer() + prog.flash(0, builder.get_bitstream_filename(mode="flash")) + +if __name__ == "__main__": + main()