From b3f175c064a724c9dd08b377fd7ef427ebdf1200 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Mon, 6 Jan 2020 00:46:13 +0100 Subject: [PATCH] add the Hackaday Supercon ECP5 badge Add the Hackaday Supercon 2019 badge which has an ECP5 FPGA: https://hackaday.io/project/167255-2019-hackaday-superconference-badge These changes are from Michael Welling's fork: https://github.com/mwelling/linux-on-litex-vexriscv During Supercon, we trying two approaches: - use the built-in 16MB QSPI SRAM - use add-on cartiridge with 32MB SDRAM by Jacob Creedon We were not able to get the QSPI SRAM working so I've removed those changes, and I have just added the changes that are needed to boot Linux with the 32MB SDRAM. Thanks to Jacob Creedon, Greg Davill and Tim Ansell who helped debug. KiCad design files for the SDRAM cartridge are available at: https://github.com/jcreedon/dram-cart/ The SDRAM cartridge PCB is shared at: https://oshpark.com/shared_projects/IQSl2lid More information in this blog post: https://blog.oshpark.com/2019/12/20/ The Hackaday Supercon badge PCB design is here: https://github.com/Spritetm/hadbadge2019_pcb --- litex_boards/partner/platforms/hadbadge.py | 215 ++++++++++++++++++ litex_boards/partner/targets/hadbadge.py | 246 +++++++++++++++++++++ 2 files changed, 461 insertions(+) create mode 100644 litex_boards/partner/platforms/hadbadge.py create mode 100755 litex_boards/partner/targets/hadbadge.py diff --git a/litex_boards/partner/platforms/hadbadge.py b/litex_boards/partner/platforms/hadbadge.py new file mode 100644 index 0000000..800e7e6 --- /dev/null +++ b/litex_boards/partner/platforms/hadbadge.py @@ -0,0 +1,215 @@ +from litex.build.generic_platform import * +from litex.build.lattice import LatticePlatform + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + ("clk8", 0, Pins("U18"), IOStandard("LVCMOS33")), + ("programn", 0, Pins("R1"), IOStandard("LVCMOS33")), + ("serial", 0, + Subsignal("rx", Pins("U2"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")), + Subsignal("tx", Pins("U1"), IOStandard("LVCMOS33")), + ), + ("led", 0, Pins("E3 D3 C3 C4 C2 B1 B20 B19 A18 K20 K19"), IOStandard("LVCMOS33")), # Anodes + ("led", 1, Pins("P19 L18 K18"), IOStandard("LVCMOS33")), # Cathodes via FET + ("usb", 0, + Subsignal("d_p", Pins("F3")), + Subsignal("d_n", Pins("G3")), + Subsignal("pullup", Pins("E4")), + Subsignal("vbusdet", Pins("F4")), + IOStandard("LVCMOS33") + ), + ("keypad", 0, + Subsignal("left", Pins("G2"), Misc("PULLMODE=UP")), + Subsignal("right", Pins("F2"), Misc("PULLMODE=UP")), + Subsignal("up", Pins("F1"), Misc("PULLMODE=UP")), + Subsignal("down", Pins("C1"), Misc("PULLMODE=UP")), + Subsignal("start", Pins("E1"), Misc("PULLMODE=UP")), + Subsignal("select", Pins("D2"), Misc("PULLMODE=UP")), + Subsignal("a", Pins("D1"), Misc("PULLMODE=UP")), + Subsignal("b", Pins("E2"), Misc("PULLMODE=UP")), + ), + ("hdmi_out", 0, + Subsignal("clk_p", Pins("P20"), Inverted(), IOStandard("TMDS_33")), + Subsignal("clk_n", Pins("R20"), Inverted(), IOStandard("TMDS_33")), + Subsignal("data0_p", Pins("N19"), IOStandard("TMDS_33")), + Subsignal("data0_n", Pins("N20"), IOStandard("TMDS_33")), + Subsignal("data1_p", Pins("L20"), IOStandard("TMDS_33")), + Subsignal("data1_n", Pins("M20"), IOStandard("TMDS_33")), + Subsignal("data2_p", Pins("L16"), IOStandard("TMDS_33")), + Subsignal("data2_n", Pins("L17"), IOStandard("TMDS_33")), + Subsignal("hpd_notif", Pins("R18"), IOStandard("LVCMOS33"), Inverted()), # Also called HDMI_HEAC_n + Subsignal("hdmi_heac_p", Pins("T19"), IOStandard("LVCMOS33"), Inverted()), + Misc("DRIVE=4"), + ), + ("lcd", 0, + Subsignal("db", Pins("J3 H1 K4 J1 K3 K2 L4 K1 L3 L2 M4 L1 M3 M1 N4 N2 N3 N1"), IOStandard("LVCMOS33")), + Subsignal("rd", Pins("P2"), IOStandard("LVCMOS33")), + Subsignal("wr", Pins("P4"), IOStandard("LVCMOS33")), + Subsignal("rs", Pins("P1"), IOStandard("LVCMOS33")), + Subsignal("cs", Pins("P3"), IOStandard("LVCMOS33")), + Subsignal("id", Pins("J4"), IOStandard("LVCMOS33")), + Subsignal("rst", Pins("H2"), IOStandard("LVCMOS33")), + Subsignal("fmark", Pins("G1"), IOStandard("LVCMOS33")), + Subsignal("blen", Pins("P5"), IOStandard("LVCMOS33")), + ), + ("spiflash", 0, # clock needs to be accessed through USRMCLK + Subsignal("cs_n", Pins("R2"), IOStandard("LVCMOS33")), + Subsignal("mosi", Pins("W2"), IOStandard("LVCMOS33")), + Subsignal("miso", Pins("V2"), IOStandard("LVCMOS33")), + Subsignal("wp", Pins("Y2"), IOStandard("LVCMOS33")), + Subsignal("hold", Pins("W1"), IOStandard("LVCMOS33")), + ), + ("spiflash4x", 0, # clock needs to be accessed through USRMCLK + Subsignal("cs_n", Pins("R2"), IOStandard("LVCMOS33")), + Subsignal("dq", Pins("W2 V2 Y2 W1"), IOStandard("LVCMOS33")), + ), + ("spiram4x", 0, + Subsignal("cs_n", Pins("D20"), IOStandard("LVCMOS33"), Misc("SLEWRATE=SLOW")), + Subsignal("clk", Pins("E20"), IOStandard("LVCMOS33"), Misc("SLEWRATE=SLOW")), + Subsignal("dq", Pins("E19 D19 C20 F19"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP"), Misc("SLEWRATE=SLOW")), + ), + ("spiram4x", 1, + Subsignal("cs_n", Pins("F20"), IOStandard("LVCMOS33"), Misc("SLEWRATE=SLOW")), + Subsignal("clk", Pins("J19"), IOStandard("LVCMOS33"), Misc("SLEWRATE=SLOW")), + Subsignal("dq", Pins("J20 G19 G20 H20"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP"), Misc("SLEWRATE=SLOW")), + ), + ("sao", 0, + Subsignal("sda", Pins("B3")), + Subsignal("scl", Pins("B2")), + Subsignal("gpio", Pins("A2 A3 B4")), + Subsignal("drm", Pins("A4")), + ), + ("sao", 1, + Subsignal("sda", Pins("A16")), + Subsignal("scl", Pins("B17")), + Subsignal("gpio", Pins("B18 A17 B16")), + Subsignal("drm", Pins("C17")), + ), + ("testpts", 0, + Subsignal("a1", Pins("A15")), + Subsignal("a2", Pins("C16")), + Subsignal("a3", Pins("A14")), + Subsignal("a4", Pins("D16")), + Subsignal("b1", Pins("B15")), + Subsignal("b2", Pins("C15")), + Subsignal("b3", Pins("A13")), + Subsignal("b4", Pins("B13")), + ), +# rev a +# ("sdram_clock", 0, Pins("C11"), IOStandard("LVCMOS33")), +# ("sdram", 0, +# Subsignal("a", Pins("D10 C10 B10 A10 C14 E17 A12 B12 H17 G18 A9 A11 A7")), +# Subsignal("dq", Pins("C5 A5 B6 D6 B5 C6 A6 C7")), +# Subsignal("we_n", Pins("C8")), +# Subsignal("ras_n", Pins("A8")), +# Subsignal("cas_n", Pins("B8")), +# Subsignal("cs_n", Pins("D9")), +# Subsignal("cke", Pins("B11")), +# Subsignal("ba", Pins("C9 B9")), +# Subsignal("dm", Pins("D11")), +# IOStandard("LVCMOS33"), Misc("SLEWRATE=FAST") +# ), +# rev b + ("sdram_clock", 0, Pins("D11"), IOStandard("LVCMOS33")), + ("sdram", 0, + Subsignal("a", Pins("A8 D9 C9 B9 C14 E17 A12 B12 H17 G18 B8 A11 B11")), + Subsignal("dq", Pins("C5 B5 A5 C6 B10 C10 D10 A9")), + Subsignal("we_n", Pins("B6")), + Subsignal("ras_n", Pins("D6")), + Subsignal("cas_n", Pins("A6")), + Subsignal("cs_n", Pins("C7")), + Subsignal("cke", Pins("C11")), + Subsignal("ba", Pins("A7 C8")), + Subsignal("dm", Pins("A10")), + IOStandard("LVCMOS33"), Misc("SLEWRATE=FAST") + ), + + # Only used for simulation + ("wishbone", 0, + Subsignal("adr", Pins(30)), + Subsignal("dat_r", Pins(32)), + Subsignal("dat_w", Pins(32)), + Subsignal("sel", Pins(4)), + Subsignal("cyc", Pins(1)), + Subsignal("stb", Pins(1)), + Subsignal("ack", Pins(1)), + Subsignal("we", Pins(1)), + Subsignal("cti", Pins(3)), + Subsignal("bte", Pins(2)), + Subsignal("err", Pins(1)) + ), + ("reset", 0, Pins(1), IOStandard("LVCMOS33")), +] + +_connectors = [ + ("pmod", "A15 C16 A14 D16 B15 C15 A13 B13"), + ("genio", "C5 B5 A5 C6 B6 A6 D6 C7 A7 C8 B8 A8 D9 C9 B9 A9 D10 C10 B10 A10 D11 C11 B11 A11 G18 H17 B12 A12 E17 C14"), +] + +_pmod_gpio = [ + ("pmod_gpio", 0, + Subsignal("p0", Pins("pmod:0")), + Subsignal("p1", Pins("pmod:1")), + Subsignal("p2", Pins("pmod:2")), + Subsignal("p3", Pins("pmod:3")), + Subsignal("p4", Pins("pmod:4")), + Subsignal("p5", Pins("pmod:5")), + Subsignal("p6", Pins("pmod:6")), + Subsignal("p7", Pins("pmod:7")), + IOStandard("LVCMOS33") + ), +] + +_genio_gpio = [ + ("genio_gpio", 0, + Subsignal("p0", Pins("genio:0")), + Subsignal("p1", Pins("genio:1")), + Subsignal("p2", Pins("genio:2")), + Subsignal("p3", Pins("genio:3")), + Subsignal("p4", Pins("genio:4")), + Subsignal("p5", Pins("genio:5")), + Subsignal("p6", Pins("genio:6")), + Subsignal("p7", Pins("genio:7")), + Subsignal("p8", Pins("genio:8")), + Subsignal("p9", Pins("genio:9")), + + Subsignal("p10", Pins("genio:10")), + Subsignal("p11", Pins("genio:11")), + Subsignal("p12", Pins("genio:12")), + Subsignal("p13", Pins("genio:13")), + Subsignal("p14", Pins("genio:14")), + Subsignal("p15", Pins("genio:15")), + Subsignal("p16", Pins("genio:16")), + Subsignal("p17", Pins("genio:17")), + Subsignal("p18", Pins("genio:18")), + Subsignal("p19", Pins("genio:19")), + + Subsignal("p20", Pins("genio:20")), + Subsignal("p21", Pins("genio:21")), + Subsignal("p22", Pins("genio:22")), + Subsignal("p23", Pins("genio:23")), + Subsignal("p24", Pins("genio:24")), + Subsignal("p25", Pins("genio:25")), + Subsignal("p26", Pins("genio:26")), + Subsignal("p27", Pins("genio:27")), + Subsignal("p28", Pins("genio:28")), + Subsignal("p29", Pins("genio:29")), + ) +] + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(LatticePlatform): + default_clk_name = "clk8" + default_clk_period = 1e9/8e6 + + def __init__(self, device="LFE5U-45F", **kwargs): + LatticePlatform.__init__(self, device + "-CABGA381", io=_io, connectors=_connectors, toolchain="trellis", **kwargs) + + def create_programmer(self): + raise ValueError("{} programmer is not supported" + .format(self.programmer)) + + def do_finalize(self, fragment): + LatticePlatform.do_finalize(self, fragment) diff --git a/litex_boards/partner/targets/hadbadge.py b/litex_boards/partner/targets/hadbadge.py new file mode 100755 index 0000000..e50829f --- /dev/null +++ b/litex_boards/partner/targets/hadbadge.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python3 + +# This file is Copyright (c) 2018-2019 Florent Kermarrec +# This file is Copyright (c) 2018 David Shah +# License: BSD + +import argparse +import sys + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex_boards.platforms import hadbadge + +from litex.soc.cores.clock import * +from litex.soc.integration.soc_sdram import * +#from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * + +#from .spi_ram_dual import SpiRamDualQuad + +from litedram import modules as litedram_modules +from litedram.phy import GENSDRPHY + +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(Module): + """Clock Resource Generator" + + Input: 8 MHz + Output: 48 MHz + """ + def __init__(self, platform, sys_clk_freq): + self.clock_domains.cd_por = ClockDomain(reset_less=True) + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_clk12 = ClockDomain() + self.clock_domains.cd_clk48 = ClockDomain() + self.clock_domains.cd_sys_ps = ClockDomain(reset_less=True) + + # # # + + self.cd_sys.clk.attr.add("keep") + self.cd_por.clk.attr.add("keep") + self.cd_clk12.clk.attr.add("keep") + self.cd_clk48.clk.attr.add("keep") + self.cd_sys_ps.clk.attr.add("keep") + + self.stop = Signal() + + # clk / rst + clk8 = platform.request("clk8") + # rst_n = platform.request("rst_n") + platform.add_period_constraint(clk8, 1e9/8e6) + platform.add_period_constraint(self.cd_sys.clk, 1e9/48e6) + platform.add_period_constraint(self.cd_clk12.clk, 1e9/12e6) + platform.add_period_constraint(self.cd_clk48.clk, 1e9/48e6) + + # power on reset + por_count = Signal(16, reset=2**16-1) + por_done = Signal() + self.comb += self.cd_por.clk.eq(clk8) + self.comb += por_done.eq(por_count == 0) + self.sync.por += If(~por_done, por_count.eq(por_count - 1)) + + # pll + self.submodules.pll = pll = ECP5PLL() + pll.register_clkin(clk8, 8e6) + pll.create_clkout(self.cd_sys, sys_clk_freq, phase=0, margin=1e-9) + pll.create_clkout(self.cd_clk12, 12e6, phase=39, margin=1e-9) + pll.create_clkout(self.cd_sys_ps, sys_clk_freq, phase=20) + self.comb += self.cd_clk48.clk.eq(self.cd_sys.clk) + # pll.create_clkout(self.cd_sys, 48e6, phase=0, margin=1e-9) + # pll.create_clkout(self.cd_clk12, 12e6, phase=132, margin=1e-9) + + # sdram clock + self.comb += platform.request("sdram_clock").eq(self.cd_sys_ps.clk) + + # Synchronize USB48 and USB12, and drive USB12 from USB48 + self.specials += [ + # Instance("ECLKSYNCB", + # i_ECLKI=self.cd_usb48_i.clk, + # i_STOP=self.stop, + # o_ECLKO=self.cd_usb48.clk), + # Instance("CLKDIVF", + # p_DIV="2.0", + # i_ALIGNWD=0, + # i_CLKI=self.cd_usb48.clk, + # i_RST=self.cd_usb48.rst, + # o_CDIVX=self.cd_usb12.clk), + AsyncResetSynchronizer(self.cd_sys, ~por_done | ~pll.locked),# | ~rst_n), + AsyncResetSynchronizer(self.cd_clk12, ~por_done | ~pll.locked),# | ~rst_n), + # AsyncResetSynchronizer(self.cd_usb48, ~por_done | ~pll.locked),# | ~rst_n) + ] + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCSDRAM): +# SoCCore.csr_map = { +# "ctrl": 0, # provided by default (optional) +# "crg": 1, # user +# "uart_phy": 2, # provided by default (optional) +# "uart": 3, # provided by default (optional) +# "identifier_mem": 4, # provided by default (optional) +# "timer0": 5, # provided by default (optional) +# "picorvspi": 7, +# "lcdif": 8, +# "usb": 9, +# "reboot": 12, +# "rgb": 13, +# "version": 14, +# "lxspi": 15, +# "messible": 16, +# } + + # We must define memory offsets here rather than using the litex + # defaults. This is because the mmu only allows for certain + # regions to be unbuffered: + # https://github.com/m-labs/VexRiscv-verilog/blob/master/src/main/scala/vexriscv/GenCoreDefault.scala#L139-L143 + SoCSDRAM.mem_map = { + "rom": 0x00000000, + "sram": 0x10000000, + "emulator_ram": 0x20000000, + "ethmac": 0x30000000, + "spiflash": 0x50000000, + "main_ram": 0xc0000000, + "csr": 0xe0000000, + } + + def __init__(self, debug=True, sdram_module_cls="AS4C32M8", **kwargs): + platform = hadbadge.Platform() + clk_freq = int(48e6) + SoCSDRAM.__init__(self, platform, clk_freq, + integrated_rom_size=16384, + integrated_sram_size=65536, + wishbone_timeout_cycles=1e9, + **kwargs) + + self.submodules.crg = _CRG(self.platform, sys_clk_freq=clk_freq) + + # Add a "Version" module so we can see what version of the board this is. +# self.submodules.version = Version("proto2", [ +# (0x02, "proto2", "Prototype Version 2 (red)") +# ], 0) + + # Add a "USB" module to let us debug the device. +# usb_pads = platform.request("usb") +# usb_iobuf = usbio.IoBuf(usb_pads.d_p, usb_pads.d_n, usb_pads.pullup) +# self.submodules.usb = ClockDomainsRenamer({ +# "usb_48": "clk48", +# "usb_12": "clk12", +# })(DummyUsb(usb_iobuf, debug=debug, product="Hackaday Supercon Badge", cdc=True)) +# +# if debug: +# self.add_wb_master(self.usb.debug_bridge.wishbone) +# +# if self.cpu_type is not None: +# self.register_mem("vexriscv_debug", 0xb00f0000, self.cpu.debug_bus, 0x200) +# self.cpu.use_external_variant("rtl/VexRiscv_HaD_Debug.v") +# elif self.cpu_type is not None: +# self.cpu.use_external_variant("rtl/VexRiscv_HaD.v") + + # Add the 16 MB SPI flash as XIP memory at address 0x03000000 +# if not is_sim: +# # flash = SpiFlashDualQuad(platform.request("spiflash4x"), dummy=5) +# # flash.add_clk_primitive(self.platform.device) +# # self.submodules.lxspi = flash +# # self.register_mem("spiflash", 0x03000000, self.lxspi.bus, size=16 * 1024 * 1024) +# self.submodules.picorvspi = flash = PicoRVSpi(self.platform, pads=platform.request("spiflash"), size=16 * 1024 * 1024) +# self.register_mem("spiflash", self.mem_map["spiflash"], self.picorvspi.bus, size=self.picorvspi.size) + + # # Add the 16 MB SPI RAM at address 0x40000000 # Value at 40010000: afbfcfef +# reset_cycles = 2**14-1 +# ram = SpiRamDualQuad(platform.request("spiram4x", 0), platform.request("spiram4x", 1), dummy=5, reset_cycles=reset_cycles, qpi=True) +# self.submodules.ram = ram +# self.register_mem("main_ram", self.mem_map["main_ram"], self.ram.bus, size=16 * 1024 * 1024) + self.submodules.sdrphy = GENSDRPHY(platform.request("sdram"), cl=2) + sdram_module = getattr(litedram_modules, sdram_module_cls)(clk_freq, "1:1") + self.register_sdram(self.sdrphy, + sdram_module.geom_settings, + sdram_module.timing_settings) + + # Let us reboot the device +# self.submodules.reboot = Reboot(platform.request("programn")) + + # Add a Messible for sending messages to the host +# self.submodules.messible = Messible() + + # Add an LCD so we can see what's up +# self.submodules.lcdif = LCDIF(platform.request("lcd")) + + # Ensure timing is correctly set up + self.platform.toolchain.build_template[1] += " --speed 8" # Add "speed grade 8" to nextpnr-ecp5 + + # SAO +# self.submodules.sao0 = ShittyAddOn(self.platform, self.platform.request("sao", 0), disable_i2c=kwargs["sao0_disable_i2c"]); +# self.add_csr("sao0") +# self.submodules.sao1 = ShittyAddOn(self.platform, self.platform.request("sao", 1), disable_i2c=kwargs["sao1_disable_i2c"]); +# self.add_csr("sao1") +# # PMOD +# platform.add_extension(_pmod_gpio) +# self.submodules.pmod = GPIOBidirectional(self.platform.request("pmod_gpio")) +# self.add_csr("pmod") +# # GENIO +# platform.add_extension(_genio_gpio) +# self.submodules.genio = GPIOBidirectional(self.platform.request("genio_gpio")) +# self.add_csr("genio") +# # LEDs +# self.submodules.led0 = gpio.GPIOOut(self.platform.request("led", 0)) +# self.add_csr("led0") +# self.submodules.led1 = gpio.GPIOOut(self.platform.request("led", 1)) +# self.add_csr("led1") +# # Keypad +# self.submodules.keypad = gpio.GPIOIn(Cat(self.platform.request("keypad", 0).flatten())) +# self.add_csr("keypad") + + +# Build -------------------------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC on Hackaday Badge") + parser.add_argument("--gateware-toolchain", dest="toolchain", default="trellis", + help='gateware toolchain to use, diamond or trellis (default)') + parser.add_argument("--device", dest="device", default="LFE5U-45F", + help='FPGA device, Hackaday badge is populated with LFE5U-45F') + parser.add_argument("--sys-clk-freq", default=48e6, + help="system clock frequency (default=48MHz)") + parser.add_argument("--sdram-module", default="MT48LC16M16", + help="SDRAM module: MT48LC16M16, AS4C32M16 or AS4C16M16 (default=MT48LC16M16)") + builder_args(parser) + soc_sdram_args(parser) + soc_core_args(parser) + args = parser.parse_args() + +# soc = BaseSoC(device=args.device, +# sys_clk_freq=int(float(args.sys_clk_freq)), +# **soc_core_argdict(args)) + soc = BaseSoC(device=args.device, toolchain=args.toolchain, + sys_clk_freq=int(float(args.sys_clk_freq)), + sdram_module_cls=args.sdram_module, + **soc_sdram_argdict(args)) + + builder = Builder(soc, **builder_argdict(args)) + builder.build() + +if __name__ == "__main__": + main()