1# This bbclass implements device tree compliation for user provided device tree 2# sources. The compilation of the device tree sources is the same as the kernel 3# device tree compilation process, this includes being able to include sources 4# from the kernel such as soc dtsi files or header files such as gpio.h. In 5# addition to device trees this bbclass also handles compilation of device tree 6# overlays. 7# 8# The output of this class behaves similar to how kernel-devicetree.bbclass 9# operates in that the output files are installed into /boot/devicetree. 10# However this class on purpose separates the deployed device trees into the 11# 'devicetree' subdirectory. This prevents clashes with the kernel-devicetree 12# output. Additionally the device trees are populated into the sysroot for 13# access via the sysroot from within other recipes. 14 15SECTION ?= "bsp" 16 17# The default inclusion of kernel device tree includes and headers means that 18# device trees built with them are at least GPL-2.0-only (and in some cases dual 19# licensed). Default to GPL-2.0-only if the recipe does not specify a license. 20LICENSE ?= "GPL-2.0-only" 21LIC_FILES_CHKSUM ?= "file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6" 22 23INHIBIT_DEFAULT_DEPS = "1" 24DEPENDS += "dtc-native" 25 26inherit deploy kernel-arch 27 28COMPATIBLE_MACHINE ?= "^$" 29 30PROVIDES = "virtual/dtb" 31 32PACKAGE_ARCH = "${MACHINE_ARCH}" 33 34SYSROOT_DIRS += "/boot/devicetree" 35FILES:${PN} = "/boot/devicetree/*.dtb /boot/devicetree/*.dtbo" 36 37S = "${WORKDIR}" 38B = "${WORKDIR}/build" 39 40# Default kernel includes, these represent what are normally used for in-kernel 41# sources. 42KERNEL_INCLUDE ??= " \ 43 ${STAGING_KERNEL_DIR}/arch/${ARCH}/boot/dts \ 44 ${STAGING_KERNEL_DIR}/arch/${ARCH}/boot/dts/* \ 45 ${STAGING_KERNEL_DIR}/scripts/dtc/include-prefixes \ 46 " 47 48DT_INCLUDE[doc] = "Search paths to be made available to both the device tree compiler and preprocessor for inclusion." 49DT_INCLUDE ?= "${DT_FILES_PATH} ${KERNEL_INCLUDE}" 50DT_FILES_PATH[doc] = "Defaults to source directory, can be used to select dts files that are not in source (e.g. generated)." 51DT_FILES_PATH ?= "${S}" 52 53DT_PADDING_SIZE[doc] = "Size of padding on the device tree blob, used as extra space typically for additional properties during boot." 54DT_PADDING_SIZE ??= "0x3000" 55DT_RESERVED_MAP[doc] = "Number of reserved map entires." 56DT_RESERVED_MAP ??= "8" 57DT_BOOT_CPU[doc] = "The boot cpu, defaults to 0" 58DT_BOOT_CPU ??= "0" 59 60DTC_FLAGS ?= "-R ${DT_RESERVED_MAP} -b ${DT_BOOT_CPU}" 61DTC_PPFLAGS ?= "-nostdinc -undef -D__DTS__ -x assembler-with-cpp" 62DTC_BFLAGS ?= "-p ${DT_PADDING_SIZE} -@" 63DTC_OFLAGS ?= "-p 0 -@ -H epapr" 64 65python () { 66 if d.getVar("KERNEL_INCLUDE"): 67 # auto add dependency on kernel tree, but only if kernel include paths 68 # are specified. 69 d.appendVarFlag("do_compile", "depends", " virtual/kernel:do_configure") 70} 71 72def expand_includes(varname, d): 73 import glob 74 includes = set() 75 # expand all includes with glob 76 for i in (d.getVar(varname) or "").split(): 77 for g in glob.glob(i): 78 if os.path.isdir(g): # only add directories to include path 79 includes.add(g) 80 return includes 81 82def devicetree_source_is_overlay(path): 83 # determine if a dts file is an overlay by checking if it uses "/plugin/;" 84 with open(path, "r") as f: 85 for i in f: 86 if i.startswith("/plugin/;"): 87 return True 88 return False 89 90def devicetree_compile(dtspath, includes, d): 91 import subprocess 92 dts = os.path.basename(dtspath) 93 dtname = os.path.splitext(dts)[0] 94 bb.note("Processing {0} [{1}]".format(dtname, dts)) 95 96 # preprocess 97 ppargs = d.getVar("BUILD_CPP").split() 98 ppargs += (d.getVar("DTC_PPFLAGS") or "").split() 99 for i in includes: 100 ppargs.append("-I{0}".format(i)) 101 ppargs += ["-o", "{0}.pp".format(dts), dtspath] 102 bb.note("Running {0}".format(" ".join(ppargs))) 103 subprocess.run(ppargs, check = True) 104 105 # determine if the file is an overlay or not (using the preprocessed file) 106 isoverlay = devicetree_source_is_overlay("{0}.pp".format(dts)) 107 108 # compile 109 dtcargs = ["dtc"] + (d.getVar("DTC_FLAGS") or "").split() 110 if isoverlay: 111 dtcargs += (d.getVar("DTC_OFLAGS") or "").split() 112 else: 113 dtcargs += (d.getVar("DTC_BFLAGS") or "").split() 114 for i in includes: 115 dtcargs += ["-i", i] 116 dtcargs += ["-o", "{0}.{1}".format(dtname, "dtbo" if isoverlay else "dtb")] 117 dtcargs += ["-I", "dts", "-O", "dtb", "{0}.pp".format(dts)] 118 bb.note("Running {0}".format(" ".join(dtcargs))) 119 subprocess.run(dtcargs, check = True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 120 121python devicetree_do_compile() { 122 includes = expand_includes("DT_INCLUDE", d) 123 listpath = d.getVar("DT_FILES_PATH") 124 for dts in os.listdir(listpath): 125 dtspath = os.path.join(listpath, dts) 126 try: 127 if not(os.path.isfile(dtspath)) or not(dts.endswith(".dts") or devicetree_source_is_overlay(dtspath)): 128 continue # skip non-.dts files and non-overlay files 129 except: 130 continue # skip if can't determine if overlay 131 devicetree_compile(dtspath, includes, d) 132} 133 134devicetree_do_install() { 135 for DTB_FILE in `ls *.dtb *.dtbo`; do 136 install -Dm 0644 ${B}/${DTB_FILE} ${D}/boot/devicetree/${DTB_FILE} 137 done 138} 139 140devicetree_do_deploy() { 141 for DTB_FILE in `ls *.dtb *.dtbo`; do 142 install -Dm 0644 ${B}/${DTB_FILE} ${DEPLOYDIR}/devicetree/${DTB_FILE} 143 done 144} 145addtask deploy before do_build after do_install 146 147EXPORT_FUNCTIONS do_compile do_install do_deploy 148 149