From f01e0c02c97c5835f68215c05d1272ef9a0bda6b Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Sat, 15 May 2021 13:16:29 +0700 Subject: [PATCH] qmtech ep4ce15: Add daughterboard support, add spiflash --- litex_boards/platforms/qmtech_ep4ce15.py | 131 +++++++++++++++++------ litex_boards/targets/qmtech_ep4ce15.py | 82 ++++++++++++-- 2 files changed, 174 insertions(+), 39 deletions(-) diff --git a/litex_boards/platforms/qmtech_ep4ce15.py b/litex_boards/platforms/qmtech_ep4ce15.py index 33ac6c3..36d0c38 100644 --- a/litex_boards/platforms/qmtech_ep4ce15.py +++ b/litex_boards/platforms/qmtech_ep4ce15.py @@ -2,6 +2,7 @@ # This file is part of LiteX-Boards. # # Copyright (c) 2020 Basel Sayeh +# Copyright (c) 2021 Hans Baier # SPDX-License-Identifier: BSD-2-Clause from litex.build.generic_platform import * @@ -14,18 +15,25 @@ _io = [ # Clk ("clk50", 0, Pins("T2"), IOStandard("3.3-V LVTTL")), - # Leds - ("user_led", 0, Pins("E4"), IOStandard("3.3-V LVTTL")), - # Button - ("key", 0, Pins("Y13"), IOStandard("3.3-V LVTTL")), + ("key", 0, Pins("Y13"), IOStandard("3.3-V LVTTL")), ("key", 1, Pins("W13"), IOStandard("3.3-V LVTTL")), # Serial ("serial", 0, # Compatible with cheap FT232 based cables (ex: Gaoominy 6Pin Ftdi Ft232Rl Ft232) - Subsignal("tx", Pins("AA13"), IOStandard("3.3-V LVTTL")), # GPIO_07 (JP1 Pin 10) - Subsignal("rx", Pins("AA14"), IOStandard("3.3-V LVTTL")) # GPIO_05 (JP1 Pin 8) + Subsignal("tx", Pins("J3:7"), IOStandard("3.3-V LVTTL")), # GPIO_07 (JP1 Pin 10) + Subsignal("rx", Pins("J3:8"), IOStandard("3.3-V LVTTL")) # GPIO_05 (JP1 Pin 8) + ), + + # SPIFlash (W25Q64) + ("spiflash", 0, + # clk + Subsignal("cs_n", Pins("E2")), + Subsignal("clk", Pins("K2")), + Subsignal("mosi", Pins("D1")), + Subsignal("miso", Pins("E2")), + IOStandard("3.3-V LVTTL"), ), # SDR SDRAM @@ -46,30 +54,74 @@ _io = [ Subsignal("dm", Pins("AA5 W7")), IOStandard("3.3-V LVTTL") ), +] - # GPIOs - #ignore for now - #("gpio_0", 0, Pins( - # "D3 C3 A2 A3 B3 B4 A4 B5", - # "A5 D5 B6 A6 B7 D6 A7 C6", - # "C8 E6 E7 D8 E8 F8 F9 E9", - # "C9 D9 E11 E10 C11 B11 A12 D11", - # "D12 B12"), - # IOStandard("3.3-V LVTTL") - #), - #("gpio_1", 0, Pins( - # "F13 T15 T14 T13 R13 T12 R12 T11", - # "T10 R11 P11 R10 N12 P9 N9 N11", - # "L16 K16 R16 L15 P15 P16 R14 N16", - # "N15 P14 L14 N14 M10 L13 J16 K15", - # "J13 J14"), - # IOStandard("3.3-V LVTTL") - #), - #("gpio_2", 0, Pins( - # "A14 B16 C14 C16 C15 D16 D15 D14", - # "F15 F16 F14 G16 G15"), - # IOStandard("3.3-V LVTTL") - #), +# The connectors are named after the daughterboard, not the core board +# because on the different core boards the names vary, but on the +# daughterboard they stay the same, which we need to connect the +# daughterboard peripherals to the core board. +# On this board J2 is U7 and J3 is U8 +_connectors = [ + ("J2", { + # odd row even row + 7: "R1", 8: "R2", + 9: "P1", 10: "P2", + 11: "N1", 12: "N2", + 13: "M1", 14: "M2", + 15: "J1", 16: "J2", + 17: "H1", 18: "H2", + 19: "F1", 20: "F2", + 21: "E1", 22: "D2", + 23: "C1", 24: "C2", + 25: "B1", 26: "B2", + 27: "B3", 28: "A3", + 29: "B4", 30: "A4", + 31: "C4", 32: "C3", + 33: "B5", 34: "A5", + 35: "B6", 36: "A6", + 37: "B7", 38: "A7", + 39: "B8", 40: "A8", + 41: "B9", 42: "A9", + 43: "B10", 44: "A10", + 45: "B13", 46: "A13", + 47: "B14", 48: "A14", + 49: "B15", 50: "A15", + 51: "B16", 52: "A16", + 53: "B17", 54: "A17", + 55: "B18", 56: "A18", + 57: "B19", 58: "A19", + 59: "B20", 60: "A20", + }), + ("J3", { + # odd row even row + 7: "AA13", 8: "AB13", + 9: "AA14", 10: "AB14", + 11: "AA15", 12: "AB15", + 13: "AA16", 14: "AB16", + 15: "AA17", 16: "AB17", + 17: "AA18", 18: "AB18", + 19: "AA19", 20: "AB19", + 21: "AA20", 22: "AB20", + 23: "Y22", 24: "Y21", + 25: "W22", 26: "W21", + 27: "V22", 28: "V21", + 29: "U22", 30: "U21", + 31: "R22", 32: "R21", + 33: "P22", 34: "P21", + 35: "N22", 36: "N21", + 37: "M22", 38: "M21", + 39: "L22", 40: "L21", + 41: "K22", 42: "K21", + 43: "J22", 44: "J21", + 45: "H22", 46: "H21", + 47: "F22", 48: "F21", + 49: "E22", 50: "E21", + 51: "D22", 52: "D21", + 53: "C22", 54: "C21", + 55: "B22", 56: "B21", + 57: "N20", 58: "N19", + 59: "M20", 60: "M19", + }) ] # Platform ----------------------------------------------------------------------------------------- @@ -77,9 +129,26 @@ _io = [ class Platform(AlteraPlatform): default_clk_name = "clk50" default_clk_period = 1e9/50e6 + core_resources = [ ("user_led", 0, Pins("E4"), IOStandard("3.3-V LVTTL")) ] - def __init__(self): - AlteraPlatform.__init__(self, "EP4CE15F23C8", _io) + def __init__(self, with_daughterboard=False): + device = "EP4CE15F23C8" + io = _io + connectors = _connectors + + if with_daughterboard: + from litex_boards.platforms.qmtech_daughterboard import QMTechDaughterboard + daughterboard = QMTechDaughterboard(IOStandard("3.3-V LVTTL")) + io += daughterboard.io + connectors += daughterboard.connectors + else: + io += self.core_resources + + AlteraPlatform.__init__(self, device, io, connectors) + + if with_daughterboard: + # an ethernet pin takes K22, so make it available + self.add_platform_command("set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION \"USE AS REGULAR IO\"") def create_programmer(self): return USBBlaster() diff --git a/litex_boards/targets/qmtech_ep4ce15.py b/litex_boards/targets/qmtech_ep4ce15.py index 15c2308..994461b 100755 --- a/litex_boards/targets/qmtech_ep4ce15.py +++ b/litex_boards/targets/qmtech_ep4ce15.py @@ -24,10 +24,13 @@ from litex.soc.cores.led import LedChaser from litedram.modules import IS42S16160 from litedram.phy import GENSDRPHY, HalfRateGENSDRPHY +from litex.soc.cores.video import VideoVGAPHY +from liteeth.phy.mii import LiteEthPHYMII + # CRG ---------------------------------------------------------------------------------------------- class _CRG(Module): - def __init__(self, platform, sys_clk_freq, sdram_rate="1:1"): + def __init__(self, platform, sys_clk_freq, with_ethernet, with_vga, sdram_rate="1:1"): self.rst = Signal() self.clock_domains.cd_sys = ClockDomain() if sdram_rate == "1:2": @@ -36,6 +39,11 @@ class _CRG(Module): else: self.clock_domains.cd_sys_ps = ClockDomain(reset_less=True) + if with_ethernet: + self.clock_domains.cd_eth = ClockDomain() + if with_vga: + self.clock_domains.cd_vga = ClockDomain(reset_less=True) + # # # # Clk / Rst @@ -48,10 +56,16 @@ class _CRG(Module): pll.create_clkout(self.cd_sys, sys_clk_freq) if sdram_rate == "1:2": pll.create_clkout(self.cd_sys2x, 2*sys_clk_freq) - pll.create_clkout(self.cd_sys2x_ps, 2*sys_clk_freq, phase=180) # Idealy 90° but needs to be increased. + # theoretically 90 degrees, but increase to relax timing + pll.create_clkout(self.cd_sys2x_ps, 2*sys_clk_freq, phase=180) else: pll.create_clkout(self.cd_sys_ps, sys_clk_freq, phase=90) + if with_ethernet: + pll.create_clkout(self.cd_eth, 25e6) + if with_vga: + pll.create_clkout(self.cd_vga, 40e6) + # SDRAM clock sdram_clk = ClockSignal("sys2x_ps" if sdram_rate == "1:2" else "sys_ps") self.specials += DDROutput(1, 0, platform.request("sdram_clock"), sdram_clk) @@ -59,17 +73,23 @@ class _CRG(Module): # BaseSoC ------------------------------------------------------------------------------------------ class BaseSoC(SoCCore): - def __init__(self, sys_clk_freq=int(50e6), sdram_rate="1:1", **kwargs): - platform = qmtech_ep4ce15.Platform() + def __init__(self, sys_clk_freq=int(50e6), with_daughterboard=False, + with_ethernet=False, with_etherbone=False, eth_ip="192.168.1.50", eth_dynamic_ip=False, + with_video_terminal=False, with_video_framebuffer=False, + ident_version=True, sdram_rate="1:1", **kwargs): + platform = qmtech_ep4ce15.Platform(with_daughterboard=with_daughterboard) # SoCCore ---------------------------------------------------------------------------------- SoCCore.__init__(self, platform, sys_clk_freq, - ident = "LiteX SoC on QMTECH EP4CE15", - ident_version = True, + ident = "LiteX SoC on QMTECH EP4CE15" + (" + Daughterboard" if with_daughterboard else ""), + ident_version = ident_version, **kwargs) # CRG -------------------------------------------------------------------------------------- - self.submodules.crg = _CRG(platform, sys_clk_freq, sdram_rate=sdram_rate) + self.submodules.crg = _CRG(platform, + sys_clk_freq, with_ethernet or with_etherbone, + with_video_terminal or with_video_framebuffer, + sdram_rate=sdram_rate) # SDR SDRAM -------------------------------------------------------------------------------- if not self.integrated_main_ram_size: @@ -81,6 +101,24 @@ class BaseSoC(SoCCore): l2_cache_size = kwargs.get("l2_size", 8192) ) + # Ethernet / Etherbone --------------------------------------------------------------------- + if with_ethernet or with_etherbone: + self.submodules.ethphy = LiteEthPHYMII( + clock_pads = self.platform.request("eth_clocks"), + pads = self.platform.request("eth")) + if with_ethernet: + self.add_ethernet(phy=self.ethphy, dynamic_ip=eth_dynamic_ip) + if with_etherbone: + self.add_etherbone(phy=self.ethphy, ip_address=eth_ip) + + # Video ------------------------------------------------------------------------------------ + if with_video_terminal or with_video_framebuffer: + self.submodules.videophy = VideoVGAPHY(platform.request("vga"), clock_domain="vga") + if with_video_terminal: + self.add_video_terminal(phy=self.videophy, timings="800x600@60Hz", clock_domain="vga") + if with_video_framebuffer: + self.add_video_framebuffer(phy=self.videophy, timings="800x600@60Hz", clock_domain="vga") + # Leds ------------------------------------------------------------------------------------- self.submodules.leds = LedChaser( pads = platform.request_all("user_led"), @@ -94,15 +132,43 @@ def main(): parser.add_argument("--load", action="store_true", help="Load bitstream") parser.add_argument("--sys-clk-freq", default=50e6, help="System clock frequency (default: 50MHz)") parser.add_argument("--sdram-rate", default="1:1", help="SDRAM Rate: 1:1 Full Rate (default) or 1:2 Half Rate") + parser.add_argument("--with-daughterboard", action="store_true", help="Whether the core board is plugged into the QMTech daughterboard") + ethopts = parser.add_mutually_exclusive_group() + ethopts.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support") + ethopts.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support") + parser.add_argument("--eth-ip", default="192.168.1.50", type=str, help="Ethernet/Etherbone IP address") + parser.add_argument("--eth-dynamic-ip", action="store_true", help="Enable dynamic Ethernet IP addresses setting") + sdopts = parser.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_argument("--no-ident-version", action="store_false", help="Disable build time output") + viopts = parser.add_mutually_exclusive_group() + viopts.add_argument("--with-video-terminal", action="store_true", help="Enable Video Terminal (VGA)") + viopts.add_argument("--with-video-framebuffer", action="store_true", help="Enable Video Framebuffer (VGA)") + builder_args(parser) soc_core_args(parser) args = parser.parse_args() soc = BaseSoC( sys_clk_freq = int(float(args.sys_clk_freq)), - sdram_rate = args.sdram_rate, + with_daughterboard = args.with_daughterboard, + with_ethernet = args.with_ethernet, + with_etherbone = args.with_etherbone, + eth_ip = args.eth_ip, + eth_dynamic_ip = args.eth_dynamic_ip, + ident_version = args.no_ident_version, + with_video_terminal = args.with_video_terminal, + with_video_framebuffer = args.with_video_framebuffer, + sdram_rate = args.sdram_rate, **soc_core_argdict(args) ) + + if args.with_spi_sdcard: + soc.add_spi_sdcard() + if args.with_sdcard: + soc.add_sdcard() + builder = Builder(soc, **builder_argdict(args)) builder.build(run=args.build)