Devicetree DTS and YAML format improvements (#492)
* **DevicetreeCompiler** * Binding properties now support default values. * Compiler returns meaningful exit codes and reports errors more clearly. * Stronger validation of device configurations with unified error handling. * Added integration tests and a dedicated Devicetree test workflow. * **Changes** * Platform binding schemas updated: some fields made required, others gained explicit defaults. * Many device-tree files simplified by removing unused/placeholder pin and transfer-size entries. * **Documentation** * Removed several outdated TODO items.
This commit is contained in:
committed by
GitHub
parent
d27404964a
commit
93efadd5e3
@@ -1,7 +1,7 @@
|
||||
import os.path
|
||||
from textwrap import dedent
|
||||
|
||||
from source.models import *
|
||||
from .exception import DevicetreeException
|
||||
|
||||
def write_include(file, include: IncludeC, verbose: bool):
|
||||
if verbose:
|
||||
@@ -26,9 +26,9 @@ def get_device_node_name_safe(device: Device):
|
||||
def get_device_type_name(device: Device, bindings: list[Binding]):
|
||||
device_binding = find_device_binding(device, bindings)
|
||||
if device_binding is None:
|
||||
raise Exception(f"Binding not found for {device.node_name}")
|
||||
raise DevicetreeException(f"Binding not found for {device.node_name}")
|
||||
if device_binding.compatible is None:
|
||||
raise Exception(f"Couldn't find compatible binding for {device.node_name}")
|
||||
raise DevicetreeException(f"Couldn't find compatible binding for {device.node_name}")
|
||||
compatible_safe = device_binding.compatible.split(",")[-1]
|
||||
return compatible_safe.replace("-", "_")
|
||||
|
||||
@@ -41,7 +41,7 @@ def find_device_property(device: Device, name: str) -> DeviceProperty:
|
||||
def find_device_binding(device: Device, bindings: list[Binding]) -> Binding:
|
||||
compatible_property = find_device_property(device, "compatible")
|
||||
if compatible_property is None:
|
||||
raise Exception(f"property 'compatible' not found in device {device.node_name}")
|
||||
raise DevicetreeException(f"property 'compatible' not found in device {device.node_name}")
|
||||
for binding in bindings:
|
||||
if binding.compatible == compatible_property.value:
|
||||
return binding
|
||||
@@ -57,44 +57,69 @@ def find_phandle(devices: list[Device], phandle: str):
|
||||
for device in devices:
|
||||
if device.node_name == phandle or device.node_alias == phandle:
|
||||
return f"&{get_device_node_name_safe(device)}"
|
||||
raise Exception(f"phandle '{phandle}' not found in device tree")
|
||||
raise DevicetreeException(f"phandle '{phandle}' not found in device tree")
|
||||
|
||||
def property_to_string(property: DeviceProperty, devices: list[Device]) -> str:
|
||||
type = property.type
|
||||
if type == "value":
|
||||
if type == "value" or type == "int":
|
||||
return property.value
|
||||
elif type == "boolean":
|
||||
elif type == "boolean" or type == "bool":
|
||||
return "true"
|
||||
elif type == "text":
|
||||
return f"\"{property.value}\""
|
||||
elif type == "values":
|
||||
return "{ " + ",".join(property.value) + " }"
|
||||
value_list = list()
|
||||
for item in property.value:
|
||||
if isinstance(item, PropertyValue):
|
||||
value_list.append(property_to_string(DeviceProperty(name="", type=item.type, value=item.value), devices))
|
||||
else:
|
||||
value_list.append(str(item))
|
||||
return "{ " + ",".join(value_list) + " }"
|
||||
elif type == "phandle":
|
||||
return find_phandle(devices, property.value)
|
||||
else:
|
||||
raise Exception(f"property_to_string() has an unsupported type: {type}")
|
||||
raise DevicetreeException(f"property_to_string() has an unsupported type: {type}")
|
||||
|
||||
def resolve_parameters_from_bindings(device: Device, bindings: list[Binding], devices: list[Device]) -> list:
|
||||
compatible_property = find_device_property(device, "compatible")
|
||||
if compatible_property is None:
|
||||
raise Exception(f"Cannot find 'compatible' property for {device.node_name}")
|
||||
raise DevicetreeException(f"Cannot find 'compatible' property for {device.node_name}")
|
||||
device_binding = find_binding(compatible_property.value, bindings)
|
||||
if device_binding is None:
|
||||
raise Exception(f"Binding not found for {device.node_name} and compatible '{compatible_property.value}'")
|
||||
raise DevicetreeException(f"Binding not found for {device.node_name} and compatible '{compatible_property.value}'")
|
||||
# Filter out system properties
|
||||
binding_properties = []
|
||||
binding_property_names = set()
|
||||
for property in device_binding.properties:
|
||||
if property.name != "compatible":
|
||||
binding_properties.append(property)
|
||||
binding_property_names.add(property.name)
|
||||
|
||||
# Check for invalid properties in device
|
||||
for device_property in device.properties:
|
||||
if device_property.name in ["compatible"]:
|
||||
continue
|
||||
if device_property.name not in binding_property_names:
|
||||
raise DevicetreeException(f"Device '{device.node_name}' has invalid property '{device_property.name}'")
|
||||
|
||||
# Allocate total expected configuration arguments
|
||||
result = [0] * len(binding_properties)
|
||||
for index, binding_property in enumerate(binding_properties):
|
||||
device_property = find_device_property(device, binding_property.name)
|
||||
if device_property is None:
|
||||
if binding_property.required:
|
||||
raise Exception(f"device {device.node_name} doesn't have property '{binding_property.name}'")
|
||||
if binding_property.default is not None:
|
||||
temp_prop = DeviceProperty(
|
||||
name=binding_property.name,
|
||||
type=binding_property.type,
|
||||
value=binding_property.default
|
||||
)
|
||||
result[index] = property_to_string(temp_prop, devices)
|
||||
elif binding_property.required:
|
||||
raise DevicetreeException(f"device {device.node_name} doesn't have property '{binding_property.name}'")
|
||||
elif binding_property.type == "bool":
|
||||
result[index] = "false"
|
||||
else:
|
||||
result[index] = '0'
|
||||
raise DevicetreeException(f"Device {device.node_name} doesn't have property '{binding_property.name}' and no default value is set")
|
||||
else:
|
||||
result[index] = property_to_string(device_property, devices)
|
||||
return result
|
||||
@@ -121,7 +146,7 @@ def write_device_structs(file, device: Device, parent_device: Device, bindings:
|
||||
type_name = get_device_type_name(device, bindings)
|
||||
compatible_property = find_device_property(device, "compatible")
|
||||
if compatible_property is None:
|
||||
raise Exception(f"Cannot find 'compatible' property for {device.node_name}")
|
||||
raise DevicetreeException(f"Cannot find 'compatible' property for {device.node_name}")
|
||||
node_name = get_device_node_name_safe(device)
|
||||
config_variable_name = f"{node_name}_config"
|
||||
if parent_device is not None:
|
||||
@@ -148,7 +173,7 @@ def write_device_init(file, device: Device, bindings: list[Binding], verbose: bo
|
||||
# Assemble some pre-requisites
|
||||
compatible_property = find_device_property(device, "compatible")
|
||||
if compatible_property is None:
|
||||
raise Exception(f"Cannot find 'compatible' property for {device.node_name}")
|
||||
raise DevicetreeException(f"Cannot find 'compatible' property for {device.node_name}")
|
||||
# Type & instance names
|
||||
node_name = get_device_node_name_safe(device)
|
||||
device_variable = node_name
|
||||
|
||||
Reference in New Issue
Block a user