From 006e94b2c99b0f87867eb98fc822fe1d2ed6aadf Mon Sep 17 00:00:00 2001 From: Raptor Engineering Development Team Date: Sun, 13 Mar 2022 19:33:24 -0500 Subject: [PATCH] Add initial Tercel SPI controller NOTE: Still needs testing on physical hardware, waiting for Arctic Tern support. --- src/ls2.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/src/ls2.py b/src/ls2.py index bcb4b3b..9ca2e86 100644 --- a/src/ls2.py +++ b/src/ls2.py @@ -1,5 +1,6 @@ # Copyright (c) 2020 LambdaConcept # Copyright (c) 2021 Luke Kenneth Casson Leighton +# Copyright (C) 2022 Raptor Engineering, LLC # # Based on code from LambaConcept, from the gram example which is BSD-2-License # https://github.com/jeanthom/gram/tree/master/examples @@ -22,6 +23,7 @@ from lambdasoc.periph.timer import TimerPeripheral from lambdasoc.periph import Peripheral from lambdasoc.soc.base import SoC from soc.bus.uart_16550 import UART16550 # opencores 16550 uart +from soc.bus.tercel import Tercel # SPI XIP master from soc.bus.external_core import ExternalCore # external libresoc/microwatt from soc.bus.wb_downconvert import WishboneDownConvert from soc.bus.syscon import MicrowattSYSCON @@ -219,10 +221,11 @@ class DDR3SoC(SoC, Elaboratable): def __init__(self, *, fpga, dram_cls, - uart_pins, ddr_pins, + uart_pins, spi_0_pins, ddr_pins, ddrphy_addr, dramcore_addr, ddr_addr, fw_addr=0x0000_0000, firmware=None, + spi0_addr, spi0_cfg_addr, clk_freq=50e6, add_cpu=True): @@ -239,9 +242,9 @@ class DDR3SoC(SoC, Elaboratable): # | # arbiter # | - # +---decoder----+--------+ - # | | | | - # uart XICS CSRs DRAM + # +---decoder----+--------+---------+ + # | | | | | + # uart XICS CSRs DRAM XIP SPI # set up wishbone bus arbiter and decoder. arbiter routes, # decoder maps local-relative addressed satellites to global addresses @@ -366,6 +369,27 @@ class DDR3SoC(SoC, Elaboratable): self.drambone = drs(drambone) self._decoder.add(self.drambone.bus, addr=ddr_addr) + # SPI controller + if spi_0_pins is not None or fpga == 'sim': + # The Lattice ECP5 devices require special handling on the dedicated SPI clock line, + # which is shared with the internal SPI controller used for FPGA bitstream loading. + spi0_is_lattice_ecp5_clk = False + if platform is not None and fpga in ['versa_ecp5', 'rcs_arctic_tern_bmc_card', 'isim']: + spi0_is_lattice_ecp5_clk = True + + # Tercel contains two independent Wishbone regions, a configuration + # region and the direct API access region, + # Set the SPI 0 access region to 16MB, as the FPGA bitstream Flash device + # is unlikely to be larger than this. + # The main SPI Flash (SPI 1) should be set to at least 28 bits (256MB) to + # allow the use of large 4BA devices. + self.spi0 = Tercel(data_width=32, spi_region_addr_width=24, + clk_freq=clk_freq, + pins=spi_0_pins, + lattice_ecp5_usrmclk=spi0_is_lattice_ecp5_clk) + self._decoder.add(self.spi0.bus, addr=spi0_addr) + self._decoder.add(self.spi0.cfg_bus, addr=spi0_cfg_addr) + self.memory_map = self._decoder.bus.memory_map self.clk_freq = clk_freq @@ -447,6 +471,16 @@ class DDR3SoC(SoC, Elaboratable): print (fname) self.uart.add_verilog_source(fname, platform) + # add Tercel verilog source. assumes a directory + # structure where ls2 has been checked out in a common + # subdirectory as https://git.libre-soc.org/git/microwatt.git + raptor_tercel = "../../microwatt/tercel" + pth = os.path.split(__file__)[0] + pth = os.path.join(pth, raptor_tercel) + fname = os.path.abspath(pth) + print (fname) + self.spi0.add_verilog_source(fname, platform) + # add the main core pth = os.path.split(__file__)[0] pth = os.path.join(pth, '../external_core_top.v') @@ -536,16 +570,31 @@ if __name__ == "__main__": "odt":4, "ras":4, "cas":4, "we":4, "cs": 4}) + # Get SPI resource pins + if platform is not None: + if toolchain == 'Trellis': + # The ECP5 series FPGAs handle the SPI clock directly on the FPGA configuration Flash device + spi_0_pins = platform.request("spi_0", 0, + dir={"dq":"io", "cs_n":"o"}, + xdr={"dq": 1, "cs_n": 1}) + else: + spi_0_pins = platform.request("spi_0", 0, + dir={"dq":"io", "cs_n":"o", "clk":"o"}, + xdr={"dq": 1, "cs_n": 1, "clk": 0}) + # set up the SOC soc = DDR3SoC(fpga=fpga, dram_cls=dram_cls, # check microwatt_soc.h for these ddrphy_addr=0xff000000, # DRAM_INIT_BASE firmware base dramcore_addr=0xc8000000, # DRAM_CTRL_BASE ddr_addr=0x40000000, # DRAM_BASE + spi0_addr=0x10000000, # SPI0_BASE + spi0_cfg_addr=0xc0003000, # SPI0_CTRL_BASE fw_addr=fw_addr, #fw_addr=None, ddr_pins=ddr_pins, uart_pins=uart_pins, + spi_0_pins=spi_0_pins, firmware=firmware, clk_freq=clk_freq, add_cpu=True) -- 2.30.2