merge_dtbs: Sort DTBOs based on needed symbols

Some DTBOs might use symbols from other DTBOs and require them to be
applied before them.

Sort them based on the __symbols__ and __fixups__ nodes, by creating a
dependency graph.

Change-Id: I40acf5da6b673b636a91f75ae3f3c634f2b5c505
This commit is contained in:
Cosmin Tanislav
2025-06-08 15:15:07 +03:00
parent 722d1ce1be
commit 0ea2a44fbc

View File

@@ -29,6 +29,7 @@
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import copy import copy
import graphlib
import os import os
import sys import sys
import subprocess import subprocess
@@ -291,6 +292,14 @@ class DeviceTree(DeviceTreeInfo):
if not self.has_any_properties(): if not self.has_any_properties():
logging.warning('{} has no properties and may match with any other devicetree'.format(os.path.basename(self.filename))) logging.warning('{} has no properties and may match with any other devicetree'.format(os.path.basename(self.filename)))
def list_props(self, node):
r = subprocess.run(["fdtget", "-p", self.filename, node],
check=False, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
if r.returncode != 0:
return []
out = r.stdout.decode("utf-8").strip()
return out.splitlines()[:-1]
def get_prop(self, node, property, prop_type='i', check_output=True): def get_prop(self, node, property, prop_type='i', check_output=True):
r = subprocess.run(["fdtget", "-t", prop_type, self.filename, node, property], r = subprocess.run(["fdtget", "-t", prop_type, self.filename, node, property],
check=check_output, stdout=subprocess.PIPE, check=check_output, stdout=subprocess.PIPE,
@@ -458,6 +467,25 @@ class MergedDeviceTree(object):
for mdt in self.merged_devicetrees: for mdt in self.merged_devicetrees:
yield mdt.save(name, out_dir) yield mdt.save(name, out_dir)
def create_adjacency(devicetrees):
graph = {}
symbol_map = {}
for dt in devicetrees:
for symbol in dt.list_props('/__symbols__'):
symbol_map.setdefault(symbol, []).append(dt.filename)
for dt in devicetrees:
graph[dt.filename] = set()
for fixup in dt.list_props('/__fixups__'):
if fixup not in symbol_map:
continue
graph[dt.filename].update(symbol_map[fixup])
return graph
def parse_dt_files(dt_folder): def parse_dt_files(dt_folder):
devicetrees = [] devicetrees = []
for root, dirs, files in os.walk(dt_folder): for root, dirs, files in os.walk(dt_folder):
@@ -468,6 +496,14 @@ def parse_dt_files(dt_folder):
devicetrees.append(DeviceTree(filepath)) devicetrees.append(DeviceTree(filepath))
return devicetrees return devicetrees
def parse_tech_dt_files(dt_folder):
devicetrees = parse_dt_files(dt_folder)
graph = create_adjacency(devicetrees)
order = graphlib.TopologicalSorter(graph).static_order()
order_index = {node: i for i, node in enumerate(order)}
devicetrees.sort(key=lambda dt: order_index[dt.filename])
return devicetrees
def main(): def main():
parser = argparse.ArgumentParser(description='Merge devicetree blobs of techpacks with Kernel Platform SoCs') parser = argparse.ArgumentParser(description='Merge devicetree blobs of techpacks with Kernel Platform SoCs')
@@ -487,7 +523,7 @@ def main():
logging.info('Parsed bases: \n{}'.format(all_bases)) logging.info('Parsed bases: \n{}'.format(all_bases))
logging.info('Parsing techpack dtb files from {}'.format(args.techpack)) logging.info('Parsing techpack dtb files from {}'.format(args.techpack))
techpacks = parse_dt_files(args.techpack) techpacks = parse_tech_dt_files(args.techpack)
all_techpacks = '\n'.join(list(map(lambda x: str(x), techpacks))) all_techpacks = '\n'.join(list(map(lambda x: str(x), techpacks)))
logging.info('Parsed techpacks: \n{}'.format(all_techpacks)) logging.info('Parsed techpacks: \n{}'.format(all_techpacks))