summaryrefslogtreecommitdiffstats
path: root/meta/classes-recipe/devicetree.bbclass
blob: 1806cb62cbf793280b5fdedae5811c0dd09287c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#
# Copyright OpenEmbedded Contributors
#
# SPDX-License-Identifier: MIT
#

# This bbclass implements device tree compilation for user provided device tree
# sources. The compilation of the device tree sources is the same as the kernel
# device tree compilation process, this includes being able to include sources
# from the kernel such as soc dtsi files or header files such as gpio.h. In
# addition to device trees this bbclass also handles compilation of device tree
# overlays.
#
# The output of this class behaves similar to how kernel-devicetree.bbclass
# operates in that the output files are installed into /boot/devicetree.
# However this class on purpose separates the deployed device trees into the
# 'devicetree' subdirectory. This prevents clashes with the kernel-devicetree
# output. Additionally the device trees are populated into the sysroot for
# access via the sysroot from within other recipes.

SECTION ?= "bsp"

# The default inclusion of kernel device tree includes and headers means that
# device trees built with them are at least GPL-2.0-only (and in some cases dual
# licensed). Default to GPL-2.0-only if the recipe does not specify a license.
LICENSE ?= "GPL-2.0-only"
LIC_FILES_CHKSUM ?= "file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6"

INHIBIT_DEFAULT_DEPS = "1"
DEPENDS += "dtc-native"

inherit deploy kernel-arch

COMPATIBLE_MACHINE ?= "^$"

PROVIDES = "virtual/dtb"

PACKAGE_ARCH = "${MACHINE_ARCH}"

SYSROOT_DIRS += "/boot/devicetree"
FILES:${PN} = "/boot/devicetree/*.dtb /boot/devicetree/*.dtbo"

S = "${WORKDIR}/sources"
UNPACKDIR = "${S}"
B = "${WORKDIR}/build"

# Default kernel includes, these represent what are normally used for in-kernel
# sources.
KERNEL_INCLUDE ??= " \
        ${STAGING_KERNEL_DIR}/arch/${ARCH}/boot/dts \
        ${STAGING_KERNEL_DIR}/arch/${ARCH}/boot/dts/* \
        ${STAGING_KERNEL_DIR}/scripts/dtc/include-prefixes \
        "

DT_INCLUDE[doc] = "Search paths to be made available to both the device tree compiler and preprocessor for inclusion."
DT_INCLUDE ?= "${DT_FILES_PATH} ${KERNEL_INCLUDE}"
DT_FILES_PATH[doc] = "Path to the directory containing dts files to build. Defaults to source directory."
DT_FILES_PATH ?= "${S}"
DT_FILES[doc] = "Space-separated list of dts or dtb files (relative to DT_FILES_PATH) to build. If empty, all dts files are built."
DT_FILES ?= ""

DT_PADDING_SIZE[doc] = "Size of padding on the device tree blob, used as extra space typically for additional properties during boot."
DT_PADDING_SIZE ??= "0x3000"
DT_RESERVED_MAP[doc] = "Number of reserved map entires."
DT_RESERVED_MAP ??= "8"
DT_BOOT_CPU[doc] = "The boot cpu, defaults to 0"
DT_BOOT_CPU ??= "0"

DTC_FLAGS ?= "-R ${DT_RESERVED_MAP} -b ${DT_BOOT_CPU}"
DTC_PPFLAGS ?= "-nostdinc -undef -D__DTS__ -x assembler-with-cpp"
DTC_BFLAGS ?= "-p ${DT_PADDING_SIZE} -@"
DTC_OFLAGS ?= "-p 0 -@ -H epapr"

python () {
    if d.getVar("KERNEL_INCLUDE"):
        # auto add dependency on kernel tree, but only if kernel include paths
        # are specified.
        d.appendVarFlag("do_compile", "depends", " virtual/kernel:do_configure")
}

def expand_includes(varname, d):
    import glob
    includes = set()
    # expand all includes with glob
    for i in (d.getVar(varname) or "").split():
        for g in glob.glob(i):
            if os.path.isdir(g): # only add directories to include path
                includes.add(g)
    return includes

def devicetree_source_is_overlay(path):
    # determine if a dts file is an overlay by checking if it uses "/plugin/;"
    with open(path, "r") as f:
        for i in f:
            if i.startswith("/plugin/;"):
                return True
    return False

def devicetree_compile(dtspath, includes, d):
    import subprocess
    dts = os.path.basename(dtspath)
    dtname = os.path.splitext(dts)[0]
    bb.note("Processing {0} [{1}]".format(dtname, dts))

    # preprocess
    ppargs = d.getVar("BUILD_CPP").split()
    ppargs += (d.getVar("DTC_PPFLAGS") or "").split()
    for i in includes:
        ppargs.append("-I{0}".format(i))
    ppargs += ["-o", "{0}.pp".format(dts), dtspath]
    bb.note("Running {0}".format(" ".join(ppargs)))
    subprocess.run(ppargs, check = True)

    # determine if the file is an overlay or not (using the preprocessed file)
    isoverlay = devicetree_source_is_overlay("{0}.pp".format(dts))

    # compile
    dtcargs = ["dtc"] + (d.getVar("DTC_FLAGS") or "").split()
    if isoverlay:
        dtcargs += (d.getVar("DTC_OFLAGS") or "").split()
    else:
        dtcargs += (d.getVar("DTC_BFLAGS") or "").split()
    for i in includes:
        dtcargs += ["-i", i]
    dtcargs += ["-o", "{0}.{1}".format(dtname, "dtbo" if isoverlay else "dtb")]
    dtcargs += ["-I", "dts", "-O", "dtb", "{0}.pp".format(dts)]
    bb.note("Running {0}".format(" ".join(dtcargs)))
    subprocess.run(dtcargs, check = True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

python devicetree_do_compile() {
    import re
    includes = expand_includes("DT_INCLUDE", d)
    dtfiles = d.getVar("DT_FILES").split()
    dtfiles = [ re.sub(r"\.dtbo?$", ".dts", dtfile) for dtfile in dtfiles ]
    listpath = d.getVar("DT_FILES_PATH")
    for dts in dtfiles or os.listdir(listpath):
        dtspath = os.path.join(listpath, dts)
        try:
            if not(os.path.isfile(dtspath)) or not(dts.endswith(".dts") or devicetree_source_is_overlay(dtspath)):
                continue # skip non-.dts files and non-overlay files
        except:
            continue # skip if can't determine if overlay
        devicetree_compile(dtspath, includes, d)
}

devicetree_do_install() {
    for DTB_FILE in `ls *.dtb *.dtbo`; do
        install -Dm 0644 ${B}/${DTB_FILE} ${D}/boot/devicetree/${DTB_FILE}
    done
}

devicetree_do_deploy() {
    for DTB_FILE in `ls *.dtb *.dtbo`; do
        install -Dm 0644 ${B}/${DTB_FILE} ${DEPLOYDIR}/devicetree/${DTB_FILE}
    done
}
addtask deploy before do_build after do_install

EXPORT_FUNCTIONS do_compile do_install do_deploy