Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scripts: dts: Refactor gen_driver_kconfig_dts #83878

Merged
merged 1 commit into from
Jan 19, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 37 additions & 45 deletions scripts/dts/gen_driver_kconfig_dts.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#!/usr/bin/env python3
#
# Copyright (c) 2022 Kumar Gala <[email protected]>
# Copyright (c) 2025 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0

import argparse
import os
import sys
import re

import yaml
try:
Expand All @@ -16,22 +15,33 @@
except ImportError:
from yaml import SafeLoader # type: ignore

sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'python-devicetree',
'src'))

def binding_paths(bindings_dirs):
# Returns a list with the paths to all bindings (.yaml files) in
# 'bindings_dirs'
HEADER = """\
# Generated devicetree Kconfig
#
# SPDX-License-Identifier: Apache-2.0"""


KCONFIG_TEMPLATE = """
DT_COMPAT_{COMPAT} := {compat}

config DT_HAS_{COMPAT}_ENABLED
\tdef_bool $(dt_compat_enabled,$(DT_COMPAT_{COMPAT}))"""

binding_paths = []

# Character translation table used to derive Kconfig symbol names
TO_UNDERSCORES = str.maketrans("-,.@/+", "______")


def binding_paths(bindings_dirs):
# Yields paths to all bindings (.yaml files) in 'bindings_dirs'

for bindings_dir in bindings_dirs:
for root, _, filenames in os.walk(bindings_dir):
for filename in filenames:
if filename.endswith(".yaml") or filename.endswith(".yml"):
binding_paths.append(os.path.join(root, filename))
if filename.endswith((".yaml", ".yml")):
yield os.path.join(root, filename)

return binding_paths

def parse_args():
# Returns parsed command-line arguments
Expand All @@ -45,56 +55,38 @@ def parse_args():

return parser.parse_args()

def printfile(s):
print(s, file=kconfig_file)

def str2ident(s):
# Converts 's' to a form suitable for (part of) an identifier

return re.sub('[-,.@/+]', '_', s.upper())

def compat2kconfig(compat):
compat_ident = str2ident(compat)

printfile(f'')
printfile(f'DT_COMPAT_{compat_ident} := {compat}')
printfile(f'')
printfile(f'config DT_HAS_{compat_ident}_ENABLED')
printfile(f'\tdef_bool $(dt_compat_enabled,$(DT_COMPAT_{compat_ident}))')

def main():
global kconfig_file
args = parse_args()

compat_list = []
compats = set()

for binding_path in binding_paths(args.bindings_dirs):
with open(binding_path, encoding="utf-8") as f:
contents = f.read()

try:
# Parsed PyYAML output (Python lists/dictionaries/strings/etc.,
# representing the file)
raw = yaml.load(contents, Loader=SafeLoader)
# Parsed PyYAML representation graph. For our purpose,
# we don't need the whole file converted into a dict.
root = yaml.compose(f, Loader=SafeLoader)
except yaml.YAMLError as e:
print(f"WARNING: '{binding_path}' appears in binding "
f"directories but isn't valid YAML: {e}")
continue
if raw is None or 'compatible' not in raw:
continue

compat_list.append(raw['compatible'])

# Remove any duplicates and sort the list
compat_list = sorted(set(compat_list))
if not isinstance(root, yaml.MappingNode):
continue
for key, node in root.value:
if key.value == "compatible" and isinstance(node, yaml.ScalarNode):
compats.add(node.value)
break

with open(args.kconfig_out, "w", encoding="utf-8") as kconfig_file:
printfile(f'# Generated devicetree Kconfig')
printfile(f'#')
printfile(f'# SPDX-License-Identifier: Apache-2.0')
print(HEADER, file=kconfig_file)

for c in compat_list:
compat2kconfig(c)
for c in sorted(compats):
out = KCONFIG_TEMPLATE.format(
compat=c, COMPAT=c.upper().translate(TO_UNDERSCORES)
)
print(out, file=kconfig_file)


if __name__ == "__main__":
Expand Down
Loading