From 9b391bbaf9ed0b83a493f20e48594a1c1e3004ce Mon Sep 17 00:00:00 2001 From: Sandeep Gundlupet Raju Date: Thu, 30 Nov 2023 22:07:47 -0700 Subject: classes: Move classes to match bbclass scope functionality Move classes to classes-global or classes-recipe as appropriate to match bbclass scope functionality. Below is the list. classes-recipe: (inherited by recipes) amd_spi_image.bbclass dfx_user_dts.bbclass image-wic-utils.bbclass kernel-simpleimage.bbclass qemuboot-xilinx.bbclass xilinx-fetch-restricted.bbclass xilinx-platform-init.bbclass classes-global: (inherited globally) xilinx-microblaze.bbclass classes: (usage context is not clearly defined) gen-machine-conf.bbclass image-types-xilinx-qemu.bbclass xilinx-testimage.bbclass xilinx-vars.bbclass xilinx-deprecated.bbclass Signed-off-by: Sandeep Gundlupet Raju Signed-off-by: Mark Hatle --- .../classes-recipe/amd_spi_image.bbclass | 142 +++++++++++ .../classes-recipe/dfx_user_dts.bbclass | 267 +++++++++++++++++++++ .../classes-recipe/image-wic-utils.bbclass | 54 +++++ .../classes-recipe/kernel-simpleimage.bbclass | 35 +++ .../classes-recipe/qemuboot-xilinx.bbclass | 140 +++++++++++ .../classes-recipe/xilinx-fetch-restricted.bbclass | 35 +++ .../classes-recipe/xilinx-platform-init.bbclass | 14 ++ 7 files changed, 687 insertions(+) create mode 100644 meta-xilinx-core/classes-recipe/amd_spi_image.bbclass create mode 100644 meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass create mode 100644 meta-xilinx-core/classes-recipe/image-wic-utils.bbclass create mode 100644 meta-xilinx-core/classes-recipe/kernel-simpleimage.bbclass create mode 100644 meta-xilinx-core/classes-recipe/qemuboot-xilinx.bbclass create mode 100644 meta-xilinx-core/classes-recipe/xilinx-fetch-restricted.bbclass create mode 100644 meta-xilinx-core/classes-recipe/xilinx-platform-init.bbclass (limited to 'meta-xilinx-core/classes-recipe') diff --git a/meta-xilinx-core/classes-recipe/amd_spi_image.bbclass b/meta-xilinx-core/classes-recipe/amd_spi_image.bbclass new file mode 100644 index 00000000..ed4c1f87 --- /dev/null +++ b/meta-xilinx-core/classes-recipe/amd_spi_image.bbclass @@ -0,0 +1,142 @@ +# +# Copyright (C) 2023, Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: MIT +# + +QSPI_SIZE ?= "0x2280000" + +# Register values +IDN_REG ?= "0x4D554241" +VERSION_REG ?= "0x1" +LENGTH_REG ?= "0x4" +PERSISTENT_REG ?= "0x01010000" + +# QSPI Offsets +IMAGE_SELECTOR_OFFSET ?= "0x0" +IMAGE_SELECTOR_BACKUP_OFFSET ?= "0x80000" +PERSISTENT_REG_OFFSET ?= "0x100000" +PERSISTENT_REG_BACKUP_OFFSET ?= "0x120000" +IMAGE_A_OFFSET ?= "0x200000" +IMAGE_A_IMGSEL_OFFSET ?= "0xF00000" +IMAGE_B_OFFSET ?= "0xF80000" +IMAGE_B_IMGSEL_OFFSET ?= "0x1C80000" +IMAGE_RCVRY_OFFSET ?= "0x1E00000" +IMAGE_RCVRY_BACKUP_OFFSET ?= "0x2000000" +VERSION_OFFSET ?= "0x2240000" +CHECKSUM_OFFSET ?= "0x2250000" + +def generate_spi_image(d): + + import io + import hashlib + import time + + qspi_size = int(d.getVar("QSPI_SIZE") or '0', 0) + int(d.getVar("QSPI_SIZE") or '0', 0) + + # Register values + idn_reg = int(d.getVar("IDN_REG") or '0', 0) + version_reg = int(d.getVar("VERSION_REG") or '0', 0) + length_reg = int(d.getVar("LENGTH_REG") or '0', 0) + persistent_reg = int(d.getVar("PERSISTENT_REG") or '0', 0) + + # QSPI Offsets + image_selector_offset = int(d.getVar("IMAGE_SELECTOR_OFFSET") or '0', 0) + image_selector_backup_offset = int(d.getVar("IMAGE_SELECTOR_BACKUP_OFFSET") or '0', 0) + persistent_reg_offset = int(d.getVar("PERSISTENT_REG_OFFSET") or '0', 0) + persistent_reg_backup_offset = int(d.getVar("PERSISTENT_REG_BACKUP_OFFSET") or '0', 0) + image_a_offset = int(d.getVar("IMAGE_A_OFFSET") or '0', 0) + image_a_imgsel_offset = int(d.getVar("IMAGE_A_IMGSEL_OFFSET") or '0', 0) + image_b_offset = int(d.getVar("IMAGE_B_OFFSET") or '0', 0) + image_b_imgsel_offset = int(d.getVar("IMAGE_B_IMGSEL_OFFSET") or '0', 0) + image_rcvry_offset = int(d.getVar("IMAGE_RCVRY_OFFSET") or '0', 0) + image_rcvry_backup_offset = int(d.getVar("IMAGE_RCVRY_BACKUP_OFFSET") or '0', 0) + version_offset = int(d.getVar("VERSION_OFFSET") or '0', 0) + checksum_offset = int(d.getVar("CHECKSUM_OFFSET") or '0', 0) + + # QSPI data + qspi_data = io.BytesIO() + qspi_data.write(b'\xFF' * qspi_size) + + # Image Selector - Primary, Backup, Image A and Image B + imgsel_file = d.getVar("DEPLOY_DIR_IMAGE")+"/imgsel-"+d.getVar("MACHINE")+".bin" + try: + with open(imgsel_file, "rb") as il: + imgsel = il.read(-1) + except OSError as err: + bb.fatal("Unable to open imgsel file: " + str(err)) + + qspi_data.seek(image_selector_offset) + qspi_data.write(imgsel) + qspi_data.seek(image_selector_backup_offset) + qspi_data.write(imgsel) + qspi_data.seek(image_a_imgsel_offset) + qspi_data.write(imgsel) + qspi_data.seek(image_b_imgsel_offset) + qspi_data.write(imgsel) + + # Persistent Registers - Primary and Backup + p_reg = [idn_reg, version_reg, length_reg, persistent_reg, \ + image_a_offset, image_b_offset, image_rcvry_offset] + checksum = 0xffffffff - (0xffffffff & sum(p_reg)) + p_reg.insert(3, checksum) + + qspi_data.seek(persistent_reg_offset) + for value in p_reg: + qspi_data.write(value.to_bytes(4, byteorder="little")) + + qspi_data.seek(persistent_reg_backup_offset) + for value in p_reg: + qspi_data.write(value.to_bytes(4, byteorder="little")) + + # Image A and B - boot.bin + try: + with open(d.getVar("DEPLOY_DIR_IMAGE")+"/boot.bin", "rb") as bo: + bootbin = bo.read(-1) + except OSError as err: + bb.fatal("Unable to open boot.bin file: " + str(err)) + + qspi_data.seek(image_a_offset) + qspi_data.write(bootbin) + qspi_data.seek(image_b_offset) + qspi_data.write(bootbin) + + # Recovery Image & Recovery Image Backup + imgrcry_file = d.getVar("DEPLOY_DIR_IMAGE")+"/imgrcry-"+d.getVar("MACHINE")+".bin" + try: + with open(imgrcry_file, "rb") as iy: + imgrcry = iy.read(-1) + except OSError as err: + bb.fatal("Unable to open imgrcry file: " + str(err)) + + qspi_data.seek(image_rcvry_offset) + qspi_data.write(imgrcry) + qspi_data.seek(image_rcvry_backup_offset) + qspi_data.write(imgrcry) + + # Version string and checksum + version = d.getVar("QSPI_IMAGE_VERSION") + date = time.strftime("%m%d%H%M") + machine = d.getVar("MACHINE")[:3] + image_name = d.getVar("QSPI_IMAGE_NAME") + + qspi_version = f"{image_name}-{machine}-v{version}-{date}\x00" + qspi_data.seek(version_offset) + qspi_data.write(qspi_version.encode()) + + qspi_sha = hashlib.sha256(qspi_data.getbuffer()) + qspi_data.seek(checksum_offset) + qspi_data.write(qspi_sha.digest()) + + # Write the QSPI data to file + with open(d.getVar("B") + "/" + d.getVar("IMAGE_NAME") + ".bin", "wb") as sq: + sq.write(qspi_data.getbuffer()) + +do_compile[depends] += "virtual/boot-bin:do_deploy virtual/imgsel:do_deploy virtual/imgrcry:do_deploy" + +python amd_spi_image_do_compile() { + generate_spi_image(d) +} + +EXPORT_FUNCTIONS do_compile diff --git a/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass new file mode 100644 index 00000000..4404aa05 --- /dev/null +++ b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass @@ -0,0 +1,267 @@ +# This bbclass is inherited by flat, DFx Static and DFx RP firmware recipes. +# dfx_user_dts.bbclass expects user to generate pl dtsi for flat, DFx Static +# and DFx RP xsa outside of yocto. + +inherit devicetree + +DEPENDS = "dtc-native bootgen-native" + +# recipes that inherit from this class need to use an appropriate machine +# override for COMPATIBLE_MACHINE to build successfully; don't allow building +# for microblaze MACHINE +COMPATIBLE_MACHINE ?= "^$" +COMPATIBLE_MACHINE:microblaze = "^$" + +PACKAGE_ARCH = "${MACHINE_ARCH}" + +PROVIDES = "" + +do_fetch[cleandirs] = "${B}" + +DT_PADDING_SIZE = "0x1000" +BOOTGEN_FLAGS ?= " -arch ${SOC_FAMILY} -w ${@bb.utils.contains('SOC_FAMILY','zynqmp','','-process_bitstream bin',d)}" + +S ?= "${WORKDIR}" +FW_DIR ?= "" +DTSI_PATH ?= "" +DTBO_PATH ?= "" +DT_FILES_PATH = "${S}/${DTSI_PATH}" +FIRMWARE_NAME_DT_FILE ?= "" +USER_DTS_FILE ?= "" + +FIRMWARE_NAME_DT_FILE[doc] = "DT file which has firmware-name device-tree property" +USER_DTS_FILE[doc] = "Final DTSI or DTS file which is used for packaging final DT overlay" + +python() { + import re + soc_family = d.getVar("SOC_FAMILY") + if "git://" in d.getVar("SRC_URI") or "https://" in d.getVar("SRC_URI"): + d.setVar("S",'${WORKDIR}/git/'+d.getVar("FW_DIR")) + else: + dtsi_found = False + dtbo_found = False + bit_found = False + bin_found = False + pdi_found = False + + # Required Inputs + if '.dtsi' in d.getVar("SRC_URI") or '.dts' in d.getVar("SRC_URI"): + dtsi_found = True + d.setVar("DTSI_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.dtsi' in a or '.dts' in a][0].lstrip('file://'))) + + if '.dtbo' in d.getVar("SRC_URI"): + dtbo_found = True + d.setVar("DTBO_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.dtbo' in a][0].lstrip('file://'))) + + if '.bit' in d.getVar("SRC_URI") and soc_family != "versal": + bit_found = True + d.setVar("BIT_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.bit' in a][0].lstrip('file://'))) + + if '.bin' in d.getVar("SRC_URI") and soc_family != "versal": + bin_found = True + d.setVar("BIT_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.bin' in a][0].lstrip('file://'))) + + if '.pdi' in d.getVar("SRC_URI") and soc_family == "versal": + pdi_found = True + d.setVar("PDI_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.pdi' in a][0].lstrip('file://'))) + + # Check for valid combination of input files in SRC_URI + if dtsi_found or dtbo_found: + bb.debug(2, "dtsi or dtbo found in SRC_URI") + if bit_found or pdi_found or bin_found: + bb.debug(2, "bitstream or pdi found in SRC_URI") + elif bit_found and bin_found: + raise bb.parse.SkipRecipe("Both '.bit' and '.bin' file found in SRC_URI, either .bit or .bin file is supported but not both.") + else: + raise bb.parse.SkipRecipe("Need one '.bit' or one '.pdi' file added to SRC_URI ") + else: + raise bb.parse.SkipRecipe("Need one '.dtsi' or one '.dtbo' file added to SRC_URI ") + + # Check for valid combination of dtsi and dts files in SRC_URI + # Following file combinations are not supported use case. + # 1. More than one '.dtsi' and zero '.dts' file. + # 2. More than one '.dts' and zero or more than one '.dtsi'file . + pattern_dts = re.compile(r'[.]+dts\b') + pattern_dtsi = re.compile(r'[.]+dtsi\b') + dts_count = len([*re.finditer(pattern_dts, d.getVar('SRC_URI'))]) + dtsi_count = len([*re.finditer(pattern_dtsi, d.getVar("SRC_URI"))]) + + if dtsi_count > 1 and dts_count == 0: + raise bb.parse.SkipRecipe("Recipe has more than one '.dtsi' and zero '.dts' found, this is an unsupported use case") + elif dts_count > 1: + raise bb.parse.SkipRecipe("Recipe has more than one '.dts' and zero or more than one '.dtsi' found, this is an unsupported use case") + + # Optional input + if '.json' in d.getVar("SRC_URI"): + d.setVar("JSON_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.json' in a][0].lstrip('file://'))) + + if '.xclbin' in d.getVar("SRC_URI"): + d.setVar("XCL_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.xclbin' in a][0].lstrip('file://'))) +} + +# Function to get dts or dtsi file count. +def get_dt_count(d, dt_ext): + import glob + dt_count = sum(1 for f in glob.iglob((d.getVar('S') + (d.getVar('DTSI_PATH')) + '/*.' + dt_ext),recursive=True) if os.path.isfile(f)) + return dt_count + +# Function to search for dt firmware-name property in dts or dtsi file. +python find_firmware_file() { + import glob + pattern_fw = 'firmware-name' + search_count = 0 + for dt_files in glob.iglob((d.getVar('S') + (d.getVar('DTSI_PATH')) + '/*.dts*'),recursive=True): + with open(dt_files, "r") as f: + current_fd = f.read() + if pattern_fw in current_fd: + search_count += 1 + if search_count > 1: + bb.error("firmware-name dt property found in more than one dt files! Please fix the dts or dtsi file.") + break + else: + d.setVar('FIRMWARE_NAME_DT_FILE', os.path.basename(dt_files)) +} + +do_configure[prefuncs] += "find_firmware_file" + +python do_configure() { + import glob, re, shutil + soc_family = d.getVar("SOC_FAMILY") + + if bb.utils.contains('MACHINE_FEATURES', 'fpga-overlay', False, True, d): + bb.warn("Using fpga-manager.bbclass requires fpga-overlay MACHINE_FEATURE to be enabled") + + # Renaming firmware-name using $PN as bitstream/PDI will be renamed using + # $PN when generating the bin/pdi file. + if os.path.isfile(d.getVar('S') + (d.getVar('DTSI_PATH') or '') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE')): + orig_dtsi = glob.glob(d.getVar('S')+ (d.getVar('DTSI_PATH') or '') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE'))[0] + new_dtsi = d.getVar('S') + '/pl.dtsi_firmwarename' + with open(new_dtsi, 'w') as newdtsi: + with open(orig_dtsi) as olddtsi: + for line in olddtsi: + if soc_family == 'versal': + newdtsi.write(re.sub('firmware-name.*\".*\"','firmware-name = \"'+d.getVar('PN')+'.pdi\"',line)) + else: + newdtsi.write(re.sub('firmware-name.*\".*\"','firmware-name = \"'+d.getVar('PN')+'.bit.bin\"',line)) + shutil.move(new_dtsi,orig_dtsi) +} + +do_compile[prefuncs] += "find_firmware_file" + +python devicetree_do_compile:append() { + import glob, subprocess, shutil + soc_family = d.getVar("SOC_FAMILY") + + dtbo_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.dtbo'),recursive=True) if os.path.isfile(f)) + + # Skip devicetree do_compile task if input file is dtbo in SRC_URI + if not dtbo_count: + # Convert .bit to bit.bin format only if dtsi is input. + # In case of dtbo as input, bbclass doesn't know if firmware-name is .bit or + # .bit.bin format and corresponding file name. Hence we are not doing + # bit.bin conversion. + if soc_family != 'versal' and glob.glob(d.getVar('S') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE')): + pn = d.getVar('PN') + biffile = pn + '.bif' + + with open(biffile, 'w') as f: + f.write('all:\n{\n\t' + glob.glob(d.getVar('S')+(d.getVar('BIT_PATH') or '') + '/*.bit')[0] + '\n}') + + bootgenargs = ["bootgen"] + (d.getVar("BOOTGEN_FLAGS") or "").split() + bootgenargs += ["-image", biffile, "-o", pn + ".bit.bin"] + subprocess.run(bootgenargs, check = True) + + # In Zynq7k using both "-process_bitstream bin" and "-o" in bootgen flag, + # to convert bit file to bin format, "-o" option will not be effective + # and generated output file name is ${S}+${BIT_PATH}/.bit.bin + # file, Hence we need to rename this file from .bit.bin to + # ${PN}.bit.bin which matches the firmware name in dtbo and move + # ${PN}.bit.bin to ${B} directory. + if soc_family == 'zynq': + src_bitbin_file = glob.glob(d.getVar('S') + (d.getVar('BIT_PATH') or '') + '/*.bit.bin')[0] + dst_bitbin_file = d.getVar('B') + '/' + pn + '.bit.bin' + shutil.move(src_bitbin_file, dst_bitbin_file) + + if not os.path.isfile(pn + ".bit.bin"): + bb.fatal("Couldn't find %s file, Enable '-log trace' in BOOTGEN_FLAGS" \ + "and check bootgen_log.txt" % (d.getVar('B') + '/' + pn + '.bit.bin')) +} + +# If user inputs both dtsi and dts files then device-tree will generate dtbo +# files for each dt file, Hence to package the firmware pick the right user dt +# overlay file. +python find_user_dts_overlay_file() { + import glob + dtbo_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.dtbo'),recursive=True) if os.path.isfile(f)) + # Skip if input file is dtbo in SRC_URI + if not dtbo_count: + dts_count = get_dt_count(d, 'dts') + dtsi_count = get_dt_count(d, 'dtsi') + if dtsi_count == 1 and dts_count == 0: + dts_file =glob.glob(d.getVar('S')+ (d.getVar('DTSI_PATH') or '') + '/*.dtsi')[0] + elif dtsi_count >=0 and dts_count == 1: + dts_file = glob.glob(d.getVar('S')+ (d.getVar('DTSI_PATH') or '') + '/*.dts')[0] + + d.setVar('USER_DTS_FILE', os.path.splitext(os.path.basename(dts_file))[0]) +} + +do_install[prefuncs] += "find_user_dts_overlay_file" + +do_install() { + install -d ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ + + # In case of dtbo as input, dtbo will be copied from directly from ${S} + # In case of dtsi as input, dtbo will be copied from directly from ${B} + if [ `ls ${S}/*.dtbo | wc -l` -eq 1 ]; then + install -Dm 0644 ${S}/*.dtbo ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ + elif [ `ls ${S}/*.dtbo | wc -l` -gt 1 ]; then + bbfatal "Multiple DTBO found, use the right DTBO in SRC_URI from the following:\n$(basename -a ${S}/*.dtbo)" + elif [ -f ${B}/${USER_DTS_FILE}.dtbo ]; then + install -Dm 0644 ${B}/${USER_DTS_FILE}.dtbo ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.dtbo + else + bbfatal "A dtbo ending '.dtbo' expected but not found" + fi + + if [ "${SOC_FAMILY}" == "versal" ]; then + # In case of dtbo as input, pdi will be copied from directly from ${S} + # without renaming the pdi name to ${PN}.pdi + if [ `ls ${S}/*.pdi | wc -l` -eq 1 ] && [ `ls ${S}/*.dtbo | wc -l` -eq 1 ]; then + install -Dm 0644 ${S}/*.pdi ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ + elif [ `ls ${S}/*.pdi | wc -l` -gt 1 ]; then + bbfatal "Multiple PDI found, use the right PDI in SRC_URI from the following:\n$(basename -a ${S}/*.pdi)" + elif [ `ls ${S}/*.pdi | wc -l` -eq 1 ] && [ -f ${B}/${USER_DTS_FILE}.dtbo ]; then + install -Dm 0644 ${S}/*.pdi ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.pdi + else + bbfatal "A PDI file with '.pdi' expected but not found" + fi + else + # In case of dtbo as input, .bit or .bin will be copied from directly + # from ${S} without renaming the .bit/.bin name to ${PN}.bit/${PN}.bin + # if more than one .bit/.bin file is found then fail the task. + if [ `ls ${S}/*.bit | wc -l` -gt 1 ]; then + bbfatal "Multiple .bit found, use the right .bit in SRC_URI from the following:\n$(basename -a ${S}/*.bit)" + elif [ `ls ${S}/*.bin | wc -l` -gt 1 ]; then + bbfatal "Multiple .bin found, use the right .bin in SRC_URI from the following:\n$(basename -a ${S}/*.bin)" + elif [ `ls ${S}/*.bit | wc -l` -eq 1 ] && [ `ls ${S}/*.dtbo | wc -l` -eq 1 ]; then + install -Dm 0644 ${S}/*.bit ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ + elif [ `ls ${S}/*.bin | wc -l` -eq 1 ] && [ `ls ${S}/*.dtbo | wc -l` -eq 1 ]; then + install -Dm 0644 ${S}/*.bin ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ + elif [ -f ${B}/${PN}.bit.bin ] && [ -f ${B}/${USER_DTS_FILE}.dtbo ]; then + install -Dm 0644 ${B}/${PN}.bit.bin ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.bit.bin + else + bbfatal "A bitstream file with '.bit' or '.bin' expected but not found" + fi + fi + + if ls ${S}/${XCL_PATH}/*.xclbin >/dev/null 2>&1; then + install -Dm 0644 ${S}/${XCL_PATH}/*.xclbin ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.xclbin + fi + + if [ -f ${S}/${JSON_PATH}/shell.json ] || [ -f ${S}/${JSON_PATH}/accel.json ]; then + install -Dm 0644 ${S}/${JSON_PATH}/*.json ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ + fi +} + +do_deploy[noexec] = "1" + +FILES:${PN} += "${nonarch_base_libdir}/firmware/xilinx/${PN}" diff --git a/meta-xilinx-core/classes-recipe/image-wic-utils.bbclass b/meta-xilinx-core/classes-recipe/image-wic-utils.bbclass new file mode 100644 index 00000000..41ad8148 --- /dev/null +++ b/meta-xilinx-core/classes-recipe/image-wic-utils.bbclass @@ -0,0 +1,54 @@ +# Helper/utility functions to work with the IMAGE_BOOT_FILES variable and its +# expected behvaior with regards to the contents of the DEPLOY_DIR_IMAGE. +# +# The use of these functions assume that the deploy directory is populated with +# any dependent files/etc. Such that the recipe using these functions depends +# on the recipe that provides the files being used/queried. + +def boot_files_split_expand(d): + # IMAGE_BOOT_FILES has extra renaming info in the format ';' + for f in (d.getVar("IMAGE_BOOT_FILES") or "").split(" "): + parts = f.split(";", 1) + sources = [parts[0].strip()] + if "*" in parts[0]: + # has glob part + import glob + deployroot = d.getVar("DEPLOY_DIR_IMAGE") + sources = [] + for i in glob.glob(os.path.join(deployroot, parts[0])): + sources.append(os.path.basename(i)) + + # for all sources, yield an entry + for s in sources: + if len(parts) == 2: + if parts[1].endswith('/'): + yield s, '%s%s' % (parts[1].strip(), s) + else: + yield s, parts[1].strip() + yield s, s + +def boot_files_bitstream(d): + expectedfiles = [("bitstream", True)] + expectedexts = [(".bit", True), (".bin", False)] + # search for bitstream paths, use the renamed file. First matching is used + for source, target in boot_files_split_expand(d): + # skip boot.bin and u-boot.bin, it is not a bitstream + skip = ["boot.bin", "u-boot.bin"] + if source in skip or target in skip: + continue + + for e, t in expectedfiles: + if source == e or target == e: + return target, t + for e, t in expectedexts: + if source.endswith(e) or target.endswith(e): + return target, t + return "", False + +def boot_files_dtb_filepath(d): + dtbs = (d.getVar("IMAGE_BOOT_FILES") or "").split(" ") + for source, target in boot_files_split_expand(d): + if target.endswith(".dtb"): + return target + return "" + diff --git a/meta-xilinx-core/classes-recipe/kernel-simpleimage.bbclass b/meta-xilinx-core/classes-recipe/kernel-simpleimage.bbclass new file mode 100644 index 00000000..110ee254 --- /dev/null +++ b/meta-xilinx-core/classes-recipe/kernel-simpleimage.bbclass @@ -0,0 +1,35 @@ +python __anonymous () { + kerneltypes = set((d.getVar("KERNEL_IMAGETYPE") or "").split()) + kerneltypes |= set((d.getVar("KERNEL_IMAGETYPES") or "").split()) + if any(t.startswith("simpleImage.") for t in kerneltypes): + # Enable building of simpleImage + bb.build.addtask('do_prep_simpleimage', 'do_compile', 'do_configure', d) + uarch = d.getVar("UBOOT_ARCH") + if uarch == "microblaze": + d.appendVarFlag('do_prep_simpleimage', 'depends', ' virtual/dtb:do_populate_sysroot') +} + +do_prep_simpleimage[dirs] += "${B}" +do_prep_simpleimage () { + install -d ${B}/arch/${ARCH}/boot/dts + for type in ${KERNEL_IMAGETYPES} ; do + if [ -z "${type##*simpleImage*}" ] && [ ${ARCH} = "microblaze" ]; then + ext="${type##*.}" + # Microblaze simpleImage only works with dts file + cp ${RECIPE_SYSROOT}/boot/devicetree/${ext}.dts ${B}/arch/${ARCH}/boot/dts/ + fi + done +} + +do_deploy:append () { + for type in ${KERNEL_IMAGETYPES} ; do + if [ -z "${type##*simpleImage*}" ] && [ ${ARCH} = "microblaze" ]; then + base_name=${type}-${KERNEL_IMAGE_NAME} + install -m 0644 ${KERNEL_OUTPUT_DIR}/${type}.strip $deployDir/${base_name}.strip + install -m 0644 ${KERNEL_OUTPUT_DIR}/${type}.unstrip $deployDir/${base_name}.unstrip + symlink_name=${type}-${KERNEL_IMAGE_LINK_NAME} + ln -sf ${base_name}.strip $deployDir/${symlink_name}.strip + ln -sf ${base_name}.unstrip $deployDir/${symlink_name}.unstrip + fi + done +} diff --git a/meta-xilinx-core/classes-recipe/qemuboot-xilinx.bbclass b/meta-xilinx-core/classes-recipe/qemuboot-xilinx.bbclass new file mode 100644 index 00000000..7466ab5e --- /dev/null +++ b/meta-xilinx-core/classes-recipe/qemuboot-xilinx.bbclass @@ -0,0 +1,140 @@ + +# enable the overrides for the context of the conf only +OVERRIDES .= ":qemuboot-xilinx" + +# Default machine targets for Xilinx QEMU (FDT Generic) +# Allow QB_MACHINE to be overridden by a BSP config +QB_MACHINE ?= "${QB_MACHINE_XILINX}" +QB_RNG="" +QB_MACHINE_XILINX:aarch64 = "-machine arm-generic-fdt" +QB_MACHINE_XILINX:arm = "-M arm-generic-fdt-7series" +QB_MACHINE_XILINX:microblaze = "-M microblaze-fdt-plnx" + +QB_SYSTEM_NAME ?= "${@qemu_target_binary(d)}" +QB_DEFAULT_FSTYPE ?= "${@qemu_rootfs_params(d,'fstype')}" +QB_ROOTFS ?= "${@qemu_rootfs_params(d,'rootfs')}" +QB_ROOTFS_OPT ?= "${@qemu_rootfs_params(d,'rootfs-opt')}" +QB_DTB ?= "${@qemu_default_dtb(d)}" + +# defaults +QB_DEFAULT_KERNEL ?= "none" +QB_DEFAULT_KERNEL:zynq ?= "${@'zImage' if \ + d.getVar('INITRAMFS_IMAGE_BUNDLE') != '1' else 'zImage-initramfs-${MACHINE}.bin'}" +QB_DEFAULT_KERNEL:microblaze ?= "${@'simpleImage.mb' if \ + d.getVar('INITRAMFS_IMAGE_BUNDLE') != '1' else 'simpleImage.mb-initramfs-${MACHINE}.bin'}" + +inherit qemuboot + +def qemu_target_binary(data): + package_arch = data.getVar("PACKAGE_ARCH") + qemu_target_binary = (data.getVar("QEMU_TARGET_BINARY_%s" % package_arch) or "") + if qemu_target_binary: + return qemu_target_binary + + target_arch = data.getVar("TARGET_ARCH") + if target_arch == "microblazeeb": + target_arch = "microblaze" + elif target_arch == "aarch64": + target_arch += "-multiarch" + elif target_arch == "arm": + target_arch = "aarch64" + return "qemu-system-%s" % target_arch + +def qemu_add_extra_args(data): + initramfs_image = data.getVar('INITRAMFS_IMAGE') or "" + bundle_image = data.getVar('INITRAMFS_IMAGE_BUNDLE') or "" + deploy_dir = data.getVar('DEPLOY_DIR_IMAGE') or "" + machine_name = data.getVar('MACHINE') or "" + soc_family = data.getVar('SOC_FAMILY') or "" + qb_extra_args = '' + # Add kernel image and boot.scr to qemu boot command when initramfs_image supplied + kernel_name = '' + bootscr_image = '%s/boot.scr' % deploy_dir + if soc_family in ('zynqmp', 'versal'): + kernel_name = 'Image' + bootscr_loadaddr = '0x20000000' + if initramfs_image: + kernel_image = '%s/%s' % (deploy_dir, kernel_name) + if bundle_image == "1": + kernel_image = '%s/%s-initramfs-%s.bin' % (deploy_dir, kernel_name, machine_name) + kernel_loadaddr = '0x200000' + if kernel_name: + qb_extra_args = ' -device loader,file=%s,addr=%s,force-raw=on' % (kernel_image, kernel_loadaddr) + qb_extra_args += ' -device loader,file=%s,addr=%s,force-raw=on' % (bootscr_image, bootscr_loadaddr) + if soc_family == 'versal': + qb_extra_args += ' -boot mode=5' + else: + if soc_family in ('zynqmp', 'versal'): + qb_extra_args = ' -boot mode=5' + return qb_extra_args + +def qemu_rootfs_params(data, param): + initramfs_image = data.getVar('INITRAMFS_IMAGE') or "" + bundle_image = data.getVar('INITRAMFS_IMAGE_BUNDLE') or "" + soc_family = data.getVar('SOC_FAMILY') or "" + tune_features = (data.getVar('TUNE_FEATURES') or []).split() + if 'microblaze' in tune_features: + soc_family = 'microblaze' + soc_variant = data.getVar('SOC_VARIANT') or "" + + if param == 'rootfs': + return 'none' if bundle_image == "1" else '' + + elif param == 'fstype': + fstype_dict = { + "microblaze": "cpio.gz", + "zynq": "cpio.gz", + "zynqmp": "cpio.gz.u-boot", + "versal": "cpio.gz.u-boot.qemu-sd-fatimg" + } + if not initramfs_image: + image_fs = data.getVar('IMAGE_FSTYPES') + if 'wic.qemu-sd' in image_fs: + return 'wic.qemu-sd' + if soc_family not in fstype_dict: + return "" + return fstype_dict[soc_family] + + elif param == 'rootfs-opt': + sd_index = "1" + if soc_family == 'zynq': + sd_index = "0" + if soc_family == 'versal' and soc_variant == 'net': + sd_index = "0" + + # Device is using a disk + if not initramfs_image: + return ' -drive if=sd,index=%s,file=@ROOTFS@,format=raw' % (sd_index) + + # Device is using a ramdisk + if soc_family not in ('zynq', 'microblaze'): + return ' -device loader,file=@ROOTFS@,addr=0x04000000,force-raw=on' + + # Ramdisk must be compiled into the kernel + return '' + +def qemu_default_dtb(data): + if data.getVar("IMAGE_BOOT_FILES", True): + dtbs = data.getVar("IMAGE_BOOT_FILES", True).split(" ") + # IMAGE_BOOT_FILES has extra renaming info in the format ';' + # Note: Wildcard sources work here only because runqemu expands them at run time + dtbs = [f.split(";")[0] for f in dtbs] + dtbs = [f for f in dtbs if f.endswith(".dtb")] + if len(dtbs) != 0: + return dtbs[0] + return "" + +def qemu_default_serial(data): + if data.getVar("SERIAL_CONSOLES", True): + first_console = data.getVar("SERIAL_CONSOLES", True).split(" ")[0] + speed, console = first_console.split(";", 1) + # zynqmp uses earlycon and stdout (in dtb) + if "zynqmp" in data.getVar("MACHINEOVERRIDES", True).split(":"): + return "" + return "console=%s,%s earlyprintk" % (console, speed) + return "" + +def qemu_zynqmp_unhalt(data, multiarch): + if multiarch: + return "-global xlnx,zynqmp-boot.cpu-num=0 -global xlnx,zynqmp-boot.use-pmufw=true" + return "-device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4 -device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4" diff --git a/meta-xilinx-core/classes-recipe/xilinx-fetch-restricted.bbclass b/meta-xilinx-core/classes-recipe/xilinx-fetch-restricted.bbclass new file mode 100644 index 00000000..a778ec7d --- /dev/null +++ b/meta-xilinx-core/classes-recipe/xilinx-fetch-restricted.bbclass @@ -0,0 +1,35 @@ +# This class is setup to override the default fetching for the target recipe. +# When fetching it forces PREMIRROR only fetching so that no attempts are made +# to fetch the Xilinx downloads that are restricted to authenticated users only. +# +# The purpose of this class is to allow for automatation with pre-downloaded +# content or content that is available with curated/user defined pre-mirrors +# and or pre-populated downloads/ directories. + +python do_fetch() { + xilinx_restricted_url = "xilinx.com/member/forms/download" + + src_uri = (d.getVar('SRC_URI') or "").split() + if len(src_uri) == 0: + return + + for i in src_uri: + if xilinx_restricted_url in i: + # force the use of premirrors only, do not attempt download from xilinx.com + d.setVar("BB_FETCH_PREMIRRORONLY", "1") + break + + try: + fetcher = bb.fetch2.Fetch(src_uri, d) + fetcher.download() + except bb.fetch2.NetworkAccess as e: + if xilinx_restricted_url in e.url: + # fatal on access to xilinx.com restricted downloads, print the url for manual download + bb.fatal("The following download cannot be fetched automatically. " \ + "Please manually download the file and place it in the 'downloads' directory (or on an available PREMIRROR).\n" \ + " %s" % (e.url.split(";")[0])) + else: + bb.fatal(str(e)) + except bb.fetch2.BBFetchException as e: + bb.fatal(str(e)) +} diff --git a/meta-xilinx-core/classes-recipe/xilinx-platform-init.bbclass b/meta-xilinx-core/classes-recipe/xilinx-platform-init.bbclass new file mode 100644 index 00000000..99f7863a --- /dev/null +++ b/meta-xilinx-core/classes-recipe/xilinx-platform-init.bbclass @@ -0,0 +1,14 @@ +# This class should be included by any recipe that wants to access or provide +# the platform init source files which are used to initialize a Zynq or ZynqMP +# SoC. + +# Define the path to the xilinx platform init code/headers +PLATFORM_INIT_DIR ?= "/usr/src/xilinx-platform-init" + +PLATFORM_INIT_STAGE_DIR = "${STAGING_DIR_HOST}${PLATFORM_INIT_DIR}" + +# Target files use for platform init +PLATFORM_INIT_FILES ?= "" +PLATFORM_INIT_FILES:zynq = "ps7_init_gpl.c ps7_init_gpl.h" +PLATFORM_INIT_FILES:zynqmp = "psu_init_gpl.c psu_init_gpl.h" + -- cgit v1.2.3-54-g00ecf From 410a0d133485390ef4bd1148bfcd43d5b225fbd8 Mon Sep 17 00:00:00 2001 From: Sandeep Gundlupet Raju Date: Fri, 1 Dec 2023 09:39:52 -0700 Subject: dfx_user_dts.bbclass: Make bitstream bin as default loadable file Make bitstream bin as default loadable file for Zynq 7000(Full) and ZynqMP(Full, DFx) dynamic configurations. Below use case are covered as part this patch. 1. If user provides a .bin file as input to dfx_user_dts bbclass then deploy this bin file to lib/firmware directory without any conversion. 2. If user provides a .bit file as input to dfx_user_dts bbclass then convert .bit file to .bin file using bootgen tool and deploy this bin file to lib/firmware directory. 3. Refactor fpga-manager.bbclass with dfx_user_dts.bbclass. Signed-off-by: Sandeep Gundlupet Raju Signed-off-by: Mark Hatle --- .../classes-recipe/dfx_user_dts.bbclass | 48 ++++++++++++---------- 1 file changed, 27 insertions(+), 21 deletions(-) (limited to 'meta-xilinx-core/classes-recipe') diff --git a/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass index 4404aa05..bde5be5d 100644 --- a/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass +++ b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass @@ -1,3 +1,8 @@ +# +# Copyright (C) 2023, Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: MIT +# # This bbclass is inherited by flat, DFx Static and DFx RP firmware recipes. # dfx_user_dts.bbclass expects user to generate pl dtsi for flat, DFx Static # and DFx RP xsa outside of yocto. @@ -59,7 +64,7 @@ python() { if '.bin' in d.getVar("SRC_URI") and soc_family != "versal": bin_found = True - d.setVar("BIT_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.bin' in a][0].lstrip('file://'))) + d.setVar("BIN_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.bin' in a][0].lstrip('file://'))) if '.pdi' in d.getVar("SRC_URI") and soc_family == "versal": pdi_found = True @@ -129,7 +134,7 @@ python do_configure() { soc_family = d.getVar("SOC_FAMILY") if bb.utils.contains('MACHINE_FEATURES', 'fpga-overlay', False, True, d): - bb.warn("Using fpga-manager.bbclass requires fpga-overlay MACHINE_FEATURE to be enabled") + bb.warn("Using dfx_user_dts.bbclass requires fpga-overlay MACHINE_FEATURE to be enabled") # Renaming firmware-name using $PN as bitstream/PDI will be renamed using # $PN when generating the bin/pdi file. @@ -142,7 +147,7 @@ python do_configure() { if soc_family == 'versal': newdtsi.write(re.sub('firmware-name.*\".*\"','firmware-name = \"'+d.getVar('PN')+'.pdi\"',line)) else: - newdtsi.write(re.sub('firmware-name.*\".*\"','firmware-name = \"'+d.getVar('PN')+'.bit.bin\"',line)) + newdtsi.write(re.sub('firmware-name.*\".*\"','firmware-name = \"'+d.getVar('PN')+'.bin\"',line)) shutil.move(new_dtsi,orig_dtsi) } @@ -153,13 +158,14 @@ python devicetree_do_compile:append() { soc_family = d.getVar("SOC_FAMILY") dtbo_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.dtbo'),recursive=True) if os.path.isfile(f)) - - # Skip devicetree do_compile task if input file is dtbo in SRC_URI - if not dtbo_count: - # Convert .bit to bit.bin format only if dtsi is input. - # In case of dtbo as input, bbclass doesn't know if firmware-name is .bit or - # .bit.bin format and corresponding file name. Hence we are not doing - # bit.bin conversion. + bin_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.bin'),recursive=True) if os.path.isfile(f)) + + # Skip devicetree do_compile task if input file is dtbo or bin in SRC_URI + if not dtbo_count and not bin_count: + # Convert .bit to .bin format only if dtsi is input. + # In case of dtbo as input, bbclass doesn't know if firmware-name is .bit + # or .bin format and corresponding file name. Hence we are not doing .bin + # conversion. if soc_family != 'versal' and glob.glob(d.getVar('S') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE')): pn = d.getVar('PN') biffile = pn + '.bif' @@ -168,23 +174,23 @@ python devicetree_do_compile:append() { f.write('all:\n{\n\t' + glob.glob(d.getVar('S')+(d.getVar('BIT_PATH') or '') + '/*.bit')[0] + '\n}') bootgenargs = ["bootgen"] + (d.getVar("BOOTGEN_FLAGS") or "").split() - bootgenargs += ["-image", biffile, "-o", pn + ".bit.bin"] + bootgenargs += ["-image", biffile, "-o", pn + ".bin"] subprocess.run(bootgenargs, check = True) # In Zynq7k using both "-process_bitstream bin" and "-o" in bootgen flag, # to convert bit file to bin format, "-o" option will not be effective - # and generated output file name is ${S}+${BIT_PATH}/.bit.bin - # file, Hence we need to rename this file from .bit.bin to - # ${PN}.bit.bin which matches the firmware name in dtbo and move - # ${PN}.bit.bin to ${B} directory. + # and generated output file name is ${S}+${BIT_PATH}/.bin + # file, Hence we need to rename this file from .bin to + # ${PN}.bin which matches the firmware name in dtbo and move + # ${PN}.bin to ${B} directory. if soc_family == 'zynq': - src_bitbin_file = glob.glob(d.getVar('S') + (d.getVar('BIT_PATH') or '') + '/*.bit.bin')[0] - dst_bitbin_file = d.getVar('B') + '/' + pn + '.bit.bin' + src_bitbin_file = glob.glob(d.getVar('S') + (d.getVar('BIT_PATH') or '') + '/*.bin')[0] + dst_bitbin_file = d.getVar('B') + '/' + pn + '.bin' shutil.move(src_bitbin_file, dst_bitbin_file) - if not os.path.isfile(pn + ".bit.bin"): + if not os.path.isfile(pn + ".bin"): bb.fatal("Couldn't find %s file, Enable '-log trace' in BOOTGEN_FLAGS" \ - "and check bootgen_log.txt" % (d.getVar('B') + '/' + pn + '.bit.bin')) + "and check bootgen_log.txt" % (d.getVar('B') + '/' + pn + '.bin')) } # If user inputs both dtsi and dts files then device-tree will generate dtbo @@ -246,8 +252,8 @@ do_install() { install -Dm 0644 ${S}/*.bit ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ elif [ `ls ${S}/*.bin | wc -l` -eq 1 ] && [ `ls ${S}/*.dtbo | wc -l` -eq 1 ]; then install -Dm 0644 ${S}/*.bin ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ - elif [ -f ${B}/${PN}.bit.bin ] && [ -f ${B}/${USER_DTS_FILE}.dtbo ]; then - install -Dm 0644 ${B}/${PN}.bit.bin ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.bit.bin + elif [ -f ${B}/${PN}.bin ] && [ -f ${B}/${USER_DTS_FILE}.dtbo ]; then + install -Dm 0644 ${B}/${PN}.bin ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.bin else bbfatal "A bitstream file with '.bit' or '.bin' expected but not found" fi -- cgit v1.2.3-54-g00ecf From 036b989385188ecb202416a7bdce57bbbceb6951 Mon Sep 17 00:00:00 2001 From: Sandeep Gundlupet Raju Date: Fri, 15 Dec 2023 22:27:08 -0700 Subject: dfx_user_dts.bbclass: Add bit or bin or pdi only packaging 1. Add support for packaging bit or bin or pdi only. 2. Fix logic for bit or bin found by adding space in search key, If user has .bit.bin file as input then both .bit and .bin was set to trun. In SRC_URI between two files there will be a space. 3. Remove versal soc family check condition and inverse the logic with zynq and zynqmp to support next generation silicon devices. 4. Fix UnboundLocalError: local variable 'dts_file' referenced before assignment. Signed-off-by: Sandeep Gundlupet Raju Signed-off-by: Mark Hatle --- .../classes-recipe/dfx_user_dts.bbclass | 129 +++++++++++++-------- 1 file changed, 81 insertions(+), 48 deletions(-) (limited to 'meta-xilinx-core/classes-recipe') diff --git a/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass index bde5be5d..c20cd8f7 100644 --- a/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass +++ b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass @@ -50,37 +50,46 @@ python() { pdi_found = False # Required Inputs - if '.dtsi' in d.getVar("SRC_URI") or '.dts' in d.getVar("SRC_URI"): + if '.dtsi ' in d.getVar("SRC_URI") or '.dts ' in d.getVar("SRC_URI"): dtsi_found = True d.setVar("DTSI_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.dtsi' in a or '.dts' in a][0].lstrip('file://'))) - if '.dtbo' in d.getVar("SRC_URI"): + if '.dtbo ' in d.getVar("SRC_URI"): dtbo_found = True d.setVar("DTBO_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.dtbo' in a][0].lstrip('file://'))) - if '.bit' in d.getVar("SRC_URI") and soc_family != "versal": - bit_found = True - d.setVar("BIT_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.bit' in a][0].lstrip('file://'))) + if soc_family == "zynq" or soc_family == "zynqmp": + if '.bit ' in d.getVar("SRC_URI"): + bit_found = True + d.setVar("BIT_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.bit' in a][0].lstrip('file://'))) - if '.bin' in d.getVar("SRC_URI") and soc_family != "versal": - bin_found = True - d.setVar("BIN_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.bin' in a][0].lstrip('file://'))) - - if '.pdi' in d.getVar("SRC_URI") and soc_family == "versal": - pdi_found = True - d.setVar("PDI_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.pdi' in a][0].lstrip('file://'))) + if '.bin ' in d.getVar("SRC_URI"): + bin_found = True + d.setVar("BIN_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.bin' in a][0].lstrip('file://'))) + else: + if '.pdi ' in d.getVar("SRC_URI"): + pdi_found = True + d.setVar("PDI_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.pdi' in a][0].lstrip('file://'))) # Check for valid combination of input files in SRC_URI - if dtsi_found or dtbo_found: - bb.debug(2, "dtsi or dtbo found in SRC_URI") - if bit_found or pdi_found or bin_found: - bb.debug(2, "bitstream or pdi found in SRC_URI") - elif bit_found and bin_found: + # Skip recipe if any of the below conditions are not satisfied. + # 1. At least one bit or bin or pdi or dts or dtsi or dtbo should exists. + # 2. More than one dtbo. + # 3. More than one bit or bin or pdi. + # 4. More than one dts and zero dtsi. + # 5. More than one dtsi and zero dts. + if dtsi_found or dtbo_found or bit_found or bin_found or pdi_found: + bb.debug(2, "dtsi or dtbo or bitstream or pdi found in SRC_URI") + if bit_found and pdi_found : + raise bb.parse.SkipRecipe("Both '.bit' and '.pdi' file found in SRC_URI, this is invalid use case.") + + if bin_found and pdi_found : + raise bb.parse.SkipRecipe("Both '.bin' and '.pdi' file found in SRC_URI, this is invalid use case.") + + if bit_found and bin_found: raise bb.parse.SkipRecipe("Both '.bit' and '.bin' file found in SRC_URI, either .bit or .bin file is supported but not both.") - else: - raise bb.parse.SkipRecipe("Need one '.bit' or one '.pdi' file added to SRC_URI ") else: - raise bb.parse.SkipRecipe("Need one '.dtsi' or one '.dtbo' file added to SRC_URI ") + raise bb.parse.SkipRecipe("Need one '.dtsi' or '.dtbo' or '.bit' or '.bin' or '.pdi' file added to SRC_URI ") # Check for valid combination of dtsi and dts files in SRC_URI # Following file combinations are not supported use case. @@ -97,10 +106,10 @@ python() { raise bb.parse.SkipRecipe("Recipe has more than one '.dts' and zero or more than one '.dtsi' found, this is an unsupported use case") # Optional input - if '.json' in d.getVar("SRC_URI"): + if '.json ' in d.getVar("SRC_URI"): d.setVar("JSON_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.json' in a][0].lstrip('file://'))) - if '.xclbin' in d.getVar("SRC_URI"): + if '.xclbin ' in d.getVar("SRC_URI"): d.setVar("XCL_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.xclbin' in a][0].lstrip('file://'))) } @@ -144,10 +153,10 @@ python do_configure() { with open(new_dtsi, 'w') as newdtsi: with open(orig_dtsi) as olddtsi: for line in olddtsi: - if soc_family == 'versal': - newdtsi.write(re.sub('firmware-name.*\".*\"','firmware-name = \"'+d.getVar('PN')+'.pdi\"',line)) - else: + if soc_family == 'zynq' or soc_family == 'zynqmp': newdtsi.write(re.sub('firmware-name.*\".*\"','firmware-name = \"'+d.getVar('PN')+'.bin\"',line)) + else: + newdtsi.write(re.sub('firmware-name.*\".*\"','firmware-name = \"'+d.getVar('PN')+'.pdi\"',line)) shutil.move(new_dtsi,orig_dtsi) } @@ -166,7 +175,7 @@ python devicetree_do_compile:append() { # In case of dtbo as input, bbclass doesn't know if firmware-name is .bit # or .bin format and corresponding file name. Hence we are not doing .bin # conversion. - if soc_family != 'versal' and glob.glob(d.getVar('S') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE')): + if soc_family == 'zynq' or soc_family == 'zynqmp' and glob.glob(d.getVar('S') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE')): pn = d.getVar('PN') biffile = pn + '.bif' @@ -199,16 +208,24 @@ python devicetree_do_compile:append() { python find_user_dts_overlay_file() { import glob dtbo_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.dtbo'),recursive=True) if os.path.isfile(f)) - # Skip if input file is dtbo in SRC_URI - if not dtbo_count: + dts_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.dts'),recursive=True) if os.path.isfile(f)) + dtsi_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.dtsi'),recursive=True) if os.path.isfile(f)) + # Set USER_DTS_FILE if input file is dts/dtsi in SRC_URI else skip operation. + if not dtbo_count and dts_count or dtsi_count: dts_count = get_dt_count(d, 'dts') dtsi_count = get_dt_count(d, 'dtsi') if dtsi_count == 1 and dts_count == 0: - dts_file =glob.glob(d.getVar('S')+ (d.getVar('DTSI_PATH') or '') + '/*.dtsi')[0] + dts_file = glob.glob(d.getVar('S')+ (d.getVar('DTSI_PATH') or '') + '/*.dtsi')[0] elif dtsi_count >=0 and dts_count == 1: dts_file = glob.glob(d.getVar('S')+ (d.getVar('DTSI_PATH') or '') + '/*.dts')[0] + else: + dts_file = '' d.setVar('USER_DTS_FILE', os.path.splitext(os.path.basename(dts_file))[0]) + elif dtbo_count: + bb.debug(2, "Firmware recipe input file is dtbo in SRC_URI") + else: + bb.debug(2, "Firmware recipe input file is bit/bin/pdi in SRC_URI") } do_install[prefuncs] += "find_user_dts_overlay_file" @@ -216,8 +233,12 @@ do_install[prefuncs] += "find_user_dts_overlay_file" do_install() { install -d ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ + # Install dtbo # In case of dtbo as input, dtbo will be copied from directly from ${S} # In case of dtsi as input, dtbo will be copied from directly from ${B} + # If more than one dtbo file is found then fatal the task. + # If no dtbo file is found add warning message as in some use case if IP + # doesn't have any driver then user can load pdi/bit/bin file. if [ `ls ${S}/*.dtbo | wc -l` -eq 1 ]; then install -Dm 0644 ${S}/*.dtbo ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ elif [ `ls ${S}/*.dtbo | wc -l` -gt 1 ]; then @@ -225,32 +246,23 @@ do_install() { elif [ -f ${B}/${USER_DTS_FILE}.dtbo ]; then install -Dm 0644 ${B}/${USER_DTS_FILE}.dtbo ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.dtbo else - bbfatal "A dtbo ending '.dtbo' expected but not found" + bbnote "A dtbo ending '.dtbo' expected but not found in ${S} or ${B}, This means firmware can be loaded without dtbo dependency." fi - if [ "${SOC_FAMILY}" == "versal" ]; then - # In case of dtbo as input, pdi will be copied from directly from ${S} - # without renaming the pdi name to ${PN}.pdi - if [ `ls ${S}/*.pdi | wc -l` -eq 1 ] && [ `ls ${S}/*.dtbo | wc -l` -eq 1 ]; then - install -Dm 0644 ${S}/*.pdi ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ - elif [ `ls ${S}/*.pdi | wc -l` -gt 1 ]; then - bbfatal "Multiple PDI found, use the right PDI in SRC_URI from the following:\n$(basename -a ${S}/*.pdi)" - elif [ `ls ${S}/*.pdi | wc -l` -eq 1 ] && [ -f ${B}/${USER_DTS_FILE}.dtbo ]; then - install -Dm 0644 ${S}/*.pdi ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.pdi - else - bbfatal "A PDI file with '.pdi' expected but not found" - fi - else - # In case of dtbo as input, .bit or .bin will be copied from directly - # from ${S} without renaming the .bit/.bin name to ${PN}.bit/${PN}.bin - # if more than one .bit/.bin file is found then fail the task. + # Install bit or bin if soc family is zynq-7000 or zynqmp. + # In case of dtbo as input or no dtbo exists in ${B}, then .bit or .bin will + # be copied from directly from ${S} without renaming the .bit/.bin name to + # ${PN}.bit/${PN}.bin. + # if more than one .bit/.bin file is found then fatal the task. + # if no .bit/.bin file is found then fatal the task. + if [ "${SOC_FAMILY}" = "zynq" ] || [ "${SOC_FAMILY}" = "zynqmp" ]; then if [ `ls ${S}/*.bit | wc -l` -gt 1 ]; then bbfatal "Multiple .bit found, use the right .bit in SRC_URI from the following:\n$(basename -a ${S}/*.bit)" elif [ `ls ${S}/*.bin | wc -l` -gt 1 ]; then bbfatal "Multiple .bin found, use the right .bin in SRC_URI from the following:\n$(basename -a ${S}/*.bin)" - elif [ `ls ${S}/*.bit | wc -l` -eq 1 ] && [ `ls ${S}/*.dtbo | wc -l` -eq 1 ]; then + elif [ `ls ${S}/*.bit | wc -l` -eq 1 ] && [ ! -f ${B}/${USER_DTS_FILE}.dtbo ]; then install -Dm 0644 ${S}/*.bit ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ - elif [ `ls ${S}/*.bin | wc -l` -eq 1 ] && [ `ls ${S}/*.dtbo | wc -l` -eq 1 ]; then + elif [ `ls ${S}/*.bin | wc -l` -eq 1 ] && [ ! -f ${B}/${USER_DTS_FILE}.dtbo ]; then install -Dm 0644 ${S}/*.bin ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ elif [ -f ${B}/${PN}.bin ] && [ -f ${B}/${USER_DTS_FILE}.dtbo ]; then install -Dm 0644 ${B}/${PN}.bin ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.bin @@ -259,10 +271,31 @@ do_install() { fi fi + # Install pdi if soc family is versal or new silicon. + # In case of dtbo as input or no dtbo exists in ${B}, then .pdi will be copied + # from directly from ${S} without renaming the pdi name to ${PN}.pdi + # if more than one .pdi file is found then fail the task. + # In case of Versal DFx Static, only static dtbo can be loaded as BOOT.bin + # already contains static pdi. bbclass is not smart enough to determine + # whether it is static pdi or not, hence change fatal to warn if no PDI is found. + if [ "${SOC_FAMILY}" != "zynq" ] && [ "${SOC_FAMILY}" != "zynqmp" ]; then + if [ `ls ${S}/*.pdi | wc -l` -eq 1 ] && [ ! -f ${B}/${USER_DTS_FILE}.dtbo ]; then + install -Dm 0644 ${S}/*.pdi ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ + elif [ `ls ${S}/*.pdi | wc -l` -gt 1 ]; then + bbfatal "Multiple PDI found, use the right PDI in SRC_URI from the following:\n$(basename -a ${S}/*.pdi)" + elif [ `ls ${S}/*.pdi | wc -l` -eq 1 ] && [ -f ${B}/${USER_DTS_FILE}.dtbo ]; then + install -Dm 0644 ${S}/*.pdi ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.pdi + else + bbwarn "A PDI file with '.pdi' expected but not found" + fi + fi + + # Install xclbin if ls ${S}/${XCL_PATH}/*.xclbin >/dev/null 2>&1; then install -Dm 0644 ${S}/${XCL_PATH}/*.xclbin ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.xclbin fi + # Install shell.json or accel.json if [ -f ${S}/${JSON_PATH}/shell.json ] || [ -f ${S}/${JSON_PATH}/accel.json ]; then install -Dm 0644 ${S}/${JSON_PATH}/*.json ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ fi -- cgit v1.2.3-54-g00ecf From b122d894dfa417c59f6c68c17e31705c0b268dbf Mon Sep 17 00:00:00 2001 From: Sandeep Gundlupet Raju Date: Thu, 21 Dec 2023 13:19:19 -0700 Subject: dfx_user_dts.bbclass: Fix build issue with bin and dtsi as input In dfx_user_dts.bbclass fix build issue with bin and dtsi as input file to firmware recipe. In case of bin file as input bootgen operation is not performed and directly copy from ${S} directory. Also remove check condition if dtbo with firmware-name doesn't exist which is not required in case of bin file as input. Signed-off-by: Sandeep Gundlupet Raju --- meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'meta-xilinx-core/classes-recipe') diff --git a/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass index c20cd8f7..9f63fccc 100644 --- a/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass +++ b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass @@ -262,7 +262,7 @@ do_install() { bbfatal "Multiple .bin found, use the right .bin in SRC_URI from the following:\n$(basename -a ${S}/*.bin)" elif [ `ls ${S}/*.bit | wc -l` -eq 1 ] && [ ! -f ${B}/${USER_DTS_FILE}.dtbo ]; then install -Dm 0644 ${S}/*.bit ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ - elif [ `ls ${S}/*.bin | wc -l` -eq 1 ] && [ ! -f ${B}/${USER_DTS_FILE}.dtbo ]; then + elif [ `ls ${S}/*.bin | wc -l` -eq 1 ]; then install -Dm 0644 ${S}/*.bin ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/ elif [ -f ${B}/${PN}.bin ] && [ -f ${B}/${USER_DTS_FILE}.dtbo ]; then install -Dm 0644 ${B}/${PN}.bin ${D}/${nonarch_base_libdir}/firmware/xilinx/${PN}/${PN}.bin -- cgit v1.2.3-54-g00ecf From a4cb65b56e0262ca236eb613d96973078424de69 Mon Sep 17 00:00:00 2001 From: Sandeep Gundlupet Raju Date: Tue, 6 Feb 2024 23:16:47 -0700 Subject: dfx_user_dts: Fix build issue if SRC_URI has only one file 1. If SRC_URI has only one file without any space as shown below SRC_URI = "file://vck190-dfx-static.pdi" With this it fails to detect input entries. This is due to current search logic doesn't work unless there is a space after end of file name or new line for each entry as shown below. SRC_URI = "file://vck190-dfx-static.pdi " or SRC_URI = " \ file://vck190-dfx-static.pdi \ " So rewrite the logic to split the SRC_URI enteries and then search key w/o the trailing space. 2. Remove get_dt_count function to avoid duplication. 3. Add docs for *_PATH variables. 4. Add warn message when multiple dtbo or bit or bin or pdi file is found. 5. Fix DTSI_PATH, BIT_PATH build issue when input files are absolute path. Signed-off-by: Sandeep Gundlupet Raju Signed-off-by: Mark Hatle --- .../classes-recipe/dfx_user_dts.bbclass | 107 +++++++++++---------- 1 file changed, 57 insertions(+), 50 deletions(-) (limited to 'meta-xilinx-core/classes-recipe') diff --git a/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass index 9f63fccc..2b699d9d 100644 --- a/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass +++ b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass @@ -1,5 +1,5 @@ # -# Copyright (C) 2023, Advanced Micro Devices, Inc. All rights reserved. +# Copyright (C) 2023-2024, Advanced Micro Devices, Inc. All rights reserved. # # SPDX-License-Identifier: MIT # @@ -30,12 +30,23 @@ S ?= "${WORKDIR}" FW_DIR ?= "" DTSI_PATH ?= "" DTBO_PATH ?= "" +BIT_PATH ?= "" +BIN_PATH ?= "" +PDI_PATH ?= "" +JSON_PATH ?= "" +XCl_PATH ?= "" DT_FILES_PATH = "${S}/${DTSI_PATH}" FIRMWARE_NAME_DT_FILE ?= "" USER_DTS_FILE ?= "" FIRMWARE_NAME_DT_FILE[doc] = "DT file which has firmware-name device-tree property" USER_DTS_FILE[doc] = "Final DTSI or DTS file which is used for packaging final DT overlay" +DTSI_PATH[doc] = "Absolute '.dtsi' or ''.dts' file path as input to SRC_URI" +DTBO_PATH[doc] = "Absolute '.dtbo' file path as input to SRC_URI" +BIT_PATH[doc] = "Absolute '.bit' file path as input to SRC_URI" +BIN_PATH[doc] = "Absolute '.bin' file path as input to SRC_URI" +JSON_PATH[doc] = "Absolute '.json' file path as input to SRC_URI" +XCL_PATH[doc] = "Absolute '.xclbin' file path as input to SRC_URI" python() { import re @@ -50,26 +61,39 @@ python() { pdi_found = False # Required Inputs - if '.dtsi ' in d.getVar("SRC_URI") or '.dts ' in d.getVar("SRC_URI"): - dtsi_found = True - d.setVar("DTSI_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.dtsi' in a or '.dts' in a][0].lstrip('file://'))) - - if '.dtbo ' in d.getVar("SRC_URI"): - dtbo_found = True - d.setVar("DTBO_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.dtbo' in a][0].lstrip('file://'))) - - if soc_family == "zynq" or soc_family == "zynqmp": - if '.bit ' in d.getVar("SRC_URI"): - bit_found = True - d.setVar("BIT_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.bit' in a][0].lstrip('file://'))) - - if '.bin ' in d.getVar("SRC_URI"): - bin_found = True - d.setVar("BIN_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.bin' in a][0].lstrip('file://'))) - else: - if '.pdi ' in d.getVar("SRC_URI"): - pdi_found = True - d.setVar("PDI_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.pdi' in a][0].lstrip('file://'))) + for s in d.getVar("SRC_URI").split(): + if s.endswith(('.dtsi', '.dts')): + dtsi_found = True + d.setVar("DTSI_PATH",os.path.dirname(s.lstrip('file://'))) + if s.endswith('.dtbo'): + if dtbo_found: + bb.warn("More then one '.dtbo' file specified in SRC_URI.") + dtbo_found = True + d.setVar("DTBO_PATH",os.path.dirname(s.lstrip('file://'))) + if soc_family == "zynq" or soc_family == "zynqmp": + if s.endswith('.bit'): + if bit_found: + bb.warn("More then one '.bit' file specified in SRC_URI.") + bit_found = True + d.setVar("BIT_PATH",os.path.dirname(s.lstrip('file://'))) + if s.endswith('.bin'): + if bin_found: + bb.warn("More then one '.bin' file specified in SRC_URI.") + bin_found = True + d.setVar("BIN_PATH",os.path.dirname(s.lstrip('file://'))) + else: + if s.endswith('.pdi'): + if pdi_found: + bb.warn("More then one '.pdi' file specified in SRC_URI.") + pdi_found = True + d.setVar("PDI_PATH",os.path.dirname(s.lstrip('file://'))) + + # Optional input + if s.endswith('.json'): + d.setVar("JSON_PATH",os.path.dirname(s.lstrip('file://'))) + + if s.endswith('.xclbin'): + d.setVar("XCL_PATH",os.path.dirname(s.lstrip('file://'))) # Check for valid combination of input files in SRC_URI # Skip recipe if any of the below conditions are not satisfied. @@ -104,27 +128,14 @@ python() { raise bb.parse.SkipRecipe("Recipe has more than one '.dtsi' and zero '.dts' found, this is an unsupported use case") elif dts_count > 1: raise bb.parse.SkipRecipe("Recipe has more than one '.dts' and zero or more than one '.dtsi' found, this is an unsupported use case") - - # Optional input - if '.json ' in d.getVar("SRC_URI"): - d.setVar("JSON_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.json' in a][0].lstrip('file://'))) - - if '.xclbin ' in d.getVar("SRC_URI"): - d.setVar("XCL_PATH",os.path.dirname([a for a in d.getVar('SRC_URI').split() if '.xclbin' in a][0].lstrip('file://'))) } -# Function to get dts or dtsi file count. -def get_dt_count(d, dt_ext): - import glob - dt_count = sum(1 for f in glob.iglob((d.getVar('S') + (d.getVar('DTSI_PATH')) + '/*.' + dt_ext),recursive=True) if os.path.isfile(f)) - return dt_count - # Function to search for dt firmware-name property in dts or dtsi file. python find_firmware_file() { import glob pattern_fw = 'firmware-name' search_count = 0 - for dt_files in glob.iglob((d.getVar('S') + (d.getVar('DTSI_PATH')) + '/*.dts*'),recursive=True): + for dt_files in glob.iglob((d.getVar('S') + '/' + (d.getVar('DTSI_PATH')) + '/*.dts*'),recursive=True): with open(dt_files, "r") as f: current_fd = f.read() if pattern_fw in current_fd: @@ -147,9 +158,9 @@ python do_configure() { # Renaming firmware-name using $PN as bitstream/PDI will be renamed using # $PN when generating the bin/pdi file. - if os.path.isfile(d.getVar('S') + (d.getVar('DTSI_PATH') or '') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE')): - orig_dtsi = glob.glob(d.getVar('S')+ (d.getVar('DTSI_PATH') or '') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE'))[0] - new_dtsi = d.getVar('S') + '/pl.dtsi_firmwarename' + if os.path.isfile(d.getVar('S') + '/' + (d.getVar('DTSI_PATH') or '') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE')): + orig_dtsi = glob.glob(d.getVar('S') + '/' + (d.getVar('DTSI_PATH') or '') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE'))[0] + new_dtsi = d.getVar('S') + '/' + (d.getVar('DTSI_PATH') or '') + '/pl.dtsi_firmwarename' with open(new_dtsi, 'w') as newdtsi: with open(orig_dtsi) as olddtsi: for line in olddtsi: @@ -168,19 +179,17 @@ python devicetree_do_compile:append() { dtbo_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.dtbo'),recursive=True) if os.path.isfile(f)) bin_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.bin'),recursive=True) if os.path.isfile(f)) - # Skip devicetree do_compile task if input file is dtbo or bin in SRC_URI if not dtbo_count and not bin_count: # Convert .bit to .bin format only if dtsi is input. # In case of dtbo as input, bbclass doesn't know if firmware-name is .bit # or .bin format and corresponding file name. Hence we are not doing .bin # conversion. - if soc_family == 'zynq' or soc_family == 'zynqmp' and glob.glob(d.getVar('S') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE')): + if soc_family == 'zynq' or soc_family == 'zynqmp' and glob.glob(d.getVar('S') + '/' +(d.getVar('DTSI_PATH') or '') + '/' + d.getVar('FIRMWARE_NAME_DT_FILE')): pn = d.getVar('PN') biffile = pn + '.bif' - with open(biffile, 'w') as f: - f.write('all:\n{\n\t' + glob.glob(d.getVar('S')+(d.getVar('BIT_PATH') or '') + '/*.bit')[0] + '\n}') + f.write('all:\n{\n\t' + glob.glob(d.getVar('S') + '/' + (d.getVar('BIT_PATH') or '') + '/*.bit')[0] + '\n}') bootgenargs = ["bootgen"] + (d.getVar("BOOTGEN_FLAGS") or "").split() bootgenargs += ["-image", biffile, "-o", pn + ".bin"] @@ -193,7 +202,7 @@ python devicetree_do_compile:append() { # ${PN}.bin which matches the firmware name in dtbo and move # ${PN}.bin to ${B} directory. if soc_family == 'zynq': - src_bitbin_file = glob.glob(d.getVar('S') + (d.getVar('BIT_PATH') or '') + '/*.bin')[0] + src_bitbin_file = glob.glob(d.getVar('S') + '/' + (d.getVar('BIT_PATH') or '') + '/*.bin')[0] dst_bitbin_file = d.getVar('B') + '/' + pn + '.bin' shutil.move(src_bitbin_file, dst_bitbin_file) @@ -207,17 +216,15 @@ python devicetree_do_compile:append() { # overlay file. python find_user_dts_overlay_file() { import glob - dtbo_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.dtbo'),recursive=True) if os.path.isfile(f)) - dts_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.dts'),recursive=True) if os.path.isfile(f)) - dtsi_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.dtsi'),recursive=True) if os.path.isfile(f)) + dtbo_count = sum(1 for f in glob.iglob((d.getVar('S') + '/' + d.getVar('DTBO_PATH') + '/*.dtbo'),recursive=True) if os.path.isfile(f)) + dts_count = sum(1 for f in glob.iglob((d.getVar('S') + '/' + d.getVar('DTSI_PATH') + '/*.dts'),recursive=True) if os.path.isfile(f)) + dtsi_count = sum(1 for f in glob.iglob((d.getVar('S') + '/' + d.getVar('DTSI_PATH') + '/*.dtsi'),recursive=True) if os.path.isfile(f)) # Set USER_DTS_FILE if input file is dts/dtsi in SRC_URI else skip operation. if not dtbo_count and dts_count or dtsi_count: - dts_count = get_dt_count(d, 'dts') - dtsi_count = get_dt_count(d, 'dtsi') if dtsi_count == 1 and dts_count == 0: - dts_file = glob.glob(d.getVar('S')+ (d.getVar('DTSI_PATH') or '') + '/*.dtsi')[0] + dts_file = glob.glob(d.getVar('S') + '/' + (d.getVar('DTSI_PATH') or '') + '/*.dtsi')[0] elif dtsi_count >=0 and dts_count == 1: - dts_file = glob.glob(d.getVar('S')+ (d.getVar('DTSI_PATH') or '') + '/*.dts')[0] + dts_file = glob.glob(d.getVar('S') + '/' + (d.getVar('DTSI_PATH') or '') + '/*.dts')[0] else: dts_file = '' -- cgit v1.2.3-54-g00ecf From 27ca7b3556e18441db49e11e531badbc79168577 Mon Sep 17 00:00:00 2001 From: Sandeep Gundlupet Raju Date: Mon, 12 Feb 2024 09:41:23 -0700 Subject: fw-package.bbclass: Create new bbclass for fw packaging Create a new fw-package.bbclass which provides infrastructure to package and deploy firmware baremetal or freertos application elf or bin files to linux root filesystem under /lib/firmware(default) or /boot directory as per requirement. Signed-off-by: Sandeep Gundlupet Raju Signed-off-by: Mark Hatle --- meta-xilinx-core/classes-recipe/fw-package.bbclass | 94 ++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 meta-xilinx-core/classes-recipe/fw-package.bbclass (limited to 'meta-xilinx-core/classes-recipe') diff --git a/meta-xilinx-core/classes-recipe/fw-package.bbclass b/meta-xilinx-core/classes-recipe/fw-package.bbclass new file mode 100644 index 00000000..e9847d33 --- /dev/null +++ b/meta-xilinx-core/classes-recipe/fw-package.bbclass @@ -0,0 +1,94 @@ +# +# Copyright (C) 2024, Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: MIT +# +# This bbclass provides infrastructure to package and deploy firmware baremetal +# or freertos application elf or bin files to linux root filesystem under +# /lib/firmware directory. + +inherit deploy + +INHERIT_DEFAULT_DEPENDS = "1" + +# Since we're just copying, we can run any config. +COMPATIBLE_HOST = ".*" + +PACKAGE_ARCH = "${MACHINE_ARCH}" + +# Default expects the user to provide the fw app in the deploy directory. +# A machine, multiconfig, or local.conf should override this. +FW_NAME ??= "" +TARGET_MC ??= "" +FW_DEPENDS ??= "" +FW_MCDEPENDS ??= "" +FW_DEPLOY_DIR ??= "${DEPLOY_DIR_IMAGE}" +FW_DEPLOY_DIR[vardepsexclude] += "TOPDIR" +FW_IMAGE_NAME ??= "${FW_NAME}-${MACHINE}-${TARGET_MC}" + +# Default is for the multilib case (without the extension .elf/.bin) +FW_FILE ??= "${FW_DEPLOY_DIR}/${FW_IMAGE_NAME}" +FW_FILE[vardepsexclude] = "FW_DEPLOY_DIR" + +do_fetch[depends] += "${FW_DEPENDS}" +do_fetch[mcdepends] += "${FW_MCDEPENDS}" + +# Set default destination directory is /lib/firmware, user can change this value +# to /boot directory depending on requirement. +DESTDIR ??= "${nonarch_base_libdir}/firmware/xilinx" +SYSROOT_DIRS += "/boot" + +INSANE_SKIP:${PN} = "arch" +INSANE_SKIP:${PN}-dbg = "arch" + +# Disable buildpaths QA check warnings. +INSANE_SKIP:${PN} += "buildpaths" + +do_install() { + if [ ! -e ${FW_FILE}.elf ]; then + echo "Unable to find FW_FILE (${FW_FILE}.elf)" + exit 1 + fi + + install -Dm 0644 ${FW_FILE}.elf ${D}${DESTDIR}/${FW_IMAGE_NAME}.elf +} + +# If the item is already in OUR deploy_image_dir, nothing to deploy! +SHOULD_DEPLOY = "${@'false' if (d.getVar('FW_FILE')).startswith(d.getVar('DEPLOY_DIR_IMAGE')) else 'true'}" +do_deploy() { + # If the item is already in OUR deploy_image_dir, nothing to deploy! + if ${SHOULD_DEPLOY}; then + install -Dm 0644 ${FW_FILE}.elf ${DEPLOYDIR}/${FW_IMAGE_NAME}.elf + install -Dm 0644 ${FW_FILE}.bin ${DEPLOYDIR}/${FW_IMAGE_NAME}.bin + fi +} + +FILES:${PN} += "${DESTDIR}/${FW_IMAGE_NAME}*" + +def check_fw_vars(d): + # If both are blank, the user MUST pass in the path to the firmware! + if not d.getVar('FW_DEPENDS') and not d.getVar('FW_MCDEPENDS'): + # Don't cache this, as the items on disk can change! + d.setVar('BB_DONT_CACHE', '1') + + msg = "" + fail = False + if not os.path.exists(d.getVar('FW_FILE') + ".elf"): + msg = msg + "The expected file %s.elf is not available. " % d.getVar('FW_FILE') + fail = True + if not os.path.exists(d.getVar('FW_FILE') + ".bin"): + msg = msg + "The expected file %s.bin is not available. " % d.getVar('FW_FILE') + fail = True + if fail: + if not d.getVar('WITHIN_EXT_SDK'): + raise bb.parse.SkipRecipe("%s\nSee the meta-xilinx-core README." % msg) + else: + # We found the file, so be sure to track it + d.setVar('SRC_URI', 'file://${FW_FILE}.elf file://${FW_FILE}.bin') + d.setVarFlag('do_install', 'file-checksums', '${FW_FILE}.elf:True ${FW_FILE}.bin:True') + d.setVarFlag('do_deploy', 'file-checksums', '${FW_FILE}.elf:True ${FW_FILE}.bin:True') + +python() { + # Need to allow bbappends to change the check + check_fw_vars(d) +} -- cgit v1.2.3-54-g00ecf From c09d6fbc6f6eb486498d81aa1f191b4be4767d7a Mon Sep 17 00:00:00 2001 From: Sandeep Gundlupet Raju Date: Wed, 3 Apr 2024 13:56:33 -0600 Subject: dfx_user_dts.bbclass: Make bit or bin or pdi as required input 1. Make bit or bin or pdi as required input for firmware recipes. If bit or bin or pdi of respective soc_family is not included then raise bitbake parse skip recipe errors. 2. Check for absolute dtbo/bin/bit path if any of these files exits in SRC_URI. 3. Skip recipe if both dtbo and dts/dtsi found in SRC_URI. 4. Fix logic to convert from bit to bin for zynqmp or zynq soc family. Signed-off-by: Sandeep Gundlupet Raju Signed-off-by: Mark Hatle --- .../classes-recipe/dfx_user_dts.bbclass | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'meta-xilinx-core/classes-recipe') diff --git a/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass index 2b699d9d..188d594b 100644 --- a/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass +++ b/meta-xilinx-core/classes-recipe/dfx_user_dts.bbclass @@ -97,12 +97,15 @@ python() { # Check for valid combination of input files in SRC_URI # Skip recipe if any of the below conditions are not satisfied. - # 1. At least one bit or bin or pdi or dts or dtsi or dtbo should exists. + # 1. At least one bit or bin or pdi should exists. # 2. More than one dtbo. # 3. More than one bit or bin or pdi. # 4. More than one dts and zero dtsi. - # 5. More than one dtsi and zero dts. - if dtsi_found or dtbo_found or bit_found or bin_found or pdi_found: + # 5. More than one dtsi and zero dts + # 6. Both bit and bin exists. + # 7. Both bit or bin and pdi exits. + # 8. Both dts or dtsi and dtbo exists. + if bit_found or bin_found or pdi_found: bb.debug(2, "dtsi or dtbo or bitstream or pdi found in SRC_URI") if bit_found and pdi_found : raise bb.parse.SkipRecipe("Both '.bit' and '.pdi' file found in SRC_URI, this is invalid use case.") @@ -112,8 +115,11 @@ python() { if bit_found and bin_found: raise bb.parse.SkipRecipe("Both '.bit' and '.bin' file found in SRC_URI, either .bit or .bin file is supported but not both.") + + if dtsi_found and dtbo_found: + raise bb.parse.SkipRecipe("Both '.dts or dtsi' and '.dtbo' file found in SRC_URI, either .dts/dtsi or .dtbo file is supported but not both.") else: - raise bb.parse.SkipRecipe("Need one '.dtsi' or '.dtbo' or '.bit' or '.bin' or '.pdi' file added to SRC_URI ") + raise bb.parse.SkipRecipe("Need one '.bit' or '.bin' or '.pdi' file added to SRC_URI.") # Check for valid combination of dtsi and dts files in SRC_URI # Following file combinations are not supported use case. @@ -177,10 +183,11 @@ python devicetree_do_compile:append() { import glob, subprocess, shutil soc_family = d.getVar("SOC_FAMILY") - dtbo_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.dtbo'),recursive=True) if os.path.isfile(f)) - bin_count = sum(1 for f in glob.iglob((d.getVar('S') + '/*.bin'),recursive=True) if os.path.isfile(f)) + dtbo_count = sum(1 for f in glob.iglob((d.getVar('S') + '/' + (d.getVar('DTSI_PATH') or '') + '/*.dtbo'),recursive=True) if os.path.isfile(f)) + bin_count = sum(1 for f in glob.iglob((d.getVar('S') + '/' + (d.getVar('BIN_PATH') or '') + '/*.bin'),recursive=True) if os.path.isfile(f)) + bit_count = sum(1 for f in glob.iglob((d.getVar('S') + '/' + (d.getVar('BIT_PATH') or '') + '/*.bit'),recursive=True) if os.path.isfile(f)) # Skip devicetree do_compile task if input file is dtbo or bin in SRC_URI - if not dtbo_count and not bin_count: + if not dtbo_count and not bin_count and bit_count: # Convert .bit to .bin format only if dtsi is input. # In case of dtbo as input, bbclass doesn't know if firmware-name is .bit # or .bin format and corresponding file name. Hence we are not doing .bin -- cgit v1.2.3-54-g00ecf