From c548b1c1e2a48fe80bda60a43701aa2791420b89 Mon Sep 17 00:00:00 2001
From: Andrew Dennison <andrew@motec.com.au>
Date: Fri, 15 Oct 2021 10:23:23 +1100
Subject: [PATCH] efinix: xyloni dev board basic support

* This works: efinix_xyloni_dev_kit.py --cpu-type None --build --load --flash
* issues with SPIflash - wrong generation for tristates miso mosi for
  some reason
---
 .../platforms/efinix_xyloni_dev_kit.py        | 103 ++++++++++++
 litex_boards/targets/efinix_xyloni_dev_kit.py | 148 ++++++++++++++++++
 test/test_targets.py                          |   2 +
 3 files changed, 253 insertions(+)
 create mode 100644 litex_boards/platforms/efinix_xyloni_dev_kit.py
 create mode 100755 litex_boards/targets/efinix_xyloni_dev_kit.py

diff --git a/litex_boards/platforms/efinix_xyloni_dev_kit.py b/litex_boards/platforms/efinix_xyloni_dev_kit.py
new file mode 100644
index 0000000..86ddad6
--- /dev/null
+++ b/litex_boards/platforms/efinix_xyloni_dev_kit.py
@@ -0,0 +1,103 @@
+#
+# This file is part of LiteX-Boards.
+#
+# Copyright (c) 2021 Franck Jullien <franck.jullien@collshade.fr>
+# Copyright (c) 2021 Florent Kermarrec <florent@enjoy-digital.fr>
+# SPDX-License-Identifier: BSD-2-Clause
+
+from litex.build.generic_platform import *
+from litex.build.efinix.platform import EfinixPlatform
+from litex.build.efinix import EfinixProgrammer
+
+# IOs ----------------------------------------------------------------------------------------------
+
+_io = [
+    # Clk 33.333MHz Oscillator
+    ("clk33", 0, Pins("C3"), IOStandard("3.3_V_LVTTL_/_LVCMOS")),  # net PLL_IN
+
+    # SPIFlash (W25Q128JVSIM)
+    ("spiflash", 0,
+        Subsignal("cs_n", Pins("J4")),  # net SPI_SS
+        Subsignal("clk",  Pins("H4")),  # net SPI_SCLK
+        Subsignal("mosi", Pins("F4")),  # net SPI_MOSI
+        Subsignal("miso", Pins("H3")),  # net SPI_MISO
+        #Subsignal("wp",   Pins("")),
+        #Subsignal("hold", Pins("")),
+        IOStandard("3.3_V_LVTTL_/_LVCMOS")
+     ),
+
+    ("spiflash2x", 0,
+        Subsignal("cs_n", Pins("J4")),  # net SPI_SS
+        Subsignal("clk",  Pins("H4")),  # net SPI_SCLK
+        Subsignal("dq", Pins("F4 H3")),  # DI DO nets SPI_MOSI, SPI_MISO
+        #Subsignal("wp",   Pins("")),
+        #Subsignal("hold", Pins("")),
+        IOStandard("3.3_V_LVTTL_/_LVCMOS")
+     ),
+
+    # SDCard
+    ("spisdcard", 0,
+        # all 4 SPI signals below have 10k pullup on dev board
+        Subsignal("clk",  Pins("J2")),  # net SD_SCLK
+        Subsignal("cs_n", Pins("G5")),  # net SD_CS
+        Subsignal("mosi", Pins("G4")),  # net SD_DI
+        Subsignal("miso", Pins("J3")),  # net SD_DO
+        Subsignal("det",  Pins("G3")),  # net CD2
+        Misc("SLEW=FAST"),
+        IOStandard("3.3_V_LVTTL_/_LVCMOS")
+     ),
+
+    # Leds  # nets LED1-4
+    ("user_led", 0, Pins("B3"), IOStandard(
+        "3.3_V_LVTTL_/_LVCMOS"), Misc("DRIVE_STRENGTH=3")),
+    ("user_led", 1, Pins("J6"), IOStandard(
+        "3.3_V_LVTTL_/_LVCMOS"), Misc("DRIVE_STRENGTH=3")),
+    ("user_led", 2, Pins("D7"),  IOStandard(
+        "3.3_V_LVTTL_/_LVCMOS"), Misc("DRIVE_STRENGTH=3")),
+    ("user_led", 3, Pins("D8"),  IOStandard(
+        "3.3_V_LVTTL_/_LVCMOS"), Misc("DRIVE_STRENGTH=3")),
+
+    # Buttons nets BTN1-2
+    ("user_btn", 0, Pins("C5"), IOStandard(
+        "3.3_V_LVTTL_/_LVCMOS"), Misc("WEAK_PULLUP")),
+    ("user_btn", 1, Pins("C9"),  IOStandard(
+        "3.3_V_LVTTL_/_LVCMOS"), Misc("WEAK_PULLUP")),
+
+    # Serial / PMOD USB-UART on PMOD E.
+    ("serial", 0,
+        Subsignal("tx", Pins("F3")),  # net TXD
+        Subsignal("rx", Pins("H2")),  # net RXD
+        IOStandard("3.3_V_LVTTL_/_LVCMOS")
+     ),
+]
+
+# Connectors ---------------------------------------------------------------------------------------
+
+_connectors = [
+    # Wacky PMOD pinout misunderstood by others too
+    # resulting in this order: GPIOL_12,14,16,19,13,15,17,18
+    ("pmod", "G1 E2 C2 D3 F1 E1 D2 E3"),
+    # GPIOR_020..28, 30..32, 34..36
+    ("j1", "F8 E7 F7 E6 F6 F5 G9 H9 J9 J8 G8 H8 J7 G6 H6"),
+    # GPIOR_19..10, 08..05, 03, 01, 00
+    ("j2", "E8 D9 D8 D7 C9 B9 D6 C8 B8 A9 A8 C7 C6 B6 A6 B5 A5"),
+]
+
+# Platform -----------------------------------------------------------------------------------------
+
+
+class Platform(EfinixPlatform):
+    default_clk_name = "clk33"
+    default_clk_period = 1e9/33.333e6
+
+    def __init__(self):
+        EfinixPlatform.__init__(self, "T8F81C2", _io,
+                                _connectors, toolchain="efinity")
+
+    def create_programmer(self):
+        return EfinixProgrammer()
+
+    def do_finalize(self, fragment):
+        EfinixPlatform.do_finalize(self, fragment)
+        self.add_period_constraint(self.lookup_request(
+            "clk33", loose=True), 1e9/33.333e6)
diff --git a/litex_boards/targets/efinix_xyloni_dev_kit.py b/litex_boards/targets/efinix_xyloni_dev_kit.py
new file mode 100755
index 0000000..ed4fb8f
--- /dev/null
+++ b/litex_boards/targets/efinix_xyloni_dev_kit.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python3
+
+#
+# This file is part of LiteX-Boards.
+#
+# Copyright (c) 2021 Franck Jullien <franck.jullien@collshade.fr>
+# Copyright (c) 2021 Florent Kermarrec <florent@enjoy-digital.fr>
+# SPDX-License-Identifier: BSD-2-Clause
+
+import argparse
+
+from migen import *
+from migen.genlib.resetsync import AsyncResetSynchronizer
+
+from litex_boards.platforms import efinix_xyloni_dev_kit
+
+from litex.soc.cores.clock import *
+from litex.soc.integration.soc_core import *
+from litex.soc.integration.soc import SoCRegion
+from litex.soc.integration.builder import *
+from litex.soc.cores.led import LedChaser
+
+# CRG ----------------------------------------------------------------------------------------------
+
+
+class _CRG(Module):
+    def __init__(self, platform, sys_clk_freq):
+        self.clock_domains.cd_sys = ClockDomain()
+
+        # # #
+
+        clk33 = platform.request("clk33")
+        rst_n = platform.request("user_btn", 0)
+
+        if sys_clk_freq == int(33.333e6):
+            self.comb += self.cd_sys.clk.eq(clk33)
+            self.specials += AsyncResetSynchronizer(self.cd_sys, ~rst_n)
+        else:
+            # PLL TODO: V1 simple pll not supported in infrastructure yet
+            self.submodules.pll = pll = TRIONPLL(platform)
+            self.comb += pll.reset.eq(~rst_n)
+            pll.register_clkin(clk33, 33.333e6)
+            pll.create_clkout(self.cd_sys, sys_clk_freq, with_reset=True)
+
+# BaseSoC ------------------------------------------------------------------------------------------
+
+
+class BaseSoC(SoCCore):
+    mem_map = {**{"sram": 0x01000000}, **{"spiflash": 0x80000000}}
+
+    def __init__(self, sys_clk_freq, bios_flash_offset, with_uartbone=False, with_spi_flash=False, with_led_chaser=True, **kwargs):
+        platform = efinix_xyloni_dev_kit.Platform()
+
+        # SoCCore ----------------------------------------------------------------------------------
+        kwargs["integrated_sram_size"] = 0xC00
+        # kwargs["integrated_rom_size"]  = 0x6000 # doesn't fit
+        kwargs["integrated_rom_size"] = 0
+
+        # Set CPU variant / reset address
+        if with_spi_flash:
+            kwargs["cpu_reset_address"] = self.mem_map["spiflash"] + \
+                bios_flash_offset
+
+        # Can probably only support minimal variant of vexriscv
+        if kwargs.get("cpu_type", "vexriscv") == "vexriscv":
+            kwargs["cpu_variant"] = "minimal"
+
+        SoCCore.__init__(self, platform, sys_clk_freq,
+                         ident="LiteX SoC on Efinix Xyloni Dev Kit",
+                         ident_version=True,
+                         integrated_rom_no_we=True,  # FIXME: Avoid this.
+                         integrated_sram_no_we=True,  # FIXME: Avoid this.
+                         integrated_main_ram_no_we=True,  # FIXME: Avoid this.
+                         **kwargs)
+
+        # CRG --------------------------------------------------------------------------------------
+        self.submodules.crg = _CRG(platform, sys_clk_freq)
+
+        # SPI Flash --------------------------------------------------------------------------------
+        if with_spi_flash:
+            from litespi.modules import W25Q128JV
+            from litespi.opcodes import SpiNorFlashOpCodes as Codes
+            self.add_spi_flash(mode="1x", module=W25Q128JV(
+                Codes.READ_1_1_1), with_master=True)
+
+            # Add ROM linker region --------------------------------------------------------------------
+            self.bus.add_region("rom", SoCRegion(
+                origin=self.mem_map["spiflash"] + bios_flash_offset,
+                size=32*1024,
+                linker=True)
+            )
+
+        # UartBone ---------------------------------------------------------------------------------
+        if with_uartbone:
+            self.add_uartbone("serial", baudrate=1e6)
+
+        # Leds -------------------------------------------------------------------------------------
+        if with_led_chaser:
+            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 Efinix Xyloni Dev Kit")
+    parser.add_argument("--build", action="store_true", help="Build bitstream")
+    parser.add_argument("--load",  action="store_true", help="Load bitstream")
+    parser.add_argument("--flash", action="store_true", help="Flash Bitstream")
+    # TODO: try a differnet frequency when PLL is supported
+    parser.add_argument("--sys-clk-freq", default=33.333e6,
+                        help="System clock frequency (default: 33.333MHz)")
+    parser.add_argument("--with-uartbone",  action="store_true",
+                        help="Enable Uartbone support")
+    parser.add_argument("--with-spi-flash", action="store_true",
+                        help="Enable SPI Flash (MMAPed)")
+    parser.add_argument("--bios-flash-offset", default=0x40000,
+                        help="BIOS offset in SPI Flash (default: 0x40000)")
+
+    builder_args(parser)
+    soc_core_args(parser)
+    args = parser.parse_args()
+
+    soc = BaseSoC(
+        int(float(args.sys_clk_freq)),
+        bios_flash_offset=args.bios_flash_offset,
+        with_uartbone=args.with_uartbone,
+        with_spi_flash=args.with_spi_flash,
+        **soc_core_argdict(args))
+    builder = Builder(soc, **builder_argdict(args))
+    builder.build(run=args.build)
+
+    if args.load:
+        prog = soc.platform.create_programmer()
+        prog.load_bitstream(os.path.join(
+            builder.gateware_dir, f"outflow/{soc.build_name}.bit"))
+
+    if args.flash:
+        from litex.build.openfpgaloader import OpenFPGALoader
+        prog = OpenFPGALoader("xyloni_spi")
+        prog.flash(0, os.path.join(builder.gateware_dir,
+                   f"outflow/{soc.build_name}.hex"))
+
+
+if __name__ == "__main__":
+    main()
diff --git a/test/test_targets.py b/test/test_targets.py
index 89c00ca..2ca005b 100644
--- a/test/test_targets.py
+++ b/test/test_targets.py
@@ -19,12 +19,14 @@ class TestTargets(unittest.TestCase):
         "quicklogic_quickfeather",          # Reason: No default clock.
         "efinix_trion_t120_bga576_dev_kit", # Reason: Require Efinity toolchain.
         "efinix_trion_t20_bga256_dev_kit",  # Reason: Require Efinity toolchain.
+        "efinix_xyloni_dev_kit",            # Reason: Require Efinity toolchain.
     ]
     excluded_targets   = [
         "simple",                           # Reason: Generic target.
         "quicklogic_quickfeather",          # Reason: No default clock.
         "efinix_trion_t120_bga576_dev_kit", # Reason: Require Efinity toolchain.
         "efinix_trion_t20_bga256_dev_kit",  # Reason: Require Efinity toolchain.
+        "efinix_xyloni_dev_kit",            # Reason: Require Efinity toolchain.
     ]
 
     # Build simple design for all platforms.