From 462ee481bf44f02b5818bed6f2998c1c3f41c7b4 Mon Sep 17 00:00:00 2001 From: Yu-Ti Kuo Date: Sat, 2 Nov 2024 10:09:06 +0800 Subject: [PATCH] Add embedfire_rise_pro Add Flash --- litex_boards/platforms/embedfire_rise_pro.py | 165 ++++++++++++++ litex_boards/targets/embedfire_rise_pro.py | 217 +++++++++++++++++++ 2 files changed, 382 insertions(+) create mode 100644 litex_boards/platforms/embedfire_rise_pro.py create mode 100755 litex_boards/targets/embedfire_rise_pro.py diff --git a/litex_boards/platforms/embedfire_rise_pro.py b/litex_boards/platforms/embedfire_rise_pro.py new file mode 100644 index 000000000..ce620c0b9 --- /dev/null +++ b/litex_boards/platforms/embedfire_rise_pro.py @@ -0,0 +1,165 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2024 Yu-Ti Kuo +# SPDX-License-Identifier: BSD-2-Clause +# embedfire rise pro FPGA: https://detail.tmall.com/item.htm?id=645153441975 + +from litex.build.generic_platform import * +from litex.build.xilinx import Xilinx7SeriesPlatform +from litex.build.openocd import OpenOCD +from litex.build.xilinx.programmer import VivadoProgrammer + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + # Clk / Rst + ("clk50" , 0, Pins("W19"), IOStandard("LVCMOS33")), + ("cpu_reset", 0, Pins("N15"), IOStandard("LVCMOS33")), + + # Leds + ("user_led", 0, Pins("M21"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("L21"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("K21"), IOStandard("LVCMOS33")), + ("user_led", 3, Pins("K22"), IOStandard("LVCMOS33")), + + # Buttons + ("user_sw", 0, Pins("V17"), IOStandard("LVCMOS33")), + ("user_sw", 1, Pins("W17"), IOStandard("LVCMOS33")), + ("user_sw", 2, Pins("AA18"), IOStandard("LVCMOS33")), + ("user_sw", 3, Pins("AB18"), IOStandard("LVCMOS33")), + + # Beeper (Buzzer) + ("beeper", 0, Pins("M17"), IOStandard("LVCMOS33")), + + # Fan + ("fan", 0, Pins("W22"), IOStandard("LVCMOS33")), + + # Serial CH340G + ("serial", 0, + Subsignal("tx", Pins("N17")), + Subsignal("rx", Pins("P17")), + IOStandard("LVCMOS33") + ), + + # I2C EEPROM 24C64 + ("i2c", 0, + Subsignal("scl", Pins("E22")), + Subsignal("sda", Pins("D22")), + IOStandard("LVCMOS33"), + ), + + # # SPIFlash N25Q128A13ESE40G + # ("spiflash4x", 0, + # Subsignal("cs_n", Pins("T19")), + # Subsignal("clk", Pins("L12")), + # Subsignal("dq", Pins("P22 R22 P21 R21")), + # IOStandard("LVCMOS33") + # ), + + # DDR3 SDRAM MT41K256M16 + ("ddram", 0, + Subsignal("a", Pins( + "AA4 AB2 AA5 AB3 AB1 U2 W1 R2", + "V2 U3 Y1 W2 Y2 U1 V3"), + IOStandard("SSTL135")), + Subsignal("ba", Pins("AA1 Y3 AA3"), IOStandard("SSTL135")), + Subsignal("ras_n", Pins("W6"), IOStandard("SSTL135")), + Subsignal("cas_n", Pins("U5"), IOStandard("SSTL135")), + Subsignal("we_n", Pins("Y4"), IOStandard("SSTL135")), + Subsignal("cs_n", Pins("T1"), IOStandard("SSTL135")), + Subsignal("dm", Pins("D2 G2 M2 M5"), IOStandard("SSTL135")), + Subsignal("dq", Pins( + "C2 G1 A1 F3 B2 F1 B1 E2", + "H3 G3 H2 H5 J1 J5 K1 H4", + "L4 M3 L3 J6 K3 K6 J4 L5", + "P1 N4 R1 N2 M6 N5 P6 P2"), + IOStandard("SSTL135"), + Misc("IN_TERM=UNTUNED_SPLIT_40")), + Subsignal("dqs_p", Pins("E1 K2 M1 P5"), + IOStandard("DIFF_SSTL135"), + Misc("IN_TERM=UNTUNED_SPLIT_40")), + Subsignal("dqs_n", Pins("D1 J2 L1 P4"), + IOStandard("DIFF_SSTL135"), + Misc("IN_TERM=UNTUNED_SPLIT_40")), + Subsignal("clk_p", Pins("V4"), IOStandard("DIFF_SSTL135")), + Subsignal("clk_n", Pins("W4"), IOStandard("DIFF_SSTL135")), + Subsignal("cke", Pins("AB5"), IOStandard("SSTL135")), + Subsignal("odt", Pins("T5"), IOStandard("SSTL135")), + Subsignal("reset_n", Pins("R3"), IOStandard("SSTL135")), + Misc("SLEW=FAST"), + ), + + # RGMII Ethernet (RTL8211F) + ("eth_clocks", 0, + Subsignal("tx", Pins("C18")), + Subsignal("rx", Pins("C19")), + IOStandard("LVCMOS33") + ), + ("eth", 0, + #SubSignal("inib"), Pins("D21")), + #Subsignal("rst_n", Pins("E21")), + Subsignal("mdio", Pins("G22")), + Subsignal("mdc", Pins("G21")), + Subsignal("rx_ctl", Pins("C22")), + Subsignal("rx_data", Pins("D20 C20 A18 A19")), + Subsignal("tx_ctl", Pins("B22")), + Subsignal("tx_data", Pins("B20 A20 B21 A21")), + IOStandard("LVCMOS33") + ), + + # SDCard + ("spisdcard", 0, + Subsignal("cd", Pins("AA19")), + Subsignal("clk", Pins("Y22")), + Subsignal("mosi", Pins("Y21")), + Subsignal("cs_n", Pins("A14")), + Subsignal("miso", Pins("AB21")), + Misc("SLEW=FAST"), + IOStandard("LVCMOS33"), + ), + + ("sdcard", 0, + Subsignal("data", Pins("AB21 AB22 AB20 W21"),), + Subsignal("cmd", Pins("Y21"),), + Subsignal("clk", Pins("Y22")), + Subsignal("cd", Pins("AA19")), + Misc("SLEW=FAST"), + IOStandard("LVCMOS33"), + ), +] +# Connectors --------------------------------------------------------------------------------------- + +_connectors = [] # ToDo + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(Xilinx7SeriesPlatform): + default_clk_name = "clk50" + default_clk_period = 1e9/50e6 + + def __init__(self, variant="a7-35", toolchain="vivado"): + device = { + "a7-35": "xc7a35tfgg484-2", + "a7-100": "xc7a100tfgg484-2", + "a7-200": "xc7a200tfbg484-2" + }[variant] + Xilinx7SeriesPlatform.__init__(self, device, _io, _connectors, toolchain=toolchain) + 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"] + self.add_platform_command("set_property INTERNAL_VREF 0.675 [get_iobanks 34]") + + def create_programmer(self): + # bscan_spi = ( + # "bscan_spi_xc7a100t.bit" if "xc7a100t" in self.device + # else "bscan_spi_xc7a200t.bit" if "xc7a200t" in self.device + # else "bscan_spi_xc7a35t.bit" + # ) + return VivadoProgrammer(flash_part="mt25ql128-spi-x1_x2_x4") + + def do_finalize(self, fragment): + Xilinx7SeriesPlatform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request("clk50", loose=True), 1e9/50e6) diff --git a/litex_boards/targets/embedfire_rise_pro.py b/litex_boards/targets/embedfire_rise_pro.py new file mode 100755 index 000000000..bd2a8417a --- /dev/null +++ b/litex_boards/targets/embedfire_rise_pro.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2024 Yu-Ti Kuo +# SPDX-License-Identifier: BSD-2-Clause +# embedfire rise pro FPGA: https://detail.tmall.com/item.htm?id=645153441975 + +from migen import * + +from litex.gen import * + +from litex_boards.platforms import embedfire_rise_pro + +from litex.soc.cores.clock import * +from litex.soc.integration.soc import SoCRegion +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * +from litex.soc.cores.led import LedChaser +from litex.soc.cores.gpio import GPIOIn +from litex.soc.cores.xadc import XADC +from litex.soc.cores.dna import DNA +from litex.soc.cores.pwm import PWM + +from litedram.modules import MT41K256M16 +from litedram.phy import s7ddrphy + +from liteeth.phy.mii import LiteEthPHYMII + +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(LiteXModule): + def __init__(self, platform, sys_clk_freq, with_dram=True, with_rst=True): + self.rst = Signal() + self.cd_sys = ClockDomain() + if with_dram: + self.cd_sys4x = ClockDomain() + self.cd_sys4x_dqs = ClockDomain() + self.cd_idelay = ClockDomain() + + # # # + + # Clk/Rst. + clk50 = platform.request("clk50") + rst = ~platform.request("cpu_reset") if with_rst else 0 + + # PLL. + self.pll = pll = S7PLL(speedgrade=-1) + self.comb += pll.reset.eq(rst | self.rst) + pll.register_clkin(clk50, 50e6) + 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. + if with_dram: + pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq) + pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90) + pll.create_clkout(self.cd_idelay, 200e6) + + # IdelayCtrl. + if with_dram: + self.idelayctrl = S7IDELAYCTRL(self.cd_idelay) + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCCore): + def __init__(self, variant="a7-35", toolchain="vivado", sys_clk_freq=50e6, + with_xadc = False, + with_dna = False, + with_ethernet = False, + with_etherbone = False, + eth_ip = "192.168.1.50", + remote_ip = None, + eth_dynamic_ip = False, + with_led_chaser = True, + with_buttons = False, + with_beeper = True, + **kwargs): + platform = embedfire_rise_pro.Platform(variant=variant, toolchain=toolchain) + + # CRG -------------------------------------------------------------------------------------- + with_dram = (kwargs.get("integrated_main_ram_size", 0) == 0) + self.crg = _CRG(platform, sys_clk_freq, with_dram) + + # SoCCore ---------------------------------------------------------------------------------- + SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on embedfire", **kwargs) + + # XADC ------------------------------------------------------------------------------------- + if with_xadc: + self.xadc = XADC() + + # DNA -------------------------------------------------------------------------------------- + if with_dna: + self.dna = DNA() + self.dna.add_timing_constraints(platform, sys_clk_freq, self.crg.cd_sys.clk) + + # DDR3 SDRAM ------------------------------------------------------------------------------- + if not self.integrated_main_ram_size: + self.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"), + memtype = "DDR3", + nphases = 4, + sys_clk_freq = sys_clk_freq) + self.add_sdram("sdram", + phy = self.ddrphy, + module = MT41K256M16(sys_clk_freq, "1:4"), + l2_cache_size = kwargs.get("l2_size", 8192) + ) + + # Ethernet / Etherbone --------------------------------------------------------------------- + if with_ethernet or with_etherbone: + self.ethphy = LiteEthPHYMII( + clock_pads = self.platform.request("eth_clocks"), + pads = self.platform.request("eth")) + if with_etherbone: + self.add_etherbone(phy=self.ethphy, ip_address=eth_ip, with_ethmac=with_ethernet) + elif with_ethernet: + self.add_ethernet(phy=self.ethphy, dynamic_ip=eth_dynamic_ip, local_ip=eth_ip, remote_ip=remote_ip) + + # Leds ------------------------------------------------------------------------------------- + if with_led_chaser: + self.leds = LedChaser( + pads = platform.request_all("user_led"), + sys_clk_freq = sys_clk_freq, + ) + self.leds.add_pwm() + + # Buttons ---------------------------------------------------------------------------------- + if with_buttons: + self.buttons = GPIOIn( + pads = platform.request_all("user_btn"), + with_irq = self.irq.enabled + ) + + # Beeper------------------------------------------------------------------------------------ + self.beeper = PWM( + pwm=platform.request("beeper", 0), + with_csr = True, + default_enable = False, + default_width = 0x800, + default_period = 0xfff, + ) + + self.fan_pwm = PWM( + pwm=platform.request("fan", 0), + with_csr = True, + default_enable = False, + default_width = 0x800, + default_period = 0xfff, + ) + +# Build -------------------------------------------------------------------------------------------- + +def main(): + from litex.build.parser import LiteXArgumentParser + parser = LiteXArgumentParser(platform=embedfire_rise_pro.Platform, description="LiteX SoC on embedfire rise pro.") + parser.add_target_argument("--flash", action="store_true", help="Flash bitstream.") + parser.add_target_argument("--variant", default="a7-35", help="Board variant (a7-35 or a7-100 or a7-200).") + parser.add_target_argument("--sys-clk-freq", default=50e6, type=float, help="System clock frequency.") + parser.add_target_argument("--with-xadc", action="store_true", help="Enable 7-Series XADC.") + parser.add_target_argument("--with-dna", action="store_true", help="Enable 7-Series DNA.") + # parser.add_target_argument("--with-usb", action="store_true", help="Enable USB Host.") + parser.add_target_argument("--with-ethernet", action="store_true", help="Enable Ethernet support.") + parser.add_target_argument("--with-etherbone", action="store_true", help="Enable Etherbone support.") + parser.add_target_argument("--eth-ip", default="192.168.1.50", help="Ethernet/Etherbone IP address.") + parser.add_target_argument("--remote-ip", default="192.168.1.100", help="Remote IP address of TFTP server.") + parser.add_target_argument("--eth-dynamic-ip", action="store_true", help="Enable dynamic Ethernet IP addresses setting.") + sdopts = parser.target_group.add_mutually_exclusive_group() + sdopts.add_argument("--with-spi-sdcard", action="store_true", help="Enable SPI-mode SDCard support.") + sdopts.add_argument("--with-sdcard", action="store_true", help="Enable SDCard support.") + # parser.add_target_argument("--sdcard-adapter", help="SDCard PMOD adapter (digilent or numato).") + # parser.add_target_argument("--with-spi-flash", action="store_true", help="Enable SPI Flash (MMAPed).") + # parser.add_target_argument("--with-pmod-gpio", action="store_true", help="Enable GPIOs through PMOD.") # FIXME: Temporary test. + # parser.add_target_argument("--with-can", action="store_true", help="Enable CAN support (Through CTU-CAN-FD Core and SN65HVD230 'PMOD'.") + args = parser.parse_args() + + assert not (args.with_etherbone and args.eth_dynamic_ip) + + soc = BaseSoC( + variant = args.variant, + toolchain = args.toolchain, + sys_clk_freq = args.sys_clk_freq, + with_xadc = args.with_xadc, + with_dna = args.with_dna, + with_ethernet = args.with_ethernet, + with_etherbone = args.with_etherbone, + eth_ip = args.eth_ip, + remote_ip = args.remote_ip, + eth_dynamic_ip = args.eth_dynamic_ip, + # with_usb = args.with_usb, + # with_spi_flash = args.with_spi_flash, + # with_pmod_gpio = args.with_pmod_gpio, + # with_can = args.with_can, + **parser.soc_argdict + ) + + # if args.sdcard_adapter == "numato": + # soc.platform.add_extension(embedfire_rise_pro._numato_sdcard_pmod_io) + # else: + # soc.platform.add_extension(embedfire_rise_pro._sdcard_pmod_io) + if args.with_spi_sdcard: + soc.add_spi_sdcard() + if args.with_sdcard: + soc.add_sdcard() + + builder = Builder(soc, **parser.builder_argdict) + if args.build: + builder.build(**parser.toolchain_argdict) + + 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()