#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2017 Sergiusz Bazanski <q3k@q3k.org>
# Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause

from litex.build.generic_platform import *
from litex.build.lattice import LatticeECP5Platform
from litex.build.lattice.programmer import OpenOCDJTAGProgrammer

# IOs ----------------------------------------------------------------------------------------------

_io = [
    # Clk / Rst
    ("clk100", 0, Pins("P3"), IOStandard("LVDS")),
    ("rst_n",  0, Pins("T1"), IOStandard("LVCMOS33")),

    # Leds
    ("user_led", 0, Pins("E16"), IOStandard("LVCMOS25")),
    ("user_led", 1, Pins("D17"), IOStandard("LVCMOS25")),
    ("user_led", 2, Pins("D18"), IOStandard("LVCMOS25")),
    ("user_led", 3, Pins("E18"), IOStandard("LVCMOS25")),
    ("user_led", 4, Pins("F17"), IOStandard("LVCMOS25")),
    ("user_led", 5, Pins("F18"), IOStandard("LVCMOS25")),
    ("user_led", 6, Pins("E17"), IOStandard("LVCMOS25")),
    ("user_led", 7, Pins("F16"), IOStandard("LVCMOS25")),

    # Switches
    ("user_dip_btn", 0, Pins("H2"),  IOStandard("LVCMOS15")),
    ("user_dip_btn", 1, Pins("K3"),  IOStandard("LVCMOS15")),
    ("user_dip_btn", 2, Pins("G3"),  IOStandard("LVCMOS15")),
    ("user_dip_btn", 3, Pins("F2"),  IOStandard("LVCMOS15")),
    ("user_dip_btn", 4, Pins("J18"), IOStandard("LVCMOS25")),
    ("user_dip_btn", 5, Pins("K18"), IOStandard("LVCMOS25")),
    ("user_dip_btn", 6, Pins("K19"), IOStandard("LVCMOS25")),
    ("user_dip_btn", 7, Pins("K20"), IOStandard("LVCMOS25")),

    # Serial
    ("serial", 0,
        Subsignal("rx", Pins("C11"), IOStandard("LVCMOS33")),
        Subsignal("tx", Pins("A11"), IOStandard("LVCMOS33")),
    ),

    # SPIFlash
    ("spiflash", 0, # clock needs to be accessed through USRMCLK
        Subsignal("cs_n", Pins("R2")),
        Subsignal("mosi", Pins("W2")),
        Subsignal("miso", Pins("V2")),
        Subsignal("wp",   Pins("Y2")),
        Subsignal("hold", Pins("W1")),
        IOStandard("LVCMOS33"),
    ),
    ("spiflash4x", 0, # clock needs to be accessed through USRMCLK
        Subsignal("cs_n", Pins("R2")),
        Subsignal("dq",   Pins("W2 V2 Y2 W1")),
        IOStandard("LVCMOS33")
    ),


    # DDR3 SDRAM
    ("ddram", 0,
        Subsignal("a", Pins(
            "P2 C4 E5 F5 B3 F4 B5 E4",
            "C5 E3 D5 B4 C3"),
            IOStandard("SSTL135_I")),
        Subsignal("ba",    Pins("P5 N3 M3"), IOStandard("SSTL135_I")),
        Subsignal("ras_n", Pins("P1"), IOStandard("SSTL135_I")),
        Subsignal("cas_n", Pins("L1"), IOStandard("SSTL135_I")),
        Subsignal("we_n",  Pins("M1"), IOStandard("SSTL135_I")),
        Subsignal("cs_n",  Pins("K1"), IOStandard("SSTL135_I")),
        Subsignal("dm", Pins("J4 H5"), IOStandard("SSTL135_I")),
        Subsignal("dq", Pins(
            "L5 F1 K4 G1 L4 H1 G2 J3",
            "D1 C1 E2 C2 F3 A2 E1 B1"),
            IOStandard("SSTL135_I"),
            Misc("TERMINATION=75")),
        Subsignal("dqs_p", Pins("K2 H4"), IOStandard("SSTL135D_I"),
            Misc("TERMINATION=OFF"),
            Misc("DIFFRESISTOR=100")),
        Subsignal("clk_p", Pins("M4"), IOStandard("SSTL135D_I")),
        Subsignal("cke",   Pins("N2"), IOStandard("SSTL135_I")),
        Subsignal("odt",   Pins("L2"), IOStandard("SSTL135_I")),
        Subsignal("reset_n", Pins("N4"), IOStandard("SSTL135_I")),
        Misc("SLEWRATE=FAST"),
    ),

    # RGMII Ethernet
    ("eth_clocks", 0,
        Subsignal("tx", Pins("P19")),
        Subsignal("rx", Pins("L20")),
        IOStandard("LVCMOS25")
    ),
    ("eth", 0,
        Subsignal("rst_n",   Pins("U17")),
        Subsignal("mdio",    Pins("U18")),
        Subsignal("mdc",     Pins("T18")),
        Subsignal("rx_ctl",  Pins("U19")),
        Subsignal("rx_data", Pins("T20 U20 T19 R18")),
        Subsignal("tx_ctl",  Pins("R20")),
        Subsignal("tx_data", Pins("N19 N20 P18 P20")),
        IOStandard("LVCMOS25")
    ),
    ("eth_clocks", 1,
        Subsignal("tx", Pins("C20")),
        Subsignal("rx", Pins("J19")),
        IOStandard("LVCMOS25")
    ),
    ("eth", 1,
        Subsignal("rst_n",   Pins("F20")),
        Subsignal("mdio",    Pins("H20")),
        Subsignal("mdc",     Pins("G19")),
        Subsignal("rx_ctl",  Pins("F19")),
        Subsignal("rx_data", Pins("G18 G16 H18 H17")),
        Subsignal("tx_ctl",  Pins("E19")),
        Subsignal("tx_data", Pins("J17 J16 D19 D20")),
        IOStandard("LVCMOS25")
    ),

    # PCIe
    ("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")),
    ),

    # External Clock
    ("ext_clk", 0,
        Subsignal("p", Pins("A4")),
        Subsignal("n", Pins("A5")),
        IOStandard("LVDS")
    ),

    # Ref Clock
    ("refclk_en",    0, Pins("C12"), IOStandard("LVCMOS33")),
    ("refclk_rst_n", 0, Pins("R1"),  IOStandard("LVCMOS33")),
    ("refclk", 0,
        Subsignal("p", Pins("Y11")),
        Subsignal("n", Pins("Y12")),
    ),
    ("refclk", 1,
        Subsignal("p", Pins("Y19")),
        Subsignal("n", Pins("W20")),
    ),

    # SMA
    ("sma_tx", 0,
        Subsignal("p", Pins("W8")),
        Subsignal("n", Pins("W9")),
    ),
    ("sma_rx", 0,
        Subsignal("p", Pins("Y7")),
        Subsignal("n", Pins("Y8")),
    ),
]

# ECP5-hat extension (https://github.com/daveshah1/ecp5-hat) ---------------------------------------

_ecp5_soc_hat_io = [
    ("sdram_clock", 0, Pins("E14"), IOStandard("LVCMOS33")),
    ("sdram", 0,
         Subsignal("a", Pins(
            "C6  E15 A16 B16 D15 C15 B15 E12",
            "D12 B10  C7  A9 C10")),
         Subsignal("dq", Pins(
            "B19 B12  B9  E6  D6  E7  D7 B11",
            "C14 A14 E13 D13 C13 B13 A13 A12")),
         Subsignal("we_n",  Pins("E9")),
         Subsignal("ras_n", Pins("B8")),
         Subsignal("cas_n", Pins("D9")),
         Subsignal("cs_n",  Pins("C8")),
         Subsignal("cke",   Pins("D11")),
         Subsignal("ba",    Pins("D8 E8")),
         Subsignal("dm",    Pins("B6 D14")),
         Misc("SLEWRATE=FAST"),
         IOStandard("LVCMOS33"),
    ),
]

# Connectors ---------------------------------------------------------------------------------------

_connectors = [
   ("X3",
        "None",  # (no pin 0)
        "None",  #  1 GND
        "None",  #  2 N/C
        "None",  #  3 +2V5
        "B19",   #  4 EXPCON_IO29
        "B12",   #  5 EXPCON_IO30
        "B9",    #  6 EXPCON_IO31
        "E6",    #  7 EXPCON_IO32
        "D6",    #  8 EXPCON_IO33
        "E7",    #  9 EXPCON_IO34
        "D7",    # 10 EXPCON_IO35
        "B11",   # 11 EXPCON_IO36
        "B6",    # 12 EXPCON_IO37
        "E9",    # 13 EXPCON_IO38
        "D9",    # 14 EXPCON_IO39
        "B8",    # 15 EXPCON_IO40
        "C8",    # 16 EXPCON_IO41
        "D8",    # 17 EXPCON_IO42
        "E8",    # 18 EXPCON_IO43
        "C7",    # 19 EXPCON_IO44
        "C6",    # 20 EXPCON_IO45
        "None",  # 21 +5V
        "None",  # 22 GND
        "None",  # 23 +2V5
        "None",  # 24 GND
        "None",  # 25 +3V3
        "None",  # 26 GND
        "None",  # 27 +3V3
        "None",  # 28 GND
        "None",  # 29 EXPCON_OSC
        "None",  # 30 GND
        "None",  # 31 EXPCON_CLKIN
        "None",  # 32 GND
        "None",  # 33 EXPCON_CLKOUT
        "None",  # 34 GND
        "None",  # 35 +3V3
        "None",  # 36 GND
        "None",  # 37 +3V3
        "None",  # 38 GND
        "None",  # 39 +3V3
        "None",  # 40 GND
    ),
]

# Platform -----------------------------------------------------------------------------------------

class Platform(LatticeECP5Platform):
    default_clk_name   = "clk100"
    default_clk_period = 1e9/100e6

    def __init__(self, device="LFE5UM5G", toolchain="trellis", **kwargs):
        assert device in ["LFE5UM5G", "LFE5UM"]
        LatticeECP5Platform.__init__(self, device + "-45F-8BG381C", _io, _connectors, toolchain=toolchain, **kwargs)

    def create_programmer(self):
        return OpenOCDJTAGProgrammer("openocd_versa_ecp5.cfg")

    def do_finalize(self, fragment):
        self.add_period_constraint(self.lookup_request("clk100", loose=True), 1e9/100e6)
        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)
