#!/usr/bin/env python3 # # This file is part of LiteX-Boards. # # Copyright (c) 2022 Ilia Sergachev # SPDX-License-Identifier: BSD-2-Clause # Build/Use: # The current support is sufficient to run LiteX BIOS on Cortex-A53 core #0: # ./xilinx_kv260.py --build --load # LiteX BIOS can then be executed on hardware using JTAG with the following xsct script from: # https://github.com/sergachev/litex-template/tree/kv260 # make -f Makefile.kv260 load will build everything and run xsct in the end. # # Relies on https://github.com/lucaceresoli/zynqmp-pmufw-builder to create a generic PMU firmware; # first build will take a while because it includes a cross-toolchain. import os from migen import * from litex.gen import LiteXModule from litex_boards.platforms import xilinx_kv260 from litex.build.tools import write_to_file from litex.soc.interconnect import axi from litex.soc.interconnect import wishbone from litex.soc.cores.clock import * from litex.soc.integration.soc_core import * from litex.soc.integration.soc import SoCRegion from litex.soc.integration.builder import * # CRG ---------------------------------------------------------------------------------------------- class _CRG(LiteXModule): def __init__(self, platform, sys_clk_freq, use_ps7_clk=False): self.rst = Signal() self.cd_sys = ClockDomain() # # # if use_ps7_clk: self.comb += ClockSignal("sys").eq(ClockSignal("ps")) self.comb += ResetSignal("sys").eq(ResetSignal("ps") | self.rst) else: self.pll = pll = S7PLL(speedgrade=-1) self.comb += pll.reset.eq(self.rst) pll.register_clkin(platform.request(platform.default_clk_name), platform.default_clk_freq) pll.create_clkout(self.cd_sys, sys_clk_freq) # Ignore sys_clk to pll.clkin path created by SoC's rst. platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # BaseSoC ------------------------------------------------------------------------------------------ class BaseSoC(SoCCore): mem_map = {"csr": 0xA000_0000} # default GP0 address on ZynqMP def __init__(self, sys_clk_freq, **kwargs): platform = xilinx_kv260.Platform() # CRG -------------------------------------------------------------------------------------- use_ps7_clk = (kwargs.get("cpu_type", None) == "zynqmp") self.crg = _CRG(platform, sys_clk_freq, use_ps7_clk) # SoCCore ---------------------------------------------------------------------------------- if kwargs.get("cpu_type", None) == "zynqmp": kwargs["integrated_sram_size"] = 0 SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on KV260", **kwargs) # ZynqMP Integration ----------------------------------------------------------------------- if kwargs.get("cpu_type", None) == "zynqmp": self.cpu.config.update({ 'PSU_MIO_36_DIRECTION' : 'out', 'PSU_MIO_37_DIRECTION' : 'in', 'PSU__UART1__BAUD_RATE' : 115200, 'PSU__CRL_APB__UART1_REF_CTRL__DIVISOR0' : 10, }) # generated from board xml presets self.cpu.config.update({ 'PSU__CRF_APB__ACPU_CTRL__FREQMHZ' : '1333.333', 'PSU__DDRC__BANK_ADDR_COUNT' : '2', 'PSU__DDRC__BG_ADDR_COUNT' : '1', 'PSU__DDRC__BRC_MAPPING' : 'ROW_BANK_COL', 'PSU__DDRC__BUS_WIDTH' : '64 Bit', 'PSU__DDRC__CL' : '16', 'PSU__DDRC__CLOCK_STOP_EN' : '0', 'PSU__DDRC__COL_ADDR_COUNT' : '10', 'PSU__DDRC__COMPONENTS' : 'Components', 'PSU__DDRC__CWL' : '12', 'PSU__DDRC__DDR4_ADDR_MAPPING' : '0', 'PSU__DDRC__DDR4_CAL_MODE_ENABLE' : '0', 'PSU__DDRC__DDR4_CRC_CONTROL' : '0', 'PSU__DDRC__DDR4_T_REF_MODE' : '0', 'PSU__DDRC__DDR4_T_REF_RANGE' : 'Normal (0-85)', 'PSU__DDRC__DEVICE_CAPACITY' : '8192 MBits', 'PSU__DDRC__DIMM_ADDR_MIRROR' : '0', 'PSU__DDRC__DM_DBI' : 'DM_NO_DBI', 'PSU__DDRC__DRAM_WIDTH' : '16 Bits', 'PSU__DDRC__ECC' : 'Disabled', 'PSU__DDRC__FGRM' : '1X', 'PSU__DDRC__LP_ASR' : 'manual normal', 'PSU__DDRC__MEMORY_TYPE' : 'DDR 4', 'PSU__DDRC__PARITY_ENABLE' : '0', 'PSU__DDRC__PER_BANK_REFRESH' : '0', 'PSU__DDRC__PHY_DBI_MODE' : '0', 'PSU__DDRC__RANK_ADDR_COUNT' : '0', 'PSU__DDRC__ROW_ADDR_COUNT' : '16', 'PSU__DDRC__SELF_REF_ABORT' : '0', 'PSU__DDRC__SPEED_BIN' : 'DDR4_2400R', 'PSU__DDRC__STATIC_RD_MODE' : '0', 'PSU__DDRC__TRAIN_DATA_EYE' : '1', 'PSU__DDRC__TRAIN_READ_GATE' : '1', 'PSU__DDRC__TRAIN_WRITE_LEVEL' : '1', 'PSU__DDRC__T_FAW' : '30.0', 'PSU__DDRC__T_RAS_MIN' : '33', 'PSU__DDRC__T_RC' : '47.06', 'PSU__DDRC__T_RCD' : '16', 'PSU__DDRC__T_RP' : '16', 'PSU__DDRC__VREF' : '1', 'PSU__FPGA_PL0_ENABLE' : '1', 'PSU__PMU__GPO4__ENABLE' : '0', # these 2 are disabled for uart1 'PSU__PMU__GPO5__ENABLE' : '0', 'PSU__UART1__PERIPHERAL__ENABLE' : '1', 'PSU__UART1__PERIPHERAL__IO' : 'MIO 36 .. 37', }) # Connect Zynq AXI master to the SoC wb_gp0 = wishbone.Interface() self.submodules += axi.AXI2Wishbone( axi = self.cpu.add_axi_gp_master(), wishbone = wb_gp0, base_address = self.mem_map["csr"]) self.bus.add_master(master=wb_gp0) self.bus.add_region("sram", SoCRegion( origin = self.cpu.mem_map["sram"], size = 2 * 1024 * 1024 * 1024) # DDR ) self.bus.add_region("rom", SoCRegion( origin = self.cpu.mem_map["rom"], size = 512 * 1024 * 1024 // 8, linker = True) ) self.constants["CONFIG_CLOCK_FREQUENCY"] = 1333333008 def finalize(self, *args, **kwargs): super(BaseSoC, self).finalize(*args, **kwargs) if self.cpu_type != "zynqmp": return libxil_path = os.path.join(self.builder.software_dir, 'libxil') os.makedirs(os.path.realpath(libxil_path), exist_ok=True) lib = os.path.join(libxil_path, 'embeddedsw') if not os.path.exists(lib): os.system("git clone --depth 1 https://github.com/Xilinx/embeddedsw {}".format(lib)) os.makedirs(os.path.realpath(self.builder.include_dir), exist_ok=True) for header in [ 'XilinxProcessorIPLib/drivers/uartps/src/xuartps_hw.h', 'lib/bsp/standalone/src/common/xil_types.h', 'lib/bsp/standalone/src/common/xil_assert.h', 'lib/bsp/standalone/src/common/xil_io.h', 'lib/bsp/standalone/src/common/xil_printf.h', 'lib/bsp/standalone/src/common/xstatus.h', 'lib/bsp/standalone/src/common/xdebug.h', 'lib/bsp/standalone/src/arm/ARMv8/64bit/xpseudo_asm.h', 'lib/bsp/standalone/src/arm/ARMv8/64bit/xreg_cortexa53.h', 'lib/bsp/standalone/src/arm/ARMv8/64bit/xil_cache.h', 'lib/bsp/standalone/src/arm/ARMv8/64bit/xil_errata.h', 'lib/bsp/standalone/src/arm/ARMv8/64bit/platform/ZynqMP/xparameters_ps.h', 'lib/bsp/standalone/src/arm/common/xil_exception.h', 'lib/bsp/standalone/src/arm/common/gcc/xpseudo_asm_gcc.h', ]: shutil.copy(os.path.join(lib, header), self.builder.include_dir) write_to_file(os.path.join(self.builder.include_dir, 'bspconfig.h'), """ #ifndef BSPCONFIG_H #define BSPCONFIG_H #define EL3 1 #define EL1_NONSECURE 0 #endif """) write_to_file(os.path.join(self.builder.include_dir, 'xparameters.h'), ''' #ifndef XPARAMETERS_H #define XPARAMETERS_H #include "xparameters_ps.h" #define STDIN_BASEADDRESS 0xFF010000 #define STDOUT_BASEADDRESS 0xFF010000 #define XPAR_PSU_DDR_0_S_AXI_BASEADDR 0x00000000 #define XPAR_PSU_DDR_0_S_AXI_HIGHADDR 0x7FFFFFFF #define XPAR_PSU_DDR_1_S_AXI_BASEADDR 0x800000000 #define XPAR_PSU_DDR_1_S_AXI_HIGHADDR 0x87FFFFFFF #define XPAR_CPU_CORTEXA53_0_TIMESTAMP_CLK_FREQ 99999001 #endif ''') # Build -------------------------------------------------------------------------------------------- def main(): from litex.build.parser import LiteXArgumentParser parser = LiteXArgumentParser(platform=xilinx_kv260.Platform, description="LiteX SoC on KV260") parser.add_target_argument("--sys-clk-freq", default=100e6, help="System clock frequency.") parser.set_defaults(cpu_type="zynqmp") parser.set_defaults(no_uart=True) args = parser.parse_args() soc = BaseSoC( sys_clk_freq=int(float(args.sys_clk_freq)), **parser.soc_core_argdict ) builder = Builder(soc, **parser.builder_argdict) if args.cpu_type == "zynqmp": soc.builder = builder builder.add_software_package('libxil') builder.add_software_library('libxil') 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 __name__ == "__main__": main()