From 13f75b383a730b3f7d1dedcf24ded2f6e6157ef9 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 25 Apr 2020 11:14:14 +0200 Subject: [PATCH 001/505] tools/dt-extract-example: support examples with root node Examples are prefixed with boiler plate in the normal case. In the rare case a root node is required this boiler plate shall not be used. Example with root node: / { chosen { ...; } } Teach the script to recognize that the example starts with a root node and avoid the boiler plate in such cases. The root node is recognized using a simple regular expression search. Signed-off-by: Sam Ravnborg --- tools/dt-extract-example | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tools/dt-extract-example b/tools/dt-extract-example index 99e59c37..0e933e4f 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -4,6 +4,7 @@ # Copyright 2019 Arm Ltd. import os +import re import sys import ruamel.yaml import argparse @@ -17,11 +18,14 @@ example_template = """ {example} }}; +}}; """ example_header = """ /dts-v1/; /plugin/; // silence any missing phandle references +""" +example_start = """ /{ compatible = "foo"; model = "foo"; @@ -49,7 +53,15 @@ if __name__ == "__main__": if 'examples' in binding.keys(): for idx,ex in enumerate(binding['examples']): - ex = ' '.join(ex.splitlines(True)) - print(example_template.format(example=ex,example_num=idx)) + # Check if example contains a root node "/{" + root_node = re.search('^/\s*{', ex) - print("\n};") + if not root_node: + print(example_start) + ex = ' '.join(ex.splitlines(True)) + print(example_template.format(example=ex,example_num=idx)) + else: + print(ex) + else: + print(example_start) + print("\n};") From 53d4204d0f1aa0b63122de9c2cf31491af93fae0 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 25 Apr 2020 11:20:33 +0200 Subject: [PATCH 002/505] tools/dt-extract-example: beautify output Fix so first line in the output has same indent as the rest of the lines in the example. This makes the examples a little easier to read. Signed-off-by: Sam Ravnborg --- tools/dt-extract-example | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/dt-extract-example b/tools/dt-extract-example index 0e933e4f..f1a222fe 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -15,8 +15,7 @@ example_template = """ #address-cells = <1>; #size-cells = <1>; -{example} - + {example} }}; }}; """ From 6a941d46b9f522feee0371134e917e185cb33105 Mon Sep 17 00:00:00 2001 From: jamesequinlan <64660907+jamesequinlan@users.noreply.github.com> Date: Fri, 1 May 2020 15:31:31 -0400 Subject: [PATCH 003/505] schemas: pci-bus: add optional prop 'aspm-no-ls' When present, indicates that the L0s component of ASPM should be disabled. --- schemas/pci/pci-bus.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/schemas/pci/pci-bus.yaml b/schemas/pci/pci-bus.yaml index 32afb28d..87c5b476 100644 --- a/schemas/pci/pci-bus.yaml +++ b/schemas/pci/pci-bus.yaml @@ -114,6 +114,10 @@ properties: supports-clkreq: type: boolean + aspm-no-l0s: + description: Disables ASPM L0s capability + type: boolean + vendor-id: description: The PCI vendor ID allOf: From a480bac366ad8ee0b522f70770f87483329662f7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 6 May 2020 17:13:09 -0500 Subject: [PATCH 004/505] Support schema with 'typeSize' of 32 Currently only schema with 'typeSize' only work for explicit YAML tags, but 32-bit values don't have an explicit size tag. For 64-bit types, we need to distinguish 32-bit values as 64-bit types can be represented as 2 32-bit values. Signed-off-by: Rob Herring --- dtschema/lib.py | 4 ++++ schemas/types.yaml | 1 + test/device.yaml | 2 ++ test/schemas/good-example.yaml | 5 +++++ 4 files changed, 12 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index dce788c2..fc68927a 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -620,6 +620,10 @@ def typeSize(validator, typeSize, instance, schema): if (isinstance(instance[0], tagged_list)): if typeSize != instance[0].type_size: yield jsonschema.ValidationError("size is %r, expected %r" % (instance[0].type_size, typeSize)) + elif isinstance(instance[0], list) and isinstance(instance[0][0], int) and \ + typeSize == 32: + # 32-bit sizes aren't explicitly tagged + return else: yield jsonschema.ValidationError("missing size tag in %r" % instance) diff --git a/schemas/types.yaml b/schemas/types.yaml index 0074b7ca..4070f012 100644 --- a/schemas/types.yaml +++ b/schemas/types.yaml @@ -304,6 +304,7 @@ definitions: - type: array minItems: 1 maxItems: 1 + typeSize: 32 items: type: array items: diff --git a/test/device.yaml b/test/device.yaml index 567c51df..2656525e 100644 --- a/test/device.yaml +++ b/test/device.yaml @@ -33,6 +33,7 @@ vendor,string-prop: [ foo ] vendor,string-list-prop: [ foobar, foobaz ] vendor,phandle-with-fixed-cells: [[!phandle 1, 2, 3]] + vendor,int64-array-prop: [ !u64 [0x10000000, 0x1] ] interrupt-controller@10: compatible: [ "vendor,soc1-ip" ] @@ -43,3 +44,4 @@ interrupt-names: [ "tx irq" ] vendor,int-array-prop: [ [5], [6], [7], [8] ] vendor,int-array-size-only-prop: [ [2], [3], [4] ] + vendor,int64-array-prop: [ [0x10000000, 0x1] ] diff --git a/test/schemas/good-example.yaml b/test/schemas/good-example.yaml index f0dd708e..7ebf8ab2 100644 --- a/test/schemas/good-example.yaml +++ b/test/schemas/good-example.yaml @@ -169,6 +169,11 @@ properties: description: Vendor specific 16-bit integer property + vendor,int64-array-prop: + allOf: + - $ref: /schemas/types.yaml#definitions/uint64-array + description: Vendor specific 64-bit integer array property + vendor,phandle-prop: $ref: "/schemas/types.yaml#/definitions/phandle" description: Vendor specific single cell phandle property From d3f984f9233dc2db37bba3aecd3fb1c5be306912 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 18 May 2020 17:16:05 -0600 Subject: [PATCH 005/505] dtschema: Fix 'select' generation with 'simple-mfd' If 'syscon' doesn't exist, then we get an exception and skip trying to remove 'simple-mfd' from the list. Each statement needs its own try/except. Signed-off-by: Rob Herring --- dtschema/lib.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index fc68927a..90a2eb54 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -409,6 +409,9 @@ def add_select_schema(schema): compatible_list = list(set(compatible_list)) try: compatible_list.remove('syscon') + except: + pass + try: compatible_list.remove('simple-mfd') except: pass From 9186fe5e9082e3875008328e79e03d98fdbbbad8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 28 May 2020 15:23:23 +0200 Subject: [PATCH 006/505] Fix interrupt controllers with interrupt-map When an interrupt controller has an "interrupt-map" property, an "is valid under each of" error is triggered. Fix this by allowing "interrupt-controller" and "interrupt-map" to coexist, in both the interrrupts meta-schema and the interrupt-controller schema. Signed-off-by: Geert Uytterhoeven Signed-off-by: Rob Herring --- meta-schemas/interrupts.yaml | 2 +- schemas/interrupt-controller.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meta-schemas/interrupts.yaml b/meta-schemas/interrupts.yaml index 70730634..93d8e4ca 100644 --- a/meta-schemas/interrupts.yaml +++ b/meta-schemas/interrupts.yaml @@ -26,7 +26,7 @@ properties: dependencies: interrupt-map: ['#interrupt-cells', 'interrupt-map-mask'] '#interrupt-cells': - oneOf: + anyOf: - required: - interrupt-controller - required: diff --git a/schemas/interrupt-controller.yaml b/schemas/interrupt-controller.yaml index f65d5f6d..5dce87d8 100644 --- a/schemas/interrupt-controller.yaml +++ b/schemas/interrupt-controller.yaml @@ -30,7 +30,7 @@ dependencies: interrupt-controller: ['#interrupt-cells'] interrupt-map: ['#interrupt-cells', 'interrupt-map-mask'] "#interrupt-cells": - oneOf: + anyOf: - required: - interrupt-controller - required: From 4d2d86c5cd65cd3944ce0aaa400866bc36727bea Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 9 Jun 2020 08:53:48 -0600 Subject: [PATCH 007/505] schemas: pci: Drop 'compatible' as a required property for bridges The pci-bus.yaml schema can apply to PCI to PCI bridges, but those may not have a compatible string. Host bridges will require a compatible anyways for matching their schema. Reported-by: Thierry Reding Signed-off-by: Rob Herring --- schemas/pci/pci-bus.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/schemas/pci/pci-bus.yaml b/schemas/pci/pci-bus.yaml index 87c5b476..95bcc681 100644 --- a/schemas/pci/pci-bus.yaml +++ b/schemas/pci/pci-bus.yaml @@ -145,7 +145,6 @@ patternProperties: - reg required: - - compatible - device_type - ranges - "#address-cells" From f871ee8af8d3e5a969fb3738493f53a0b101fd02 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 9 Jun 2020 13:26:51 +0200 Subject: [PATCH 008/505] README: Fix a couple of typos There are a couple of minor typos in the README file. Fix them. Signed-off-by: Thierry Reding --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a1de03d7..605c8276 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ Found in `./meta-schemas` *Devicetree Meta-Schemas* describe the data format of Devicetree Schema files. The Meta-schemas make sure all the binding schemas are in the correct format -and the tool will emit an error is the format is incorrect. +and the tool will emit an error if the format is incorrect. As a developer you normally will not need to write metaschema files. @@ -89,9 +89,9 @@ them against the DT meta-schema. tools/dt-mk-schema This tool takes user provided schema file(s) plus the core schema files in this -repo, removed everything not needed for validation, applies fix-ups to the -schemas, and outputs a single file with the processed schema. This is step is -done separately to speed up subsequent validate of YAML Devicetrees. +repo, removes everything not needed for validation, applies fix-ups to the +schemas, and outputs a single file with the processed schema. This step is +done separately to speed up subsequent validation of YAML Devicetrees. tools/dt-validate This tool takes user provided YAML Devicetree(s) and either a schema directory From 6265f5d48443f9ae301f15faf56ef6aa5bd77a01 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 9 Jun 2020 13:28:19 +0200 Subject: [PATCH 009/505] schemas: gpio: Split up GPIO consumer and hog bindings Move the GPIO consumer bindings into a separate file and add a separate bindings document for GPIO hogs. This is necessary to make sure that the schema for GPIO consumers doesn't apply to GPIO hogs because they conflict. Signed-off-by: Thierry Reding --- schemas/gpio/gpio-consumer.yaml | 21 ++++++++++++++++++ schemas/gpio/gpio-hog.yaml | 39 +++++++++++++++++++++++++++++++++ schemas/gpio/gpio.yaml | 6 ----- 3 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 schemas/gpio/gpio-consumer.yaml create mode 100644 schemas/gpio/gpio-hog.yaml diff --git a/schemas/gpio/gpio-consumer.yaml b/schemas/gpio/gpio-consumer.yaml new file mode 100644 index 00000000..315a81dd --- /dev/null +++ b/schemas/gpio/gpio-consumer.yaml @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2018 Linaro Ltd. +$id: "http://devicetree.org/schemas/gpio/gpio-consumer.yaml#" +$schema: "http://devicetree.org/meta-schemas/base.yaml#" +title: GPIO consumer devicetree schema +description: "Schema for GPIO consumer devicetree bindings" +maintainers: + - Rob Herring + +# do not select this schema for GPIO hogs +select: + properties: + gpio-hog: false + +properties: + gpios: + $ref: "/schemas/types.yaml#/definitions/phandle-array" + +patternProperties: + "(? + +# select this schema for GPIO hogs +select: + properties: + gpio-hog: true + + required: + - gpio-hog + +properties: + gpio-hog: + $ref: "/schemas/types.yaml#/definitions/flag" + + gpios: + $ref: "/schemas/types.yaml#/definitions/uint32-matrix" + + input: + $ref: "/schemas/types.yaml#/definitions/flag" + + line-name: + $ref: "/schemas/types.yaml#/definitions/string" + + output-high: + $ref: "/schemas/types.yaml#/definitions/flag" + + output-low: + $ref: "/schemas/types.yaml#/definitions/flag" + +required: + - gpio-hog + - gpios diff --git a/schemas/gpio/gpio.yaml b/schemas/gpio/gpio.yaml index 2c433145..2e015ced 100644 --- a/schemas/gpio/gpio.yaml +++ b/schemas/gpio/gpio.yaml @@ -33,12 +33,6 @@ properties: - type: object - $ref: "/schemas/types.yaml#/definitions/phandle-array" -patternProperties: - "(? Date: Wed, 17 Jun 2020 15:39:53 +0200 Subject: [PATCH 010/505] schemas: pci: Allow 'ranges' to be a flag For PCI root port nodes we want to allow the 'ranges' property to be a flag, meaning that there's a 1:1 translation between the root port and the PCI host bridge. Signed-off-by: Thierry Reding --- schemas/pci/pci-bus.yaml | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/schemas/pci/pci-bus.yaml b/schemas/pci/pci-bus.yaml index 95bcc681..95087a0c 100644 --- a/schemas/pci/pci-bus.yaml +++ b/schemas/pci/pci-bus.yaml @@ -28,19 +28,21 @@ properties: pattern: "^pcie?@" ranges: - minItems: 1 - maxItems: 32 # Should be enough - items: - minItems: 5 - maxItems: 7 - additionalItems: true - items: - - enum: - - 0x01000000 - - 0x02000000 - - 0x03000000 - - 0x42000000 - - 0x43000000 + oneOf: + - $ref: "/schemas/types.yaml#/definitions/flag" + - minItems: 1 + maxItems: 32 # Should be enough + items: + minItems: 5 + maxItems: 7 + additionalItems: true + items: + - enum: + - 0x01000000 + - 0x02000000 + - 0x03000000 + - 0x42000000 + - 0x43000000 dma-ranges: oneOf: From 16da0025b4f93e07d7f0bb133ac2379019c7f941 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 17 Jun 2020 18:44:53 +0200 Subject: [PATCH 011/505] meta-schemas: Allow *Properties to be any schema According to the json-schema specification, additionalProperties and unevaluatedProperties must be a valid JSON schema and it doesn't put any further restrictions on them. Match the specification by allowing both to be either boolean or a sub-schema. Signed-off-by: Thierry Reding --- meta-schemas/keywords.yaml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/meta-schemas/keywords.yaml b/meta-schemas/keywords.yaml index ed543235..aa88f726 100644 --- a/meta-schemas/keywords.yaml +++ b/meta-schemas/keywords.yaml @@ -79,7 +79,11 @@ properties: additionalItems: type: boolean additionalProperties: - type: boolean + oneOf: + - type: object + allOf: + - $ref: "#/definitions/sub-schemas" + - type: boolean allOf: items: $ref: "#/definitions/sub-schemas" @@ -140,7 +144,11 @@ properties: type: true typeSize: true unevaluatedProperties: - type: boolean + oneOf: + - type: object + allOf: + - $ref: "#/definitions/sub-schemas" + - type: boolean uniqueItems: type: boolean From 58dae8bf6e2f704ca75b324239530e7ac7f03f75 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 11 Jun 2020 10:24:59 -0600 Subject: [PATCH 012/505] schemas: Add a schema to check 'reg' sizes Add a schema to ensure the size for each 'reg' entry matches the parent's #address-cells plus #size-cells size. Signed-off-by: Rob Herring --- schemas/reg.yaml | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 schemas/reg.yaml diff --git a/schemas/reg.yaml b/schemas/reg.yaml new file mode 100644 index 00000000..4aca6310 --- /dev/null +++ b/schemas/reg.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2020 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/reg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: reg property checks + +description: | + Common checks for 'reg' properties + +maintainers: + - Rob Herring + +select: true + +properties: {} + +allOf: + - if: + properties: + '#address-cells': + const: 2 + '#size-cells': + const: 2 + required: + - '#address-cells' + - '#size-cells' + then: + patternProperties: + '@': + properties: + reg: + items: + minItems: 4 + maxItems: 4 + + - if: + properties: + '#address-cells': + const: 1 + '#size-cells': + const: 1 + required: + - '#address-cells' + - '#size-cells' + then: + patternProperties: + '@': + properties: + reg: + items: + minItems: 2 + maxItems: 2 + + - if: + properties: + '#address-cells': + const: 2 + '#size-cells': + const: 1 + required: + - '#address-cells' + - '#size-cells' + then: + patternProperties: + '@': + properties: + reg: + items: + minItems: 3 + maxItems: 3 + +... From d38bb3388f8efa7fcd001bf3bdc5270fa168268a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 19 Jun 2020 12:46:47 +0200 Subject: [PATCH 013/505] dt-validate: Check status of correct instance When deciding whether or not to emit an error, look at the 'status' property of the instance that failed to validate rather than of the node that is being checked. Cases where this can happen are when a schema describes required properties for patternProperties or other child nodes, in which case the invalid instance differs from the node being checked. Signed-off-by: Thierry Reding --- tools/dt-validate | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/dt-validate b/tools/dt-validate index 473e5e3a..8639e5a8 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -58,8 +58,8 @@ class schema_group(): # boards using that particular node. Thus, if the # node is marked as disabled, let's just ignore # any error message reporting a missing property. - if 'status' in node and \ - 'disabled' in node['status'] and \ + if 'status' in error.instance and \ + 'disabled' in error.instance['status'] and \ 'required property' in error.message: continue From 1d35fa1296fd17b0f8500f2d4374db6ce124269d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 19 Jun 2020 12:51:00 +0200 Subject: [PATCH 014/505] meta-schemas: Document 'memory-region-names' property The 'memory-region-names' property can be used to distinguish between multiple entries in the 'memory-region' property. Document the new property and model the dependency in the same way as for the 'clocks' and 'clock-names' properties. Signed-off-by: Thierry Reding --- meta-schemas/core.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index e623fda0..844803c1 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -30,6 +30,8 @@ definitions: $ref: "string-array.yaml" memory-region: $ref: "cell.yaml#array" + memory-region-names: + $ref: "string-array.yaml" propertyNames: # Ensure DT property names are not json-schema vocabulary names not: @@ -73,6 +75,7 @@ definitions: dependencies: "#size-cells": [ "#address-cells" ] + memory-region-names: [ memory-region ] properties: patternProperties: From 0d4d87a3efa3ae7794e803891fe005db7009f959 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 19 Jun 2020 13:18:46 -0600 Subject: [PATCH 015/505] dt-validate: Don't report no match when 'compatible' is not used for 'select' Some schema have 'compatible' but don't use it to match and we're reporting those cases as having no match when using '-m'. Instead, check the schema has 'compatible' rather than 'select'. Signed-off-by: Rob Herring --- tools/dt-validate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/dt-validate b/tools/dt-validate index 8639e5a8..f18f1cd0 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -46,7 +46,7 @@ class schema_group(): if schema['select'] != True: matched_schemas.append(schema['$id']) node_matched = True - if 'compatible' in schema['select']['properties'].keys(): + if 'compatible' in schema['properties']: node_compatible_matched = True try: errors = sorted(dtschema.DTValidator(schema).iter_errors(node), key=lambda e: e.linecol) From ba393c3a9a424562216ffef0a51b829637773c07 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 19 Jun 2020 14:59:27 -0600 Subject: [PATCH 016/505] Add a license file Every file has a SPDX tag, but Python packaging likes a LICENSE.txt. Signed-off-by: Rob Herring --- LICENSE.txt | 23 +++++++++++++++++++++++ setup.py | 2 ++ 2 files changed, 25 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..7b729684 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,23 @@ +Copyright 2018-2019 Linaro Ltd. +Copyright 2018-2020 Arm Ltd. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/setup.py b/setup.py index 39a974f1..13cca214 100755 --- a/setup.py +++ b/setup.py @@ -29,6 +29,8 @@ description="DeviceTree validation schema and tools", long_description=long_description, url="https://github.com/devicetree-org/dt-schema", + license="BSD", + license_files=["LICENSE.txt"], packages=['dtschema'], package_data={'dtschema': data_files}, From b29a9bbba0ea1148d41000d5df4b64f29f66209a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 19 Jun 2020 14:21:54 -0600 Subject: [PATCH 017/505] Add Travis-CI PyPI deployment Signed-off-by: Rob Herring --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index 269a5212..ba2e24d6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,3 +7,10 @@ python: script: - pip install . - test/test-dt-validate.py +deploy: + provider: pypi + username: "__token__" + password: + secure: Oy7FwsHPiJvJLwgVFwrm4aIzRy//HMkfe28h4AwT7l59/20HQ+68qPoblkwC7ZtM6o2uy4hcZO3oqvcgbFiTK4StF8PfPAln0r3r0/8CQYBejtS58dsp0n1O1b4JFc+r0CmY554bDquj1vNH+ztAtF/s012Aw2gK581TYvP2i44c74oZh0KciJY4GGLguU/pO+UIDSIZGeOAnAUPReGN+xjbnrmCiUV7ef4FDjERBvjaf4OnoDMwAwhzNrSXkGcWbtqpwiJnnHXtB42Zs/SZ9H3VaexSkBGXb1EzyDyO1mXBsYWw/KUg8Nc76qeD6g9dDURTQek0VhvkLLgkYyTw4n52HyNSOclA7XKbxOANrWIwXLcJLMB37/aAYBe6yZIdpYQ1iA9SW+GZ0xnPH9ONaj8/fMBOnwfEBZltHqIzTWbxx1UpXN7Q91PoNx0ytodHxaALPzcaOfet1ClhWBvWMoFBSKwb7ecvBoRFC81mZzMzuPKj8XektUojWyzhQy7U+zGzPkA0ONkFecZwhOaSD0YOv0Pz0keukriW2kiMkif9DDOUfmepLgiDmWatqYpcwIS6p+XOiLIs7r8iRq4ZUowHsy/LC/lpS9EK4K6g/chNCy4LoPmcITXlV0kwRIsV1fDAi9v+EkWXkATDUQSiZyjMLcEhjw2Gkq1JfZe1uRM= + on: + tags: true From 395eb52c0358ae235db4819267b6f341b18cb7f1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 19 Jun 2020 15:22:44 -0600 Subject: [PATCH 018/505] setup.py: Set long description type to markdown Signed-off-by: Rob Herring --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 13cca214..12767c55 100755 --- a/setup.py +++ b/setup.py @@ -28,6 +28,7 @@ author_email="robh@kernel.org", description="DeviceTree validation schema and tools", long_description=long_description, + long_description_content_type="text/markdown", url="https://github.com/devicetree-org/dt-schema", license="BSD", license_files=["LICENSE.txt"], From 46d2867ff595776a34f7ceef9bbed33e7bf47bab Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 29 Jun 2020 19:20:38 -0600 Subject: [PATCH 019/505] dt-validate: Fix backtrace when error instance is not a dict error.instance can be a scalar value. The check for disabled nodes needs to only check errors that apply to the whole node which are when the error.instance is a dict. Signed-off-by: Rob Herring --- tools/dt-validate | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/dt-validate b/tools/dt-validate index f18f1cd0..62534030 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -58,7 +58,8 @@ class schema_group(): # boards using that particular node. Thus, if the # node is marked as disabled, let's just ignore # any error message reporting a missing property. - if 'status' in error.instance and \ + if isinstance(error.instance, dict) and \ + 'status' in error.instance and \ 'disabled' in error.instance['status'] and \ 'required property' in error.message: continue From 1330cddcba757bee7b335c7c7d8233d9da949113 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 9 Jul 2020 16:26:59 -0600 Subject: [PATCH 020/505] schemas: Make additionalProperties/unevaluatedProperties explicit In preparation to add a meta-schema to check for missing additionalProperties or unevaluatedProperties, add them to all the schemas. Signed-off-by: Rob Herring --- schemas/cache-controller.yaml | 2 ++ schemas/dma/dma.yaml | 2 ++ schemas/hwlock/hwlock-consumer.yaml | 2 ++ schemas/i2c/i2c-controller.yaml | 2 ++ schemas/iommu/iommu.yaml | 2 ++ schemas/memory.yaml | 2 ++ schemas/pci/pci-bus.yaml | 2 ++ schemas/pinctrl/pinctrl-consumer.yaml | 2 ++ schemas/property-units.yaml | 2 ++ schemas/reg.yaml | 2 ++ schemas/root-node.yaml | 3 ++- schemas/serial.yaml | 2 ++ schemas/simple-bus.yaml | 2 +- test/schemas/child-node-example.yaml | 2 ++ test/schemas/conditionals-allof-example.yaml | 2 ++ test/schemas/conditionals-single-example.yaml | 2 ++ test/schemas/good-example.yaml | 2 ++ 17 files changed, 33 insertions(+), 2 deletions(-) diff --git a/schemas/cache-controller.yaml b/schemas/cache-controller.yaml index f1403f56..9b347e69 100644 --- a/schemas/cache-controller.yaml +++ b/schemas/cache-controller.yaml @@ -45,3 +45,5 @@ if: then: required: - cache-level + +additionalProperties: true diff --git a/schemas/dma/dma.yaml b/schemas/dma/dma.yaml index 48e16d86..58bdde28 100644 --- a/schemas/dma/dma.yaml +++ b/schemas/dma/dma.yaml @@ -21,3 +21,5 @@ properties: dependencies: dma-names: [ dmas ] + +additionalProperties: true diff --git a/schemas/hwlock/hwlock-consumer.yaml b/schemas/hwlock/hwlock-consumer.yaml index 89ea229c..bdb4c88c 100644 --- a/schemas/hwlock/hwlock-consumer.yaml +++ b/schemas/hwlock/hwlock-consumer.yaml @@ -23,3 +23,5 @@ properties: dependencies: hwlock-names: [ hwlocks ] + +additionalProperties: true diff --git a/schemas/i2c/i2c-controller.yaml b/schemas/i2c/i2c-controller.yaml index a3bd514d..7f8a4b19 100644 --- a/schemas/i2c/i2c-controller.yaml +++ b/schemas/i2c/i2c-controller.yaml @@ -27,3 +27,5 @@ properties: clock-frequency: minimum: 1000 maximum: 3000000 + +additionalProperties: true diff --git a/schemas/iommu/iommu.yaml b/schemas/iommu/iommu.yaml index b472bb57..6d7b2638 100644 --- a/schemas/iommu/iommu.yaml +++ b/schemas/iommu/iommu.yaml @@ -16,3 +16,5 @@ select: true properties: iommus: $ref: "/schemas/types.yaml#/definitions/phandle-array" + +additionalProperties: true diff --git a/schemas/memory.yaml b/schemas/memory.yaml index ea09e558..ea500254 100644 --- a/schemas/memory.yaml +++ b/schemas/memory.yaml @@ -25,3 +25,5 @@ properties: required: - device_type - reg + +additionalProperties: true diff --git a/schemas/pci/pci-bus.yaml b/schemas/pci/pci-bus.yaml index 95087a0c..7c427fd3 100644 --- a/schemas/pci/pci-bus.yaml +++ b/schemas/pci/pci-bus.yaml @@ -151,3 +151,5 @@ required: - ranges - "#address-cells" - "#size-cells" + +additionalProperties: true diff --git a/schemas/pinctrl/pinctrl-consumer.yaml b/schemas/pinctrl/pinctrl-consumer.yaml index cad30260..56c73769 100644 --- a/schemas/pinctrl/pinctrl-consumer.yaml +++ b/schemas/pinctrl/pinctrl-consumer.yaml @@ -24,3 +24,5 @@ patternProperties: dependencies: pinctrl-names: [ pinctrl-0 ] + +additionalProperties: true diff --git a/schemas/property-units.yaml b/schemas/property-units.yaml index bb822bcd..20e6f6eb 100644 --- a/schemas/property-units.yaml +++ b/schemas/property-units.yaml @@ -89,3 +89,5 @@ patternProperties: "-kpascal$": $ref: "types.yaml#/definitions/uint32-array" description: kiloPascal + +additionalProperties: true diff --git a/schemas/reg.yaml b/schemas/reg.yaml index 4aca6310..8b153724 100644 --- a/schemas/reg.yaml +++ b/schemas/reg.yaml @@ -17,6 +17,8 @@ select: true properties: {} +additionalProperties: true + allOf: - if: properties: diff --git a/schemas/root-node.yaml b/schemas/root-node.yaml index 3be5f308..8031409f 100644 --- a/schemas/root-node.yaml +++ b/schemas/root-node.yaml @@ -16,7 +16,6 @@ maintainers: properties: $nodename: const: "/" - compatible: {} model: { "$ref" : "types.yaml#definitions/string-array"} "#address-cells": enum: [1, 2] @@ -30,6 +29,8 @@ required: - "#address-cells" - "#size-cells" +additionalProperties: true + examples: - | / { diff --git a/schemas/serial.yaml b/schemas/serial.yaml index 995f1ccc..b478e2ed 100644 --- a/schemas/serial.yaml +++ b/schemas/serial.yaml @@ -13,3 +13,5 @@ maintainers: properties: $nodename: pattern: "^serial(@[0-9a-f,]+)*$" + +additionalProperties: true diff --git a/schemas/simple-bus.yaml b/schemas/simple-bus.yaml index 248ac9dd..7428e39e 100644 --- a/schemas/simple-bus.yaml +++ b/schemas/simple-bus.yaml @@ -49,7 +49,7 @@ patternProperties: - required: - ranges -#additionalProperties: false +additionalProperties: true required: - compatible diff --git a/test/schemas/child-node-example.yaml b/test/schemas/child-node-example.yaml index 054fd3b8..80b96021 100644 --- a/test/schemas/child-node-example.yaml +++ b/test/schemas/child-node-example.yaml @@ -74,3 +74,5 @@ patternProperties: required: - compatible - child-node-fixed-name + +additionalProperties: false diff --git a/test/schemas/conditionals-allof-example.yaml b/test/schemas/conditionals-allof-example.yaml index 2e5e22ac..b6e2a404 100644 --- a/test/schemas/conditionals-allof-example.yaml +++ b/test/schemas/conditionals-allof-example.yaml @@ -16,6 +16,8 @@ properties: - vendor,conditionals-allof-test-controller - vendor,second-conditionals-allof-test-controller +unevaluatedProperties: false + allOf: - if: properties: diff --git a/test/schemas/conditionals-single-example.yaml b/test/schemas/conditionals-single-example.yaml index 6275203c..a542ba89 100644 --- a/test/schemas/conditionals-single-example.yaml +++ b/test/schemas/conditionals-single-example.yaml @@ -30,3 +30,5 @@ else: properties: vendor,property: const: test5678 + +unevaluatedProperties: false diff --git a/test/schemas/good-example.yaml b/test/schemas/good-example.yaml index 7ebf8ab2..7b51b53e 100644 --- a/test/schemas/good-example.yaml +++ b/test/schemas/good-example.yaml @@ -198,6 +198,8 @@ properties: required: - compatible +additionalProperties: false + examples: - | /dts-v1/; From 15f48944e5542249b71dc015f3707c89e2891960 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 5 Aug 2020 10:35:15 -0600 Subject: [PATCH 021/505] dt-extract-example: Drop dtschema import The dtschema import is slow and only needed to get the version. Let's just drop the version option for now. Signed-off-by: Rob Herring --- tools/dt-extract-example | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/dt-extract-example b/tools/dt-extract-example index f1a222fe..ae888102 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -8,7 +8,6 @@ import re import sys import ruamel.yaml import argparse -import dtschema example_template = """ example-{example_num} {{ @@ -42,8 +41,6 @@ if __name__ == "__main__": ap = argparse.ArgumentParser() ap.add_argument("yamlfile", type=str, help="Filename of YAML encoded schema input file") - ap.add_argument('-V', '--version', help="Print version number", - action="version", version=dtschema.__version__) args = ap.parse_args() binding = yaml.load(open(args.yamlfile, encoding='utf-8').read()) From 8fd8ce7ff6bd47616ceb48f69d1a04116dee7a41 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 5 Aug 2020 10:38:08 -0600 Subject: [PATCH 022/505] dt-extract-example: Use the C yaml parser The 'pure' (Python) loader was needed at one time for YAML 1.2, but ruamel has supported 1.2 with its libyaml since 0.15.63 and we depend on version 0.15.70 at least. Signed-off-by: Rob Herring --- tools/dt-extract-example | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/dt-extract-example b/tools/dt-extract-example index ae888102..b7fb9887 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -33,8 +33,7 @@ example_start = """ """ -# Need pure until YAML 1.2 is supported -yaml = ruamel.yaml.YAML(typ='safe', pure=True) +yaml = ruamel.yaml.YAML(typ='safe') if __name__ == "__main__": ex = '// empty' From 86e87d99ec85e235625f9e1566a86bf0871c7229 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 12 Aug 2020 07:50:02 -0600 Subject: [PATCH 023/505] dt-doc-validate: support multiple file and directory args Signed-off-by: Rob Herring --- tools/dt-doc-validate | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/dt-doc-validate b/tools/dt-doc-validate index 4a90d6f1..d94970de 100755 --- a/tools/dt-doc-validate +++ b/tools/dt-doc-validate @@ -41,7 +41,7 @@ def check_doc(filename): if __name__ == "__main__": ap = argparse.ArgumentParser() - ap.add_argument("yamldt", type=str, + ap.add_argument("yamldt", nargs='*', type=str, help="Filename of YAML encoded devicetree input file") ap.add_argument('-v', '--verbose', help="verbose mode", action="store_true") ap.add_argument('-n', '--line-number', help="Print line and column numbers (slower)", action="store_true") @@ -55,12 +55,14 @@ if __name__ == "__main__": if args.url_path: dtschema.add_schema_path(args.url_path) - if os.path.isdir(args.yamldt): - for filename in glob.iglob(args.yamldt + "/**/*.yaml", recursive=True): - ret = check_doc(filename) - if ret != 0: - break - else: - ret = check_doc(args.yamldt) + ret = 0 + for f in args.yamldt: + if os.path.isdir(f): + for filename in glob.iglob(f + "/**/*.yaml", recursive=True): + ret = check_doc(filename) + if ret != 0: + break + else: + ret = check_doc(f) exit(ret) From b614f97158cd55d169e6d4b0eca5fd7185f99cbe Mon Sep 17 00:00:00 2001 From: Andrei Ziureaev Date: Tue, 11 Aug 2020 19:47:53 +0100 Subject: [PATCH 024/505] dt-mk-schema: Change help messages A couple of help messages don't look right. Make them more hepful. Signed-off-by: Andrei Ziureaev Signed-off-by: Rob Herring --- tools/dt-mk-schema | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/dt-mk-schema b/tools/dt-mk-schema index 50caefe8..d396575d 100755 --- a/tools/dt-mk-schema +++ b/tools/dt-mk-schema @@ -23,9 +23,9 @@ import jsonschema if __name__ == "__main__": ap = argparse.ArgumentParser() ap.add_argument("-o", "--outfile", type=str, - help="Filename of YAML encoded devicetree input file") + help="Filename of the processed schema") ap.add_argument("schemas", nargs='*', type=str, - help="Filename of YAML encoded devicetree input file") + help="Names of directories, or YAML encoded schema files") ap.add_argument('-u', '--useronly', help="Only process user schemas", action="store_true") ap.add_argument('-V', '--version', help="Print version number", action="version", version=dtschema.__version__) From b08c62bb06318ec260418620ad43df7d0c5ad438 Mon Sep 17 00:00:00 2001 From: Andrei Ziureaev Date: Tue, 11 Aug 2020 19:47:54 +0100 Subject: [PATCH 025/505] dt-mk-schema: Add an option for json output Add a -j flag that sets the output to be in json. Signed-off-by: Andrei Ziureaev Signed-off-by: Rob Herring --- tools/dt-mk-schema | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/dt-mk-schema b/tools/dt-mk-schema index d396575d..0fd5e102 100755 --- a/tools/dt-mk-schema +++ b/tools/dt-mk-schema @@ -17,6 +17,7 @@ import dtschema import argparse import glob import jsonschema +import json @@ -24,6 +25,8 @@ if __name__ == "__main__": ap = argparse.ArgumentParser() ap.add_argument("-o", "--outfile", type=str, help="Filename of the processed schema") + ap.add_argument("-j", "--json", help="Encode the processed schema in json", + action="store_true") ap.add_argument("schemas", nargs='*', type=str, help="Names of directories, or YAML encoded schema files") ap.add_argument('-u', '--useronly', help="Only process user schemas", action="store_true") @@ -40,5 +43,8 @@ if __name__ == "__main__": else: f = sys.stdout - yaml = ruamel.yaml.YAML(typ='safe') - yaml.dump(schemas, f) + if (args.json): + json.dump(schemas, f) + else: + yaml = ruamel.yaml.YAML(typ='safe') + yaml.dump(schemas, f) From d6f924bd1a7a90e2b8c39b3d0f3fb62bb5217c5f Mon Sep 17 00:00:00 2001 From: Andrei Ziureaev Date: Tue, 11 Aug 2020 19:47:55 +0100 Subject: [PATCH 026/505] Add support for loading json-encoded schemas Use the json parser if a schema file has the .json extension. Signed-off-by: Andrei Ziureaev Signed-off-by: Rob Herring --- dtschema/lib.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index 90a2eb54..92ec52ff 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -9,6 +9,7 @@ import re import pprint import copy +import json from ruamel.yaml.comments import CommentedMap @@ -103,6 +104,9 @@ def check_id_path(filename, id): def do_load(filename): with open(filename, 'r', encoding='utf-8') as f: + if filename.endswith('.json'): + return json.load(f) + # ruamel C loader doesn't support 1.2, but 1.1 is good enough for us tmp = f.read().replace('YAML 1.2', 'YAML 1.1') return yaml.load(tmp) From 6b4e213fc0a3bcb609e0ed0c57099f2de42a18a8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 12 Aug 2020 15:20:56 -0600 Subject: [PATCH 027/505] test: Omit 'additionalProperties' from required properties Since adding 'additionalProperties' to good-example.yaml, the tests are failing: FAIL: test_required_property_missing (__main__.TestDTMetaSchema) (k='additionalProperties') ---------------------------------------------------------------------- Traceback (most recent call last): File "test/test-dt-validate.py", line 47, in test_required_property_missing self.assertRaises(jsonschema.SchemaError, dtschema.DTValidator.check_schema, schema_tmp) AssertionError: SchemaError not raised by check_schema Add 'additionalProperties' to the list of optional properties. Really this test needs to be reworked. It's fragile as it needs to be kept in sync with the meta-schema. Rather than modifying a schema at run-time we should probably have a set of expected fail schema files. Signed-off-by: Rob Herring --- test/test-dt-validate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index fab83edc..500c992b 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -39,7 +39,7 @@ def test_required_properties(self): def test_required_property_missing(self): for key in self.schema.keys(): - if key in ['$schema', 'properties', 'required', 'description', 'examples']: + if key in ['$schema', 'properties', 'required', 'description', 'examples', 'additionalProperties']: continue with self.subTest(k=key): schema_tmp = self.schema.copy() From 76261317e5d70e999f7673d3217629045ab15a7f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 13 Aug 2020 17:01:48 -0600 Subject: [PATCH 028/505] tools: Add support for getting command line arguments from a file The file list arguments can be very long and exceed maximum sizes of the OS. Fortunately argparse has built-in support for fetching command line arguments from a file, so let's use that. Signed-off-by: Rob Herring --- tools/dt-doc-validate | 3 ++- tools/dt-mk-schema | 3 ++- tools/dt-validate | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/dt-doc-validate b/tools/dt-doc-validate index d94970de..777d1bfc 100755 --- a/tools/dt-doc-validate +++ b/tools/dt-doc-validate @@ -40,7 +40,8 @@ def check_doc(filename): return ret if __name__ == "__main__": - ap = argparse.ArgumentParser() + ap = argparse.ArgumentParser(fromfile_prefix_chars='@', + epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("yamldt", nargs='*', type=str, help="Filename of YAML encoded devicetree input file") ap.add_argument('-v', '--verbose', help="verbose mode", action="store_true") diff --git a/tools/dt-mk-schema b/tools/dt-mk-schema index 0fd5e102..cdb2b2ca 100755 --- a/tools/dt-mk-schema +++ b/tools/dt-mk-schema @@ -22,7 +22,8 @@ import json if __name__ == "__main__": - ap = argparse.ArgumentParser() + ap = argparse.ArgumentParser(fromfile_prefix_chars='@', + epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("-o", "--outfile", type=str, help="Filename of the processed schema") ap.add_argument("-j", "--json", help="Encode the processed schema in json", diff --git a/tools/dt-validate b/tools/dt-validate index 62534030..16dc7fc8 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -108,7 +108,8 @@ class schema_group(): self.check_subtree(dt, subtree, "/", "/", filename) if __name__ == "__main__": - ap = argparse.ArgumentParser() + ap = argparse.ArgumentParser(fromfile_prefix_chars='@', + epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("yamldt", nargs='*', help="Filename or directory of YAML encoded devicetree input file(s)") ap.add_argument('-s', '--schema', help="path to additional additional schema files") From 30f10b5279bb41a19cb6f606bc12e5060a0c28cc Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 17 Aug 2020 16:52:15 -0600 Subject: [PATCH 029/505] dtschema: Apply fixups to 'additionalProperties' schemas Now that we allow 'additionalProperties' to be schemas instead of just boolean, we need to apply fixups under 'additionalProperties' too. Signed-off-by: Rob Herring --- dtschema/lib.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 92ec52ff..4a3180ae 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -329,7 +329,7 @@ def fixup_schema(schema): # If, then and else contain subschemas that we'll want to # fixup as well. Let's recurse into those subschemas. - if k in ['if', 'then', 'else']: + if k in ['if', 'then', 'else', 'additionalProperties']: fixup_schema(v) # allOf can contain a list of if, then and else statements, @@ -487,6 +487,9 @@ def fixup_node_props(schema): for k,v in schema['patternProperties'].items(): fixup_node_props(v) + if 'additionalProperties' in schema: + fixup_node_props(schema['additionalProperties']) + if not 'properties' in schema: schema['properties'] = {} From 3baf308b01786788e3ccb9824fce6d7136b21214 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 18 Aug 2020 12:19:17 -0600 Subject: [PATCH 030/505] schemas: simple-bus: Fix child node 'ranges' size simple-bus child nodes such as PCI could have 3 address cells, so 'ranges' entries could be up to 7 cells. Signed-off-by: Rob Herring --- schemas/simple-bus.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemas/simple-bus.yaml b/schemas/simple-bus.yaml index 7428e39e..9331fbb3 100644 --- a/schemas/simple-bus.yaml +++ b/schemas/simple-bus.yaml @@ -39,7 +39,7 @@ patternProperties: oneOf: - items: minItems: 3 - maxItems: 6 + maxItems: 7 minItems: 0 maxItems: 1024 - $ref: "types.yaml#/definitions/flag" From bab67075926b8bdc4093edbb9888aaa5bd8befd5 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 5 May 2020 16:50:54 +0100 Subject: [PATCH 031/505] simple-bus: Allow prefix before -bus node name Some systems (Arm VExpress based) use nested busses to express their system architecture. Just allowing generic node names like "bus" or "soc" makes their DT files hard to read. Allow the node name for a simple-bus node to have an explaining prefix, so multiple busses can be distinguished more easily. Signed-off-by: Andre Przywara [robh: restrict prefixes to [a-z0-9\-]] Signed-off-by: Rob Herring --- schemas/simple-bus.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemas/simple-bus.yaml b/schemas/simple-bus.yaml index 9331fbb3..949e6c9c 100644 --- a/schemas/simple-bus.yaml +++ b/schemas/simple-bus.yaml @@ -14,7 +14,7 @@ maintainers: properties: $nodename: - pattern: "^(bus|soc|axi|ahb|apb)(@[0-9a-f]+)?$" + pattern: "^([a-z][a-z0-9\\-]+-bus|bus|soc|axi|ahb|apb)(@[0-9a-f]+)?$" compatible: contains: const: simple-bus From c31d2d808faaeab6e357f3a027d2aa7745f081c9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 19 Aug 2020 09:56:41 -0600 Subject: [PATCH 032/505] schemas: pci: Allow setting the non-relocatable bit in 'ranges' The non-relocatable bit is a don't care for FDT and is ignored AFAICT, so let's allow it to be set. Signed-off-by: Rob Herring --- schemas/pci/pci-bus.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/schemas/pci/pci-bus.yaml b/schemas/pci/pci-bus.yaml index 7c427fd3..74c67b3f 100644 --- a/schemas/pci/pci-bus.yaml +++ b/schemas/pci/pci-bus.yaml @@ -43,6 +43,11 @@ properties: - 0x03000000 - 0x42000000 - 0x43000000 + - 0x81000000 + - 0x82000000 + - 0x83000000 + - 0xc2000000 + - 0xc3000000 dma-ranges: oneOf: From c38438eb08f56089ff10ef93aafcc9e932b69f39 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 19 Aug 2020 12:21:41 -0600 Subject: [PATCH 033/505] dt-validate: Print the schema file causing the error Since multiple schemas can be applied to a node, it's not always clear where the source of an error was. The jsonschema errors also don't have any way to get back to the schema file, but we have at least the starting schema file, so let's print it. If the schema file references other files, then those files could be the actual source. There's not currently a way to track $refs, so we only get the starting point. Signed-off-by: Rob Herring --- tools/dt-validate | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/dt-validate b/tools/dt-validate index 16dc7fc8..c03efd38 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -64,9 +64,9 @@ class schema_group(): 'required property' in error.message: continue - print(dtschema.format_error(filename, error, - nodename=nodename, - verbose=verbose), file=sys.stderr) + print(dtschema.format_error(filename, error, nodename=nodename, verbose=verbose) + + '\n\tFrom schema: ' + schema['$filename'], + file=sys.stderr) except RecursionError as e: print(ap.prog + ": recursion error: Check for prior errors in a referenced schema", file=sys.stderr) From 2dd372d66ba216df060976089ae54d39d125924b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 20 Sep 2020 21:40:33 +0200 Subject: [PATCH 034/505] schemas: gpio: require GPIO hog input/output properties The GPIO hogs should require proper direction and value of a GPIO. Signed-off-by: Krzysztof Kozlowski --- schemas/gpio/gpio-hog.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/schemas/gpio/gpio-hog.yaml b/schemas/gpio/gpio-hog.yaml index 15f48ee5..fa9531c9 100644 --- a/schemas/gpio/gpio-hog.yaml +++ b/schemas/gpio/gpio-hog.yaml @@ -37,3 +37,11 @@ properties: required: - gpio-hog - gpios + +oneOf: + - required: + - input + - required: + - output-high + - required: + - output-low From d63b6539851e9f13927ee4260fed04ba666a8ec5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 20 Sep 2020 21:41:57 +0200 Subject: [PATCH 035/505] schemas: gpio: expect naming of GPIO hog nodes Expect GPIO hog nodes to contain "hog", either as full name ("hog-X") or as a suffix (".*-hog"). Signed-off-by: Krzysztof Kozlowski --- schemas/gpio/gpio-hog.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/schemas/gpio/gpio-hog.yaml b/schemas/gpio/gpio-hog.yaml index fa9531c9..01863e4c 100644 --- a/schemas/gpio/gpio-hog.yaml +++ b/schemas/gpio/gpio-hog.yaml @@ -16,6 +16,9 @@ select: - gpio-hog properties: + $nodename: + pattern: "^(hog-[0-9]+|.+-hog(-[0-9]+)?)$" + gpio-hog: $ref: "/schemas/types.yaml#/definitions/flag" From 0bb9729e072dbe768460be82680694e17e43253e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 1 Oct 2020 16:06:40 -0500 Subject: [PATCH 036/505] schemas: More making 'additionalProperties' explicit In order to check for missing 'additionalProperties' or 'unevaluatedProperties' make 'additionalProperties: true' explicit even though the default is true. Signed-off-by: Rob Herring --- schemas/clock/clock.yaml | 2 ++ schemas/cpus.yaml | 2 ++ schemas/gpio/gpio-consumer.yaml | 2 ++ schemas/gpio/gpio-hog.yaml | 2 ++ schemas/gpio/gpio.yaml | 2 ++ schemas/interrupt-controller.yaml | 2 ++ schemas/interrupts.yaml | 2 ++ schemas/mbox/mbox-consumer.yaml | 2 ++ schemas/memory.yaml | 2 ++ schemas/phy/phy-consumer.yaml | 2 ++ schemas/phy/phy-provider.yaml | 2 ++ schemas/power-domain/power-domain-consumer.yaml | 2 ++ schemas/pwm/pwm-consumer.yaml | 2 ++ schemas/reset/reset.yaml | 2 ++ schemas/types.yaml | 2 ++ 15 files changed, 30 insertions(+) diff --git a/schemas/clock/clock.yaml b/schemas/clock/clock.yaml index 81154071..a530f676 100644 --- a/schemas/clock/clock.yaml +++ b/schemas/clock/clock.yaml @@ -98,3 +98,5 @@ dependencies: assigned-clocks: [clocks] assigned-clock-parents: [assigned-clocks] assigned-clock-rates: [assigned-clocks] + +additionalProperties: true diff --git a/schemas/cpus.yaml b/schemas/cpus.yaml index d9b797d8..3d0c3ba3 100644 --- a/schemas/cpus.yaml +++ b/schemas/cpus.yaml @@ -144,4 +144,6 @@ required: - '#address-cells' - '#size-cells' +additionalProperties: true + ... diff --git a/schemas/gpio/gpio-consumer.yaml b/schemas/gpio/gpio-consumer.yaml index 315a81dd..607e91b2 100644 --- a/schemas/gpio/gpio-consumer.yaml +++ b/schemas/gpio/gpio-consumer.yaml @@ -19,3 +19,5 @@ properties: patternProperties: "(? Date: Mon, 5 Oct 2020 11:34:12 -0500 Subject: [PATCH 037/505] meta-schemas: Restrict property names to valid DT property/node names While we have checks that property and node names in DT files are within the allowed character set, that check was missing on schema files. This was noticed when a regex was placed under 'properties'. Signed-off-by: Rob Herring --- meta-schemas/base.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/meta-schemas/base.yaml b/meta-schemas/base.yaml index 08201827..e3916f21 100644 --- a/meta-schemas/base.yaml +++ b/meta-schemas/base.yaml @@ -45,7 +45,9 @@ properties: additionalProperties: true dependencies: true patternProperties: true - properties: true + properties: + propertyNames: + pattern: "^[#$a-zA-Z][a-zA-Z0-9,+\\-._@]{0,63}$" if: true then: true else: true From e6678bbf8a5816311b044ed5b59a43683fa80a3d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 22 Oct 2020 12:33:28 -0500 Subject: [PATCH 038/505] schemas: i2c: Fix i2c-bus $ref The 'i2c-bus' node $ref is not valid because '#/properties' doesn't point to a valid schema as it's just pointing to DT properties. We need to point to the top-level instead. Signed-off-by: Rob Herring --- schemas/i2c/i2c-controller.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemas/i2c/i2c-controller.yaml b/schemas/i2c/i2c-controller.yaml index 7f8a4b19..e1696b9b 100644 --- a/schemas/i2c/i2c-controller.yaml +++ b/schemas/i2c/i2c-controller.yaml @@ -16,7 +16,7 @@ properties: i2c-bus: type: object - $ref: "#/properties" + $ref: "#" "#address-cells": const: 1 From 14db51af82b0ab52f4a69f9aaa86726087b3022a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Jan 2020 16:38:11 -0600 Subject: [PATCH 039/505] meta-schemas: Require 'additionalProperties' or 'unevaluatedProperties' While the default behavior is additional/unevaluated properties are allowed, there's not any hard pattern we can match to fixup/enforce the non-default behavior (e.g. additionalProperties: false). This is a constant source of review issues, so an automated check is needed. If we have a $ref, then either 'additionalProperties' or 'unevaluatedProperties' is required. If there's no $ref, then 'additionalProperties' is required. Signed-off-by: Rob Herring --- meta-schemas/base.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/meta-schemas/base.yaml b/meta-schemas/base.yaml index e3916f21..5cfc27e8 100644 --- a/meta-schemas/base.yaml +++ b/meta-schemas/base.yaml @@ -76,4 +76,25 @@ required: - title - maintainers +if: + oneOf: + - properties: + allOf: + contains: + required: + - $ref + required: + - allOf + - required: + - $ref +then: + oneOf: + - required: + - unevaluatedProperties + - required: + - additionalProperties +else: + required: + - additionalProperties + additionalProperties: false From 85c37b15fc2c433d4b49b19e7db282a4276634ea Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 28 Oct 2020 13:50:34 -0500 Subject: [PATCH 040/505] test: Update test schemas for 'additionalProperties' checks If there's not another schema referenced, then we should use 'additionalProperties' rather than 'unevaluatedProperties'. This means that properties must be defined under the main 'properties' section and not just the if/then schema. Signed-off-by: Rob Herring --- test/schemas/conditionals-allof-example.yaml | 13 +++++++++---- test/schemas/conditionals-single-example.yaml | 6 +++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/test/schemas/conditionals-allof-example.yaml b/test/schemas/conditionals-allof-example.yaml index b6e2a404..37899d90 100644 --- a/test/schemas/conditionals-allof-example.yaml +++ b/test/schemas/conditionals-allof-example.yaml @@ -16,7 +16,15 @@ properties: - vendor,conditionals-allof-test-controller - vendor,second-conditionals-allof-test-controller -unevaluatedProperties: false + vendor,property: + description: A vendor prop + $ref: /schemas/types.yaml#/definitions/string + + vendor,other-property: + description: Other vendor prop + type: boolean + +additionalProperties: false allOf: - if: @@ -40,8 +48,5 @@ allOf: const: vendor,second-conditionals-allof-test-controller then: - properties: - vendor,other-property: true - required: - vendor,other-property diff --git a/test/schemas/conditionals-single-example.yaml b/test/schemas/conditionals-single-example.yaml index a542ba89..f2dbe253 100644 --- a/test/schemas/conditionals-single-example.yaml +++ b/test/schemas/conditionals-single-example.yaml @@ -16,6 +16,10 @@ properties: - vendor,test-controller - vendor,second-test-controller + vendor,property: + description: A vendor prop + $ref: /schemas/types.yaml#/definitions/string + if: properties: compatible: @@ -31,4 +35,4 @@ else: vendor,property: const: test5678 -unevaluatedProperties: false +additionalProperties: false From b1e6294cd6200c0ebd463a944ad57a4314a2506c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 28 Oct 2020 16:26:26 +0000 Subject: [PATCH 041/505] schemas: iio: Add schema covering generic IIO device properties Pulled across from linux kernel bindings/iio/iio-bindings.txt as part of an effort to convert all IIO binding descriptions to yaml. IIO also has a generic label property. That seems likely to potentially cause problems so is not included here for now. Perhaps we can generalize that anything called label is a string? Signed-off-by: Jonathan Cameron --- schemas/iio/iio.yaml | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 schemas/iio/iio.yaml diff --git a/schemas/iio/iio.yaml b/schemas/iio/iio.yaml new file mode 100644 index 00000000..fd654d62 --- /dev/null +++ b/schemas/iio/iio.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/iio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic IIO bindings + +select: true + +maintainers: + - Jonathan Cameron + +description: + This binding describes generic properties that can be applied to an + IIO device binding. + + As well, direct readings of channels on an IIO Device, an IIO device + can provide services in the form of readings and properties for + channels to consumer devices. For example, an ADC might provide + 3 channels to an analog accelerometer so that an accelerometer + driver can use them to read the voltages that correspond to the + accelerations on the 3 axis. + +properties: + "#io-channel-cells": + enum: [0, 1, 2] + description: > + Number of cells in an IIO specifier; Typically 0 for nodes + with a single IIO output and 1 for nodes with multiple IIO outputs. + A few unusual devices have a 2 level mapping. + + mount-matrix: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + minItems: 9 + maxItems: 9 + description: + 3x3 matrix specifying the sensor orientation wrt to a reference plane. + +additionalProperties: true From 170a908a2204838652407662d326f30cbeb87142 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 28 Oct 2020 16:33:30 +0000 Subject: [PATCH 042/505] schemas: iio: iio-consumer schema Moved over from bindings/iio/iio-bindings.txt file in the linux kernel. This schema describes the properties used by consumers of an io-channel. The provider must specify #io-channel-cells. Signed-off-by: Jonathan Cameron --- schemas/iio/iio-consumer.yaml | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 schemas/iio/iio-consumer.yaml diff --git a/schemas/iio/iio-consumer.yaml b/schemas/iio/iio-consumer.yaml new file mode 100644 index 00000000..abf86ca5 --- /dev/null +++ b/schemas/iio/iio-consumer.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/iio-consumer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Generic IIO consumer-bindings + +maintainers: + - Jonathan Cameron + +description: + This binding describes generic properties a consumer of the channels + provided by an IIO device may use. + + As well, direct readings of channels on an IIO Device, an IIO device + can provide services to consumer devices. Thes are in the form of channel + readings and properties. For example, an ADC might provide 3 channels to + an analog accelerometer so that an accelerometer driver can use them to + read the voltages that correspond to the accelerations on the 3 axis and + apply appropriate calibration to provide useful outputs. + +select: true + +properties: + io-channels: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: > + List of phandle and IIO specifier pairs, one pair for each IIO input + to the device. Note: if the IIO provider specifies '0' for + #io-channel-cells, then only the phandle portion of the pair will appear. + + io-channel-ranges: + type: boolean + description: > + Empty property indicating that child nodes can inherit named IIO channels + from this node. Useful for bus nodes to provide and IIO channel to their + children. + +dependencies: + io-channel-names: [io-channels] + io-channel-ranges: [io-channels] + +additionalProperties: true From ffe1d1735d53aaeda8711a3e86e5d78e9913af9e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 2 Nov 2020 16:58:52 -0600 Subject: [PATCH 043/505] schemas: Refactor vendor-props.yaml for better error messages Everything under a oneOf can give misleading error messages. Let's drop the now unused 'not' schema and refactor things out of the conditional schemas. Signed-off-by: Rob Herring --- meta-schemas/vendor-props.yaml | 38 +++++++--------------------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/meta-schemas/vendor-props.yaml b/meta-schemas/vendor-props.yaml index ec917126..a5f97a0b 100644 --- a/meta-schemas/vendor-props.yaml +++ b/meta-schemas/vendor-props.yaml @@ -20,56 +20,34 @@ patternProperties: additionalProperties: type: object + required: + - description oneOf: - - properties: # A deprecated property using 'not' - description: - type: string - not: true - required: - - description - - not - additionalProperties: false - - properties: # A boolean property - description: - type: string + description: true type: const: boolean deprecated: true required: - - description - type additionalProperties: false - properties: # A string property with exact values - description: - type: string + description: true enum: items: type: string const: type: string deprecated: true - required: - - description oneOf: - required: [ enum ] - required: [ const ] additionalProperties: false - - properties: # A property with a type and no additional constraints - description: - type: string + - properties: # A property with a type and additional constraints $ref: pattern: "types.yaml#[\/]{0,1}definitions\/.*" - deprecated: true - required: - - description - - $ref - - - properties: # A property with a type and additional constraints - description: - type: string allOf: items: - properties: @@ -77,8 +55,8 @@ additionalProperties: pattern: "types.yaml#[\/]{0,1}definitions\/.*" required: - $ref - required: - - description - - allOf + oneOf: + - required: [ $ref ] + - required: [ allOf ] ... From f66186d375125084bacb20aecbbc56cefc51569d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 2 Nov 2020 17:24:12 -0600 Subject: [PATCH 044/505] dtschema: Rework anyOf/oneOf error message printing Being extra verbose and picking best match doesn't really help for anyOf/oneOf errors. There's no point in repeating the file name and property for sub errors either, so let's drop that too. Signed-off-by: Rob Herring --- dtschema/lib.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 4a3180ae..160f1bf3 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -743,7 +743,6 @@ def check_quotes(self, err_msg, schema): self.check_quotes(err_msg, s) def format_error(filename, error, prefix="", nodename=None, verbose=False): - submsg = "" src = prefix + os.path.abspath(filename) + ':' if error.linecol[0] >= 0 : @@ -759,23 +758,24 @@ def format_error(filename, error, prefix="", nodename=None, verbose=False): src += str(path) + ":" src += ' ' - # An error on a conditional will have context with sub-errors - if error.context: - submsg = " (Possible causes of the failure):\n" - best = jsonschema.exceptions.best_match(error.context) - submsg += format_error(filename, best, prefix=prefix+"\t", nodename=nodename, verbose=verbose) + "\n" + #print(error.__dict__) + if verbose: + msg = str(error) + elif error.context: + # An error on a conditional will have context with sub-errors + msg = "'" + error.schema_path[-1] + "' conditional failed, one must be fixed:" for suberror in sorted(error.context, key=lambda e: e.path): - if suberror != best and len(suberror.path) > 0: - submsg += format_error(filename, suberror, prefix=prefix+"\t", nodename=nodename, verbose=verbose) + "\n" + if suberror.context: + msg += '\n' + format_error(filename, suberror, prefix=prefix+"\t", nodename=nodename, verbose=verbose) + else: + msg += '\n' + prefix + '\t' + suberror.message + + elif error.schema_path[-1] == 'oneOf': + msg = 'More than one condition true in oneOf schema:\n\t' + \ + '\t'.join(pprint.pformat(error.schema, width=72).splitlines(True)) - if verbose: - msg = str(error) else: msg = error.message - # Failures under 'oneOf', 'allOf', or 'anyOf' schema don't give useful - # error messages, so dump the schema in those cases. - if not error.path and error.validator in ['oneOf', 'allOf', 'anyOf']: - msg += '\n' + pprint.pformat(error.schema, width=72) - return src + msg + submsg + return src + msg From 436b8e7759e390c8fc2c2187e753a43c3562dfc9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 3 Nov 2020 15:27:38 -0600 Subject: [PATCH 045/505] dtschema: Don't print duplicate error messages Sometimes we may have duplicate error messages printed. They aren't really duplicates as they are the same schema check, but from different subschemas in an oneOf/anyOf. In any case, there's not any more useful information, so let's drop the message. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 160f1bf3..85d472d0 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -768,7 +768,7 @@ def format_error(filename, error, prefix="", nodename=None, verbose=False): for suberror in sorted(error.context, key=lambda e: e.path): if suberror.context: msg += '\n' + format_error(filename, suberror, prefix=prefix+"\t", nodename=nodename, verbose=verbose) - else: + elif not suberror.message in msg: msg += '\n' + prefix + '\t' + suberror.message elif error.schema_path[-1] == 'oneOf': From ab5a73fcef26af69e79ebb6669432c98156af870 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 11 Nov 2020 11:17:26 -0600 Subject: [PATCH 046/505] dt-validate: Improve filtering disabled node required properties If we have required properties expressed as: oneOf: - required: [ foo ] - required: [ bar ] The disabled node filtering of required properties on disabled nodes misses these cases because the required property error is in the sub-schema. So we need to check the error contexts, too. Signed-off-by: Rob Herring --- tools/dt-validate | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/dt-validate b/tools/dt-validate index c03efd38..03ff2625 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -60,9 +60,15 @@ class schema_group(): # any error message reporting a missing property. if isinstance(error.instance, dict) and \ 'status' in error.instance and \ - 'disabled' in error.instance['status'] and \ - 'required property' in error.message: - continue + 'disabled' in error.instance['status']: + if 'required property' in error.message: + continue + elif error.context: + for e in error.context: + if not 'required property' in e.message: + break + else: + continue print(dtschema.format_error(filename, error, nodename=nodename, verbose=verbose) + '\n\tFrom schema: ' + schema['$filename'], From 1356213b2c453c73f3b19ff4d3c2e17c4b5a1cdf Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Fri, 30 Oct 2020 22:09:16 +0530 Subject: [PATCH 047/505] schemas: Add graph binding schema Convert device tree bindings OF graph to YAML format. Currently graph.txt in Linux kernel is referenced in multiple files and all of these need to use schema references. For users of the graph binding, they should reference to the graph schema from either 'ports' or 'port' property: properties: ports: type: object $ref: /schemas/graph.yaml#/properties/ports properties: port@0: description: What data this port has ... Or: properties: port: description: What data this port has $ref: /schemas/graph.yaml#/properties/port Signed-off-by: Sameer Pujar Acked-by: Philipp Zabel Reviewed-by: Sam Ravnborg Reviewed-by: Laurent Pinchart Signed-off-by: Rob Herring --- schemas/graph.yaml | 202 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 schemas/graph.yaml diff --git a/schemas/graph.yaml b/schemas/graph.yaml new file mode 100644 index 00000000..b1e8519b --- /dev/null +++ b/schemas/graph.yaml @@ -0,0 +1,202 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/graph.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: Common bindings for device graphs + +description: | + The hierarchical organisation of the device tree is well suited to describe + control flow to devices, but there can be more complex connections between + devices that work together to form a logical compound device, following an + arbitrarily complex graph. + There already is a simple directed graph between devices tree nodes using + phandle properties pointing to other nodes to describe connections that + can not be inferred from device tree parent-child relationships. The device + tree graph bindings described herein abstract more complex devices that can + have multiple specifiable ports, each of which can be linked to one or more + ports of other devices. + + These common bindings do not contain any information about the direction or + type of the connections, they just map their existence. Specific properties + may be described by specialized bindings depending on the type of connection. + + To see how this binding applies to video pipelines, for example, see + Documentation/devicetree/bindings/media/video-interfaces.txt. + Here the ports describe data interfaces, and the links between them are + the connecting data buses. A single port with multiple connections can + correspond to multiple devices being connected to the same physical bus. + +maintainers: + - Philipp Zabel + +select: false + +properties: + port: + type: object + description: + If there is more than one endpoint node or 'reg' property present in + endpoint nodes then '#address-cells' and '#size-cells' properties are + required. + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^endpoint(@[0-9a-f]+)?$": + type: object + properties: + reg: + maxItems: 1 + + remote-endpoint: + description: | + phandle to an 'endpoint' subnode of a remote device node. + $ref: /schemas/types.yaml#/definitions/phandle + + ports: + type: object + description: + If there is more than one port node or 'reg' property present in port + nodes then '#address-cells' and '#size-cells' properties are required. + In such cases all port nodes can be grouped under 'ports' independently + from any other child device nodes a device might have. + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^port(@[0-9a-f]+)?$": + $ref: "#/properties/port" + type: object + + properties: + reg: + maxItems: 1 + + required: + - reg + + oneOf: + - required: + - port + - required: + - "#address-cells" + - "#size-cells" + + additionalProperties: false + +additionalProperties: true + +examples: + # Organisation of ports and endpoints: + # + # Ports are described by child 'port' nodes contained in the device node. + # Each port node contains an 'endpoint' subnode for each remote device port + # connected to this port. If a single port is connected to more than one + # remote device, an 'endpoint' child node must be provided for each link. + # If more than one port is present in a device node or there is more than + # one endpoint at a port, or a port node needs to be associated with a + # selected hardware interface, a common scheme using '#address-cells', + # '#size-cells' and 'reg' properties is used to number the nodes. + - | + device { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + endpoint@0 { + reg = <0>; + // ... + }; + endpoint@1 { + reg = <1>; + // ... + }; + }; + + port@1 { + reg = <1>; + + endpoint { + // ... + }; + }; + }; + + # All 'port' nodes can be grouped under an optional 'ports' node, which + # allows to specify #address-cells, #size-cells properties for the 'port' + # nodes independently from any other child device nodes a device might + # have. + - | + device { + // ... + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + // ... + + endpoint@0 { + reg = <0>; + // ... + }; + endpoint@1 { + reg = <1>; + // ... + }; + }; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + // ... + }; + }; + }; + + # Links between endpoints: + # + # Each endpoint should contain a 'remote-endpoint' phandle property that + # points to the corresponding endpoint in the port of the remote device. + # In turn, the remote endpoint should contain a 'remote-endpoint' property. + # If it has one, it must not point to anything other than the local endpoint. + # Two endpoints with their 'remote-endpoint' phandles pointing at each other + # form a link between the containing ports. + - | + device-1 { + port { + device_1_output: endpoint { + remote-endpoint = <&device_2_input>; + }; + }; + }; + + device-2 { + port { + device_2_input: endpoint { + remote-endpoint = <&device_1_output>; + }; + }; + }; + +... From a3b6a0c29888eac2140ee4c9815b0e182fe4020f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 17 Nov 2020 09:06:55 -0600 Subject: [PATCH 048/505] meta-schemas: Allow '$ref' instead of 'type' for nodes Signed-off-by: Rob Herring --- meta-schemas/core.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index 844803c1..4c644bf2 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -69,9 +69,12 @@ definitions: - type then: $ref: "nodes.yaml#" - - dependencies: - properties: [ type ] + - if: + required: [ properties ] + then: + anyOf: + - required: [ type ] + - required: [ $ref ] dependencies: "#size-cells": [ "#address-cells" ] From 6de1c45de79480b9d04e2a11e2b1488635a1bde1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 17 Nov 2020 10:49:28 -0600 Subject: [PATCH 049/505] schemas: iio: Drop io-channel-ranges 'io-channel-ranges' is defined to be a consumer property, but it is frequently defined on the provider side which has no effect (at least for Linux). It's unlikely that we'd have a case where we really have a bunch of child nodes sharing an io-channel and it's too burdensome to just use 'io-channels' in each child node. So let's just drop 'io-channel-ranges'. Signed-off-by: Rob Herring --- schemas/iio/iio-consumer.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/schemas/iio/iio-consumer.yaml b/schemas/iio/iio-consumer.yaml index abf86ca5..ad7d290d 100644 --- a/schemas/iio/iio-consumer.yaml +++ b/schemas/iio/iio-consumer.yaml @@ -30,15 +30,7 @@ properties: to the device. Note: if the IIO provider specifies '0' for #io-channel-cells, then only the phandle portion of the pair will appear. - io-channel-ranges: - type: boolean - description: > - Empty property indicating that child nodes can inherit named IIO channels - from this node. Useful for bus nodes to provide and IIO channel to their - children. - dependencies: io-channel-names: [io-channels] - io-channel-ranges: [io-channels] additionalProperties: true From 6015fae8144667824cbe437956aab2f207c0adab Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Dec 2020 14:03:57 -0700 Subject: [PATCH 050/505] Correct JSON pointers in $ref's A JSON pointer fragment must begin with a '/' after the '#'. Without a /, the string should be interpretted as a subschema identifier. The jsonschema module currently doesn't handle subschema identifiers and incorrectly allows JSON pointers to begin without a '/'. Signed-off-by: Rob Herring --- meta-schemas/cell.yaml | 18 +++++++++--------- meta-schemas/clocks.yaml | 14 +++++++------- meta-schemas/core.yaml | 12 ++++++------ meta-schemas/gpios.yaml | 8 ++++---- meta-schemas/interrupts.yaml | 6 +++--- meta-schemas/mailbox.yaml | 4 ++-- meta-schemas/reset.yaml | 2 +- schemas/aliases.yaml | 2 +- schemas/chosen.yaml | 18 +++++++++--------- schemas/root-node.yaml | 2 +- test/schemas/good-example.yaml | 12 ++++++------ 11 files changed, 49 insertions(+), 49 deletions(-) diff --git a/meta-schemas/cell.yaml b/meta-schemas/cell.yaml index 91c350ef..9fb51484 100644 --- a/meta-schemas/cell.yaml +++ b/meta-schemas/cell.yaml @@ -13,11 +13,11 @@ array: maxItems: const: 1 required: [maxItems] - - $ref: '#single-array' + - $ref: '#/single-array' - propertyNames: oneOf: - enum: [maxItems] - - $ref: '#single-array-names' + - $ref: '#/single-array-names' - properties: minItems: minimum: 1 @@ -26,19 +26,19 @@ array: oneOf: type: array items: - $ref: '#array' + $ref: '#/array' anyOf: type: array items: - $ref: '#array' + $ref: '#/array' items: oneOf: - type: object allOf: - - $ref: '#array' + - $ref: '#/array' - type: array items: - $ref: '#single' + $ref: '#/single' additionalItems: type: boolean const: true @@ -46,7 +46,7 @@ array: additionalProperties: false - - $ref: '#single' + - $ref: '#/single' single-array: properties: @@ -71,6 +71,6 @@ single-array-names: single: allOf: - - $ref: '#single-array' + - $ref: '#/single-array' - propertyNames: - $ref: '#single-array-names' + $ref: '#/single-array-names' diff --git a/meta-schemas/clocks.yaml b/meta-schemas/clocks.yaml index ac6cdeb6..9871d08b 100644 --- a/meta-schemas/clocks.yaml +++ b/meta-schemas/clocks.yaml @@ -9,26 +9,26 @@ $schema: "http://json-schema.org/draft-07/schema#" properties: clocks: oneOf: - - $ref: "cell.yaml#array" + - $ref: "cell.yaml#/array" - $ref: "nodes.yaml" clock-ranges: $ref: "boolean.yaml" clock-indices: - $ref: "cell.yaml#array" + $ref: "cell.yaml#/array" assigned-clocks: - $ref: "cell.yaml#array" + $ref: "cell.yaml#/array" assigned-clock-parents: - $ref: "cell.yaml#array" + $ref: "cell.yaml#/array" assigned-clock-rates: - $ref: "cell.yaml#array" + $ref: "cell.yaml#/array" clock-frequency: - $ref: "cell.yaml#single" + $ref: "cell.yaml#/single" properties: default: {} required: [default] bus-frequency: - $ref: "cell.yaml#single" + $ref: "cell.yaml#/single" properties: default: {} required: [default] diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index 4c644bf2..3a6bf8af 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -13,7 +13,7 @@ allOf: definitions: all-properties: allOf: - - $ref: "#definitions/core-properties" + - $ref: "#/definitions/core-properties" - $ref: "clocks.yaml#" - $ref: "gpios.yaml#" - $ref: "interrupts.yaml#" @@ -23,13 +23,13 @@ definitions: core-properties: properties: reg: - $ref: "cell.yaml#array" + $ref: "cell.yaml#/array" compatible: $ref: "string-array.yaml" $nodename: $ref: "string-array.yaml" memory-region: - $ref: "cell.yaml#array" + $ref: "cell.yaml#/array" memory-region-names: $ref: "string-array.yaml" propertyNames: @@ -46,7 +46,7 @@ definitions: $ref: "string-array.yaml" '^#.*-cells$': - $ref: "cell.yaml#single" + $ref: "cell.yaml#/single" '^.*$': properties: @@ -82,9 +82,9 @@ definitions: properties: patternProperties: - $ref: "#definitions/all-properties" + $ref: "#/definitions/all-properties" properties: - $ref: "#definitions/all-properties" + $ref: "#/definitions/all-properties" anyOf: - required: diff --git a/meta-schemas/gpios.yaml b/meta-schemas/gpios.yaml index 84cf9bda..add30fd1 100644 --- a/meta-schemas/gpios.yaml +++ b/meta-schemas/gpios.yaml @@ -12,15 +12,15 @@ properties: gpio-line-names: $ref: "string-array.yaml" ngpios: - $ref: "cell.yaml#single" + $ref: "cell.yaml#/single" gpio-ranges: - $ref: "cell.yaml#array" + $ref: "cell.yaml#/array" gpios: - $ref: "cell.yaml#array" + $ref: "cell.yaml#/array" patternProperties: '(? Date: Tue, 1 Dec 2020 14:18:53 -0700 Subject: [PATCH 051/505] Remove 'allOf' when used with '$ref' In json-schema 2019.09 syntax, keywords in addition to an $ref are no longer ignored so an 'allOf' is no longer needed. We fix this up when preprocessing the schemas until jsonschema module has 2019.09 support. Remove all the cases in the schemas and test schemas so others don't copy the old syntax. Signed-off-by: Rob Herring --- schemas/cache-controller.yaml | 5 +- schemas/chosen.yaml | 18 +++---- schemas/dt-core.yaml | 17 +++--- schemas/gpio/gpio.yaml | 9 ++-- schemas/pci/pci-bus.yaml | 15 ++---- test/schemas/good-example.yaml | 95 ++++++++++++++-------------------- 6 files changed, 64 insertions(+), 95 deletions(-) diff --git a/schemas/cache-controller.yaml b/schemas/cache-controller.yaml index 9b347e69..835b4b80 100644 --- a/schemas/cache-controller.yaml +++ b/schemas/cache-controller.yaml @@ -15,9 +15,8 @@ properties: pattern: "^(cache-controller|cpu)(@[0-9a-f,]+)*$" cache-level: - allOf: - - $ref: "/schemas/types.yaml#/definitions/uint32" - - maximum: 32 + $ref: "/schemas/types.yaml#/definitions/uint32" + maximum: 32 cache-unified: $ref: "/schemas/types.yaml#/definitions/flag" diff --git a/schemas/chosen.yaml b/schemas/chosen.yaml index 75300d36..a0dde76d 100644 --- a/schemas/chosen.yaml +++ b/schemas/chosen.yaml @@ -75,18 +75,16 @@ properties: a different secondary CPU release mechanism). linux,elfcorehdr: - allOf: - - $ref: types.yaml#/definitions/uint64-array - - maxItems: 2 + $ref: types.yaml#/definitions/uint64-array + maxItems: 2 description: This property (currently used only on arm64) holds the memory range, the address and the size, of the elf core header which mainly describes the panicked kernel\'s memory layout as PT_LOAD segments of elf format. linux,usable-memory-range: - allOf: - - $ref: types.yaml#/definitions/uint64-array - - maxItems: 2 + $ref: types.yaml#/definitions/uint64-array + maxItems: 2 description: | This property (arm64 only) holds a base address and size, describing a limited region in which memory may be considered available for use by @@ -126,8 +124,7 @@ properties: linux,initrd-end is exclusive. linux,pci-probe-only: - allOf: - - $ref: types.yaml#/definitions/uint32 + $ref: types.yaml#/definitions/uint32 enum: [ 0, 1 ] description: Optional property which takes a single-cell argument. If '0', then Linux @@ -135,9 +132,8 @@ properties: assign devices and instead use them as they are configured already. stdout-path: - allOf: - - $ref: types.yaml#/definitions/string - - pattern: "^[a-zA-Z0-9@/,+\\-._]*(:[0-9]*[noe]?[78]?[r]?)?$" + $ref: types.yaml#/definitions/string + pattern: "^[a-zA-Z0-9@/,+\\-._]*(:[0-9]*[noe]?[78]?[r]?)?$" description: | Device trees may specify the device to be used for boot console output with a stdout-path property under /chosen, as described in the Devicetree diff --git a/schemas/dt-core.yaml b/schemas/dt-core.yaml index 3d871b3b..4296fc44 100644 --- a/schemas/dt-core.yaml +++ b/schemas/dt-core.yaml @@ -18,8 +18,7 @@ properties: $nodename: $ref: "types.yaml#/definitions/string" compatible: - allOf: - - $ref: "types.yaml#/definitions/string-array" + $ref: "types.yaml#/definitions/string-array" items: pattern: "^[a-zA-Z][a-zA-Z0-9,+\\-._]+$" dma-coherent: @@ -35,17 +34,13 @@ properties: reg: $ref: "types.yaml#/definitions/uint32-matrix" status: - allOf: - - $ref: "types.yaml#/definitions/string" - - items: - - enum: [ okay, disabled ] + $ref: "types.yaml#/definitions/string" + enum: [ okay, disabled ] patternProperties: "^#.*-cells$": - allOf: - - $ref: "types.yaml#/definitions/uint32" - - items: - - items: - maximum: 8 + $ref: "types.yaml#/definitions/uint32" + items: + maximum: 8 ".*-names$": $ref: "types.yaml#/definitions/non-unique-string-array" diff --git a/schemas/gpio/gpio.yaml b/schemas/gpio/gpio.yaml index 85435d4b..612fc8f0 100644 --- a/schemas/gpio/gpio.yaml +++ b/schemas/gpio/gpio.yaml @@ -19,11 +19,10 @@ properties: ngpios: $ref: "/schemas/types.yaml#/definitions/uint32" gpio-reserved-ranges: - allOf: - - $ref: "/schemas/types.yaml#/definitions/uint32-matrix" - - items: - minItems: 2 - maxItems: 2 + $ref: "/schemas/types.yaml#/definitions/uint32-matrix" + items: + minItems: 2 + maxItems: 2 gpio-ranges: $ref: "/schemas/types.yaml#/definitions/phandle-array" diff --git a/schemas/pci/pci-bus.yaml b/schemas/pci/pci-bus.yaml index 74c67b3f..37c2f9b2 100644 --- a/schemas/pci/pci-bus.yaml +++ b/schemas/pci/pci-bus.yaml @@ -75,8 +75,7 @@ properties: const: pci bus-range: - allOf: - - $ref: /schemas/types.yaml#/definitions/uint32-array + $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 2 maxItems: 2 items: @@ -106,12 +105,10 @@ properties: maximum: 7 linux,pci-domain: - allOf: - - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: /schemas/types.yaml#/definitions/uint32 max-link-speed: - allOf: - - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: /schemas/types.yaml#/definitions/uint32 enum: [ 1, 2, 3, 4 ] reset-gpios: @@ -127,13 +124,11 @@ properties: vendor-id: description: The PCI vendor ID - allOf: - - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: /schemas/types.yaml#/definitions/uint32 device-id: description: The PCI device ID - allOf: - - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: /schemas/types.yaml#/definitions/uint32 patternProperties: "^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@1?[0-9a-f](,[0-7])?$": diff --git a/test/schemas/good-example.yaml b/test/schemas/good-example.yaml index c554dfcc..7d771f81 100644 --- a/test/schemas/good-example.yaml +++ b/test/schemas/good-example.yaml @@ -88,50 +88,44 @@ properties: description: A vendor specific boolean property vendor,int-prop: - allOf: - - $ref: "/schemas/types.yaml#/definitions/uint32" - - enum: [ 1, 2, 3 ] + $ref: "/schemas/types.yaml#/definitions/uint32" + enum: [ 1, 2, 3 ] description: Vendor specific single cell integer property vendor,int-array-prop: - allOf: - - $ref: "/schemas/types.yaml#/definitions/uint32-array" - - items: - minimum: 5 - maximum: 10 + $ref: "/schemas/types.yaml#/definitions/uint32-array" + items: + minimum: 5 + maximum: 10 description: Vendor specific integer array property vendor,int-array-prop-2: - allOf: - - $ref: "/schemas/types.yaml#/definitions/uint32-array" - - items: - - const: 5 - - const: 10 + $ref: "/schemas/types.yaml#/definitions/uint32-array" + items: + - const: 5 + - const: 10 description: Vendor specific integer array property vendor,int-array-size-only-prop: - allOf: - - $ref: "/schemas/types.yaml#/definitions/uint32-array" + $ref: "/schemas/types.yaml#/definitions/uint32-array" minItems: 2 maxItems: 5 description: Vendor specific integer array property with only a size range. This can use either form of brackets. vendor,string-prop: - allOf: - - $ref: "/schemas/types.yaml#/definitions/string" - - enum: - - foo - - bar + $ref: "/schemas/types.yaml#/definitions/string" + enum: + - foo + - bar description: Vendor specific single string property vendor,string-list-prop: - allOf: - - $ref: "/schemas/types.yaml#/definitions/string-array" - - minItems: 2 - items: - - const: foobar - - const: foobaz + $ref: "/schemas/types.yaml#/definitions/string-array" + minItems: 2 + items: + - const: foobar + - const: foobaz description: Vendor specific string list property vendor,int8-prop: @@ -139,39 +133,32 @@ properties: description: Vendor specific 8-bit integer property vendor,int8-array-prop: - allOf: - - $ref: /schemas/types.yaml#/definitions/uint8-array - - items: - - minItems: 2 - maxItems: 3 + $ref: /schemas/types.yaml#/definitions/uint8-array + items: + - minItems: 2 + maxItems: 3 description: A vendor specific uint8 array property with 2 or 3 entries vendor,int16-prop: - allOf: - - $ref: /schemas/types.yaml#/definitions/uint16 - - enum: [ 1, 2, 3 ] + $ref: /schemas/types.yaml#/definitions/uint16 + enum: [ 1, 2, 3 ] description: Vendor specific 16-bit integer property vendor,int16-array-prop: - allOf: - - $ref: /schemas/types.yaml#/definitions/uint16-array - - items: - - const: 1 - - const: 2 + $ref: /schemas/types.yaml#/definitions/uint16-array + items: + - const: 1 + - const: 2 description: Vendor specific 16-bit integer array property vendor,int64-prop: - allOf: - - $ref: /schemas/types.yaml#/definitions/uint64 - - items: - - items: - - minimum: 0x1234 + $ref: /schemas/types.yaml#/definitions/uint64 + minimum: 0x1234 description: Vendor specific 16-bit integer property vendor,int64-array-prop: - allOf: - - $ref: /schemas/types.yaml#/definitions/uint64-array + $ref: /schemas/types.yaml#/definitions/uint64-array description: Vendor specific 64-bit integer array property vendor,phandle-prop: @@ -179,19 +166,17 @@ properties: description: Vendor specific single cell phandle property vendor,phandle-array-prop: - allOf: - - $ref: "/schemas/types.yaml#/definitions/phandle-array" - - minItems: 2 + $ref: "/schemas/types.yaml#/definitions/phandle-array" + minItems: 2 description: Vendor specific array of phandles property vendor,phandle-with-fixed-cells: - allOf: - - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: "/schemas/types.yaml#/definitions/phandle-array" + items: - items: - - items: - - description: the phandle to something - - description: the 1st cell data - - description: the 2nd cell data + - description: the phandle to something + - description: the 1st cell data + - description: the 2nd cell data description: Vendor specific array of phandles property From b92867d7534234b7fe941e2473ecbf00884ea835 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 18 Nov 2020 12:18:10 -0600 Subject: [PATCH 052/505] Allow using '$defs' keyword json-schema 2019.09 standardized '$defs' keyword for reusable schema fragments. Let's allow it to be used in schemas. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- meta-schemas/base.yaml | 1 + meta-schemas/keywords.yaml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 85d472d0..e835543c 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -344,7 +344,7 @@ def fixup_schema(schema): for prop in v: fixup_schema(v[prop]) - if not k in ['properties', 'patternProperties']: + if not k in ['properties', 'patternProperties', '$defs']: continue walk_properties(v) diff --git a/meta-schemas/base.yaml b/meta-schemas/base.yaml index 5cfc27e8..a63e1ec1 100644 --- a/meta-schemas/base.yaml +++ b/meta-schemas/base.yaml @@ -42,6 +42,7 @@ properties: anyOf: true oneOf: true definitions: true + $defs: true additionalProperties: true dependencies: true patternProperties: true diff --git a/meta-schemas/keywords.yaml b/meta-schemas/keywords.yaml index aa88f726..3c41f3ac 100644 --- a/meta-schemas/keywords.yaml +++ b/meta-schemas/keywords.yaml @@ -94,6 +94,7 @@ properties: $ref: "#/definitions/sub-schemas" const: true default: true + $defs: true definitions: true dependencies: true deprecated: true From d4edb088acd02b904c193d9199229dbc3ad25b97 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 18 Nov 2020 11:40:20 -0600 Subject: [PATCH 053/505] schemas: Improve graph schema to allow extending The initial graph schema is not flexible enough to handle cases with additional properties in endpoint nodes. The problem is a $ref plus 'unevaluatedProperties: false' only works on immediate properties and doesn't work for child properties in an endpoint schema. So endpoint nodes must have their own $ref. Rework the to add base definitions 'port-base' and 'endpoint-base' which can be used by graph users to extend the schema. For users without additional properties, they can reference '/properties/port' and 'properties/endpoint'. Signed-off-by: Rob Herring --- schemas/graph.yaml | 57 +++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/schemas/graph.yaml b/schemas/graph.yaml index b1e8519b..617bdc57 100644 --- a/schemas/graph.yaml +++ b/schemas/graph.yaml @@ -33,8 +33,19 @@ maintainers: select: false -properties: - port: +$defs: + endpoint-base: + type: object + properties: + reg: + maxItems: 1 + + remote-endpoint: + description: | + phandle to an 'endpoint' subnode of a remote device node. + $ref: /schemas/types.yaml#/definitions/phandle + + port-base: type: object description: If there is more than one endpoint node or 'reg' property present in @@ -48,17 +59,30 @@ properties: "#size-cells": const: 0 - patternProperties: - "^endpoint(@[0-9a-f]+)?$": + reg: + maxItems: 1 + + endpoint: type: object - properties: - reg: - maxItems: 1 - remote-endpoint: - description: | - phandle to an 'endpoint' subnode of a remote device node. - $ref: /schemas/types.yaml#/definitions/phandle + patternProperties: + "^endpoint@[0-9a-f]+$": + $ref: "#/$defs/endpoint-base" + required: + - reg + +properties: + endpoint: + $ref: "#/$defs/endpoint-base" + unevaluatedProperties: false + + port: + $ref: "#/$defs/port-base" + unevaluatedProperties: false + + patternProperties: + "^endpoint(@[0-9a-f]+)?$": + $ref: "#/properties/endpoint" ports: type: object @@ -75,15 +99,12 @@ properties: "#size-cells": const: 0 - patternProperties: - "^port(@[0-9a-f]+)?$": - $ref: "#/properties/port" + port: type: object - properties: - reg: - maxItems: 1 - + patternProperties: + "^port@[0-9a-f]+$": + type: object required: - reg From 1952c756baa3061502a9f96a331655bf1228cb16 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 21 Dec 2020 14:29:39 -0700 Subject: [PATCH 054/505] meta-schemas: Ensure 'minItems' is never 0 Setting 'minItems' to 0 doesn't make sense as that's just no property present. Signed-off-by: Rob Herring --- meta-schemas/keywords.yaml | 3 ++- schemas/simple-bus.yaml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/meta-schemas/keywords.yaml b/meta-schemas/keywords.yaml index 3c41f3ac..64ead999 100644 --- a/meta-schemas/keywords.yaml +++ b/meta-schemas/keywords.yaml @@ -115,7 +115,8 @@ properties: - type: array items: $ref: "#/definitions/sub-schemas" - minItems: true + minItems: + minimum: 1 minimum: true maintainers: true maxItems: true diff --git a/schemas/simple-bus.yaml b/schemas/simple-bus.yaml index 949e6c9c..bc824083 100644 --- a/schemas/simple-bus.yaml +++ b/schemas/simple-bus.yaml @@ -40,7 +40,7 @@ patternProperties: - items: minItems: 3 maxItems: 7 - minItems: 0 + minItems: 1 maxItems: 1024 - $ref: "types.yaml#/definitions/flag" anyOf: From 62f4e39189515d1b6ddefaea5e702fc790bde010 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 23 Dec 2020 11:27:53 -0700 Subject: [PATCH 055/505] meta-schemas: Also check redundant array sizes if minItems is not present It's also redundant if an array defines 'maxItems' with same length as 'items' and 'minItems' is not specified. Signed-off-by: Rob Herring --- meta-schemas/items.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/meta-schemas/items.yaml b/meta-schemas/items.yaml index 7138b4dd..2b767ec6 100644 --- a/meta-schemas/items.yaml +++ b/meta-schemas/items.yaml @@ -27,7 +27,6 @@ allOf: - if: required: - items - - minItems - maxItems oneOf: - properties: From 92925913da412243cf927da405889156b930c4c7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 23 Dec 2020 11:16:46 -0700 Subject: [PATCH 056/505] meta-schemas: Add missing 1 item array check Also check for redundant 'maxItems: 1' with an 'items' list. Signed-off-by: Rob Herring --- meta-schemas/items.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/meta-schemas/items.yaml b/meta-schemas/items.yaml index 2b767ec6..28b6b415 100644 --- a/meta-schemas/items.yaml +++ b/meta-schemas/items.yaml @@ -29,6 +29,13 @@ allOf: - items - maxItems oneOf: + - properties: + items: + type: array + minItems: 1 + maxItems: 1 + maxItems: + const: 1 - properties: items: type: array From d6b249ea1a216da0f61461d3d59d56a973e3aaab Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 21 Dec 2020 16:52:34 -0700 Subject: [PATCH 057/505] meta-schemas: Add some missing common properties Add meta-schemas for *-supply, dma, iio, iommu, phy, power-domain, and pwm binding properties. Signed-off-by: Rob Herring --- meta-schemas/core.yaml | 14 ++++++++++++++ meta-schemas/dma.yaml | 13 +++++++++++++ meta-schemas/iio.yaml | 13 +++++++++++++ meta-schemas/iommu.yaml | 10 ++++++++++ meta-schemas/phy.yaml | 13 +++++++++++++ meta-schemas/power-domain.yaml | 13 +++++++++++++ meta-schemas/pwm.yaml | 13 +++++++++++++ 7 files changed, 89 insertions(+) create mode 100644 meta-schemas/dma.yaml create mode 100644 meta-schemas/iio.yaml create mode 100644 meta-schemas/iommu.yaml create mode 100644 meta-schemas/phy.yaml create mode 100644 meta-schemas/power-domain.yaml create mode 100644 meta-schemas/pwm.yaml diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index 3a6bf8af..3245df31 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -15,13 +15,22 @@ definitions: allOf: - $ref: "#/definitions/core-properties" - $ref: "clocks.yaml#" + - $ref: "dma.yaml#" - $ref: "gpios.yaml#" + - $ref: "iio.yaml#" - $ref: "interrupts.yaml#" + - $ref: "iommu.yaml#" + - $ref: "mailbox.yaml#" + - $ref: "phy.yaml#" + - $ref: "power-domain.yaml#" + - $ref: "pwm.yaml#" - $ref: "reset.yaml#" - $ref: "mailbox.yaml#" - $ref: "vendor-props.yaml#" core-properties: properties: + ranges: + $ref: "cell.yaml#/array" reg: $ref: "cell.yaml#/array" compatible: @@ -48,6 +57,10 @@ definitions: '^#.*-cells$': $ref: "cell.yaml#/single" + '-supply$': + propertyNames: + enum: [ description, deprecated ] + '^.*$': properties: # 'boolean' and 'object' are the only native types allowed @@ -79,6 +92,7 @@ definitions: dependencies: "#size-cells": [ "#address-cells" ] memory-region-names: [ memory-region ] + reg-names: [ reg ] properties: patternProperties: diff --git a/meta-schemas/dma.yaml b/meta-schemas/dma.yaml new file mode 100644 index 00000000..f8cf7f1b --- /dev/null +++ b/meta-schemas/dma.yaml @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2020 Arm Ltd. +%YAML 1.2 +--- +$id: "http://devicetree.org/meta-schemas/dma.yaml#" +$schema: "http://json-schema.org/draft-07/schema#" + +properties: + dmas: + $ref: "cell.yaml#/array" + +dependencies: + dma-names: [dmas] diff --git a/meta-schemas/iio.yaml b/meta-schemas/iio.yaml new file mode 100644 index 00000000..85c8397a --- /dev/null +++ b/meta-schemas/iio.yaml @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2020 Arm Ltd. +%YAML 1.2 +--- +$id: "http://devicetree.org/meta-schemas/iio.yaml#" +$schema: "http://json-schema.org/draft-07/schema#" + +properties: + io-channels: + $ref: "cell.yaml#/array" + +dependencies: + io-channel-names: [io-channels] diff --git a/meta-schemas/iommu.yaml b/meta-schemas/iommu.yaml new file mode 100644 index 00000000..0e4951bc --- /dev/null +++ b/meta-schemas/iommu.yaml @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2020 Arm Ltd. +%YAML 1.2 +--- +$id: "http://devicetree.org/meta-schemas/iommu.yaml#" +$schema: "http://json-schema.org/draft-07/schema#" + +properties: + iommus: + $ref: "cell.yaml#/array" diff --git a/meta-schemas/phy.yaml b/meta-schemas/phy.yaml new file mode 100644 index 00000000..d7a321d2 --- /dev/null +++ b/meta-schemas/phy.yaml @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2020 Arm Ltd. +%YAML 1.2 +--- +$id: "http://devicetree.org/meta-schemas/phy.yaml#" +$schema: "http://json-schema.org/draft-07/schema#" + +properties: + phys: + $ref: "cell.yaml#/array" + +dependencies: + phy-names: [phys] diff --git a/meta-schemas/power-domain.yaml b/meta-schemas/power-domain.yaml new file mode 100644 index 00000000..c5022b78 --- /dev/null +++ b/meta-schemas/power-domain.yaml @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2020 Arm Ltd. +%YAML 1.2 +--- +$id: "http://devicetree.org/meta-schemas/power-domain.yaml#" +$schema: "http://json-schema.org/draft-07/schema#" + +properties: + power-domains: + $ref: "cell.yaml#/array" + +dependencies: + power-domain-names: [power-domains] diff --git a/meta-schemas/pwm.yaml b/meta-schemas/pwm.yaml new file mode 100644 index 00000000..51af653a --- /dev/null +++ b/meta-schemas/pwm.yaml @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2020 Arm Ltd. +%YAML 1.2 +--- +$id: "http://devicetree.org/meta-schemas/pwm.yaml#" +$schema: "http://json-schema.org/draft-07/schema#" + +properties: + pwms: + $ref: "cell.yaml#/array" + +dependencies: + pwm-names: [pwms] From 29a3778f83a33126c3131f1c04c2c7b52ee6292d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 23 Dec 2020 11:17:49 -0700 Subject: [PATCH 058/505] meta-schemas: Add check for correct JSON pointer format A JSON pointer should always begin with a '/', so check for this. Signed-off-by: Rob Herring --- meta-schemas/core.yaml | 2 ++ meta-schemas/vendor-props.yaml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index 3245df31..369858a6 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -70,6 +70,8 @@ definitions: $ref: "#/definitions/all-properties" patternProperties: $ref: "#/definitions/all-properties" + $ref: + pattern: '(#$|#\/)?' allOf: - $ref: "items.yaml#" diff --git a/meta-schemas/vendor-props.yaml b/meta-schemas/vendor-props.yaml index a5f97a0b..0105f856 100644 --- a/meta-schemas/vendor-props.yaml +++ b/meta-schemas/vendor-props.yaml @@ -47,12 +47,12 @@ additionalProperties: - properties: # A property with a type and additional constraints $ref: - pattern: "types.yaml#[\/]{0,1}definitions\/.*" + pattern: "types.yaml#\/definitions\/" allOf: items: - properties: $ref: - pattern: "types.yaml#[\/]{0,1}definitions\/.*" + pattern: "types.yaml#\/definitions\/" required: - $ref oneOf: From 45027cc1d09657951dae66431e00c7c39f7ec3dd Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 23 Dec 2020 11:18:44 -0700 Subject: [PATCH 059/505] meta-schemas: Rework cell array and single meta-schema Signed-off-by: Rob Herring --- meta-schemas/cell.yaml | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/meta-schemas/cell.yaml b/meta-schemas/cell.yaml index 9fb51484..02c99e4a 100644 --- a/meta-schemas/cell.yaml +++ b/meta-schemas/cell.yaml @@ -8,16 +8,12 @@ $schema: "http://json-schema.org/draft-07/schema#" array: anyOf: - - allOf: - - properties: - maxItems: - const: 1 - required: [maxItems] - - $ref: '#/single-array' - - propertyNames: - oneOf: - - enum: [maxItems] - - $ref: '#/single-array-names' + - properties: + maxItems: + const: 1 + required: [maxItems] + propertyNames: + enum: [maxItems, description, deprecated] - properties: minItems: minimum: 1 @@ -48,7 +44,7 @@ array: - $ref: '#/single' -single-array: +single: properties: description: true const: @@ -65,12 +61,5 @@ single-array: minimum: [maximum] maximum: [minimum] -single-array-names: - enum: [ description, deprecated, const, enum, minimum, maximum, default, $ref ] - - -single: - allOf: - - $ref: '#/single-array' - - propertyNames: - $ref: '#/single-array-names' + propertyNames: + enum: [ description, deprecated, const, enum, minimum, maximum, default, $ref ] From c2b04ec2a54a02eb808f8df221a0f5e51176014b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 4 Jan 2021 13:38:03 -0700 Subject: [PATCH 060/505] meta-schemas: Add hwlock and nvmem properties Signed-off-by: Rob Herring --- meta-schemas/core.yaml | 2 ++ meta-schemas/hwlock.yaml | 13 +++++++++++++ meta-schemas/nvmem.yaml | 17 +++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 meta-schemas/hwlock.yaml create mode 100644 meta-schemas/nvmem.yaml diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index 369858a6..ab1e5d3f 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -17,10 +17,12 @@ definitions: - $ref: "clocks.yaml#" - $ref: "dma.yaml#" - $ref: "gpios.yaml#" + - $ref: "hwlock.yaml#" - $ref: "iio.yaml#" - $ref: "interrupts.yaml#" - $ref: "iommu.yaml#" - $ref: "mailbox.yaml#" + - $ref: "nvmem.yaml#" - $ref: "phy.yaml#" - $ref: "power-domain.yaml#" - $ref: "pwm.yaml#" diff --git a/meta-schemas/hwlock.yaml b/meta-schemas/hwlock.yaml new file mode 100644 index 00000000..7f0ea9a2 --- /dev/null +++ b/meta-schemas/hwlock.yaml @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2021 Arm Ltd. +%YAML 1.2 +--- +$id: "http://devicetree.org/meta-schemas/hwlock.yaml#" +$schema: "http://json-schema.org/draft-07/schema#" + +properties: + hwlocks: + $ref: "cell.yaml#/array" + +dependencies: + hwlock-names: [hwlocks] diff --git a/meta-schemas/nvmem.yaml b/meta-schemas/nvmem.yaml new file mode 100644 index 00000000..f5729d43 --- /dev/null +++ b/meta-schemas/nvmem.yaml @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2021 Arm Ltd. +%YAML 1.2 +--- +$id: "http://devicetree.org/meta-schemas/nvmem.yaml#" +$schema: "http://json-schema.org/draft-07/schema#" + +properties: + nvmem: + $ref: "cell.yaml#/array" + + nvmem-cells: + $ref: "cell.yaml#/array" + +dependencies: + nvmem-names: [nvmem] + nvmem-cell-names: [nvmem-cells] From e7a76dd302940574e79356b933f05ee8bf7d7bf4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 20 Jan 2021 08:04:26 -0600 Subject: [PATCH 061/505] Reverse 'interrupt-map-mask' dependency 'interrupt-map-mask' should depend on 'interrupt-map', not the other way around. Signed-off-by: Rob Herring --- meta-schemas/interrupts.yaml | 3 ++- schemas/interrupt-controller.yaml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/meta-schemas/interrupts.yaml b/meta-schemas/interrupts.yaml index d56555ed..d18cd956 100644 --- a/meta-schemas/interrupts.yaml +++ b/meta-schemas/interrupts.yaml @@ -24,7 +24,8 @@ properties: interrupt-parent: false # interrupt-parent is implicit dependencies: - interrupt-map: ['#interrupt-cells', 'interrupt-map-mask'] + interrupt-map: ['#interrupt-cells'] + 'interrupt-map-mask': [ interrupt-map ] '#interrupt-cells': anyOf: - required: diff --git a/schemas/interrupt-controller.yaml b/schemas/interrupt-controller.yaml index c9bd7a49..8f59a402 100644 --- a/schemas/interrupt-controller.yaml +++ b/schemas/interrupt-controller.yaml @@ -28,7 +28,8 @@ properties: dependencies: interrupt-controller: ['#interrupt-cells'] - interrupt-map: ['#interrupt-cells', 'interrupt-map-mask'] + interrupt-map: ['#interrupt-cells' ] + interrupt-map-mask: [ interrupt-map ] "#interrupt-cells": anyOf: - required: From b003a54826cb3784b74d29e6f2015d9b1c06f526 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 20 Jan 2021 12:59:00 -0600 Subject: [PATCH 062/505] Add .eggs to .gitignore Signed-off-by: Rob Herring --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9d8c38d9..5bafa3b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.eggs __pycache__ build dist From ed926c1e6f831cef5ac03d609d5801216e9cbfe2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 20 Jan 2021 13:23:31 -0600 Subject: [PATCH 063/505] meta-schemas: Expand regex exclusion for vendor properties Not all regex's for patternProperties start with '^', so let's rework the matching for more common regex characters which are not valid DT node or property characters. Signed-off-by: Rob Herring --- meta-schemas/vendor-props.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-schemas/vendor-props.yaml b/meta-schemas/vendor-props.yaml index 0105f856..c620490d 100644 --- a/meta-schemas/vendor-props.yaml +++ b/meta-schemas/vendor-props.yaml @@ -9,7 +9,7 @@ $schema: "http://json-schema.org/draft-07/schema#" description: Metaschema for vendor specific properties patternProperties: - '^\^': true + '[\[\]*{}$\^\\]+': true # exclude regex's '^[^,]*$': true '^linux,.*$': true '-(gpio|gpios)$': true From a2c4549ceac589b7a4f862c3fbd3ec799bff9a58 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 20 Jan 2021 13:40:21 -0600 Subject: [PATCH 064/505] meta-schemas: Allow for single entries with individual cell constraints There are some cases where we need to define constraints on the cells of each entry of a multi-cell value. This is currently rejected. With this change, this form is allowed: items: - items: - description: 1st cell - description: 2nd cell - description: 3rd cell Signed-off-by: Rob Herring --- meta-schemas/cell.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/meta-schemas/cell.yaml b/meta-schemas/cell.yaml index 02c99e4a..591dffe7 100644 --- a/meta-schemas/cell.yaml +++ b/meta-schemas/cell.yaml @@ -35,6 +35,13 @@ array: - type: array items: $ref: '#/single' + - type: array + maxItems: 1 # for more than 1, outer 'items' should be a schema + items: + allOf: + - $ref: '#/array' + required: + - items additionalItems: type: boolean const: true From 50f666a2f4b231683cb2629fa1ed860a9018a9de Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 21 Jan 2021 10:19:17 -0600 Subject: [PATCH 065/505] dtschema: Add '$defs' handling to node fixups Signed-off-by: Rob Herring --- dtschema/lib.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index e835543c..e7239673 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -476,7 +476,7 @@ def fixup_interrupts(schema): schema['required'].remove('interrupts') def fixup_node_props(schema): - if not (isinstance(schema, dict) and schema.keys() & {'properties', 'patternProperties'}): + if not (isinstance(schema, dict) and schema.keys() & {'properties', 'patternProperties', '$defs'}): return if 'properties' in schema: @@ -487,6 +487,10 @@ def fixup_node_props(schema): for k,v in schema['patternProperties'].items(): fixup_node_props(v) + if '$defs' in schema: + for k,v in schema['$defs'].items(): + fixup_node_props(v) + if 'additionalProperties' in schema: fixup_node_props(schema['additionalProperties']) From c3424745f900e8cf0a0e3acebffeeda83a82f6d4 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 14 Jan 2021 10:40:38 +0100 Subject: [PATCH 066/505] dtschema: Add assigned-clock* properties by default Since the assigned-clocks and related properties are handled by the core itself most of the time, can be applied to pretty much any device node and can depend on a specific board setup, we would eventually have to add these properties to pretty much every YAML schema. Add them in the tools just like status and pinctrl properties, but only if the schema doesn't define them already and if the node has a clocks property. Signed-off-by: Maxime Ripard Signed-off-by: Rob Herring --- dtschema/lib.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index e7239673..69fa0f9e 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -516,6 +516,11 @@ def fixup_node_props(schema): schema.setdefault('patternProperties', dict()) schema['patternProperties']['pinctrl-[0-9]+'] = True + if "clocks" in keys and not "assigned-clocks" in keys: + schema['properties']['assigned-clocks'] = True + schema['properties']['assigned-clock-rates'] = True + schema['properties']['assigned-clock-parents'] = True + def process_schema(filename): try: schema = load_schema(filename) From 0f587893f486ce08749727a5d083699bc289b78e Mon Sep 17 00:00:00 2001 From: Prakhar Srivastava Date: Sun, 19 Jul 2020 23:16:36 -0700 Subject: [PATCH 067/505] dt-bindings: document linux,ima-kexec-buffer Signed-off-by: Rob Herring --- schemas/chosen.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/schemas/chosen.yaml b/schemas/chosen.yaml index a0dde76d..b93cd1df 100644 --- a/schemas/chosen.yaml +++ b/schemas/chosen.yaml @@ -172,6 +172,24 @@ properties: "linux,stdout-path" and "stdout" properties are deprecated. New platforms should only use the "stdout-path" property. + linux,ima-kexec-buffer: + $ref: types.yaml#definitions/uint64-array + maxItems: 2 + description: + This property(currently used by powerpc, arm64) holds the memory range, + "the address and the size", of the Integrity Measuremnet Architecture(IMA) + measurement logs that are being carried over to the new kernel. + + / { + chosen { + linux,ima-kexec-buffer = <0x9 0x82000000 0x0 0x00008000>; + }; + }; + + This property does not represent real hardware, but the memory allocated for + carrying the IMA measurement logs. The address and the suze are expressed in + #address-cells and #size-cells, respectively of the root node. + patternProperties: "^framebuffer": true From e65b6b9cef79be9d22e4c0ac7eae902dc2aa1e15 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 26 Jan 2021 14:00:58 -0600 Subject: [PATCH 068/505] Merge separate fixup functions fixup_schema and fixup_node_props There's currently 2 schema walking functions, fixup_node_props and fixup_schema, and they are done at 2 different times. Let's simplify things and do all the schema walking in one place. With this, the schema after check_schema() has all the fixups applied. Signed-off-by: Rob Herring --- dtschema/lib.py | 184 +++++++++++++++++++----------------------------- 1 file changed, 73 insertions(+), 111 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 69fa0f9e..3da8aed0 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -214,6 +214,9 @@ def _fixup_int_array_min_max_to_matrix(subschema): if subschema['oneOf'][0].get('minItems') == 1: subschema['oneOf'][0]['minItems'] += 1 + # Since we added an 'oneOf' the tree walking code won't find it and we need to do fixups + _fixup_items_size(subschema['oneOf']) + def _fixup_int_array_items_to_matrix(subschema): if 'allOf' in subschema and '$ref' in subschema['allOf'][0]: if not re.match('.*uint(8|16|32)-array', subschema['allOf'][0]['$ref']): @@ -261,6 +264,7 @@ def _fixup_items_size(schema): for l in schema: _fixup_items_size(l) elif isinstance(schema, dict): + schema.pop('description', None) if 'items' in schema: schema['type'] = 'array' @@ -273,14 +277,14 @@ def _fixup_items_size(schema): if not 'additionalItems' in schema: schema['additionalItems'] = False + + _fixup_items_size(schema['items']) + elif 'maxItems' in schema and not 'minItems' in schema: schema['minItems'] = schema['maxItems'] elif 'minItems' in schema and not 'maxItems' in schema: schema['maxItems'] = schema['minItems'] - for prop,val in schema.items(): - _fixup_items_size(val) - def fixup_vals(schema): # Now we should be a the schema level to do actual fixups # print(schema) @@ -292,65 +296,95 @@ def fixup_vals(schema): schema['allOf'] = [ {'$ref': schema['$ref']} ] schema.pop('$ref') + schema.pop('description', None) + _fixup_int_array_min_max_to_matrix(schema) _fixup_int_array_items_to_matrix(schema) _fixup_string_to_array(schema) _fixup_scalar_to_array(schema) + _fixup_items_size(schema) # print(schema) -def walk_conditionals(schema): +def walk_properties(schema): + if not isinstance(schema, dict): + return # Recurse until we don't hit a conditional # Note we expect to encounter conditionals first. # For example, a conditional below 'items' is not supported for cond in ['allOf', 'oneOf', 'anyOf']: if cond in schema.keys(): for l in schema[cond]: - walk_conditionals(l) - else: - fixup_vals(schema) + walk_properties(l) -def walk_properties(props): - for prop in props: - if not isinstance(props[prop], dict): - continue - - walk_conditionals(props[prop]) + fixup_vals(schema) def fixup_schema(schema): + # Remove parts not necessary for validation + schema.pop('examples', None) + schema.pop('maintainers', None) + schema.pop('historical', None) + + add_select_schema(schema) + fixup_sub_schema(schema, True) + +def fixup_sub_schema(schema, is_prop): if not isinstance(schema, dict): return + schema.pop('description', None) fixup_interrupts(schema) + if is_prop: + fixup_node_props(schema) for k,v in schema.items(): - # select is a subschema that we want to fixup - if k in ['select']: - fixup_schema(v) - - # If, then and else contain subschemas that we'll want to - # fixup as well. Let's recurse into those subschemas. - if k in ['if', 'then', 'else', 'additionalProperties']: - fixup_schema(v) - - # allOf can contain a list of if, then and else statements, - # that in turn will contain subschemas that we'll want to - # fixup. Let's recurse into each of those subschemas. + if k in ['select', 'if', 'then', 'else', 'additionalProperties']: + fixup_sub_schema(v, False) + if k in ['allOf', 'anyOf', 'oneOf']: for subschema in v: - fixup_schema(subschema) - - # properties within dependencies can be a schema - if k in ['dependencies']: - for prop in v: - fixup_schema(v[prop]) + fixup_sub_schema(subschema, True) - if not k in ['properties', 'patternProperties', '$defs']: + if not k in ['dependencies', 'properties', 'patternProperties', '$defs']: continue - walk_properties(v) for prop in v: + walk_properties(v[prop]) # Recurse to check for {properties,patternProperties} in each prop - fixup_schema(v[prop]) + fixup_sub_schema(v[prop], True) + +def fixup_node_props(schema): + if not {'properties', 'patternProperties'} & schema.keys(): + return + if not ('additionalProperties' in schema and schema['additionalProperties'] is not True) and \ + not ('unevaluatedProperties' in schema and schema['unevaluatedProperties'] is not True): + return + + schema.setdefault('properties', dict()) + schema['properties']['phandle'] = True + schema['properties']['status'] = True + + if not '$nodename' in schema['properties']: + schema['properties']['$nodename'] = True + + keys = list() + if 'properties' in schema: + keys.extend(schema['properties']) + + if 'patternProperties' in schema: + keys.extend(schema['patternProperties']) + + for key in keys: + if "pinctrl" in key: + break + else: + schema['properties']['pinctrl-names'] = True + schema.setdefault('patternProperties', dict()) + schema['patternProperties']['pinctrl-[0-9]+'] = True + + if "clocks" in keys and not "assigned-clocks" in keys: + schema['properties']['assigned-clocks'] = True + schema['properties']['assigned-clock-rates'] = True + schema['properties']['assigned-clock-parents'] = True def item_generator(json_input, lookup_key): if isinstance(json_input, dict): @@ -394,6 +428,10 @@ def add_select_schema(schema): if "select" in schema: return + if not 'properties' in schema: + schema['select'] = False + return + if 'compatible' in schema['properties']: sch = schema['properties']['compatible'] compatible_list = [ ] @@ -428,7 +466,7 @@ def add_select_schema(schema): return - if schema['properties']['$nodename'] != True: + if '$nodename' in schema['properties'] and schema['properties']['$nodename'] != True: schema['select'] = { 'required': ['$nodename'], 'properties': {'$nodename': convert_to_dict(schema['properties']['$nodename']) }} @@ -437,15 +475,6 @@ def add_select_schema(schema): schema['select'] = False -def remove_description(schema): - if isinstance(schema, list): - for s in schema: - remove_description(s) - if isinstance(schema, dict): - schema.pop('description', None) - for k,v in schema.items(): - remove_description(v) - def fixup_interrupts(schema): # Supporting 'interrupts' implies 'interrupts-extended' is also supported. if not 'properties' in schema: @@ -475,52 +504,6 @@ def fixup_interrupts(schema): schema['oneOf'] = reqlist schema['required'].remove('interrupts') -def fixup_node_props(schema): - if not (isinstance(schema, dict) and schema.keys() & {'properties', 'patternProperties', '$defs'}): - return - - if 'properties' in schema: - for k,v in schema['properties'].items(): - fixup_node_props(v) - - if 'patternProperties' in schema: - for k,v in schema['patternProperties'].items(): - fixup_node_props(v) - - if '$defs' in schema: - for k,v in schema['$defs'].items(): - fixup_node_props(v) - - if 'additionalProperties' in schema: - fixup_node_props(schema['additionalProperties']) - - if not 'properties' in schema: - schema['properties'] = {} - - schema['properties']['phandle'] = True - schema['properties']['status'] = True - - keys = list() - if 'properties' in schema: - keys.extend(schema['properties']) - - if 'patternProperties' in schema: - keys.extend(schema['patternProperties']) - - for key in keys: - if "pinctrl" in key: - break - - else: - schema['properties']['pinctrl-names'] = True - schema.setdefault('patternProperties', dict()) - schema['patternProperties']['pinctrl-[0-9]+'] = True - - if "clocks" in keys and not "assigned-clocks" in keys: - schema['properties']['assigned-clocks'] = True - schema['properties']['assigned-clock-rates'] = True - schema['properties']['assigned-clock-parents'] = True - def process_schema(filename): try: schema = load_schema(filename) @@ -536,27 +519,6 @@ def process_schema(filename): #print(exc.message) return - # Remove parts not necessary for validation - schema.pop('examples', None) - schema.pop('maintainers', None) - schema.pop('historical', None) - - remove_description(schema) - - if not schema.keys() & {'properties', 'patternProperties'}: - return schema - - if not 'properties' in schema: - schema['properties'] = {} - - if not '$nodename' in schema['properties']: - schema['properties']['$nodename'] = True - - # Add any implicit properties - fixup_node_props(schema) - _fixup_items_size(schema) - - add_select_schema(schema) if not 'select' in schema: return From 262a847ac9fd77da162336157c2d3affbe002c6d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 26 Jan 2021 17:27:55 +0100 Subject: [PATCH 069/505] schemas: property-units: Add percentage Add percentages to the list of recognized units. Signed-off-by: Geert Uytterhoeven Signed-off-by: Rob Herring --- schemas/property-units.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/schemas/property-units.yaml b/schemas/property-units.yaml index 20e6f6eb..655e9eec 100644 --- a/schemas/property-units.yaml +++ b/schemas/property-units.yaml @@ -26,6 +26,11 @@ patternProperties: "-bits$": $ref: "types.yaml#/definitions/uint32-array" description: Number of bits + + "-percent$": + $ref: "types.yaml#/definitions/uint32-array" + description: percentage + # Time/Frequency "-mhz$": $ref: "types.yaml#/definitions/uint32-array" From 7fe8d4bcca458c589a8ed0c28de3af29a9486f93 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 26 Jan 2021 17:27:56 +0100 Subject: [PATCH 070/505] meta-schemas: vendor-props: Add percentage Add percentages to the list of recognized vendor properties. Signed-off-by: Geert Uytterhoeven Signed-off-by: Rob Herring --- meta-schemas/vendor-props.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-schemas/vendor-props.yaml b/meta-schemas/vendor-props.yaml index c620490d..35092ab5 100644 --- a/meta-schemas/vendor-props.yaml +++ b/meta-schemas/vendor-props.yaml @@ -14,7 +14,7 @@ patternProperties: '^linux,.*$': true '-(gpio|gpios)$': true '-supply$': true - '-(bits|mhz|hz|sec|ms|us|ns|ps|mm)$': true + '-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm)$': true '-(microamp|microamp-hours|ohms|micro-ohms|microwatt-hours)$': true '-(microvolt|picofarads|celsius|millicelsius|kpascal)$': true From d60b612dd10fbad6264151ef3ef93d55cbe8105a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Jan 2021 12:10:19 -0600 Subject: [PATCH 071/505] dt-validate: Fix traceback splat when no 'properties' in schema A new schema doc has no 'properties' schema in the schema which results in the following splat: Traceback (most recent call last): File "/usr/local/bin/dt-validate", line 165, in sg.check_trees(filename, testtree) File "/usr/local/bin/dt-validate", line 114, in check_trees self.check_subtree(dt, subtree, "/", "/", filename) File "/usr/local/bin/dt-validate", line 100, in check_subtree self.check_node(tree, subtree, nodename, fullname, filename) File "/usr/local/bin/dt-validate", line 49, in check_node if 'compatible' in schema['properties']: KeyError: 'properties' Signed-off-by: Rob Herring --- tools/dt-validate | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/dt-validate b/tools/dt-validate index 03ff2625..fe94fa76 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -46,8 +46,8 @@ class schema_group(): if schema['select'] != True: matched_schemas.append(schema['$id']) node_matched = True - if 'compatible' in schema['properties']: - node_compatible_matched = True + if 'properties' in schema: + node_compatible_matched = 'compatible' in schema['properties'] try: errors = sorted(dtschema.DTValidator(schema).iter_errors(node), key=lambda e: e.linecol) for error in errors: From 613d7b16f0390b843b7f2d2238626e1dbca47f21 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 22 Jan 2021 19:45:43 -0600 Subject: [PATCH 072/505] meta-schemas: Allow deprecated and multipleOf for cell schemas We missed 'deprecated' for cell arrays and 'multipleOf' for single cell schemas. Add them. Signed-off-by: Rob Herring --- meta-schemas/cell.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meta-schemas/cell.yaml b/meta-schemas/cell.yaml index 591dffe7..14804e80 100644 --- a/meta-schemas/cell.yaml +++ b/meta-schemas/cell.yaml @@ -46,6 +46,7 @@ array: type: boolean const: true description: true + deprecated: true additionalProperties: false @@ -69,4 +70,4 @@ single: maximum: [minimum] propertyNames: - enum: [ description, deprecated, const, enum, minimum, maximum, default, $ref ] + enum: [ description, deprecated, const, enum, minimum, maximum, multipleOf, default, $ref ] From 87dc00b7f1a1e38cda9a0b6438ef37a0955d0930 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Jan 2021 08:54:57 -0600 Subject: [PATCH 073/505] meta-schemas: Drop requiring both 'minimum' and 'maximum' together It wasn't universally enforced and there are cases where both aren't needed. Signed-off-by: Rob Herring --- meta-schemas/cell.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/meta-schemas/cell.yaml b/meta-schemas/cell.yaml index 14804e80..873cb524 100644 --- a/meta-schemas/cell.yaml +++ b/meta-schemas/cell.yaml @@ -65,9 +65,5 @@ single: default: type: integer - dependencies: - minimum: [maximum] - maximum: [minimum] - propertyNames: enum: [ description, deprecated, const, enum, minimum, maximum, multipleOf, default, $ref ] From 5bb9978894a466d3b83fc1de5a05d8ec6e35110d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Jan 2021 17:36:41 -0600 Subject: [PATCH 074/505] dt-validate: Fix compatible match tracking Commit d60b612dd10f ("dt-validate: Fix traceback splat when no 'properties' in schema") broke tracking whether we have seen a compatible match. Signed-off-by: Rob Herring --- tools/dt-validate | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/dt-validate b/tools/dt-validate index fe94fa76..599c0744 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -46,8 +46,8 @@ class schema_group(): if schema['select'] != True: matched_schemas.append(schema['$id']) node_matched = True - if 'properties' in schema: - node_compatible_matched = 'compatible' in schema['properties'] + if 'properties' in schema and 'compatible' in schema['properties']: + node_compatible_matched = True try: errors = sorted(dtschema.DTValidator(schema).iter_errors(node), key=lambda e: e.linecol) for error in errors: From 52e1ecbf67683aef6ca5adc9018e682d41a97df5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Jan 2021 08:59:51 -0600 Subject: [PATCH 075/505] dtschema: Pass property name to fixup functions There's a need to know the property name (specifically ones with standard unit suffix) in the fixup functions, so add the property name as an arg. Signed-off-by: Rob Herring --- dtschema/lib.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 3da8aed0..4bda961a 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -162,7 +162,7 @@ def _extract_single_schemas(subschema): return tmpsch -def _fixup_string_to_array(subschema): +def _fixup_string_to_array(propname, subschema): # nothing to do if we don't have a set of string schema if not _is_string_schema(subschema): return @@ -184,7 +184,7 @@ def _is_matrix_schema(subschema): # Fixup an int array that only defines the number of items. # In this case, we allow either form [[ 0, 1, 2]] or [[0], [1], [2]] -def _fixup_int_array_min_max_to_matrix(subschema): +def _fixup_int_array_min_max_to_matrix(propname, subschema): if not ('allOf' in subschema and \ '$ref' in subschema['allOf'][0] and \ re.match('.*uint(8|16|32)-array', subschema['allOf'][0]['$ref'])): @@ -217,7 +217,7 @@ def _fixup_int_array_min_max_to_matrix(subschema): # Since we added an 'oneOf' the tree walking code won't find it and we need to do fixups _fixup_items_size(subschema['oneOf']) -def _fixup_int_array_items_to_matrix(subschema): +def _fixup_int_array_items_to_matrix(propname, subschema): if 'allOf' in subschema and '$ref' in subschema['allOf'][0]: if not re.match('.*uint(8|16|32)-array', subschema['allOf'][0]['$ref']): return @@ -252,7 +252,7 @@ def _fixup_int_array_items_to_matrix(subschema): if isinstance(subschema['items'],list): subschema['items'] = [ {'items': subschema['items']} ] -def _fixup_scalar_to_array(subschema): +def _fixup_scalar_to_array(propname, subschema): if not _is_int_schema(subschema): return @@ -285,7 +285,7 @@ def _fixup_items_size(schema): elif 'minItems' in schema and not 'maxItems' in schema: schema['maxItems'] = schema['minItems'] -def fixup_vals(schema): +def fixup_vals(propname, schema): # Now we should be a the schema level to do actual fixups # print(schema) @@ -298,14 +298,14 @@ def fixup_vals(schema): schema.pop('description', None) - _fixup_int_array_min_max_to_matrix(schema) - _fixup_int_array_items_to_matrix(schema) - _fixup_string_to_array(schema) - _fixup_scalar_to_array(schema) + _fixup_int_array_min_max_to_matrix(propname, schema) + _fixup_int_array_items_to_matrix(propname, schema) + _fixup_string_to_array(propname, schema) + _fixup_scalar_to_array(propname, schema) _fixup_items_size(schema) # print(schema) -def walk_properties(schema): +def walk_properties(propname, schema): if not isinstance(schema, dict): return # Recurse until we don't hit a conditional @@ -314,9 +314,9 @@ def walk_properties(schema): for cond in ['allOf', 'oneOf', 'anyOf']: if cond in schema.keys(): for l in schema[cond]: - walk_properties(l) + walk_properties(propname, l) - fixup_vals(schema) + fixup_vals(propname, schema) def fixup_schema(schema): # Remove parts not necessary for validation @@ -348,7 +348,7 @@ def fixup_sub_schema(schema, is_prop): continue for prop in v: - walk_properties(v[prop]) + walk_properties(prop, v[prop]) # Recurse to check for {properties,patternProperties} in each prop fixup_sub_schema(v[prop], True) From d3e5b7107b3e399a7d8d2c9d002482e8af15547c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Jan 2021 09:11:51 -0600 Subject: [PATCH 076/505] dtschema: Rework int array detection and fixups Currently, the int array detection relies on finding a type $ref. That was because we couldn't distinguish an int array from a string array or matrix if the items had no constraints. This is not ideal especially for properties where we know the type. These are primarily ones with a unit suffix. For now, let's detect these by looking at the property name. This isn't really ideal, but should handle most cases. Besides enabling fixups on properties with unit suffixes, this change has the side effect of allowing both array forms in some additional cases. Signed-off-by: Rob Herring --- dtschema/lib.py | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 4bda961a..637df655 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -182,19 +182,34 @@ def _is_matrix_schema(subschema): return False +def is_int_array_schema(propname, subschema): + if 'allOf' in subschema: + # Find 'items'. It may be under the 'allOf' or at the same level + for item in subschema['allOf']: + if 'items' in item: + subschema = item + continue + if '$ref' in item: + return re.match('.*uint(8|16|32)-array', item['$ref']) + elif re.match('.*-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours|microvolt|picofarads|celsius|millicelsius|kpascal)$', propname): + return True + + return 'items' in subschema and \ + ((isinstance(subschema['items'],list) and _is_int_schema(subschema['items'][0])) or \ + (isinstance(subschema['items'],dict) and _is_int_schema(subschema['items']))) + # Fixup an int array that only defines the number of items. # In this case, we allow either form [[ 0, 1, 2]] or [[0], [1], [2]] def _fixup_int_array_min_max_to_matrix(propname, subschema): - if not ('allOf' in subschema and \ - '$ref' in subschema['allOf'][0] and \ - re.match('.*uint(8|16|32)-array', subschema['allOf'][0]['$ref'])): + if not is_int_array_schema(propname, subschema): return - # Find 'min/maxItems'. It may be under the 'allOf' or at the same level - for item in subschema['allOf']: - if item.keys() & {'minItems', 'maxItems'}: - subschema = item - break + if 'allOf' in subschema: + # Find 'min/maxItems'. It may be under the 'allOf' or at the same level + for item in subschema['allOf']: + if item.keys() & {'minItems', 'maxItems'}: + subschema = item + break if _is_matrix_schema(subschema): return @@ -218,25 +233,17 @@ def _fixup_int_array_min_max_to_matrix(propname, subschema): _fixup_items_size(subschema['oneOf']) def _fixup_int_array_items_to_matrix(propname, subschema): - if 'allOf' in subschema and '$ref' in subschema['allOf'][0]: - if not re.match('.*uint(8|16|32)-array', subschema['allOf'][0]['$ref']): - return + if not is_int_array_schema(propname, subschema): + return + if 'allOf' in subschema: # Find 'items'. It may be under the 'allOf' or at the same level for item in subschema['allOf']: if 'items' in item: subschema = item break - if not 'items' in subschema: - return - - elif not 'items' in subschema or \ - (isinstance(subschema['items'],list) and not _is_int_schema(subschema['items'][0])) or \ - (isinstance(subschema['items'],dict) and not _is_int_schema(subschema['items'])): - return - - if _is_matrix_schema(subschema): + if not 'items' in subschema or _is_matrix_schema(subschema): return if isinstance(subschema['items'],dict): From beb25079ec29c1f81eed5d50f3e492631b8b75cf Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Jan 2021 12:03:10 -0600 Subject: [PATCH 077/505] dtschema: Only fixup array form when more than 1 max entry There's no need for supporting 2 array forms in the case of a single element. Signed-off-by: Rob Herring --- dtschema/lib.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index 637df655..43c4287c 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -214,6 +214,9 @@ def _fixup_int_array_min_max_to_matrix(propname, subschema): if _is_matrix_schema(subschema): return + if subschema.get('maxItems') == 1: + return + tmpsch = {} if 'minItems' in subschema: tmpsch['minItems'] = subschema.pop('minItems') From 93e7ada8d53af099074cb5d53f7caa12835784e0 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Jan 2021 17:37:06 -0600 Subject: [PATCH 078/505] Improve checking for undocumented compatible strings The current checks for schemas with compatible strings doesn't work well. Primarily, there are false positives for any compatible strings define as a child node of the node we match schemas on. It also didn't work for compatible strings defined by a 'pattern' keyword. Instead, let's extract all the compatible string values and patterns from schemas and generate a schema just to check for undocumented compatible strings. This gives a less than useful error message listing every known compatible, so we detect this error and print our own error message. Signed-off-by: Rob Herring --- dtschema/__init__.py | 1 + dtschema/lib.py | 110 ++++++++++++++++++++++++++++++------------- tools/dt-validate | 27 +++++------ 3 files changed, 91 insertions(+), 47 deletions(-) diff --git a/dtschema/__init__.py b/dtschema/__init__.py index df4cdba6..2126aec3 100644 --- a/dtschema/__init__.py +++ b/dtschema/__init__.py @@ -6,6 +6,7 @@ set_schema, DTValidator, format_error, + extract_compatibles, ) from dtschema.version import ( diff --git a/dtschema/lib.py b/dtschema/lib.py index 43c4287c..20b2fc68 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -396,14 +396,38 @@ def fixup_node_props(schema): schema['properties']['assigned-clock-rates'] = True schema['properties']['assigned-clock-parents'] = True +def extract_node_compatibles(schema): + if not isinstance(schema, dict): + return set() + + compatible_list = set() + + for l in item_generator(schema, 'enum'): + compatible_list.update(l) + + for l in item_generator(schema, 'const'): + compatible_list.update([str(l)]) + + for l in item_generator(schema, 'pattern'): + compatible_list.update([l]) + + return compatible_list + +def extract_compatibles(schema): + if not isinstance(schema, dict): + return set() + + compatible_list = set() + for sch in item_generator(schema, 'compatible'): + compatible_list.update(extract_node_compatibles(sch)) + + return compatible_list + def item_generator(json_input, lookup_key): if isinstance(json_input, dict): for k, v in json_input.items(): if k == lookup_key: - if isinstance(v, str): - yield [v] - else: - yield v + yield v else: for child_val in item_generator(v, lookup_key): yield child_val @@ -443,38 +467,24 @@ def add_select_schema(schema): return if 'compatible' in schema['properties']: - sch = schema['properties']['compatible'] - compatible_list = [ ] - for l in item_generator(sch, 'enum'): - compatible_list.extend(l) - - for l in item_generator(sch, 'const'): - compatible_list.extend(l) - - if 'contains' in sch: - for l in item_generator(sch['contains'], 'enum'): - compatible_list.extend(l) + compatible_list = extract_node_compatibles(schema['properties']['compatible']) - for l in item_generator(sch['contains'], 'const'): - compatible_list.extend(l) - - compatible_list = list(set(compatible_list)) - try: - compatible_list.remove('syscon') - except: - pass - try: - compatible_list.remove('simple-mfd') - except: - pass + if len(compatible_list): + try: + compatible_list.remove('syscon') + except: + pass + try: + compatible_list.remove('simple-mfd') + except: + pass - compatible_list.sort() - if len(compatible_list) != 0: - schema['select'] = { - 'required': ['compatible'], - 'properties': {'compatible': {'contains': {'enum': compatible_list}}}} + if len(compatible_list) != 0: + schema['select'] = { + 'required': ['compatible'], + 'properties': {'compatible': {'contains': {'enum': list(compatible_list)}}}} - return + return if '$nodename' in schema['properties'] and schema['properties']['$nodename'] != True: schema['select'] = { @@ -514,6 +524,38 @@ def fixup_interrupts(schema): schema['oneOf'] = reqlist schema['required'].remove('interrupts') +def make_compatible_schema(schemas): + compat_sch = [{'enum': []}] + compatible_list = set() + for sch in schemas: + compatible_list |= extract_compatibles(sch) + + # Allow 'foo' values for examples + compat_sch += [{'pattern': '^foo'}] + + prog = re.compile('.*[\^\[{\(\$].*') + for c in compatible_list: + if prog.match(c): + # Exclude the generic pattern + if c != '^[a-zA-Z][a-zA-Z0-9,+\-._]+$': + compat_sch += [{'pattern': c }] + else: + compat_sch[0]['enum'].append(c) + + compat_sch[0]['enum'].sort() + schemas += [{ + '$id': 'generated-compatibles', + '$filename': 'Generated schema of documented compatible strings', + 'select': True, + 'properties': { + 'compatible': { + 'items': { + 'anyOf': compat_sch + } + } + } + }] + def process_schema(filename): try: schema = load_schema(filename) @@ -571,6 +613,8 @@ def process_schemas(schema_paths, core_schema=True): if count == 0: print("warning: no schema found in path: %s" % path, file=sys.stderr) + make_compatible_schema(schemas) + return schemas def load(filename, line_number=False, duplicate_keys=True): diff --git a/tools/dt-validate b/tools/dt-validate index 599c0744..410b0538 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -38,7 +38,6 @@ class schema_group(): # Skip any generated nodes node['$nodename'] = [ nodename ] node_matched = False - node_compatible_matched = False matched_schemas = [] for schema in self.schemas: if schema['$select_validator'].is_valid(node): @@ -46,8 +45,6 @@ class schema_group(): if schema['select'] != True: matched_schemas.append(schema['$id']) node_matched = True - if 'properties' in schema and 'compatible' in schema['properties']: - node_compatible_matched = True try: errors = sorted(dtschema.DTValidator(schema).iter_errors(node), key=lambda e: e.linecol) for error in errors: @@ -70,6 +67,19 @@ class schema_group(): else: continue + if schema['$id'] == 'generated-compatibles': + if show_unmatched < 1: + continue + if isinstance(node, ruamel.yaml.comments.CommentedBase): + line = node.lc.line + col = node.lc.col + else: + line = 0 + col = 0 + print("%s:%i:%i: %s: failed to match any schema with compatible: %s" % + (filename, line, col, fullname, node['compatible']), file=sys.stderr) + continue + print(dtschema.format_error(filename, error, nodename=nodename, verbose=verbose) + '\n\tFrom schema: ' + schema['$filename'], file=sys.stderr) @@ -80,17 +90,6 @@ class schema_group(): print("%s: %s: matched on schema(s)\n\t" % (filename, fullname) + '\n\t'.join(matched_schemas), file=sys.stderr) - if show_unmatched >= 1 and 'compatible' in node.keys() and \ - not node_compatible_matched: - if isinstance(node, ruamel.yaml.comments.CommentedBase): - line = node.lc.line - col = node.lc.col - else: - line = 0 - col = 0 - print("%s:%i:%i: %s: failed to match any schema with compatible(s): %s" % - (filename, line, col, fullname, ', '.join(node["compatible"])), file=sys.stderr) - if show_unmatched >= 2 and not node_matched: print("%s: %s: failed to match any schema" % (filename, fullname), file=sys.stderr) From 865a5d6ce7cec96e1b4bfc9074add8adade59acb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 3 Feb 2021 09:24:16 -0600 Subject: [PATCH 079/505] dtschema: Fix traceback for erroneous dict in an 'enum' There's a case where an 'enum' contains a dict in error. This causes a traceback when extracting compatible strings. Let's check for this condition so that schemas without the fix work. Signed-off-by: Rob Herring --- dtschema/lib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 20b2fc68..30f2ba4c 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -403,7 +403,8 @@ def extract_node_compatibles(schema): compatible_list = set() for l in item_generator(schema, 'enum'): - compatible_list.update(l) + if isinstance(l[0], str): + compatible_list.update(l) for l in item_generator(schema, 'const'): compatible_list.update([str(l)]) From 1e15328ed6ca0874d34d70cd4f246fa465a31367 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 5 Feb 2021 11:43:48 -0600 Subject: [PATCH 080/505] dtschema: Always disable duplicate keys Duplicate keys were allowed for YAML encoded DT files due to some collisions with node names and property names. This is valid, but something discouraged and has undefined behavior. The spec should probably be updated to disallow it. If we end up needing to add this back, we should instead warn and then fallback to allowing duplicates. Signed-off-by: Rob Herring --- dtschema/lib.py | 9 +++------ test/device.yaml | 1 - test/test-dt-validate.py | 6 ++---- tools/dt-doc-validate | 2 +- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 30f2ba4c..b18eda43 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -45,7 +45,7 @@ def constructor(loader, node): return phandle_int(loader.construct_yaml_int(node)) rtyaml = ruamel.yaml.YAML(typ='rt') -rtyaml.allow_duplicate_keys = True +rtyaml.allow_duplicate_keys = False rtyaml.preserve_quotes=True rtyaml.Constructor.add_constructor(u'!u8', tagged_list.constructor) rtyaml.Constructor.add_constructor(u'!u16', tagged_list.constructor) @@ -54,7 +54,7 @@ def constructor(loader, node): rtyaml.Constructor.add_constructor(u'!phandle', phandle_int.constructor) yaml = ruamel.yaml.YAML(typ='safe') -yaml.allow_duplicate_keys = True +yaml.allow_duplicate_keys = False yaml.Constructor.add_constructor(u'!u8', tagged_list.constructor) yaml.Constructor.add_constructor(u'!u16', tagged_list.constructor) yaml.Constructor.add_constructor(u'!u32', tagged_list.constructor) @@ -112,7 +112,6 @@ def do_load(filename): return yaml.load(tmp) def load_schema(schema): - yaml.allow_duplicate_keys = False for path in schema_user_paths: if schema.startswith('schemas/'): schema_file = schema.partition('/')[2] @@ -618,13 +617,11 @@ def process_schemas(schema_paths, core_schema=True): return schemas -def load(filename, line_number=False, duplicate_keys=True): +def load(filename, line_number=False): with open(filename, 'r', encoding='utf-8') as f: if line_number: - rtyaml.allow_duplicate_keys = duplicate_keys return rtyaml.load(f.read()) else: - yaml.allow_duplicate_keys = duplicate_keys return yaml.load(f.read()) schema_cache = [] diff --git a/test/device.yaml b/test/device.yaml index 2656525e..1ff97c87 100644 --- a/test/device.yaml +++ b/test/device.yaml @@ -30,7 +30,6 @@ vendor,int64-prop: [ !u64 [0x100000000] ] vendor,phandle-prop: [[!phandle 1]] vendor,phandle-array-prop: [[!phandle 1], [!phandle 2]] - vendor,string-prop: [ foo ] vendor,string-list-prop: [ foobar, foobaz ] vendor,phandle-with-fixed-cells: [[!phandle 1, 2, 3]] vendor,int64-array-prop: [ !u64 [0x10000000, 0x1] ] diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index 500c992b..9d057f37 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -18,10 +18,8 @@ class TestDTMetaSchema(unittest.TestCase): def setUp(self): - self.schema = dtschema.load(os.path.join(basedir, 'schemas/good-example.yaml'), - duplicate_keys=False) - self.bad_schema = dtschema.load(os.path.join(basedir, 'schemas/bad-example.yaml'), - duplicate_keys=False) + self.schema = dtschema.load(os.path.join(basedir, 'schemas/good-example.yaml')) + self.bad_schema = dtschema.load(os.path.join(basedir, 'schemas/bad-example.yaml')) def test_metaschema_valid(self): '''The DTValidator metaschema must be a valid Draft7 schema''' diff --git a/tools/dt-doc-validate b/tools/dt-doc-validate index 777d1bfc..3b4d52e4 100755 --- a/tools/dt-doc-validate +++ b/tools/dt-doc-validate @@ -22,7 +22,7 @@ line_number = False def check_doc(filename): ret = 0 try: - testtree = dtschema.load(filename, line_number=line_number, duplicate_keys=False) + testtree = dtschema.load(filename, line_number=line_number) except (ruamel.yaml.scanner.ScannerError, ruamel.yaml.parser.ParserError) as exc: print(filename + ": ", exc, file=sys.stderr) return 1 From f754e834dde62a57a48b5ae39cc790d112fa51de Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 8 Feb 2021 16:12:58 -0600 Subject: [PATCH 081/505] schemas: Enforce simple-bus child nodes unit-addresses The current simple-bus child node schema checks nodes matching a correct unit-address (plus uppercase), but don't check for incorrect unit-addresses (though dtc will). Rework the schema such that all child nodes must have a unit-address and the unit-address format is correct. Really, additional DT properties shouldn't be allowed at all, but there's already too many cases of extra properties. Signed-off-by: Rob Herring --- schemas/simple-bus.yaml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/schemas/simple-bus.yaml b/schemas/simple-bus.yaml index bc824083..2ad9d43b 100644 --- a/schemas/simple-bus.yaml +++ b/schemas/simple-bus.yaml @@ -1,5 +1,6 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2018 Linaro Ltd. +# Copyright 2021 Arm Ltd. %YAML 1.2 --- $id: http://devicetree.org/schemas/simple-bus.yaml# @@ -19,6 +20,7 @@ properties: contains: const: simple-bus ranges: true + dma-ranges: true "#address-cells": enum: [ 1, 2 ] "#size-cells": @@ -26,7 +28,7 @@ properties: patternProperties: # All other properties should be child nodes with unit-address and 'reg' - "^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-fA-F]+$": + "@(0|[1-9a-f][0-9a-f]*)$": type: object properties: reg: @@ -49,7 +51,12 @@ patternProperties: - required: - ranges -additionalProperties: true + "^[^@]+$": + # Only additional properties should be properties, not nodes. + not: + type: object + +additionalProperties: false required: - compatible From af620027006de70f0b6254f3f43241f13e85e2df Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 8 Feb 2021 15:45:25 -0600 Subject: [PATCH 082/505] schemas: Enforce root node unit-address and reg checks Root nodes generally follow simple-bus structure except child nodes may not have unit-addresses. If they do, the same rules for unit-address format and reg and ranges properties apply. So let's copy the simple-bus schema. Signed-off-by: Rob Herring --- schemas/root-node.yaml | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/schemas/root-node.yaml b/schemas/root-node.yaml index a732f16e..ea27e641 100644 --- a/schemas/root-node.yaml +++ b/schemas/root-node.yaml @@ -1,6 +1,6 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2018 Linaro Ltd. -# Copyright 2018 Arm Ltd. +# Copyright 2018,2021 Arm Ltd. %YAML 1.2 --- $id: http://devicetree.org/schemas/root-node.yaml# @@ -23,13 +23,40 @@ properties: enum: [1, 2] memory: false +patternProperties: + "@(0|[1-9a-f][0-9a-f]*)$": + type: object + properties: + reg: + items: + minItems: 2 + maxItems: 4 + minItems: 1 + maxItems: 1024 + ranges: + oneOf: + - items: + minItems: 3 + maxItems: 7 + minItems: 1 + maxItems: 1024 + - $ref: "types.yaml#/definitions/flag" + anyOf: + - required: + - reg + - required: + - ranges + + # Anything else should not have a unit-address + "^[^@]+$": true + required: - compatible - model - "#address-cells" - "#size-cells" -additionalProperties: true +additionalProperties: false examples: - | From a630df5dc48c2c6eda5bd243d98165c15164f2a7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 11 Feb 2021 09:14:17 -0600 Subject: [PATCH 083/505] Add '-femtofarads' property unit suffix Signed-off-by: Rob Herring --- meta-schemas/vendor-props.yaml | 2 +- schemas/property-units.yaml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/meta-schemas/vendor-props.yaml b/meta-schemas/vendor-props.yaml index 35092ab5..b2ad162c 100644 --- a/meta-schemas/vendor-props.yaml +++ b/meta-schemas/vendor-props.yaml @@ -16,7 +16,7 @@ patternProperties: '-supply$': true '-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm)$': true '-(microamp|microamp-hours|ohms|micro-ohms|microwatt-hours)$': true - '-(microvolt|picofarads|celsius|millicelsius|kpascal)$': true + '-(microvolt|(femto|pico)farads|celsius|millicelsius|kpascal)$': true additionalProperties: type: object diff --git a/schemas/property-units.yaml b/schemas/property-units.yaml index 655e9eec..ee23f50d 100644 --- a/schemas/property-units.yaml +++ b/schemas/property-units.yaml @@ -81,6 +81,9 @@ patternProperties: "-picofarads$": $ref: "types.yaml#/definitions/uint32-array" description: picofarads + "-femtofarads$": + $ref: "types.yaml#/definitions/uint32-array" + description: femtofarads # Temperature "-celsius$": From 9be4deb854bcbc31ef0454260456be29f59eaeeb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 11 Feb 2021 09:20:22 -0600 Subject: [PATCH 084/505] Add '-kBps' property unit suffix Signed-off-by: Rob Herring --- meta-schemas/vendor-props.yaml | 2 +- schemas/property-units.yaml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/meta-schemas/vendor-props.yaml b/meta-schemas/vendor-props.yaml index b2ad162c..56011108 100644 --- a/meta-schemas/vendor-props.yaml +++ b/meta-schemas/vendor-props.yaml @@ -14,7 +14,7 @@ patternProperties: '^linux,.*$': true '-(gpio|gpios)$': true '-supply$': true - '-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm)$': true + '-(bits|-kBps|percent|mhz|hz|sec|ms|us|ns|ps|mm)$': true '-(microamp|microamp-hours|ohms|micro-ohms|microwatt-hours)$': true '-(microvolt|(femto|pico)farads|celsius|millicelsius|kpascal)$': true diff --git a/schemas/property-units.yaml b/schemas/property-units.yaml index ee23f50d..34e573d5 100644 --- a/schemas/property-units.yaml +++ b/schemas/property-units.yaml @@ -27,6 +27,10 @@ patternProperties: $ref: "types.yaml#/definitions/uint32-array" description: Number of bits + "-kBps$": + $ref: "types.yaml#/definitions/uint32-array" + description: Kilobytes per second + "-percent$": $ref: "types.yaml#/definitions/uint32-array" description: percentage From 141ce158dcd5aea2a4e4b1bd3917bff91e810284 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 29 Jan 2021 16:06:47 -0600 Subject: [PATCH 085/505] meta-schemas: Descend into allOf/anyOf/oneOf/if schemas Signed-off-by: Rob Herring --- meta-schemas/core.yaml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index ab1e5d3f..fa11182e 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -103,6 +103,33 @@ properties: $ref: "#/definitions/all-properties" properties: $ref: "#/definitions/all-properties" + allOf: + items: + properties: + properties: + $ref: "#/definitions/all-properties" + patternProperties: + $ref: "#/definitions/all-properties" + anyOf: + items: + properties: + properties: + $ref: "#/definitions/all-properties" + patternProperties: + $ref: "#/definitions/all-properties" + oneOf: + items: + properties: + properties: + $ref: "#/definitions/all-properties" + patternProperties: + $ref: "#/definitions/all-properties" + if: + properties: + properties: + $ref: "#/definitions/all-properties" + patternProperties: + $ref: "#/definitions/all-properties" anyOf: - required: From eac7bc81b7c79517c894e50b7f4b1caaf3a14c21 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Jan 2021 09:13:44 -0600 Subject: [PATCH 086/505] meta-schemas: Add meta-schema for properties with unit suffixes Properties with unit-suffixes are also just cell arrays. This will fix the common problem of having a type definition on these standard properties. Signed-off-by: Rob Herring --- meta-schemas/core.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index fa11182e..581e72c1 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -63,6 +63,9 @@ definitions: propertyNames: enum: [ description, deprecated ] + '-(bits|-kBps|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kpascal)$': + $ref: "cell.yaml#/array" + '^.*$': properties: # 'boolean' and 'object' are the only native types allowed From a653023cef93fed076592b3edd94e5d2aab38e7d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 22 Jan 2021 19:44:45 -0600 Subject: [PATCH 087/505] types.yaml: Map all signed types to unsigned Since the DT yaml output makes everything unsigned, we need to map the signed types to unsigned. Signed-off-by: Rob Herring --- schemas/types.yaml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/schemas/types.yaml b/schemas/types.yaml index 5b19c08a..3ee31f6c 100644 --- a/schemas/types.yaml +++ b/schemas/types.yaml @@ -73,7 +73,7 @@ definitions: items: type: array items: - $ref: "#/definitions/int8-item" + $ref: "#/definitions/uint8-item" int8-array: type: array typeSize: 8 @@ -82,7 +82,7 @@ definitions: items: type: array items: - $ref: "#/definitions/int8-item" + $ref: "#/definitions/uint8-item" int8: type: array typeSize: 8 @@ -91,7 +91,7 @@ definitions: items: type: array items: - $ref: "#/definitions/int8-item" + $ref: "#/definitions/uint8-item" minItems: 1 maxItems: 1 @@ -137,7 +137,7 @@ definitions: items: type: array items: - $ref: "#/definitions/int16-item" + $ref: "#/definitions/uint16-item" int16-array: type: array typeSize: 16 @@ -146,7 +146,7 @@ definitions: items: type: array items: - $ref: "#/definitions/int16-item" + $ref: "#/definitions/uint16-item" int16: type: array typeSize: 16 @@ -155,7 +155,7 @@ definitions: items: type: array items: - $ref: "#/definitions/int16-item" + $ref: "#/definitions/uint16-item" minItems: 1 maxItems: 1 @@ -213,7 +213,7 @@ definitions: items: type: array items: - $ref: "#/definitions/int32-item" + $ref: "#/definitions/cell" int32-array: # For single cell arrays, we need to support encodings as either: # prop = <0x1234 0x5678>; @@ -226,14 +226,14 @@ definitions: items: type: array items: - $ref: "#/definitions/int32-item" + $ref: "#/definitions/cell" - type: array items: type: array minItems: 1 maxItems: 1 items: - $ref: "#/definitions/int32-item" + $ref: "#/definitions/cell" int32: type: array minItems: 1 @@ -241,7 +241,7 @@ definitions: items: type: array items: - $ref: "#/definitions/int32-item" + $ref: "#/definitions/cell" minItems: 1 maxItems: 1 From b0a5b0d5e85b0dc9dd5b09da180b3c4640f2b8bd Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 15 Mar 2021 15:31:20 -0600 Subject: [PATCH 088/505] schemas: Core schemas only need to follow base.yaml meta-schema We need a better split (or at least better naming) between 'base' and 'core' meta-schema. The 'base' meta-schema defines only the top-level schema file structure. The 'core' meta-schema also defines requirements for users of common DT properties. The 'core' schema doesn't work for the schemas of those common DT properties, so use 'base' instead. Signed-off-by: Rob Herring --- schemas/dma/dma.yaml | 2 +- schemas/iio/iio-consumer.yaml | 2 +- schemas/iommu/iommu.yaml | 2 +- schemas/pci/pci-bus.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/schemas/dma/dma.yaml b/schemas/dma/dma.yaml index 58bdde28..af6d093f 100644 --- a/schemas/dma/dma.yaml +++ b/schemas/dma/dma.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: http://devicetree.org/schemas/dma/dma.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# title: Common DMA binding diff --git a/schemas/iio/iio-consumer.yaml b/schemas/iio/iio-consumer.yaml index ad7d290d..c2b47b9d 100644 --- a/schemas/iio/iio-consumer.yaml +++ b/schemas/iio/iio-consumer.yaml @@ -2,7 +2,7 @@ %YAML 1.2 --- $id: http://devicetree.org/schemas/iio/iio-consumer.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# title: Generic IIO consumer-bindings diff --git a/schemas/iommu/iommu.yaml b/schemas/iommu/iommu.yaml index 6d7b2638..d1b90c59 100644 --- a/schemas/iommu/iommu.yaml +++ b/schemas/iommu/iommu.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: http://devicetree.org/schemas/iommu/iommu.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# title: Common IOMMU Binding diff --git a/schemas/pci/pci-bus.yaml b/schemas/pci/pci-bus.yaml index 37c2f9b2..de340387 100644 --- a/schemas/pci/pci-bus.yaml +++ b/schemas/pci/pci-bus.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: http://devicetree.org/schemas/pci/pci-bus.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# title: PCI bus schema From cb53a16a1eb3e2169ce170c071e47940845ec26e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 15 Mar 2021 15:24:18 -0600 Subject: [PATCH 089/505] meta-schemas: Exclude '.*-names' from vendor properties ',.*-names' vendor properties only need a description at a minimum as they already have a type definition. Signed-off-by: Rob Herring --- meta-schemas/vendor-props.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/meta-schemas/vendor-props.yaml b/meta-schemas/vendor-props.yaml index 56011108..b32ad4c4 100644 --- a/meta-schemas/vendor-props.yaml +++ b/meta-schemas/vendor-props.yaml @@ -18,6 +18,11 @@ patternProperties: '-(microamp|microamp-hours|ohms|micro-ohms|microwatt-hours)$': true '-(microvolt|(femto|pico)farads|celsius|millicelsius|kpascal)$': true + ",.*-names$": + type: object + required: + - description + additionalProperties: type: object required: From 760c229148dac0262d803b490a3d56226fb2bf9d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 5 May 2021 11:14:02 -0500 Subject: [PATCH 090/505] dtschema: Add 'description' from schemas to error messages Some error messages don't give any clues where they come from or how to fix them. To give some hints, let's extract the lowest 'description' and '$id' in the schema path. This is complicated since the description could be in 'error.schema' or above that in the parent schema where we have to walk the schema from the root. Signed-off-by: Rob Herring --- dtschema/lib.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index b18eda43..69604dfd 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -681,16 +681,56 @@ def __init__(self, schema, types=()): jsonschema.Draft7Validator.__init__(self, schema, types, resolver=self.resolver, format_checker=self.format_checker) + @classmethod + def annotate_error(self, error, schema, path): + error.note = None + error.schema_file = None + + for e in error.context: + self.annotate_error(e, schema, path + e.schema_path) + + scope = self.ID_OF(schema) + self.resolver.push_scope(scope) + ref_depth = 1 + + for p in path: + if p == 'if': + continue + if '$ref' in schema and isinstance(schema['$ref'], str): + ref = self.resolver.resolve(schema['$ref']) + schema = ref[1] + self.resolver.push_scope(ref[0]) + ref_depth += 1 + + if '$id' in schema and isinstance(schema['$id'], str): + error.schema_file = schema['$id'] + + schema = schema[p] + + if isinstance(schema, dict): + if 'description' in schema and isinstance(schema['description'], str): + error.note = schema['description'] + + while ref_depth > 0: + self.resolver.pop_scope() + ref_depth -= 1 + + if isinstance(error.schema, dict) and 'description' in error.schema: + error.note = error.schema['description'] + @classmethod def iter_schema_errors(cls, schema): meta_schema = cls.resolver.resolve_from_url(schema['$schema']) for error in cls(meta_schema).iter_errors(schema): + cls(meta_schema).annotate_error(error, meta_schema, error.schema_path) error.linecol = get_line_col(schema, error.path) yield error def iter_errors(self, instance, _schema=None): for error in jsonschema.Draft7Validator.iter_errors(self, instance, _schema): error.linecol = get_line_col(instance, error.path) + error.note = None + error.schema_file = None yield error @classmethod @@ -793,6 +833,8 @@ def format_error(filename, error, prefix="", nodename=None, verbose=False): msg += '\n' + format_error(filename, suberror, prefix=prefix+"\t", nodename=nodename, verbose=verbose) elif not suberror.message in msg: msg += '\n' + prefix + '\t' + suberror.message + if suberror.note and suberror.note != error.note: + msg += '\n\t\t' + prefix + 'hint: ' + suberror.note elif error.schema_path[-1] == 'oneOf': msg = 'More than one condition true in oneOf schema:\n\t' + \ @@ -801,4 +843,10 @@ def format_error(filename, error, prefix="", nodename=None, verbose=False): else: msg = error.message + if error.note: + msg += '\n\t' + prefix + 'hint: ' + error.note + + if error.schema_file: + msg += '\n\t' + prefix + 'from schema $id: ' + error.schema_file + return src + msg From 340e7fd1898fcab80c1c437bb73ccfb65e1b53bf Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 5 May 2021 13:04:56 -0500 Subject: [PATCH 091/505] meta-schemas: Add descriptions for error hints Add some initial 'description' entries which will get added to error messages. Signed-off-by: Rob Herring --- meta-schemas/base.yaml | 7 +++++++ meta-schemas/cell.yaml | 14 ++++++++++++-- meta-schemas/core.yaml | 2 +- meta-schemas/items.yaml | 2 ++ meta-schemas/keywords.yaml | 25 ++++++++++++++----------- meta-schemas/nodes.yaml | 2 ++ meta-schemas/vendor-props.yaml | 12 +++++++++--- 7 files changed, 47 insertions(+), 17 deletions(-) diff --git a/meta-schemas/base.yaml b/meta-schemas/base.yaml index a63e1ec1..b88cb568 100644 --- a/meta-schemas/base.yaml +++ b/meta-schemas/base.yaml @@ -62,6 +62,7 @@ properties: format: email select: + description: '"select" must contain a valid json-schema' allOf: - $ref: "http://json-schema.org/draft-07/schema#" - oneOf: @@ -89,12 +90,18 @@ if: - required: - $ref then: + description: + 'A schema with a "$ref" to another schema either can define all properties used and + use "additionalProperties" or can use "unevaluatedProperties"' oneOf: - required: - unevaluatedProperties - required: - additionalProperties else: + description: + 'A schema without a "$ref" to another schema must define all properties and + use "additionalProperties"' required: - additionalProperties diff --git a/meta-schemas/cell.yaml b/meta-schemas/cell.yaml index 873cb524..3b79af4e 100644 --- a/meta-schemas/cell.yaml +++ b/meta-schemas/cell.yaml @@ -7,14 +7,20 @@ $id: "http://devicetree.org/meta-schemas/cell.yaml#" $schema: "http://json-schema.org/draft-07/schema#" array: + description: cell array properties must define how many entries and what the + entries are when there is more than one entry. anyOf: - - properties: + - description: 'Only "maxItems" is required for a single entry if there are + no constraints defined for the values.' + properties: maxItems: const: 1 required: [maxItems] propertyNames: enum: [maxItems, description, deprecated] - - properties: + - description: + Arrays must be described with a combination of minItems/maxItems/items + properties: minItems: minimum: 1 maxItems: @@ -28,6 +34,9 @@ array: items: $ref: '#/array' items: + description: '"items" can be a list defining each entry or a schema + applying to all items. A list has an implicit size. A schema + requires minItems/maxItems to define the size.' oneOf: - type: object allOf: @@ -53,6 +62,7 @@ array: - $ref: '#/single' single: + description: A singular entry should be described with scalar constraints properties: description: true const: diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index 581e72c1..8a668bb9 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -44,7 +44,7 @@ definitions: memory-region-names: $ref: "string-array.yaml" propertyNames: - # Ensure DT property names are not json-schema vocabulary names + description: A json-schema keyword was found instead of a DT property name. not: enum: [ $ref, additionalItems, additionalProperties, allOf, anyOf, const, contains, default, dependencies, deprecated, description, diff --git a/meta-schemas/items.yaml b/meta-schemas/items.yaml index 28b6b415..681789e2 100644 --- a/meta-schemas/items.yaml +++ b/meta-schemas/items.yaml @@ -154,6 +154,8 @@ allOf: maxItems: const: 32 then: + description: + '"minItems/maxItems" equal to the "items" list length are not necessary' properties: minItems: false maxItems: false diff --git a/meta-schemas/keywords.yaml b/meta-schemas/keywords.yaml index 64ead999..8a6efff4 100644 --- a/meta-schemas/keywords.yaml +++ b/meta-schemas/keywords.yaml @@ -6,8 +6,7 @@ $id: "http://devicetree.org/meta-schemas/keywords.yaml#" $schema: "http://json-schema.org/draft-07/schema#" description: - Metaschema to only allow for known json-schema vocabulary keywords. This is a - subset of json-schema vocabulary plus our additional keywords. + Keywords must be a subset of known json-schema keywords definitions: sub-schemas: @@ -51,15 +50,19 @@ definitions: - uniqueItems scalar-prop-list: - properties: - enum: false - exclusiveMaximum: false - exclusiveMinimum: false - const: false - maximum: false - minimum: false - multipleOf: false - pattern: false + propertyNames: + description: + Scalar and array keywords cannot be mixed + not: + enum: + - const + - enum + - exclusiveMaximum + - exclusiveMinimum + - minimum + - maximum + - multipleOf + - pattern # Array keywords should not be mixed with scalar keywords dependencies: diff --git a/meta-schemas/nodes.yaml b/meta-schemas/nodes.yaml index b8381267..0b0fac93 100644 --- a/meta-schemas/nodes.yaml +++ b/meta-schemas/nodes.yaml @@ -7,6 +7,8 @@ $schema: "http://json-schema.org/draft-07/schema#" type: object +description: 'DT nodes ("object" type in schemas) can only use a subset of json-schema keywords' + properties: type: const: object diff --git a/meta-schemas/vendor-props.yaml b/meta-schemas/vendor-props.yaml index b32ad4c4..13b3460f 100644 --- a/meta-schemas/vendor-props.yaml +++ b/meta-schemas/vendor-props.yaml @@ -27,8 +27,11 @@ additionalProperties: type: object required: - description + description: Vendor specific properties must have a type and description + unless they have a defined, common suffix. oneOf: - - properties: # A boolean property + - description: 'A vendor boolean property can use "type: boolean"' + properties: description: true type: const: boolean @@ -37,7 +40,9 @@ additionalProperties: - type additionalProperties: false - - properties: # A string property with exact values + - description: A vendor string property with exact values has an implicit + type + properties: # A string property with exact values description: true enum: items: @@ -50,7 +55,8 @@ additionalProperties: - required: [ const ] additionalProperties: false - - properties: # A property with a type and additional constraints + - description: A vendor property needs a $ref to types.yaml + properties: # A property with a type and additional constraints $ref: pattern: "types.yaml#\/definitions\/" allOf: From ac2f0e1068282d94ba4fbe87d963802e753cd158 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 5 May 2021 13:07:35 -0500 Subject: [PATCH 092/505] meta-schemas: base: Use 'propertyNames' instead of empty schemas in 'properties' Signed-off-by: Rob Herring --- meta-schemas/base.yaml | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/meta-schemas/base.yaml b/meta-schemas/base.yaml index b88cb568..9599c618 100644 --- a/meta-schemas/base.yaml +++ b/meta-schemas/base.yaml @@ -25,12 +25,10 @@ properties: - "http://devicetree.org/meta-schemas/base.yaml#" title: maxLength: 100 - description: true examples: type: array items: type: string - required: true allOf: items: propertyNames: @@ -39,21 +37,9 @@ properties: - if - then - else - anyOf: true - oneOf: true - definitions: true - $defs: true - additionalProperties: true - dependencies: true - patternProperties: true properties: propertyNames: pattern: "^[#$a-zA-Z][a-zA-Z0-9,+\\-._@]{0,63}$" - if: true - then: true - else: true - unevaluatedProperties: true - deprecated: true maintainers: type: array @@ -72,6 +58,12 @@ properties: required: true - type: boolean +propertyNames: + enum: [ $id, $schema, title, description, examples, required, allOf, anyOf, oneOf, + definitions, $defs, additionalProperties, dependencies, patternProperties, + properties, if, then, else, unevaluatedProperties, deprecated, maintainers, + select ] + required: - $id - $schema @@ -105,4 +97,3 @@ else: required: - additionalProperties -additionalProperties: false From 175a309ab4703284e095bb3b72c5ffd68ed90c85 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 10 Mar 2021 18:06:38 +0900 Subject: [PATCH 093/505] simple-bus: Fix incorrect description Signed-off-by: Hector Martin --- schemas/simple-bus.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/schemas/simple-bus.yaml b/schemas/simple-bus.yaml index 2ad9d43b..0a6d2a0c 100644 --- a/schemas/simple-bus.yaml +++ b/schemas/simple-bus.yaml @@ -7,8 +7,7 @@ $id: http://devicetree.org/schemas/simple-bus.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: simple-bus nodes -description: | - Common properties always required in /memory nodes +description: Common simple-bus binding maintainers: - Rob Herring From 0227e71a1f8d2ee1e02e4a05a8d50d48a571534b Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 10 Mar 2021 18:06:53 +0900 Subject: [PATCH 094/505] simple-bus: Add nonposted-mmio property This property indicates that nodes which are direct children of this bus shall use non-posted (i.e. no early return) MMIO mapping modes when mapping MMIO registers. This is a requirement that can be imposed by the bus on otherwise generic devices. Signed-off-by: Hector Martin --- schemas/simple-bus.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/schemas/simple-bus.yaml b/schemas/simple-bus.yaml index 0a6d2a0c..2a70acaf 100644 --- a/schemas/simple-bus.yaml +++ b/schemas/simple-bus.yaml @@ -24,6 +24,12 @@ properties: enum: [ 1, 2 ] "#size-cells": enum: [ 1, 2 ] + nonposted-mmio: + $ref: /schemas/types.yaml#/definitions/flag + description: + If present, specifies that direct children of this bus should use + non-posted memory accesses (i.e. a non-posted mapping mode) for MMIO + ranges. patternProperties: # All other properties should be child nodes with unit-address and 'reg' From 855f178a34d7a103ef8561ce3eedc9a48413954d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 2 Jun 2021 16:45:31 -0500 Subject: [PATCH 095/505] dtschema: Add 'type: object' to top level schemas If schemas without 'type: object' are applied to a DT property, they silently pass which isn't desired. As we never have schema files that apply to a property rather than a node, let's add 'type: object' to all the schema files when we do fixups. Signed-off-by: Rob Herring --- dtschema/lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index 69604dfd..48294911 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -574,6 +574,7 @@ def process_schema(filename): if not 'select' in schema: return + schema["type"] = "object" schema["$filename"] = filename return schema From 244f5052681be1f42cab21465526b270e7a8181e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 14 Jun 2021 14:47:57 -0600 Subject: [PATCH 096/505] Add github action for CI As travis-ci is moving, let's move to GH Actions which does everything we need. Signed-off-by: Rob Herring --- .github/workflows/ci.yml | 32 ++++++++++++++++++++++++++++++++ .github/workflows/publish.yml | 30 ++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..9abcd7bd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ + +on: push + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [3.6, 3.7, 3.8, 3.9] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install flake8 + pip install . + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test + run: | + test/test-dt-validate.py diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..1d379fd7 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,30 @@ +name: Upload Python Package + +on: + push: + tags: + - 'v*' + - '!v*-pre' + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + - name: Publish package + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} From 33cf8cf53285c6087a89c6bd8951a6f6acd43f7d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 14 Jun 2021 16:02:40 -0600 Subject: [PATCH 097/505] Remove TravisCI config As travis-ci.org is about to stop running and we've switched to GH Actions, remove the .travis.yml config file. Signed-off-by: Rob Herring --- .travis.yml | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ba2e24d6..00000000 --- a/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -sudo: false -dist: trusty -language: python -python: - - 3.6 - -script: - - pip install . - - test/test-dt-validate.py -deploy: - provider: pypi - username: "__token__" - password: - secure: Oy7FwsHPiJvJLwgVFwrm4aIzRy//HMkfe28h4AwT7l59/20HQ+68qPoblkwC7ZtM6o2uy4hcZO3oqvcgbFiTK4StF8PfPAln0r3r0/8CQYBejtS58dsp0n1O1b4JFc+r0CmY554bDquj1vNH+ztAtF/s012Aw2gK581TYvP2i44c74oZh0KciJY4GGLguU/pO+UIDSIZGeOAnAUPReGN+xjbnrmCiUV7ef4FDjERBvjaf4OnoDMwAwhzNrSXkGcWbtqpwiJnnHXtB42Zs/SZ9H3VaexSkBGXb1EzyDyO1mXBsYWw/KUg8Nc76qeD6g9dDURTQek0VhvkLLgkYyTw4n52HyNSOclA7XKbxOANrWIwXLcJLMB37/aAYBe6yZIdpYQ1iA9SW+GZ0xnPH9ONaj8/fMBOnwfEBZltHqIzTWbxx1UpXN7Q91PoNx0ytodHxaALPzcaOfet1ClhWBvWMoFBSKwb7ecvBoRFC81mZzMzuPKj8XektUojWyzhQy7U+zGzPkA0ONkFecZwhOaSD0YOv0Pz0keukriW2kiMkif9DDOUfmepLgiDmWatqYpcwIS6p+XOiLIs7r8iRq4ZUowHsy/LC/lpS9EK4K6g/chNCy4LoPmcITXlV0kwRIsV1fDAi9v+EkWXkATDUQSiZyjMLcEhjw2Gkq1JfZe1uRM= - on: - tags: true From e5f58d415b1d5e4088eca655c06880196764599d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 22 Jun 2021 13:11:37 -0600 Subject: [PATCH 098/505] dtschema: Drop forcing YAML 1.1 parsing This reverts commit 1c7f33244d91 ("dtschema: Force the loader to use YAML 1.1"). The ruamel C parser has supported YAML 1.2 since 2018 which was well before that commit. It seems like it was likely a configuration issue or need to adjust dependencies. In any case, using YAML 1.1 is actually problematic for a few cases where 'on' and 'off' are used in binding and get treated as boolean instead of strings. Signed-off-by: Rob Herring --- dtschema/lib.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 48294911..85b6defa 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -107,9 +107,7 @@ def do_load(filename): if filename.endswith('.json'): return json.load(f) - # ruamel C loader doesn't support 1.2, but 1.1 is good enough for us - tmp = f.read().replace('YAML 1.2', 'YAML 1.1') - return yaml.load(tmp) + return yaml.load(f.read()) def load_schema(schema): for path in schema_user_paths: From f5a200cb84c705651df149351a5d8cce568f759b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 24 Jun 2021 11:24:01 -0600 Subject: [PATCH 099/505] schemas: Allow a matrix for -microvolt suffix The OPP binding is a case that defines a matrix property with '-microvolt'. Signed-off-by: Rob Herring --- schemas/property-units.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemas/property-units.yaml b/schemas/property-units.yaml index 34e573d5..1e710bc0 100644 --- a/schemas/property-units.yaml +++ b/schemas/property-units.yaml @@ -80,7 +80,7 @@ patternProperties: $ref: "types.yaml#/definitions/uint32-array" description: micro Watt-hours "-microvolt$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: "types.yaml#/definitions/uint32-matrix" description: micro volts "-picofarads$": $ref: "types.yaml#/definitions/uint32-array" From 25b1b49772377a5fb09d487309c2830c8abb0329 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 2 Jul 2021 14:35:23 -0600 Subject: [PATCH 100/505] meta-schemas: Drop restrictions on top level 'allOf' The restrictions on 'allOf' are overly restrictive. In particular, there's a need for multiple 'oneOf' schemas under an 'allOf'. Let's just drop the restrictions and use the same as sub-schemas. Signed-off-by: Rob Herring --- meta-schemas/base.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/meta-schemas/base.yaml b/meta-schemas/base.yaml index 9599c618..bce839b5 100644 --- a/meta-schemas/base.yaml +++ b/meta-schemas/base.yaml @@ -29,14 +29,6 @@ properties: type: array items: type: string - allOf: - items: - propertyNames: - enum: - - $ref - - if - - then - - else properties: propertyNames: pattern: "^[#$a-zA-Z][a-zA-Z0-9,+\\-._@]{0,63}$" From 0971453d3e27ba140a6f8807ce73cf281780131c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 2 Jul 2021 14:39:16 -0600 Subject: [PATCH 101/505] meta-schemas: keywords: Drop redundant allowed properties The propertyNames schema in base.yaml covers allowed property names, so there's no need to do the same with 'properties' entries and 'additionalProperties'. Signed-off-by: Rob Herring --- meta-schemas/keywords.yaml | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/meta-schemas/keywords.yaml b/meta-schemas/keywords.yaml index 8a6efff4..ad74c88e 100644 --- a/meta-schemas/keywords.yaml +++ b/meta-schemas/keywords.yaml @@ -76,9 +76,6 @@ dependencies: $ref: "#/definitions/scalar-prop-list" properties: - $id: true - $schema: true - $ref: true additionalItems: type: boolean additionalProperties: @@ -95,19 +92,8 @@ properties: $ref: "#/definitions/sub-schemas" contains: $ref: "#/definitions/sub-schemas" - const: true - default: true - $defs: true - definitions: true - dependencies: true - deprecated: true - description: true else: $ref: "#/definitions/sub-schemas" - enum: true - examples: true - exclusiveMaximum: true - exclusiveMinimum: true if: $ref: "#/definitions/sub-schemas" items: @@ -120,17 +106,11 @@ properties: $ref: "#/definitions/sub-schemas" minItems: minimum: 1 - minimum: true - maintainers: true - maxItems: true - maximum: true - multipleOf: true not: $ref: "#/definitions/sub-schemas" oneOf: items: $ref: "#/definitions/sub-schemas" - pattern: true patternProperties: additionalProperties: $ref: "#/definitions/sub-schemas" @@ -145,9 +125,6 @@ properties: $ref: "#/definitions/sub-schemas" then: $ref: "#/definitions/sub-schemas" - title: true - type: true - typeSize: true unevaluatedProperties: oneOf: - type: object @@ -156,5 +133,3 @@ properties: - type: boolean uniqueItems: type: boolean - -additionalProperties: false From bd96f4bb5cb9b22d67ff35b5c81b473993f52364 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 2 Jul 2021 14:44:02 -0600 Subject: [PATCH 102/505] meta-schemas: Make DT property name check cover sub-schemas (aka child node schemas) The restriction that 'properties' values match DT property name patterns also applies to sub-schemas, so let's move the check into keywords.yaml so that sub-schemas are checked. Signed-off-by: Rob Herring --- meta-schemas/base.yaml | 3 --- meta-schemas/keywords.yaml | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/meta-schemas/base.yaml b/meta-schemas/base.yaml index bce839b5..7cd0d1fa 100644 --- a/meta-schemas/base.yaml +++ b/meta-schemas/base.yaml @@ -29,9 +29,6 @@ properties: type: array items: type: string - properties: - propertyNames: - pattern: "^[#$a-zA-Z][a-zA-Z0-9,+\\-._@]{0,63}$" maintainers: type: array diff --git a/meta-schemas/keywords.yaml b/meta-schemas/keywords.yaml index ad74c88e..3dda1f00 100644 --- a/meta-schemas/keywords.yaml +++ b/meta-schemas/keywords.yaml @@ -115,6 +115,8 @@ properties: additionalProperties: $ref: "#/definitions/sub-schemas" properties: + propertyNames: + pattern: "^[#$a-zA-Z][a-zA-Z0-9,+\\-._@]{0,63}$" additionalProperties: $ref: "#/definitions/sub-schemas" required: From 24cfe6953f2d41a1525b94e8da6a8b2c2c8078d0 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 2 Jul 2021 14:47:58 -0600 Subject: [PATCH 103/505] meta-schemas: Reject 'patternProperties' values that are fixed string patterns Any property that's a fixed string should go under 'properties', not 'patternProperties', so let's check for this case. Signed-off-by: Rob Herring --- meta-schemas/keywords.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meta-schemas/keywords.yaml b/meta-schemas/keywords.yaml index 3dda1f00..df5b13e5 100644 --- a/meta-schemas/keywords.yaml +++ b/meta-schemas/keywords.yaml @@ -112,6 +112,9 @@ properties: items: $ref: "#/definitions/sub-schemas" patternProperties: + propertyNames: + not: + pattern: '^\^[a-zA-Z0-9,\-._#]+\$$' additionalProperties: $ref: "#/definitions/sub-schemas" properties: From 19d754e9e2b6b319bbfd98efa26c1578e61a088a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 8 Jul 2021 10:37:23 -0600 Subject: [PATCH 104/505] Revert "meta-schemas: Reject 'patternProperties' values that are fixed string patterns" This reverts commit 24cfe6953f2d41a1525b94e8da6a8b2c2c8078d0. --- meta-schemas/keywords.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/meta-schemas/keywords.yaml b/meta-schemas/keywords.yaml index df5b13e5..3dda1f00 100644 --- a/meta-schemas/keywords.yaml +++ b/meta-schemas/keywords.yaml @@ -112,9 +112,6 @@ properties: items: $ref: "#/definitions/sub-schemas" patternProperties: - propertyNames: - not: - pattern: '^\^[a-zA-Z0-9,\-._#]+\$$' additionalProperties: $ref: "#/definitions/sub-schemas" properties: From 633a6e71dbeb3e8e2a79cd7a45c19841ba616f10 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 15 Jul 2021 12:13:54 -0600 Subject: [PATCH 105/505] dtschema: Fix breakage with upcoming jsonschema 4.0 release The 'type' parameter is removed in the upcoming release (v4.0) of jsonschema. Evidently it has been deprecated for 2 years. Let's remove it as we don't need it. Signed-off-by: Rob Herring --- dtschema/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 85b6defa..12df76aa 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -676,8 +676,8 @@ class DTValidator(DTVal): resolver = jsonschema.RefResolver('', None, handlers=handlers) format_checker = jsonschema.FormatChecker() - def __init__(self, schema, types=()): - jsonschema.Draft7Validator.__init__(self, schema, types, resolver=self.resolver, + def __init__(self, schema): + jsonschema.Draft7Validator.__init__(self, schema, resolver=self.resolver, format_checker=self.format_checker) @classmethod From 5cc4e9a0555418359c126dfaf44eb354847144fb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 16 Jul 2021 10:52:12 -0600 Subject: [PATCH 106/505] meta-schemas: clocks: Drop 'default' requirement on {bus,clock}-frequency Since draft7 and earlier ignore schemas in addition to a '$ref', requiring 'default' had no effect for clock-frequency and bus-frequency. This changes in newer json-schema versions and we could fix this with an 'allOf', but now there are lots of schemas without 'default'. So let's just drop the constraint. Signed-off-by: Rob Herring --- meta-schemas/clocks.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/meta-schemas/clocks.yaml b/meta-schemas/clocks.yaml index 9871d08b..f5e0dae1 100644 --- a/meta-schemas/clocks.yaml +++ b/meta-schemas/clocks.yaml @@ -24,14 +24,8 @@ properties: clock-frequency: $ref: "cell.yaml#/single" - properties: - default: {} - required: [default] bus-frequency: $ref: "cell.yaml#/single" - properties: - default: {} - required: [default] dependencies: clock-output-names: ['#clock-cells'] From c18426c7137144faf982ec84cb4138f4e19481a3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 16 Jul 2021 14:00:53 -0600 Subject: [PATCH 107/505] dtschema: Don't use jsonschema.compat.urlopen wrapper This wrapper was for Python2 support which is being removed from jsonschema and we don't support Python2.x anyways. Just use urllib.request.urlopen() directly which is what jsonschema does for Python3. Signed-off-by: Rob Herring --- dtschema/lib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 12df76aa..c7c914a6 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -12,6 +12,7 @@ import json from ruamel.yaml.comments import CommentedMap +from urllib.request import urlopen import jsonschema import pkgutil @@ -641,7 +642,7 @@ def http_handler(uri): return load_schema(uri.replace(schema_base_url, '')) return process_schema(uri.replace(schema_base_url, '')) - return yaml.load(jsonschema.compat.urlopen(uri).read().decode('utf-8')) + return yaml.load(urlopen(uri).read().decode('utf-8')) except FileNotFoundError as e: print('Unknown file referenced:', e, file=sys.stderr) exit(-1) From 50ef37d5a65814de0652f4ac44d5febdeca8badd Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 16 Jul 2021 15:46:07 -0600 Subject: [PATCH 108/505] dtschema: Fix logic for node fixups with additionalProperties/unevaluatedProperties The logic for skipping fixups on incomplete (typically shared, common) schemas is broken. If additionalProperties or unevaluatedProperties is true, then we skip node fixups. Signed-off-by: Rob Herring --- dtschema/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index c7c914a6..decafac9 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -363,8 +363,8 @@ def fixup_sub_schema(schema, is_prop): def fixup_node_props(schema): if not {'properties', 'patternProperties'} & schema.keys(): return - if not ('additionalProperties' in schema and schema['additionalProperties'] is not True) and \ - not ('unevaluatedProperties' in schema and schema['unevaluatedProperties'] is not True): + if ('additionalProperties' in schema and schema['additionalProperties'] is True) or \ + ('unevaluatedProperties' in schema and schema['unevaluatedProperties'] is True): return schema.setdefault('properties', dict()) From bc85fc16099c87364e98052761abf27997211071 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 13 Jul 2021 11:56:37 -0600 Subject: [PATCH 109/505] dtschema: Ensure select compatibles are sorted Ensure the order is consistent from the set of compatibles by sorting them. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index decafac9..e6fa2b1a 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -481,7 +481,7 @@ def add_select_schema(schema): if len(compatible_list) != 0: schema['select'] = { 'required': ['compatible'], - 'properties': {'compatible': {'contains': {'enum': list(compatible_list)}}}} + 'properties': {'compatible': {'contains': {'enum': sorted(compatible_list)}}}} return From 57fdf5463d7f61625d706ad9444031986c13b54b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 13 Jul 2021 11:28:24 -0600 Subject: [PATCH 110/505] dtschema: Simplify $ref allOf fixup Let's remove the 'description' first and then checking for additional schemas can be simplified. Signed-off-by: Rob Herring --- dtschema/lib.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index e6fa2b1a..fd106a7c 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -297,15 +297,13 @@ def fixup_vals(propname, schema): # Now we should be a the schema level to do actual fixups # print(schema) + schema.pop('description', None) + # This can be removed once draft 2019.09 is supported - if '$ref' in schema and \ - ((len(schema) > 1 and not 'description' in schema) or \ - (len(schema) > 2 and 'description' in schema)): + if '$ref' in schema and (len(schema) > 1): schema['allOf'] = [ {'$ref': schema['$ref']} ] schema.pop('$ref') - schema.pop('description', None) - _fixup_int_array_min_max_to_matrix(propname, schema) _fixup_int_array_items_to_matrix(propname, schema) _fixup_string_to_array(propname, schema) From 03b509d39858aa59acf653a1b47f9cf4fc7e53b2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 16 Jul 2021 15:18:35 -0600 Subject: [PATCH 111/505] dtschema: use super() instead of explicit validator Use super() instead of the specific version of validator to make switching jsonschema versions easier. Signed-off-by: Rob Herring --- dtschema/lib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index fd106a7c..7106e186 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -676,8 +676,8 @@ class DTValidator(DTVal): format_checker = jsonschema.FormatChecker() def __init__(self, schema): - jsonschema.Draft7Validator.__init__(self, schema, resolver=self.resolver, - format_checker=self.format_checker) + super().__init__(schema, resolver=self.resolver, + format_checker=self.format_checker) @classmethod def annotate_error(self, error, schema, path): @@ -725,7 +725,7 @@ def iter_schema_errors(cls, schema): yield error def iter_errors(self, instance, _schema=None): - for error in jsonschema.Draft7Validator.iter_errors(self, instance, _schema): + for error in super().iter_errors(instance, _schema): error.linecol = get_line_col(instance, error.path) error.note = None error.schema_file = None From 9a5d330fd40e1e255bd712bda5ae7e0f7164daba Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 19 Jul 2021 15:36:25 -0600 Subject: [PATCH 112/505] schemas: pci-bus: Add 'num-lanes' property Multiple bindings use 'num-lanes' properties, so let's make it common. Signed-off-by: Rob Herring --- schemas/pci/pci-bus.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/schemas/pci/pci-bus.yaml b/schemas/pci/pci-bus.yaml index de340387..26118bf8 100644 --- a/schemas/pci/pci-bus.yaml +++ b/schemas/pci/pci-bus.yaml @@ -111,6 +111,11 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 enum: [ 1, 2, 3, 4 ] + num-lanes: + description: The number of PCIe lanes + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 1, 2, 4, 8, 16, 32 ] + reset-gpios: description: GPIO controlled connection to PERST# signal maxItems: 1 From a197a2232d545965fc77f915e46227697d804ff7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 29 Jul 2021 09:45:47 -0600 Subject: [PATCH 113/505] schemas: pci: Add missing comma in pciclass compatible strings The DT PCI bus spec defines the class compatible as 'pciclass,.*', but the schema pattern missed the comma. There's several dts files in upstream Linux that did too. Signed-off-by: Rob Herring --- schemas/pci/pci-bus.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemas/pci/pci-bus.yaml b/schemas/pci/pci-bus.yaml index 26118bf8..da29dbdd 100644 --- a/schemas/pci/pci-bus.yaml +++ b/schemas/pci/pci-bus.yaml @@ -141,7 +141,7 @@ patternProperties: properties: compatible: contains: - pattern: "^(pci[0-9a-f]{3,4},[0-9a-f]{1,4}|pciclass[0-9a-f]{4,6})$" + pattern: "^(pci[0-9a-f]{3,4},[0-9a-f]{1,4}|pciclass,[0-9a-f]{4,6})$" reg: items: minItems: 5 From 0fff07e09407ee432e69406078f7b2e3162d0194 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 17 Aug 2021 11:20:19 -0500 Subject: [PATCH 114/505] dtschema: Apply fixups on 'not' schemas As 'not' contains a sub-schema, we need to descend into 'not' schemas and apply fixups. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 7106e186..022bdf9b 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -343,7 +343,7 @@ def fixup_sub_schema(schema, is_prop): fixup_node_props(schema) for k,v in schema.items(): - if k in ['select', 'if', 'then', 'else', 'additionalProperties']: + if k in ['select', 'if', 'then', 'else', 'additionalProperties', 'not']: fixup_sub_schema(v, False) if k in ['allOf', 'anyOf', 'oneOf']: From 4cf603762d0b299a18d79cd28b1d204f2d1ded74 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 17 Aug 2021 11:22:14 -0500 Subject: [PATCH 115/505] Use DTValidator instead of specific jsonschema version validator No functional change, but this makes switching the underlying validator easier. Signed-off-by: Rob Herring --- test/test-dt-validate.py | 2 +- tools/dt-validate | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index 9d057f37..73736bcf 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -101,7 +101,7 @@ def setUp(self): self.schemas = dtschema.process_schemas([ os.path.join(os.path.abspath(basedir), "schemas/")]) for schema in self.schemas: - schema["$select_validator"] = jsonschema.Draft7Validator(schema['select']) + schema["$select_validator"] = dtschema.DTValidator(schema['select']) def check_node(self, nodename, node, fail): if nodename == "/": diff --git a/tools/dt-validate b/tools/dt-validate index 410b0538..5021ae10 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -107,7 +107,7 @@ class schema_group(): """Check the given DT against all schemas""" for schema in self.schemas: - schema["$select_validator"] = jsonschema.Draft7Validator(schema['select']) + schema["$select_validator"] = dtschema.DTValidator(schema['select']) for subtree in dt: self.check_subtree(dt, subtree, "/", "/", filename) From e11b1a0c193f5974a587324c5c0302dfa42edf92 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 1 Sep 2021 17:10:45 +0200 Subject: [PATCH 116/505] schemas: property-units: Sanitize unit naming Make the naming of units consistent with common practices: - Do not capitalize the first character of units ("Celsius" is special, as it is not the unit name, but a reference to its proposer), - Do not use plural for units, - Do not abbreviate "ampere", - Concatenate prefixes and units (no spaces or hyphens), - Separate units by spaces not hyphens, - "milli" applies to "degree", not to "Celsius". Signed-off-by: Geert Uytterhoeven Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20210901151045.2483811-1-geert+renesas@glider.be --- schemas/property-units.yaml | 40 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/schemas/property-units.yaml b/schemas/property-units.yaml index 1e710bc0..c1d53182 100644 --- a/schemas/property-units.yaml +++ b/schemas/property-units.yaml @@ -25,11 +25,11 @@ select: true patternProperties: "-bits$": $ref: "types.yaml#/definitions/uint32-array" - description: Number of bits + description: number of bits "-kBps$": $ref: "types.yaml#/definitions/uint32-array" - description: Kilobytes per second + description: kilobytes per second "-percent$": $ref: "types.yaml#/definitions/uint32-array" @@ -41,65 +41,65 @@ patternProperties: description: megahertz "-hz$": $ref: "types.yaml#/definitions/uint32-array" - description: Hertz (preferred) + description: hertz (preferred) "-sec$": $ref: "types.yaml#/definitions/uint32-array" - description: seconds + description: second "-ms$": $ref: "types.yaml#/definitions/uint32-array" - description: milliseconds + description: millisecond "-us$": $ref: "types.yaml#/definitions/uint32-array" - description: microseconds + description: microsecond "-ns$": $ref: "types.yaml#/definitions/uint32-array" - description: nanoseconds + description: nanosecond "-ps$": $ref: "types.yaml#/definitions/uint32-array" - description: picoseconds + description: picosecond # Distance "-mm$": $ref: "types.yaml#/definitions/uint32-array" - description: millimeters + description: millimeter # Electricity "-microamp$": $ref: "types.yaml#/definitions/uint32-array" - description: micro amps + description: microampere "-microamp-hours$": $ref: "types.yaml#/definitions/uint32-array" - description: micro amp-hours + description: microampere hour "-ohms$": $ref: "types.yaml#/definitions/uint32-array" - description: Ohms + description: ohm "-micro-ohms$": $ref: "types.yaml#/definitions/uint32-array" - description: micro Ohms + description: microohm "-microwatt-hours$": $ref: "types.yaml#/definitions/uint32-array" - description: micro Watt-hours + description: microwatt hour "-microvolt$": $ref: "types.yaml#/definitions/uint32-matrix" - description: micro volts + description: microvolt "-picofarads$": $ref: "types.yaml#/definitions/uint32-array" - description: picofarads + description: picofarad "-femtofarads$": $ref: "types.yaml#/definitions/uint32-array" - description: femtofarads + description: femtofarad # Temperature "-celsius$": $ref: "types.yaml#/definitions/uint32-array" - description: Degrees Celsius + description: degree Celsius "-millicelsius$": $ref: "types.yaml#/definitions/uint32-array" - description: Degreee milli-Celsius + description: millidegree Celsius # Pressure "-kpascal$": $ref: "types.yaml#/definitions/uint32-array" - description: kiloPascal + description: kilopascal additionalProperties: true From e88f97951e670a9912eec4f063962c5763ada981 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 1 Sep 2021 17:13:09 +0200 Subject: [PATCH 117/505] schemas: chosen: Generalize linux,elfcorehdr and linux,usable-memory-range The properties "linux,elfcorehdr" and "linux,usable-memory-range" are no longer limited to arm64. Signed-off-by: Geert Uytterhoeven Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20210901151310.2484003-1-geert+renesas@glider.be --- schemas/chosen.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/schemas/chosen.yaml b/schemas/chosen.yaml index b93cd1df..78b87cb1 100644 --- a/schemas/chosen.yaml +++ b/schemas/chosen.yaml @@ -78,17 +78,17 @@ properties: $ref: types.yaml#/definitions/uint64-array maxItems: 2 description: - This property (currently used only on arm64) holds the memory range, - the address and the size, of the elf core header which mainly describes - the panicked kernel\'s memory layout as PT_LOAD segments of elf format. + This property holds the memory range, the address and the size, of the + elf core header which mainly describes the panicked kernel\'s memory + layout as PT_LOAD segments of elf format. linux,usable-memory-range: $ref: types.yaml#/definitions/uint64-array maxItems: 2 description: | - This property (arm64 only) holds a base address and size, describing a - limited region in which memory may be considered available for use by - the kernel. Memory outside of this range is not available for use. + This property holds a base address and size, describing a limited region + in which memory may be considered available for use by the kernel. Memory + outside of this range is not available for use. This property describes a limitation: memory within this range is only valid when also described through another mechanism that the kernel From d7c64b60c59123981f3d619fe76ef4b40bfca9e2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 1 Sep 2021 17:13:10 +0200 Subject: [PATCH 118/505] schemas: chosen: Improve linux,elfcorehdr documentation Add an example for the "linux,elfcorehdr" property, and clarify the length of its address and size. Signed-off-by: Geert Uytterhoeven Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20210901151310.2484003-2-geert+renesas@glider.be --- schemas/chosen.yaml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/schemas/chosen.yaml b/schemas/chosen.yaml index 78b87cb1..d66d10ad 100644 --- a/schemas/chosen.yaml +++ b/schemas/chosen.yaml @@ -77,11 +77,21 @@ properties: linux,elfcorehdr: $ref: types.yaml#/definitions/uint64-array maxItems: 2 - description: + description: | This property holds the memory range, the address and the size, of the elf core header which mainly describes the panicked kernel\'s memory layout as PT_LOAD segments of elf format. + / { + chosen { + linux,elfcorehdr = <0x9 0xfffff000 0x0 0x800>; + }; + }; + + While this property does not represent a real hardware, the address + and the size are expressed in #address-cells and #size-cells, + respectively, of the root node. + linux,usable-memory-range: $ref: types.yaml#/definitions/uint64-array maxItems: 2 From c5211d872a0906e13388d050fd13fd6a26008ebe Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Sep 2021 14:46:16 -0500 Subject: [PATCH 119/505] dtschema: Fix walking schema paths with 'if' A meta-schema may have 'if' schemas and 'if' properties, so we need to distinguish the 2 cases. The need for filtering out an 'if' schema in the path is only on 3.2.0 and earlier, so add a note. Signed-off-by: Rob Herring --- dtschema/lib.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 022bdf9b..f4fc0a6e 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -691,10 +691,14 @@ def annotate_error(self, error, schema, path): self.resolver.push_scope(scope) ref_depth = 1 + lastp = '' for p in path: - if p == 'if': + # json-schema 3.2.0 includes 'if' in schema path + if lastp != 'properties' and p == 'if': continue - if '$ref' in schema and isinstance(schema['$ref'], str): + lastp = p + + while '$ref' in schema and isinstance(schema['$ref'], str): ref = self.resolver.resolve(schema['$ref']) schema = ref[1] self.resolver.push_scope(ref[0]) From 793fe2015c1a7efb9c4b5d727631cdea2cfc10d6 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 19 Aug 2021 12:24:54 -0500 Subject: [PATCH 120/505] schemas/dt-core: Add "reserved" as valid value for status property As per Devicetree Specification, Release v0.3, status can have "okay", "disabled", "reserved", "fail", "fail-sss" as valid values. While "fail" and "fail-sss" descriptions could indicate a variable and potentially dynamic definition, "reserved" is more clear and static description. Lets add that to the enum list. Signed-off-by: Nishanth Menon --- schemas/dt-core.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemas/dt-core.yaml b/schemas/dt-core.yaml index 4296fc44..1aff4c33 100644 --- a/schemas/dt-core.yaml +++ b/schemas/dt-core.yaml @@ -35,7 +35,7 @@ properties: $ref: "types.yaml#/definitions/uint32-matrix" status: $ref: "types.yaml#/definitions/string" - enum: [ okay, disabled ] + enum: [ okay, disabled, reserved ] patternProperties: "^#.*-cells$": $ref: "types.yaml#/definitions/uint32" From 5f2eddc9d6583e8966b79b881abff869a6ff79ae Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Thu, 9 Sep 2021 01:02:34 +0200 Subject: [PATCH 121/505] schemas: root-node: Introduce 'chassis-type' property This patch adds an optional 'chassis-type' property to the root node in order to specify the device form factor, mimicking what is already available through DMI on ACPI-based systems. Such information can be useful (for example, in order to implement different behavior on a desktop and on a smartphone) but is not currently available on DT-based systems. Possible values are identical to those used by systemd's hostnamed. Signed-off-by: Arnaud Ferraris --- schemas/root-node.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/schemas/root-node.yaml b/schemas/root-node.yaml index ea27e641..f5160573 100644 --- a/schemas/root-node.yaml +++ b/schemas/root-node.yaml @@ -17,6 +17,17 @@ properties: $nodename: const: "/" model: { "$ref" : "types.yaml#/definitions/string-array"} + chassis-type: + items: + - const: desktop + - const: laptop + - const: convertible + - const: server + - const: tablet + - const: handset + - const: watch + - const: embedded + maxItems: 1 "#address-cells": enum: [1, 2] "#size-cells": @@ -63,6 +74,7 @@ examples: / { compatible = "acme,boogieboard"; model = "Acme Ltd. Boogieboard developer system"; + chassis-type = "embedded"; #address-cells = <1>; #size-cells = <1>; memory@0 { From e868a0f0b3b0a7214211087317957b5c921fd6a5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 28 Sep 2021 18:30:46 -0500 Subject: [PATCH 122/505] schemas: Fix chassis-type schema Signed-off-by: Rob Herring --- schemas/root-node.yaml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/schemas/root-node.yaml b/schemas/root-node.yaml index f5160573..323f2371 100644 --- a/schemas/root-node.yaml +++ b/schemas/root-node.yaml @@ -18,16 +18,15 @@ properties: const: "/" model: { "$ref" : "types.yaml#/definitions/string-array"} chassis-type: - items: - - const: desktop - - const: laptop - - const: convertible - - const: server - - const: tablet - - const: handset - - const: watch - - const: embedded - maxItems: 1 + enum: + - desktop + - laptop + - convertible + - server + - tablet + - handset + - watch + - embedded "#address-cells": enum: [1, 2] "#size-cells": From 2dc580f87dae4445d090e74357b3233eadab315d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 13 Jul 2021 12:39:55 -0600 Subject: [PATCH 123/505] dtschema: Skip array fixup for items list The fixup to support both array forms ([[1],[2],[3]] and [[1,2,3]]) is supposed to only be applied when there's just minItems and maxItems. However, a schema with those and an 'items' list also get fixed up, but not correctly. Make sure there's not an items list when doing the fixup. Signed-off-by: Rob Herring --- dtschema/lib.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index f4fc0a6e..1e86a761 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -209,6 +209,9 @@ def _fixup_int_array_min_max_to_matrix(propname, subschema): subschema = item break + if 'items' in subschema and isinstance(subschema['items'],list): + return + if _is_matrix_schema(subschema): return From 9dea6ccfb5b950626d6d6da2f9ea701e092b7713 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Sep 2021 14:24:31 -0500 Subject: [PATCH 124/505] dtschema: Use dict comprehension for extracting subsets of schemas Dictionary compreshensions are a nice way to extract a subset of a dict. Signed-off-by: Rob Herring --- dtschema/lib.py | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 1e86a761..5b13b082 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -150,15 +150,7 @@ def _is_string_schema(subschema): return False def _extract_single_schemas(subschema): - tmpsch = {} - - for match in ['const', 'enum', 'pattern', 'minimum', 'maximum']: - if not match in subschema: - continue - tmpsch[match] = subschema[match] - del subschema[match] - - return tmpsch + return { k: subschema.pop(k) for k in ('const', 'enum', 'pattern', 'minimum', 'maximum') if k in subschema } def _fixup_string_to_array(propname, subschema): # nothing to do if we don't have a set of string schema @@ -237,6 +229,7 @@ def _fixup_int_array_min_max_to_matrix(propname, subschema): _fixup_items_size(subschema['oneOf']) def _fixup_int_array_items_to_matrix(propname, subschema): + itemkeys = ('items','minItems','maxItems', 'uniqueItems', 'default') if not is_int_array_schema(propname, subschema): return @@ -251,14 +244,7 @@ def _fixup_int_array_items_to_matrix(propname, subschema): return if isinstance(subschema['items'],dict): - subschema['items'] = copy.deepcopy(subschema) - # Don't copy 'allOf' - subschema['items'].pop('allOf', None) - subschema['items'].pop('oneOf', None) - for k in list(subschema.keys()): - if k in ['items', 'allOf', 'oneOf']: - continue - subschema.pop(k) + subschema['items'] = {k: subschema.pop(k) for k in itemkeys if k in subschema} if isinstance(subschema['items'],list): subschema['items'] = [ {'items': subschema['items']} ] From 032a09cfa299a33eca85468a294aa7662671f723 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 13 Jul 2021 11:29:53 -0600 Subject: [PATCH 125/505] dtschema: Properly handle minItems/maxItems for items list On a schema such as this: minItems: 1 items: - {} - {} The fixups are not handling 'minItems' correctly and it gets lost. We need to move all the array properties into the outer array, not just 'items'. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 5b13b082..dd684276 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -247,7 +247,7 @@ def _fixup_int_array_items_to_matrix(propname, subschema): subschema['items'] = {k: subschema.pop(k) for k in itemkeys if k in subschema} if isinstance(subschema['items'],list): - subschema['items'] = [ {'items': subschema['items']} ] + subschema['items'] = [ {k: subschema.pop(k) for k in itemkeys if k in subschema} ] def _fixup_scalar_to_array(propname, subschema): if not _is_int_schema(subschema): From fc2fd2b817f67741deb76c8e2a9e5a57e7af7e57 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Sep 2021 22:48:49 -0500 Subject: [PATCH 126/505] Don't allow jsonschema 4.0.0 jsonschema 4.0.0 broke us with changes just before the release, so disallow it until we can figure out how to fix it. Signed-off-by: Rob Herring --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 12767c55..94bc53a5 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ install_requires=[ 'ruamel.yaml>0.15.69', - 'jsonschema>=3.0.1', + 'jsonschema>=3.0.1,<4.0.0', 'rfc3987', ], From ae00cf651d34bf822f64f310e3fc2a4255c7a4e1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 30 Sep 2021 08:39:29 -0500 Subject: [PATCH 127/505] dtschema: Rework __init__ arg handling for jsonschema 4.0.0 jsonschema 4.0.0 changed how Validator class attrs are initialized which broke us. Update how we pass keyword args. Sub-classing a validator is not supported according to the jsonschema author and subject to breaking (as it just did), so we will need to rework the interface. Signed-off-by: Rob Herring --- dtschema/lib.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index dd684276..bc4c1f57 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -664,9 +664,10 @@ class DTValidator(DTVal): resolver = jsonschema.RefResolver('', None, handlers=handlers) format_checker = jsonschema.FormatChecker() - def __init__(self, schema): - super().__init__(schema, resolver=self.resolver, - format_checker=self.format_checker) + def __init__(self, *args, **kwargs): + kwargs.setdefault('resolver', self.resolver) + kwargs.setdefault('format_checker', self.format_checker) + super().__init__(*args, **kwargs) @classmethod def annotate_error(self, error, schema, path): From 026661fbb007cc8950c39eb07d4f132e30367ca9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 30 Sep 2021 08:45:10 -0500 Subject: [PATCH 128/505] Revert "Don't allow jsonschema 4.0.0" This reverts commit fc2fd2b817f67741deb76c8e2a9e5a57e7af7e57. Now that we've properly fixed working with 4.0.0, we can allow it again. Signed-off-by: Rob Herring --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 94bc53a5..12767c55 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ install_requires=[ 'ruamel.yaml>0.15.69', - 'jsonschema>=3.0.1,<4.0.0', + 'jsonschema>=3.0.1', 'rfc3987', ], From 018dd2720e53cb78a2fc6eb59165d623412c5ad2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 14 Jun 2021 14:46:17 -0600 Subject: [PATCH 129/505] meta-schemas: Make items length check handle only minItems or maxItems The items meta-schema is incomplete. It only prevents having both minItems and maxItems equal to the length of the 'items' list. We want to prevent having either one equal to the length of the list. Signed-off-by: Rob Herring --- meta-schemas/items.yaml | 106 +++++++++++---------------------- test/schemas/good-example.yaml | 3 - 2 files changed, 36 insertions(+), 73 deletions(-) diff --git a/meta-schemas/items.yaml b/meta-schemas/items.yaml index 681789e2..05d93f41 100644 --- a/meta-schemas/items.yaml +++ b/meta-schemas/items.yaml @@ -1,5 +1,5 @@ # SPDX-License-Identifier: BSD-2-Clause -# Copyright 2019 Arm Ltd. +# Copyright 2019-2021 Arm Ltd. %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/items.yaml#" @@ -25,139 +25,105 @@ properties: allOf: - if: + type: object + properties: + items: + type: array + additionalItems: false required: - items - maxItems + then: + description: '"maxItems" is not needed with an "items" list' + not: + required: + - maxItems + - if: + type: object + properties: + items: + type: array + additionalItems: false + required: + - items + - minItems + then: + description: + '"minItems" is only needed if less than the "items" list length' oneOf: - properties: items: - type: array minItems: 1 maxItems: 1 - maxItems: - const: 1 + minItems: false - properties: items: - type: array minItems: 2 maxItems: 2 minItems: - const: 2 - maxItems: - const: 2 + const: 1 - properties: items: - type: array minItems: 3 maxItems: 3 minItems: - const: 3 - maxItems: - const: 3 + maximum: 2 - properties: items: - type: array minItems: 4 maxItems: 4 minItems: - const: 4 - maxItems: - const: 4 + maximum: 3 - properties: items: - type: array minItems: 5 maxItems: 5 minItems: - const: 5 - maxItems: - const: 5 + maximum: 4 - properties: items: - type: array minItems: 6 maxItems: 6 minItems: - const: 6 - maxItems: - const: 6 + maximum: 5 - properties: items: - type: array minItems: 7 maxItems: 7 minItems: - const: 7 - maxItems: - const: 7 + maximum: 6 - properties: items: - type: array minItems: 8 maxItems: 8 minItems: - const: 8 - maxItems: - const: 8 + maximum: 7 - properties: items: - type: array minItems: 9 maxItems: 9 minItems: - const: 9 - maxItems: - const: 9 + maximum: 8 - properties: items: - type: array minItems: 10 maxItems: 10 minItems: - const: 10 - maxItems: - const: 10 + maximum: 9 - properties: items: - type: array minItems: 11 maxItems: 11 minItems: - const: 11 - maxItems: - const: 11 + maximum: 10 - properties: items: - type: array minItems: 12 maxItems: 12 minItems: - const: 12 - maxItems: - const: 12 - - properties: - items: - type: array - minItems: 16 - maxItems: 16 - minItems: - const: 16 - maxItems: - const: 16 + maximum: 11 - properties: items: - type: array - minItems: 32 - maxItems: 32 - minItems: - const: 32 - maxItems: - const: 32 - then: - description: - '"minItems/maxItems" equal to the "items" list length are not necessary' - properties: - minItems: false - maxItems: false + minItems: 13 ... diff --git a/test/schemas/good-example.yaml b/test/schemas/good-example.yaml index 7d771f81..9a9ccba1 100644 --- a/test/schemas/good-example.yaml +++ b/test/schemas/good-example.yaml @@ -37,7 +37,6 @@ properties: interrupts: minItems: 1 - maxItems: 2 items: - description: 1st irq - description: 2nd irq @@ -59,7 +58,6 @@ properties: clocks: minItems: 1 - maxItems: 2 items: - description: 1st clock - description: 2nd clock @@ -122,7 +120,6 @@ properties: vendor,string-list-prop: $ref: "/schemas/types.yaml#/definitions/string-array" - minItems: 2 items: - const: foobar - const: foobaz From c999e4a533c17d5e33390a5d17f4e409e3086f78 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 24 Aug 2021 15:27:44 -0500 Subject: [PATCH 130/505] meta-schemas: Use 'enum' rather than 'oneOf' + 'const' entries 'enum' is preferred over 'oneOf' + multiple 'const' entries, so let's enforce that. 'oneOf' can still be used when other schema keywords are present. Signed-off-by: Rob Herring --- meta-schemas/keywords.yaml | 12 ++++++++++-- test/schemas/child-node-example.yaml | 5 +++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/meta-schemas/keywords.yaml b/meta-schemas/keywords.yaml index 3dda1f00..733c6a8b 100644 --- a/meta-schemas/keywords.yaml +++ b/meta-schemas/keywords.yaml @@ -109,8 +109,16 @@ properties: not: $ref: "#/definitions/sub-schemas" oneOf: - items: - $ref: "#/definitions/sub-schemas" + allOf: + - items: + $ref: "#/definitions/sub-schemas" + - description: Use 'enum' rather than 'oneOf' + 'const' entries + not: + items: + propertyNames: + const: const + required: + - const patternProperties: additionalProperties: $ref: "#/definitions/sub-schemas" diff --git a/test/schemas/child-node-example.yaml b/test/schemas/child-node-example.yaml index 80b96021..0296a4f6 100644 --- a/test/schemas/child-node-example.yaml +++ b/test/schemas/child-node-example.yaml @@ -53,8 +53,9 @@ patternProperties: allOf: - $ref: "/schemas/types.yaml#/definitions/uint32" - oneOf: - # Testing for 'oneOf', otherwise this could just be an enum - - const: 2 + - description: | + Testing for 'oneOf', otherwise this could just be an enum + const: 2 - const: 4 description: test reg: From e909a2b17cad6cfaf257284f1f4449a143c5a610 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 2 Sep 2021 15:49:42 -0500 Subject: [PATCH 131/505] meta-schemas: Ensure standard unit properties don't have a $ref As all unit suffix properties have a type already, there shouldn't be a need to have a $ref to define the type. Signed-off-by: Rob Herring --- meta-schemas/core.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index 8a668bb9..00ce3360 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -64,7 +64,12 @@ definitions: enum: [ description, deprecated ] '-(bits|-kBps|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kpascal)$': - $ref: "cell.yaml#/array" + allOf: + - $ref: "cell.yaml#/array" + - description: Standard unit suffix properties don't need a type $ref + propertyNames: + not: + const: $ref '^.*$': properties: From 14eda075241fecdb9740bcf01d4310c2d91d43f5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 14 Oct 2021 13:14:21 -0500 Subject: [PATCH 132/505] dt-validate: Disable required property checks when parent node(s) disabled 'disabled' status is inherited from parent nodes, so the required properties errors should be disabled for that case too. Signed-off-by: Rob Herring --- tools/dt-validate | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tools/dt-validate b/tools/dt-validate index 5021ae10..ccfff0c4 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -34,7 +34,7 @@ class schema_group(): else: exit(-1) - def check_node(self, tree, node, nodename, fullname, filename): + def check_node(self, tree, node, disabled, nodename, fullname, filename): # Skip any generated nodes node['$nodename'] = [ nodename ] node_matched = False @@ -55,9 +55,9 @@ class schema_group(): # boards using that particular node. Thus, if the # node is marked as disabled, let's just ignore # any error message reporting a missing property. - if isinstance(error.instance, dict) and \ + if disabled or (isinstance(error.instance, dict) and \ 'status' in error.instance and \ - 'disabled' in error.instance['status']: + 'disabled' in error.instance['status']): if 'required property' in error.message: continue elif error.context: @@ -93,15 +93,21 @@ class schema_group(): if show_unmatched >= 2 and not node_matched: print("%s: %s: failed to match any schema" % (filename, fullname), file=sys.stderr) - def check_subtree(self, tree, subtree, nodename, fullname, filename): + def check_subtree(self, tree, subtree, disabled, nodename, fullname, filename): if nodename.startswith('__'): return - self.check_node(tree, subtree, nodename, fullname, filename) + + try: + disabled = ('disabled' in subtree['status']) + except: + pass + + self.check_node(tree, subtree, disabled, nodename, fullname, filename) if fullname != "/": fullname += "/" for name,value in subtree.items(): if isinstance(value, dict): - self.check_subtree(tree, value, name, fullname + name, filename) + self.check_subtree(tree, value, disabled, name, fullname + name, filename) def check_trees(self, filename, dt): """Check the given DT against all schemas""" @@ -110,7 +116,7 @@ class schema_group(): schema["$select_validator"] = dtschema.DTValidator(schema['select']) for subtree in dt: - self.check_subtree(dt, subtree, "/", "/", filename) + self.check_subtree(dt, subtree, False, "/", "/", filename) if __name__ == "__main__": ap = argparse.ArgumentParser(fromfile_prefix_chars='@', From 214dd9af1eeedb46443a28628cf51c2a0f688ce7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 29 Oct 2021 13:56:56 -0500 Subject: [PATCH 133/505] meta-schemas: Add description for node schemas Node schemas must have a type (object) or a $ref. Signed-off-by: Rob Herring --- meta-schemas/core.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index 00ce3360..4d2efd93 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -97,6 +97,7 @@ definitions: - if: required: [ properties ] then: + description: node schemas must have a type or $ref anyOf: - required: [ type ] - required: [ $ref ] From 75a2368fcfae667e098dc7d3cc4e642ba67c36af Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 1 Oct 2021 17:16:24 -0500 Subject: [PATCH 134/505] meta-schemas: Allow draft2019-09 dependentRequired/dependentSchemas vocab Allow schemas to use draft2019-09 dependentRequired/dependentSchemas vocabulary. We already allow unevaluatedProperties/unevaluatedItems and don't care about anything else ATM. Signed-off-by: Rob Herring --- meta-schemas/base.yaml | 6 +++--- meta-schemas/core.yaml | 6 +++--- meta-schemas/keywords.yaml | 2 ++ meta-schemas/nodes.yaml | 2 ++ 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/meta-schemas/base.yaml b/meta-schemas/base.yaml index 7cd0d1fa..8b4ef775 100644 --- a/meta-schemas/base.yaml +++ b/meta-schemas/base.yaml @@ -49,9 +49,9 @@ properties: propertyNames: enum: [ $id, $schema, title, description, examples, required, allOf, anyOf, oneOf, - definitions, $defs, additionalProperties, dependencies, patternProperties, - properties, if, then, else, unevaluatedProperties, deprecated, maintainers, - select ] + definitions, $defs, additionalProperties, dependencies, dependentRequired, + dependentSchemas, patternProperties, properties, if, then, else, + unevaluatedProperties, deprecated, maintainers, select ] required: - $id diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index 4d2efd93..8faa6fde 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -47,9 +47,9 @@ definitions: description: A json-schema keyword was found instead of a DT property name. not: enum: [ $ref, additionalItems, additionalProperties, allOf, anyOf, - const, contains, default, dependencies, deprecated, description, - else, enum, if, items, maxItems, maximum, minItems, minimum, - multipleOf, not, oneOf, pattern, patternProperties, properties, + const, contains, default, dependencies, dependentRequired, dependentSchemas, + deprecated, description, else, enum, if, items, maxItems, maximum, minItems, + minimum, multipleOf, not, oneOf, pattern, patternProperties, properties, propertyNames, required, then, unevaluatedProperties ] patternProperties: diff --git a/meta-schemas/keywords.yaml b/meta-schemas/keywords.yaml index 733c6a8b..f38a7623 100644 --- a/meta-schemas/keywords.yaml +++ b/meta-schemas/keywords.yaml @@ -24,6 +24,8 @@ definitions: - contains - default - dependencies + - dependentRequired + - dependentSchemas - deprecated - description - else diff --git a/meta-schemas/nodes.yaml b/meta-schemas/nodes.yaml index 0b0fac93..1c412e7b 100644 --- a/meta-schemas/nodes.yaml +++ b/meta-schemas/nodes.yaml @@ -18,6 +18,8 @@ propertyNames: - type - description - dependencies + - dependentRequired + - dependentSchemas - properties - patternProperties - additionalProperties From 4cc3eb160f43ac858b0aeb2b7929284fc1a7efb7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 24 Jun 2021 11:22:18 -0600 Subject: [PATCH 135/505] meta-schemas: Validate meta-schemas against draft2019-09 schema The meta-schemas need to match the version of the validator. In preparation to switch to draft2019-09, update all the meta-schemas to draft2019-09. This means the 'dependencies' schemas have no effect until we switch. Signed-off-by: Rob Herring --- meta-schemas/base.yaml | 3 +-- meta-schemas/boolean.yaml | 2 +- meta-schemas/cell.yaml | 2 +- meta-schemas/clocks.yaml | 4 ++-- meta-schemas/core.yaml | 4 ++-- meta-schemas/dma.yaml | 4 ++-- meta-schemas/gpios.yaml | 4 ++-- meta-schemas/hwlock.yaml | 4 ++-- meta-schemas/iio.yaml | 4 ++-- meta-schemas/interrupts.yaml | 6 ++++-- meta-schemas/iommu.yaml | 2 +- meta-schemas/items.yaml | 2 +- meta-schemas/keywords.yaml | 4 ++-- meta-schemas/mailbox.yaml | 4 ++-- meta-schemas/nodes.yaml | 2 +- meta-schemas/nvmem.yaml | 4 ++-- meta-schemas/phy.yaml | 4 ++-- meta-schemas/power-domain.yaml | 4 ++-- meta-schemas/pwm.yaml | 4 ++-- meta-schemas/reset.yaml | 4 ++-- meta-schemas/string-array.yaml | 2 +- meta-schemas/vendor-props.yaml | 2 +- 22 files changed, 38 insertions(+), 37 deletions(-) diff --git a/meta-schemas/base.yaml b/meta-schemas/base.yaml index 8b4ef775..643898f7 100644 --- a/meta-schemas/base.yaml +++ b/meta-schemas/base.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/base.yaml#" -$schema: "http://json-schema.org/draft-07/schema#" +$schema: "http://json-schema.org/draft/2019-09/schema" description: "Metaschema for devicetree binding documentation" allOf: @@ -85,4 +85,3 @@ else: use "additionalProperties"' required: - additionalProperties - diff --git a/meta-schemas/boolean.yaml b/meta-schemas/boolean.yaml index a6191691..1821cc23 100644 --- a/meta-schemas/boolean.yaml +++ b/meta-schemas/boolean.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/boolean.yaml#" -$schema: "http://json-schema.org/draft-07/schema#" +$schema: "http://json-schema.org/draft/2019-09/schema#" properties: type: diff --git a/meta-schemas/cell.yaml b/meta-schemas/cell.yaml index 3b79af4e..91328cfb 100644 --- a/meta-schemas/cell.yaml +++ b/meta-schemas/cell.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/cell.yaml#" -$schema: "http://json-schema.org/draft-07/schema#" +$schema: "http://json-schema.org/draft/2019-09/schema#" array: description: cell array properties must define how many entries and what the diff --git a/meta-schemas/clocks.yaml b/meta-schemas/clocks.yaml index f5e0dae1..facad30b 100644 --- a/meta-schemas/clocks.yaml +++ b/meta-schemas/clocks.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/clocks.yaml#" -$schema: "http://json-schema.org/draft-07/schema#" +$schema: "http://json-schema.org/draft/2019-09/schema#" properties: clocks: @@ -27,7 +27,7 @@ properties: bus-frequency: $ref: "cell.yaml#/single" -dependencies: +dependentRequired: clock-output-names: ['#clock-cells'] clock-indices: ['#clock-cells'] clock-names: [clocks] diff --git a/meta-schemas/core.yaml b/meta-schemas/core.yaml index 8faa6fde..4d4d6dcb 100644 --- a/meta-schemas/core.yaml +++ b/meta-schemas/core.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/core.yaml#" -$schema: "http://json-schema.org/draft-07/schema#" +$schema: "http://json-schema.org/draft/2019-09/schema#" description: "Metaschema for devicetree binding documentation" allOf: @@ -102,7 +102,7 @@ definitions: - required: [ type ] - required: [ $ref ] - dependencies: + dependentRequired: "#size-cells": [ "#address-cells" ] memory-region-names: [ memory-region ] reg-names: [ reg ] diff --git a/meta-schemas/dma.yaml b/meta-schemas/dma.yaml index f8cf7f1b..e0ada191 100644 --- a/meta-schemas/dma.yaml +++ b/meta-schemas/dma.yaml @@ -3,11 +3,11 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/dma.yaml#" -$schema: "http://json-schema.org/draft-07/schema#" +$schema: "http://json-schema.org/draft/2019-09/schema#" properties: dmas: $ref: "cell.yaml#/array" -dependencies: +dependentRequired: dma-names: [dmas] diff --git a/meta-schemas/gpios.yaml b/meta-schemas/gpios.yaml index add30fd1..b80040a4 100644 --- a/meta-schemas/gpios.yaml +++ b/meta-schemas/gpios.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/gpios.yaml#" -$schema: "http://json-schema.org/draft-07/schema#" +$schema: "http://json-schema.org/draft/2019-09/schema#" properties: gpio-controller: @@ -22,7 +22,7 @@ patternProperties: '(? Date: Mon, 16 Aug 2021 19:31:48 -0500 Subject: [PATCH 136/505] dtschema: Switch to jsonschema Draft 2019-09 Now that jsonschema 4.x supports Draft 2019-09, switch to it. We need it for the unevaluatedProperties support. Draft2020-12 could be used, but it has features we don't want (items -> prefixItems). Signed-off-by: Rob Herring --- dtschema/lib.py | 47 +++++++++++++++++++++++++++++++++++++++++++++-- setup.py | 2 +- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index bc4c1f57..8da514d1 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -282,6 +282,45 @@ def _fixup_items_size(schema): elif 'minItems' in schema and not 'maxItems' in schema: schema['maxItems'] = schema['minItems'] +def fixup_schema_to_201909(schema): + if not isinstance(schema, dict): + return + + # dependencies is now split into dependentRequired and dependentSchema + try: + val = schema.pop('dependencies') + for k,v in val.items(): + if isinstance(v, list): + schema.setdefault('dependentRequired', {}) + schema['dependentRequired'][k] = v + else: + schema.setdefault('dependentSchemas', {}) + schema['dependentSchemas'][k] = v + except: + pass + +def fixup_schema_to_202012(schema): + if not isinstance(schema, dict): + return + + fixup_schema_to_201909(schema) + + try: + if isinstance(schema['items'], list): + schema['prefixItems'] = schema.pop('items') + for i in schema['prefixItems']: + fixup_schema_to_202012(i) + if isinstance(schema['items'], dict): + fixup_schema_to_202012(schema['items']) + except: + pass + + try: + val = schema.pop('additionalItems') + schema['unevaluatedItems'] = val + except: + pass + def fixup_vals(propname, schema): # Now we should be a the schema level to do actual fixups # print(schema) @@ -298,6 +337,8 @@ def fixup_vals(propname, schema): _fixup_string_to_array(propname, schema) _fixup_scalar_to_array(propname, schema) _fixup_items_size(schema) + + fixup_schema_to_201909(schema) # print(schema) def walk_properties(propname, schema): @@ -339,7 +380,7 @@ def fixup_sub_schema(schema, is_prop): for subschema in v: fixup_sub_schema(subschema, True) - if not k in ['dependencies', 'properties', 'patternProperties', '$defs']: + if not k in ['dependentRequired', 'dependentSchemas', 'dependencies', 'properties', 'patternProperties', '$defs']: continue for prop in v: @@ -347,6 +388,8 @@ def fixup_sub_schema(schema, is_prop): # Recurse to check for {properties,patternProperties} in each prop fixup_sub_schema(v[prop], True) + fixup_schema_to_201909(schema) + def fixup_node_props(schema): if not {'properties', 'patternProperties'} & schema.keys(): return @@ -651,7 +694,7 @@ def phandle(validator, phandle, instance, schema): if not isinstance(instance, phandle_int): yield jsonschema.ValidationError("missing phandle tag in %r" % instance) -DTVal = jsonschema.validators.extend(jsonschema.Draft7Validator, {'typeSize': typeSize, 'phandle': phandle}) +DTVal = jsonschema.validators.extend(jsonschema.Draft201909Validator, {'typeSize': typeSize, 'phandle': phandle}) class DTValidator(DTVal): '''Custom Validator for Devicetree Schemas diff --git a/setup.py b/setup.py index 12767c55..7505827a 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ install_requires=[ 'ruamel.yaml>0.15.69', - 'jsonschema>=3.0.1', + 'jsonschema>=4.1.2', 'rfc3987', ], From 85119d46d8f824cc3e96ac2ab128d03451a19a62 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 29 Oct 2021 16:25:24 -0500 Subject: [PATCH 137/505] github workflows: Drop python 3.6 and add 3.10 jsonschema 4.1.x dropped support for python 3.6. Since we require that version, we must drop it too. While we're here, we can add 3.10 testing. Signed-off-by: Rob Herring --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9abcd7bd..6665a5e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: [3.7, 3.8, 3.9, 3.10] steps: - uses: actions/checkout@v2 From d7354482e7efcf093b440894086ed84aa0e18a29 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 29 Oct 2021 16:32:57 -0500 Subject: [PATCH 138/505] github workflows: quote python version numbers The python version numbers need to be quoted or they are treated by YAML as numbers and 3.10 gets interpretted as 3.1. Signed-off-by: Rob Herring --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6665a5e9..da5845ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [3.7, 3.8, 3.9, 3.10] + python-version: ['3.7', '3.8', '3.9', '3.10'] steps: - uses: actions/checkout@v2 From 697395c38fd03d50b44b4156728dbc927588737b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 3 Nov 2021 19:47:16 -0500 Subject: [PATCH 139/505] dtschema: Only add 'interrupt-parent' if not already present Blindly overwriting 'interrupt-parent' meant the actual schema for it got overwritten. Signed-off-by: Rob Herring --- dtschema/lib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 8da514d1..3cc5e428 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -530,7 +530,8 @@ def fixup_interrupts(schema): return # Any node with 'interrupts' can have 'interrupt-parent' - if schema['properties'].keys() & {'interrupts', 'interrupt-controller'}: + if schema['properties'].keys() & {'interrupts', 'interrupt-controller'} and \ + not 'interrupt-parent' in schema['properties']: schema['properties']['interrupt-parent'] = True if not 'interrupts' in schema['properties']: From b89dde831dea7fcf903ebdd04461c9c36e3d93db Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 11 Oct 2021 13:10:48 +0200 Subject: [PATCH 140/505] schemas: cpus: document CPU-specific "status" property As discussed in [1] and [2], CPU nodes have an unusual interpretation of the "disabled" status. Explicitly document the okay, disabled and fail status values in cpus.yaml. [1] https://www.lkml.org/lkml/2020/8/26/1237 [2] https://www.spinics.net/lists/devicetree-spec/msg01007.html Signed-off-by: Matthias Schiffer --- schemas/cpus.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/schemas/cpus.yaml b/schemas/cpus.yaml index 3d0c3ba3..3ecfa7a5 100644 --- a/schemas/cpus.yaml +++ b/schemas/cpus.yaml @@ -73,6 +73,14 @@ patternProperties: Specifies the current frequency at which the timebase and the decrementer registers are updated (in Hertz). + status: + $ref: "types.yaml#/definitions/string" + enum: [ okay, disabled, fail ] + description: + A standard property describing the state of a CPU. A CPU may be + running ("okay"), in a quiescent state ("disabled") or be not + operational or not exist ("fail"). + enable-method: $ref: /schemas/types.yaml#/definitions/string-array description: From 9db185f231f4f6ccd27b47fe4521cddc2b23e8b9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 27 Oct 2021 19:34:45 -0600 Subject: [PATCH 141/505] schemas: add option node schema The descriptions are based on chosen.yaml with some additional notes to explain the purpose. Signed-off-by: Simon Glass --- schemas/options.yaml | 79 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 schemas/options.yaml diff --git a/schemas/options.yaml b/schemas/options.yaml new file mode 100644 index 00000000..d6f5bbb0 --- /dev/null +++ b/schemas/options.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-clause +# Copyright 2021 Google LLC +# + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/options.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: /options Node + +maintainers: + - Simon Glass + +description: | + The '/options' node does not represent a real device, but serves as a place + for passing data into and between firmware components, such as memory + mappings. Data in the '/options' node does not represent the hardware. It is + ignored by operating systems. + + Properties in this node should be common to (and used by) at least two + firmware projects, such as U-Boot and TF-A. Project-specific subnodes can be + used for properties which are specific to a single project. + + This is based on the precedent set by IEEE 1275-1994 IEEE Standard for Boot + (Initialization Configuration) Firmware: Core Requirements and Practices + at https://www.openfirmware.info/data/docs/of1275.pdf + + Purpose of '/options' node + -------------------------- + + A common problem with firmware is that many builds are needed to deal with the + slight variations between different, related models of the same hardware. For + example, one model may have a TPM and another may not. Devicetree provides an + excellent solution to this problem, in that the devicetree to actually use on + a platform can be injected in the factory based on which model is being + manufactured at the time. + + A related problem causing build proliferation is dealing with the differences + between development firmware, developer-friendly firmware (e.g. with all + security features present but with the ability to access the command line), + test firmware (which runs tests used in the factory), final production + firmware (before signing), signed firmware (where the signatures have been + inserted) and the like. Ideally all or most of these should use the same + firmware build, with just some options to determine the features available. + For example, being able to control whether the UART console or JTAG are + available, on any image, is a great debugging aid. + + When the firmware consists of multiple parts (various U-Boot phases, TF-A, + OP-TEE), it is helpful that all operate the same way at runtime, regardless of + how they were built. This can be achieved by passing the runtime configuration + (e.g. 'enable UART console', 'here are your public keys') along the chain + through each firmware stage. It is frustrating to have to replicate a bug on + production firmware which does not happen on developer firmware, because they + are completely different builds. + + The '/options' node provides useful functionality for this. It allows the + different controls to be 'factored out' of the firmware binaries, so they can + be controlled separately from the initial source-code build. The node can be + easily updated by a build or factory tool and can control various features in + the firmware binaries. It is similar in concept to a Kconfig option, except + that it can be changed after firmware binaries are built. + + The '/options' node is similar in concept to /chosen (see chosen.yaml) except + that it is for passing information *into* and *between*) firmware components, + instead of from firmware to the operating system. Also, while operating + systems typically have a (sometimes extremely long) command line, firmware + binaries typically do not support this. The devicetree provides a more + structured approach in any case. + +properties: + $nodename: + const: options + + "#address-cells": true + "#size-cells": true + +additionalProperties: + type: object From 0986f729eff0f40a66e85ab9dfb37681bf025ac4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 27 Oct 2021 19:48:29 -0600 Subject: [PATCH 142/505] dt-bindings: u-boot: Add an initial binding for config U-Boot makes use of the devicetree for its driver model. Devices are bound based on the hardware description in the devicetree. Since U-Boot is not an operating system, it has no command line or user space to provide configuration and policy information. This must be made available in some other way. Therefore U-Boot uses devicetree for configuration and run-time control and has done for approximately 9 years. This works extremely well in the project and is very flexible. However the bindings have never been incorporated in the devicetree bindings in the Linux tree. This could be a good time to start this work as we try to create standard bindings for communicating between firmware components. Add an initial binding for this node, covering just the config node, which is the main requirement. It is similar in concept to the chosen node, but used for passing information between firmware components, instead of from firmware to the operating system. Signed-off-by: Simon Glass --- schemas/options/u-boot.yaml | 106 ++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 schemas/options/u-boot.yaml diff --git a/schemas/options/u-boot.yaml b/schemas/options/u-boot.yaml new file mode 100644 index 00000000..71dfda71 --- /dev/null +++ b/schemas/options/u-boot.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2021 Google LLC + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/options/u-boot.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: U-Boot configuration node + +maintainers: + - Simon Glass + +description: | + The u-boot,config node provides basic configuration information to U-Boot, + for use during its execution. It can be used to control U-Boot's behaviour + in various ways. + +properties: + $nodename: + const: u-boot + + compatible: + const: u-boot,config + + bootcmd: + $ref: /schemas/types.yaml#/definitions/string + description: | + Allows overwriting of the boot command used by U-Boot on startup. If + present, U-Boot uses this command instead. Note that this feature can + work even if loading the environment is disabled, e.g. for security + reasons. See also bootsecure. + + bootdelay-sec: + description: | + Allows selecting of the U-Boot bootdelay, to control whether U-Boot + waits on boot or for how long. This allows this option to be configured + by the build system or by a previous-stage binary. For example, if the + images is being packed for testing or a user holds down a button, it may + allow a delay, but disable it for production. + + If this property is not present, a default value is used instead. + + Note that this uses the 'sec' property unit, even though it allows a + negative value. + + Values: + + -1: no bootdelay and the user cannot interrupt boot + 0: no bootdelay but use user can still interrupt boot by holding down a + key, if enabled + >= 1: delay for this many seconds + + + bootsecure: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + maximum: 2 + description: | + Controls the execution of the boot command in U-Boot, e.g. selecting + between using a special function to run commands, or the normal CLI. This + can be used in production images, to restrict the amount of parsing done + or the options available, to cut back on the available surface for + security attacks. + + Values: + + 0: normal boot using CLI (default if not present) + 1: use secure boot mechanism instead to parse and run commands + other values are reserved for future use + 2: use simplified command line (e.g. avoid hush) + 3... reserved + + silent-console: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + maximum: 2 + description: | + This allows the console to be silenced by default on boot. This can allow + easy disabling of console output on a production build, for example. When + suppressed, the console is still active. This feature only suppresses the + console output itself, on all output devices. + + Values: + + 0: console output appears as normal (default) + 1: console output is suppressed but console recording still operates (if + enabled) + 2: console output is suppressed and not recorded + +required: + - compatible + +additionalProperties: false + +examples: + - | + options { + u-boot { + compatible = "u-boot,config"; + bootcmd = "vboot go auto"; + bootdelay-sec = <(-1)>; + bootsecure = <1>; + silent-console = <1>; + }; + }; From 088800c7fedbce7df4cce1038e6bedbc8745f070 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 27 Oct 2021 20:07:05 -0600 Subject: [PATCH 143/505] README: Use Python 3 version of the ruamel.yaml module The Python 2 version does not exist on some newer distributions, such as Ubuntu 20.04 Signed-off-by: Simon Glass --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 605c8276..3379726a 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ On Debian/Ubuntu, the dependencies can be installed with apt and/or pip. The rfc3987 module is not packaged, so pip must be used: ``` -apt-get install python3 python-ruamel.yaml +apt-get install python3 python3-ruamel.yaml pip3 install rfc3987 ``` From 6e8cc9cbaf9e4afbbf06029ece455f6e2798cdbe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 27 Oct 2021 20:08:43 -0600 Subject: [PATCH 144/505] README: Put the tool names in a fixed-width font Show these in a different style to make them stand out more. Signed-off-by: Simon Glass --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3379726a..aaea2bbc 100644 --- a/README.md +++ b/README.md @@ -83,19 +83,20 @@ Devicetree Meta-Schema files are normal YAML files using the jsonschema vocabula ## Usage There are several tools available in the *tools/* directory. -tools/dt-doc-validate +`tools/dt-doc-validate` This tool takes a schema file(s) or directory of schema files and validates them against the DT meta-schema. -tools/dt-mk-schema -This tool takes user provided schema file(s) plus the core schema files in this +`tools/dt-mk-schema` +This tool takes user-provided schema file(s) plus the core schema files in this repo, removes everything not needed for validation, applies fix-ups to the schemas, and outputs a single file with the processed schema. This step is done separately to speed up subsequent validation of YAML Devicetrees. -tools/dt-validate -This tool takes user provided YAML Devicetree(s) and either a schema directory -or pre-processed schema file and validates the YAML Devicetree against the schema. +`tools/dt-validate` +This tool takes user-provided YAML Devicetree(s) and either a schema directory +or pre-processed schema file and validates the YAML Devicetree against the +schema. ## Installing From be1c1cd88ae59406fd0d5537adf8acb656339ef0 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 15 Nov 2021 10:05:26 -0600 Subject: [PATCH 145/505] workflows: Enable workflow on pull requests Signed-off-by: Rob Herring --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da5845ea..268f61b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,5 @@ -on: push +on: [push, pull_request] jobs: build: From 965704cef73b27a78ee29b332611b9503bb62b70 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 1 Dec 2021 12:47:41 -0600 Subject: [PATCH 146/505] dtschema: Drop pre draft 2019-09 allOf $ref fixup Now that draft 2019-09 is used, there's no need to put $ref under an allOf to keep other vocabulary from being ignored as earlier drafts required. Signed-off-by: Rob Herring --- dtschema/lib.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 3cc5e428..0839a621 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -181,6 +181,8 @@ def is_int_array_schema(propname, subschema): continue if '$ref' in item: return re.match('.*uint(8|16|32)-array', item['$ref']) + elif '$ref' in subschema: + return re.match('.*uint(8|16|32)-array', subschema['$ref']) elif re.match('.*-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours|microvolt|picofarads|celsius|millicelsius|kpascal)$', propname): return True @@ -327,11 +329,6 @@ def fixup_vals(propname, schema): schema.pop('description', None) - # This can be removed once draft 2019.09 is supported - if '$ref' in schema and (len(schema) > 1): - schema['allOf'] = [ {'$ref': schema['$ref']} ] - schema.pop('$ref') - _fixup_int_array_min_max_to_matrix(propname, schema) _fixup_int_array_items_to_matrix(propname, schema) _fixup_string_to_array(propname, schema) From b9cce4d6ba978c62c8f72f7efa23572c575c2635 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 1 Dec 2021 18:59:11 -0600 Subject: [PATCH 147/505] Revert "dtschema: Drop pre draft 2019-09 allOf $ref fixup" This reverts commit 965704cef73b27a78ee29b332611b9503bb62b70. Dropping this exposed error in a schema file which was masked because its 'allOf' entry was overwritten by the fixup. Signed-off-by: Rob Herring --- dtschema/lib.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 0839a621..3cc5e428 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -181,8 +181,6 @@ def is_int_array_schema(propname, subschema): continue if '$ref' in item: return re.match('.*uint(8|16|32)-array', item['$ref']) - elif '$ref' in subschema: - return re.match('.*uint(8|16|32)-array', subschema['$ref']) elif re.match('.*-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours|microvolt|picofarads|celsius|millicelsius|kpascal)$', propname): return True @@ -329,6 +327,11 @@ def fixup_vals(propname, schema): schema.pop('description', None) + # This can be removed once draft 2019.09 is supported + if '$ref' in schema and (len(schema) > 1): + schema['allOf'] = [ {'$ref': schema['$ref']} ] + schema.pop('$ref') + _fixup_int_array_min_max_to_matrix(propname, schema) _fixup_int_array_items_to_matrix(propname, schema) _fixup_string_to_array(propname, schema) From c9c2bc82934730d9c1ff41150a729d1ec8c036e1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 13 Jul 2021 10:41:29 -0600 Subject: [PATCH 148/505] meta-schemas: Allow vendor properties to reference a local definition Allow for a vendor property to just reference a local definition. Signed-off-by: Rob Herring --- meta-schemas/vendor-props.yaml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/meta-schemas/vendor-props.yaml b/meta-schemas/vendor-props.yaml index 374aa9b8..c8767fae 100644 --- a/meta-schemas/vendor-props.yaml +++ b/meta-schemas/vendor-props.yaml @@ -25,8 +25,6 @@ patternProperties: additionalProperties: type: object - required: - - description description: Vendor specific properties must have a type and description unless they have a defined, common suffix. oneOf: @@ -38,6 +36,7 @@ additionalProperties: deprecated: true required: - type + - description additionalProperties: false - description: A vendor string property with exact values has an implicit @@ -50,6 +49,8 @@ additionalProperties: const: type: string deprecated: true + required: + - description oneOf: - required: [ enum ] - required: [ const ] @@ -66,8 +67,15 @@ additionalProperties: pattern: "types.yaml#\/definitions\/" required: - $ref + required: + - description oneOf: - required: [ $ref ] - required: [ allOf ] + - description: A vendor property can have a $ref to a a $defs schema + properties: # A property with a type and additional constraints + $ref: + pattern: "^#\/(definitions|$defs)\/" + required: [ $ref ] ... From 388748b0b5a32314d56afb35dabeccd2bde108f5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 20 Dec 2021 12:49:57 -0600 Subject: [PATCH 149/505] meta-schemas: Add 'rcar_sound' as an excluded vendor prefix 'rcar_sound' was used as node name prefix for a binding and can't be changed, so add it to the excluded list of vendor prefixes. Signed-off-by: Rob Herring --- meta-schemas/vendor-props.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/meta-schemas/vendor-props.yaml b/meta-schemas/vendor-props.yaml index c8767fae..40ac7f5d 100644 --- a/meta-schemas/vendor-props.yaml +++ b/meta-schemas/vendor-props.yaml @@ -14,6 +14,7 @@ patternProperties: '^linux,.*$': true '-(gpio|gpios)$': true '-supply$': true + '^rcar_sound,': true '-(bits|-kBps|percent|mhz|hz|sec|ms|us|ns|ps|mm)$': true '-(microamp|microamp-hours|ohms|micro-ohms|microwatt-hours)$': true '-(microvolt|(femto|pico)farads|celsius|millicelsius|kpascal)$': true From db782c83725eefc712229bb0e76d737165ef3879 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 20 Dec 2021 09:46:52 -0600 Subject: [PATCH 150/505] meta-schemas: Allow $ref at top level Now with draft 2019-09 support, $ref can be allowed at the top level schema without being under an 'allOf'. Signed-off-by: Rob Herring --- meta-schemas/base.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta-schemas/base.yaml b/meta-schemas/base.yaml index 643898f7..f0d9e0a9 100644 --- a/meta-schemas/base.yaml +++ b/meta-schemas/base.yaml @@ -51,7 +51,7 @@ propertyNames: enum: [ $id, $schema, title, description, examples, required, allOf, anyOf, oneOf, definitions, $defs, additionalProperties, dependencies, dependentRequired, dependentSchemas, patternProperties, properties, if, then, else, - unevaluatedProperties, deprecated, maintainers, select ] + unevaluatedProperties, deprecated, maintainers, select, $ref ] required: - $id From 773dbf3313310dc3b210e08f1c92ec0ac878af9a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 20 Dec 2021 09:50:02 -0600 Subject: [PATCH 151/505] schemas: i2c: Add a child node schema Add a child node definition for i2c controllers/buses. This will allow 'unevaluatedProperties' to work correctly for schemas referencing this one. Signed-off-by: Rob Herring --- schemas/i2c/i2c-controller.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/schemas/i2c/i2c-controller.yaml b/schemas/i2c/i2c-controller.yaml index e1696b9b..945eb739 100644 --- a/schemas/i2c/i2c-controller.yaml +++ b/schemas/i2c/i2c-controller.yaml @@ -28,4 +28,8 @@ properties: minimum: 1000 maximum: 3000000 +patternProperties: + '@[0-9a-f]+$': + type: object + additionalProperties: true From a017dec67a9a6a92e48e9089672cffefa4f7a4d7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 20 Dec 2021 09:51:40 -0600 Subject: [PATCH 152/505] schemas: pci: Add 'reg' property A PCI bus node always has a 'reg' property, so add it to the schema. Signed-off-by: Rob Herring --- schemas/pci/pci-bus.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/schemas/pci/pci-bus.yaml b/schemas/pci/pci-bus.yaml index da29dbdd..7892228e 100644 --- a/schemas/pci/pci-bus.yaml +++ b/schemas/pci/pci-bus.yaml @@ -49,6 +49,8 @@ properties: - 0xc2000000 - 0xc3000000 + reg: true + dma-ranges: oneOf: - type: boolean @@ -154,6 +156,7 @@ patternProperties: required: - device_type - ranges + - reg - "#address-cells" - "#size-cells" From 7a0ff641363d6bfc02a943ef032b7ca315dba3d4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 21 Dec 2021 19:36:11 -0400 Subject: [PATCH 153/505] schemas: Allow node/properties starting with [0-9] There's a couple of vendor prefixes that start with a number which we need to support. Signed-off-by: Rob Herring --- schemas/dt-core.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemas/dt-core.yaml b/schemas/dt-core.yaml index 1aff4c33..0e2dd7d3 100644 --- a/schemas/dt-core.yaml +++ b/schemas/dt-core.yaml @@ -52,7 +52,7 @@ patternProperties: $ref: "types.yaml#/definitions/phandle" # property and node namespace overlaps. Catch both here - "^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}$": + "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]{0,63}$": type: [object, array, boolean, 'null'] # Anything with a '@' is definitely a node From a31c7ac5d1d9103b9f917ed288dc6af9bd938fae Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Dec 2021 09:06:18 -0400 Subject: [PATCH 154/505] dtschema: Avoid 2 error messages on process_schema() errors For YAML parsing or schema checks, a 2nd error message is printed. The only case needing a message is a schema without a 'select', so add a more specific error message for that case and remove the duplicate message. Signed-off-by: Rob Herring --- dtschema/lib.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 3cc5e428..dd4d9f6c 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -602,6 +602,7 @@ def process_schema(filename): return if not 'select' in schema: + print(filename + ": warning: no 'select' found in schema found", file=sys.stderr) return schema["type"] = "object" @@ -616,13 +617,12 @@ def process_schemas(schema_paths, core_schema=True): if not os.path.isfile(filename): continue sch = process_schema(os.path.abspath(filename)) - if sch: - schemas.append(sch) - if ids.count(sch['$id']): - print(os.path.abspath(filename) + ": duplicate '$id' value '" + sch['$id'] + "'", file=sys.stderr) - ids.append(sch['$id']) - else: - print("warning: no schema found in file: %s" % filename, file=sys.stderr) + if not sch: + continue + schemas.append(sch) + if ids.count(sch['$id']): + print(os.path.abspath(filename) + ": duplicate '$id' value '" + sch['$id'] + "'", file=sys.stderr) + ids.append(sch['$id']) if core_schema: schema_paths.append(os.path.join(schema_basedir, 'schemas/')) From d572e188e835130a0eae2fef56a9779082c8de6a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Dec 2021 11:44:12 -0400 Subject: [PATCH 155/505] Handle more YAML parsing exceptions Duplicate keys specifically are not handled and result in a splat. Rework the exception handling in the various places YAML schema files are parsed. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- tools/dt-doc-validate | 3 +++ tools/dt-extract-example | 6 +++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index dd4d9f6c..a2819b0e 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -589,7 +589,7 @@ def make_compatible_schema(schemas): def process_schema(filename): try: schema = load_schema(filename) - except ruamel.yaml.error.YAMLError as exc: + except: print(filename + ": ignoring, error parsing file", file=sys.stderr) return diff --git a/tools/dt-doc-validate b/tools/dt-doc-validate index 3b4d52e4..93f13d08 100755 --- a/tools/dt-doc-validate +++ b/tools/dt-doc-validate @@ -29,6 +29,9 @@ def check_doc(filename): except ruamel.yaml.YAMLError as exc: print(filename + ":", exc.path[-1], exc.message, file=sys.stderr) return 1 + except ruamel.yaml.constructor.DuplicateKeyError as exc: + print(filename + ":", exc.problem, file=sys.stderr) + return 1 for error in sorted(dtschema.DTValidator.iter_schema_errors(testtree), key=lambda e: e.linecol): print(dtschema.format_error(filename, error, verbose=args.verbose), file=sys.stderr) diff --git a/tools/dt-extract-example b/tools/dt-extract-example index b7fb9887..046e8755 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -42,7 +42,11 @@ if __name__ == "__main__": help="Filename of YAML encoded schema input file") args = ap.parse_args() - binding = yaml.load(open(args.yamlfile, encoding='utf-8').read()) + try: + binding = yaml.load(open(args.yamlfile, encoding='utf-8').read()) + except ruamel.yaml.constructor.DuplicateKeyError as exc: + print(args.yamlfile + ":", exc.problem, file=sys.stderr) + exit(1) print(example_header) From ce55bbb6645059efd7d6675749535ba19aa3af4d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Dec 2021 15:58:21 -0400 Subject: [PATCH 156/505] dtschema: Also apply array fixups on signed and 64-bit arrays For some reason, we weren't fixing up signed or 64-bit array types. Add these types to the matching regex. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index a2819b0e..9eb5b8a5 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -180,7 +180,7 @@ def is_int_array_schema(propname, subschema): subschema = item continue if '$ref' in item: - return re.match('.*uint(8|16|32)-array', item['$ref']) + return re.match('.*int(8|16|32|64)-array', item['$ref']) elif re.match('.*-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours|microvolt|picofarads|celsius|millicelsius|kpascal)$', propname): return True From f9253fe8404c0c852e78ca9b9383588a2901b3c0 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Thu, 23 Dec 2021 10:48:12 +0000 Subject: [PATCH 157/505] schemas: core: Add 'label' property Support a 'label' property on all device nodes. This property is useful to be able to identify an individual device when multiple individual ones are present in the system. Signed-off-by: Paul Cercueil --- schemas/dt-core.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/schemas/dt-core.yaml b/schemas/dt-core.yaml index 0e2dd7d3..6e553eb4 100644 --- a/schemas/dt-core.yaml +++ b/schemas/dt-core.yaml @@ -21,6 +21,8 @@ properties: $ref: "types.yaml#/definitions/string-array" items: pattern: "^[a-zA-Z][a-zA-Z0-9,+\\-._]+$" + label: + $ref: "types.yaml#/definitions/string" dma-coherent: $ref: "types.yaml#/definitions/flag" dma-ranges: From 5b4bcef8f81d1a455915033589acb803f4b382fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Thu, 6 Jan 2022 17:01:12 +0100 Subject: [PATCH 158/505] Add '-milliwatt' and '-microwatt' property unit suffixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marek Behún --- schemas/property-units.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/schemas/property-units.yaml b/schemas/property-units.yaml index c1d53182..bea43651 100644 --- a/schemas/property-units.yaml +++ b/schemas/property-units.yaml @@ -76,6 +76,12 @@ patternProperties: "-micro-ohms$": $ref: "types.yaml#/definitions/uint32-array" description: microohm + "-microwatt$": + $ref: "types.yaml#/definitions/uint32-array" + description: microwatt + "-milliwatt$": + $ref: "types.yaml#/definitions/uint32-array" + description: milliwatt "-microwatt-hours$": $ref: "types.yaml#/definitions/uint32-array" description: microwatt hour From 7b2d7c521ba55903846cbba00518e1c4038699b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 5 Jan 2022 17:56:46 +0100 Subject: [PATCH 159/505] schemas: pci-bus: Add 'slot-power-limit-milliwatt' property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 'slot-power-limit-milliwatt' property that specifies slot power limit, which is a form-factor and board specific value and must be initialized by hardware. Some PCIe controllers delegate this work to software to allow hardware flexibility and therefore this property basically specifies what should host bridge program into PCIe Slot Capabilities registers. The property needs to be specified in milliwatts unit instead of the special format defined by Slot Capabilities register (which encodes scaling factor or different unit). Host drivers should convert the value from milliwatts to the needed format. Signed-off-by: Pali Rohár Signed-off-by: Marek Behún --- schemas/pci/pci-bus.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/schemas/pci/pci-bus.yaml b/schemas/pci/pci-bus.yaml index 7892228e..421c6099 100644 --- a/schemas/pci/pci-bus.yaml +++ b/schemas/pci/pci-bus.yaml @@ -122,6 +122,12 @@ properties: description: GPIO controlled connection to PERST# signal maxItems: 1 + slot-power-limit-milliwatt: + description: + If present, specifies slot power limit in milliwatts. + This property is invalid in host bridge nodes. + maxItems: 1 + supports-clkreq: type: boolean From 5d169594ab5ac94cd27cc4ef64be89c5b952beec Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 6 Jan 2022 10:01:01 -0600 Subject: [PATCH 160/505] Don't overwrite 'status' and 'phandle' properties 'status' and 'phandle' properties are never checked because we are always overwriting them unconditionally. Fix this. Signed-off-by: Rob Herring --- dtschema/lib.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 9eb5b8a5..9ee76fe7 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -398,8 +398,10 @@ def fixup_node_props(schema): return schema.setdefault('properties', dict()) - schema['properties']['phandle'] = True - schema['properties']['status'] = True + if not 'phandle' in schema['properties']: + schema['properties']['phandle'] = True + if not 'status' in schema['properties']: + schema['properties']['status'] = True if not '$nodename' in schema['properties']: schema['properties']['$nodename'] = True From 36b19209fc3df19785fac2776a027d8f92508cd2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 6 Jan 2022 10:03:02 -0600 Subject: [PATCH 161/505] schemas: Add 'phandle' property schema A 'phandle' schema with a type will be needed for decoding .dtb data. Signed-off-by: Rob Herring --- schemas/dt-core.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/schemas/dt-core.yaml b/schemas/dt-core.yaml index 6e553eb4..e0f94b3d 100644 --- a/schemas/dt-core.yaml +++ b/schemas/dt-core.yaml @@ -38,6 +38,9 @@ properties: status: $ref: "types.yaml#/definitions/string" enum: [ okay, disabled, reserved ] + phandle: + $ref: "types.yaml#/definitions/uint32" + patternProperties: "^#.*-cells$": $ref: "types.yaml#/definitions/uint32" From 3c35bfee83c2e38e2ae7af5f83eb89ca94a521e8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 7 Jan 2022 16:25:53 -0600 Subject: [PATCH 162/505] Move schema and meta-schema files under dtschema directory The symlinks to the schemas and meta-schemas are kind of a pain. Just more the files and be done with it. Signed-off-by: Rob Herring --- dtschema/.gitignore | 2 -- dtschema/meta-schemas | 1 - {meta-schemas => dtschema/meta-schemas}/base.yaml | 0 {meta-schemas => dtschema/meta-schemas}/boolean.yaml | 0 {meta-schemas => dtschema/meta-schemas}/cell.yaml | 0 {meta-schemas => dtschema/meta-schemas}/clocks.yaml | 0 {meta-schemas => dtschema/meta-schemas}/core.yaml | 0 {meta-schemas => dtschema/meta-schemas}/dma.yaml | 0 {meta-schemas => dtschema/meta-schemas}/gpios.yaml | 0 {meta-schemas => dtschema/meta-schemas}/hwlock.yaml | 0 {meta-schemas => dtschema/meta-schemas}/iio.yaml | 0 {meta-schemas => dtschema/meta-schemas}/interrupts.yaml | 0 {meta-schemas => dtschema/meta-schemas}/iommu.yaml | 0 {meta-schemas => dtschema/meta-schemas}/items.yaml | 0 {meta-schemas => dtschema/meta-schemas}/keywords.yaml | 0 {meta-schemas => dtschema/meta-schemas}/mailbox.yaml | 0 {meta-schemas => dtschema/meta-schemas}/nodes.yaml | 0 {meta-schemas => dtschema/meta-schemas}/nvmem.yaml | 0 {meta-schemas => dtschema/meta-schemas}/phy.yaml | 0 {meta-schemas => dtschema/meta-schemas}/power-domain.yaml | 0 {meta-schemas => dtschema/meta-schemas}/pwm.yaml | 0 {meta-schemas => dtschema/meta-schemas}/reset.yaml | 0 {meta-schemas => dtschema/meta-schemas}/string-array.yaml | 0 {meta-schemas => dtschema/meta-schemas}/vendor-props.yaml | 0 dtschema/schemas | 1 - {schemas => dtschema/schemas}/aliases.yaml | 0 {schemas => dtschema/schemas}/cache-controller.yaml | 0 {schemas => dtschema/schemas}/chosen.yaml | 0 {schemas => dtschema/schemas}/clock/clock.yaml | 0 {schemas => dtschema/schemas}/cpus.yaml | 0 {schemas => dtschema/schemas}/dma/dma.yaml | 0 {schemas => dtschema/schemas}/dt-core.yaml | 0 {schemas => dtschema/schemas}/gpio/gpio-consumer.yaml | 0 {schemas => dtschema/schemas}/gpio/gpio-hog.yaml | 0 {schemas => dtschema/schemas}/gpio/gpio.yaml | 0 {schemas => dtschema/schemas}/graph.yaml | 0 {schemas => dtschema/schemas}/hwlock/hwlock-consumer.yaml | 0 {schemas => dtschema/schemas}/i2c/i2c-controller.yaml | 0 {schemas => dtschema/schemas}/iio/iio-consumer.yaml | 0 {schemas => dtschema/schemas}/iio/iio.yaml | 0 {schemas => dtschema/schemas}/interrupt-controller.yaml | 0 {schemas => dtschema/schemas}/interrupts.yaml | 0 {schemas => dtschema/schemas}/iommu/iommu.yaml | 0 {schemas => dtschema/schemas}/mbox/mbox-consumer.yaml | 0 {schemas => dtschema/schemas}/memory.yaml | 0 {schemas => dtschema/schemas}/options.yaml | 0 {schemas => dtschema/schemas}/options/u-boot.yaml | 0 {schemas => dtschema/schemas}/pci/pci-bus.yaml | 0 {schemas => dtschema/schemas}/phy/phy-consumer.yaml | 0 {schemas => dtschema/schemas}/phy/phy-provider.yaml | 0 {schemas => dtschema/schemas}/pinctrl/pinctrl-consumer.yaml | 0 .../schemas}/power-domain/power-domain-consumer.yaml | 0 {schemas => dtschema/schemas}/property-units.yaml | 0 {schemas => dtschema/schemas}/pwm/pwm-consumer.yaml | 0 {schemas => dtschema/schemas}/reg.yaml | 0 {schemas => dtschema/schemas}/reset/reset.yaml | 0 {schemas => dtschema/schemas}/root-node.yaml | 0 {schemas => dtschema/schemas}/serial.yaml | 0 {schemas => dtschema/schemas}/simple-bus.yaml | 0 {schemas => dtschema/schemas}/types.yaml | 0 60 files changed, 4 deletions(-) delete mode 120000 dtschema/meta-schemas rename {meta-schemas => dtschema/meta-schemas}/base.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/boolean.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/cell.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/clocks.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/core.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/dma.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/gpios.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/hwlock.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/iio.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/interrupts.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/iommu.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/items.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/keywords.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/mailbox.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/nodes.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/nvmem.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/phy.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/power-domain.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/pwm.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/reset.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/string-array.yaml (100%) rename {meta-schemas => dtschema/meta-schemas}/vendor-props.yaml (100%) delete mode 120000 dtschema/schemas rename {schemas => dtschema/schemas}/aliases.yaml (100%) rename {schemas => dtschema/schemas}/cache-controller.yaml (100%) rename {schemas => dtschema/schemas}/chosen.yaml (100%) rename {schemas => dtschema/schemas}/clock/clock.yaml (100%) rename {schemas => dtschema/schemas}/cpus.yaml (100%) rename {schemas => dtschema/schemas}/dma/dma.yaml (100%) rename {schemas => dtschema/schemas}/dt-core.yaml (100%) rename {schemas => dtschema/schemas}/gpio/gpio-consumer.yaml (100%) rename {schemas => dtschema/schemas}/gpio/gpio-hog.yaml (100%) rename {schemas => dtschema/schemas}/gpio/gpio.yaml (100%) rename {schemas => dtschema/schemas}/graph.yaml (100%) rename {schemas => dtschema/schemas}/hwlock/hwlock-consumer.yaml (100%) rename {schemas => dtschema/schemas}/i2c/i2c-controller.yaml (100%) rename {schemas => dtschema/schemas}/iio/iio-consumer.yaml (100%) rename {schemas => dtschema/schemas}/iio/iio.yaml (100%) rename {schemas => dtschema/schemas}/interrupt-controller.yaml (100%) rename {schemas => dtschema/schemas}/interrupts.yaml (100%) rename {schemas => dtschema/schemas}/iommu/iommu.yaml (100%) rename {schemas => dtschema/schemas}/mbox/mbox-consumer.yaml (100%) rename {schemas => dtschema/schemas}/memory.yaml (100%) rename {schemas => dtschema/schemas}/options.yaml (100%) rename {schemas => dtschema/schemas}/options/u-boot.yaml (100%) rename {schemas => dtschema/schemas}/pci/pci-bus.yaml (100%) rename {schemas => dtschema/schemas}/phy/phy-consumer.yaml (100%) rename {schemas => dtschema/schemas}/phy/phy-provider.yaml (100%) rename {schemas => dtschema/schemas}/pinctrl/pinctrl-consumer.yaml (100%) rename {schemas => dtschema/schemas}/power-domain/power-domain-consumer.yaml (100%) rename {schemas => dtschema/schemas}/property-units.yaml (100%) rename {schemas => dtschema/schemas}/pwm/pwm-consumer.yaml (100%) rename {schemas => dtschema/schemas}/reg.yaml (100%) rename {schemas => dtschema/schemas}/reset/reset.yaml (100%) rename {schemas => dtschema/schemas}/root-node.yaml (100%) rename {schemas => dtschema/schemas}/serial.yaml (100%) rename {schemas => dtschema/schemas}/simple-bus.yaml (100%) rename {schemas => dtschema/schemas}/types.yaml (100%) diff --git a/dtschema/.gitignore b/dtschema/.gitignore index d550c9f7..98527864 100644 --- a/dtschema/.gitignore +++ b/dtschema/.gitignore @@ -1,3 +1 @@ version.py -schemas -meta-schemas diff --git a/dtschema/meta-schemas b/dtschema/meta-schemas deleted file mode 120000 index 5d6d902f..00000000 --- a/dtschema/meta-schemas +++ /dev/null @@ -1 +0,0 @@ -../meta-schemas \ No newline at end of file diff --git a/meta-schemas/base.yaml b/dtschema/meta-schemas/base.yaml similarity index 100% rename from meta-schemas/base.yaml rename to dtschema/meta-schemas/base.yaml diff --git a/meta-schemas/boolean.yaml b/dtschema/meta-schemas/boolean.yaml similarity index 100% rename from meta-schemas/boolean.yaml rename to dtschema/meta-schemas/boolean.yaml diff --git a/meta-schemas/cell.yaml b/dtschema/meta-schemas/cell.yaml similarity index 100% rename from meta-schemas/cell.yaml rename to dtschema/meta-schemas/cell.yaml diff --git a/meta-schemas/clocks.yaml b/dtschema/meta-schemas/clocks.yaml similarity index 100% rename from meta-schemas/clocks.yaml rename to dtschema/meta-schemas/clocks.yaml diff --git a/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml similarity index 100% rename from meta-schemas/core.yaml rename to dtschema/meta-schemas/core.yaml diff --git a/meta-schemas/dma.yaml b/dtschema/meta-schemas/dma.yaml similarity index 100% rename from meta-schemas/dma.yaml rename to dtschema/meta-schemas/dma.yaml diff --git a/meta-schemas/gpios.yaml b/dtschema/meta-schemas/gpios.yaml similarity index 100% rename from meta-schemas/gpios.yaml rename to dtschema/meta-schemas/gpios.yaml diff --git a/meta-schemas/hwlock.yaml b/dtschema/meta-schemas/hwlock.yaml similarity index 100% rename from meta-schemas/hwlock.yaml rename to dtschema/meta-schemas/hwlock.yaml diff --git a/meta-schemas/iio.yaml b/dtschema/meta-schemas/iio.yaml similarity index 100% rename from meta-schemas/iio.yaml rename to dtschema/meta-schemas/iio.yaml diff --git a/meta-schemas/interrupts.yaml b/dtschema/meta-schemas/interrupts.yaml similarity index 100% rename from meta-schemas/interrupts.yaml rename to dtschema/meta-schemas/interrupts.yaml diff --git a/meta-schemas/iommu.yaml b/dtschema/meta-schemas/iommu.yaml similarity index 100% rename from meta-schemas/iommu.yaml rename to dtschema/meta-schemas/iommu.yaml diff --git a/meta-schemas/items.yaml b/dtschema/meta-schemas/items.yaml similarity index 100% rename from meta-schemas/items.yaml rename to dtschema/meta-schemas/items.yaml diff --git a/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml similarity index 100% rename from meta-schemas/keywords.yaml rename to dtschema/meta-schemas/keywords.yaml diff --git a/meta-schemas/mailbox.yaml b/dtschema/meta-schemas/mailbox.yaml similarity index 100% rename from meta-schemas/mailbox.yaml rename to dtschema/meta-schemas/mailbox.yaml diff --git a/meta-schemas/nodes.yaml b/dtschema/meta-schemas/nodes.yaml similarity index 100% rename from meta-schemas/nodes.yaml rename to dtschema/meta-schemas/nodes.yaml diff --git a/meta-schemas/nvmem.yaml b/dtschema/meta-schemas/nvmem.yaml similarity index 100% rename from meta-schemas/nvmem.yaml rename to dtschema/meta-schemas/nvmem.yaml diff --git a/meta-schemas/phy.yaml b/dtschema/meta-schemas/phy.yaml similarity index 100% rename from meta-schemas/phy.yaml rename to dtschema/meta-schemas/phy.yaml diff --git a/meta-schemas/power-domain.yaml b/dtschema/meta-schemas/power-domain.yaml similarity index 100% rename from meta-schemas/power-domain.yaml rename to dtschema/meta-schemas/power-domain.yaml diff --git a/meta-schemas/pwm.yaml b/dtschema/meta-schemas/pwm.yaml similarity index 100% rename from meta-schemas/pwm.yaml rename to dtschema/meta-schemas/pwm.yaml diff --git a/meta-schemas/reset.yaml b/dtschema/meta-schemas/reset.yaml similarity index 100% rename from meta-schemas/reset.yaml rename to dtschema/meta-schemas/reset.yaml diff --git a/meta-schemas/string-array.yaml b/dtschema/meta-schemas/string-array.yaml similarity index 100% rename from meta-schemas/string-array.yaml rename to dtschema/meta-schemas/string-array.yaml diff --git a/meta-schemas/vendor-props.yaml b/dtschema/meta-schemas/vendor-props.yaml similarity index 100% rename from meta-schemas/vendor-props.yaml rename to dtschema/meta-schemas/vendor-props.yaml diff --git a/dtschema/schemas b/dtschema/schemas deleted file mode 120000 index 0f972371..00000000 --- a/dtschema/schemas +++ /dev/null @@ -1 +0,0 @@ -../schemas \ No newline at end of file diff --git a/schemas/aliases.yaml b/dtschema/schemas/aliases.yaml similarity index 100% rename from schemas/aliases.yaml rename to dtschema/schemas/aliases.yaml diff --git a/schemas/cache-controller.yaml b/dtschema/schemas/cache-controller.yaml similarity index 100% rename from schemas/cache-controller.yaml rename to dtschema/schemas/cache-controller.yaml diff --git a/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml similarity index 100% rename from schemas/chosen.yaml rename to dtschema/schemas/chosen.yaml diff --git a/schemas/clock/clock.yaml b/dtschema/schemas/clock/clock.yaml similarity index 100% rename from schemas/clock/clock.yaml rename to dtschema/schemas/clock/clock.yaml diff --git a/schemas/cpus.yaml b/dtschema/schemas/cpus.yaml similarity index 100% rename from schemas/cpus.yaml rename to dtschema/schemas/cpus.yaml diff --git a/schemas/dma/dma.yaml b/dtschema/schemas/dma/dma.yaml similarity index 100% rename from schemas/dma/dma.yaml rename to dtschema/schemas/dma/dma.yaml diff --git a/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml similarity index 100% rename from schemas/dt-core.yaml rename to dtschema/schemas/dt-core.yaml diff --git a/schemas/gpio/gpio-consumer.yaml b/dtschema/schemas/gpio/gpio-consumer.yaml similarity index 100% rename from schemas/gpio/gpio-consumer.yaml rename to dtschema/schemas/gpio/gpio-consumer.yaml diff --git a/schemas/gpio/gpio-hog.yaml b/dtschema/schemas/gpio/gpio-hog.yaml similarity index 100% rename from schemas/gpio/gpio-hog.yaml rename to dtschema/schemas/gpio/gpio-hog.yaml diff --git a/schemas/gpio/gpio.yaml b/dtschema/schemas/gpio/gpio.yaml similarity index 100% rename from schemas/gpio/gpio.yaml rename to dtschema/schemas/gpio/gpio.yaml diff --git a/schemas/graph.yaml b/dtschema/schemas/graph.yaml similarity index 100% rename from schemas/graph.yaml rename to dtschema/schemas/graph.yaml diff --git a/schemas/hwlock/hwlock-consumer.yaml b/dtschema/schemas/hwlock/hwlock-consumer.yaml similarity index 100% rename from schemas/hwlock/hwlock-consumer.yaml rename to dtschema/schemas/hwlock/hwlock-consumer.yaml diff --git a/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml similarity index 100% rename from schemas/i2c/i2c-controller.yaml rename to dtschema/schemas/i2c/i2c-controller.yaml diff --git a/schemas/iio/iio-consumer.yaml b/dtschema/schemas/iio/iio-consumer.yaml similarity index 100% rename from schemas/iio/iio-consumer.yaml rename to dtschema/schemas/iio/iio-consumer.yaml diff --git a/schemas/iio/iio.yaml b/dtschema/schemas/iio/iio.yaml similarity index 100% rename from schemas/iio/iio.yaml rename to dtschema/schemas/iio/iio.yaml diff --git a/schemas/interrupt-controller.yaml b/dtschema/schemas/interrupt-controller.yaml similarity index 100% rename from schemas/interrupt-controller.yaml rename to dtschema/schemas/interrupt-controller.yaml diff --git a/schemas/interrupts.yaml b/dtschema/schemas/interrupts.yaml similarity index 100% rename from schemas/interrupts.yaml rename to dtschema/schemas/interrupts.yaml diff --git a/schemas/iommu/iommu.yaml b/dtschema/schemas/iommu/iommu.yaml similarity index 100% rename from schemas/iommu/iommu.yaml rename to dtschema/schemas/iommu/iommu.yaml diff --git a/schemas/mbox/mbox-consumer.yaml b/dtschema/schemas/mbox/mbox-consumer.yaml similarity index 100% rename from schemas/mbox/mbox-consumer.yaml rename to dtschema/schemas/mbox/mbox-consumer.yaml diff --git a/schemas/memory.yaml b/dtschema/schemas/memory.yaml similarity index 100% rename from schemas/memory.yaml rename to dtschema/schemas/memory.yaml diff --git a/schemas/options.yaml b/dtschema/schemas/options.yaml similarity index 100% rename from schemas/options.yaml rename to dtschema/schemas/options.yaml diff --git a/schemas/options/u-boot.yaml b/dtschema/schemas/options/u-boot.yaml similarity index 100% rename from schemas/options/u-boot.yaml rename to dtschema/schemas/options/u-boot.yaml diff --git a/schemas/pci/pci-bus.yaml b/dtschema/schemas/pci/pci-bus.yaml similarity index 100% rename from schemas/pci/pci-bus.yaml rename to dtschema/schemas/pci/pci-bus.yaml diff --git a/schemas/phy/phy-consumer.yaml b/dtschema/schemas/phy/phy-consumer.yaml similarity index 100% rename from schemas/phy/phy-consumer.yaml rename to dtschema/schemas/phy/phy-consumer.yaml diff --git a/schemas/phy/phy-provider.yaml b/dtschema/schemas/phy/phy-provider.yaml similarity index 100% rename from schemas/phy/phy-provider.yaml rename to dtschema/schemas/phy/phy-provider.yaml diff --git a/schemas/pinctrl/pinctrl-consumer.yaml b/dtschema/schemas/pinctrl/pinctrl-consumer.yaml similarity index 100% rename from schemas/pinctrl/pinctrl-consumer.yaml rename to dtschema/schemas/pinctrl/pinctrl-consumer.yaml diff --git a/schemas/power-domain/power-domain-consumer.yaml b/dtschema/schemas/power-domain/power-domain-consumer.yaml similarity index 100% rename from schemas/power-domain/power-domain-consumer.yaml rename to dtschema/schemas/power-domain/power-domain-consumer.yaml diff --git a/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml similarity index 100% rename from schemas/property-units.yaml rename to dtschema/schemas/property-units.yaml diff --git a/schemas/pwm/pwm-consumer.yaml b/dtschema/schemas/pwm/pwm-consumer.yaml similarity index 100% rename from schemas/pwm/pwm-consumer.yaml rename to dtschema/schemas/pwm/pwm-consumer.yaml diff --git a/schemas/reg.yaml b/dtschema/schemas/reg.yaml similarity index 100% rename from schemas/reg.yaml rename to dtschema/schemas/reg.yaml diff --git a/schemas/reset/reset.yaml b/dtschema/schemas/reset/reset.yaml similarity index 100% rename from schemas/reset/reset.yaml rename to dtschema/schemas/reset/reset.yaml diff --git a/schemas/root-node.yaml b/dtschema/schemas/root-node.yaml similarity index 100% rename from schemas/root-node.yaml rename to dtschema/schemas/root-node.yaml diff --git a/schemas/serial.yaml b/dtschema/schemas/serial.yaml similarity index 100% rename from schemas/serial.yaml rename to dtschema/schemas/serial.yaml diff --git a/schemas/simple-bus.yaml b/dtschema/schemas/simple-bus.yaml similarity index 100% rename from schemas/simple-bus.yaml rename to dtschema/schemas/simple-bus.yaml diff --git a/schemas/types.yaml b/dtschema/schemas/types.yaml similarity index 100% rename from schemas/types.yaml rename to dtschema/schemas/types.yaml From 8447fe31d66407f92bc7bf367824b99204fb3b12 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 7 Jan 2022 16:52:09 -0600 Subject: [PATCH 163/505] test: Update schema and meta-schema paths After the move, the tests were still looking for the schemas and meta-schemas in the old path (and passing!). Update the path and use absolute path. Signed-off-by: Rob Herring --- test/test-dt-validate.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index 73736bcf..5b52dd59 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -16,6 +16,8 @@ import jsonschema import dtschema +dtschema_dir = os.path.dirname(dtschema.__file__) + class TestDTMetaSchema(unittest.TestCase): def setUp(self): self.schema = dtschema.load(os.path.join(basedir, 'schemas/good-example.yaml')) @@ -27,7 +29,7 @@ def test_metaschema_valid(self): def test_all_metaschema_valid(self): '''The metaschema must all be a valid Draft7 schema''' - for filename in glob.iglob('meta-schemas/**/*.yaml', recursive=True): + for filename in glob.iglob(os.path.join(dtschema_dir, 'meta-schemas/**/*.yaml'), recursive=True): with self.subTest(schema=filename): schema = dtschema.load_schema(filename) jsonschema.Draft7Validator.check_schema(schema) @@ -68,27 +70,27 @@ def test_bad_properties(self): class TestDTSchema(unittest.TestCase): def test_binding_schemas_valid(self): - '''Test that all schema files under ./schemas/ validate against the DT metaschema''' - for filename in glob.iglob('schemas/**/*.yaml', recursive=True): + '''Test that all schema files under ./dtschema/schemas/ validate against the DT metaschema''' + for filename in glob.iglob(os.path.join(dtschema_dir, 'schemas/**/*.yaml'), recursive=True): with self.subTest(schema=filename): schema = dtschema.load_schema(filename) dtschema.DTValidator.check_schema(schema) def test_binding_schemas_id_is_unique(self): - '''Test that all schema files under ./schemas/ validate against the DT metaschema''' + '''Test that all schema files under ./dtschema/schemas/ validate against the DT metaschema''' ids = [] - for filename in glob.iglob('schemas/**/*.yaml', recursive=True): + for filename in glob.iglob(os.path.join(dtschema_dir, 'schemas/**/*.yaml'), recursive=True): with self.subTest(schema=filename): schema = dtschema.load_schema(filename) self.assertEqual(ids.count(schema['$id']), 0) ids.append(schema['$id']) def test_binding_schemas_valid_draft7(self): - '''Test that all schema files under ./schemas/ validate against the Draft7 metaschema + '''Test that all schema files under ./dtschema/schemas/ validate against the Draft7 metaschema The DT Metaschema is supposed to force all schemas to be valid against Draft7. This test makes absolutely sure that they are. ''' - for filename in glob.iglob('schemas/**/*.yaml', recursive=True): + for filename in glob.iglob(os.path.join(dtschema_dir, 'schemas/**/*.yaml'), recursive=True): with self.subTest(schema=filename): schema = dtschema.load_schema(filename) jsonschema.Draft7Validator.check_schema(schema) From 977f2e5d3de6ac71d28889652adf6c0fd3058b0c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 10 Jan 2022 09:21:07 -0600 Subject: [PATCH 164/505] meta-schemas: Fix check for json-schema vocabulary used as a DT property name The existing check for json-schema vocabulary used as a DT property name fails to recurse into sub schema such as: allOf: - if: properties: ... Move this check to keywords.yaml which is a more logical place for it, always gets applied (some schemas only use base.yaml), and recurses the schemas fully. We can also remove the duplicated list of allowed json-schema vocabulary. Signed-off-by: Rob Herring --- dtschema/meta-schemas/core.yaml | 9 --------- dtschema/meta-schemas/keywords.yaml | 11 +++++++++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index 4d4d6dcb..62601581 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -43,15 +43,6 @@ definitions: $ref: "cell.yaml#/array" memory-region-names: $ref: "string-array.yaml" - propertyNames: - description: A json-schema keyword was found instead of a DT property name. - not: - enum: [ $ref, additionalItems, additionalProperties, allOf, anyOf, - const, contains, default, dependencies, dependentRequired, dependentSchemas, - deprecated, description, else, enum, if, items, maxItems, maximum, minItems, - minimum, multipleOf, not, oneOf, pattern, patternProperties, properties, - propertyNames, required, then, unevaluatedProperties ] - patternProperties: '.*-names$': $ref: "string-array.yaml" diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 4cb8e0dc..909096e8 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -125,8 +125,15 @@ properties: additionalProperties: $ref: "#/definitions/sub-schemas" properties: - propertyNames: - pattern: "^[#$a-zA-Z][a-zA-Z0-9,+\\-._@]{0,63}$" + if: + # Filter out overlapping json-schema and DT property names + not: + propertyNames: + const: type + then: + not: + $ref: "#/definitions/sub-schemas" + description: A json-schema keyword was found instead of a DT property name. additionalProperties: $ref: "#/definitions/sub-schemas" required: From 6e57434652fe1fc23d1325841f444d24c9aa3e5b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 10 Jan 2022 09:33:58 -0600 Subject: [PATCH 165/505] meta-schemas: Add back DT property name check The prior commit changed checking for a valid DT property name pattern to checking for not json-schema keywords. In fact, both checks are needed as the valid DT property name check will catch regex patterns. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 909096e8..6d6fdfd0 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -134,6 +134,9 @@ properties: not: $ref: "#/definitions/sub-schemas" description: A json-schema keyword was found instead of a DT property name. + propertyNames: + description: Expected a valid DT property name + pattern: "^[#$a-zA-Z][a-zA-Z0-9,+\\-._@]{0,63}$" additionalProperties: $ref: "#/definitions/sub-schemas" required: From b878eedb48dbabd59134fb0578dd120338026c7b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 13 Jan 2022 15:13:33 -0600 Subject: [PATCH 166/505] schemas: Add interconnects consumer schema 'interconnects' is missing a schema, so let's add it. The producer side is just '#interconnect-cells', so adding it wouldn't add much validation and can wait for all the documentation to be converted. Signed-off-by: Rob Herring --- dtschema/schemas/interconnects.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 dtschema/schemas/interconnects.yaml diff --git a/dtschema/schemas/interconnects.yaml b/dtschema/schemas/interconnects.yaml new file mode 100644 index 00000000..64a95570 --- /dev/null +++ b/dtschema/schemas/interconnects.yaml @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2021 Arm Ltd. +$id: "http://devicetree.org/schemas/interconnects.yaml#" +$schema: "http://devicetree.org/meta-schemas/base.yaml#" + +title: Interconnects consumer schema + +maintainers: + - Rob Herring + +# always select the core schema +select: true + +properties: + interconnects: + $ref: "types.yaml#/definitions/phandle-array" + +dependencies: + interconnect-names: [interconnects] + +additionalProperties: true From cdcaf86a4f19a3a46b6c6afa34b08bd1f2752a11 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 13 Jan 2022 15:14:26 -0600 Subject: [PATCH 167/505] schemas: Add a type ref for 'interrupt-map' property While 'interrupt-map' contains phandles, 'phandle-array' doesn't work as that assumes phandle+args style properties. Let's just use uint32-matrix for now so we have at least some type. Signed-off-by: Rob Herring --- dtschema/schemas/interrupt-controller.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/interrupt-controller.yaml b/dtschema/schemas/interrupt-controller.yaml index 8f59a402..48381085 100644 --- a/dtschema/schemas/interrupt-controller.yaml +++ b/dtschema/schemas/interrupt-controller.yaml @@ -21,7 +21,7 @@ properties: $ref: "types.yaml#/definitions/flag" interrupt-map: - true # FIXME + $ref: "/schemas/types.yaml#/definitions/uint32-matrix" interrupt-map-mask: $ref: "types.yaml#/definitions/uint32-array" From 73077277d1e3c7d38d2435c8701d2e31f8d8d8a2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 12 Jan 2022 18:40:53 -0600 Subject: [PATCH 168/505] dtschema: walk if/then schemas under properties for fixups A 'then' schema within a property schema are missing getting fixups. This is not a common pattern, but possible. Signed-off-by: Rob Herring --- dtschema/lib.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index 9ee76fe7..fd56ac7c 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -352,6 +352,9 @@ def walk_properties(propname, schema): for l in schema[cond]: walk_properties(propname, l) + if 'then' in schema.keys(): + walk_properties(propname, schema['then']) + fixup_vals(propname, schema) def fixup_schema(schema): From ddfe0f14d5dd93f5426cd62a5171e608255b85e1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 24 Jan 2022 11:43:20 -0600 Subject: [PATCH 169/505] dtschema: Load urllib.request on demand urllib.request is fairly slow to import, so let's only do it on demand. Signed-off-by: Rob Herring --- dtschema/lib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index fd56ac7c..45f0ab01 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -12,7 +12,6 @@ import json from ruamel.yaml.comments import CommentedMap -from urllib.request import urlopen import jsonschema import pkgutil @@ -678,6 +677,8 @@ def http_handler(uri): return load_schema(uri.replace(schema_base_url, '')) return process_schema(uri.replace(schema_base_url, '')) + from urllib.request import urlopen + return yaml.load(urlopen(uri).read().decode('utf-8')) except FileNotFoundError as e: print('Unknown file referenced:', e, file=sys.stderr) From b803c4339290ea599e6a35a09d74af486e3dc9b6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 26 Jan 2022 17:54:24 -0600 Subject: [PATCH 170/505] dtschema: Don't overwrite existing 'interrupts-extended' properties Any existing 'interrupts-extended' property including the core definition was getting overwritten. Fix this. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 45f0ab01..5898b9cc 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -538,7 +538,7 @@ def fixup_interrupts(schema): not 'interrupt-parent' in schema['properties']: schema['properties']['interrupt-parent'] = True - if not 'interrupts' in schema['properties']: + if not 'interrupts' in schema['properties'] or 'interrupts-extended' in schema['properties']: return schema['properties']['interrupts-extended'] = copy.deepcopy(schema['properties']['interrupts']); From 54d1f026426a8d470717edef2bca570de435aff5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 27 Jan 2022 14:55:18 -0600 Subject: [PATCH 171/505] dtschema: compile regex in advance is_int_array_schema() is called frequently so compile the regex's it uses in advance. Signed-off-by: Rob Herring --- dtschema/lib.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 5898b9cc..be7372cc 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -171,6 +171,9 @@ def _is_matrix_schema(subschema): return False +int_array_re = re.compile('int(8|16|32|64)-array') +unit_types_re = re.compile('-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours|microvolt|picofarads|celsius|millicelsius|kpascal)$') + def is_int_array_schema(propname, subschema): if 'allOf' in subschema: # Find 'items'. It may be under the 'allOf' or at the same level @@ -179,8 +182,8 @@ def is_int_array_schema(propname, subschema): subschema = item continue if '$ref' in item: - return re.match('.*int(8|16|32|64)-array', item['$ref']) - elif re.match('.*-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours|microvolt|picofarads|celsius|millicelsius|kpascal)$', propname): + return int_array_re.search(item['$ref']) + elif unit_types_re.search(propname): return True return 'items' in subschema and \ From 12c1f2c797d3db68a4281b14173855cda8055f18 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 27 Jan 2022 15:14:10 -0600 Subject: [PATCH 172/505] dtschema: Handle cases of '$ref' not under an 'allOf' Before removing this pre draft2019-09 fixup, make sure we handle '$ref' when not under an 'allOf'. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index be7372cc..5de16466 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -183,6 +183,8 @@ def is_int_array_schema(propname, subschema): continue if '$ref' in item: return int_array_re.search(item['$ref']) + if '$ref' in subschema: + return int_array_re.search(subschema['$ref']) elif unit_types_re.search(propname): return True From 5e2076e6317c43a39845bd7bac593ff49c44d8c9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 1 Dec 2021 12:47:41 -0600 Subject: [PATCH 173/505] dtschema: Drop pre draft2019-09 allOf $ref fixup Now that draft2019-09 is used, there's no need to put $ref under an allOf to keep other vocabulary from being ignored as earlier drafts required. Signed-off-by: Rob Herring --- dtschema/lib.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 5de16466..b2c20d89 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -331,11 +331,6 @@ def fixup_vals(propname, schema): schema.pop('description', None) - # This can be removed once draft 2019.09 is supported - if '$ref' in schema and (len(schema) > 1): - schema['allOf'] = [ {'$ref': schema['$ref']} ] - schema.pop('$ref') - _fixup_int_array_min_max_to_matrix(propname, schema) _fixup_int_array_items_to_matrix(propname, schema) _fixup_string_to_array(propname, schema) From 01409e10ab4f726b8fa4bade414607d7021ceef3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 27 Jan 2022 16:29:48 -0600 Subject: [PATCH 174/505] dtschema: use dict.setdefault() to avoid overwriting existing keys Use dict.setdefault() method to avoid overwriting existing keys rather than checking first ourself. Signed-off-by: Rob Herring --- dtschema/lib.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index b2c20d89..41d3ad01 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -400,13 +400,9 @@ def fixup_node_props(schema): return schema.setdefault('properties', dict()) - if not 'phandle' in schema['properties']: - schema['properties']['phandle'] = True - if not 'status' in schema['properties']: - schema['properties']['status'] = True - - if not '$nodename' in schema['properties']: - schema['properties']['$nodename'] = True + schema['properties'].setdefault('phandle', True) + schema['properties'].setdefault('status', True) + schema['properties'].setdefault('$nodename', True) keys = list() if 'properties' in schema: From f6f5ff6eb9d47c8b555a7714117cd97006afcf8e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 27 Jan 2022 16:30:29 -0600 Subject: [PATCH 175/505] dtschema: Fix a bunch of flake8 lint errors Signed-off-by: Rob Herring --- dtschema/lib.py | 152 +++++++++++++++++++++++++++++++----------------- 1 file changed, 99 insertions(+), 53 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 41d3ad01..020f1ae0 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -11,10 +11,7 @@ import copy import json -from ruamel.yaml.comments import CommentedMap - import jsonschema -import pkgutil schema_base_url = "http://devicetree.org/" schema_basedir = os.path.dirname(os.path.abspath(__file__)) @@ -23,6 +20,7 @@ # peformance impact. re._MAXCACHE = 2048 + class tagged_list(list): tags = {u'!u8': 8, u'!u16': 16, u'!u32': 32, u'!u64': 64} @@ -35,6 +33,7 @@ def __init__(self, int_list, tag, tags=tags): def constructor(loader, node): return tagged_list(loader.construct_sequence(node), node.tag) + class phandle_int(int): def __new__(cls, value): @@ -44,9 +43,10 @@ def __new__(cls, value): def constructor(loader, node): return phandle_int(loader.construct_yaml_int(node)) + rtyaml = ruamel.yaml.YAML(typ='rt') rtyaml.allow_duplicate_keys = False -rtyaml.preserve_quotes=True +rtyaml.preserve_quotes = True rtyaml.Constructor.add_constructor(u'!u8', tagged_list.constructor) rtyaml.Constructor.add_constructor(u'!u16', tagged_list.constructor) rtyaml.Constructor.add_constructor(u'!u32', tagged_list.constructor) @@ -61,11 +61,13 @@ def constructor(loader, node): yaml.Constructor.add_constructor(u'!u64', tagged_list.constructor) yaml.Constructor.add_constructor(u'!phandle', phandle_int.constructor) + def path_to_obj(tree, path): for pc in path: tree = tree[pc] return tree + def get_line_col(tree, path, obj=None): if isinstance(obj, ruamel.yaml.comments.CommentedBase): return obj.lc.line, obj.lc.col @@ -81,12 +83,15 @@ def get_line_col(tree, path, obj=None): return obj.lc.key(path[-1]) return -1, -1 + schema_user_paths = [] + def add_schema_path(path): if os.path.isdir(path): schema_user_paths.append(os.path.abspath(path)) + def check_id_path(filename, id): id = id.replace('http://devicetree.org/schemas/', '') id = id.replace('#', '') @@ -100,7 +105,11 @@ def check_id_path(filename, id): base = base.replace(os.path.abspath('schemas/') + '/', '') if not id == base: - print(filename + ": $id: relative path/filename doesn't match actual path or filename\n\texpected: http://devicetree.org/schemas/" + base + '#' , file=sys.stderr) + print(filename + + ": $id: relative path/filename doesn't match actual path or filename\n\texpected: http://devicetree.org/schemas/" + + base + '#', + file=sys.stderr) + def do_load(filename): with open(filename, 'r', encoding='utf-8') as f: @@ -109,6 +118,7 @@ def do_load(filename): return yaml.load(f.read()) + def load_schema(schema): for path in schema_user_paths: if schema.startswith('schemas/'): @@ -123,8 +133,9 @@ def load_schema(schema): return do_load(os.path.join(schema_basedir, schema)) + def _value_is_type(subschema, key, type): - if not key in subschema: + if key not in subschema: return False if isinstance(subschema[key], list): @@ -134,6 +145,7 @@ def _value_is_type(subschema, key, type): return isinstance(val, type) + def _is_int_schema(subschema): for match in ['const', 'enum', 'minimum', 'maximum']: if _value_is_type(subschema, match, int): @@ -141,6 +153,7 @@ def _is_int_schema(subschema): return False + def _is_string_schema(subschema): for match in ['const', 'enum', 'pattern']: if _value_is_type(subschema, match, str): @@ -148,18 +161,21 @@ def _is_string_schema(subschema): return False + def _extract_single_schemas(subschema): - return { k: subschema.pop(k) for k in ('const', 'enum', 'pattern', 'minimum', 'maximum') if k in subschema } + return {k: subschema.pop(k) for k in ('const', 'enum', 'pattern', 'minimum', 'maximum') if k in subschema} + def _fixup_string_to_array(propname, subschema): # nothing to do if we don't have a set of string schema if not _is_string_schema(subschema): return - subschema['items'] = [ _extract_single_schemas(subschema) ] + subschema['items'] = [_extract_single_schemas(subschema)] + def _is_matrix_schema(subschema): - if not 'items' in subschema: + if 'items' not in subschema: return False if isinstance(subschema['items'], list): @@ -171,9 +187,11 @@ def _is_matrix_schema(subschema): return False + int_array_re = re.compile('int(8|16|32|64)-array') unit_types_re = re.compile('-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours|microvolt|picofarads|celsius|millicelsius|kpascal)$') + def is_int_array_schema(propname, subschema): if 'allOf' in subschema: # Find 'items'. It may be under the 'allOf' or at the same level @@ -189,8 +207,9 @@ def is_int_array_schema(propname, subschema): return True return 'items' in subschema and \ - ((isinstance(subschema['items'],list) and _is_int_schema(subschema['items'][0])) or \ - (isinstance(subschema['items'],dict) and _is_int_schema(subschema['items']))) + ((isinstance(subschema['items'], list) and _is_int_schema(subschema['items'][0])) or + (isinstance(subschema['items'], dict) and _is_int_schema(subschema['items']))) + # Fixup an int array that only defines the number of items. # In this case, we allow either form [[ 0, 1, 2]] or [[0], [1], [2]] @@ -205,7 +224,7 @@ def _fixup_int_array_min_max_to_matrix(propname, subschema): subschema = item break - if 'items' in subschema and isinstance(subschema['items'],list): + if 'items' in subschema and isinstance(subschema['items'], list): return if _is_matrix_schema(subschema): @@ -221,8 +240,8 @@ def _fixup_int_array_min_max_to_matrix(propname, subschema): tmpsch['maxItems'] = subschema.pop('maxItems') if tmpsch: - subschema['oneOf'] = [ copy.deepcopy(tmpsch), {'items': [ copy.deepcopy(tmpsch) ]} ] - subschema['oneOf'][0].update({'items': { 'maxItems': 1 }}) + subschema['oneOf'] = [copy.deepcopy(tmpsch), {'items': [copy.deepcopy(tmpsch)]}] + subschema['oneOf'][0].update({'items': {'maxItems': 1}}) # if minItems can be 1, then both oneOf clauses can be true so increment # minItems in one clause to prevent that. @@ -232,8 +251,9 @@ def _fixup_int_array_min_max_to_matrix(propname, subschema): # Since we added an 'oneOf' the tree walking code won't find it and we need to do fixups _fixup_items_size(subschema['oneOf']) + def _fixup_int_array_items_to_matrix(propname, subschema): - itemkeys = ('items','minItems','maxItems', 'uniqueItems', 'default') + itemkeys = ('items', 'minItems', 'maxItems', 'uniqueItems', 'default') if not is_int_array_schema(propname, subschema): return @@ -244,20 +264,22 @@ def _fixup_int_array_items_to_matrix(propname, subschema): subschema = item break - if not 'items' in subschema or _is_matrix_schema(subschema): + if 'items' not in subschema or _is_matrix_schema(subschema): return - if isinstance(subschema['items'],dict): + if isinstance(subschema['items'], dict): subschema['items'] = {k: subschema.pop(k) for k in itemkeys if k in subschema} - if isinstance(subschema['items'],list): - subschema['items'] = [ {k: subschema.pop(k) for k in itemkeys if k in subschema} ] + if isinstance(subschema['items'], list): + subschema['items'] = [{k: subschema.pop(k) for k in itemkeys if k in subschema}] + def _fixup_scalar_to_array(propname, subschema): if not _is_int_schema(subschema): return - subschema['items'] = [ {'items': [ _extract_single_schemas(subschema) ] } ] + subschema['items'] = [{'items': [_extract_single_schemas(subschema)]}] + def _fixup_items_size(schema): # Make items list fixed size-spec @@ -271,21 +293,22 @@ def _fixup_items_size(schema): if isinstance(schema['items'], list): c = len(schema['items']) - if not 'minItems' in schema: + if 'minItems' not in schema: schema['minItems'] = c - if not 'maxItems' in schema: + if 'maxItems' not in schema: schema['maxItems'] = c - if not 'additionalItems' in schema: + if 'additionalItems' not in schema: schema['additionalItems'] = False _fixup_items_size(schema['items']) - elif 'maxItems' in schema and not 'minItems' in schema: + elif 'maxItems' in schema and 'minItems' not in schema: schema['minItems'] = schema['maxItems'] - elif 'minItems' in schema and not 'maxItems' in schema: + elif 'minItems' in schema and 'maxItems' not in schema: schema['maxItems'] = schema['minItems'] + def fixup_schema_to_201909(schema): if not isinstance(schema, dict): return @@ -293,7 +316,7 @@ def fixup_schema_to_201909(schema): # dependencies is now split into dependentRequired and dependentSchema try: val = schema.pop('dependencies') - for k,v in val.items(): + for k, v in val.items(): if isinstance(v, list): schema.setdefault('dependentRequired', {}) schema['dependentRequired'][k] = v @@ -303,6 +326,7 @@ def fixup_schema_to_201909(schema): except: pass + def fixup_schema_to_202012(schema): if not isinstance(schema, dict): return @@ -325,9 +349,10 @@ def fixup_schema_to_202012(schema): except: pass + def fixup_vals(propname, schema): # Now we should be a the schema level to do actual fixups -# print(schema) + #print(schema) schema.pop('description', None) @@ -338,7 +363,7 @@ def fixup_vals(propname, schema): _fixup_items_size(schema) fixup_schema_to_201909(schema) -# print(schema) + def walk_properties(propname, schema): if not isinstance(schema, dict): @@ -356,6 +381,7 @@ def walk_properties(propname, schema): fixup_vals(propname, schema) + def fixup_schema(schema): # Remove parts not necessary for validation schema.pop('examples', None) @@ -365,6 +391,7 @@ def fixup_schema(schema): add_select_schema(schema) fixup_sub_schema(schema, True) + def fixup_sub_schema(schema, is_prop): if not isinstance(schema, dict): return @@ -374,7 +401,7 @@ def fixup_sub_schema(schema, is_prop): if is_prop: fixup_node_props(schema) - for k,v in schema.items(): + for k, v in schema.items(): if k in ['select', 'if', 'then', 'else', 'additionalProperties', 'not']: fixup_sub_schema(v, False) @@ -382,7 +409,7 @@ def fixup_sub_schema(schema, is_prop): for subschema in v: fixup_sub_schema(subschema, True) - if not k in ['dependentRequired', 'dependentSchemas', 'dependencies', 'properties', 'patternProperties', '$defs']: + if k not in ['dependentRequired', 'dependentSchemas', 'dependencies', 'properties', 'patternProperties', '$defs']: continue for prop in v: @@ -392,6 +419,7 @@ def fixup_sub_schema(schema, is_prop): fixup_schema_to_201909(schema) + def fixup_node_props(schema): if not {'properties', 'patternProperties'} & schema.keys(): return @@ -419,11 +447,12 @@ def fixup_node_props(schema): schema.setdefault('patternProperties', dict()) schema['patternProperties']['pinctrl-[0-9]+'] = True - if "clocks" in keys and not "assigned-clocks" in keys: + if "clocks" in keys and "assigned-clocks" not in keys: schema['properties']['assigned-clocks'] = True schema['properties']['assigned-clock-rates'] = True schema['properties']['assigned-clock-parents'] = True + def extract_node_compatibles(schema): if not isinstance(schema, dict): return set() @@ -442,6 +471,7 @@ def extract_node_compatibles(schema): return compatible_list + def extract_compatibles(schema): if not isinstance(schema, dict): return set() @@ -452,6 +482,7 @@ def extract_compatibles(schema): return compatible_list + def item_generator(json_input, lookup_key): if isinstance(json_input, dict): for k, v in json_input.items(): @@ -465,6 +496,7 @@ def item_generator(json_input, lookup_key): for item_val in item_generator(item, lookup_key): yield item_val + # Convert to standard types from ruamel's CommentedMap/Seq def convert_to_dict(schema): if isinstance(schema, dict): @@ -480,6 +512,7 @@ def convert_to_dict(schema): return result + def add_select_schema(schema): '''Get a schema to be used in select tests. @@ -491,7 +524,7 @@ def add_select_schema(schema): if "select" in schema: return - if not 'properties' in schema: + if 'properties' not in schema: schema['select'] = False return @@ -515,29 +548,30 @@ def add_select_schema(schema): return - if '$nodename' in schema['properties'] and schema['properties']['$nodename'] != True: + if '$nodename' in schema['properties'] and schema['properties']['$nodename'] is not True: schema['select'] = { 'required': ['$nodename'], - 'properties': {'$nodename': convert_to_dict(schema['properties']['$nodename']) }} + 'properties': {'$nodename': convert_to_dict(schema['properties']['$nodename'])}} return schema['select'] = False + def fixup_interrupts(schema): # Supporting 'interrupts' implies 'interrupts-extended' is also supported. - if not 'properties' in schema: + if 'properties' not in schema: return # Any node with 'interrupts' can have 'interrupt-parent' if schema['properties'].keys() & {'interrupts', 'interrupt-controller'} and \ - not 'interrupt-parent' in schema['properties']: + 'interrupt-parent' not in schema['properties']: schema['properties']['interrupt-parent'] = True - if not 'interrupts' in schema['properties'] or 'interrupts-extended' in schema['properties']: + if 'interrupts' not in schema['properties'] or 'interrupts-extended' in schema['properties']: return - schema['properties']['interrupts-extended'] = copy.deepcopy(schema['properties']['interrupts']); + schema['properties']['interrupts-extended'] = copy.deepcopy(schema['properties']['interrupts']) if not ('required' in schema and 'interrupts' in schema['required']): return @@ -545,15 +579,16 @@ def fixup_interrupts(schema): # Currently no better way to express either 'interrupts' or 'interrupts-extended' # is required. If this fails validation, the error reporting is the whole # schema file fails validation - reqlist = [ {'required': ['interrupts']}, {'required': ['interrupts-extended']} ] + reqlist = [{'required': ['interrupts']}, {'required': ['interrupts-extended']}] if 'oneOf' in schema: - if not 'allOf' in schema: + if 'allOf' not in schema: schema['allOf'] = [] - schema['allOf'].append({ 'oneOf': reqlist }) + schema['allOf'].append({'oneOf': reqlist}) else: schema['oneOf'] = reqlist schema['required'].remove('interrupts') + def make_compatible_schema(schemas): compat_sch = [{'enum': []}] compatible_list = set() @@ -568,7 +603,7 @@ def make_compatible_schema(schemas): if prog.match(c): # Exclude the generic pattern if c != '^[a-zA-Z][a-zA-Z0-9,+\-._]+$': - compat_sch += [{'pattern': c }] + compat_sch += [{'pattern': c}] else: compat_sch[0]['enum'].append(c) @@ -586,6 +621,7 @@ def make_compatible_schema(schemas): } }] + def process_schema(filename): try: schema = load_schema(filename) @@ -597,11 +633,12 @@ def process_schema(filename): try: DTValidator.check_schema(schema) except jsonschema.SchemaError as exc: - print(filename + ": ignoring, error in schema: " + ': '.join(str(x) for x in exc.path), file=sys.stderr) + print(filename + ": ignoring, error in schema: " + ': '.join(str(x) for x in exc.path), + file=sys.stderr) #print(exc.message) return - if not 'select' in schema: + if 'select' not in schema: print(filename + ": warning: no 'select' found in schema found", file=sys.stderr) return @@ -609,6 +646,7 @@ def process_schema(filename): schema["$filename"] = filename return schema + def process_schemas(schema_paths, core_schema=True): ids = [] schemas = [] @@ -648,6 +686,7 @@ def process_schemas(schema_paths, core_schema=True): return schemas + def load(filename, line_number=False): with open(filename, 'r', encoding='utf-8') as f: if line_number: @@ -655,12 +694,15 @@ def load(filename, line_number=False): else: return yaml.load(f.read()) + schema_cache = [] + def set_schema(schemas): global schema_cache schema_cache = schemas + def http_handler(uri): global schema_cache '''Custom handler for http://devicetre.org YAML references''' @@ -680,25 +722,29 @@ def http_handler(uri): print('Unknown file referenced:', e, file=sys.stderr) exit(-1) + handlers = {"http": http_handler} + def typeSize(validator, typeSize, instance, schema): if (isinstance(instance[0], tagged_list)): if typeSize != instance[0].type_size: yield jsonschema.ValidationError("size is %r, expected %r" % (instance[0].type_size, typeSize)) - elif isinstance(instance[0], list) and isinstance(instance[0][0], int) and \ - typeSize == 32: + elif isinstance(instance[0], list) and isinstance(instance[0][0], int) and typeSize == 32: # 32-bit sizes aren't explicitly tagged return else: yield jsonschema.ValidationError("missing size tag in %r" % instance) + def phandle(validator, phandle, instance, schema): if not isinstance(instance, phandle_int): yield jsonschema.ValidationError("missing phandle tag in %r" % instance) + DTVal = jsonschema.validators.extend(jsonschema.Draft201909Validator, {'typeSize': typeSize, 'phandle': phandle}) + class DTValidator(DTVal): '''Custom Validator for Devicetree Schemas @@ -802,12 +848,11 @@ def check_schema_refs(self, filename, schema): check_id_path(filename, schema['$id']) - @classmethod def _check_str(self, err_msg, schema, key, v): if not (isinstance(v, ruamel.yaml.scalarstring.SingleQuotedScalarString) or - isinstance(v, ruamel.yaml.scalarstring.DoubleQuotedScalarString)): - return + isinstance(v, ruamel.yaml.scalarstring.DoubleQuotedScalarString)): + return # Only checking const and list values if key and key != 'const': @@ -834,7 +879,7 @@ def _check_str(self, err_msg, schema, key, v): @classmethod def check_quotes(self, err_msg, schema): if isinstance(schema, dict): - for k,v in schema.items(): + for k, v in schema.items(): self._check_str(err_msg, schema, k, v) self.check_quotes(err_msg, v) @@ -843,11 +888,12 @@ def check_quotes(self, err_msg, schema): self._check_str(err_msg, schema, None, s) self.check_quotes(err_msg, s) + def format_error(filename, error, prefix="", nodename=None, verbose=False): src = prefix + os.path.abspath(filename) + ':' - if error.linecol[0] >= 0 : - src = src + '%i:%i: '%(error.linecol[0]+1, error.linecol[1]+1) + if error.linecol[0] >= 0: + src = src + '%i:%i: ' % (error.linecol[0]+1, error.linecol[1]+1) else: src += ' ' @@ -869,7 +915,7 @@ def format_error(filename, error, prefix="", nodename=None, verbose=False): for suberror in sorted(error.context, key=lambda e: e.path): if suberror.context: msg += '\n' + format_error(filename, suberror, prefix=prefix+"\t", nodename=nodename, verbose=verbose) - elif not suberror.message in msg: + elif suberror.message not in msg: msg += '\n' + prefix + '\t' + suberror.message if suberror.note and suberror.note != error.note: msg += '\n\t\t' + prefix + 'hint: ' + suberror.note From 09772d98982bf222c0da8ad5de3fa659a7c49dd1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 19 Jan 2022 16:43:59 -0600 Subject: [PATCH 176/505] test: Convert the test inputs to dts format In preparation to support running tests with DTBs, the input needs to be DTS format. Also, as the YAML format is not necessarily stable and is deemed an intermediate format, it's better if we store DTS files. Signed-off-by: Rob Herring --- .github/workflows/ci.yml | 1 + test/child-node-fail.dts | 94 +++++++++++++++ test/child-node-fail.yaml | 72 ----------- test/child-node.dts | 27 +++++ test/child-node.yaml | 21 ---- test/conditionals-allof-fail.dts | 37 ++++++ test/conditionals-allof-fail.yaml | 28 ----- test/conditionals-allof-pass.dts | 25 ++++ test/conditionals-allof-pass.yaml | 18 --- test/conditionals-single-fail.dts | 30 +++++ test/conditionals-single-fail.yaml | 22 ---- test/conditionals-single-pass.dts | 24 ++++ test/conditionals-single-pass.yaml | 17 --- test/device-fail.dts | 184 +++++++++++++++++++++++++++++ test/device-fail.yaml | 152 ------------------------ test/device.dts | 55 +++++++++ test/device.yaml | 46 -------- test/schemas/good-example.yaml | 5 +- test/simple-bus-fail.dts | 20 ++++ test/simple-bus-fail.yaml | 15 --- test/simple-bus-pass.dts | 32 +++++ test/simple-bus-pass.yaml | 24 ---- test/test-dt-validate.py | 20 +++- 23 files changed, 545 insertions(+), 424 deletions(-) create mode 100644 test/child-node-fail.dts delete mode 100644 test/child-node-fail.yaml create mode 100644 test/child-node.dts delete mode 100644 test/child-node.yaml create mode 100644 test/conditionals-allof-fail.dts delete mode 100644 test/conditionals-allof-fail.yaml create mode 100644 test/conditionals-allof-pass.dts delete mode 100644 test/conditionals-allof-pass.yaml create mode 100644 test/conditionals-single-fail.dts delete mode 100644 test/conditionals-single-fail.yaml create mode 100644 test/conditionals-single-pass.dts delete mode 100644 test/conditionals-single-pass.yaml create mode 100644 test/device-fail.dts delete mode 100644 test/device-fail.yaml create mode 100644 test/device.dts delete mode 100644 test/device.yaml create mode 100644 test/simple-bus-fail.dts delete mode 100644 test/simple-bus-fail.yaml create mode 100644 test/simple-bus-pass.dts delete mode 100644 test/simple-bus-pass.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 268f61b1..50aeeb39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,6 +18,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | + sudo apt-get -qq -y install device-tree-compiler python -m pip install --upgrade pip python -m pip install flake8 pip install . diff --git a/test/child-node-fail.dts b/test/child-node-fail.dts new file mode 100644 index 00000000..48230fac --- /dev/null +++ b/test/child-node-fail.dts @@ -0,0 +1,94 @@ +// SPDX-License-Identifier { BSD-2-Clause +// Copyright 2018 Linaro Ltd. +// Copyright 2018-2022 Arm Ltd. +/dts-v1/; +/plugin/; // silence any missing phandle references +/ { + model = "none"; + compatible = "foo"; + + #address-cells = <1>; + #size-cells = <1>; + + bad-child-node-missing-req-prop { + compatible = "vendor,node-with-child-node"; + + child-node-fixed-name { + vendor,optional-property = <1234>; + }; + }; + + bad-child-node-property-value { + compatible = "vendor,node-with-child-node"; + + child-node-fixed-name { + vendor,required-property = "a string"; + }; + }; + + bad-parent-node-property { + compatible = "vendor,node-with-child-node"; + foo = <0 1>; + + child-node-fixed-name { + vendor,required-property = <1234>; + }; + }; + + bad-child-node-reg-size { + compatible = "vendor,node-with-child-node"; + + child-node-fixed-name { + vendor,required-property = <1234>; + }; + + child-node@0 { + compatible = "a-child-compatible"; + reg = <0>, <1>; + vendor,a-child-property = <2>; + }; + }; + + bad-child-node-u32-property { + compatible = "vendor,node-with-child-node"; + + child-node-fixed-name { + vendor,required-property = <1234>; + }; + + child-node@0 { + compatible = "a-child-compatible"; + reg = <0>; + vendor,a-child-property = <1>; + }; + }; + + bad-child-node-u32-property2 { + compatible = "vendor,node-with-child-node"; + + child-node-fixed-name { + vendor,required-property = <1234>; + }; + + child-node@0 { + compatible = "a-child-compatible"; + reg = <0>; + vendor,a-child-property2 = <1>; + }; + }; + + bad-child-node-string-property { + compatible = "vendor,node-with-child-node"; + + child-node-fixed-name { + vendor,required-property = <1234>; + }; + + child-node@0 { + compatible = "a-child-compatible"; + reg = <0>; + vendor,a-child-property = <2>; + vendor,a-child-string-property = "a-string", "bad-string"; + }; + }; +}; diff --git a/test/child-node-fail.yaml b/test/child-node-fail.yaml deleted file mode 100644 index 7809d419..00000000 --- a/test/child-node-fail.yaml +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: BSD-2-Clause -# Copyright 2018 Linaro Ltd. -# Copyright 2018 Arm Ltd. -- model: [ "none" ] - compatible: [ "none" ] - - "#address-cells": [[1]] - "#size-cells": [[1]] - - bad-child-node-missing-req-prop: - compatible: [ "vendor,node-with-child-node" ] - - child-node-fixed-name: - vendor,optional-property: [[1234]] - - bad-child-node-property-value: - compatible: [ "vendor,node-with-child-node" ] - - child-node-fixed-name: - vendor,required-property: [ "a string" ] - - bad-parent-node-property: - compatible: [ "vendor,node-with-child-node" ] - foo: [[0, 1]] - - child-node-fixed-name: - vendor,required-property: [[1234]] - - bad-child-node-reg-size: - compatible: [ "vendor,node-with-child-node" ] - - child-node-fixed-name: - vendor,required-property: [[1234]] - - child-node@0: - compatible: [ "a-child-compatible" ] - reg: [[0], [1]] - vendor,a-child-property: [ !u32 [2]] - - bad-child-node-u32-property: - compatible: [ "vendor,node-with-child-node" ] - - child-node-fixed-name: - vendor,required-property: [[1234]] - - child-node@0: - compatible: [ "a-child-compatible" ] - reg: [[0]] - vendor,a-child-property: [ !u32 [1]] - - bad-child-node-u32-property2: - compatible: [ "vendor,node-with-child-node" ] - - child-node-fixed-name: - vendor,required-property: [[1234]] - - child-node@0: - compatible: [ "a-child-compatible" ] - reg: [[0]] - vendor,a-child-property2: [ !u32 [1]] - - bad-child-node-string-property: - compatible: [ "vendor,node-with-child-node" ] - - child-node-fixed-name: - vendor,required-property: [[1234]] - - child-node@0: - compatible: [ "a-child-compatible" ] - reg: [[0]] - vendor,a-child-property: [ !u32 [2]] - vendor,a-child-string-property: [ "a-string", "bad-string" ] diff --git a/test/child-node.dts b/test/child-node.dts new file mode 100644 index 00000000..6dc41124 --- /dev/null +++ b/test/child-node.dts @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright 2018 Linaro Ltd. +// Copyright 2018-2022 Arm Ltd. +/dts-v1/; +/plugin/; // silence any missing phandle references +/ { + model = "none"; + compatible = "foo"; + + #address-cells = <1>; + #size-cells = <1>; + good-child-node-test { + compatible = "vendor,node-with-child-node"; + + child-node-fixed-name { + vendor,required-property = <1234>; + }; + + child-node@0 { + compatible = "a-child-compatible"; + reg = <0>; + vendor,a-child-property = <2>; + vendor,a-child-property2 = <4>; + vendor,a-child-string-property = "a-string"; + }; + }; +}; diff --git a/test/child-node.yaml b/test/child-node.yaml deleted file mode 100644 index 95869677..00000000 --- a/test/child-node.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# SPDX-License-Identifier: BSD-2-Clause -# Copyright 2018 Linaro Ltd. -# Copyright 2018 Arm Ltd. -- model: [ "none" ] - compatible: [ "none" ] - - "#address-cells": [[1]] - "#size-cells": [[1]] - - good-child-node-test: - compatible: [ "vendor,node-with-child-node" ] - - child-node-fixed-name: - vendor,required-property: [[1234]] - - child-node@0: - compatible: [ "a-child-compatible" ] - reg: [[0]] - vendor,a-child-property: [ !u32 [2]] - vendor,a-child-property2: [ !u32 [4]] - vendor,a-child-string-property: [ "a-string" ] diff --git a/test/conditionals-allof-fail.dts b/test/conditionals-allof-fail.dts new file mode 100644 index 00000000..618a6028 --- /dev/null +++ b/test/conditionals-allof-fail.dts @@ -0,0 +1,37 @@ +// SPDX-License-Identifier { BSD-2-Clause +// Copyright 2019 Maxime Ripard +// Copyright 2022 Arm Ltd. +/dts-v1/; +/plugin/; // silence any missing phandle references +/ { + model = "none"; + compatible = "none"; + + #address-cells = <1>; + #size-cells = <1>; + + bad-child-node-wrong-vendor-property { + compatible = "vendor,conditionals-allof-test-controller"; + + vendor,property = "test"; + }; + + bad-child-node-too-long { + compatible = "vendor,conditionals-allof-test-controller"; + + vendor,property = "test1234", "test12345678"; + }; + + bad-child-node-second-wrong-vendor-property { + compatible = "vendor,second-conditionals-allof-test-controller"; + + vendor,property = "test"; + vendor,other-property; + }; + + bad-child-node-second-missing-other-property { + compatible = "vendor,second-conditionals-allof-test-controller"; + + vendor,property = "test5678"; + }; +}; \ No newline at end of file diff --git a/test/conditionals-allof-fail.yaml b/test/conditionals-allof-fail.yaml deleted file mode 100644 index be142085..00000000 --- a/test/conditionals-allof-fail.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# SPDX-License-Identifier: BSD-2-Clause -# Copyright 2019 Maxime Ripard -- model: [ "none" ] - compatible: [ "none" ] - - "#address-cells": [[1]] - "#size-cells": [[1]] - - bad-child-node-wrong-vendor-property: - compatible: [ "vendor,conditionals-allof-test-controller" ] - - vendor,property: [ "test" ] - - bad-child-node-too-long: - compatible: [ "vendor,conditionals-allof-test-controller" ] - - vendor,property: [ "test1234", "test12345678" ] - - bad-child-node-second-wrong-vendor-property: - compatible: [ "vendor,second-conditionals-allof-test-controller" ] - - vendor,property: [ "test" ] - vendor,other-property: true - - bad-child-node-second-missing-other-property: - compatible: [ "vendor,second-conditionals-allof-test-controller" ] - - vendor,property: [ "test5678" ] diff --git a/test/conditionals-allof-pass.dts b/test/conditionals-allof-pass.dts new file mode 100644 index 00000000..8fb252f9 --- /dev/null +++ b/test/conditionals-allof-pass.dts @@ -0,0 +1,25 @@ +// SPDX-License-Identifier { BSD-2-Clause +// Copyright 2019 Maxime Ripard +// Copyright 2022 Arm Ltd. +/dts-v1/; +/plugin/; // silence any missing phandle references +/ { + model = "none"; + compatible = "none"; + + #address-cells = <1>; + #size-cells = <1>; + + test-controller { + compatible = "vendor,conditionals-allof-test-controller"; + + vendor,property = "test1234"; + }; + + second-test-controller { + compatible = "vendor,second-conditionals-allof-test-controller"; + + vendor,property = "test5678"; + vendor,other-property; + }; +}; diff --git a/test/conditionals-allof-pass.yaml b/test/conditionals-allof-pass.yaml deleted file mode 100644 index 77c0c072..00000000 --- a/test/conditionals-allof-pass.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: BSD-2-Clause -# Copyright 2019 Maxime Ripard -- model: [ "none" ] - compatible: [ "none" ] - - "#address-cells": [[1]] - "#size-cells": [[1]] - - test-controller: - compatible: [ "vendor,conditionals-allof-test-controller" ] - - vendor,property: [ "test1234" ] - - second-test-controller: - compatible: [ "vendor,second-conditionals-allof-test-controller" ] - - vendor,property: [ "test5678" ] - vendor,other-property: true diff --git a/test/conditionals-single-fail.dts b/test/conditionals-single-fail.dts new file mode 100644 index 00000000..2dc8d756 --- /dev/null +++ b/test/conditionals-single-fail.dts @@ -0,0 +1,30 @@ +// SPDX-License-Identifier { BSD-2-Clause +// Copyright 2019 Maxime Ripard +// Copyright 2022 Arm Ltd. +/dts-v1/; +/plugin/; // silence any missing phandle references +/ { + model = "none"; + compatible = "none"; + + #address-cells = <1>; + #size-cells = <1>; + + bad-child-node-wrong-vendor-property { + compatible = "vendor,test-controller"; + + vendor,property = "test"; + }; + + bad-child-node-too-long { + compatible = "vendor,test-controller"; + + vendor,property = "test1234", "test12345678"; + }; + + bad-child-node-second-wrong-vendor-property { + compatible = "vendor,second-test-controller"; + + vendor,property = "test"; + }; +}; diff --git a/test/conditionals-single-fail.yaml b/test/conditionals-single-fail.yaml deleted file mode 100644 index 16c54774..00000000 --- a/test/conditionals-single-fail.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-License-Identifier: BSD-2-Clause -# Copyright 2019 Maxime Ripard -- model: [ "none" ] - compatible: [ "none" ] - - "#address-cells": [[1]] - "#size-cells": [[1]] - - bad-child-node-wrong-vendor-property: - compatible: [ "vendor,test-controller" ] - - vendor,property: [ "test" ] - - bad-child-node-too-long: - compatible: [ "vendor,test-controller" ] - - vendor,property: [ "test1234", "test12345678" ] - - bad-child-node-second-wrong-vendor-property: - compatible: [ "vendor,second-test-controller" ] - - vendor,property: [ "test" ] diff --git a/test/conditionals-single-pass.dts b/test/conditionals-single-pass.dts new file mode 100644 index 00000000..7e17adde --- /dev/null +++ b/test/conditionals-single-pass.dts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier { BSD-2-Clause +// Copyright 2019 Maxime Ripard +// Copyright 2022 Arm Ltd. +/dts-v1/; +/plugin/; // silence any missing phandle references +/ { + model = "none"; + compatible = "none"; + + #address-cells = <1>; + #size-cells = <1>; + + test-controller { + compatible = "vendor,test-controller"; + + vendor,property = "test1234"; + }; + + second-test-controller { + compatible = "vendor,second-test-controller"; + + vendor,property = "test5678"; + }; +}; diff --git a/test/conditionals-single-pass.yaml b/test/conditionals-single-pass.yaml deleted file mode 100644 index fc9f269a..00000000 --- a/test/conditionals-single-pass.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: BSD-2-Clause -# Copyright 2019 Maxime Ripard -- model: [ "none" ] - compatible: [ "none" ] - - "#address-cells": [[1]] - "#size-cells": [[1]] - - test-controller: - compatible: [ "vendor,test-controller" ] - - vendor,property: [ "test1234" ] - - second-test-controller: - compatible: [ "vendor,second-test-controller" ] - - vendor,property: [ "test5678" ] diff --git a/test/device-fail.dts b/test/device-fail.dts new file mode 100644 index 00000000..c886283c --- /dev/null +++ b/test/device-fail.dts @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright 2018 Linaro Ltd. +// Copyright 2018-2022 Arm Ltd. +/dts-v1/; +/plugin/; // silence any missing phandle references +/ { + model = "none"; + compatible = "none"; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-controller@0 { + // bad-num-interrupts-test: + compatible = "vendor,soc1-ip"; + reg = <0 0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <10>, <11>, <12>; + }; + + interrupt-controller@1 { + // bad-interrupt-type-test: + compatible = "vendor,soc1-ip"; + reg = <1 0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = "string"; + }; + + interrupt-controller@2 { + // bad-no-interrupt-cells-test: + compatible = "vendor,soc1-ip"; + reg = <2 0>; + interrupt-controller; + interrupts = <10>; + }; + + interrupt-controller@3 { + // bad-compatible-test: + compatible = "vendor,soc4-ip", "vendor,soc3-ip"; + reg = <3 0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <10>; + }; + + interrupt-controller@4 { + // bad-compatible-order-test: + compatible = "vendor,soc1-ip", "vendor,soc3-ip"; + reg = <4 0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <10>; + }; + + interrupt-controller@5 { + // bad-compatible-missing-test: + compatible = "vendor,soc3-ip"; + reg = <5 0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <10>; + }; + + interrupt-controller@6 { + // bad-compatible-value-test: + compatible = "vendor,undocumented-compatible string", "vendor,soc1-ip"; + reg = <6 0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <10>; + }; + + interrupt-controller@7 { + // bad-clock-freqency-test: + compatible = "vendor,soc1-ip"; + reg = <7 0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <10>; + clock-frequency = <1>; + }; + + interrupt-controller@8 { + // bad-interrupt-names-test1: + compatible = "vendor,soc1-ip"; + reg = <8 0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-names = "a irq"; + interrupts = <10>; + }; + + interrupt-controller@9 { + // bad-interrupt-names-test2: + compatible = "vendor,soc1-ip"; + reg = <9 0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-names = "tx irq", "rx irq", "bad irq"; + interrupts = <10>; + }; + + bad-vendor-bool-prop-test { + compatible = "vendor,soc1-ip"; + vendor,bool-prop = "true"; + }; + + bad-vendor-int-test { + compatible = "vendor,soc1-ip"; + vendor,int-prop = <5>; + }; + + bad-vendor-int-array-test { + compatible = "vendor,soc1-ip"; + vendor,int-array-prop = <5>, <4>; + }; + + bad-vendor-int-array-2-test { + compatible = "vendor,soc1-ip"; + vendor,int-array-prop-2 = <5 4>; + }; + + bad-vendor-int-array-3-test { + compatible = "vendor,soc1-ip"; + vendor,int-array-size-only-prop = <5 6 7 8 9 10>; + }; + + bad-vendor-string-test { + compatible = "vendor,soc1-ip"; + vendor,string-prop = "foobaz"; + }; + + bad-vendor-string-list-test { + compatible = "vendor,soc1-ip"; + vendor,string-list-prop = "foobar"; + }; + + bad-vendor-int8-prop-test { + compatible = "vendor,soc1-ip"; + vendor,int8-prop = /bits/ 16 <1>; + }; + + bad-vendor-int8-array-prop-test { + compatible = "vendor,soc1-ip"; + vendor,int8-array-prop = /bits/ 8 <1>; + }; + + bad-vendor-int16-prop-test { + compatible = "vendor,soc1-ip"; + vendor,int16-prop = <1>; + }; + + bad-vendor-int16-array-prop-test { + compatible = "vendor,soc1-ip"; + vendor,int16-array-prop = /bits/ 16 <1 2 3>; + }; + + bad-vendor-int64-prop-test { + compatible = "vendor,soc1-ip"; + vendor,int64-prop = /bits/ 64 <0x123>; + }; + + bad-vendor-phandle-prop-test { + compatible = "vendor,soc1-ip"; + vendor,phandle-prop = <&foo 0>, <1>; + vendor,phandle-array-prop = <&foo>; + }; + + bad-vendor-phandle-prop-tag-test { + compatible = "vendor,soc1-ip"; + vendor,phandle-prop = <1>; + vendor,phandle-array-prop = <1>, <2>; + }; + + bad-vendor-phandle-args-len-test { + compatible = "vendor,soc1-ip"; + vendor,phandle-with-fixed-cells = <&foo 2>; + }; +}; diff --git a/test/device-fail.yaml b/test/device-fail.yaml deleted file mode 100644 index 203f0920..00000000 --- a/test/device-fail.yaml +++ /dev/null @@ -1,152 +0,0 @@ -# SPDX-License-Identifier: BSD-2-Clause -# Copyright 2018 Linaro Ltd. -# Copyright 2018 Arm Ltd. -- model: [ "none" ] - compatible: [ "none" ] - - "#address-cells": [[1]] - "#size-cells": [[1]] - - interrupt-controller@0: - # bad-num-interrupts-test: - compatible: [ "vendor,soc1-ip" ] - reg: [ [ 0, 0] ] - interrupt-controller: true - '#interrupt-cells': [[2]] - interrupts: [ [10], [11], [12] ] - - interrupt-controller@1: - # bad-interrupt-type-test: - compatible: [ "vendor,soc1-ip" ] - reg: [ [ 1, 0] ] - interrupt-controller: true - '#interrupt-cells': [[2]] - interrupts: [ "string" ] - - interrupt-controller@2: - # bad-no-interrupt-cells-test: - compatible: [ "vendor,soc1-ip" ] - reg: [ [ 2, 0] ] - interrupt-controller: true - interrupts: [ [10] ] - - interrupt-controller@3: - # bad-compatible-test: - compatible: [ "vendor,soc4-ip", "vendor,soc3-ip" ] - reg: [ [ 3, 0] ] - interrupt-controller: true - '#interrupt-cells': [[2]] - interrupts: [ [10] ] - - interrupt-controller@4: - # bad-compatible-order-test: - compatible: [ "vendor,soc1-ip", "vendor,soc3-ip" ] - reg: [ [ 4, 0] ] - interrupt-controller: true - '#interrupt-cells': [[2]] - interrupts: [ [10] ] - - interrupt-controller@5: - # bad-compatible-missing-test: - compatible: [ "vendor,soc3-ip" ] - reg: [ [ 5, 0] ] - interrupt-controller: true - '#interrupt-cells': [[2]] - interrupts: [ [10] ] - - interrupt-controller@6: - # bad-compatible-value-test: - compatible: [ "vendor,undocumented-compatible string", "vendor,soc1-ip" ] - reg: [ [ 6, 0] ] - interrupt-controller: true - '#interrupt-cells': [[2]] - interrupts: [ [10] ] - - interrupt-controller@7: - # bad-clock-freqency-test: - compatible: [ "vendor,soc1-ip" ] - reg: [ [ 7, 0] ] - interrupt-controller: true - '#interrupt-cells': [[2]] - interrupts: [ [10] ] - clock-frequency: [ [1] ] - - interrupt-controller@8: - # bad-interrupt-names-test1: - compatible: [ "vendor,soc1-ip" ] - reg: [ [ 8, 0] ] - interrupt-controller: true - '#interrupt-cells': [[2]] - interrupt-names: [ "a irq" ] - interrupts: [ [10] ] - - interrupt-controller@9: - # bad-interrupt-names-test2: - compatible: [ "vendor,soc1-ip" ] - reg: [ [ 9, 0] ] - interrupt-controller: true - '#interrupt-cells': [[2]] - interrupt-names: [ "tx irq", "rx irq", "bad irq" ] - interrupts: [ [10] ] - - bad-vendor-bool-prop-test: - compatible: [ "vendor,soc1-ip" ] - vendor,bool-prop: [ "true" ] - - bad-vendor-int-test: - compatible: [ "vendor,soc1-ip" ] - vendor,int-prop: [ [5] ] - - bad-vendor-int-array-test: - compatible: [ "vendor,soc1-ip" ] - vendor,int-array-prop: [ [5], [4] ] - - bad-vendor-int-array-2-test: - compatible: [ "vendor,soc1-ip" ] - vendor,int-array-prop-2: [ [5, 4] ] - - bad-vendor-int-array-3-test: - compatible: [ "vendor,soc1-ip" ] - vendor,int-array-size-only-prop: [ [5, 6, 7, 8, 9, 10] ] - - bad-vendor-string-test: - compatible: [ "vendor,soc1-ip" ] - vendor,string-prop: [ "foobaz" ] - - bad-vendor-string-list-test: - compatible: [ "vendor,soc1-ip" ] - vendor,string-list-prop: [ "foobar" ] - - bad-vendor-int8-prop-test: - compatible: [ "vendor,soc1-ip" ] - vendor,int8-prop: [ !u16 [1] ] - - bad-vendor-int8-array-prop-test: - compatible: [ "vendor,soc1-ip" ] - vendor,int8-array-prop: [ !u8 [1] ] - - bad-vendor-int16-prop-test: - compatible: [ "vendor,soc1-ip" ] - vendor,int16-prop: [ [1] ] - - bad-vendor-int16-array-prop-test: - compatible: [ "vendor,soc1-ip" ] - vendor,int16-array-prop: [ !u16 [1, 2, 3] ] - - bad-vendor-int64-prop-test: - compatible: [ "vendor,soc1-ip" ] - vendor,int64-prop: [ !u64 [0x123] ] - - bad-vendor-phandle-prop-test: - compatible: [ "vendor,soc1-ip" ] - vendor,phandle-prop: [[!phandle 1, 0], [1]] - vendor,phandle-array-prop: [[!phandle 1]] - - bad-vendor-phandle-prop-tag-test: - compatible: [ "vendor,soc1-ip" ] - vendor,phandle-prop: [[1]] - vendor,phandle-array-prop: [[1], [2]] - - bad-vendor-phandle-args-len-test: - compatible: [ "vendor,soc1-ip" ] - vendor,phandle-with-fixed-cells: [[!phandle 1, 2]] diff --git a/test/device.dts b/test/device.dts new file mode 100644 index 00000000..47aa31c5 --- /dev/null +++ b/test/device.dts @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright 2018 Linaro Ltd. +// Copyright 2018-2022 Arm Ltd. +/dts-v1/; +/plugin/; // silence any missing phandle references +/ { + model = "none"; + compatible = "foo"; + + #address-cells = <1>; + #size-cells = <1>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-controller@0 { + compatible = "vendor,soc4-ip", "vendor,soc1-ip"; + reg = <0x0 0x4>, <0x8 0x4>; + reg-names = "coreAAA", "aux"; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <10>, <11>; + some-gpios = <&gpio0 0>, <&gpio0 1 0>; + clocks = <&clk0>; + clock-names = "clk1" , "clk2"; + vendor,bool-prop; + vendor,int-prop = <3>; + vendor,int-array-prop = <5 6 7 8>; + vendor,int-array-prop-2 = <5 10>; + vendor,int-array-size-only-prop = <2 3>; + vendor,string-prop = "foo"; + vendor,int8-prop = /bits/ 8 <1>; + vendor,int8-array-prop = /bits/ 8 <1 2>; + vendor,int16-prop = /bits/ 16 <1>; + vendor,int16-array-prop = /bits/ 16 <1 2>; + vendor,int64-prop = /bits/ 64 <0x100000000>; + vendor,phandle-prop = <&a_phandle>; + vendor,phandle-array-prop = <&a_phandle>, <&a_phandle>; + vendor,string-list-prop = "foobar", "foobaz"; + vendor,phandle-with-fixed-cells = <&a_phandle 2 3>; + vendor,int64-array-prop = /bits/ 64 <0x10000000 0x1>; + }; + + interrupt-controller@10 { + compatible = "vendor,soc1-ip"; + interrupt-controller; + reg = <0x10 0x4>, <0x8 0x4>; + #interrupt-cells = <2>; + interrupts = <10>; + interrupt-names = "tx irq"; + vendor,int-array-prop = <5>, <6>, <7>, <8>; + vendor,int-array-size-only-prop = <2>, <3>, <4>; + vendor,int64-array-prop = /bits/ 64 <0x10000000 0x1>; + }; +}; \ No newline at end of file diff --git a/test/device.yaml b/test/device.yaml deleted file mode 100644 index 1ff97c87..00000000 --- a/test/device.yaml +++ /dev/null @@ -1,46 +0,0 @@ -# SPDX-License-Identifier: BSD-2-Clause -# Copyright 2018 Linaro Ltd. -# Copyright 2018 Arm Ltd. -- model: [ "none" ] - compatible: [ "none" ] - - "#address-cells": [[1]] - "#size-cells": [[1]] - - interrupt-controller@0: - compatible: [ "vendor,soc4-ip", "vendor,soc1-ip" ] - reg: [ [0x0, 0x4], [0x8, 0x4] ] - reg-names: [ "coreAAA", "aux"] - interrupt-controller: true - '#interrupt-cells': [[2]] - interrupts: [ [10], [11, 1, 0] ] - some-gpios: [ [ !phandle 0xdead, 0, 0 ], [ !phandle 0xdead, 1, 0 ] ] - clocks: [ [0] ] - clock-names: [ "clk1" , "clk2"] - vendor,bool-prop: - vendor,int-prop: [[3]] - vendor,int-array-prop: [[ 5, 6, 7, 8 ]] - vendor,int-array-prop-2: [[ 5, 10 ]] - vendor,int-array-size-only-prop: [[ 2, 3 ]] - vendor,string-prop: [ "foo" ] - vendor,int8-prop: [ !u8 [1] ] - vendor,int8-array-prop: [ !u8 [1, 2] ] - vendor,int16-prop: [ !u16 [1] ] - vendor,int16-array-prop: [ !u16 [1, 2] ] - vendor,int64-prop: [ !u64 [0x100000000] ] - vendor,phandle-prop: [[!phandle 1]] - vendor,phandle-array-prop: [[!phandle 1], [!phandle 2]] - vendor,string-list-prop: [ foobar, foobaz ] - vendor,phandle-with-fixed-cells: [[!phandle 1, 2, 3]] - vendor,int64-array-prop: [ !u64 [0x10000000, 0x1] ] - - interrupt-controller@10: - compatible: [ "vendor,soc1-ip" ] - interrupt-controller: true - reg: [ [0x10, 0x4], [0x8, 0x4] ] - '#interrupt-cells': [[2]] - interrupts: [ [10] ] - interrupt-names: [ "tx irq" ] - vendor,int-array-prop: [ [5], [6], [7], [8] ] - vendor,int-array-size-only-prop: [ [2], [3], [4] ] - vendor,int64-array-prop: [ [0x10000000, 0x1] ] diff --git a/test/schemas/good-example.yaml b/test/schemas/good-example.yaml index 9a9ccba1..6673d9f5 100644 --- a/test/schemas/good-example.yaml +++ b/test/schemas/good-example.yaml @@ -131,9 +131,8 @@ properties: vendor,int8-array-prop: $ref: /schemas/types.yaml#/definitions/uint8-array - items: - - minItems: 2 - maxItems: 3 + minItems: 2 + maxItems: 3 description: A vendor specific uint8 array property with 2 or 3 entries vendor,int16-prop: diff --git a/test/simple-bus-fail.dts b/test/simple-bus-fail.dts new file mode 100644 index 00000000..007ea18e --- /dev/null +++ b/test/simple-bus-fail.dts @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright 2019-2022 Arm Ltd. +/dts-v1/; +/plugin/; // silence any missing phandle references +/ { + model = "none"; + compatible = "none"; + + #address-cells = <1>; + #size-cells = <1>; + + bus@8000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x8000 0x4000>; + + child@200 {}; + }; +}; diff --git a/test/simple-bus-fail.yaml b/test/simple-bus-fail.yaml deleted file mode 100644 index 0c652acc..00000000 --- a/test/simple-bus-fail.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: BSD-2-Clause -# Copyright 2019 Arm Ltd. -- model: [ "none" ] - compatible: [ "none" ] - - "#address-cells": [[1]] - "#size-cells": [[1]] - - bus@8000: - compatible: [ "simple-bus" ] - "#address-cells": [[1]] - "#size-cells": [[1]] - ranges: [ [ 0, 0x8000, 0x4000 ] ] - - child@200: diff --git a/test/simple-bus-pass.dts b/test/simple-bus-pass.dts new file mode 100644 index 00000000..d44774c5 --- /dev/null +++ b/test/simple-bus-pass.dts @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright 2019-2022 Arm Ltd. +/dts-v1/; +/plugin/; // silence any missing phandle references +/ { + model = "none"; + compatible = "none"; + + #address-cells = <1>; + #size-cells = <1>; + + bus@1000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1000 0x4000>; + + child@0 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0x100>; + + grand-child@0 { + reg = <0 0x100>; + }; + }; + + child@100 { + reg = <0x100 0x100>; + }; + }; +}; diff --git a/test/simple-bus-pass.yaml b/test/simple-bus-pass.yaml deleted file mode 100644 index ae5da63f..00000000 --- a/test/simple-bus-pass.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# SPDX-License-Identifier: BSD-2-Clause -# Copyright 2019 Arm Ltd. -- model: [ "none" ] - compatible: [ "none" ] - - "#address-cells": [[1]] - "#size-cells": [[1]] - - bus@1000: - compatible: [ "simple-bus" ] - "#address-cells": [[1]] - "#size-cells": [[1]] - ranges: [ [ 0, 0x1000, 0x4000 ] ] - - child@0: - "#address-cells": [[1]] - "#size-cells": [[1]] - ranges: [ [ 0, 0, 0x100 ] ] - - grand-child@0: - reg: [ [ 0, 0x100 ] ] - - child@100: - reg: [ [ 0x100, 0x100 ] ] diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index 5b52dd59..a1e70c08 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -12,6 +12,9 @@ import os import glob import sys +import subprocess +import tempfile + basedir = os.path.dirname(__file__) import jsonschema import dtschema @@ -101,12 +104,13 @@ def setUp(self): self.schemas = list() self.schemas = dtschema.process_schemas([ os.path.join(os.path.abspath(basedir), "schemas/")]) + dtschema.set_schema(self.schemas) for schema in self.schemas: schema["$select_validator"] = dtschema.DTValidator(schema['select']) def check_node(self, nodename, node, fail): - if nodename == "/": + if nodename == "/" or nodename.startswith('__'): return node['$nodename'] = [ nodename ] @@ -133,13 +137,17 @@ def check_subtree(self, nodename, subtree, fail): if isinstance(value, dict): self.check_subtree(name, value, fail) - - def test_dt_validation(self): - '''Test that all DT YAML files under ./test/ validate against the DT schema''' - for filename in glob.iglob('test/*.yaml'): + def test_dt_yaml_validation(self): + '''Test that all DT files under ./test/ validate against the DT schema''' + for filename in glob.iglob('test/*.dts'): with self.subTest(schema=filename): expect_fail = "-fail" in filename - testtree = dtschema.load(filename)[0] + tmpfile = tempfile.NamedTemporaryFile() + # The test files have lots of expected warnings, so send stderr to /dev/null + res = subprocess.run(['dtc', '-Oyaml', filename], stdout=tmpfile, stderr=subprocess.PIPE) + self.assertEqual(res.returncode, 0, msg='dtc failed:\n' + res.stderr.decode()) + + testtree = dtschema.load(tmpfile.name)[0] for name,value in testtree.items(): if isinstance(value, dict): self.check_node(name, value, expect_fail) From d2e869328bdfbcbd892c5155c7cecc6c50ba07de Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Jan 2022 11:31:34 -0600 Subject: [PATCH 177/505] dtschema: Rework storing int size and phandle tag information Create a 'sized_int' class which stores both the size in bits and phandle flag. This decouples the size information from the brackets which will help with dtb validation. Signed-off-by: Rob Herring --- dtschema/lib.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 020f1ae0..305abc13 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -26,22 +26,25 @@ class tagged_list(list): tags = {u'!u8': 8, u'!u16': 16, u'!u32': 32, u'!u64': 64} def __init__(self, int_list, tag, tags=tags): + int_list = [sized_int(i, size=tags[tag]) for i in int_list] super().__init__(int_list) - self.type_size = tags[tag] @staticmethod def constructor(loader, node): return tagged_list(loader.construct_sequence(node), node.tag) -class phandle_int(int): - - def __new__(cls, value): +class sized_int(int): + def __new__(cls, value, *args, **kwargs): return int.__new__(cls, value) + def __init__(self, value, size=32, phandle=False): + self.size = size + self.phandle = phandle + @staticmethod def constructor(loader, node): - return phandle_int(loader.construct_yaml_int(node)) + return sized_int(loader.construct_yaml_int(node), phandle=True) rtyaml = ruamel.yaml.YAML(typ='rt') @@ -51,7 +54,7 @@ def constructor(loader, node): rtyaml.Constructor.add_constructor(u'!u16', tagged_list.constructor) rtyaml.Constructor.add_constructor(u'!u32', tagged_list.constructor) rtyaml.Constructor.add_constructor(u'!u64', tagged_list.constructor) -rtyaml.Constructor.add_constructor(u'!phandle', phandle_int.constructor) +rtyaml.Constructor.add_constructor(u'!phandle', sized_int.constructor) yaml = ruamel.yaml.YAML(typ='safe') yaml.allow_duplicate_keys = False @@ -59,7 +62,7 @@ def constructor(loader, node): yaml.Constructor.add_constructor(u'!u16', tagged_list.constructor) yaml.Constructor.add_constructor(u'!u32', tagged_list.constructor) yaml.Constructor.add_constructor(u'!u64', tagged_list.constructor) -yaml.Constructor.add_constructor(u'!phandle', phandle_int.constructor) +yaml.Constructor.add_constructor(u'!phandle', sized_int.constructor) def path_to_obj(tree, path): @@ -727,18 +730,19 @@ def http_handler(uri): def typeSize(validator, typeSize, instance, schema): - if (isinstance(instance[0], tagged_list)): - if typeSize != instance[0].type_size: - yield jsonschema.ValidationError("size is %r, expected %r" % (instance[0].type_size, typeSize)) - elif isinstance(instance[0], list) and isinstance(instance[0][0], int) and typeSize == 32: - # 32-bit sizes aren't explicitly tagged + if not isinstance(instance[0], list): return + if isinstance(instance[0][0], sized_int): + size = instance[0][0].size else: - yield jsonschema.ValidationError("missing size tag in %r" % instance) + size = 32 + + if typeSize != size: + yield jsonschema.ValidationError("size is %r, expected %r" % (size, typeSize)) def phandle(validator, phandle, instance, schema): - if not isinstance(instance, phandle_int): + if not isinstance(instance, sized_int) or not instance.phandle: yield jsonschema.ValidationError("missing phandle tag in %r" % instance) From 5059bf170b7b25bfed825ed4d25bfc09a22dc9a6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Jan 2022 10:15:53 -0600 Subject: [PATCH 178/505] test: child-node-fail: Fix 'reg' entry sizes The bad 'reg' size depends on the brackets to be the wrong number of entries, but since the entry size was wrong with only 1 cell the overall size was correct (1 address cell and 1 size cell). Update the entry to be 2 entries which is too many and will fail tests regardless of source brackets. Signed-off-by: Rob Herring --- test/child-node-fail.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/child-node-fail.dts b/test/child-node-fail.dts index 48230fac..c09013b9 100644 --- a/test/child-node-fail.dts +++ b/test/child-node-fail.dts @@ -44,7 +44,7 @@ child-node@0 { compatible = "a-child-compatible"; - reg = <0>, <1>; + reg = <0 1>, <1 1>; vendor,a-child-property = <2>; }; }; From 114a6f2be34716c422bad7150398327df5f7183f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Feb 2022 20:16:39 -0600 Subject: [PATCH 179/505] dtschema: Remove 'items' lists with empty schemas If 'items' list has empty schema, then 'minItems' and 'maxItems' are sufficient constraints and 'items' is unnecessary bloat. Signed-off-by: Rob Herring --- dtschema/lib.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index 305abc13..f52b4a3d 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -255,6 +255,25 @@ def _fixup_int_array_min_max_to_matrix(propname, subschema): _fixup_items_size(subschema['oneOf']) +def _fixup_remove_empty_items(subschema): + if 'items' not in subschema: + return + elif isinstance(subschema['items'], dict): + _fixup_remove_empty_items(subschema['items']) + return + + for item in subschema['items']: + item.pop('description', None) + _fixup_remove_empty_items(item) + if item != {}: + break + else: + subschema.setdefault('type', 'array') + subschema.setdefault('maxItems', len(subschema['items'])) + subschema.setdefault('minItems', len(subschema['items'])) + del subschema['items'] + + def _fixup_int_array_items_to_matrix(propname, subschema): itemkeys = ('items', 'minItems', 'maxItems', 'uniqueItems', 'default') if not is_int_array_schema(propname, subschema): @@ -359,6 +378,7 @@ def fixup_vals(propname, schema): schema.pop('description', None) + _fixup_remove_empty_items(schema) _fixup_int_array_min_max_to_matrix(propname, schema) _fixup_int_array_items_to_matrix(propname, schema) _fixup_string_to_array(propname, schema) From a52c8202158ba49da7b97ec13f8395ea66583f51 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Feb 2022 20:18:59 -0600 Subject: [PATCH 180/505] dtschema: Drop adding 'additionalItems: false' With 'maxItems' set to the length of 'items', adding 'additionalItems: false' has no effect and can be removed. Signed-off-by: Rob Herring --- dtschema/lib.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index f52b4a3d..ae5a3bc6 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -320,9 +320,6 @@ def _fixup_items_size(schema): if 'maxItems' not in schema: schema['maxItems'] = c - if 'additionalItems' not in schema: - schema['additionalItems'] = False - _fixup_items_size(schema['items']) elif 'maxItems' in schema and 'minItems' not in schema: From 55cf0d576357b2d9ca8ab1d9424bf7c7ece984f4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Feb 2022 14:36:27 -0600 Subject: [PATCH 181/505] schemas: types: Rework signed type value ranges As signed types didn't work with DT YAML format (dtc upstream was against passing sign information thru to YAML), the signed types have used their unsigned range instead. With validation of DTBs, signed values will be correct so the types need the signed range. Since we need to support both sources for some time, make the range the most negative signed value to the unsigned maximum. Signed-off-by: Rob Herring --- dtschema/schemas/types.yaml | 39 ++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/dtschema/schemas/types.yaml b/dtschema/schemas/types.yaml index 3ee31f6c..0a4c22d5 100644 --- a/dtschema/schemas/types.yaml +++ b/dtschema/schemas/types.yaml @@ -66,14 +66,15 @@ definitions: int8-item: type: integer minimum: -128 - maximum: 127 + # maximum: 127 + maximum: 0xff int8-matrix: type: array typeSize: 8 items: type: array items: - $ref: "#/definitions/uint8-item" + $ref: "#/definitions/int8-item" int8-array: type: array typeSize: 8 @@ -82,7 +83,7 @@ definitions: items: type: array items: - $ref: "#/definitions/uint8-item" + $ref: "#/definitions/int8-item" int8: type: array typeSize: 8 @@ -91,7 +92,7 @@ definitions: items: type: array items: - $ref: "#/definitions/uint8-item" + $ref: "#/definitions/int8-item" minItems: 1 maxItems: 1 @@ -130,7 +131,8 @@ definitions: int16-item: type: integer minimum: -8192 - maximum: 8191 + # maximum: 8191 + maximum: 0xffff int16-matrix: type: array typeSize: 16 @@ -205,7 +207,8 @@ definitions: int32-item: type: integer minimum: -2147483648 - maximum: 2147483647 + # maximum: 2147483647 + maximum: 0xffffffff int32-matrix: type: array @@ -213,7 +216,7 @@ definitions: items: type: array items: - $ref: "#/definitions/cell" + $ref: "#/definitions/int32-item" int32-array: # For single cell arrays, we need to support encodings as either: # prop = <0x1234 0x5678>; @@ -226,14 +229,14 @@ definitions: items: type: array items: - $ref: "#/definitions/cell" + $ref: "#/definitions/int32-item" - type: array items: type: array minItems: 1 maxItems: 1 items: - $ref: "#/definitions/cell" + $ref: "#/definitions/int32-item" int32: type: array minItems: 1 @@ -241,10 +244,16 @@ definitions: items: type: array items: - $ref: "#/definitions/cell" + $ref: "#/definitions/int32-item" minItems: 1 maxItems: 1 + int64-item: + type: integer + minimum: -9223372036854775808 + # maximum: 9223372036854775807 + maximum: 0xffffffffffffffff + int64: type: array minItems: 1 @@ -253,8 +262,7 @@ definitions: items: type: array items: - minimum: -9223372036854775808 - maximum: 9223372036854775807 + $ref: "#/definitions/int64-item" minItems: 1 maxItems: 1 int64-array: @@ -265,8 +273,7 @@ definitions: items: type: array items: - minimum: -9223372036854775808 - maximum: 9223372036854775807 + $ref: "#/definitions/int64-item" int64-matrix: type: array minItems: 1 @@ -274,8 +281,7 @@ definitions: items: type: array items: - minimum: -9223372036854775808 - maximum: 9223372036854775807 + $ref: "#/definitions/int64-item" uint64: oneOf: @@ -359,6 +365,7 @@ definitions: - oneOf: - phandle: true type: integer + minimum: 1 maximum: 0xffffffff - type: integer const: 0 From f677c858d5b1392cbe597abeb92dcb10adc82679 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 31 Jan 2022 11:29:34 -0600 Subject: [PATCH 182/505] schemas: mbox: Add 'shmem' property Mailbox consumers often have a chunk of shared-memory associated with the mailbox. The standard property for it is 'shmem'. Add it so it has a type defined. Signed-off-by: Rob Herring --- dtschema/schemas/mbox/mbox-consumer.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dtschema/schemas/mbox/mbox-consumer.yaml b/dtschema/schemas/mbox/mbox-consumer.yaml index 0af817e9..2e47f4d3 100644 --- a/dtschema/schemas/mbox/mbox-consumer.yaml +++ b/dtschema/schemas/mbox/mbox-consumer.yaml @@ -21,6 +21,11 @@ properties: mbox-names: $ref: "/schemas/types.yaml#/definitions/string-array" + shmem: + $ref: "/schemas/types.yaml#/definitions/phandle-array" + items: + maxItems: 1 + dependencies: mbox-names: [ mboxes ] From c3c47458496a0d47d310e8c99d6001098f84bf74 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Mar 2022 16:34:00 -0600 Subject: [PATCH 183/505] test: Improve schema for phandle array property As the phandle-array type is loosely defined, just specifying the number of items is ambiguous. An array of phandles should be in the form: vendor,phandle-array-prop = <&foo>, <&bar>; Update the schema to enforce this form. Signed-off-by: Rob Herring --- test/schemas/good-example.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/schemas/good-example.yaml b/test/schemas/good-example.yaml index 6673d9f5..b8493a97 100644 --- a/test/schemas/good-example.yaml +++ b/test/schemas/good-example.yaml @@ -164,6 +164,8 @@ properties: vendor,phandle-array-prop: $ref: "/schemas/types.yaml#/definitions/phandle-array" minItems: 2 + items: + maxItems: 1 description: Vendor specific array of phandles property vendor,phandle-with-fixed-cells: From a0adfc4b0c6bd4b296c8eb6332adb7f1d58bf11e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Mar 2022 16:18:00 -0600 Subject: [PATCH 184/505] test: Add another failing phandle+args test case Test that we catch properties with the wrong number of phandle arg cells. Signed-off-by: Rob Herring --- test/device-fail.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/device-fail.dts b/test/device-fail.dts index c886283c..e49f84fc 100644 --- a/test/device-fail.dts +++ b/test/device-fail.dts @@ -181,4 +181,9 @@ compatible = "vendor,soc1-ip"; vendor,phandle-with-fixed-cells = <&foo 2>; }; + + bad-vendor-phandle-args-len-test2 { + compatible = "vendor,soc1-ip"; + vendor,phandle-with-fixed-cells = <&foo 2 3>, <&foo 1>; + }; }; From 4d1c58ada7dc7a230e10b93fa29bcbb2163c68b6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Feb 2022 21:25:12 -0600 Subject: [PATCH 185/505] dtschema: Disable phandle tag check The YAML !phandle tags are not going to work with DTB validation. The easiest thing to do is just drop the check for now (and maybe forever). Signed-off-by: Rob Herring --- dtschema/lib.py | 7 +------ test/device-fail.dts | 6 ------ 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index ae5a3bc6..9d51496a 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -758,12 +758,7 @@ def typeSize(validator, typeSize, instance, schema): yield jsonschema.ValidationError("size is %r, expected %r" % (size, typeSize)) -def phandle(validator, phandle, instance, schema): - if not isinstance(instance, sized_int) or not instance.phandle: - yield jsonschema.ValidationError("missing phandle tag in %r" % instance) - - -DTVal = jsonschema.validators.extend(jsonschema.Draft201909Validator, {'typeSize': typeSize, 'phandle': phandle}) +DTVal = jsonschema.validators.extend(jsonschema.Draft201909Validator, {'typeSize': typeSize}) class DTValidator(DTVal): diff --git a/test/device-fail.dts b/test/device-fail.dts index e49f84fc..cde50d72 100644 --- a/test/device-fail.dts +++ b/test/device-fail.dts @@ -171,12 +171,6 @@ vendor,phandle-array-prop = <&foo>; }; - bad-vendor-phandle-prop-tag-test { - compatible = "vendor,soc1-ip"; - vendor,phandle-prop = <1>; - vendor,phandle-array-prop = <1>, <2>; - }; - bad-vendor-phandle-args-len-test { compatible = "vendor,soc1-ip"; vendor,phandle-with-fixed-cells = <&foo 2>; From 3063a564202a33caf02f0734993f9a3a4cd1c3f1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 2 Feb 2022 11:52:08 -0600 Subject: [PATCH 186/505] dt-validate: Add '-l' option to limit schemas for validation In order to do validation on dtb files, a complete set of schemas is always needed to extract type information. That doesn't work when only validating with a subset of schemas. In order to continue to support that use case, add an explicit option, -l or --limit, to dt-validate to provide a specific schema to use for validation. The option can be a substring which is useful for selecting a number of schemas. Signed-off-by: Rob Herring --- tools/dt-validate | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/dt-validate b/tools/dt-validate index ccfff0c4..525dd290 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -21,6 +21,7 @@ import dtschema verbose = False show_unmatched = False +match_schema_file = None class schema_group(): def __init__(self, schema_file=""): @@ -40,7 +41,7 @@ class schema_group(): node_matched = False matched_schemas = [] for schema in self.schemas: - if schema['$select_validator'].is_valid(node): + if '$select_validator' in schema and schema['$select_validator'].is_valid(node): # We have a match if a conditional schema is selected if schema['select'] != True: matched_schemas.append(schema['$id']) @@ -113,6 +114,8 @@ class schema_group(): """Check the given DT against all schemas""" for schema in self.schemas: + if match_schema_file and match_schema_file not in schema['$filename']: + continue schema["$select_validator"] = dtschema.DTValidator(schema['select']) for subtree in dt: @@ -125,6 +128,7 @@ if __name__ == "__main__": help="Filename or directory of YAML encoded devicetree input file(s)") ap.add_argument('-s', '--schema', help="path to additional additional schema files") ap.add_argument('-p', '--preparse', help="preparsed schema file") + ap.add_argument('-l', '--limit', help="limit validation to schema files matching substring") ap.add_argument('-m', '--show-unmatched', default=0, help="Print out nodes which don't match any schema.\n" \ "Once for only nodes with 'compatible'\n" \ @@ -141,6 +145,7 @@ if __name__ == "__main__": verbose = args.verbose show_unmatched = args.show_unmatched show_matched = args.show_matched + match_schema_file = args.limit if args.url_path: dtschema.add_schema_path(args.url_path) From 022f1d319f8f6556761020ea5e5e46eea089a772 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 2 Jun 2021 15:22:32 -0500 Subject: [PATCH 187/505] Add a tool to extract type information of properties from schemas Add a program, dt-extract-props, which can dump out all the type information from a set of schemas. It is primarily intended for debug purposes. Signed-off-by: Rob Herring --- dtschema/__init__.py | 1 + dtschema/lib.py | 145 +++++++++++++++++++++++++++++++++++++++++ setup.py | 3 +- tools/dt-extract-props | 67 +++++++++++++++++++ 4 files changed, 215 insertions(+), 1 deletion(-) create mode 100755 tools/dt-extract-props diff --git a/dtschema/__init__.py b/dtschema/__init__.py index 2126aec3..f9749d0e 100644 --- a/dtschema/__init__.py +++ b/dtschema/__init__.py @@ -7,6 +7,7 @@ DTValidator, format_error, extract_compatibles, + extract_types, ) from dtschema.version import ( diff --git a/dtschema/lib.py b/dtschema/lib.py index 9d51496a..864c1b59 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -707,6 +707,151 @@ def process_schemas(schema_paths, core_schema=True): return schemas +def _get_array_range(subschema): + if isinstance(subschema, list): + if len(subschema) != 1: + return (0, 0) + subschema = subschema[0] + if 'items' in subschema and isinstance(subschema['items'], list): + max = len(subschema['items']) + min = subschema.get('minItems', max) + else: + min = subschema.get('minItems', 1) + max = subschema.get('maxItems', subschema.get('minItems', 0)) + + return (min, max) + + +def _merge_dim(dim1, dim2): + d = [] + for i in range(0, 2): + if dim1[i] == (0, 0): + d.insert(i, dim2[i]) + elif dim2[i] == (0, 0): + d.insert(i, dim1[i]) + else: + d.insert(i, (min(dim1[i] + dim2[i]), max(dim1[i] + dim2[i]))) + + return tuple(d) + + +type_re = re.compile('(flag|u?int(8|16|32|64)(-(array|matrix))?|string(-array)?|phandle(-array)?)') + + +def _extract_prop_type(props, schema, propname, subschema): + if not isinstance(subschema, dict): + return + + if subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: + _extract_subschema_types(props, schema, subschema) + + # We only support local refs + if '$ref' in subschema and subschema['$ref'].startswith('#/'): + sch_path = subschema['$ref'].split('/')[1:] + subschema = schema + for p in sch_path: + subschema = subschema[p] + #print(propname, sch_path, subschema, file=sys.stderr) + _extract_prop_type(props, schema, propname, subschema) + + try: + prop_type = type_re.search(subschema['$ref']).group(0) + except: + if 'type' in subschema and subschema['type'] == 'boolean': + prop_type = 'flag' + elif 'items' in subschema: + items = subschema['items'] + if (isinstance(items, list) and _is_string_schema(items[0])) or \ + (isinstance(items, dict) and _is_string_schema(items)): + # implicit string type + prop_type = 'string-array' + else: + prop_type = None + else: + prop_type = None + + if prop_type: + props.setdefault(propname, {}) + + if prop_type == 'phandle-array' or prop_type.endswith('-matrix'): + dim = (_get_array_range(subschema), _get_array_range(subschema.get('items', {}))) + if dim != ((0, 0), (0, 0)): + if not 'dim' in props[propname]: + props[propname]['dim'] = dim + elif props[propname]['dim'] != dim: + # Conflicting dimensions + props[propname]['dim'] = _merge_dim(props[propname]['dim'], dim) + + if 'type' in props[propname]: + if prop_type in props[propname]['type']: + # Already have the same type + return + for t in props[propname]['type']: + if prop_type in t: + # Already have the looser type + return + if t in prop_type: + # Replace scalar type with array type + i = props[propname]['type'].index(t) + props[propname]['type'][i] = prop_type + props[propname]['$id'][i] = schema['$id'] + return + else: + props[propname]['type'] = [] + props[propname]['$id'] = [] + + props[propname]['type'] += [ prop_type ] + props[propname]['$id'] += [ schema['$id'] ] + return + + for k in subschema.keys() & {'allOf', 'oneOf', 'anyOf'}: + for v in subschema[k]: + _extract_prop_type(props, schema, propname, v) + + +def _extract_subschema_types(props, schema, subschema): + if not isinstance(subschema, dict): + return + + for k in subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: + if isinstance(subschema[k], dict): + for p,v in subschema[k].items(): + _extract_prop_type(props, schema, p, v) + + +def extract_types(schemas): + if not isinstance(schemas, list): + return + + props = {} + for sch in schemas: + _extract_subschema_types(props, sch, sch) + + return props + + +def get_prop_types(): + global schema_cache + pat_props = {} + + props = dtschema.extract_types(schema_cache) + + # hack to remove aliases pattern + del props['^[a-z][a-z0-9\-]*$'] + + # Remove all properties without a type + for key in [key for key in props if 'type' not in props[key] ]: del props[key] + + # Split out pattern properties + for key in [key for key in props if re.fullmatch('(^\^.*|.*\$$|.*[*[].*)', key) ]: + #print(key, props[key]) + pat_props[key] = props[key] + pat_props[key]['regex'] = re.compile(key) + del props[key] + + return [ props, pat_props ] + + def load(filename, line_number=False): with open(filename, 'r', encoding='utf-8') as f: if line_number: diff --git a/setup.py b/setup.py index 7505827a..994d0721 100755 --- a/setup.py +++ b/setup.py @@ -40,7 +40,8 @@ 'tools/dt-validate', 'tools/dt-doc-validate', 'tools/dt-mk-schema', - 'tools/dt-extract-example' + 'tools/dt-extract-example', + 'tools/dt-extract-props' ], python_requires='>=3.5', diff --git a/tools/dt-extract-props b/tools/dt-extract-props new file mode 100755 index 00000000..b7fd42c2 --- /dev/null +++ b/tools/dt-extract-props @@ -0,0 +1,67 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2022 Arm Ltd. + +import signal + +def sigint_handler(signum, frame): + sys.exit(-2) + +signal.signal(signal.SIGINT, sigint_handler) + +import argparse +import os +import sys +import pprint + +import dtschema + +strict = False + +if __name__ == "__main__": + ap = argparse.ArgumentParser() + ap.add_argument("schema_files", type=str, nargs='*', + help="Schema directories and/or files") + ap.add_argument('-d', '--duplicates', help="Only output properties with more than one type", action="store_true") + ap.add_argument('-v', '--verbose', help="Additional search path for references", action="store_true") + ap.add_argument('-V', '--version', help="Print version number", + action="version", version=dtschema.__version__) + args = ap.parse_args() + + if os.path.isfile(args.schema_files[0]): + schemas = dtschema.load_schema(os.path.abspath(args.schema_files[0])) + else: + schemas = dtschema.process_schemas(args.schema_files) + dtschema.set_schema(schemas) + + props = dtschema.extract_types(schemas) + + if args.duplicates: + tmp_props = {} + for k,v in props.items(): + if 'type' in v and len(v['type']) > 1: + tmp_props[k] = v + + props = tmp_props + + if args.verbose: + prop_types = props + else: + prop_types = {} + for k,v in props.items(): + if 'type' in v: + prop_types[k] = v['type'] + else: + prop_types[k] = None + + try: + pprint.pprint(prop_types, compact=True) + # flush output here to force SIGPIPE to be triggered + # while inside this try block. + sys.stdout.flush() + except BrokenPipeError: + # Python flushes standard streams on exit; redirect remaining output + # to devnull to avoid another BrokenPipeError at shutdown + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + sys.exit(1) # Python exits with error code 1 on EPIPE From af8b75533e19bda30cd2b5174a4202ac31596663 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 23 Dec 2021 13:46:45 -0400 Subject: [PATCH 188/505] dt-extract-example: Add a valid interrupt provider In order to support extracting interrupt fields from examples as dtbs, make the parent node the interrupt provider. This depends on 'interrupts' being bracketed. Signed-off-by: Rob Herring --- tools/dt-extract-example | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tools/dt-extract-example b/tools/dt-extract-example index 046e8755..981a9ae4 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: BSD-2-Clause # Copyright 2018 Linaro Ltd. -# Copyright 2019 Arm Ltd. +# Copyright 2019-2022 Arm Ltd. import os import re @@ -9,11 +9,18 @@ import sys import ruamel.yaml import argparse +interrupt_template = """ + interrupt-controller; + #interrupt-cells = < {int_cells} >; +""" + example_template = """ example-{example_num} {{ #address-cells = <1>; #size-cells = <1>; + {interrupt} + {example} }}; }}; @@ -27,7 +34,6 @@ example_start = """ /{ compatible = "foo"; model = "foo"; - interrupt-parent = <&foo>; #address-cells = <1>; #size-cells = <1>; @@ -56,9 +62,20 @@ if __name__ == "__main__": root_node = re.search('^/\s*{', ex) if not root_node: + try: + int_val = re.search('\sinterrupts\s*=\s*<([0-9a-zA-Z |()_]+)>', ex).group(1) + int_val = re.sub(r'\(.+|\)', r'0', int_val) + int_cells = len(int_val.strip().split()) + except: + int_cells = 0 print(example_start) ex = ' '.join(ex.splitlines(True)) - print(example_template.format(example=ex,example_num=idx)) + if int_cells > 0: + int_props = interrupt_template.format(int_cells=int_cells) + else: + int_props = "" + print(example_template.format(example=ex, example_num=idx, + interrupt=int_props)) else: print(ex) else: From 5646cd473017d702844fda382c7b88994e080ee8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 10 Nov 2021 07:16:32 -0600 Subject: [PATCH 189/505] Add support to validate dtbs There's a desire to be able to run DT validation on running systems where there might not be an original source dts file. As the YAML DT format is tied to the DT source level annotations (e.g. /bits/, brackets, etc.), a dtb->dts->yaml or dtb->yaml conversion won't work. Therefore, a different approach is used. pylibfdt is used to unflatten a dtb directly into python data structures. Then type information from the schemas are used to decode the property values into the right types. This approach removes the YAML format from the picture making the format for validation purely an internal format (though the dtb2py program will dump it) and avoids some short comings of the YAML format. This change also improves the validation some. For example, some validation could pass before with incorrect bracketing because the validation is not aware of cell sizes. Signed-off-by: Rob Herring --- dtschema/__init__.py | 2 + dtschema/dtb.py | 480 ++++++++++++++++++++++++++++++ dtschema/lib.py | 46 ++- dtschema/schemas/clock/clock.yaml | 2 +- setup.py | 4 +- tools/dtb2py | 43 +++ 6 files changed, 574 insertions(+), 3 deletions(-) create mode 100644 dtschema/dtb.py create mode 100755 tools/dtb2py diff --git a/dtschema/__init__.py b/dtschema/__init__.py index f9749d0e..f4fc8768 100644 --- a/dtschema/__init__.py +++ b/dtschema/__init__.py @@ -8,6 +8,8 @@ format_error, extract_compatibles, extract_types, + get_prop_types, + sized_int, ) from dtschema.version import ( diff --git a/dtschema/dtb.py b/dtschema/dtb.py new file mode 100644 index 00000000..9865591b --- /dev/null +++ b/dtschema/dtb.py @@ -0,0 +1,480 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2021-2022 Arm Ltd. +# Python library for Devicetree schema validation + +import sys +import struct +import pprint + +import libfdt +from libfdt import QUIET_NOTFOUND + +import dtschema + +props = {} +pat_props = {} + +u8 = struct.Struct('B') +s8 = struct.Struct('b') +u16 = struct.Struct('>H') +s16 = struct.Struct('>h') +u32 = struct.Struct('>L') +s32 = struct.Struct('>l') +u64 = struct.Struct('>Q') +s64 = struct.Struct('>q') + +type_format = { + 'int8': s8, + 'uint8': u8, + 'int16': s16, + 'uint16': u16, + 'int32': s32, + 'uint32': u32, + 'int64': s64, + 'uint64': u64, + 'phandle': u32 +} + + +def bytes_to_string(b): + try: + strings = b.decode(encoding='ascii').split('\0') + + count = len(strings) - 1 + if count > 0 and not len(strings[-1]): + for string in strings[:-1]: + if not string: + continue + if not string.isprintable(): + break + else: + return strings[:-1] + except: + return None + + +def get_stride(len, dim): + match = 0 + if min(dim) == 0: + return 0 + for d in range(dim[0], dim[1] + 1): + if not len % d: + match += 1 + stride = d + if match == 1: + return stride + + return 0 + + +def prop_value(nodename, p): + # First, check for a boolean type + if not len(p): + return True + + dim = None + data = bytes(p) + fmt = None + + if nodename in {'__fixups__', 'aliases'}: + return data[:-1].decode(encoding='ascii').split('\0') + + if p.name in props: + v = props[p.name] + if {'string', 'string-array'} & set(v['type']): + #print(p.name, v) + str = bytes_to_string(data) + if str: + return str + # Assuming only one other type + try: + fmt = set(v['type']).difference({'string', 'string-array'}).pop() + except: + return data + elif len(v['type']): + fmt = v['type'][0] + # properties like ranges can be boolean or have a value + if fmt == 'flag' and len(data) and len(v['type']) > 1: + fmt = v['type'][1] + if (fmt.endswith('matrix') or fmt == 'phandle-array') and 'dim' in v: + dim = v['dim'] + #print(p.name, fmt) + else: + for pat, v in pat_props.items(): + if v['regex'].search(p.name): + #print(p.name, v, file=sys.stderr) + if fmt and fmt != v['type'][0]: + #print('Multiple regex match with differring types:', fmt, v['type'][0], pat, file=sys.stderr) + if len(data) > 4 and '-' in fmt: + continue + fmt = v['type'][0] + fmt_base = fmt.split('-', 1)[0] + if fmt_base in type_format: + if (fmt.endswith('matrix') or fmt == 'phandle-array') and 'dim' in v: + dim = v['dim'] + continue + elif 'string' in v['type'][0]: + return data[:-1].decode(encoding='ascii').split('\0') + else: + if not fmt: + # Primarily for aliases properties + try: + s = data.decode(encoding='ascii') + if s.endswith('\0'): + s = s[:-1] + if s.isprintable(): + return [s] + except: + pass + if not len(data) % 4: + fmt = 'uint32-array' + else: + #print(p.name + ': no type found', file=sys.stderr) + return data + + if fmt == 'flag': + if len(data): + print('{prop}: boolean property with value {val}'.format(prop=p.name, val=data), + file=sys.stderr) + return data + return True + + val_int = list() + #print(p.name, fmt, bytes(p)) + try: + type_struct = type_format[fmt.split('-', 1)[0]] + for i in type_struct.iter_unpack(data): + val_int += [dtschema.sized_int(i[0], size=(type_struct.size * 8))] + except: + print('{prop}: size ({len}) error for type {fmt}'.format(prop=p.name, len=len(p), fmt=fmt), file=sys.stderr) + if len(p) == 4: + type_struct = type_format['uint32'] + elif len(p) == 2: + type_struct = type_format['uint16'] + elif len(p) == 1: + type_struct = type_format['uint8'] + else: + return data + for i in type_struct.iter_unpack(data): + val_int += [dtschema.sized_int(i[0], size=(type_struct.size * 8))] + + if dim: + if max(dim[1]) and dim[1][0] == dim[1][1]: + stride = dim[1][1] + elif max(dim[0]) and dim[0][0] == dim[0][1]: + stride, rem = divmod(len(val_int), dim[0][1]) + if rem: + stride = len(val_int) + else: + # If multiple dimensions, check if one and only one dimension fits + stride = get_stride(len(val_int), dim[1]) + #if stride == 0: + # stride = get_stride(len(val_int), dim[0]) + if stride == 0: + stride = len(val_int) + + #print(p.name, dim, stride) + return [val_int[i:i+stride] for i in range(0, len(val_int), stride)] + + return [val_int] + + +def node_props(fdt, nodename, offset): + props_dict = {} + poffset = fdt.first_property_offset(offset, QUIET_NOTFOUND) + while poffset >= 0: + p = fdt.get_property_by_offset(poffset) + props_dict[p.name] = prop_value(nodename, p) + + poffset = fdt.next_property_offset(poffset, QUIET_NOTFOUND) + + return props_dict + + +phandles = {} +phandle_loc = [] + + +def process_fixups(fdt, nodename, offset): + if nodename != '__fixups__': + return + props = node_props(fdt, nodename, offset) + global phandle_loc + phandle_loc += [s for l in props.values() for s in l] + + +def process_local_fixups(fdt, nodename, path, offset): + global phandle_loc + + if nodename: + path += '/' + nodename + + poffset = fdt.first_property_offset(offset, QUIET_NOTFOUND) + while poffset >= 0: + p = fdt.get_property_by_offset(poffset) + + for i in type_format['uint32'].iter_unpack(bytes(p)): + phandle_loc += [path + ':' + p.name + ':' + str(i[0])] + + poffset = fdt.next_property_offset(poffset, QUIET_NOTFOUND) + + offset = fdt.first_subnode(offset, QUIET_NOTFOUND) + while offset >= 0: + nodename = fdt.get_name(offset) + process_local_fixups(fdt, nodename, path, offset) + + offset = fdt.next_subnode(offset, QUIET_NOTFOUND) + + +def fdt_scan_node(fdt, nodename, offset): + if nodename == '__fixups__': + process_fixups(fdt, nodename, offset) + return + if nodename == '__local_fixups__': + process_local_fixups(fdt, '', '', offset) + return + + node_dict = node_props(fdt, nodename, offset) + if 'phandle' in node_dict: + #print('phandle', node_dict['phandle']) + phandles[node_dict['phandle'][0][0]] = node_dict + + offset = fdt.first_subnode(offset, QUIET_NOTFOUND) + while offset >= 0: + nodename = fdt.get_name(offset) + node = fdt_scan_node(fdt, nodename, offset) + if node is not None: + node_dict[nodename] = node + + offset = fdt.next_subnode(offset, QUIET_NOTFOUND) + + return node_dict + + +phandle_args = { + # phandle+args properties which don't match standard 'foos' and '#foo-cells' pattern + 'assigned-clocks': '#clock-cells', + 'assigned-clock-parents': '#clock-cells', + 'cooling-device': '#cooling-cells', + 'interrupts-extended': '#interrupt-cells', + 'interconnects': '#interconnect-cells', + 'mboxes': '#mbox-cells', + 'sound-dai': '#sound-dai-cells', + + 'nvmem-cells': None, + 'memory-region': None, +} + + +def _get_cells_size(node, cellname): + if cellname in node: + return node[cellname][0][0] + else: + return 0 + + +def _check_is_phandle(prop_path, cell): + path = prop_path + ':' + str(cell * 4) + return path in phandle_loc + + +def _get_phandle_arg_size(prop_path, idx, cells, cellname): + if not cells: + return 0 + phandle = cells[0] + if phandle == 0 or not cellname: + return 1 + if phandle == 0xffffffff: + # Use fixups data if available (examples) + # Mixing unresolved and resolved phandles doesn't work + if _check_is_phandle(prop_path, idx): + cell_count = 1 + while (cell_count < len(cells)) and not _check_is_phandle(prop_path, idx + cell_count): + cell_count += 1 + + return cell_count + else: + return 0 + + if phandle not in phandles: + return 0 + + node = phandles[phandle] + if cellname not in node: + return 0 + + return _get_cells_size(node, cellname) + 1 + + +def fixup_phandles(dt, path=''): + for k, v in dt.items(): + if isinstance(v, dict): + fixup_phandles(v, path=path + '/' + k) + continue + elif not k in props or not {'phandle-array'} & set(props[k]['type']): + continue + elif not isinstance(v, list) or (len(v) > 1 or not isinstance(v[0], list)): + # Not a matrix or already split, nothing to do + continue + elif k in phandle_args: + cellname = phandle_args[k] + elif k.endswith('s'): + cellname = '#' + k[:-1] + '-cells' + #print(k, v) + i = _get_phandle_arg_size(path + ':' + k, 0, v[0], cellname) + if i == 0: + continue + else: + continue + + i = 0 + dt[k] = [] + val = v[0] + #print(k, v) + while i < len(val): + #print(k, v, file=sys.stderr) + cells = _get_phandle_arg_size(path + ':' + k, i, val[i:], cellname) + if cells == 0: + #print(k, v) + break + + # Special case for interconnects which is pairs of phandles+args + if k == 'interconnects': + cells += _get_phandle_arg_size(path + ':' + k, i + cells, val[i + cells:], cellname) + + val[i] = dtschema.sized_int(val[i], phandle=True) + dt[k] += [val[i:i + cells]] + #print(k, dt[k], file=sys.stderr) + + i += cells + + +def fixup_gpios(dt): + if 'gpio-hog' in dt: + return + for k, v in dt.items(): + if isinstance(v, dict): + fixup_gpios(v) + elif (k.endswith('-gpios') or k.endswith('-gpio') or k in {'gpio', 'gpios'}) and \ + not k.endswith(',nr-gpios'): + i = 0 + dt[k] = [] + val = v[0] + while i < len(val): + phandle = val[i] + if phandle == 0: + cells = 0 + elif phandle == 0xffffffff: + #print(val, file=sys.stderr) + try: + cells = val.index(0xffffffff, i + 1, -1) + except: + cells = len(val) + #print(cells, file=sys.stderr) + cells -= (i + 1) + else: + #print(k, v, file=sys.stderr) + node = phandles[phandle] + cells = _get_cells_size(node, '#gpio-cells') + + dt[k] += [val[i:i + cells + 1]] + + i += cells + 1 + + +def fixup_interrupts(dt, icells): + if 'interrupt-parent' in dt and isinstance(dt['interrupt-parent'], list): + phandle = dt['interrupt-parent'][0][0] + if phandle == 0xffffffff: + del dt['interrupt-parent'] + else: + icells = _get_cells_size(phandles[phandle], '#interrupt-cells') + + for k, v in dt.items(): + if isinstance(v, dict): + if '#interrupt-cells' in dt: + icells = _get_cells_size(dt, '#interrupt-cells') + fixup_interrupts(v, icells) + elif k == 'interrupts' and not isinstance(v, bytes): + i = 0 + dt[k] = [] + val = v[0] + while i < len(val): + dt[k] += [val[i:i + icells]] + i += icells + elif k == 'interrupt-map' and not isinstance(v, bytes): + icells = _get_cells_size(dt, '#interrupt-cells') + ac = _get_cells_size(dt, '#address-cells') + i = 0 + dt[k] = [] + val = v[0] + phandle = val[ac + icells] + if phandle == 0xffffffff: + # Assume uniform sizes (same interrupt provider) + try: + cells = val.index(0xffffffff, ac + icells + 1) - (ac + icells) + while i < len(val): + dt[k] += [val[i:i + cells]] + i += cells + except: + pass # Only 1 entry, nothing to do + else: + while i < len(val): + p_icells = _get_cells_size(phandles[phandle], '#interrupt-cells') + if '#address-cells' in phandles[phandle]: + p_ac = _get_cells_size(phandles[phandle], '#address-cells') + else: + p_ac = 0 + + cells = ac + icells + 1 + p_ac + p_icells + dt[k] += [val[i:i + cells]] + i += cells + + +def fixup_addresses(dt, ac, sc): + for k, v in dt.items(): + if isinstance(v, dict): + if '#address-cells' in dt: + ac = _get_cells_size(dt,'#address-cells') + if '#size-cells' in dt: + sc = _get_cells_size(dt, '#size-cells') + fixup_addresses(v, ac, sc) + elif k == 'reg': + i = 0 + dt[k] = [] + val = v[0] + while i < len(val): + dt[k] += [val[i:i + ac + sc]] + i += ac + sc + elif k in {'ranges', 'dma-ranges'} and not isinstance(v, bool): + child_cells = _get_cells_size(dt, '#address-cells') + child_cells += _get_cells_size(dt, '#size-cells') + i = 0 + dt[k] = [] + val = v[0] + while i < len(val): + dt[k] += [val[i:i + ac + child_cells]] + i += ac + child_cells + + +def fdt_unflatten(dtb): + p = dtschema.get_prop_types() + global props + global pat_props + + props = p[0] + pat_props = p[1] + + fdt = libfdt.Fdt(dtb) + + offset = fdt.first_subnode(-1, QUIET_NOTFOUND) + dt = fdt_scan_node(fdt, '/', offset) + + #print(phandle_loc) + fixup_gpios(dt) + fixup_interrupts(dt, 1) + fixup_addresses(dt, 2, 1) + fixup_phandles(dt) + +# pprint.pprint(dt, compact=True) + return dt diff --git a/dtschema/lib.py b/dtschema/lib.py index 864c1b59..25c3c242 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -13,6 +13,8 @@ import jsonschema +import dtschema.dtb + schema_base_url = "http://devicetree.org/" schema_basedir = os.path.dirname(os.path.abspath(__file__)) @@ -177,6 +179,26 @@ def _fixup_string_to_array(propname, subschema): subschema['items'] = [_extract_single_schemas(subschema)] +def _fixup_reg_schema(propname, subschema): + # nothing to do if we don't have a set of string schema + if propname != 'reg': + return + + if 'items' in subschema: + if isinstance(subschema['items'], list): + item_schema = subschema['items'][0] + else: + item_schema = subschema['items'] + if not _is_int_schema(item_schema): + return + elif _is_int_schema(subschema): + item_schema = subschema + else: + return + + subschema['items'] = [ {'items': [ _extract_single_schemas(item_schema) ] } ] + + def _is_matrix_schema(subschema): if 'items' not in subschema: return False @@ -190,10 +212,27 @@ def _is_matrix_schema(subschema): return False +# If we have a matrix with variable inner and outer dimensions, then drop the dimensions +# because we have no way to reconstruct them. +def _fixup_int_matrix(subschema): + if not _is_matrix_schema(subschema): + return + + outer_dim = _get_array_range(subschema) + inner_dim = _get_array_range(subschema.get('items', {})) + + if outer_dim[0] != outer_dim[1] and inner_dim[0] != inner_dim[1]: + subschema.pop('items', None) + subschema.pop('maxItems', None) + subschema.pop('minItems', None) + subschema['type'] = 'array' + int_array_re = re.compile('int(8|16|32|64)-array') unit_types_re = re.compile('-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours|microvolt|picofarads|celsius|millicelsius|kpascal)$') +# Remove this once we remove array to matrix fixups +known_array_props = {'assigned-clock-rates', 'linux,keycodes'} def is_int_array_schema(propname, subschema): if 'allOf' in subschema: @@ -206,7 +245,7 @@ def is_int_array_schema(propname, subschema): return int_array_re.search(item['$ref']) if '$ref' in subschema: return int_array_re.search(subschema['$ref']) - elif unit_types_re.search(propname): + elif unit_types_re.search(propname) or propname in known_array_props: return True return 'items' in subschema and \ @@ -375,7 +414,9 @@ def fixup_vals(propname, schema): schema.pop('description', None) + _fixup_reg_schema(propname, schema) _fixup_remove_empty_items(schema) + _fixup_int_matrix(schema) _fixup_int_array_min_max_to_matrix(propname, schema) _fixup_int_array_items_to_matrix(propname, schema) _fixup_string_to_array(propname, schema) @@ -853,6 +894,9 @@ def get_prop_types(): def load(filename, line_number=False): + if filename.endswith('.dtb'): + with open(filename, 'rb') as f: + return [ dtschema.dtb.fdt_unflatten(f.read()) ] with open(filename, 'r', encoding='utf-8') as f: if line_number: return rtyaml.load(f.read()) diff --git a/dtschema/schemas/clock/clock.yaml b/dtschema/schemas/clock/clock.yaml index a530f676..54f2da5f 100644 --- a/dtschema/schemas/clock/clock.yaml +++ b/dtschema/schemas/clock/clock.yaml @@ -26,7 +26,7 @@ properties: # Legacy clock properties clock-frequency: description: Legacy property for single, fixed frequency clocks - oneOf: + anyOf: - $ref: "/schemas/types.yaml#/definitions/uint32" - $ref: "/schemas/types.yaml#/definitions/uint64" bus-frequency: diff --git a/setup.py b/setup.py index 994d0721..db8a2637 100755 --- a/setup.py +++ b/setup.py @@ -41,7 +41,8 @@ 'tools/dt-doc-validate', 'tools/dt-mk-schema', 'tools/dt-extract-example', - 'tools/dt-extract-props' + 'tools/dt-extract-props', + 'tools/dtb2py' ], python_requires='>=3.5', @@ -50,6 +51,7 @@ 'ruamel.yaml>0.15.69', 'jsonschema>=4.1.2', 'rfc3987', + 'pylibfdt', ], classifiers=[ diff --git a/tools/dtb2py b/tools/dtb2py new file mode 100755 index 00000000..505b9ed2 --- /dev/null +++ b/tools/dtb2py @@ -0,0 +1,43 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2022 Arm Ltd. + +import argparse +import os +import sys +import pprint + +import dtschema + +strict = False + +if __name__ == "__main__": + ap = argparse.ArgumentParser() + ap.add_argument("dtbfile", type=str, help="Schema directories and/or files") + ap.add_argument('-s', '--schema', help="path to additional additional schema files") + ap.add_argument('-V', '--version', help="Print version number", + action="version", version=dtschema.__version__) + args = ap.parse_args() + + if not os.path.isfile(args.dtbfile): + exit(1) + + if os.path.isfile(args.schema): + schemas = dtschema.load_schema(os.path.abspath(args.schema)) + else: + schemas = dtschema.process_schemas([args.schema]) + dtschema.set_schema(schemas) + + dt = dtschema.load(args.dtbfile) + + try: + pprint.pprint(dt, compact=True) + # flush output here to force SIGPIPE to be triggered + # while inside this try block. + sys.stdout.flush() + except BrokenPipeError: + # Python flushes standard streams on exit; redirect remaining output + # to devnull to avoid another BrokenPipeError at shutdown + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + sys.exit(1) # Python exits with error code 1 on EPIPE From 2944dee02bade9d5010df1c696b8a66da880d951 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 27 Jan 2022 17:07:02 -0600 Subject: [PATCH 190/505] test: Add test for direct dtb validation Now that direct dtb validation is supported, add a test for it. Signed-off-by: Rob Herring --- test/test-dt-validate.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index a1e70c08..e4283f16 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -138,7 +138,7 @@ def check_subtree(self, nodename, subtree, fail): self.check_subtree(name, value, fail) def test_dt_yaml_validation(self): - '''Test that all DT files under ./test/ validate against the DT schema''' + '''Test that all DT files under ./test/ validate against the DT schema (YAML)''' for filename in glob.iglob('test/*.dts'): with self.subTest(schema=filename): expect_fail = "-fail" in filename @@ -152,6 +152,18 @@ def test_dt_yaml_validation(self): if isinstance(value, dict): self.check_node(name, value, expect_fail) + def test_dtb_validation(self): + '''Test that all DT files under ./test/ validate against the DT schema (DTB)''' + for filename in glob.iglob('test/*.dts'): + with self.subTest(schema=filename): + expect_fail = "-fail" in filename + res = subprocess.run(['dtc', '-Odtb', filename], capture_output=True) + testtree = dtschema.dtb.fdt_unflatten(res.stdout) + self.assertEqual(res.returncode, 0, msg='dtc failed:\n' + res.stderr.decode()) + for name, value in testtree.items(): + if isinstance(value, dict): + self.check_node(name, value, expect_fail) + if __name__ == '__main__': unittest.main() From 12b82ba6f182f6d74c5cbe9d7384f7fe4821d19f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 2 Mar 2022 13:41:51 -0600 Subject: [PATCH 191/505] README.md: Bring up to date The README is really out of date, update it. Signed-off-by: Rob Herring --- README.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index aaea2bbc..4b72d018 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,11 @@ representation. There is no special information in these files. They are used as test cases against the validation tooling. +Validation of .dtb files is now supported and preferred over YAML DT encoding. + ### *Devicetree Schemas* -Found under `./schemas` +Found under `./dtschema/schemas` *Devicetree Schemas* describe the format of devicetree data. The raw Devicetree file format is very open ended and doesn't restrict how @@ -70,7 +72,7 @@ is present. Single entries in schemas are fixed up to match this encoding. ### *Devicetree Meta-Schemas* -Found in `./meta-schemas` +Found in `./dtschema/meta-schemas` *Devicetree Meta-Schemas* describe the data format of Devicetree Schema files. The Meta-schemas make sure all the binding schemas are in the correct format @@ -100,10 +102,16 @@ schema. ## Installing -The project and its dependencies can be installed with pip directly from git: +The project and its dependencies can be installed with pip: + +``` +pip3 install dtschema +``` + +or directly from git: ``` -pip3 install git+https://github.com/devicetree-org/dt-schema.git@master +pip3 install git+https://github.com/devicetree-org/dt-schema.git@main ``` All executables will be installed. Ensure ~/.local/bin is in the PATH. @@ -121,22 +129,23 @@ pip3 install -e . Note: The above installation instructions handle all of the dependencies automatically. -This code depends on Python 3 with the ruamel.yaml, rfc3987, and jsonschema -libraries. +This code depends on Python 3 with the pylibfdt, ruamel.yaml, rfc3987, and jsonschema +libraries. Installing pylibfdt depends on the 'swig' program. On Debian/Ubuntu, the dependencies can be installed with apt and/or pip. The rfc3987 module is not packaged, so pip must be used: ``` -apt-get install python3 python3-ruamel.yaml +sudo apt install swig +sudo apt install python3 python3-ruamel.yaml pip3 install rfc3987 ``` ### jsonschema -This code depends on at least version 3.0.0 of the +This code depends on at least version 4.1.2 of the [Python jsonschema](https://github.com/Julian/jsonschema/tree/master) -library for Draft 6 support. +library for Draft 2019-09 support. The module can be installed directly from github with pip: From a11e37a9dcfe6498af09c6bc494fb58bc9979459 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 6 Mar 2022 12:00:46 +0100 Subject: [PATCH 192/505] dtschema: Accept uint32-matrix as -hz type There is at least one case in bindings using a table of frequency pairs (min and max in Hz), so allow such pairs (uint32-matrix is superset of uint32-array). Signed-off-by: Krzysztof Kozlowski --- dtschema/schemas/property-units.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index bea43651..ff042a55 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -40,7 +40,7 @@ patternProperties: $ref: "types.yaml#/definitions/uint32-array" description: megahertz "-hz$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: "types.yaml#/definitions/uint32-matrix" description: hertz (preferred) "-sec$": $ref: "types.yaml#/definitions/uint32-array" From 3f7d21648ae8788e99e3add2c2ab75117f9314d1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 4 Mar 2022 11:42:13 -0600 Subject: [PATCH 193/505] dtb: Ignore any nodes starting with '__' For DTBs built with '-@' option, the '__symbols__' node needs to be ignored. To future proof things, just ignore any nodes starting with '__'. Reported-by: Geert Uytterhoeven Signed-off-by: Rob Herring --- dtschema/dtb.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 9865591b..45f8a01e 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -233,6 +233,8 @@ def fdt_scan_node(fdt, nodename, offset): if nodename == '__local_fixups__': process_local_fixups(fdt, '', '', offset) return + if nodename.startswith('__'): + return node_dict = node_props(fdt, nodename, offset) if 'phandle' in node_dict: From 53e04bb43d8533ffd34e9b4af8b01d67325dc891 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 4 Mar 2022 11:44:52 -0600 Subject: [PATCH 194/505] schemas: Rework memory node schema to only apply to root /memory nodes 'memory' is sometimes used as a nodename in besides in the root node. For example, under /reserved-memory node. Rework the schema to only check root node 'memory' nodes. Signed-off-by: Rob Herring --- dtschema/schemas/memory.yaml | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/dtschema/schemas/memory.yaml b/dtschema/schemas/memory.yaml index 4e27b73b..1d744109 100644 --- a/dtschema/schemas/memory.yaml +++ b/dtschema/schemas/memory.yaml @@ -15,16 +15,30 @@ maintainers: properties: $nodename: - pattern: "^memory(@[0-9a-f]+)?$" - device_type: - const: memory - reg: - minItems: 1 - maxItems: 1024 - -required: - - device_type - - reg + const: '/' + +patternProperties: + "^memory(@[0-9a-f]+)?$": + type: object + additionalProperties: false + + properties: + device_type: + const: memory + reg: + minItems: 1 + maxItems: 1024 + + numa-node-id: + $ref: types.yaml#/definitions/uint32 + description: + For the purpose of identification, each NUMA node is associated with + a unique token known as a node id. + + + required: + - device_type + - reg additionalProperties: true From cb3fc590d8f72b02ae7055d4623f8cff18452074 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 9 Mar 2022 13:09:32 -0600 Subject: [PATCH 195/505] dt-validate: Fix missing set_schema() call after processing schemas In the case of using unprocessed schemas, we need to set the schema after processing. This didn't matter too much until v2022.03 with validation of DTBs as before the $ref handling would still find the schemas. Signed-off-by: Rob Herring --- tools/dt-validate | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/dt-validate b/tools/dt-validate index 525dd290..38f2c0ea 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -31,10 +31,11 @@ class schema_group(): self.schemas = dtschema.process_schemas([schema_file]) elif os.path.isfile(schema_file): self.schemas = dtschema.load_schema(os.path.abspath(schema_file)) - dtschema.set_schema(self.schemas) else: exit(-1) + dtschema.set_schema(self.schemas) + def check_node(self, tree, node, disabled, nodename, fullname, filename): # Skip any generated nodes node['$nodename'] = [ nodename ] From d04e9368ce20508330eeffc09f45bfeb0db907a7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 11 Mar 2022 17:36:27 -0600 Subject: [PATCH 196/505] dtschema: Handle standard unit matrix types with dimensions Handle standard unit type properties with a schema defining dimensions. Most cases of standard units are a scalar or array, but there's a few cases of matrices. For these, we need to capture the property name, type and dimensions. Signed-off-by: Rob Herring --- dtschema/lib.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index 25c3c242..f70579a3 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -806,6 +806,10 @@ def _extract_prop_type(props, schema, propname, subschema): (isinstance(items, dict) and _is_string_schema(items)): # implicit string type prop_type = 'string-array' + elif not (isinstance(items, list) and len(items) == 1 and \ + 'items' in items and isinstance(items['items'], list) and len(items['items']) == 1) and \ + unit_types_re.search(propname): + prop_type = 'uint32-matrix' else: prop_type = None else: From be3435d0fc8499abce846120ae04d2caea5ac03e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 31 Mar 2022 09:58:36 -0500 Subject: [PATCH 197/505] Handle valid YAML files without schemas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While a variety of file errors are handled such as bad YAML and bad schemas, files which are valid YAML, but are not a mapping/dict at the root level will backtrace. Handle these errors. Reported-by: Rafał Miłecki Signed-off-by: Rob Herring --- dtschema/lib.py | 4 ++++ tools/dt-doc-validate | 10 +++++++--- tools/dt-extract-example | 2 ++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index f70579a3..070ae00d 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -698,6 +698,10 @@ def process_schema(filename): file=sys.stderr) #print(exc.message) return + except: + print(filename + ": ignoring, unknown error in schema (not a schema?)", + file=sys.stderr) + return if 'select' not in schema: print(filename + ": warning: no 'select' found in schema found", file=sys.stderr) diff --git a/tools/dt-doc-validate b/tools/dt-doc-validate index 93f13d08..3a042eb9 100755 --- a/tools/dt-doc-validate +++ b/tools/dt-doc-validate @@ -33,9 +33,13 @@ def check_doc(filename): print(filename + ":", exc.problem, file=sys.stderr) return 1 - for error in sorted(dtschema.DTValidator.iter_schema_errors(testtree), key=lambda e: e.linecol): - print(dtschema.format_error(filename, error, verbose=args.verbose), file=sys.stderr) - ret = 1 + try: + for error in sorted(dtschema.DTValidator.iter_schema_errors(testtree), key=lambda e: e.linecol): + print(dtschema.format_error(filename, error, verbose=args.verbose), file=sys.stderr) + ret = 1 + except: + print(filename + ': error checking schema file', file=sys.stderr) + return 1 dtschema.DTValidator.check_schema_refs(filename, testtree) dtschema.DTValidator.check_quotes(filename + ":", testtree) diff --git a/tools/dt-extract-example b/tools/dt-extract-example index 981a9ae4..c1acaf41 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -50,6 +50,8 @@ if __name__ == "__main__": try: binding = yaml.load(open(args.yamlfile, encoding='utf-8').read()) + if not isinstance(binding, dict): + exit(0) except ruamel.yaml.constructor.DuplicateKeyError as exc: print(args.yamlfile + ":", exc.problem, file=sys.stderr) exit(1) From a20ca985d9f4fdd3b7bf8e9627311cada01fe221 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 13 Apr 2022 15:29:14 -0500 Subject: [PATCH 198/505] schemas: Add 'protected-clocks' property schema The description is copied from the Linux kernel and written by Stephen Boyd. It's relicensed as BSD-2-Clause. Acked-by: Stephen Boyd Signed-off-by: Rob Herring --- dtschema/schemas/clock/clock.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dtschema/schemas/clock/clock.yaml b/dtschema/schemas/clock/clock.yaml index 54f2da5f..6255bd04 100644 --- a/dtschema/schemas/clock/clock.yaml +++ b/dtschema/schemas/clock/clock.yaml @@ -90,6 +90,16 @@ properties: assigned-clock-rates: $ref: "/schemas/types.yaml#/definitions/uint32-array" + protected-clocks: + $ref: "/schemas/types.yaml#/definitions/uint32-array" + description: + Some platforms or firmwares may not fully expose all the clocks to the OS, + such as in situations where those clks are used by drivers running in ARM + secure execution levels. Such a configuration can be specified in + devicetree with the protected-clocks property in the form of a clock + specifier list. This property should only be specified in the node that is + providing the clocks being protected. + dependencies: clock-names: [clocks] clock-output-names: ["#clock-cells"] @@ -98,5 +108,6 @@ dependencies: assigned-clocks: [clocks] assigned-clock-parents: [assigned-clocks] assigned-clock-rates: [assigned-clocks] + protected-clocks: ["#clock-cells"] additionalProperties: true From 80ebd7a766bac42b05904c977115b385505e2e7e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 13 Apr 2022 16:34:57 -0500 Subject: [PATCH 199/505] schemas: clock: Allow 'assigned-clocks' when '#clock-cells' is present Some clock providers need to configure clocks, so make '#clock-cells' a dependency in addition to 'clocks'. Signed-off-by: Rob Herring --- dtschema/schemas/clock/clock.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dtschema/schemas/clock/clock.yaml b/dtschema/schemas/clock/clock.yaml index 6255bd04..2416d046 100644 --- a/dtschema/schemas/clock/clock.yaml +++ b/dtschema/schemas/clock/clock.yaml @@ -100,14 +100,19 @@ properties: specifier list. This property should only be specified in the node that is providing the clocks being protected. -dependencies: +dependentRequired: clock-names: [clocks] clock-output-names: ["#clock-cells"] clock-indices: [clock-output-names] clock-ranges: [clocks] - assigned-clocks: [clocks] assigned-clock-parents: [assigned-clocks] assigned-clock-rates: [assigned-clocks] protected-clocks: ["#clock-cells"] +dependentSchemas: + assigned-clocks: + anyOf: + - required: [clocks] + - required: ["#clock-cells"] + additionalProperties: true From ba55f96c6d8d8c58f375393bca0c251574986c40 Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Thu, 14 Apr 2022 09:54:36 +0200 Subject: [PATCH 200/505] schemas: i2c-controller: Add 'no-detect' property In some cases, operating systems may attempt to detect the presence of devices on an I2C bus by, for example, attempting to read specific registers from a list of addresses which some common peripherals is known to use. Add a property which can be used to indicate that there are no devices on the bus except the ones listed in the devicetree, thus allowing operating systems to choose to avoid spending time on attempting this kind of detection of devices which do not exist. Signed-off-by: Vincent Whitchurch --- dtschema/schemas/i2c/i2c-controller.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index 945eb739..91eac62a 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -28,6 +28,12 @@ properties: minimum: 1000 maximum: 3000000 + no-detect: + type: boolean + description: + States that no other devices are present on this bus other than the ones + listed in the devicetree. + patternProperties: '@[0-9a-f]+$': type: object From a24d97d43491e55d4def006213213a6c4045b646 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 12 Apr 2022 16:24:39 +0100 Subject: [PATCH 201/505] schemas: chosen: Add 'u-boot,bootconf' node Add string property allowing to pass down the name of the selected image configuration node of a uImage.FIT to the operating system. Signed-off-by: Daniel Golle --- dtschema/schemas/chosen.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dtschema/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml index d66d10ad..8eca480e 100644 --- a/dtschema/schemas/chosen.yaml +++ b/dtschema/schemas/chosen.yaml @@ -200,6 +200,12 @@ properties: carrying the IMA measurement logs. The address and the suze are expressed in #address-cells and #size-cells, respectively of the root node. + u-boot,bootconf: + $ref: types.yaml#/definitions/string + description: + This property can be used by U-Boot to pass the selected configuration unit + name of the booted image down to the operating system. + patternProperties: "^framebuffer": true From 020bb749873622cf0cb978cab56f75dc513f03e1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 20 Apr 2022 13:44:59 -0500 Subject: [PATCH 202/505] meta-schemas: Rework additionalProperties/unevaluatedProperties Requiring 'additionalProperties' when there's no '$ref' is too restrictive and encourages working around the limitation. Let's drop the requirement and instead only allow 'additionalProperties' when 'properties', 'patternProperties' or 'type: object' is present (a corner case of a node matching all child nodes and no properties). Also, this check catches some cases of both 'additionalProperties' and 'unevaluatedProperties' being present. Signed-off-by: Rob Herring --- dtschema/meta-schemas/base.yaml | 27 --------------------------- dtschema/meta-schemas/core.yaml | 4 ++++ dtschema/meta-schemas/keywords.yaml | 6 ++++++ dtschema/schemas/types.yaml | 2 -- 4 files changed, 10 insertions(+), 29 deletions(-) diff --git a/dtschema/meta-schemas/base.yaml b/dtschema/meta-schemas/base.yaml index f0d9e0a9..9f27da12 100644 --- a/dtschema/meta-schemas/base.yaml +++ b/dtschema/meta-schemas/base.yaml @@ -58,30 +58,3 @@ required: - $schema - title - maintainers - -if: - oneOf: - - properties: - allOf: - contains: - required: - - $ref - required: - - allOf - - required: - - $ref -then: - description: - 'A schema with a "$ref" to another schema either can define all properties used and - use "additionalProperties" or can use "unevaluatedProperties"' - oneOf: - - required: - - unevaluatedProperties - - required: - - additionalProperties -else: - description: - 'A schema without a "$ref" to another schema must define all properties and - use "additionalProperties"' - required: - - additionalProperties diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index 62601581..0c01ac71 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -9,6 +9,10 @@ description: "Metaschema for devicetree binding documentation" allOf: - $ref: "http://devicetree.org/meta-schemas/base.yaml#" + - description: Either unevaluatedProperties or additionalProperties must be present + oneOf: + - required: [ unevaluatedProperties ] + - required: [ additionalProperties ] definitions: all-properties: diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 6d6fdfd0..2dbcca9b 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -76,6 +76,12 @@ dependentSchemas: $ref: "#/definitions/scalar-prop-list" minItems: $ref: "#/definitions/scalar-prop-list" + additionalProperties: + description: "'additionalProperties' depends on 'properties' or 'patternProperties'" + anyOf: + - required: [ type ] + - required: [ properties ] + - required: [ patternProperties ] properties: additionalItems: diff --git a/dtschema/schemas/types.yaml b/dtschema/schemas/types.yaml index 0a4c22d5..4a2464ae 100644 --- a/dtschema/schemas/types.yaml +++ b/dtschema/schemas/types.yaml @@ -371,5 +371,3 @@ definitions: const: 0 additionalItems: $ref: "#/definitions/cell" - -additionalProperties: true From 4cacc375b768a54e4bdb166a7c3ba75a82e20178 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 22 Apr 2022 16:17:19 -0500 Subject: [PATCH 203/505] dtschema: Handle schema errors on ref lookups If a referenced schema has errors, it won't be in the schema list. Return a false schema so we return a normal schema error in that case. Signed-off-by: Rob Herring --- dtschema/lib.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index 070ae00d..41033266 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -928,6 +928,9 @@ def http_handler(uri): for sch in schema_cache: if uri in sch['$id']: return sch + # If we have a schema_cache, then the schema should have been there unless the schema had errors + if len(schema_cache): + return False if 'meta-schemas' in uri: return load_schema(uri.replace(schema_base_url, '')) return process_schema(uri.replace(schema_base_url, '')) From 07d47b084dea474543ea9504b735293197ce5b81 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Apr 2022 15:31:33 -0500 Subject: [PATCH 204/505] dtschema: Improve error messages for $ref resolution errors check_schema_refs() may raise an exception or print errors from process_schema(). In the latter case, the file path is not clear. If the referring schema had an non-existent file, the referring schema file is not printed. Fix this by always raising a RefResolutionError exception with an appropriate message. Signed-off-by: Rob Herring --- dtschema/lib.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 41033266..51d6d24b 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -13,6 +13,8 @@ import jsonschema +from jsonschema.exceptions import RefResolutionError + import dtschema.dtb schema_base_url = "http://devicetree.org/" @@ -933,7 +935,18 @@ def http_handler(uri): return False if 'meta-schemas' in uri: return load_schema(uri.replace(schema_base_url, '')) - return process_schema(uri.replace(schema_base_url, '')) + + try: + schema = load_schema(uri.replace(schema_base_url, '')) + except Exception as exc: + raise RefResolutionError('Unable to find schema file matching $id: ' + uri) + + try: + DTValidator.check_schema(schema) + except Exception as exc: + raise RefResolutionError('Error in referenced schema matching $id: ' + uri) + + return schema from urllib.request import urlopen From ecdd64d77b2202f9d5344753200085753127dbe2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 27 Apr 2022 12:52:39 -0500 Subject: [PATCH 205/505] meta-schemas: Allow 'oneOf' in single cell constraints A 'oneOf' is needed to define multiple ranges of values for example. Signed-off-by: Rob Herring --- dtschema/meta-schemas/cell.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/cell.yaml b/dtschema/meta-schemas/cell.yaml index 91328cfb..454e62e5 100644 --- a/dtschema/meta-schemas/cell.yaml +++ b/dtschema/meta-schemas/cell.yaml @@ -74,6 +74,8 @@ single: maximum: {} default: type: integer + oneOf: + $ref: #/single propertyNames: - enum: [ description, deprecated, const, enum, minimum, maximum, multipleOf, default, $ref ] + enum: [ description, deprecated, const, enum, minimum, maximum, multipleOf, default, $ref, oneOf ] From d4fae6fc62446e36070eadc6f2d72520ffd0b015 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 12 Jul 2021 16:16:06 -0600 Subject: [PATCH 206/505] Revert "Revert "meta-schemas: Reject 'patternProperties' values that are fixed string patterns"" This reverts commit 19d754e9e2b6b319bbfd98efa26c1578e61a088a. --- dtschema/meta-schemas/keywords.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 2dbcca9b..134d001a 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -128,6 +128,9 @@ properties: required: - const patternProperties: + propertyNames: + not: + pattern: '^\^[a-zA-Z0-9,\-._#]+\$$' additionalProperties: $ref: "#/definitions/sub-schemas" properties: From 70209b55697061fcbee77f1c30123b0333e60e9c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 4 Jun 2021 17:05:24 -0500 Subject: [PATCH 207/505] meta-schemas: Add constraints on $ref values Ensure that $ref values start with '/schemas/' for absolute paths, '../' for relative paths, a '#' for local refs, or a filename character. Full URLs are also not allowed. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 134d001a..712619eb 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -84,6 +84,10 @@ dependentSchemas: - required: [ patternProperties ] properties: + $ref: + pattern: '^(/schemas/|\.\./|#(/|$)|[a-zA-Z0-9]+)' + not: + pattern: '^https?://' additionalItems: type: boolean additionalProperties: From a3b6651ee04fd1e3e200ea872d566edfbed5d954 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 22 Apr 2022 19:01:19 -0500 Subject: [PATCH 208/505] schemas: Add an ISA bus schema ISA bus is still in use in some DTs. Add a basic schema for it so that 'isa' is a documented compatible. There are a few cases of custom ISA bridges that have a specific binding, so the schema is split between a bus schema and a generic bridge schema. Signed-off-by: Rob Herring --- dtschema/schemas/isa/isa-bridge.yaml | 46 +++++++++++++++++++++ dtschema/schemas/isa/isa-bus.yaml | 60 ++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 dtschema/schemas/isa/isa-bridge.yaml create mode 100644 dtschema/schemas/isa/isa-bus.yaml diff --git a/dtschema/schemas/isa/isa-bridge.yaml b/dtschema/schemas/isa/isa-bridge.yaml new file mode 100644 index 00000000..f6f5087e --- /dev/null +++ b/dtschema/schemas/isa/isa-bridge.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2022 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/isa/isa-bridge.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: ISA bus bridge schema + +description: | + Schema for ISA bridge nodes. This is for bridges with I/O space mapped into + the parent bus. + + ISA Bus Binding to: IEEE Std 1275-1994 + https://www.devicetree.org/open-firmware/bindings/isa/isa0_4d.ps + +maintainers: + - Rob Herring + +select: + properties: + compatible: + contains: + enum: + - isa + - pciclass,0601 + device_type: + const: isa + + anyOf: + - required: [ device_type ] + - required: [ compatible ] + +allOf: + - $ref: isa-bus.yaml# + +properties: + compatible: + enum: + - isa + - pciclass,0601 + +required: + - ranges + +unevaluatedProperties: false diff --git a/dtschema/schemas/isa/isa-bus.yaml b/dtschema/schemas/isa/isa-bus.yaml new file mode 100644 index 00000000..d1ef316b --- /dev/null +++ b/dtschema/schemas/isa/isa-bus.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2022 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/isa/isa-bus.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: ISA bus schema + +description: | + Common properties for ISA bus nodes + + ISA Bus Binding to: IEEE Std 1275-1994 + https://www.devicetree.org/open-firmware/bindings/isa/isa0_4d.ps + +maintainers: + - Rob Herring + +properties: + $nodename: + pattern: "^isa@" + + device_type: + const: isa + + ranges: + description: Required for memory accesses or memory mapped I/O space. Optional if only + indirect I/O is supported. + + "#address-cells": + const: 2 + + "#size-cells": + const: 1 + +patternProperties: + '@(m|i?)[0-9a-f]{1,8}$': + type: object + description: Child devices + + properties: + reg: + items: + items: + - enum: + - 0x0 # memory address + - 0x1 # I/O address + - description: address + - description: size + minItems: 3 + maxItems: 3 + + required: + - reg + +required: + - "#address-cells" + - "#size-cells" + +additionalProperties: true From 097abe6680e4c7bca533f94e56132bcedf00e7e5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 10 May 2022 16:37:38 -0500 Subject: [PATCH 209/505] dt-extract-example: Write output in a single print In case we exit early, don't write any output until the end so that we don't have partial output. Of course, if print() is not atomic, then this only partially helps. Signed-off-by: Rob Herring --- tools/dt-extract-example | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tools/dt-extract-example b/tools/dt-extract-example index c1acaf41..0fba1126 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -56,7 +56,7 @@ if __name__ == "__main__": print(args.yamlfile + ":", exc.problem, file=sys.stderr) exit(1) - print(example_header) + example_dts = example_header if 'examples' in binding.keys(): for idx,ex in enumerate(binding['examples']): @@ -70,16 +70,17 @@ if __name__ == "__main__": int_cells = len(int_val.strip().split()) except: int_cells = 0 - print(example_start) + example_dts += example_start ex = ' '.join(ex.splitlines(True)) if int_cells > 0: int_props = interrupt_template.format(int_cells=int_cells) else: int_props = "" - print(example_template.format(example=ex, example_num=idx, - interrupt=int_props)) + example_dts += example_template.format(example=ex, example_num=idx, interrupt=int_props) else: - print(ex) + example_dts += ex else: - print(example_start) - print("\n};") + example_dts += example_start + example_dts += "\n};" + + print(example_dts) From ea4ca82bca6bbec0b5e27a8fa89063edceec6ef8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 13 May 2022 12:36:03 +0200 Subject: [PATCH 210/505] dtschema: Add basis points property unity Document the basis points property unit: one hundredth of 1 percentage point. The unit is not very popular but recently new bindings using it were submitted. Signed-off-by: Krzysztof Kozlowski --- dtschema/schemas/property-units.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index ff042a55..da8b505f 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -35,6 +35,10 @@ patternProperties: $ref: "types.yaml#/definitions/uint32-array" description: percentage + "-bp$": + $ref: "types.yaml#/definitions/uint32-array" + description: basis points (1/100 of a percent) + # Time/Frequency "-mhz$": $ref: "types.yaml#/definitions/uint32-array" From 8506979e2020e17c5bafd9caa3f7a04c9ffd2987 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 18 May 2022 19:15:00 -0500 Subject: [PATCH 211/505] dtschema: Fix property type extraction under 'additionalProperties' 'additionalProperties' is a schema rather than a dict of DT properties like 'properties' or 'patternProperties'. Therefore it needs to be handled differently from them. Signed-off-by: Rob Herring --- dtschema/lib.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 51d6d24b..121c5cf1 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -864,7 +864,10 @@ def _extract_subschema_types(props, schema, subschema): if not isinstance(subschema, dict): return - for k in subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: + if 'additionalProperties' in subschema: + _extract_subschema_types(props, schema, subschema['additionalProperties']) + + for k in subschema.keys() & {'properties', 'patternProperties'}: if isinstance(subschema[k], dict): for p,v in subschema[k].items(): _extract_prop_type(props, schema, p, v) From 7cf42920ebd1adbb3abecbd217d836515ab3a7ad Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 18 May 2022 14:09:00 -0500 Subject: [PATCH 212/505] meta-schemas: Require 'maxItems' is at least 1 'maxItems: 0' doesn't make sense as 0 items would be the same as not present. 'minItems' was already fixed, but we missed 'maxItems'. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 712619eb..2c214f9e 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -116,6 +116,8 @@ properties: - type: array items: $ref: "#/definitions/sub-schemas" + maxItems: + minimum: 1 minItems: minimum: 1 not: From 9537788bcf08d9c5176b0b44bd7ea630181b461e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 18 May 2022 14:10:41 -0500 Subject: [PATCH 213/505] Add schema and fixup for 'secure-status' property The 'secure-status' property is equivalent to 'status' but used by 'secure world' on Arm. It's been around for some time, but not widely used. Signed-off-by: Rob Herring --- dtschema/lib.py | 1 + dtschema/schemas/dt-core.yaml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index 121c5cf1..2c47307b 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -493,6 +493,7 @@ def fixup_node_props(schema): schema.setdefault('properties', dict()) schema['properties'].setdefault('phandle', True) schema['properties'].setdefault('status', True) + schema['properties'].setdefault('secure-status', True) schema['properties'].setdefault('$nodename', True) keys = list() diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index e0f94b3d..b14ca0f8 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -35,6 +35,9 @@ properties: - $ref: "types.yaml#/definitions/uint32-matrix" reg: $ref: "types.yaml#/definitions/uint32-matrix" + secure-status: + $ref: "types.yaml#/definitions/string" + enum: [ okay, disabled, reserved ] status: $ref: "types.yaml#/definitions/string" enum: [ okay, disabled, reserved ] From 903a4e41cd6957641694ffb840862767fd4cd3e9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 18 May 2022 19:14:16 -0500 Subject: [PATCH 214/505] schemas: Add 'wakeup-parent' property Some interrupt controllers may have a separate wakeup controller to resume from low power modes. 'wakeup-parent' allows linking an interrupt controller to its wakeup controller. Signed-off-by: Rob Herring --- dtschema/schemas/interrupt-controller.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dtschema/schemas/interrupt-controller.yaml b/dtschema/schemas/interrupt-controller.yaml index 48381085..6c9927f7 100644 --- a/dtschema/schemas/interrupt-controller.yaml +++ b/dtschema/schemas/interrupt-controller.yaml @@ -26,6 +26,16 @@ properties: interrupt-map-mask: $ref: "types.yaml#/definitions/uint32-array" + wakeup-parent: + $ref: types.yaml#/definitions/phandle + description: + Some interrupt controllers in a SoC, are always powered on and have a + select interrupts routed to them, so that they can wakeup the SoC from + suspend. These interrupt controllers do not fall into the category of a + parent interrupt controller and can be specified by the "wakeup-parent" + property and contain a single phandle referring to the wakeup capable + interrupt controller. + dependencies: interrupt-controller: ['#interrupt-cells'] interrupt-map: ['#interrupt-cells' ] From 1dea26126e2a2bffeab6c491f3254f981a2ceb03 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 19 May 2022 14:11:03 -0500 Subject: [PATCH 215/505] schemas: Add 'reg-io-width' and 'reg-shift' property schemas 'reg-io-width' and 'reg-shift' are common properties used to describe device register layout. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index b14ca0f8..1bafff41 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -35,6 +35,16 @@ properties: - $ref: "types.yaml#/definitions/uint32-matrix" reg: $ref: "types.yaml#/definitions/uint32-matrix" + reg-io-width: + $ref: "types.yaml#/definitions/uint32" + minimum: 1 + maximum: 0xf + description: + Typically, a single set bit indicating the access size, but some uses treat + this as a bit mask of allowed sizes. + reg-shift: + $ref: "types.yaml#/definitions/uint32" + enum: [ 0, 1, 2 ] secure-status: $ref: "types.yaml#/definitions/string" enum: [ okay, disabled, reserved ] From 70b3204b69d7fcae19c6af2e896314cccd1c6fde Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Apr 2022 10:20:41 -0500 Subject: [PATCH 216/505] schemas: clock: Add assigned-clocks description Add description for assigned-clocks properties from clock-binding.txt in the Linux kernel. This is relicensed from GPL-2.0 (the default) to BSD-2-Clause. The Cc list are the original authors. Cc: Stephen Boyd Acked-by: Sylwester Nawrocki Reviewed-by: Stephen Boyd Signed-off-by: Rob Herring --- dtschema/schemas/clock/clock.yaml | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/dtschema/schemas/clock/clock.yaml b/dtschema/schemas/clock/clock.yaml index 2416d046..5299653b 100644 --- a/dtschema/schemas/clock/clock.yaml +++ b/dtschema/schemas/clock/clock.yaml @@ -19,6 +19,44 @@ description: | output on a device. The length of a clock specifier is defined by the value of a #clock-cells property in the clock provider node. + Assigned clock parents and rates + -------------------------------- + + Some platforms may require initial configuration of default parent clocks + and clock frequencies. Such a configuration can be specified in a device tree + node through assigned-clocks, assigned-clock-parents and assigned-clock-rates + properties. The assigned-clock-parents property should contain a list of parent + clocks in the form of a phandle and clock specifier pair and the + assigned-clock-rates property should contain a list of frequencies in Hz. Both + these properties should correspond to the clocks listed in the assigned-clocks + property. + + To skip setting parent or rate of a clock its corresponding entry should be + set to 0, or can be omitted if it is not followed by any non-zero entry. + + serial@a000 { + compatible = "fsl,imx-uart"; + reg = <0xa000 0x1000>; + ... + clocks = <&osc 0>, <&pll 1>; + clock-names = "baud", "register"; + + assigned-clocks = <&clkcon 0>, <&pll 2>; + assigned-clock-parents = <&pll 2>; + assigned-clock-rates = <0>, <460800>; + }; + + In this example the <&pll 2> clock is set as parent of clock <&clkcon 0> and + the <&pll 2> clock is assigned a frequency value of 460800 Hz. + + Configuring a clock's parent and rate through the device node that consumes + the clock can be done only for clocks that have a single user. Specifying + conflicting parent or rate configuration in multiple consumer nodes for + a shared clock is forbidden. + + Configuration of common clocks, which affect multiple consumer devices can + be similarly specified in the clock provider node. + # always select the core schema select: true From 4af6db61ac2bcfe6d9b76ac4ea32a97e644c2d17 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 25 May 2022 08:32:19 +0200 Subject: [PATCH 217/505] dtschema: Fix -bp property name suffix matching It is not enough to add unit suffix to property-units.yaml. It should also be added to other places checking for ref/description. Fixes: 06b6480db133 ("dtschema: Add basis points property unity") Signed-off-by: Krzysztof Kozlowski --- dtschema/lib.py | 2 +- dtschema/meta-schemas/core.yaml | 2 +- dtschema/meta-schemas/vendor-props.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 2c47307b..3483b45e 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -231,7 +231,7 @@ def _fixup_int_matrix(subschema): int_array_re = re.compile('int(8|16|32|64)-array') -unit_types_re = re.compile('-(bits|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours|microvolt|picofarads|celsius|millicelsius|kpascal)$') +unit_types_re = re.compile('-(bits|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours|microvolt|picofarads|celsius|millicelsius|kpascal)$') # Remove this once we remove array to matrix fixups known_array_props = {'assigned-clock-rates', 'linux,keycodes'} diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index 0c01ac71..c6902262 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -58,7 +58,7 @@ definitions: propertyNames: enum: [ description, deprecated ] - '-(bits|-kBps|percent|mhz|hz|sec|ms|us|ns|ps|mm|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kpascal)$': + '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kpascal)$': allOf: - $ref: "cell.yaml#/array" - description: Standard unit suffix properties don't need a type $ref diff --git a/dtschema/meta-schemas/vendor-props.yaml b/dtschema/meta-schemas/vendor-props.yaml index 40ac7f5d..c2da5b6a 100644 --- a/dtschema/meta-schemas/vendor-props.yaml +++ b/dtschema/meta-schemas/vendor-props.yaml @@ -15,7 +15,7 @@ patternProperties: '-(gpio|gpios)$': true '-supply$': true '^rcar_sound,': true - '-(bits|-kBps|percent|mhz|hz|sec|ms|us|ns|ps|mm)$': true + '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm)$': true '-(microamp|microamp-hours|ohms|micro-ohms|microwatt-hours)$': true '-(microvolt|(femto|pico)farads|celsius|millicelsius|kpascal)$': true From ea547ffbd0016108f37eeffa0401c157a7d9bde4 Mon Sep 17 00:00:00 2001 From: Francesco Dolcini Date: Thu, 19 May 2022 11:02:49 +0200 Subject: [PATCH 218/505] schemas: chosen: Add 'u-boot,version' property Add a string property to pass down the U-Boot version to the operating system. Signed-off-by: Francesco Dolcini --- dtschema/schemas/chosen.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dtschema/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml index 8eca480e..ea71fe22 100644 --- a/dtschema/schemas/chosen.yaml +++ b/dtschema/schemas/chosen.yaml @@ -206,6 +206,13 @@ properties: This property can be used by U-Boot to pass the selected configuration unit name of the booted image down to the operating system. + u-boot,version: + $ref: types.yaml#/definitions/string + pattern: "^20[0-9]{2}\\.[0-9]{2}.*$" + description: + This property is used by U-Boot to pass its version down to the operating + system. + patternProperties: "^framebuffer": true From 85028cf947c0de82f710bbfacc8bad94148a51ab Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 1 Jun 2022 09:52:42 -0500 Subject: [PATCH 219/505] Rework yaml parsing error handling messages Simplify the YAML exception handling messages. There's no need to get each specific type of error as the base ruamel.yaml.YAMLError is enough and can also provide line numbers. Signed-off-by: Rob Herring --- tools/dt-doc-validate | 9 ++------- tools/dt-extract-example | 5 +++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/tools/dt-doc-validate b/tools/dt-doc-validate index 3a042eb9..e601f372 100755 --- a/tools/dt-doc-validate +++ b/tools/dt-doc-validate @@ -23,14 +23,9 @@ def check_doc(filename): ret = 0 try: testtree = dtschema.load(filename, line_number=line_number) - except (ruamel.yaml.scanner.ScannerError, ruamel.yaml.parser.ParserError) as exc: - print(filename + ": ", exc, file=sys.stderr) - return 1 except ruamel.yaml.YAMLError as exc: - print(filename + ":", exc.path[-1], exc.message, file=sys.stderr) - return 1 - except ruamel.yaml.constructor.DuplicateKeyError as exc: - print(filename + ":", exc.problem, file=sys.stderr) + print(filename + ":" + str(exc.problem_mark.line + 1) + ":" + + str(exc.problem_mark.column + 1) + ":", exc.problem, file=sys.stderr) return 1 try: diff --git a/tools/dt-extract-example b/tools/dt-extract-example index 0fba1126..e4c6c221 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -52,8 +52,9 @@ if __name__ == "__main__": binding = yaml.load(open(args.yamlfile, encoding='utf-8').read()) if not isinstance(binding, dict): exit(0) - except ruamel.yaml.constructor.DuplicateKeyError as exc: - print(args.yamlfile + ":", exc.problem, file=sys.stderr) + except ruamel.yaml.YAMLError as exc: + print(args.yamlfile + ":" + str(exc.problem_mark.line + 1) + ":" + + str(exc.problem_mark.column + 1) + ":", exc.problem, file=sys.stderr) exit(1) example_dts = example_header From 53e3f437ae30556c93ae375770908467db2319e2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 30 Mar 2022 10:15:23 -0500 Subject: [PATCH 220/505] meta-schemas: Ensure valid combinations of if/then/else schemas While json-schema meta-schema allows any combination of if/then/else to be present, only a subset makes sense. Wrong indentation is a common cause of invalid combinations. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 2c214f9e..1fc227f9 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -83,6 +83,16 @@ dependentSchemas: - required: [ properties ] - required: [ patternProperties ] +dependentRequired: + # Ensure only valid combinations of if/then/else are present + if: + - then + then: + - if + else: + - if + - then + properties: $ref: pattern: '^(/schemas/|\.\./|#(/|$)|[a-zA-Z0-9]+)' From d0035e3fbd30d746387029289a3acd0462d83f10 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 1 Apr 2022 08:50:13 -0500 Subject: [PATCH 221/505] meta-schemas: Ensure array lists have unique entries Once again, the json-schema meta-schema allows anything, but duplicate entries on these keywords is a sure sign of an error for us. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 1fc227f9..61520dd0 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -107,15 +107,22 @@ properties: - $ref: "#/definitions/sub-schemas" - type: boolean allOf: + uniqueItems: true items: $ref: "#/definitions/sub-schemas" anyOf: + uniqueItems: true items: $ref: "#/definitions/sub-schemas" contains: $ref: "#/definitions/sub-schemas" + dependentRequired: + uniqueItems: true else: $ref: "#/definitions/sub-schemas" + enum: + type: array + uniqueItems: true if: $ref: "#/definitions/sub-schemas" items: @@ -166,6 +173,7 @@ properties: $ref: "#/definitions/sub-schemas" required: type: array + uniqueItems: true items: pattern: '^([a-zA-Z#][a-zA-Z0-9,+\-._@]{0,63}|\$nodename)$' select: From a858f8b9c86ba273002b947cf6da28ea5303dae4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 13 Apr 2022 15:28:39 -0500 Subject: [PATCH 222/505] meta-schemas: Add check for array properties with a scalar type Scalar types should not have json-schema vocabulary for arrays such as 'minItems' and 'maxItems'. Add a meta-schema to check for this. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 14 ++++++++++++++ dtschema/schemas/dt-core.yaml | 3 +-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 61520dd0..ada4c749 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -188,3 +188,17 @@ properties: - type: boolean uniqueItems: type: boolean + +allOf: + - description: Scalar properties should not have array keywords + if: + properties: + $ref: + pattern: '(int[1-8]+|phandle|flag)$' + required: + - $ref + then: + properties: + maxItems: false + minItems: false + items: false diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 1bafff41..9efe165b 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -57,8 +57,7 @@ properties: patternProperties: "^#.*-cells$": $ref: "types.yaml#/definitions/uint32" - items: - maximum: 8 + maximum: 8 ".*-names$": $ref: "types.yaml#/definitions/non-unique-string-array" From 22ded98fb750ec4a1d45379ed56dcb4f6c947b70 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 3 May 2022 11:16:08 -0500 Subject: [PATCH 223/505] meta-schemas: Ensure items.yaml schema is applied at for all sub-schemas The items.yaml schema was not getting applied to if/then schemas. Move where it is referenced so it is applied for all sub-schemas. Signed-off-by: Rob Herring --- dtschema/meta-schemas/core.yaml | 1 - dtschema/meta-schemas/keywords.yaml | 1 + dtschema/schemas/isa/isa-bus.yaml | 2 -- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index c6902262..fcf932a3 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -79,7 +79,6 @@ definitions: pattern: '(#$|#\/)?' allOf: - - $ref: "items.yaml#" - if: type: object properties: diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index ada4c749..e6ed5960 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -12,6 +12,7 @@ definitions: sub-schemas: allOf: - $ref: "#" + - $ref: items.yaml# propertyNames: # The subset of keywords allowed for sub-schema enum: diff --git a/dtschema/schemas/isa/isa-bus.yaml b/dtschema/schemas/isa/isa-bus.yaml index d1ef316b..95a0e65f 100644 --- a/dtschema/schemas/isa/isa-bus.yaml +++ b/dtschema/schemas/isa/isa-bus.yaml @@ -47,8 +47,6 @@ patternProperties: - 0x1 # I/O address - description: address - description: size - minItems: 3 - maxItems: 3 required: - reg From 83d3175483092ea68cead2f2df91327894fb72a1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 27 Apr 2022 12:17:57 -0500 Subject: [PATCH 224/505] schemas: i2c: Add missing properties and descriptions Add remaining properties and descriptions from i2c.txt binding in Linux kernel tree. The Cc list are the authors of i2c.txt. Acked-by: Matt Johnston Acked-by: Dmitry Torokhov Acked-by: Alain Volmat Acked-by: Wolfram Sang Acked-by: Eugen Hristev Cc: Codrin Ciubotariu Cc: Jon Hunter Signed-off-by: Rob Herring --- dtschema/schemas/i2c/i2c-controller.yaml | 144 +++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index 91eac62a..86be59d7 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -1,5 +1,7 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2018 Linaro Ltd. +# Copyright 2015,2020 Wolfram Sang +# Copyright 2022 Arm Ltd. %YAML 1.2 --- $id: http://devicetree.org/schemas/i2c/i2c-controller.yaml# @@ -28,6 +30,91 @@ properties: minimum: 1000 maximum: 3000000 + i2c-scl-falling-time-ns: + description: + Number of nanoseconds the SCL signal takes to fall; t(f) in the I2C + specification. + + i2c-scl-internal-delay-ns: + description: + Number of nanoseconds the IP core additionally needs to setup SCL. + + i2c-scl-rising-time-ns: + description: + Number of nanoseconds the SCL signal takes to rise; t(r) in the I2C + specification. + + i2c-sda-falling-time-ns: + description: + Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C + specification. + + i2c-analog-filter: + type: boolean + description: + Enable analog filter for i2c lines. + + i2c-digital-filter: + type: boolean + description: + Enable digital filter for i2c lines. + + i2c-digital-filter-width-ns: + description: + Width of spikes which can be filtered by digital filter + (i2c-digital-filter). This width is specified in nanoseconds. + + i2c-analog-filter-cutoff-frequency: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Frequency that the analog filter (i2c-analog-filter) uses to distinguish + which signal to filter. Signal with higher frequency than specified will + be filtered out. Only lower frequency will pass (this is applicable to a + low-pass analog filter). Typical value should be above the normal i2c bus + clock frequency (clock-frequency). Specified in Hz. + + mctp-controller: + type: boolean + description: + Indicates that the system is accessible via this bus as an endpoint for + MCTP over I2C transport. + + multi-master: + type: boolean + description: + States that there is another master active on this bus. The OS can use + this information to adapt power management to keep the arbitration awake + all the time, for example. Can not be combined with 'single-master'. + + scl-gpios: + maxItems: 1 + description: + Specifies the GPIO related to SCL pin. Used for GPIO bus recovery. + + sda-gpios: + maxItems: 1 + description: + Specifies the GPIO related to SDA pin. Optional for GPIO bus recovery. + + single-master: + type: boolean + description: + States that there is no other master active on this bus. The OS can use + this information to detect a stalled bus more reliably, for example. Can + not be combined with 'multi-master'. + + smbus: + type: boolean + description: + States that additional SMBus restrictions and features apply to this bus. + An example of feature is SMBusHostNotify. Examples of restrictions are + more reserved addresses and timeout definitions. + + smbus-alert: + type: boolean + description: + states that the optional SMBus-Alert feature apply to this bus. + no-detect: type: boolean description: @@ -38,4 +125,61 @@ patternProperties: '@[0-9a-f]+$': type: object + properties: + reg: + items: + items: + - oneOf: + - maximum: 0x7f + - minimum: 0x40000000 + maximum: 0x4000007f + - minimum: 0x80000000 + maximum: 0x800003ff + - minimum: 0xc0000000 + maximum: 0xc00003ff + description: | + One or many I2C slave addresses. These are usually a 7 bit addresses. + However, flags can be attached to an address. I2C_TEN_BIT_ADDRESS is + used to mark a 10 bit address. It is needed to avoid the ambiguity + between e.g. a 7 bit address of 0x50 and a 10 bit address of 0x050 + which, in theory, can be on the same bus. + Another flag is I2C_OWN_SLAVE_ADDRESS to mark addresses on which we + listen to be devices ourselves. + + host-notify: + description: + Device uses SMBus host notify protocol instead of interrupt line. + Requires being connected to an adapter that supports this feature. + + interrupts: + description: + I2C core will treat "irq" interrupt (or the very first interrupt if + not using interrupt names) as primary interrupt for the slave. + + interrupt-names: + anyOf: + - {} # Any name is allowed. + - items: + enum: + - irq + - wakeup + - smbus_alert + description: + Names which are recognized by I2C core, other names are left to + individual bindings. + + wakeup-source: + description: + Device can be used as a wakeup source. The device should also have + "wakeup" interrupt for the device. If "wakeup" interrupt name is not + present in the binding, then primary interrupt will be used as wakeup + interrupt. + + required: + - reg + +dependentRequired: + i2c-analog-filter-cutoff-frequency: [ i2c-analog-filter ] + i2c-digital-filter-width-ns: [ i2c-digital-filter ] + additionalProperties: true From cd64f75fe09105247a6accefe96a607b0e839987 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 14 Jun 2022 13:09:27 -0600 Subject: [PATCH 225/505] meta-schemas: Allow 'deprecated' for boolean properties Signed-off-by: Rob Herring --- dtschema/meta-schemas/boolean.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/dtschema/meta-schemas/boolean.yaml b/dtschema/meta-schemas/boolean.yaml index 1821cc23..49688032 100644 --- a/dtschema/meta-schemas/boolean.yaml +++ b/dtschema/meta-schemas/boolean.yaml @@ -11,5 +11,6 @@ properties: const: boolean description: {} default: {} + deprecated: {} additionalProperties: false From 2f1adfa41a990ce789ea4f3ceb51e683b8948b90 Mon Sep 17 00:00:00 2001 From: ValentinGrim Date: Mon, 20 Jun 2022 11:45:23 +0200 Subject: [PATCH 226/505] schemas: i2c: Removing tab line 168 These tabs prevent YAML from being loaded inside a python script with PyYAML. Error "yaml.scanner.ScannerError: while scanning for the next token found character '\t' that cannot start any token" --- dtschema/schemas/i2c/i2c-controller.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index 86be59d7..91249154 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -165,7 +165,7 @@ patternProperties: - wakeup - smbus_alert description: - Names which are recognized by I2C core, other names are left to + Names which are recognized by I2C core, other names are left to individual bindings. wakeup-source: From c807aeb272cd4f726e91a5fe7edb64e2eb8712fa Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 28 Jun 2022 13:16:20 +0200 Subject: [PATCH 227/505] schemas: add dma-noncoherent property When using dma-coherent, the assumption is that the system is noncoherent in general with specific devices being coherent. Similarly there can be systems being coherent by default with specific devices being noncoherent. Add a 'dma-noncoherent' property to the schema which also got added to the specification. Signed-off-by: Heiko Stuebner --- dtschema/schemas/dt-core.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 9efe165b..e1475810 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -25,6 +25,8 @@ properties: $ref: "types.yaml#/definitions/string" dma-coherent: $ref: "types.yaml#/definitions/flag" + dma-noncoherent: + $ref: "types.yaml#/definitions/flag" dma-ranges: oneOf: - $ref: "types.yaml#/definitions/flag" From d1f3102e12921727b1329887127771d54deca9d1 Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Tue, 28 Jun 2022 17:29:31 +0300 Subject: [PATCH 228/505] dtschema: add nanoamp unit Signed-off-by: Cosmin Tanislav [robh: also update lib.py unit regex] Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- dtschema/meta-schemas/core.yaml | 2 +- dtschema/meta-schemas/vendor-props.yaml | 2 +- dtschema/schemas/property-units.yaml | 3 +++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 3483b45e..679f9f7e 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -231,7 +231,7 @@ def _fixup_int_matrix(subschema): int_array_re = re.compile('int(8|16|32|64)-array') -unit_types_re = re.compile('-(bits|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours|microvolt|picofarads|celsius|millicelsius|kpascal)$') +unit_types_re = re.compile('-(bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|(micro|nano)amp|(micro-)?ohms|micro(amp|watt)-hours|microvolt|picofarads|(milli)?celsius|kpascal)$') # Remove this once we remove array to matrix fixups known_array_props = {'assigned-clock-rates', 'linux,keycodes'} diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index fcf932a3..6621cdf8 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -58,7 +58,7 @@ definitions: propertyNames: enum: [ description, deprecated ] - '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kpascal)$': + '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|nanoamp|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kpascal)$': allOf: - $ref: "cell.yaml#/array" - description: Standard unit suffix properties don't need a type $ref diff --git a/dtschema/meta-schemas/vendor-props.yaml b/dtschema/meta-schemas/vendor-props.yaml index c2da5b6a..9cff2666 100644 --- a/dtschema/meta-schemas/vendor-props.yaml +++ b/dtschema/meta-schemas/vendor-props.yaml @@ -16,7 +16,7 @@ patternProperties: '-supply$': true '^rcar_sound,': true '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm)$': true - '-(microamp|microamp-hours|ohms|micro-ohms|microwatt-hours)$': true + '-(nanoamp|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours)$': true '-(microvolt|(femto|pico)farads|celsius|millicelsius|kpascal)$': true ",.*-names$": diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index da8b505f..4166d51e 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -71,6 +71,9 @@ patternProperties: "-microamp$": $ref: "types.yaml#/definitions/uint32-array" description: microampere + "-nanoamp$": + $ref: "types.yaml#/definitions/uint32-array" + description: nanoampere "-microamp-hours$": $ref: "types.yaml#/definitions/uint32-array" description: microampere hour From f5f03f655760e165c250aceac829fc3c4eddd43f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Jun 2022 10:29:23 -0600 Subject: [PATCH 229/505] Partially Revert "dtschema: add nanoamp unit" This partially reverts commit d1f3102e12921727b1329887127771d54deca9d1. There's already some uses of '-nanoamp' which have a type $ref. Those will have to be fixed before enabling this check. Signed-off-by: Rob Herring --- dtschema/meta-schemas/core.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index 6621cdf8..fcf932a3 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -58,7 +58,7 @@ definitions: propertyNames: enum: [ description, deprecated ] - '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|nanoamp|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kpascal)$': + '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kpascal)$': allOf: - $ref: "cell.yaml#/array" - description: Standard unit suffix properties don't need a type $ref From 8699fcbd5f6778c9991b80894efc0d4ff18cd37b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 5 Jul 2022 16:33:01 -0600 Subject: [PATCH 230/505] dtschema: Add 'max8997,pmic-buck.-dvs-voltage' properties to known array list These properties have an if/then schema that causes warnings because 'maxItems' alone is ambiguous. Need a better solution here if the list gets longer. Dropping the YAML encoded DT will probably help with a better solution. Signed-off-by: Rob Herring --- dtschema/lib.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 679f9f7e..bda87402 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -234,7 +234,14 @@ def _fixup_int_matrix(subschema): unit_types_re = re.compile('-(bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|(micro|nano)amp|(micro-)?ohms|micro(amp|watt)-hours|microvolt|picofarads|(milli)?celsius|kpascal)$') # Remove this once we remove array to matrix fixups -known_array_props = {'assigned-clock-rates', 'linux,keycodes'} +known_array_props = { + 'assigned-clock-rates', + 'linux,keycodes', + 'max8997,pmic-buck1-dvs-voltage', + 'max8997,pmic-buck2-dvs-voltage', + 'max8997,pmic-buck5-dvs-voltage', +} + def is_int_array_schema(propname, subschema): if 'allOf' in subschema: From a58e504b0bfbc28701287e769785b75150012201 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 5 Jul 2022 16:36:49 -0600 Subject: [PATCH 231/505] dtschema: Add a known variable sized matrix property list A few properties are used in multiple, separate schemas with differing dimensions. In this case, we need to give up with enforcing constraints on the dimensions. 'fsl,pins' is the only known one ATM. Signed-off-by: Rob Herring --- dtschema/lib.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index bda87402..635ee82b 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -214,16 +214,23 @@ def _is_matrix_schema(subschema): return False + +known_variable_matrix_props = { + 'fsl,pins', +} + + # If we have a matrix with variable inner and outer dimensions, then drop the dimensions # because we have no way to reconstruct them. -def _fixup_int_matrix(subschema): +def _fixup_int_matrix(propname, subschema): if not _is_matrix_schema(subschema): return outer_dim = _get_array_range(subschema) inner_dim = _get_array_range(subschema.get('items', {})) - if outer_dim[0] != outer_dim[1] and inner_dim[0] != inner_dim[1]: + if propname in known_variable_matrix_props or \ + (outer_dim[0] != outer_dim[1] and inner_dim[0] != inner_dim[1]): subschema.pop('items', None) subschema.pop('maxItems', None) subschema.pop('minItems', None) @@ -425,7 +432,7 @@ def fixup_vals(propname, schema): _fixup_reg_schema(propname, schema) _fixup_remove_empty_items(schema) - _fixup_int_matrix(schema) + _fixup_int_matrix(propname, schema) _fixup_int_array_min_max_to_matrix(propname, schema) _fixup_int_array_items_to_matrix(propname, schema) _fixup_string_to_array(propname, schema) From dca1f25316d80138f29e14e31c11ba8b1d1f6214 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 20 Dec 2021 10:07:42 -0600 Subject: [PATCH 232/505] dtschema: Strip 'additionalProperties: true' from schemas An 'additionalProperties: true' makes all properties evaluated, so an 'unevaluatedProperties: false' schema doesn't work when referencing a schema with 'additionalProperties: true'. Really, 'additionalProperties: true' should be dropped, but it is used as a flag for common schemas which are usually incomplete and included by device specific schemas. Removing it would mean dropping the meta-schema requiring either 'additionalProperties' or 'unevaluatedProperties'. Signed-off-by: Rob Herring --- dtschema/lib.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index 635ee82b..5dcb05fa 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -473,6 +473,11 @@ def fixup_sub_schema(schema, is_prop): if not isinstance(schema, dict): return + # 'additionalProperties: true' doesn't work with 'unevaluatedProperties', so + # remove it. It's in the schemas for common (incomplete) schemas. + if 'additionalProperties' in schema and schema['additionalProperties'] == True: + schema.pop('additionalProperties', None) + schema.pop('description', None) fixup_interrupts(schema) if is_prop: From fd1b64f546db9ecf76c55249589a5b13c83641d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Tue, 5 Jul 2022 20:01:14 +0200 Subject: [PATCH 233/505] schemas: simple-bus: support 'localbus' node name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Existing FSL device-trees use 'localbus' node name for nodes containing "simple-bus" compatible. Signed-off-by: Marek Behún --- dtschema/schemas/simple-bus.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/simple-bus.yaml b/dtschema/schemas/simple-bus.yaml index 2a70acaf..42a7504d 100644 --- a/dtschema/schemas/simple-bus.yaml +++ b/dtschema/schemas/simple-bus.yaml @@ -14,7 +14,7 @@ maintainers: properties: $nodename: - pattern: "^([a-z][a-z0-9\\-]+-bus|bus|soc|axi|ahb|apb)(@[0-9a-f]+)?$" + pattern: "^([a-z][a-z0-9\\-]+-bus|bus|localbus|soc|axi|ahb|apb)(@[0-9a-f]+)?$" compatible: contains: const: simple-bus From e83694e0905b5f9b2600f19933c2a7a178d5b9e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Tue, 5 Jul 2022 19:56:27 +0200 Subject: [PATCH 234/505] schemas: simple-bus: drop checking of unit-address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop unit-address checking of simple-bus and let parent bus do it. Some simple-busses have multiple address cells separated by commas in the unit-address part. Signed-off-by: Marek Behún --- dtschema/schemas/simple-bus.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/simple-bus.yaml b/dtschema/schemas/simple-bus.yaml index 42a7504d..8a78091a 100644 --- a/dtschema/schemas/simple-bus.yaml +++ b/dtschema/schemas/simple-bus.yaml @@ -14,7 +14,7 @@ maintainers: properties: $nodename: - pattern: "^([a-z][a-z0-9\\-]+-bus|bus|localbus|soc|axi|ahb|apb)(@[0-9a-f]+)?$" + pattern: "^([a-z][a-z0-9\\-]+-bus|bus|localbus|soc|axi|ahb|apb)(@.+)?$" compatible: contains: const: simple-bus From ea47a21d29b40a3a4bb3cee7eff5e4d84988fe23 Mon Sep 17 00:00:00 2001 From: sean-anderson-seco <74551845+sean-anderson-seco@users.noreply.github.com> Date: Mon, 11 Jul 2022 16:10:44 -0400 Subject: [PATCH 235/505] Escape $defs in vendor-props.yaml $ will match the end of the property, ensuring that $defs will never be matched. Fix this by escaping it. Signed-off-by: Sean Anderson --- dtschema/meta-schemas/vendor-props.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/vendor-props.yaml b/dtschema/meta-schemas/vendor-props.yaml index 9cff2666..a89dfae0 100644 --- a/dtschema/meta-schemas/vendor-props.yaml +++ b/dtschema/meta-schemas/vendor-props.yaml @@ -76,7 +76,7 @@ additionalProperties: - description: A vendor property can have a $ref to a a $defs schema properties: # A property with a type and additional constraints $ref: - pattern: "^#\/(definitions|$defs)\/" + pattern: "^#\/(definitions|\\$defs)\/" required: [ $ref ] ... From e9b21019cdd9ffeb835f0b1d765fcf87a119c8fe Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 14 Jul 2022 09:41:40 -0600 Subject: [PATCH 236/505] meta-schemas: Allow 'default' on string array types Allow 'default' on string array types. Signed-off-by: Rob Herring --- dtschema/meta-schemas/string-array.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/dtschema/meta-schemas/string-array.yaml b/dtschema/meta-schemas/string-array.yaml index a113cc78..a7ee4011 100644 --- a/dtschema/meta-schemas/string-array.yaml +++ b/dtschema/meta-schemas/string-array.yaml @@ -52,6 +52,7 @@ all-properties: pattern: '^[a-zA-Z0-9,.\-_ #+/]+$' contains: $ref: '#/all-properties' + default: {} deprecated: {} pattern: type: string From 20107d373f69c188aaaa0a58f8274a026937403d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 14 Jul 2022 09:42:58 -0600 Subject: [PATCH 237/505] schemas: core: Allow 'compatible' strings to start with a number There's a few vendor prefixes that start with a number, so allow this for compatible strings. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index e1475810..1766fd00 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -20,7 +20,7 @@ properties: compatible: $ref: "types.yaml#/definitions/string-array" items: - pattern: "^[a-zA-Z][a-zA-Z0-9,+\\-._]+$" + pattern: "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]+$" label: $ref: "types.yaml#/definitions/string" dma-coherent: From 43d0bd2f7970ef22c7254e261a7199e6f56133a6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 15 Jul 2022 08:25:04 -0600 Subject: [PATCH 238/505] schemas: i2c: Add missing boolean type to 'host-notify' 'host-notify' is missing a type definition, so add it. Signed-off-by: Rob Herring --- dtschema/schemas/i2c/i2c-controller.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index 91249154..1f97a736 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -147,6 +147,7 @@ patternProperties: listen to be devices ourselves. host-notify: + type: boolean description: Device uses SMBus host notify protocol instead of interrupt line. Requires being connected to an adapter that supports this feature. From 2c03cbcc962b9f9c3890e61cafc56f782da141e9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 15 Jul 2022 08:29:31 -0600 Subject: [PATCH 239/505] dtschema: Add missing kBps, milliwatt, and microwatt unit suffixes for fixups The unit suffix regex for the fixups is missing a few units. Add kBps, milliwatt, and microwatt unit suffixes. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 5dcb05fa..31b7a9df 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -238,7 +238,7 @@ def _fixup_int_matrix(propname, subschema): int_array_re = re.compile('int(8|16|32|64)-array') -unit_types_re = re.compile('-(bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|(micro|nano)amp|(micro-)?ohms|micro(amp|watt)-hours|microvolt|picofarads|(milli)?celsius|kpascal)$') +unit_types_re = re.compile('-(kBps|bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|microvolt|picofarads|(milli)?celsius|kpascal)$') # Remove this once we remove array to matrix fixups known_array_props = { From 055ea514d445de17599f67aab5cef5863b8d2a6d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 15 Jul 2022 13:16:09 -0600 Subject: [PATCH 240/505] Rework load_schema/process_schemas/set_schema to single 'set_schemas' API Currently, a different API is exposed depending on whether a pre-processed schema file or unprocessed schemas files are used. Rework the interface for loading schemas to be unified whether passing a single pre-processed schema file or a list of files/directories of schemas. This ensures the schemas are passed to dtschema module for subsequent calls to get type or other information from the schemas. Signed-off-by: Rob Herring --- dtschema/__init__.py | 3 +-- dtschema/lib.py | 20 ++++++++++++-------- test/test-dt-validate.py | 3 +-- tools/dt-extract-props | 11 +++-------- tools/dt-mk-schema | 2 +- tools/dt-validate | 12 ++++-------- tools/dtb2py | 8 ++++---- 7 files changed, 26 insertions(+), 33 deletions(-) diff --git a/dtschema/__init__.py b/dtschema/__init__.py index f4fc8768..5442eb8c 100644 --- a/dtschema/__init__.py +++ b/dtschema/__init__.py @@ -2,8 +2,7 @@ add_schema_path, load_schema, load, - process_schemas, - set_schema, + set_schemas, DTValidator, format_error, extract_compatibles, diff --git a/dtschema/lib.py b/dtschema/lib.py index 31b7a9df..09cd6bd9 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -893,22 +893,20 @@ def _extract_subschema_types(props, schema, subschema): _extract_prop_type(props, schema, p, v) -def extract_types(schemas): - if not isinstance(schemas, list): - return +def extract_types(): + global schema_cache props = {} - for sch in schemas: + for sch in schema_cache: _extract_subschema_types(props, sch, sch) return props def get_prop_types(): - global schema_cache pat_props = {} - props = dtschema.extract_types(schema_cache) + props = dtschema.extract_types() # hack to remove aliases pattern del props['^[a-z][a-z0-9\-]*$'] @@ -940,10 +938,16 @@ def load(filename, line_number=False): schema_cache = [] -def set_schema(schemas): +def set_schemas(schema_files, core_schema=True): global schema_cache - schema_cache = schemas + if len(schema_files) == 1 and os.path.isfile(schema_files[0]): + # a processed schema file + schema_cache = dtschema.load_schema(os.path.abspath(schema_files[0])) + else: + schema_cache = process_schemas(schema_files, core_schema) + + return schema_cache def http_handler(uri): global schema_cache diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index e4283f16..4f3f80ad 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -103,8 +103,7 @@ class TestDTValidate(unittest.TestCase): def setUp(self): self.schemas = list() - self.schemas = dtschema.process_schemas([ os.path.join(os.path.abspath(basedir), "schemas/")]) - dtschema.set_schema(self.schemas) + self.schemas = dtschema.set_schemas([ os.path.join(os.path.abspath(basedir), "schemas/")]) for schema in self.schemas: schema["$select_validator"] = dtschema.DTValidator(schema['select']) diff --git a/tools/dt-extract-props b/tools/dt-extract-props index b7fd42c2..4f1deda5 100755 --- a/tools/dt-extract-props +++ b/tools/dt-extract-props @@ -21,20 +21,15 @@ strict = False if __name__ == "__main__": ap = argparse.ArgumentParser() ap.add_argument("schema_files", type=str, nargs='*', - help="Schema directories and/or files") + help="preparsed schema file or list of additional schema files/directories") ap.add_argument('-d', '--duplicates', help="Only output properties with more than one type", action="store_true") ap.add_argument('-v', '--verbose', help="Additional search path for references", action="store_true") ap.add_argument('-V', '--version', help="Print version number", action="version", version=dtschema.__version__) args = ap.parse_args() - if os.path.isfile(args.schema_files[0]): - schemas = dtschema.load_schema(os.path.abspath(args.schema_files[0])) - else: - schemas = dtschema.process_schemas(args.schema_files) - dtschema.set_schema(schemas) - - props = dtschema.extract_types(schemas) + dtschema.set_schemas(args.schema_files) + props = dtschema.extract_types() if args.duplicates: tmp_props = {} diff --git a/tools/dt-mk-schema b/tools/dt-mk-schema index cdb2b2ca..7ee3267f 100755 --- a/tools/dt-mk-schema +++ b/tools/dt-mk-schema @@ -35,7 +35,7 @@ if __name__ == "__main__": action="version", version=dtschema.__version__) args = ap.parse_args() - schemas = dtschema.process_schemas(args.schemas, core_schema=(not args.useronly)) + schemas = dtschema.set_schemas(args.schemas, core_schema=(not args.useronly)) if not schemas: exit(-1) diff --git a/tools/dt-validate b/tools/dt-validate index 38f2c0ea..ec1401bc 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -27,14 +27,10 @@ class schema_group(): def __init__(self, schema_file=""): self.schemas = list() - if schema_file == "" or os.path.isdir(schema_file): - self.schemas = dtschema.process_schemas([schema_file]) - elif os.path.isfile(schema_file): - self.schemas = dtschema.load_schema(os.path.abspath(schema_file)) - else: + if schema_file != "" and not os.path.exists(schema_file): exit(-1) - dtschema.set_schema(self.schemas) + self.schemas = dtschema.set_schemas([schema_file]) def check_node(self, tree, node, disabled, nodename, fullname, filename): # Skip any generated nodes @@ -127,8 +123,8 @@ if __name__ == "__main__": epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("yamldt", nargs='*', help="Filename or directory of YAML encoded devicetree input file(s)") - ap.add_argument('-s', '--schema', help="path to additional additional schema files") - ap.add_argument('-p', '--preparse', help="preparsed schema file") + ap.add_argument('-s', '--schema', help="preparsed schema file or path to schema files") + ap.add_argument('-p', '--preparse', help="preparsed schema file (deprecated, use '-s')") ap.add_argument('-l', '--limit', help="limit validation to schema files matching substring") ap.add_argument('-m', '--show-unmatched', default=0, help="Print out nodes which don't match any schema.\n" \ diff --git a/tools/dtb2py b/tools/dtb2py index 505b9ed2..151fe1c6 100755 --- a/tools/dtb2py +++ b/tools/dtb2py @@ -22,11 +22,11 @@ if __name__ == "__main__": if not os.path.isfile(args.dtbfile): exit(1) - if os.path.isfile(args.schema): - schemas = dtschema.load_schema(os.path.abspath(args.schema)) + if args.schema: + schemas = [args.schemas] else: - schemas = dtschema.process_schemas([args.schema]) - dtschema.set_schema(schemas) + schemas = [] + dtschema.set_schemas(schemas) dt = dtschema.load(args.dtbfile) From 848e7bc96c1bcd965fd9e0aad753c7ebd0fdd7c1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 18 Jul 2022 08:49:28 -0600 Subject: [PATCH 241/505] dtschema: Fix generated compatible list schema The generated compatible schema must exclude the generic compatible pattern. Commit 20107d373f69 ("schemas: core: Allow 'compatible' strings to start with a number") changed the pattern, but didn't update the exclusion. Fixes: 20107d373f69 ("schemas: core: Allow 'compatible' strings to start with a number") Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- dtschema/schemas/dt-core.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 09cd6bd9..9fddcfa5 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -685,7 +685,7 @@ def make_compatible_schema(schemas): for c in compatible_list: if prog.match(c): # Exclude the generic pattern - if c != '^[a-zA-Z][a-zA-Z0-9,+\-._]+$': + if c != '^[a-zA-Z0-9][a-zA-Z0-9,+\-._]+$': compat_sch += [{'pattern': c}] else: compat_sch[0]['enum'].append(c) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 1766fd00..1622ca0e 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -20,6 +20,7 @@ properties: compatible: $ref: "types.yaml#/definitions/string-array" items: + # Keep in sync with make_compatible_schema() pattern: "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]+$" label: $ref: "types.yaml#/definitions/string" From 109bde712466281e8c96a4fadb0f68e7a90a6eca Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 20 Jul 2022 09:18:14 -0600 Subject: [PATCH 242/505] schemas: pci: Add msi-map properties msi-map/msi-map-mask properties are existing properties and are only for PCI root complexes, so add them to the PCI schema. Signed-off-by: Rob Herring --- dtschema/schemas/pci/pci-bus.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/dtschema/schemas/pci/pci-bus.yaml b/dtschema/schemas/pci/pci-bus.yaml index 421c6099..31bc1b99 100644 --- a/dtschema/schemas/pci/pci-bus.yaml +++ b/dtschema/schemas/pci/pci-bus.yaml @@ -113,6 +113,22 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 enum: [ 1, 2, 3, 4 ] + msi-map: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + items: + minItems: 3 + items: + - description: The RID base matched by the entry + - description: phandle to msi-controller node + - description: (optional) The msi-specifier produced for the first RID matched + by the entry. Currently, msi-specifier is 0 or 1 cells. + - description: The length of consecutive RIDs following the RID base + + msi-map-mask: + description: A mask to be applied to each Requester ID prior to being + mapped to an msi-specifier per the msi-map property. + $ref: /schemas/types.yaml#/definitions/uint32 + num-lanes: description: The number of PCIe lanes $ref: /schemas/types.yaml#/definitions/uint32 @@ -166,4 +182,7 @@ required: - "#address-cells" - "#size-cells" +dependentRequired: + msi-map-mask: [ msi-map ] + additionalProperties: true From 5bc0e9a2067a78a5a2d2b0e78abf7d9844333791 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 20 Jul 2022 09:19:25 -0600 Subject: [PATCH 243/505] schemas: phy: Add 'phy-type' property 'phy-type' is an already used property for phy providers which support multiple possible modes. Signed-off-by: Rob Herring --- dtschema/schemas/phy/phy-provider.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dtschema/schemas/phy/phy-provider.yaml b/dtschema/schemas/phy/phy-provider.yaml index a7de9c34..9b901a54 100644 --- a/dtschema/schemas/phy/phy-provider.yaml +++ b/dtschema/schemas/phy/phy-provider.yaml @@ -16,9 +16,21 @@ properties: phy-supply: true + phy-type: + description: Some PHYs can operate in multiple modes. This sets the operating + mode of the PHY. This only works for PHY providers with a single PHY as + this only allows 1 mode. For instances with multiple PHYs, the mode can be + set in the PHY cells. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 11 + required: - "#phy-cells" +dependentRequired: + phy-type: [ '#phy-cells' ] + additionalProperties: true ... From 08f78227e5c153c90e2b74a7d60e8c0ad3a853ff Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 20 Jul 2022 09:21:16 -0600 Subject: [PATCH 244/505] schemas: Add '-kelvin' unit suffix We already have Celsius, but '-kelvin' is already in use, too. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- dtschema/meta-schemas/core.yaml | 2 +- dtschema/meta-schemas/vendor-props.yaml | 2 +- dtschema/schemas/property-units.yaml | 3 +++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 9fddcfa5..b1f671fc 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -238,7 +238,7 @@ def _fixup_int_matrix(propname, subschema): int_array_re = re.compile('int(8|16|32|64)-array') -unit_types_re = re.compile('-(kBps|bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|microvolt|picofarads|(milli)?celsius|kpascal)$') +unit_types_re = re.compile('-(kBps|bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|microvolt|picofarads|(milli)?celsius|kelvin|kpascal)$') # Remove this once we remove array to matrix fixups known_array_props = { diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index fcf932a3..61987295 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -58,7 +58,7 @@ definitions: propertyNames: enum: [ description, deprecated ] - '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kpascal)$': + '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kelvin|kpascal)$': allOf: - $ref: "cell.yaml#/array" - description: Standard unit suffix properties don't need a type $ref diff --git a/dtschema/meta-schemas/vendor-props.yaml b/dtschema/meta-schemas/vendor-props.yaml index a89dfae0..de884f64 100644 --- a/dtschema/meta-schemas/vendor-props.yaml +++ b/dtschema/meta-schemas/vendor-props.yaml @@ -17,7 +17,7 @@ patternProperties: '^rcar_sound,': true '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm)$': true '-(nanoamp|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours)$': true - '-(microvolt|(femto|pico)farads|celsius|millicelsius|kpascal)$': true + '-(microvolt|(femto|pico)farads|celsius|millicelsius|kelvin|kpascal)$': true ",.*-names$": type: object diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index 4166d51e..546fcd5c 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -109,6 +109,9 @@ patternProperties: "-millicelsius$": $ref: "types.yaml#/definitions/uint32-array" description: millidegree Celsius + "-kelvin$": + $ref: "types.yaml#/definitions/uint32-array" + description: SI unit of thermodynamic temperature # Pressure "-kpascal$": From 85321380fdb2add08e1ada4c6d057406c7e63e6c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 18 Jul 2022 16:19:01 -0600 Subject: [PATCH 245/505] dtschema: Stop guessing on which properties are patternProperties Some patternProperties are just fixed strings, so trying to figure out which properties are a pattern from the property strings having regex characters isn't completely accurate. As we already know this information when parsing the schemas, just pass it along and add a 'regex' entry for patternProperties. Signed-off-by: Rob Herring --- dtschema/lib.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index b1f671fc..47ffec76 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -805,7 +805,7 @@ def _merge_dim(dim1, dim2): type_re = re.compile('(flag|u?int(8|16|32|64)(-(array|matrix))?|string(-array)?|phandle(-array)?)') -def _extract_prop_type(props, schema, propname, subschema): +def _extract_prop_type(props, schema, propname, subschema, is_pattern): if not isinstance(subschema, dict): return @@ -819,7 +819,7 @@ def _extract_prop_type(props, schema, propname, subschema): for p in sch_path: subschema = subschema[p] #print(propname, sch_path, subschema, file=sys.stderr) - _extract_prop_type(props, schema, propname, subschema) + _extract_prop_type(props, schema, propname, subschema, is_pattern) try: prop_type = type_re.search(subschema['$ref']).group(0) @@ -843,6 +843,8 @@ def _extract_prop_type(props, schema, propname, subschema): if prop_type: props.setdefault(propname, {}) + if is_pattern: + props[propname].setdefault('regex', re.compile(propname)) if prop_type == 'phandle-array' or prop_type.endswith('-matrix'): dim = (_get_array_range(subschema), _get_array_range(subschema.get('items', {}))) @@ -877,7 +879,7 @@ def _extract_prop_type(props, schema, propname, subschema): for k in subschema.keys() & {'allOf', 'oneOf', 'anyOf'}: for v in subschema[k]: - _extract_prop_type(props, schema, propname, v) + _extract_prop_type(props, schema, propname, v, is_pattern) def _extract_subschema_types(props, schema, subschema): @@ -890,7 +892,7 @@ def _extract_subschema_types(props, schema, subschema): for k in subschema.keys() & {'properties', 'patternProperties'}: if isinstance(subschema[k], dict): for p,v in subschema[k].items(): - _extract_prop_type(props, schema, p, v) + _extract_prop_type(props, schema, p, v, k == 'patternProperties') def extract_types(): @@ -915,10 +917,11 @@ def get_prop_types(): for key in [key for key in props if 'type' not in props[key] ]: del props[key] # Split out pattern properties - for key in [key for key in props if re.fullmatch('(^\^.*|.*\$$|.*[*[].*)', key) ]: - #print(key, props[key]) - pat_props[key] = props[key] - pat_props[key]['regex'] = re.compile(key) + for key in [key for key in props if 'regex' in props[key] ]: + # Only want patternProperties with type and some amount of fixed string + if 'type' in props[key] and re.search(r'[0-9a-zA-F]{2}', key): + #print(key, props[key], file=sys.stderr) + pat_props[key] = props[key] del props[key] return [ props, pat_props ] From b0f5103c428478fb44cc479cf223a262a062ada7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 30 Sep 2021 17:31:01 -0500 Subject: [PATCH 246/505] dtschema: Make the list of schemas a dict instead As we need to retrieve schemas by $id, it makes more sense to use a dict with $id as the key instead of a list to store the schemas. Since the dt-mk-schema output is also the same format, we need to be able to read old format which is easy to detect and translate. Signed-off-by: Rob Herring --- dtschema/lib.py | 37 +++++++++++++++++++++---------------- test/test-dt-validate.py | 6 +++--- tools/dt-validate | 6 ++---- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 47ffec76..7c88793c 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -675,7 +675,7 @@ def fixup_interrupts(schema): def make_compatible_schema(schemas): compat_sch = [{'enum': []}] compatible_list = set() - for sch in schemas: + for sch in schemas.values(): compatible_list |= extract_compatibles(sch) # Allow 'foo' values for examples @@ -691,7 +691,7 @@ def make_compatible_schema(schemas): compat_sch[0]['enum'].append(c) compat_sch[0]['enum'].sort() - schemas += [{ + schemas['generated-compatibles'] = { '$id': 'generated-compatibles', '$filename': 'Generated schema of documented compatible strings', 'select': True, @@ -702,7 +702,7 @@ def make_compatible_schema(schemas): } } } - }] + } def process_schema(filename): @@ -735,8 +735,7 @@ def process_schema(filename): def process_schemas(schema_paths, core_schema=True): - ids = [] - schemas = [] + schemas = {} for filename in schema_paths: if not os.path.isfile(filename): @@ -744,10 +743,10 @@ def process_schemas(schema_paths, core_schema=True): sch = process_schema(os.path.abspath(filename)) if not sch: continue - schemas.append(sch) - if ids.count(sch['$id']): + if sch['$id'] in schemas: print(os.path.abspath(filename) + ": duplicate '$id' value '" + sch['$id'] + "'", file=sys.stderr) - ids.append(sch['$id']) + else: + schemas[sch['$id']] = sch if core_schema: schema_paths.append(os.path.join(schema_basedir, 'schemas/')) @@ -761,10 +760,10 @@ def process_schemas(schema_paths, core_schema=True): sch = process_schema(os.path.abspath(filename)) if sch: count += 1 - schemas.append(sch) - if ids.count(sch['$id']): + if sch['$id'] in schemas: print(os.path.abspath(filename) + ": duplicate '$id' value '" + sch['$id'] + "'", file=sys.stderr) - ids.append(sch['$id']) + else: + schemas[sch['$id']] = sch if count == 0: print("warning: no schema found in path: %s" % path, file=sys.stderr) @@ -899,7 +898,7 @@ def extract_types(): global schema_cache props = {} - for sch in schema_cache: + for sch in schema_cache.values(): _extract_subschema_types(props, sch, sch) return props @@ -938,7 +937,7 @@ def load(filename, line_number=False): return yaml.load(f.read()) -schema_cache = [] +schema_cache = {} def set_schemas(schema_files, core_schema=True): @@ -947,6 +946,12 @@ def set_schemas(schema_files, core_schema=True): if len(schema_files) == 1 and os.path.isfile(schema_files[0]): # a processed schema file schema_cache = dtschema.load_schema(os.path.abspath(schema_files[0])) + # Convert old format to new + if isinstance(schema_cache, list): + d = {} + for sch in schema_cache: + d[sch['$id']] = sch + schema_cache = d else: schema_cache = process_schemas(schema_files, core_schema) @@ -957,9 +962,9 @@ def http_handler(uri): '''Custom handler for http://devicetre.org YAML references''' try: if schema_base_url in uri: - for sch in schema_cache: - if uri in sch['$id']: - return sch + my_uri = uri + '#' + if my_uri in schema_cache: + return schema_cache[my_uri] # If we have a schema_cache, then the schema should have been there unless the schema had errors if len(schema_cache): return False diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index 4f3f80ad..b22803a3 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -105,7 +105,7 @@ def setUp(self): self.schemas = dtschema.set_schemas([ os.path.join(os.path.abspath(basedir), "schemas/")]) - for schema in self.schemas: + for schema in self.schemas.values(): schema["$select_validator"] = dtschema.DTValidator(schema['select']) def check_node(self, nodename, node, fail): @@ -117,13 +117,13 @@ def check_node(self, nodename, node, fail): if fail: node_matched = False with self.assertRaises(jsonschema.ValidationError, msg=nodename): - for schema in self.schemas: + for schema in self.schemas.values(): if schema['$select_validator'].is_valid(node): node_matched = True dtschema.DTValidator(schema).validate(node) else: node_matched = False - for schema in self.schemas: + for schema in self.schemas.values(): if schema['$select_validator'].is_valid(node): node_matched = True self.assertIsNone(dtschema.DTValidator(schema).validate(node)) diff --git a/tools/dt-validate b/tools/dt-validate index ec1401bc..9e4b113a 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -25,8 +25,6 @@ match_schema_file = None class schema_group(): def __init__(self, schema_file=""): - self.schemas = list() - if schema_file != "" and not os.path.exists(schema_file): exit(-1) @@ -37,7 +35,7 @@ class schema_group(): node['$nodename'] = [ nodename ] node_matched = False matched_schemas = [] - for schema in self.schemas: + for schema in self.schemas.values(): if '$select_validator' in schema and schema['$select_validator'].is_valid(node): # We have a match if a conditional schema is selected if schema['select'] != True: @@ -110,7 +108,7 @@ class schema_group(): def check_trees(self, filename, dt): """Check the given DT against all schemas""" - for schema in self.schemas: + for schema in self.schemas.values(): if match_schema_file and match_schema_file not in schema['$filename']: continue schema["$select_validator"] = dtschema.DTValidator(schema['select']) From fb821bbbee5ae9eee36fa4d9668602238b2548b1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 28 Jun 2022 14:20:40 -0600 Subject: [PATCH 247/505] Add dt-check-compatible tool to check compatible strings Add a new tool, dt-check-compatible, which will check a list of compatible strings for matching or not matching in schemas. Signed-off-by: Rob Herring --- dtschema/__init__.py | 1 + dtschema/lib.py | 12 ++++++++++++ setup.py | 1 + tools/dt-check-compatible | 40 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+) create mode 100755 tools/dt-check-compatible diff --git a/dtschema/__init__.py b/dtschema/__init__.py index 5442eb8c..696cce2c 100644 --- a/dtschema/__init__.py +++ b/dtschema/__init__.py @@ -8,6 +8,7 @@ extract_compatibles, extract_types, get_prop_types, + get_undocumented_compatibles, sized_int, ) diff --git a/dtschema/lib.py b/dtschema/lib.py index 7c88793c..3def7b6b 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -705,6 +705,18 @@ def make_compatible_schema(schemas): } +def get_undocumented_compatibles(compatible_list): + global schema_cache + undoc_compats = [] + + validator = dtschema.DTValidator(schema_cache['generated-compatibles']) + for compat in compatible_list: + if not validator.is_valid({"compatible": [ compat ]}): + undoc_compats += [ compat ] + + return undoc_compats + + def process_schema(filename): try: schema = load_schema(filename) diff --git a/setup.py b/setup.py index db8a2637..62db8afc 100755 --- a/setup.py +++ b/setup.py @@ -37,6 +37,7 @@ package_data={'dtschema': data_files}, scripts=[ + 'tools/dt-check-compatible', 'tools/dt-validate', 'tools/dt-doc-validate', 'tools/dt-mk-schema', diff --git a/tools/dt-check-compatible b/tools/dt-check-compatible new file mode 100755 index 00000000..433dbe24 --- /dev/null +++ b/tools/dt-check-compatible @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2022 Arm Ltd. + +import signal + +def sigint_handler(signum, frame): + sys.exit(-2) + +signal.signal(signal.SIGINT, sigint_handler) + +import sys +import os +import argparse + +import dtschema + +if __name__ == "__main__": + ap = argparse.ArgumentParser(fromfile_prefix_chars='@', + epilog='Arguments can also be passed in a file prefixed with a "@" character.') + ap.add_argument("compatible_str", nargs='+', + help="1 or more compatible strings to check for a match") + ap.add_argument('-v', '--invert-match', action="store_true", + help="invert sense of matching, printing compatible which don't match") + ap.add_argument('-V', '--version', help="Print version number", + action="version", version=dtschema.__version__) + ap.add_argument('-s', '--schema', required=True, help="path to processed schema file or schema directory") + args = ap.parse_args() + + if args.schema != "" and not os.path.exists(args.schema): + exit(-1) + + dtschema.set_schemas([args.schema]) + + undoc_compats = dtschema.get_undocumented_compatibles(args.compatible_str) + + if args.invert_match: + print(*undoc_compats, sep="\n") + else: + print(*set(args.compatible_str).difference(undoc_compats), sep="\n") From 2c953c7e337701d1dfa93323b58c8de06d73d7fc Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 12 Apr 2022 10:37:44 -0500 Subject: [PATCH 248/505] Rework property type data structure and interface The interface to get property type information exposes the data structure which doesn't work well when there are multiple types. Rework the interface to not expose the data structure and instead provide methods to retrieve the type(s) and matrix dimensions. Signed-off-by: Rob Herring --- dtschema/__init__.py | 3 +- dtschema/dtb.py | 90 ++++++++------------ dtschema/lib.py | 189 ++++++++++++++++++++++++++++------------- tools/dt-extract-props | 10 +-- 4 files changed, 173 insertions(+), 119 deletions(-) diff --git a/dtschema/__init__.py b/dtschema/__init__.py index 696cce2c..cb1e4094 100644 --- a/dtschema/__init__.py +++ b/dtschema/__init__.py @@ -7,8 +7,9 @@ format_error, extract_compatibles, extract_types, - get_prop_types, get_undocumented_compatibles, + property_get_type, + property_get_type_dim, sized_int, ) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 45f8a01e..8505cfca 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -11,9 +11,6 @@ import dtschema -props = {} -pat_props = {} - u8 = struct.Struct('B') s8 = struct.Struct('b') u16 = struct.Struct('>H') @@ -79,58 +76,46 @@ def prop_value(nodename, p): if nodename in {'__fixups__', 'aliases'}: return data[:-1].decode(encoding='ascii').split('\0') - if p.name in props: - v = props[p.name] - if {'string', 'string-array'} & set(v['type']): - #print(p.name, v) + prop_types = dtschema.property_get_type(p.name) + if 'node' in prop_types: + prop_types.remove('node') + + if len(prop_types) > 1: + if {'string', 'string-array'} & set(prop_types): str = bytes_to_string(data) if str: return str # Assuming only one other type try: - fmt = set(v['type']).difference({'string', 'string-array'}).pop() + fmt = set(prop_types).difference({'string', 'string-array'}).pop() except: return data - elif len(v['type']): - fmt = v['type'][0] - # properties like ranges can be boolean or have a value - if fmt == 'flag' and len(data) and len(v['type']) > 1: - fmt = v['type'][1] - if (fmt.endswith('matrix') or fmt == 'phandle-array') and 'dim' in v: - dim = v['dim'] - #print(p.name, fmt) - else: - for pat, v in pat_props.items(): - if v['regex'].search(p.name): - #print(p.name, v, file=sys.stderr) - if fmt and fmt != v['type'][0]: - #print('Multiple regex match with differring types:', fmt, v['type'][0], pat, file=sys.stderr) - if len(data) > 4 and '-' in fmt: - continue - fmt = v['type'][0] - fmt_base = fmt.split('-', 1)[0] - if fmt_base in type_format: - if (fmt.endswith('matrix') or fmt == 'phandle-array') and 'dim' in v: - dim = v['dim'] - continue - elif 'string' in v['type'][0]: - return data[:-1].decode(encoding='ascii').split('\0') + elif 'flag' in prop_types and len(data): + fmt = set(prop_types).difference({'flag'}).pop() else: - if not fmt: - # Primarily for aliases properties - try: - s = data.decode(encoding='ascii') - if s.endswith('\0'): - s = s[:-1] - if s.isprintable(): - return [s] - except: - pass - if not len(data) % 4: - fmt = 'uint32-array' - else: - #print(p.name + ': no type found', file=sys.stderr) - return data + #print(p.name + ': multiple types found', file=sys.stderr) + fmt = None + elif len(prop_types) == 1: + fmt = prop_types[0] + + if not fmt: + # Primarily for aliases properties + try: + s = data.decode(encoding='ascii') + if s.endswith('\0'): + s = s[:-1] + if s.isprintable(): + return [s] + except: + pass + if not len(data) % 4: + fmt = 'uint32-array' + else: + #print(p.name + ': no type found', file=sys.stderr) + return data + + if fmt.startswith('string'): + return data[:-1].decode(encoding='ascii').split('\0') if fmt == 'flag': if len(data): @@ -158,6 +143,8 @@ def prop_value(nodename, p): for i in type_struct.iter_unpack(data): val_int += [dtschema.sized_int(i[0], size=(type_struct.size * 8))] + if 'matrix' in fmt or 'phandle-array' in fmt: + dim = dtschema.property_get_type_dim(p.name) if dim: if max(dim[1]) and dim[1][0] == dim[1][1]: stride = dim[1][1] @@ -313,7 +300,7 @@ def fixup_phandles(dt, path=''): if isinstance(v, dict): fixup_phandles(v, path=path + '/' + k) continue - elif not k in props or not {'phandle-array'} & set(props[k]['type']): + elif not {'phandle-array'} & set(dtschema.property_get_type(k)): continue elif not isinstance(v, list) or (len(v) > 1 or not isinstance(v[0], list)): # Not a matrix or already split, nothing to do @@ -460,13 +447,6 @@ def fixup_addresses(dt, ac, sc): def fdt_unflatten(dtb): - p = dtschema.get_prop_types() - global props - global pat_props - - props = p[0] - pat_props = p[1] - fdt = libfdt.Fdt(dtb) offset = fdt.first_subnode(-1, QUIET_NOTFOUND) diff --git a/dtschema/lib.py b/dtschema/lib.py index 3def7b6b..057c6560 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -820,6 +820,9 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): if not isinstance(subschema, dict): return + if propname.startswith('$'): + return + if subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: _extract_subschema_types(props, schema, subschema) @@ -832,65 +835,85 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): #print(propname, sch_path, subschema, file=sys.stderr) _extract_prop_type(props, schema, propname, subschema, is_pattern) - try: - prop_type = type_re.search(subschema['$ref']).group(0) - except: - if 'type' in subschema and subschema['type'] == 'boolean': - prop_type = 'flag' - elif 'items' in subschema: - items = subschema['items'] - if (isinstance(items, list) and _is_string_schema(items[0])) or \ - (isinstance(items, dict) and _is_string_schema(items)): - # implicit string type - prop_type = 'string-array' - elif not (isinstance(items, list) and len(items) == 1 and \ - 'items' in items and isinstance(items['items'], list) and len(items['items']) == 1) and \ - unit_types_re.search(propname): - prop_type = 'uint32-matrix' + for k in subschema.keys() & {'allOf', 'oneOf', 'anyOf'}: + for v in subschema[k]: + _extract_prop_type(props, schema, propname, v, is_pattern) + + props.setdefault(propname, []) + + new_prop = {} + prop_type = None + + if 'type' in subschema and subschema['type'] == 'object': + prop_type = 'node' + else: + try: + prop_type = type_re.search(subschema['$ref']).group(0) + except: + if 'type' in subschema and subschema['type'] == 'boolean': + prop_type = 'flag' + elif 'items' in subschema: + items = subschema['items'] + if (isinstance(items, list) and _is_string_schema(items[0])) or \ + (isinstance(items, dict) and _is_string_schema(items)): + # implicit string type + prop_type = 'string-array' + elif not (isinstance(items, list) and len(items) == 1 and \ + 'items' in items and isinstance(items['items'], list) and len(items['items']) == 1) and \ + unit_types_re.search(propname): + prop_type = 'uint32-matrix' + else: + prop_type = None + elif '$ref' in subschema and re.search(r'\.yaml#?$', subschema['$ref']): + prop_type = 'node' else: prop_type = None - else: - prop_type = None - - if prop_type: - props.setdefault(propname, {}) - if is_pattern: - props[propname].setdefault('regex', re.compile(propname)) - - if prop_type == 'phandle-array' or prop_type.endswith('-matrix'): - dim = (_get_array_range(subschema), _get_array_range(subschema.get('items', {}))) - if dim != ((0, 0), (0, 0)): - if not 'dim' in props[propname]: - props[propname]['dim'] = dim - elif props[propname]['dim'] != dim: - # Conflicting dimensions - props[propname]['dim'] = _merge_dim(props[propname]['dim'], dim) - if 'type' in props[propname]: - if prop_type in props[propname]['type']: - # Already have the same type - return - for t in props[propname]['type']: - if prop_type in t: - # Already have the looser type - return - if t in prop_type: - # Replace scalar type with array type - i = props[propname]['type'].index(t) - props[propname]['type'][i] = prop_type - props[propname]['$id'][i] = schema['$id'] - return - else: - props[propname]['type'] = [] - props[propname]['$id'] = [] + new_prop['type'] = prop_type + new_prop['$id'] = [schema['$id']] + if is_pattern: + new_prop['regex'] = re.compile(propname) - props[propname]['type'] += [ prop_type ] - props[propname]['$id'] += [ schema['$id'] ] + if not prop_type: + if len(props[propname]) == 0: + props[propname] += [new_prop] return - for k in subschema.keys() & {'allOf', 'oneOf', 'anyOf'}: - for v in subschema[k]: - _extract_prop_type(props, schema, propname, v, is_pattern) + # handle matrix dimensions + if prop_type == 'phandle-array' or prop_type.endswith('-matrix'): + dim = (_get_array_range(subschema), _get_array_range(subschema.get('items', {}))) + new_prop['dim'] = dim + else: + dim = ((0, 0), (0, 0)) + + if propname in props: + dup_prop = None + for p in props[propname]: + if p['type'] is None: + dup_prop = p + break + if dim != ((0, 0), (0, 0)) and (p['type'] == 'phandle-array' or p['type'].endswith('-matrix')): + if not 'dim' in p: + p['dim'] = dim + elif p['dim'] != dim: + # Conflicting dimensions + p['dim'] = _merge_dim(p['dim'], dim) + return + if p['type'].startswith(prop_type): + # Already have the same or looser type + if schema['$id'] not in p['$id']: + p['$id'] += [schema['$id']] + return + elif p['type'] in prop_type: + # Replace scalar type with array type + new_prop['$id'] += p['$id'] + dup_prop = p + break + + if dup_prop: + props[propname].remove(dup_prop) + + props[propname] += [new_prop] def _extract_subschema_types(props, schema, subschema): @@ -916,21 +939,25 @@ def extract_types(): return props -def get_prop_types(): +def get_prop_types(want_missing_types=False): pat_props = {} props = dtschema.extract_types() - # hack to remove aliases pattern + # hack to remove aliases and generic patterns del props['^[a-z][a-z0-9\-]*$'] + props.pop('^[a-zA-Z][a-zA-Z0-9\\-_]{0,63}$', None) + props.pop('^.*$', None) + props.pop('.*', None) # Remove all properties without a type - for key in [key for key in props if 'type' not in props[key] ]: del props[key] + if not want_missing_types: + for key in [key for key in props if props[key][0]['type'] is None]: del props[key] # Split out pattern properties - for key in [key for key in props if 'regex' in props[key] ]: + for key in [key for key in props if len(props[key]) and 'regex' in props[key][0] ]: # Only want patternProperties with type and some amount of fixed string - if 'type' in props[key] and re.search(r'[0-9a-zA-F]{2}', key): + if re.search(r'[0-9a-zA-F-]{3}', key): #print(key, props[key], file=sys.stderr) pat_props[key] = props[key] del props[key] @@ -938,6 +965,52 @@ def get_prop_types(): return [ props, pat_props ] +props = None +pat_props = None + + +def property_get_type(propname): + global props + global pat_props + + if not props: + props, pat_props = get_prop_types() + + type = [] + if propname in props: + for v in props[propname]: + if v['type']: + type += [v['type']] + if len(type) == 0: + for v in pat_props.values(): + if v[0]['type'] and v[0]['type'] not in type and v[0]['regex'].search(propname): + type += [v[0]['type']] + + # Don't return 'node' as a type if there's other types + if len(type) > 1 and 'node' in type: + type.remove('node') + return type + + +def property_get_type_dim(propname): + global props + global pat_props + + if not props: + props, pat_props = get_prop_types() + + if propname in props: + for v in props[propname]: + if 'dim' in v: + return v['dim'] + + for v in pat_props.values(): + if v[0]['type'] and 'dim' in v[0] and v[0]['regex'].search(propname): + return v[0]['dim'] + + return None + + def load(filename, line_number=False): if filename.endswith('.dtb'): with open(filename, 'rb') as f: diff --git a/tools/dt-extract-props b/tools/dt-extract-props index 4f1deda5..1fa73969 100755 --- a/tools/dt-extract-props +++ b/tools/dt-extract-props @@ -34,7 +34,7 @@ if __name__ == "__main__": if args.duplicates: tmp_props = {} for k,v in props.items(): - if 'type' in v and len(v['type']) > 1: + if len(v) > 1: tmp_props[k] = v props = tmp_props @@ -44,10 +44,10 @@ if __name__ == "__main__": else: prop_types = {} for k,v in props.items(): - if 'type' in v: - prop_types[k] = v['type'] - else: - prop_types[k] = None + prop_types[k] = [] + for l in v: + if 'type' in l: + prop_types[k] += [l['type']] try: pprint.pprint(prop_types, compact=True) From 8ecd2452a7ee3c1bb207f66b2a34c570e011c1fe Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 27 Jul 2022 17:23:10 -0600 Subject: [PATCH 249/505] dtb2py: Fix typo in schema arg Fixes: 055ea514d445 ("Rework load_schema/process_schemas/set_schema to single 'set_schemas' API") Signed-off-by: Rob Herring --- tools/dtb2py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/dtb2py b/tools/dtb2py index 151fe1c6..61a54d59 100755 --- a/tools/dtb2py +++ b/tools/dtb2py @@ -23,7 +23,7 @@ if __name__ == "__main__": exit(1) if args.schema: - schemas = [args.schemas] + schemas = [args.schema] else: schemas = [] dtschema.set_schemas(schemas) From 354d3f740a943c4185c6f4137b2947a72f3da46c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 27 Jul 2022 19:45:59 -0600 Subject: [PATCH 250/505] schemas: gpio: Add size constraints on gpio-ranges Signed-off-by: Rob Herring --- dtschema/schemas/gpio/gpio.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dtschema/schemas/gpio/gpio.yaml b/dtschema/schemas/gpio/gpio.yaml index 612fc8f0..0eccfbeb 100644 --- a/dtschema/schemas/gpio/gpio.yaml +++ b/dtschema/schemas/gpio/gpio.yaml @@ -25,6 +25,12 @@ properties: maxItems: 2 gpio-ranges: $ref: "/schemas/types.yaml#/definitions/phandle-array" + items: + items: + - description: pin controller phandle + - description: GPIO controller offset + - description: pin controller offset + - description: number of pins gpio: # 'gpio' can appear as a property or node name From 13d395249583cc8214caec8f0a8155d8974c2a18 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 27 Jul 2022 17:25:16 -0600 Subject: [PATCH 251/505] dtb: Fix handling of optional #.*-cells property Some bindings have an optional #.*-cells property which is treated as 0 cells. In this case, we need to return 1 for the phandle cell. Signed-off-by: Rob Herring --- dtschema/dtb.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 8505cfca..4fe6a625 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -289,8 +289,6 @@ def _get_phandle_arg_size(prop_path, idx, cells, cellname): return 0 node = phandles[phandle] - if cellname not in node: - return 0 return _get_cells_size(node, cellname) + 1 @@ -307,7 +305,7 @@ def fixup_phandles(dt, path=''): continue elif k in phandle_args: cellname = phandle_args[k] - elif k.endswith('s'): + elif k.endswith('s') and 'gpio' not in k: cellname = '#' + k[:-1] + '-cells' #print(k, v) i = _get_phandle_arg_size(path + ':' + k, 0, v[0], cellname) From ef7924a3a52a954f81c7f3e5c05f3a684f1a7c2e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 27 Jul 2022 17:37:29 -0600 Subject: [PATCH 252/505] dtb: Properly handle fixed size phandle plus arg properties Properties with a fixed arg size such as 'gpio-ranges' where not being handled correctly. Allow 'cellname' to be a number for cases with a fixed size. Signed-off-by: Rob Herring --- dtschema/dtb.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 4fe6a625..72037454 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -241,7 +241,8 @@ def fdt_scan_node(fdt, nodename, offset): phandle_args = { - # phandle+args properties which don't match standard 'foos' and '#foo-cells' pattern + # phandle+args properties with fixed arg size or which don't match standard + # 'foos' and '#foo-cells' pattern 'assigned-clocks': '#clock-cells', 'assigned-clock-parents': '#clock-cells', 'cooling-device': '#cooling-cells', @@ -249,6 +250,7 @@ def fdt_scan_node(fdt, nodename, offset): 'interconnects': '#interconnect-cells', 'mboxes': '#mbox-cells', 'sound-dai': '#sound-dai-cells', + 'gpio-ranges': 3, 'nvmem-cells': None, 'memory-region': None, @@ -256,7 +258,9 @@ def fdt_scan_node(fdt, nodename, offset): def _get_cells_size(node, cellname): - if cellname in node: + if isinstance(cellname, int): + return cellname + elif cellname in node: return node[cellname][0][0] else: return 0 From 59f2e3103b6e776afe4f42e45897f7eabae06fa4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 27 Jul 2022 14:49:09 -0600 Subject: [PATCH 253/505] schemas: Add MSI consumer schema The only property so far for consumers is 'msi-parent'. As it depends on the provider '#msi-cells', dtb decoding needs to handle it as well. Signed-off-by: Rob Herring --- dtschema/dtb.py | 1 + dtschema/schemas/msi-consumer.yaml | 34 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 dtschema/schemas/msi-consumer.yaml diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 72037454..0473c85a 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -250,6 +250,7 @@ def fdt_scan_node(fdt, nodename, offset): 'interconnects': '#interconnect-cells', 'mboxes': '#mbox-cells', 'sound-dai': '#sound-dai-cells', + 'msi-parent': '#msi-cells', 'gpio-ranges': 3, 'nvmem-cells': None, diff --git a/dtschema/schemas/msi-consumer.yaml b/dtschema/schemas/msi-consumer.yaml new file mode 100644 index 00000000..c50dde16 --- /dev/null +++ b/dtschema/schemas/msi-consumer.yaml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2022 Arm Ltd. +$id: http://devicetree.org/schemas/msi-consumer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MSI consumer properties + +maintainers: + - Rob Herring + +# always select the core schema +select: true + +properties: + msi-parent: + description: | + A list of phandle + msi-specifier pairs, one for each MSI controller which the + device is capable of using. + + This property is unordered, and MSIs may be allocated from any combination of + MSI controllers listed in the msi-parent property. + + If a device has restrictions on the allocation of MSIs, these restrictions + must be described with additional properties. + + When #msi-cells is non-zero, busses with an msi-parent will require + additional properties to describe the relationship between devices on the bus + and the set of MSIs they can potentially generate. + $ref: types.yaml#/definitions/phandle-array + items: + minItems: 1 + maxItems: 2 + +additionalProperties: true From 3d44bf2b46a9ac638550ca3916d7d7f70823bb58 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Jul 2022 11:27:49 -0600 Subject: [PATCH 254/505] schemas: Add PCI iommu-map schema Add schema for PCI iommu-map/iommu-map-mask properties. Based on Documentation/devicetree/bindings/pci/pci-iommu.txt in the Linux kernel. Signed-off-by: Rob Herring --- dtschema/schemas/pci/pci-iommu.yaml | 183 ++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 dtschema/schemas/pci/pci-iommu.yaml diff --git a/dtschema/schemas/pci/pci-iommu.yaml b/dtschema/schemas/pci/pci-iommu.yaml new file mode 100644 index 00000000..aac6b417 --- /dev/null +++ b/dtschema/schemas/pci/pci-iommu.yaml @@ -0,0 +1,183 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2016,2022 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/pci-iommu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: PCI IOMMU mapping schema + +description: | + This document describes the generic device tree binding for describing the + relationship between PCI(e) devices and IOMMU(s). + + Each PCI(e) device under a root complex is uniquely identified by its Requester + ID (AKA RID). A Requester ID is a triplet of a Bus number, Device number, and + Function number. + + For the purpose of this document, when treated as a numeric value, a RID is + formatted such that: + + * Bits [15:8] are the Bus number. + * Bits [7:3] are the Device number. + * Bits [2:0] are the Function number. + * Any other bits required for padding must be zero. + + IOMMUs may distinguish PCI devices through sideband data derived from the + Requester ID. While a given PCI device can only master through one IOMMU, a + root complex may split masters across a set of IOMMUs (e.g. with one IOMMU per + bus). + + The generic 'iommus' property is insufficient to describe this relationship, + and a mechanism is required to map from a PCI device to its IOMMU and sideband + data. + +maintainers: + - Rob Herring + +select: true + +properties: + iommu-map: + description: | + Maps a Requester ID to an IOMMU and associated IOMMU specifier data. + + The property is an arbitrary number of tuples of + (rid-base,iommu,iommu-base,length). + + Any RID r in the interval [rid-base, rid-base + length) is associated with + the listed IOMMU, with the IOMMU specifier (r - rid-base + iommu-base). + $ref: /schemas/types.yaml#/definitions/uint32-matrix + items: + items: + - description: RID base + maximum: 0xffff + - description: phandle to IOMMU + - description: IOMMU specifier base (currently always 1 cell) + - description: Number of RIDs + maximum: 0x10000 + + iommu-map-mask: + description: + A mask to be applied to each Requester ID prior to being mapped to an + IOMMU specifier per the iommu-map property. + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 0xffff + +additionalProperties: true + +examples: + - | + / { + #address-cells = <1>; + #size-cells = <1>; + + iommu: iommu@a { + reg = <0xa 0x1>; + compatible = "foo,some-iommu"; + #iommu-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "foo,pcie-root-complex"; + device_type = "pci"; + + /* + * The sideband data provided to the IOMMU is the RID, + * identity-mapped. + */ + iommu-map = <0x0 &iommu 0x0 0x10000>; + }; + }; + + - | + / { + #address-cells = <1>; + #size-cells = <1>; + + iommu: iommu@a { + reg = <0xa 0x1>; + compatible = "foo,some-iommu"; + #iommu-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "foo,pcie-root-complex"; + device_type = "pci"; + + /* + * The sideband data provided to the IOMMU is the RID with the + * function bits masked out. + */ + iommu-map = <0x0 &iommu 0x0 0x10000>; + iommu-map-mask = <0xfff8>; + }; + }; + + - | + / { + #address-cells = <1>; + #size-cells = <1>; + + iommu: iommu@a { + reg = <0xa 0x1>; + compatible = "foo,some-iommu"; + #iommu-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "foo,pcie-root-complex"; + device_type = "pci"; + + /* + * The sideband data provided to the IOMMU is the RID, + * but the high bits of the bus number are flipped. + */ + iommu-map = <0x0000 &iommu 0x8000 0x8000>, + <0x8000 &iommu 0x0000 0x8000>; + }; + }; + + - | + / { + #address-cells = <1>; + #size-cells = <1>; + + iommu_a: iommu@a { + reg = <0xa 0x1>; + compatible = "foo,some-iommu"; + #iommu-cells = <1>; + }; + + iommu_b: iommu@b { + reg = <0xb 0x1>; + compatible = "foo,some-iommu"; + #iommu-cells = <1>; + }; + + iommu_c: iommu@c { + reg = <0xc 0x1>; + compatible = "foo,some-iommu"; + #iommu-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "foo,pcie-root-complex"; + device_type = "pci"; + + /* + * Devices with bus number 0-127 are mastered via IOMMU + * a, with sideband data being RID[14:0]. + * Devices with bus number 128-255 are mastered via + * IOMMU b, with sideband data being RID[14:0]. + * No devices master via IOMMU c. + */ + iommu-map = <0x0000 &iommu_a 0x0000 0x8000>, + <0x8000 &iommu_b 0x0000 0x8000>; + }; + }; +... From bf775bffa2c1cd9dab3d4c625ddb4ca378d7a958 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Jul 2022 16:55:30 -0600 Subject: [PATCH 255/505] dtschema: Move dropping 'additionalProperties: true' to after fixup_node_props() fixup_node_props() looks at additionalProperties, so we need to strip it after calling it instead of before. Signed-off-by: Rob Herring --- dtschema/lib.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 057c6560..6780effc 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -473,16 +473,16 @@ def fixup_sub_schema(schema, is_prop): if not isinstance(schema, dict): return - # 'additionalProperties: true' doesn't work with 'unevaluatedProperties', so - # remove it. It's in the schemas for common (incomplete) schemas. - if 'additionalProperties' in schema and schema['additionalProperties'] == True: - schema.pop('additionalProperties', None) - schema.pop('description', None) fixup_interrupts(schema) if is_prop: fixup_node_props(schema) + # 'additionalProperties: true' doesn't work with 'unevaluatedProperties', so + # remove it. It's in the schemas for common (incomplete) schemas. + if 'additionalProperties' in schema and schema['additionalProperties'] == True: + schema.pop('additionalProperties', None) + for k, v in schema.items(): if k in ['select', 'if', 'then', 'else', 'additionalProperties', 'not']: fixup_sub_schema(v, False) From f9e3f3ff9227a297f23f88566347ece30a00e923 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 29 Jul 2022 10:43:30 -0600 Subject: [PATCH 256/505] dtschema: Fix populating pinctrl properties if only 'pinctrl-names' is present Commit bf775bffa2c1 ("dtschema: Move dropping 'additionalProperties: true' to after fixup_node_props()") exposed an issue with a schema that defined 'pinctrl-names' but not 'pinctrl-[0-9]' properties. This was masked because the automatic properties were being added to a common schema which was referenced. Prior to that, it was masked by unevaluatedProperties not being fully working. Rework the pinctrl check to only look for 'pinctrl-[0-9]' properties when deciding whether to add pinctrl related properties. Signed-off-by: Rob Herring --- dtschema/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 6780effc..c6ff93dc 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -523,10 +523,10 @@ def fixup_node_props(schema): keys.extend(schema['patternProperties']) for key in keys: - if "pinctrl" in key: + if re.match(r'^pinctrl-[0-9]', key): break else: - schema['properties']['pinctrl-names'] = True + schema['properties'].setdefault('pinctrl-names', True) schema.setdefault('patternProperties', dict()) schema['patternProperties']['pinctrl-[0-9]+'] = True From be9e3794c90a2bb7d4b2298717001116dd9cf8e1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 29 Jul 2022 13:13:57 -0600 Subject: [PATCH 257/505] dt-mk-schema: Make the json output human readable Currently, the processed schema json output is not readable being a single line. Set the json.dump() 'indent' option so we get human readable output. Signed-off-by: Rob Herring --- tools/dt-mk-schema | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/dt-mk-schema b/tools/dt-mk-schema index 7ee3267f..1dc22611 100755 --- a/tools/dt-mk-schema +++ b/tools/dt-mk-schema @@ -45,7 +45,7 @@ if __name__ == "__main__": f = sys.stdout if (args.json): - json.dump(schemas, f) + json.dump(schemas, f, indent=4) else: yaml = ruamel.yaml.YAML(typ='safe') yaml.dump(schemas, f) From d3a9da518526bab22b3a1aa2cc2d9cbb5dca0af4 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 29 Jul 2022 10:32:29 -0600 Subject: [PATCH 258/505] dtschema: Save type information in processed schemas Extracting type information out of the schemas for every invocation takes a significant amount of time. As we save the processed schemas already, add the type information to it. This improves the validation time by ~20%. Signed-off-by: Rob Herring --- dtschema/lib.py | 53 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index c6ff93dc..574aea6a 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -939,7 +939,7 @@ def extract_types(): return props -def get_prop_types(want_missing_types=False): +def get_prop_types(want_missing_types=False, want_node_types=False): pat_props = {} props = dtschema.extract_types() @@ -950,9 +950,18 @@ def get_prop_types(want_missing_types=False): props.pop('^.*$', None) props.pop('.*', None) + # Remove node types + if not want_node_types: + for val in props.values(): + val[:] = [t for t in val if t['type'] != 'node'] + # Remove all properties without a type if not want_missing_types: - for key in [key for key in props if props[key][0]['type'] is None]: del props[key] + for val in props.values(): + val[:] = [t for t in val if t['type'] is not None] + + # Delete any entries now empty due to above operations + for key in [key for key in props if len(props[key]) == 0]: del props[key] # Split out pattern properties for key in [key for key in props if len(props[key]) and 'regex' in props[key][0] ]: @@ -1022,11 +1031,39 @@ def load(filename, line_number=False): return yaml.load(f.read()) -schema_cache = {} +def make_property_type_cache(): + global schema_cache + + props, pat_props = get_prop_types() + + for val in props.values(): + val[:] = [t for t in val if 'regex' not in t] + for t in val: del t['$id'] + + schema_cache['generated-types'] = { + '$id': 'generated-types', + '$filename': 'Generated property types', + 'select': False, + 'properties': props + } + for val in pat_props.values(): + for t in val: + t.pop('regex', None) + del t['$id'] + + schema_cache['generated-pattern-types'] = { + '$id': 'generated-pattern-types', + '$filename': 'Generated property types', + 'select': False, + 'properties': pat_props + } + + +schema_cache = {} def set_schemas(schema_files, core_schema=True): - global schema_cache + global schema_cache, pat_props, props if len(schema_files) == 1 and os.path.isfile(schema_files[0]): # a processed schema file @@ -1037,8 +1074,16 @@ def set_schemas(schema_files, core_schema=True): for sch in schema_cache: d[sch['$id']] = sch schema_cache = d + + if 'generated-types' in schema_cache: + props = schema_cache['generated-types']['properties'] + if 'generated-pattern-types' in schema_cache: + pat_props = schema_cache['generated-pattern-types']['properties'] + for k in pat_props: + pat_props[k][0]['regex'] = re.compile(k) else: schema_cache = process_schemas(schema_files, core_schema) + make_property_type_cache() return schema_cache From 2d1c1e7cf592a78cfd779496de324cd0d21c36e5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 29 Jul 2022 13:50:25 -0600 Subject: [PATCH 259/505] dt-validate: Skip validating schema example root and 'example-' nodes There's little point in validating the generated nodes in the schema examples and they take ~15% of the validation time, so lets skip over them. Signed-off-by: Rob Herring --- tools/dt-validate | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/dt-validate b/tools/dt-validate index 9e4b113a..ba60092d 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -31,7 +31,10 @@ class schema_group(): self.schemas = dtschema.set_schemas([schema_file]) def check_node(self, tree, node, disabled, nodename, fullname, filename): - # Skip any generated nodes + # Hack to save some time validating examples + if 'example-0' in node or 'example-' in nodename: + return + node['$nodename'] = [ nodename ] node_matched = False matched_schemas = [] From aa0c2de43ae30ad9f101d27309bc6b84246e6ec1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 4 Aug 2022 14:32:53 -0600 Subject: [PATCH 260/505] schemas: Add qemu,platform bus schema QEMU virtual platforms define a 'qemu,platform' bus compatible with a fallback to 'simple-bus'. Signed-off-by: Rob Herring --- dtschema/schemas/bus/qemu,platform.yaml | 54 +++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 dtschema/schemas/bus/qemu,platform.yaml diff --git a/dtschema/schemas/bus/qemu,platform.yaml b/dtschema/schemas/bus/qemu,platform.yaml new file mode 100644 index 00000000..aa45bee7 --- /dev/null +++ b/dtschema/schemas/bus/qemu,platform.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2022 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bus/qemu,platform.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: QEMU Platform bus + +maintainers: + - Rob Herring + +select: + properties: + compatible: + contains: + const: qemu,platform + required: + - compatible + +properties: + compatible: + items: + - const: qemu,platform + - const: simple-bus + + ranges: true + dma-ranges: true + + "#address-cells": + enum: [ 1, 2 ] + "#size-cells": + enum: [ 1, 2 ] + + nonposted-mmio: + $ref: /schemas/types.yaml#/definitions/flag + description: + If present, specifies that direct children of this bus should use + non-posted memory accesses (i.e. a non-posted mapping mode) for MMIO + ranges. + +patternProperties: + # All other properties should be child nodes with unit-address and 'reg' + "@(0|[1-9a-f][0-9a-f]*)$": + type: object + +additionalProperties: false + +required: + - compatible + - "#address-cells" + - "#size-cells" + - ranges +... From b12b3737cabc8f500446d6ac89aa6aefbeccadf5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 8 Aug 2022 11:46:37 -0600 Subject: [PATCH 261/505] dtschema: Apply fixups to nodes with only a $ref Some node schemas contain only a '$ref' to a common schema and an 'unevaluatedProperties: false'. These also need node fixups applied to the schema. Using 'unevaluatedProperties' here is a better indication that the schema is for a node than '$ref' would be. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 574aea6a..71cebd9a 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -503,7 +503,7 @@ def fixup_sub_schema(schema, is_prop): def fixup_node_props(schema): - if not {'properties', 'patternProperties'} & schema.keys(): + if not {'properties', 'patternProperties', 'unevaluatedProperties'} & schema.keys(): return if ('additionalProperties' in schema and schema['additionalProperties'] is True) or \ ('unevaluatedProperties' in schema and schema['unevaluatedProperties'] is True): From 0d1b78cd0c3d9a3d523ced17d7da64b03f6c18ea Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 8 Aug 2022 13:17:44 -0600 Subject: [PATCH 262/505] dtschema: Ensure generated property type output is sorted Mainly for purposes of before and after comparisons of the processed schemas, ensure the generated property type output is sorted. Signed-off-by: Rob Herring --- dtschema/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 71cebd9a..dac1b1f2 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1044,7 +1044,7 @@ def make_property_type_cache(): '$id': 'generated-types', '$filename': 'Generated property types', 'select': False, - 'properties': props + 'properties': {k: props[k] for k in sorted(props)} } for val in pat_props.values(): @@ -1056,7 +1056,7 @@ def make_property_type_cache(): '$id': 'generated-pattern-types', '$filename': 'Generated property types', 'select': False, - 'properties': pat_props + 'properties': {k: pat_props[k] for k in sorted(pat_props)} } From 31be03d17b6e58824c040940f2c51538f65267c3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sun, 14 Aug 2022 17:34:40 -0600 Subject: [PATCH 263/505] meta-schemas: Rework DT and json-schema property name collisions The existing meta-schema would not catch cases containing both DT property names and json-schema keywords. Rework the meta-schema also handle this case. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 97 +++++++++++++++-------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index e6ed5960..3ee190e4 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -9,48 +9,56 @@ description: Keywords must be a subset of known json-schema keywords definitions: + json-schema-prop-names: + enum: + - $ref + - additionalItems + - additionalProperties + - allOf + - anyOf + - const + - contains + - default + - dependencies + - dependentRequired + - dependentSchemas + - deprecated + - description + - else + - enum + - exclusiveMaximum + - exclusiveMinimum + - items + - if + - minItems + - minimum + - maxItems + - maximum + - multipleOf + - not + - oneOf + - pattern + - patternProperties + - properties + - required + - then + - typeSize + - unevaluatedProperties + - uniqueItems + + overlapping-json-schema-prop-names: + # 'type' is also a DT property name + const: type + sub-schemas: allOf: - $ref: "#" - $ref: items.yaml# propertyNames: # The subset of keywords allowed for sub-schema - enum: - - $ref - - additionalItems - - additionalProperties - - allOf - - anyOf - - const - - contains - - default - - dependencies - - dependentRequired - - dependentSchemas - - deprecated - - description - - else - - enum - - exclusiveMaximum - - exclusiveMinimum - - items - - if - - minItems - - minimum - - maxItems - - maximum - - multipleOf - - not - - oneOf - - pattern - - patternProperties - - properties - - required - - then - - type - - typeSize - - unevaluatedProperties - - uniqueItems + anyOf: + - $ref: "#/definitions/json-schema-prop-names" + - $ref: "#/definitions/overlapping-json-schema-prop-names" scalar-prop-list: propertyNames: @@ -158,18 +166,13 @@ properties: additionalProperties: $ref: "#/definitions/sub-schemas" properties: - if: - # Filter out overlapping json-schema and DT property names - not: - propertyNames: - const: type - then: - not: - $ref: "#/definitions/sub-schemas" - description: A json-schema keyword was found instead of a DT property name. propertyNames: - description: Expected a valid DT property name - pattern: "^[#$a-zA-Z][a-zA-Z0-9,+\\-._@]{0,63}$" + allOf: + - description: Expected a valid DT property name + pattern: "^[#$a-zA-Z][a-zA-Z0-9,+\\-._@]{0,63}$" + - description: A json-schema keyword was found instead of a DT property name. + not: + $ref: "#/definitions/json-schema-prop-names" additionalProperties: $ref: "#/definitions/sub-schemas" required: From f9454b2eeb0a2c7c5e7cbc756b0ee58a12b9ee0d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sun, 14 Aug 2022 17:38:56 -0600 Subject: [PATCH 264/505] dtschema: Avoid infinite recursion parsing property type info Recursive $refs can cause infinite recursion when parsing type information. Fix this by skipping $refs if we've already seen the property name. That also requires adding property names before doing any recursion. Signed-off-by: Rob Herring --- dtschema/lib.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index dac1b1f2..c711ce81 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -823,11 +823,13 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): if propname.startswith('$'): return + props.setdefault(propname, []) + if subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: _extract_subschema_types(props, schema, subschema) # We only support local refs - if '$ref' in subschema and subschema['$ref'].startswith('#/'): + if propname not in props and '$ref' in subschema and subschema['$ref'].startswith('#/'): sch_path = subschema['$ref'].split('/')[1:] subschema = schema for p in sch_path: @@ -839,8 +841,6 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): for v in subschema[k]: _extract_prop_type(props, schema, propname, v, is_pattern) - props.setdefault(propname, []) - new_prop = {} prop_type = None From 9c931b41778b6ea15153480b65a2391b7ddafd61 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 17 Aug 2022 09:39:18 -0600 Subject: [PATCH 265/505] Disallow jsonschema version 4.10.0 and later The 4.10.0 release and later breaks us due to commit 18a64d7e0fd1 ("Add support for referencing schemas across different drafts."). The DTValidator class needs to be reworked to not subclass the validator which isn't considered supported. Signed-off-by: Rob Herring --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 62db8afc..50ba4a8b 100755 --- a/setup.py +++ b/setup.py @@ -50,7 +50,7 @@ install_requires=[ 'ruamel.yaml>0.15.69', - 'jsonschema>=4.1.2', + 'jsonschema>=4.1.2,<4.10.0', 'rfc3987', 'pylibfdt', ], From 45c9714d238bcddbee3a1a4d0f412176a18c99a8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 19 Aug 2022 08:19:22 -0500 Subject: [PATCH 266/505] dtschema: Remove unnecessary if condition in _extract_prop_type 'propname' is always in 'props' since the default entry is set earlier in _extract_prop_type. Signed-off-by: Rob Herring --- dtschema/lib.py | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index c711ce81..3c4a5833 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -886,32 +886,31 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): else: dim = ((0, 0), (0, 0)) - if propname in props: - dup_prop = None - for p in props[propname]: - if p['type'] is None: - dup_prop = p - break - if dim != ((0, 0), (0, 0)) and (p['type'] == 'phandle-array' or p['type'].endswith('-matrix')): - if not 'dim' in p: - p['dim'] = dim - elif p['dim'] != dim: - # Conflicting dimensions - p['dim'] = _merge_dim(p['dim'], dim) - return - if p['type'].startswith(prop_type): - # Already have the same or looser type - if schema['$id'] not in p['$id']: - p['$id'] += [schema['$id']] - return - elif p['type'] in prop_type: - # Replace scalar type with array type - new_prop['$id'] += p['$id'] - dup_prop = p - break + dup_prop = None + for p in props[propname]: + if p['type'] is None: + dup_prop = p + break + if dim != ((0, 0), (0, 0)) and (p['type'] == 'phandle-array' or p['type'].endswith('-matrix')): + if not 'dim' in p: + p['dim'] = dim + elif p['dim'] != dim: + # Conflicting dimensions + p['dim'] = _merge_dim(p['dim'], dim) + return + if p['type'].startswith(prop_type): + # Already have the same or looser type + if schema['$id'] not in p['$id']: + p['$id'] += [schema['$id']] + return + elif p['type'] in prop_type: + # Replace scalar type with array type + new_prop['$id'] += p['$id'] + dup_prop = p + break - if dup_prop: - props[propname].remove(dup_prop) + if dup_prop: + props[propname].remove(dup_prop) props[propname] += [new_prop] From 206ef0ac741dcef38bf12a5859b9e8f71054ce16 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 19 Aug 2022 08:12:55 -0500 Subject: [PATCH 267/505] dtschema: Try 2 to avoid infinite recursion parsing property type info This reverts commit f9454b2eeb0a ("dtschema: Avoid infinite recursion parsing property type info") which broke parsing types in some schemas. Now we only recurse if we haven't seen the node name and matching schema $id. Signed-off-by: Rob Herring --- dtschema/lib.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 3c4a5833..0f7a2149 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -823,13 +823,8 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): if propname.startswith('$'): return - props.setdefault(propname, []) - - if subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: - _extract_subschema_types(props, schema, subschema) - # We only support local refs - if propname not in props and '$ref' in subschema and subschema['$ref'].startswith('#/'): + if '$ref' in subschema and subschema['$ref'].startswith('#/'): sch_path = subschema['$ref'].split('/')[1:] subschema = schema for p in sch_path: @@ -841,6 +836,8 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): for v in subschema[k]: _extract_prop_type(props, schema, propname, v, is_pattern) + props.setdefault(propname, []) + new_prop = {} prop_type = None @@ -902,6 +899,9 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): # Already have the same or looser type if schema['$id'] not in p['$id']: p['$id'] += [schema['$id']] + # Descend into child schemas if we haven't seen this node already + if prop_type == 'node': + break return elif p['type'] in prop_type: # Replace scalar type with array type @@ -914,6 +914,9 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): props[propname] += [new_prop] + if subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: + _extract_subschema_types(props, schema, subschema) + def _extract_subschema_types(props, schema, subschema): if not isinstance(subschema, dict): From 35a613f205858908cf267ece850d06105e16c380 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 17 Aug 2022 17:50:39 -0600 Subject: [PATCH 268/505] meta-schemas: Correct the draft 2019-09 meta-schema URI The URI for json-schema draft 2019-09 meta-schema uses https and doesn't have a trailing '#'. This didn't matter until a jsonschema change in 4.10.0 which caused draft 2020-12 validator to be used. It is now fixed again. However, it's best to still go ahead and fix this. Signed-off-by: Rob Herring --- dtschema/meta-schemas/base.yaml | 2 +- dtschema/meta-schemas/boolean.yaml | 2 +- dtschema/meta-schemas/cell.yaml | 2 +- dtschema/meta-schemas/clocks.yaml | 2 +- dtschema/meta-schemas/core.yaml | 2 +- dtschema/meta-schemas/dma.yaml | 2 +- dtschema/meta-schemas/gpios.yaml | 2 +- dtschema/meta-schemas/hwlock.yaml | 2 +- dtschema/meta-schemas/iio.yaml | 2 +- dtschema/meta-schemas/interrupts.yaml | 2 +- dtschema/meta-schemas/iommu.yaml | 2 +- dtschema/meta-schemas/items.yaml | 2 +- dtschema/meta-schemas/keywords.yaml | 2 +- dtschema/meta-schemas/mailbox.yaml | 2 +- dtschema/meta-schemas/nodes.yaml | 2 +- dtschema/meta-schemas/nvmem.yaml | 2 +- dtschema/meta-schemas/phy.yaml | 2 +- dtschema/meta-schemas/power-domain.yaml | 2 +- dtschema/meta-schemas/pwm.yaml | 2 +- dtschema/meta-schemas/reset.yaml | 2 +- dtschema/meta-schemas/string-array.yaml | 2 +- dtschema/meta-schemas/vendor-props.yaml | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/dtschema/meta-schemas/base.yaml b/dtschema/meta-schemas/base.yaml index 9f27da12..e21d324d 100644 --- a/dtschema/meta-schemas/base.yaml +++ b/dtschema/meta-schemas/base.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/base.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema" +$schema: https://json-schema.org/draft/2019-09/schema description: "Metaschema for devicetree binding documentation" allOf: diff --git a/dtschema/meta-schemas/boolean.yaml b/dtschema/meta-schemas/boolean.yaml index 49688032..6cc638a3 100644 --- a/dtschema/meta-schemas/boolean.yaml +++ b/dtschema/meta-schemas/boolean.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/boolean.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: type: diff --git a/dtschema/meta-schemas/cell.yaml b/dtschema/meta-schemas/cell.yaml index 454e62e5..21253cdb 100644 --- a/dtschema/meta-schemas/cell.yaml +++ b/dtschema/meta-schemas/cell.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/cell.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema array: description: cell array properties must define how many entries and what the diff --git a/dtschema/meta-schemas/clocks.yaml b/dtschema/meta-schemas/clocks.yaml index facad30b..572a5d70 100644 --- a/dtschema/meta-schemas/clocks.yaml +++ b/dtschema/meta-schemas/clocks.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/clocks.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: clocks: diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index 61987295..0ab315e5 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/core.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema description: "Metaschema for devicetree binding documentation" allOf: diff --git a/dtschema/meta-schemas/dma.yaml b/dtschema/meta-schemas/dma.yaml index e0ada191..fb76f4b4 100644 --- a/dtschema/meta-schemas/dma.yaml +++ b/dtschema/meta-schemas/dma.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/dma.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: dmas: diff --git a/dtschema/meta-schemas/gpios.yaml b/dtschema/meta-schemas/gpios.yaml index b80040a4..b8424191 100644 --- a/dtschema/meta-schemas/gpios.yaml +++ b/dtschema/meta-schemas/gpios.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/gpios.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: gpio-controller: diff --git a/dtschema/meta-schemas/hwlock.yaml b/dtschema/meta-schemas/hwlock.yaml index f02d90eb..c76638e6 100644 --- a/dtschema/meta-schemas/hwlock.yaml +++ b/dtschema/meta-schemas/hwlock.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/hwlock.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: hwlocks: diff --git a/dtschema/meta-schemas/iio.yaml b/dtschema/meta-schemas/iio.yaml index b739aae6..60e64f00 100644 --- a/dtschema/meta-schemas/iio.yaml +++ b/dtschema/meta-schemas/iio.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/iio.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: io-channels: diff --git a/dtschema/meta-schemas/interrupts.yaml b/dtschema/meta-schemas/interrupts.yaml index a1ecfa58..d3816e28 100644 --- a/dtschema/meta-schemas/interrupts.yaml +++ b/dtschema/meta-schemas/interrupts.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/interrupts.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: interrupts: diff --git a/dtschema/meta-schemas/iommu.yaml b/dtschema/meta-schemas/iommu.yaml index 1c922a98..b1a0921e 100644 --- a/dtschema/meta-schemas/iommu.yaml +++ b/dtschema/meta-schemas/iommu.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/iommu.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: iommus: diff --git a/dtschema/meta-schemas/items.yaml b/dtschema/meta-schemas/items.yaml index cb7b7d20..a586fa1e 100644 --- a/dtschema/meta-schemas/items.yaml +++ b/dtschema/meta-schemas/items.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/items.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema description: Meta-schema for 'items' schema. This meta-schema checks that an 'items' list diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 3ee190e4..d5889764 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/keywords.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema description: Keywords must be a subset of known json-schema keywords diff --git a/dtschema/meta-schemas/mailbox.yaml b/dtschema/meta-schemas/mailbox.yaml index 3ba92aa2..cb24de8e 100644 --- a/dtschema/meta-schemas/mailbox.yaml +++ b/dtschema/meta-schemas/mailbox.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/mailbox.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: mboxes: diff --git a/dtschema/meta-schemas/nodes.yaml b/dtschema/meta-schemas/nodes.yaml index 686cd0ba..1226a407 100644 --- a/dtschema/meta-schemas/nodes.yaml +++ b/dtschema/meta-schemas/nodes.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/nodes.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema type: object diff --git a/dtschema/meta-schemas/nvmem.yaml b/dtschema/meta-schemas/nvmem.yaml index af8b1c27..3feeb9f6 100644 --- a/dtschema/meta-schemas/nvmem.yaml +++ b/dtschema/meta-schemas/nvmem.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/nvmem.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: nvmem: diff --git a/dtschema/meta-schemas/phy.yaml b/dtschema/meta-schemas/phy.yaml index 260c21ab..efb4b864 100644 --- a/dtschema/meta-schemas/phy.yaml +++ b/dtschema/meta-schemas/phy.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/phy.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: phys: diff --git a/dtschema/meta-schemas/power-domain.yaml b/dtschema/meta-schemas/power-domain.yaml index fc59ba0a..2eea69da 100644 --- a/dtschema/meta-schemas/power-domain.yaml +++ b/dtschema/meta-schemas/power-domain.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/power-domain.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: power-domains: diff --git a/dtschema/meta-schemas/pwm.yaml b/dtschema/meta-schemas/pwm.yaml index f6f4e8c1..f45bb0bb 100644 --- a/dtschema/meta-schemas/pwm.yaml +++ b/dtschema/meta-schemas/pwm.yaml @@ -3,7 +3,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/pwm.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: pwms: diff --git a/dtschema/meta-schemas/reset.yaml b/dtschema/meta-schemas/reset.yaml index 2ebbb1f5..b9d4568e 100644 --- a/dtschema/meta-schemas/reset.yaml +++ b/dtschema/meta-schemas/reset.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/reset.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema properties: resets: diff --git a/dtschema/meta-schemas/string-array.yaml b/dtschema/meta-schemas/string-array.yaml index a7ee4011..c15c8c30 100644 --- a/dtschema/meta-schemas/string-array.yaml +++ b/dtschema/meta-schemas/string-array.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/string-array.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema #type: object if: diff --git a/dtschema/meta-schemas/vendor-props.yaml b/dtschema/meta-schemas/vendor-props.yaml index de884f64..0deff14b 100644 --- a/dtschema/meta-schemas/vendor-props.yaml +++ b/dtschema/meta-schemas/vendor-props.yaml @@ -4,7 +4,7 @@ %YAML 1.2 --- $id: "http://devicetree.org/meta-schemas/vendor-props.yaml#" -$schema: "http://json-schema.org/draft/2019-09/schema#" +$schema: https://json-schema.org/draft/2019-09/schema description: Metaschema for vendor specific properties From 2b780611b59e3249bac2b067bc032fb28e1488a2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 17 Aug 2022 10:02:18 -0600 Subject: [PATCH 269/505] Revert "Disallow jsonschema version 4.10.0 and later" This reverts commit 9c931b41778b6ea15153480b65a2391b7ddafd61. The issue in json-schema has been fixed. Signed-off-by: Rob Herring --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 50ba4a8b..62db8afc 100755 --- a/setup.py +++ b/setup.py @@ -50,7 +50,7 @@ install_requires=[ 'ruamel.yaml>0.15.69', - 'jsonschema>=4.1.2,<4.10.0', + 'jsonschema>=4.1.2', 'rfc3987', 'pylibfdt', ], From 65287ceb78939cbcd4020d817cde0699abbe8924 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 23 Aug 2022 11:51:42 -0500 Subject: [PATCH 270/505] test: Test meta-schemas against draft2019-09 rather than draft7 The meta-schemas were updated to draft2019-09 and should be tested against that version of the spec. Signed-off-by: Rob Herring --- test/test-dt-validate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index b22803a3..f810e631 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -31,11 +31,11 @@ def test_metaschema_valid(self): jsonschema.Draft7Validator.check_schema(dtschema.DTValidator.META_SCHEMA) def test_all_metaschema_valid(self): - '''The metaschema must all be a valid Draft7 schema''' + '''The metaschema must all be a valid Draft2019-09 schema''' for filename in glob.iglob(os.path.join(dtschema_dir, 'meta-schemas/**/*.yaml'), recursive=True): with self.subTest(schema=filename): schema = dtschema.load_schema(filename) - jsonschema.Draft7Validator.check_schema(schema) + jsonschema.Draft201909Validator.check_schema(schema) def test_required_properties(self): dtschema.DTValidator.check_schema(self.schema) From 70d7a3fee70438e18ca87cdd5d6bced75cf7ad72 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 19 Aug 2022 10:51:00 -0500 Subject: [PATCH 271/505] dtschema: De-subclass DTValidator class jsonschema has deprecated subclassing its Validator class, so rework DTValidator to avoid subclassing. The subclass mainly provides the same API, but we can do that without a subclass. Signed-off-by: Rob Herring --- dtschema/lib.py | 30 +++++++++++++++++++----------- test/test-dt-validate.py | 4 ---- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 0f7a2149..48484431 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1138,10 +1138,7 @@ def typeSize(validator, typeSize, instance, schema): yield jsonschema.ValidationError("size is %r, expected %r" % (size, typeSize)) -DTVal = jsonschema.validators.extend(jsonschema.Draft201909Validator, {'typeSize': typeSize}) - - -class DTValidator(DTVal): +class DTValidator(): '''Custom Validator for Devicetree Schemas Overrides the Draft7 metaschema with the devicetree metaschema. This @@ -1151,11 +1148,12 @@ class DTValidator(DTVal): ''' resolver = jsonschema.RefResolver('', None, handlers=handlers) format_checker = jsonschema.FormatChecker() + DTVal = jsonschema.validators.extend(jsonschema.Draft201909Validator, {'typeSize': typeSize}, version='DT') def __init__(self, *args, **kwargs): kwargs.setdefault('resolver', self.resolver) kwargs.setdefault('format_checker', self.format_checker) - super().__init__(*args, **kwargs) + self.validator = self.DTVal(*args, **kwargs) @classmethod def annotate_error(self, error, schema, path): @@ -1165,7 +1163,7 @@ def annotate_error(self, error, schema, path): for e in error.context: self.annotate_error(e, schema, path + e.schema_path) - scope = self.ID_OF(schema) + scope = schema['$id'] self.resolver.push_scope(scope) ref_depth = 1 @@ -1201,22 +1199,32 @@ def annotate_error(self, error, schema, path): @classmethod def iter_schema_errors(cls, schema): meta_schema = cls.resolver.resolve_from_url(schema['$schema']) - for error in cls(meta_schema).iter_errors(schema): - cls(meta_schema).annotate_error(error, meta_schema, error.schema_path) + val = cls.DTVal(meta_schema, resolver=cls.resolver) + for error in val.iter_errors(schema): + cls.annotate_error(error, meta_schema, error.schema_path) error.linecol = get_line_col(schema, error.path) yield error def iter_errors(self, instance, _schema=None): - for error in super().iter_errors(instance, _schema): + for error in self.validator.iter_errors(instance, _schema): error.linecol = get_line_col(instance, error.path) error.note = None error.schema_file = None yield error + def validate(self, *args, **kwargs): + for error in self.iter_errors(*args, **kwargs): + raise error + + def is_valid(self, instance): + error = next(self.iter_errors(instance), None) + return error is None + @classmethod def check_schema(cls, schema): meta_schema = cls.resolver.resolve_from_url(schema['$schema']) - for error in cls(meta_schema).iter_errors(schema): + val = cls.DTVal(meta_schema, resolver=cls.resolver) + for error in val.iter_errors(schema): raise jsonschema.SchemaError.create_from(error) fixup_schema(schema) @@ -1233,7 +1241,7 @@ def _check_schema_refs(self, schema): @classmethod def check_schema_refs(self, filename, schema): - scope = self.ID_OF(schema) + scope = schema['$id'] if scope: self.resolver.push_scope(scope) diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index f810e631..bd0ead08 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -26,10 +26,6 @@ def setUp(self): self.schema = dtschema.load(os.path.join(basedir, 'schemas/good-example.yaml')) self.bad_schema = dtschema.load(os.path.join(basedir, 'schemas/bad-example.yaml')) - def test_metaschema_valid(self): - '''The DTValidator metaschema must be a valid Draft7 schema''' - jsonschema.Draft7Validator.check_schema(dtschema.DTValidator.META_SCHEMA) - def test_all_metaschema_valid(self): '''The metaschema must all be a valid Draft2019-09 schema''' for filename in glob.iglob(os.path.join(dtschema_dir, 'meta-schemas/**/*.yaml'), recursive=True): From 0e28a44059a6e33314784cfaf7b45d48afd10527 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 23 Aug 2022 14:28:23 -0500 Subject: [PATCH 272/505] meta-schemas: Allow '#' anywhere is DT property names While it's preferred that '#' is only allowed at the beginning of property names, there's a case, 'marvell,#interrupts', that has it in the middle, so relax the regex. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index d5889764..d6a25db1 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -169,7 +169,7 @@ properties: propertyNames: allOf: - description: Expected a valid DT property name - pattern: "^[#$a-zA-Z][a-zA-Z0-9,+\\-._@]{0,63}$" + pattern: "^[#$a-zA-Z][a-zA-Z0-9#,+\\-._@]{0,63}$" - description: A json-schema keyword was found instead of a DT property name. not: $ref: "#/definitions/json-schema-prop-names" From 5efef3f04dc2c286db1609275bcf783172c61d69 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 29 Aug 2022 16:29:18 -0500 Subject: [PATCH 273/505] dtschema: Support opening DTB files without '.dtb' extension Signed-off-by: Rob Herring --- dtschema/lib.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 48484431..ffbfd5b3 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1023,9 +1023,14 @@ def property_get_type_dim(propname): def load(filename, line_number=False): - if filename.endswith('.dtb'): - with open(filename, 'rb') as f: - return [ dtschema.dtb.fdt_unflatten(f.read()) ] + try: + if not filename.endswith('.yaml'): + with open(filename, 'rb') as f: + return [ dtschema.dtb.fdt_unflatten(f.read()) ] + except: + if filename.endswith('.dtb'): + raise + with open(filename, 'r', encoding='utf-8') as f: if line_number: return rtyaml.load(f.read()) From b061654bcbafa9c46d4ce7d7d181547a0d3ac24d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 29 Aug 2022 16:31:30 -0500 Subject: [PATCH 274/505] dtschema: Test if errors have 'note' attr Errors may not have a 'note' attr added in all cases. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index ffbfd5b3..e590ad71 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1326,7 +1326,7 @@ def format_error(filename, error, prefix="", nodename=None, verbose=False): msg += '\n' + format_error(filename, suberror, prefix=prefix+"\t", nodename=nodename, verbose=verbose) elif suberror.message not in msg: msg += '\n' + prefix + '\t' + suberror.message - if suberror.note and suberror.note != error.note: + if hasattr(suberror, 'note') and suberror.note != error.note: msg += '\n\t\t' + prefix + 'hint: ' + suberror.note elif error.schema_path[-1] == 'oneOf': From 03d7a5dc49a5442b70fba5d46cd5775f58651f27 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 1 Sep 2022 16:09:39 -0500 Subject: [PATCH 275/505] dtschema: Handle 'msi-ranges' in dtb decoding Signed-off-by: Rob Herring --- dtschema/dtb.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 0473c85a..0492dc97 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -251,6 +251,7 @@ def fdt_scan_node(fdt, nodename, offset): 'mboxes': '#mbox-cells', 'sound-dai': '#sound-dai-cells', 'msi-parent': '#msi-cells', + 'msi-ranges': '#interrupt-cells', 'gpio-ranges': 3, 'nvmem-cells': None, @@ -330,6 +331,10 @@ def fixup_phandles(dt, path=''): #print(k, v) break + # Special case for msi-ranges which has an additional span cell + if k == 'msi-ranges': + cells += 1 + # Special case for interconnects which is pairs of phandles+args if k == 'interconnects': cells += _get_phandle_arg_size(path + ':' + k, i + cells, val[i + cells:], cellname) From 26c0f4357e153623c27c28a2c76de66cd045bcbf Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 9 Sep 2022 11:57:29 -0500 Subject: [PATCH 276/505] dtschema: Another fix for errors 'note' attr Commit b061654bcbaf ("dtschema: Test if errors have 'note' attr") changed checking error 'note' attr exists, but we still need to check it is not None. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index e590ad71..fb4560d3 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1326,7 +1326,7 @@ def format_error(filename, error, prefix="", nodename=None, verbose=False): msg += '\n' + format_error(filename, suberror, prefix=prefix+"\t", nodename=nodename, verbose=verbose) elif suberror.message not in msg: msg += '\n' + prefix + '\t' + suberror.message - if hasattr(suberror, 'note') and suberror.note != error.note: + if hasattr(suberror, 'note') and suberror.note and suberror.note != error.note: msg += '\n\t\t' + prefix + 'hint: ' + suberror.note elif error.schema_path[-1] == 'oneOf': From 4cc58d9dc4d4a4f49a517d82f4502b2d57120221 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 11 Sep 2022 21:06:09 +0200 Subject: [PATCH 277/505] dt-validate: if node is disabled, pass on any missing property Validation of a node with with disabled nodes is failing, if the schema references multiple other schemas in oneOf. For example: mdss { ... dsi-phy@c996400 { ... // Some required property is missing status = "disabled"; }; }; and schema: properties: "^dsi-phy@[1-9a-f][0-9a-f]*$": type: object oneOf: - $ref: dsi-phy-14nm.yaml - $ref: dsi-phy-20nm.yaml - $ref: dsi-phy-28nm.yaml The check_node() was ignoring errors for disabled nodes if they contained 'required property' in error message or all of sub-errors do not have such error. Thus if any of referenced schemas failed with any other error, the entire check failed. Rework check_node() so it will ignore errors for disabled nodes if any of messages contain 'required property'. This might hide some useful errors, but only for disabled nodes which is not that important. Signed-off-by: Krzysztof Kozlowski --- tools/dt-validate | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/dt-validate b/tools/dt-validate index ba60092d..28350954 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -60,10 +60,12 @@ class schema_group(): if 'required property' in error.message: continue elif error.context: + found = False for e in error.context: - if not 'required property' in e.message: + if 'required property' in e.message: + found = True break - else: + if found: continue if schema['$id'] == 'generated-compatibles': From 9d47ffaacf28158876bd12e3c0fe582abb80e391 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 14 Sep 2022 13:19:37 -0500 Subject: [PATCH 278/505] dtschema: Skip dtb decoding fixups for phandle-arrays with fixed dimensions Some phandle-array properties which happen to end in 's' get truncated by mistake. 'phandle-array' types with fixed dimensions have already been decoded before fixup_phandles() runs, so make sure they are skipped. Signed-off-by: Rob Herring --- dtschema/__init__.py | 1 + dtschema/dtb.py | 2 ++ dtschema/lib.py | 8 ++++++++ 3 files changed, 11 insertions(+) diff --git a/dtschema/__init__.py b/dtschema/__init__.py index cb1e4094..28751f71 100644 --- a/dtschema/__init__.py +++ b/dtschema/__init__.py @@ -10,6 +10,7 @@ get_undocumented_compatibles, property_get_type, property_get_type_dim, + property_has_fixed_dimensions, sized_int, ) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 0492dc97..adfc710c 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -306,6 +306,8 @@ def fixup_phandles(dt, path=''): continue elif not {'phandle-array'} & set(dtschema.property_get_type(k)): continue + elif dtschema.property_has_fixed_dimensions(k): + continue elif not isinstance(v, list) or (len(v) > 1 or not isinstance(v[0], list)): # Not a matrix or already split, nothing to do continue diff --git a/dtschema/lib.py b/dtschema/lib.py index fb4560d3..60537cab 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1022,6 +1022,14 @@ def property_get_type_dim(propname): return None +def property_has_fixed_dimensions(propname): + dim = property_get_type_dim(propname) + if dim and dim[0][0] == dim[0][1] or dim[1][0] == dim[1][1]: + return True + + return False + + def load(filename, line_number=False): try: if not filename.endswith('.yaml'): From b592e121db9b3d936a61e48b704b253b48c9955d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 15 Sep 2022 09:51:41 -0500 Subject: [PATCH 279/505] dtschema: Use a set instead of list for property types A set is a better match for storing property types. Signed-off-by: Rob Herring --- dtschema/dtb.py | 13 ++++++------- dtschema/lib.py | 8 ++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index adfc710c..4f556c4b 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -76,27 +76,26 @@ def prop_value(nodename, p): if nodename in {'__fixups__', 'aliases'}: return data[:-1].decode(encoding='ascii').split('\0') - prop_types = dtschema.property_get_type(p.name) - if 'node' in prop_types: - prop_types.remove('node') + prop_types = set(dtschema.property_get_type(p.name)) + prop_types -= {'node'} if len(prop_types) > 1: - if {'string', 'string-array'} & set(prop_types): + if {'string', 'string-array'} & prop_types: str = bytes_to_string(data) if str: return str # Assuming only one other type try: - fmt = set(prop_types).difference({'string', 'string-array'}).pop() + fmt = prop_types.difference({'string', 'string-array'}).pop() except: return data elif 'flag' in prop_types and len(data): - fmt = set(prop_types).difference({'flag'}).pop() + fmt = prop_types.difference({'flag'}).pop() else: #print(p.name + ': multiple types found', file=sys.stderr) fmt = None elif len(prop_types) == 1: - fmt = prop_types[0] + fmt = prop_types.pop() if not fmt: # Primarily for aliases properties diff --git a/dtschema/lib.py b/dtschema/lib.py index 60537cab..f71811ec 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -987,19 +987,19 @@ def property_get_type(propname): if not props: props, pat_props = get_prop_types() - type = [] + type = set() if propname in props: for v in props[propname]: if v['type']: - type += [v['type']] + type.add(v['type']) if len(type) == 0: for v in pat_props.values(): if v[0]['type'] and v[0]['type'] not in type and v[0]['regex'].search(propname): - type += [v[0]['type']] + type.add(v[0]['type']) # Don't return 'node' as a type if there's other types if len(type) > 1 and 'node' in type: - type.remove('node') + type -= {'node'} return type From 3995ddefeed80957cd167476acf54ac4d6046a4e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 22 Aug 2022 19:40:27 -0500 Subject: [PATCH 280/505] schemas: Make 32-bit sizes explicit Without an explicit size, 32-bit type schemas will pass on other sizes. This is not yet a problem, but will be with the next commit. Signed-off-by: Rob Herring --- dtschema/lib.py | 6 ++---- dtschema/schemas/types.yaml | 6 ++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index f71811ec..89c0c520 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1140,11 +1140,9 @@ def http_handler(uri): def typeSize(validator, typeSize, instance, schema): - if not isinstance(instance[0], list): - return - if isinstance(instance[0][0], sized_int): + try: size = instance[0][0].size - else: + except: size = 32 if typeSize != size: diff --git a/dtschema/schemas/types.yaml b/dtschema/schemas/types.yaml index 4a2464ae..90b01989 100644 --- a/dtschema/schemas/types.yaml +++ b/dtschema/schemas/types.yaml @@ -168,6 +168,7 @@ definitions: uint32-matrix: type: array + typeSize: 32 minItems: 1 items: type: array @@ -178,6 +179,7 @@ definitions: # prop = <0x1234 0x5678>; # or # prop = <0x1234>, <0x5678>; + typeSize: 32 anyOf: - type: array minItems: 1 @@ -195,6 +197,7 @@ definitions: $ref: "#/definitions/cell" uint32: type: array + typeSize: 32 minItems: 1 maxItems: 1 items: @@ -212,6 +215,7 @@ definitions: int32-matrix: type: array + typeSize: 32 minItems: 1 items: type: array @@ -222,6 +226,7 @@ definitions: # prop = <0x1234 0x5678>; # or # prop = <0x1234>, <0x5678>; + typeSize: 32 anyOf: - type: array minItems: 1 @@ -239,6 +244,7 @@ definitions: $ref: "#/definitions/int32-item" int32: type: array + typeSize: 32 minItems: 1 maxItems: 1 items: From c5b87d125a705c7f6e94d119847922cb024a7def Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 15 Sep 2022 11:22:51 -0500 Subject: [PATCH 281/505] schemas: Drop 32-bit encoding for 64-bit types With dtb decoding, there's no longer a need to support 2 different encodings of 64-bit values. This may introduce warnings for YAML encoded DTs, but support for that is bit-rotting. Signed-off-by: Rob Herring --- dtschema/schemas/types.yaml | 86 +++++++++++++------------------------ 1 file changed, 30 insertions(+), 56 deletions(-) diff --git a/dtschema/schemas/types.yaml b/dtschema/schemas/types.yaml index 90b01989..867036c5 100644 --- a/dtschema/schemas/types.yaml +++ b/dtschema/schemas/types.yaml @@ -289,65 +289,39 @@ definitions: items: $ref: "#/definitions/int64-item" + uint64-item: + type: integer + minimum: 0 + maximum: 0xffffffffffffffff + uint64: - oneOf: - - type: array - minItems: 1 - maxItems: 1 - items: - type: array - items: - $ref: "#/definitions/cell" - minItems: 2 - maxItems: 2 - - type: array - minItems: 1 - maxItems: 1 - typeSize: 64 - items: - type: array - items: - minimum: 0 - maximum: 0xffffffffffffffff - minItems: 1 - maxItems: 1 + type: array + minItems: 1 + maxItems: 1 + typeSize: 64 + items: + type: array + items: + $ref: "#/definitions/uint64-item" + minItems: 1 + maxItems: 1 uint64-array: - oneOf: - - type: array - minItems: 1 - maxItems: 1 - typeSize: 32 - items: - type: array - items: - $ref: "#/definitions/cell" - minItems: 2 - - type: array - minItems: 1 - maxItems: 1 - typeSize: 64 - items: - type: array - items: - minimum: 0 - maximum: 0xffffffffffffffff + type: array + minItems: 1 + maxItems: 1 + typeSize: 64 + items: + type: array + items: + $ref: "#/definitions/uint64-item" uint64-matrix: - oneOf: - - type: array - minItems: 1 - items: - type: array - items: - $ref: "#/definitions/cell" - minItems: 2 - - type: array - minItems: 1 - typeSize: 64 - items: - type: array - items: - minimum: 0 - maximum: 0xffffffffffffffff + type: array + minItems: 1 + typeSize: 64 + items: + type: array + items: + $ref: "#/definitions/uint64-item" phandle: type: array From 4d0dc855679266b053e14a1cc38ab23ab2f2dcfe Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 15 Sep 2022 09:55:47 -0500 Subject: [PATCH 282/505] dtschema: Filter out property types which don't match a property length This fixes a problem where a property with a type of 'uint32' or 'phandle-array' was selected to be 'uint32-array' (divisible by 4) and fixup_phandles() was then skipped. Signed-off-by: Rob Herring --- dtschema/dtb.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 4f556c4b..c1473b31 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -79,6 +79,17 @@ def prop_value(nodename, p): prop_types = set(dtschema.property_get_type(p.name)) prop_types -= {'node'} + # Filter out types impossible for the size of the property + if len(prop_types) > 1: + if len(p) > 4: + prop_types -= {'int32', 'uint32'} + if len(p) > 2: + prop_types -= {'int16', 'uint16'} + if len(p) > 1: + prop_types -= {'int8', 'uint8'} + else: + prop_types -= {'flag'} + if len(prop_types) > 1: if {'string', 'string-array'} & prop_types: str = bytes_to_string(data) @@ -89,8 +100,6 @@ def prop_value(nodename, p): fmt = prop_types.difference({'string', 'string-array'}).pop() except: return data - elif 'flag' in prop_types and len(data): - fmt = prop_types.difference({'flag'}).pop() else: #print(p.name + ': multiple types found', file=sys.stderr) fmt = None From a62404d64e6dc7d18610b17bdb8765ad3d18189e Mon Sep 17 00:00:00 2001 From: sean-anderson-seco <74551845+sean-anderson-seco@users.noreply.github.com> Date: Mon, 12 Sep 2022 15:59:18 -0400 Subject: [PATCH 283/505] schemas: phy: Increase phy-type maximum With the (pending) addition of PHY_TYPE_2500BASEX and PHY_TYPE_10GBASER [1], the maximum value for phy-type must also be increased. [1] https://lore.kernel.org/linux-phy/20220902213721.946138-2-sean.anderson@seco.com/ Signed-off-by: Sean Anderson --- dtschema/schemas/phy/phy-provider.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/phy/phy-provider.yaml b/dtschema/schemas/phy/phy-provider.yaml index 9b901a54..daeaf6ec 100644 --- a/dtschema/schemas/phy/phy-provider.yaml +++ b/dtschema/schemas/phy/phy-provider.yaml @@ -23,7 +23,7 @@ properties: set in the PHY cells. $ref: /schemas/types.yaml#/definitions/uint32 minimum: 1 - maximum: 11 + maximum: 13 required: - "#phy-cells" From 4f386ecbd81398462a4eb98d615f23730803ad0f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 15 Sep 2022 13:19:43 -0500 Subject: [PATCH 284/505] schemas: chosen: Fix linux,ima-kexec-buffer description formatting Signed-off-by: Rob Herring --- dtschema/schemas/chosen.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dtschema/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml index ea71fe22..bbb53313 100644 --- a/dtschema/schemas/chosen.yaml +++ b/dtschema/schemas/chosen.yaml @@ -185,7 +185,7 @@ properties: linux,ima-kexec-buffer: $ref: types.yaml#definitions/uint64-array maxItems: 2 - description: + description: | This property(currently used by powerpc, arm64) holds the memory range, "the address and the size", of the Integrity Measuremnet Architecture(IMA) measurement logs that are being carried over to the new kernel. @@ -193,8 +193,8 @@ properties: / { chosen { linux,ima-kexec-buffer = <0x9 0x82000000 0x0 0x00008000>; - }; - }; + }; + }; This property does not represent real hardware, but the memory allocated for carrying the IMA measurement logs. The address and the suze are expressed in From 9834d10385b30d2c1b7b52f34931904455a91289 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 23 Jun 2022 22:05:10 -0500 Subject: [PATCH 285/505] schemas: chosen: Fix typos in description of 'linux,ima-kexec-buffer' Signed-off-by: Stefan Berger --- dtschema/schemas/chosen.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dtschema/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml index bbb53313..fd439e20 100644 --- a/dtschema/schemas/chosen.yaml +++ b/dtschema/schemas/chosen.yaml @@ -187,7 +187,7 @@ properties: maxItems: 2 description: | This property(currently used by powerpc, arm64) holds the memory range, - "the address and the size", of the Integrity Measuremnet Architecture(IMA) + "the address and the size", of the Integrity Measurement Architecture(IMA) measurement logs that are being carried over to the new kernel. / { @@ -197,7 +197,7 @@ properties: }; This property does not represent real hardware, but the memory allocated for - carrying the IMA measurement logs. The address and the suze are expressed in + carrying the IMA measurement logs. The address and the size are expressed in #address-cells and #size-cells, respectively of the root node. u-boot,bootconf: From 50495c80441601cd468d3be39d4db0c6c40a3b7e Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 23 Jun 2022 22:07:01 -0500 Subject: [PATCH 286/505] schemas: chosen: Add description for 'linux,tpm-kexec-buffer' Add a memory range (address and size) propery to pass to the new kernel. Signed-off-by: Stefan Berger --- dtschema/schemas/chosen.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dtschema/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml index fd439e20..ca09186a 100644 --- a/dtschema/schemas/chosen.yaml +++ b/dtschema/schemas/chosen.yaml @@ -200,6 +200,24 @@ properties: carrying the IMA measurement logs. The address and the size are expressed in #address-cells and #size-cells, respectively of the root node. + linux,tpm-kexec-buffer: + $ref: types.yaml#definitions/uint64-array + maxItems: 2 + description: | + This property (currently used by powerpc64) holds the memory range, + "the address and the size", of the TPM's measurement log that is being + carried over to the new kernel. + + / { + chosen { + linux,tpm-kexec-buffer = <0x9 0x82000000 0x0 0x00008000>; + }; + }; + + This property does not represent real hardware, but the memory allocated for + carrying the TPM measurement log. The address and the size are expressed in + #address-cells and #size-cells, respectively of the root node. + u-boot,bootconf: $ref: types.yaml#/definitions/string description: From c406d9115bff68e130c268295e04859367636764 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Brucker Date: Wed, 14 Sep 2022 17:45:13 +0100 Subject: [PATCH 287/505] schemas: qemu,platform: Add interrupt-parent property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The device-tree node for the qemu,plaform bus contains an interrupt-parent property, even though only the bus' children generate interrupts. According to the specification v0.3, the interrupt-parent property should only be on devices generating interrupts: Nodes that represent interrupt-generating devices contain an interrupt-parent property which has a phandle value that points to the device to which the device’s interrupts are routed, typically an interrupt controller. If an interrupt-generating device does not have an interrupt-parent property, its interrupt parent is assumed to be its devicetree parent. However, the interrupt-parent property is commonly found in root and intermediate bus nodes so this case is de facto valid [1]. Add the interrupt-parent property to the schema. Unfortunately this requires removing the current rule for interrupt-parent, otherwise it produces a syntax error ("qemu,platform.yaml: ignoring, error in schema: properties: interrupt-parent" "False schema does not allow {'$ref': '/schemas/types.yaml#/definitions/phandle'}") [1] https://www.spinics.net/lists/devicetree-spec/msg00839.html Signed-off-by: Jean-Philippe Brucker Signed-off-by: Rob Herring --- dtschema/meta-schemas/interrupts.yaml | 5 ++++- dtschema/schemas/bus/qemu,platform.yaml | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/interrupts.yaml b/dtschema/meta-schemas/interrupts.yaml index d3816e28..1b6c1e9e 100644 --- a/dtschema/meta-schemas/interrupts.yaml +++ b/dtschema/meta-schemas/interrupts.yaml @@ -21,13 +21,16 @@ properties: oneOf: - $ref: "boolean.yaml" - $ref: "nodes.yaml" - interrupt-parent: false # interrupt-parent is implicit dependentRequired: interrupt-map: ['#interrupt-cells'] 'interrupt-map-mask': [ interrupt-map ] dependentSchemas: + 'interrupts': + properties: + interrupt-parent: false # interrupt-parent is implicitly allowed (added by tooling) + '#interrupt-cells': anyOf: - required: diff --git a/dtschema/schemas/bus/qemu,platform.yaml b/dtschema/schemas/bus/qemu,platform.yaml index aa45bee7..b9546a4d 100644 --- a/dtschema/schemas/bus/qemu,platform.yaml +++ b/dtschema/schemas/bus/qemu,platform.yaml @@ -39,6 +39,8 @@ properties: non-posted memory accesses (i.e. a non-posted mapping mode) for MMIO ranges. + interrupt-parent: true + patternProperties: # All other properties should be child nodes with unit-address and 'reg' "@(0|[1-9a-f][0-9a-f]*)$": From 99646e265f78c0f34f8597393d14c668fc59fe62 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 27 Sep 2022 17:21:05 -0500 Subject: [PATCH 288/505] meta-schemas: Restrict 'const' to scalar values While the jsonschema spec allows for array values of 'const', we don't have a use for that currently. It could be useful, but is probably confusing to have 2 different forms and the fixups certainly assume 'const' is a scalar value. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index d6a25db1..70c48a50 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -129,6 +129,8 @@ properties: uniqueItems: true else: $ref: "#/definitions/sub-schemas" + const: + type: [ integer, string ] enum: type: array uniqueItems: true From f2b7cbf87ad4753dd28e0b6a75725fb035a2afc7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 27 Sep 2022 16:20:14 -0500 Subject: [PATCH 289/505] dtschema: Relax validation of schemas when processed New meta-schema checks cause existing schemas to have warnings which causes the entire schema to be omitted when it was previously included. This is not great because all the new warnings have to be fixed before a new version of dtschema can be used. Let's relax the validation to just check against Draft7 schema instead of the full DT schema. That should be good enough to exclude things which aren't valid at all. Signed-off-by: Rob Herring --- dtschema/lib.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 89c0c520..785c89fd 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -726,7 +726,7 @@ def process_schema(filename): # Check that the validation schema is valid try: - DTValidator.check_schema(schema) + DTValidator.check_schema(schema, strict=False) except jsonschema.SchemaError as exc: print(filename + ": ignoring, error in schema: " + ': '.join(str(x) for x in exc.path), file=sys.stderr) @@ -1232,8 +1232,16 @@ def is_valid(self, instance): return error is None @classmethod - def check_schema(cls, schema): - meta_schema = cls.resolver.resolve_from_url(schema['$schema']) + def check_schema(cls, schema, strict=True): + """ + Test if schema is valid and apply fixups + 'strict' determines whether the full DT meta-schema is used or just the draft7 meta-schema + """ + if strict: + meta_schema = cls.resolver.resolve_from_url(schema['$schema']) + else: + # Using the draft7 metaschema because 2019-09 with $recursiveRef seems broken + meta_schema = jsonschema.Draft7Validator.META_SCHEMA val = cls.DTVal(meta_schema, resolver=cls.resolver) for error in val.iter_errors(schema): raise jsonschema.SchemaError.create_from(error) From 43e6cdcb770946a8a06d1212b1be08ec1864e312 Mon Sep 17 00:00:00 2001 From: sean-anderson-seco <74551845+sean-anderson-seco@users.noreply.github.com> Date: Tue, 20 Sep 2022 15:55:07 -0400 Subject: [PATCH 290/505] schemas: phy: Once again increase phy-type maximum With the combination of [1] and (soon to be resent) [2], the maximum value for phy-type must be increased to a minimum of 14. To give us some breathing room, increase the maximum to 32. This should reduce the number of patches needed when adding new phy types for the near future. [1] https://lore.kernel.org/r/20220628122255.24265-3-rogerq@kernel.org [2] https://lore.kernel.org/linux-phy/20220902213721.946138-2-sean.anderson@seco.com/ Signed-off-by: Sean Anderson --- dtschema/schemas/phy/phy-provider.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/phy/phy-provider.yaml b/dtschema/schemas/phy/phy-provider.yaml index daeaf6ec..5e9dc7ce 100644 --- a/dtschema/schemas/phy/phy-provider.yaml +++ b/dtschema/schemas/phy/phy-provider.yaml @@ -23,7 +23,7 @@ properties: set in the PHY cells. $ref: /schemas/types.yaml#/definitions/uint32 minimum: 1 - maximum: 13 + maximum: 32 required: - "#phy-cells" From 4ee50b70379c74d192a2b556ed3e45ab7f9b2c04 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 7 Oct 2022 09:36:57 -0500 Subject: [PATCH 291/505] README: Add examples of running commands Signed-off-by: Rob Herring --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 4b72d018..61b8902e 100644 --- a/README.md +++ b/README.md @@ -89,17 +89,32 @@ There are several tools available in the *tools/* directory. This tool takes a schema file(s) or directory of schema files and validates them against the DT meta-schema. +Example: +``` +dt-doc-validate -u test/schema test/schemas/good-example.yaml +``` + `tools/dt-mk-schema` This tool takes user-provided schema file(s) plus the core schema files in this repo, removes everything not needed for validation, applies fix-ups to the schemas, and outputs a single file with the processed schema. This step is done separately to speed up subsequent validation of YAML Devicetrees. +Example: +``` +dt-mk-schema -j test/schemas/ > processed-schema.json +``` + `tools/dt-validate` This tool takes user-provided YAML Devicetree(s) and either a schema directory or pre-processed schema file and validates the YAML Devicetree against the schema. +Example: +``` +dtc -O dtb -o device.dtb test/device.dts +dt-validate -s processed-schema.json device.dtb +``` ## Installing The project and its dependencies can be installed with pip: From 810d7e1ff19da00e3129e97d5fd01bfb182f4f05 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 10 Oct 2022 12:54:29 -0500 Subject: [PATCH 292/505] README: Add details on dt-check-compatible Signed-off-by: Rob Herring --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 61b8902e..4b547c36 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,16 @@ dtc -O dtb -o device.dtb test/device.dts dt-validate -s processed-schema.json device.dtb ``` +`tools/dt-check-compatible` +This tool tests whether a list of compatible strings are found or not in +the schemas. By default, a compatible string is printed when it matches +one (or a pattern) in the schemas. + +Example: +``` +dt-check-compatible -s processed-schema.json vendor,a-compatible +``` + ## Installing The project and its dependencies can be installed with pip: From cb0edfe5be8f5b99667db25e9dbd0b8c2e20d877 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 7 Oct 2022 09:40:23 -0500 Subject: [PATCH 293/505] README: Remove stale details on YAML encoded DTs Use of the YAML encoded DT is optional now in favor of using direct DTB validation. The YAML encoding is not stored in the repository now either. Rework the README to remove some of these out of date details. Signed-off-by: Rob Herring --- README.md | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 4b547c36..ae849a16 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,16 @@ -# Tooling for devicetree validation using YAML and jsonschema +# Devicetree Schema Tools This repository contains test code for devicetree schema validation using the [json-schema](http://json-schema.org/documentation.html) vocabulary. Schema -files are written in YAML (a superset of JSON), and operate on the YAML -encoding of Devicetree data. Devicetree data must be transcoded from DTS to -YAML before being used by this tool. +files are written in a JSON compatible subset of YAML. ## Data Model To understand how validation works, it is important to understand how schema data is organized and used. If you're reading this, I assume you're already familiar with Devicetree and the .dts file format. -In this repository you will find three kinds of files; *YAML Devicetrees*, *Schemas* and *Meta-Schemas*. - -### *YAML Devicetrees* - -Found under `./test` - -*YAML Devicetrees* files are regular .dts files transcoded into a YAML -representation. -There is no special information in these files. -They are used as test cases against the validation tooling. - -Validation of .dtb files is now supported and preferred over YAML DT encoding. +In this repository you will find 2 kinds of files; *Schemas* and +*Meta-Schemas*. ### *Devicetree Schemas* @@ -82,6 +70,18 @@ As a developer you normally will not need to write metaschema files. Devicetree Meta-Schema files are normal YAML files using the jsonschema vocabulary. +### *YAML Devicetrees* + +*YAML Devicetrees* files are regular .dts files transcoded into a YAML +representation. +There is no special information in these files. They are an intermediate +format suitable for the schema validation tools. + +Direct validation of .dtb files is also supported and preferred over +YAML DT encoding. As the DTB format has no type information within it, +the Devicetree Schemas are used for their type information to decode +the DT property values. + ## Usage There are several tools available in the *tools/* directory. @@ -97,8 +97,9 @@ dt-doc-validate -u test/schema test/schemas/good-example.yaml `tools/dt-mk-schema` This tool takes user-provided schema file(s) plus the core schema files in this repo, removes everything not needed for validation, applies fix-ups to the -schemas, and outputs a single file with the processed schema. This step is -done separately to speed up subsequent validation of YAML Devicetrees. +schemas, and outputs a single file with the processed schema. This step +is optional and can be done separately to speed up subsequent validation +of Devicetrees. Example: ``` @@ -106,9 +107,9 @@ dt-mk-schema -j test/schemas/ > processed-schema.json ``` `tools/dt-validate` -This tool takes user-provided YAML Devicetree(s) and either a schema directory -or pre-processed schema file and validates the YAML Devicetree against the -schema. +This tool takes user-provided Devicetree(s) and either a schema directory +or a pre-processed schema file from `dt-mk-schema`, and then validates the +Devicetree against the schema. Example: ``` From c5c022e2cb480c073ad950bd9a012c0d3090c584 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 7 Oct 2022 09:42:31 -0500 Subject: [PATCH 294/505] README: Re-wrap some long lines Signed-off-by: Rob Herring --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ae849a16..162a33bf 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ files are written in a JSON compatible subset of YAML. ## Data Model -To understand how validation works, it is important to understand how schema data is organized and used. -If you're reading this, I assume you're already familiar with Devicetree and the .dts file format. +To understand how validation works, it is important to understand how +schema data is organized and used. If you're reading this, I assume +you're already familiar with Devicetree and the .dts file format. In this repository you will find 2 kinds of files; *Schemas* and *Meta-Schemas*. From ea2acfa5267a064ec595c733b49a754bc02ab99d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Oct 2022 17:21:09 -0500 Subject: [PATCH 295/505] README: More minor rework Signed-off-by: Rob Herring --- README.md | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 162a33bf..d4884748 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ # Devicetree Schema Tools -This repository contains test code for devicetree schema validation using the -[json-schema](http://json-schema.org/documentation.html) vocabulary. Schema -files are written in a JSON compatible subset of YAML. +The dtschema module contains tools and schema data for Devicetree +schema validation using the +[json-schema](http://json-schema.org/documentation.html) vocabulary. +The tools validate Devicetree files using DT binding schema files. The +tools also validate the DT binding schema files. Schema files are +written in a JSON compatible subset of YAML to be both human and machine +readable. ## Data Model @@ -10,7 +14,7 @@ To understand how validation works, it is important to understand how schema data is organized and used. If you're reading this, I assume you're already familiar with Devicetree and the .dts file format. -In this repository you will find 2 kinds of files; *Schemas* and +In this repository you will find 2 kinds of data files; *Schemas* and *Meta-Schemas*. ### *Devicetree Schemas* @@ -19,32 +23,31 @@ Found under `./dtschema/schemas` *Devicetree Schemas* describe the format of devicetree data. The raw Devicetree file format is very open ended and doesn't restrict how -data is encoded. -Hence, it is easy to make mistakes when writing a Devicetree. -Schema files impose constraints on what data can be put into a devicetree. -As the foundation, a single core schema describes all the common property types -that every devicetree node must match. -e.g. In every node the 'compatible' property must be an array of strings. -However, most devicetree data is heterogeneous as each device binding requires -a different set of data, therefore multiple schema files are used to capture the -data format of an entire devicetree. +data is encoded.Hence, it is easy to make mistakes when writing a +Devicetree. Schema files impose the constraints on what data can be put +into a Devicetree. + +This repository contains the 'core' schemas which consists of DT +properties defined within the DT Specification and common bindings such +as the GPIO, clock, and PHY bindings. + +This repository does not contain device specific bindings. Those are +currently maintained within the Linux kernel tree alongside Devicetree +files (.dts). When validating, the tool will load all the schema files it can find and then -iterate over all the nodes of the devicetree. +iterate over all the nodes of the Devicetree. For each node, the tool will determine which schema(s) are applicable and make sure the node data matches the schema constraints. Nodes failing a schema test will emit an error. -Nodes that don't match any schema will emit a warning. +Nodes that don't match any schema can emit a warning. -As a developer, you would write a devicetree schema file for each new +As a developer, you would write a Devicetree schema file for each new device binding that you create and add it to the `./schemas` directory. Schema files also have the dual purpose of documenting a binding. When you define a new binding, you only have to create one file that contains both the machine-verifiable data format and the documentation. -Documentation generation tools are being written to extract documentation -from a schema file and emit a format that can be included in the devicetree -specification documents. Devicetree Schema files are normal YAML files using the jsonschema vocabulary. @@ -65,7 +68,10 @@ Found in `./dtschema/meta-schemas` *Devicetree Meta-Schemas* describe the data format of Devicetree Schema files. The Meta-schemas make sure all the binding schemas are in the correct format -and the tool will emit an error if the format is incorrect. +and the tool will emit an error if the format is incorrect. json-schema +by default is very relaxed in terms of what is allowed in schemas. Unknown +keywords are silently ignored as an example. The DT Meta-schemas are designed +to limit what is allowed and catch common errors in writing schemas. As a developer you normally will not need to write metaschema files. From 128715919ba2874f0a13ea63dd18a43ae6db4874 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Oct 2022 10:33:10 -0500 Subject: [PATCH 296/505] meta-schemas: Add a hint for wrong $ref URL The error message for $ref paths is not very clear, so add a hint as to what is correct. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 70c48a50..1d697da6 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -104,6 +104,9 @@ dependentRequired: properties: $ref: + description: + References must start with '/schemas' or be relative to current + schema's path. pattern: '^(/schemas/|\.\./|#(/|$)|[a-zA-Z0-9]+)' not: pattern: '^https?://' From 8f8e82a863469252b9f53b6a9532cdc6fda334b1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Oct 2022 11:09:11 -0500 Subject: [PATCH 297/505] dt-extract-example: Add missing ctrl-C handler We generally don't want backtraces on a ctrl-C, so a signal handler is needed to catch these globally. dt-extract-example was missing one. Signed-off-by: Rob Herring --- tools/dt-extract-example | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/dt-extract-example b/tools/dt-extract-example index e4c6c221..224d33da 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -3,6 +3,13 @@ # Copyright 2018 Linaro Ltd. # Copyright 2019-2022 Arm Ltd. +import signal + +def sigint_handler(signum, frame): + exit(130) + +signal.signal(signal.SIGINT, sigint_handler) + import os import re import sys From 89081468d4e1be88a5690aaa4986525b14d1aa49 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Oct 2022 10:32:36 -0500 Subject: [PATCH 298/505] dtschema: Raise schema error when '$schema' keyword is missing or invalid It is possible to have valid YAML, but has errors such that the meta-schema can't be identified. For example '$schema' keyword is missing. Raise an exception in this case. Signed-off-by: Rob Herring --- dtschema/lib.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 785c89fd..74d8df4e 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1209,7 +1209,15 @@ def annotate_error(self, error, schema, path): @classmethod def iter_schema_errors(cls, schema): - meta_schema = cls.resolver.resolve_from_url(schema['$schema']) + try: + meta_schema = cls.resolver.resolve_from_url(schema['$schema']) + except (KeyError, TypeError, jsonschema.RefResolutionError, jsonschema.SchemaError): + error = jsonschema.SchemaError("Missing or invalid $schema keyword") + error.linecol = (-1,-1) + error.note = None + error.schema_file = None + yield error + return val = cls.DTVal(meta_schema, resolver=cls.resolver) for error in val.iter_errors(schema): cls.annotate_error(error, meta_schema, error.schema_path) @@ -1331,6 +1339,8 @@ def format_error(filename, error, prefix="", nodename=None, verbose=False): #print(error.__dict__) if verbose: msg = str(error) + elif not error.schema_path: + msg = error.message elif error.context: # An error on a conditional will have context with sub-errors msg = "'" + error.schema_path[-1] + "' conditional failed, one must be fixed:" From c27e52b46bc6b4da33b2364f18a16b25548913d8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Oct 2022 13:28:40 -0500 Subject: [PATCH 299/505] dtschema: Add some checks for missing '$id' key Add checks to better handle invalid schema files. Signed-off-by: Rob Herring --- dtschema/lib.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 74d8df4e..67de4ba3 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -753,7 +753,7 @@ def process_schemas(schema_paths, core_schema=True): if not os.path.isfile(filename): continue sch = process_schema(os.path.abspath(filename)) - if not sch: + if not sch or '$id' not in sch: continue if sch['$id'] in schemas: print(os.path.abspath(filename) + ": duplicate '$id' value '" + sch['$id'] + "'", file=sys.stderr) @@ -1087,6 +1087,8 @@ def set_schemas(schema_files, core_schema=True): if isinstance(schema_cache, list): d = {} for sch in schema_cache: + if not isinstance(sch, dict): + return None d[sch['$id']] = sch schema_cache = d @@ -1268,6 +1270,8 @@ def _check_schema_refs(self, schema): @classmethod def check_schema_refs(self, filename, schema): + if '$id' not in schema: + return scope = schema['$id'] if scope: self.resolver.push_scope(scope) From 879e21fdccd96660fb9d433de2f10b63c2f4af60 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Oct 2022 13:33:03 -0500 Subject: [PATCH 300/505] dtschema: Avoid printing messages for catchall exception clauses Printing errors in unspecific exception handlers is problematic for unexpected exceptions. For example, an exception from a Ctrl-C. Signed-off-by: Rob Herring --- dtschema/lib.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 67de4ba3..3b6c937a 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -720,7 +720,7 @@ def get_undocumented_compatibles(compatible_list): def process_schema(filename): try: schema = load_schema(filename) - except: + except ruamel.yaml.YAMLError: print(filename + ": ignoring, error parsing file", file=sys.stderr) return @@ -732,10 +732,6 @@ def process_schema(filename): file=sys.stderr) #print(exc.message) return - except: - print(filename + ": ignoring, unknown error in schema (not a schema?)", - file=sys.stderr) - return if 'select' not in schema: print(filename + ": warning: no 'select' found in schema found", file=sys.stderr) From 547c943ab55f4d0b44fd88e3c36c7f6fa49c6ae2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Oct 2022 13:38:32 -0500 Subject: [PATCH 301/505] dt-doc-validate: Rework error handling With a list of files, we don't exit if there is an exception, but we do for a directory. Unify the behavior to continue on for schema errors, but exit immediately for any other exception. Signed-off-by: Rob Herring --- tools/dt-doc-validate | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/tools/dt-doc-validate b/tools/dt-doc-validate index e601f372..b5885b62 100755 --- a/tools/dt-doc-validate +++ b/tools/dt-doc-validate @@ -28,13 +28,9 @@ def check_doc(filename): str(exc.problem_mark.column + 1) + ":", exc.problem, file=sys.stderr) return 1 - try: - for error in sorted(dtschema.DTValidator.iter_schema_errors(testtree), key=lambda e: e.linecol): - print(dtschema.format_error(filename, error, verbose=args.verbose), file=sys.stderr) - ret = 1 - except: - print(filename + ': error checking schema file', file=sys.stderr) - return 1 + for error in sorted(dtschema.DTValidator.iter_schema_errors(testtree), key=lambda e: e.linecol): + print(dtschema.format_error(filename, error, verbose=args.verbose), file=sys.stderr) + ret = 1 dtschema.DTValidator.check_schema_refs(filename, testtree) dtschema.DTValidator.check_quotes(filename + ":", testtree) @@ -62,10 +58,8 @@ if __name__ == "__main__": for f in args.yamldt: if os.path.isdir(f): for filename in glob.iglob(f + "/**/*.yaml", recursive=True): - ret = check_doc(filename) - if ret != 0: - break + ret |= check_doc(filename) else: - ret = check_doc(f) + ret |= check_doc(f) exit(ret) From 7247a67f0dc8d6ea6c8c539193f67f2b2c4203bb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 3 Nov 2022 15:26:51 -0500 Subject: [PATCH 302/505] dtschema: dtb: Filter out more impossible types In order to deal with a given property having multiple possible types, the types are filtered based on the property's length. The existing code was filtering out types which are too small for the length, but not types which are too big for the length. Signed-off-by: Rob Herring --- dtschema/dtb.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index c1473b31..90c41901 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -83,12 +83,16 @@ def prop_value(nodename, p): if len(prop_types) > 1: if len(p) > 4: prop_types -= {'int32', 'uint32'} + else: + prop_types -= {'int64', 'uint64', 'int64-array', 'uint64-array'} if len(p) > 2: prop_types -= {'int16', 'uint16'} + else: + prop_types -= {'int32', 'uint32', 'int32-array', 'uint32-array'} if len(p) > 1: prop_types -= {'int8', 'uint8'} else: - prop_types -= {'flag'} + prop_types -= {'int16', 'uint16', 'int16-array', 'uint16-array', 'flag'} if len(prop_types) > 1: if {'string', 'string-array'} & prop_types: From af1d65ae593b60fca9eb39b1f9edc5514afc6b6a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 8 Nov 2022 11:47:52 -0600 Subject: [PATCH 303/505] dtschema: Handle missing error attrs Errors from schemas under a 'oneOf' won't have our added error attrs. Rework format_error() to check everywhere they are used. With this we can avoid setting empty values. Reported-by: Serge Semin Signed-off-by: Rob Herring --- dtschema/lib.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 3b6c937a..8b155d03 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1212,8 +1212,6 @@ def iter_schema_errors(cls, schema): except (KeyError, TypeError, jsonschema.RefResolutionError, jsonschema.SchemaError): error = jsonschema.SchemaError("Missing or invalid $schema keyword") error.linecol = (-1,-1) - error.note = None - error.schema_file = None yield error return val = cls.DTVal(meta_schema, resolver=cls.resolver) @@ -1225,8 +1223,6 @@ def iter_schema_errors(cls, schema): def iter_errors(self, instance, _schema=None): for error in self.validator.iter_errors(instance, _schema): error.linecol = get_line_col(instance, error.path) - error.note = None - error.schema_file = None yield error def validate(self, *args, **kwargs): @@ -1323,7 +1319,7 @@ def check_quotes(self, err_msg, schema): def format_error(filename, error, prefix="", nodename=None, verbose=False): src = prefix + os.path.abspath(filename) + ':' - if error.linecol[0] >= 0: + if hasattr(error, 'linecol') and error.linecol[0] >= 0: src = src + '%i:%i: ' % (error.linecol[0]+1, error.linecol[1]+1) else: src += ' ' @@ -1360,10 +1356,10 @@ def format_error(filename, error, prefix="", nodename=None, verbose=False): else: msg = error.message - if error.note: + if hasattr(error, 'note') and error.note: msg += '\n\t' + prefix + 'hint: ' + error.note - if error.schema_file: + if hasattr(error, 'schema_file') and error.schema_file: msg += '\n\t' + prefix + 'from schema $id: ' + error.schema_file return src + msg From 0ab470028c975f5bea14c928baeb2434ef2a1e47 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 8 Nov 2022 13:13:23 -0600 Subject: [PATCH 304/505] dt-validate: Drop sorting by line number Line numbers only worked for YAML encoded DT files which are on the way out. Signed-off-by: Rob Herring --- dtschema/lib.py | 1 - tools/dt-validate | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 8b155d03..1bce0700 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1222,7 +1222,6 @@ def iter_schema_errors(cls, schema): def iter_errors(self, instance, _schema=None): for error in self.validator.iter_errors(instance, _schema): - error.linecol = get_line_col(instance, error.path) yield error def validate(self, *args, **kwargs): diff --git a/tools/dt-validate b/tools/dt-validate index 28350954..fb1d2413 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -45,8 +45,7 @@ class schema_group(): matched_schemas.append(schema['$id']) node_matched = True try: - errors = sorted(dtschema.DTValidator(schema).iter_errors(node), key=lambda e: e.linecol) - for error in errors: + for error in dtschema.DTValidator(schema).iter_errors(node): # Disabled nodes might not have all the required # properties filled in, such as a regulator or a From 4ca57f88df3cd6c0adf43b4eda5912e1612a9e40 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 11 Nov 2022 13:22:32 -0600 Subject: [PATCH 305/505] schemas: Add 'cpus' property 'cpus' is a common property for nodes which need to be associated with a subset of CPUs. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 1622ca0e..25d509f9 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -22,6 +22,14 @@ properties: items: # Keep in sync with make_compatible_schema() pattern: "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]+$" + cpus: + description: + Phandles to CPU nodes associated with the referring node. + oneOf: + - type: object + - $ref: "types.yaml#/definitions/phandle-array" + items: + maxItems: 1 label: $ref: "types.yaml#/definitions/string" dma-coherent: From a0228fbc86c27ad363a004bb86868b36dbcd3f4d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 11 Nov 2022 13:27:55 -0600 Subject: [PATCH 306/505] schemas: Drop Grant as maintainer Grant is not actively working on DT, so drop him. He'll be back though, he can't escape. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 1 - dtschema/schemas/interrupt-controller.yaml | 1 - dtschema/schemas/interrupts.yaml | 1 - 3 files changed, 3 deletions(-) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 25d509f9..d6c563ab 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -8,7 +8,6 @@ $schema: "http://devicetree.org/meta-schemas/base.yaml#" title: Core devicetree node schema which applies to all nodes description: "Schema for core devicetree bindings" maintainers: - - Grant Likely - Rob Herring # always select the core schema diff --git a/dtschema/schemas/interrupt-controller.yaml b/dtschema/schemas/interrupt-controller.yaml index 6c9927f7..28bde688 100644 --- a/dtschema/schemas/interrupt-controller.yaml +++ b/dtschema/schemas/interrupt-controller.yaml @@ -6,7 +6,6 @@ $schema: "http://devicetree.org/meta-schemas/base.yaml#" title: Interrupt Controller devicetree node schema maintainers: - - Grant Likely - Rob Herring properties: diff --git a/dtschema/schemas/interrupts.yaml b/dtschema/schemas/interrupts.yaml index 91a947a2..63f1039f 100644 --- a/dtschema/schemas/interrupts.yaml +++ b/dtschema/schemas/interrupts.yaml @@ -6,7 +6,6 @@ $id: "http://devicetree.org/schemas/interrupts.yaml#" $schema: "http://devicetree.org/meta-schemas/base.yaml#" title: Interrupt consumer devicetree node schema maintainers: - - Grant Likely - Rob Herring # always select the core schema From 55b2016a8dc9a4d7dcc1e6cfe5b1f23c8c70d2d6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 11 Nov 2022 13:08:51 -0600 Subject: [PATCH 307/505] dt-extract-example: Don't require '/{' at the start of the example Requiring '/{' to be at the start of the examples is overly restrictive. Often include files may come first for example. Relax the regex to check for a root node anywhere. Signed-off-by: Rob Herring --- tools/dt-extract-example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/dt-extract-example b/tools/dt-extract-example index 224d33da..8bee24a0 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -69,7 +69,7 @@ if __name__ == "__main__": if 'examples' in binding.keys(): for idx,ex in enumerate(binding['examples']): # Check if example contains a root node "/{" - root_node = re.search('^/\s*{', ex) + root_node = re.search('/\s*{', ex) if not root_node: try: From eaf245e8ac4da55c65be3916a303e3b4422c8d50 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 10 Nov 2022 09:22:24 -0600 Subject: [PATCH 308/505] dtb: Improve multiple types handling for flag/boolean types Improve determining the correct type for decoding DTBs when one of the possible types is a flag/boolean. If there's no property data, then it is a boolean. Duh! Signed-off-by: Rob Herring --- dtschema/dtb.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 90c41901..abe0478b 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -92,7 +92,9 @@ def prop_value(nodename, p): if len(p) > 1: prop_types -= {'int8', 'uint8'} else: - prop_types -= {'int16', 'uint16', 'int16-array', 'uint16-array', 'flag'} + prop_types -= {'int16', 'uint16', 'int16-array', 'uint16-array'} + if len(p) > 0: + prop_types -= {'flag'} if len(prop_types) > 1: if {'string', 'string-array'} & prop_types: @@ -129,12 +131,14 @@ def prop_value(nodename, p): if fmt.startswith('string'): return data[:-1].decode(encoding='ascii').split('\0') - if fmt == 'flag': + if {'flag'} & prop_types: if len(data): - print('{prop}: boolean property with value {val}'.format(prop=p.name, val=data), - file=sys.stderr) - return data - return True + if fmt == 'flag': + print('{prop}: boolean property with value {val}'.format(prop=p.name, val=data), + file=sys.stderr) + return data + else: + return True val_int = list() #print(p.name, fmt, bytes(p)) From 6140ce5b9ef1c7041836d199fa6213d3d4ed3bad Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 15 Nov 2022 16:20:29 -0600 Subject: [PATCH 309/505] Handle special case for 'opp-hz' uint64 type 'opp-hz' was not getting decoded correctly as a uint64. 'opp-hz' is a special case which is a uint64-matrix rather than uint32. Signed-off-by: Rob Herring --- dtschema/lib.py | 11 ++++++++--- dtschema/schemas/property-units.yaml | 8 +++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 1bce0700..8f78e784 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -852,9 +852,14 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): # implicit string type prop_type = 'string-array' elif not (isinstance(items, list) and len(items) == 1 and \ - 'items' in items and isinstance(items['items'], list) and len(items['items']) == 1) and \ - unit_types_re.search(propname): - prop_type = 'uint32-matrix' + 'items' in items and isinstance(items['items'], list) and len(items['items']) == 1): + # Keep in sync with property-units.yaml + if re.search('-microvolt$', propname): + prop_type = 'uint32-matrix' + elif re.search('(^(?!opp)).*-hz$', propname): + prop_type = 'uint32-matrix' + else: + prop_type = None else: prop_type = None elif '$ref' in subschema and re.search(r'\.yaml#?$', subschema['$ref']): diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index 546fcd5c..7479e3df 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -22,6 +22,12 @@ description: select: true +# Special case(s) which don't follow the standard type. +# Please don't add to this. +properties: + opp-hz: + $ref: "types.yaml#/definitions/uint64-matrix" + patternProperties: "-bits$": $ref: "types.yaml#/definitions/uint32-array" @@ -43,7 +49,7 @@ patternProperties: "-mhz$": $ref: "types.yaml#/definitions/uint32-array" description: megahertz - "-hz$": + "(^(?!opp)).*-hz$": $ref: "types.yaml#/definitions/uint32-matrix" description: hertz (preferred) "-sec$": From 5015a086fed2224760363ba360c1a33c554267a9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 15 Nov 2022 18:45:10 -0600 Subject: [PATCH 310/505] schemas: Correct signed unit types The YAML DT encoding didn't handle signed types, so several signed types were treated as unsigned. The DTB decoding handles signed types correctly, so let's fix the ranges and types for some property units. This probably breaks the YAML DT encoding validation, but that's going to be removed soon. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- dtschema/schemas/property-units.yaml | 6 +++--- dtschema/schemas/types.yaml | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 8f78e784..aa57b3c8 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -855,7 +855,7 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): 'items' in items and isinstance(items['items'], list) and len(items['items']) == 1): # Keep in sync with property-units.yaml if re.search('-microvolt$', propname): - prop_type = 'uint32-matrix' + prop_type = 'int32-matrix' elif re.search('(^(?!opp)).*-hz$', propname): prop_type = 'uint32-matrix' else: diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index 7479e3df..062711fb 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -99,7 +99,7 @@ patternProperties: $ref: "types.yaml#/definitions/uint32-array" description: microwatt hour "-microvolt$": - $ref: "types.yaml#/definitions/uint32-matrix" + $ref: "types.yaml#/definitions/int32-matrix" description: microvolt "-picofarads$": $ref: "types.yaml#/definitions/uint32-array" @@ -110,10 +110,10 @@ patternProperties: # Temperature "-celsius$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: "types.yaml#/definitions/int32-array" description: degree Celsius "-millicelsius$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: "types.yaml#/definitions/int32-array" description: millidegree Celsius "-kelvin$": $ref: "types.yaml#/definitions/uint32-array" diff --git a/dtschema/schemas/types.yaml b/dtschema/schemas/types.yaml index 867036c5..6113d3bf 100644 --- a/dtschema/schemas/types.yaml +++ b/dtschema/schemas/types.yaml @@ -210,8 +210,7 @@ definitions: int32-item: type: integer minimum: -2147483648 - # maximum: 2147483647 - maximum: 0xffffffff + maximum: 2147483647 int32-matrix: type: array @@ -257,8 +256,7 @@ definitions: int64-item: type: integer minimum: -9223372036854775808 - # maximum: 9223372036854775807 - maximum: 0xffffffffffffffff + maximum: 9223372036854775807 int64: type: array From 65502bf9e4fdef1332db8872194f4dcedb218f1d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 17 Nov 2022 13:39:06 -0600 Subject: [PATCH 311/505] meta-schemas: Ensure 'patternProperties' aren't jsonschema vocab Just like 'properties', make sure 'patternProperties' values aren't jsonschema vocabulary. This typically happens when indentation is off. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 1d697da6..82824e6d 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -166,8 +166,13 @@ properties: - const patternProperties: propertyNames: - not: - pattern: '^\^[a-zA-Z0-9,\-._#]+\$$' + allOf: + - description: Fixed strings belong in 'properties', not 'patternProperties' + not: + pattern: '^\^[a-zA-Z0-9,\-._#]+\$$' + - description: A json-schema keyword was found instead of a DT property name. + not: + $ref: "#/definitions/json-schema-prop-names" additionalProperties: $ref: "#/definitions/sub-schemas" properties: From 13f98be981b7894d8f375667b5eeee0f282edfcb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 17 Nov 2022 13:42:55 -0600 Subject: [PATCH 312/505] schemas: Move 'gpio' property to gpio-consumer.yaml schema 'gpio' is a consumer property, so move it to the right place. Signed-off-by: Rob Herring --- dtschema/schemas/gpio/gpio-consumer.yaml | 7 +++++++ dtschema/schemas/gpio/gpio.yaml | 6 ------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/dtschema/schemas/gpio/gpio-consumer.yaml b/dtschema/schemas/gpio/gpio-consumer.yaml index 607e91b2..fbb5c9fd 100644 --- a/dtschema/schemas/gpio/gpio-consumer.yaml +++ b/dtschema/schemas/gpio/gpio-consumer.yaml @@ -16,6 +16,13 @@ properties: gpios: $ref: "/schemas/types.yaml#/definitions/phandle-array" + gpio: + # 'gpio' can appear as a property or node name + oneOf: + - type: object + - $ref: "/schemas/types.yaml#/definitions/phandle-array" + + patternProperties: "(? Date: Thu, 17 Nov 2022 13:41:36 -0600 Subject: [PATCH 313/505] schemas: Drop redundant 'schema' or 'binding' in 'title' Every schema file is a schema/binding, so there's no need to state that in every 'title'. Signed-off-by: Rob Herring --- dtschema/schemas/cache-controller.yaml | 2 +- dtschema/schemas/clock/clock.yaml | 4 +++- dtschema/schemas/cpus.yaml | 2 +- dtschema/schemas/dma/dma.yaml | 2 +- dtschema/schemas/dt-core.yaml | 4 +++- dtschema/schemas/gpio/gpio-consumer.yaml | 5 ++++- dtschema/schemas/gpio/gpio-hog.yaml | 5 ++++- dtschema/schemas/gpio/gpio.yaml | 3 ++- dtschema/schemas/graph.yaml | 2 +- dtschema/schemas/hwlock/hwlock-consumer.yaml | 2 +- dtschema/schemas/iio/iio-consumer.yaml | 2 +- dtschema/schemas/iio/iio.yaml | 2 +- dtschema/schemas/interconnects.yaml | 2 +- dtschema/schemas/interrupt-controller.yaml | 3 ++- dtschema/schemas/interrupts.yaml | 4 +++- dtschema/schemas/iommu/iommu.yaml | 2 +- dtschema/schemas/isa/isa-bridge.yaml | 2 +- dtschema/schemas/isa/isa-bus.yaml | 2 +- dtschema/schemas/mbox/mbox-consumer.yaml | 2 +- dtschema/schemas/pci/pci-bus.yaml | 2 +- dtschema/schemas/pci/pci-iommu.yaml | 2 +- dtschema/schemas/phy/phy-consumer.yaml | 2 +- dtschema/schemas/phy/phy-provider.yaml | 2 +- dtschema/schemas/pinctrl/pinctrl-consumer.yaml | 2 +- dtschema/schemas/power-domain/power-domain-consumer.yaml | 2 +- dtschema/schemas/pwm/pwm-consumer.yaml | 2 +- dtschema/schemas/reset/reset.yaml | 2 +- dtschema/schemas/serial.yaml | 2 +- test/schemas/child-node-example.yaml | 2 +- test/schemas/good-example.yaml | 2 +- 30 files changed, 44 insertions(+), 30 deletions(-) diff --git a/dtschema/schemas/cache-controller.yaml b/dtschema/schemas/cache-controller.yaml index 835b4b80..9b560970 100644 --- a/dtschema/schemas/cache-controller.yaml +++ b/dtschema/schemas/cache-controller.yaml @@ -5,7 +5,7 @@ $id: http://devicetree.org/schemas/cache-controller.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common Cache Binding +title: Common Cache Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/clock/clock.yaml b/dtschema/schemas/clock/clock.yaml index 5299653b..8b764207 100644 --- a/dtschema/schemas/clock/clock.yaml +++ b/dtschema/schemas/clock/clock.yaml @@ -5,7 +5,9 @@ --- $id: "http://devicetree.org/schemas/clock/clock.yaml#" $schema: "http://devicetree.org/meta-schemas/base.yaml#" -title: Clock binding devicetree schema + +title: Clock Common Properties + maintainers: - Michael Turquette - Stephen Boyd diff --git a/dtschema/schemas/cpus.yaml b/dtschema/schemas/cpus.yaml index 3ecfa7a5..a578b755 100644 --- a/dtschema/schemas/cpus.yaml +++ b/dtschema/schemas/cpus.yaml @@ -15,7 +15,7 @@ $id: http://devicetree.org/schemas/cpus.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common cpus binding +title: Common CPU Nodes properties maintainers: - Devicetree Specification Mailing List diff --git a/dtschema/schemas/dma/dma.yaml b/dtschema/schemas/dma/dma.yaml index af6d093f..2ff00080 100644 --- a/dtschema/schemas/dma/dma.yaml +++ b/dtschema/schemas/dma/dma.yaml @@ -5,7 +5,7 @@ $id: http://devicetree.org/schemas/dma/dma.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common DMA binding +title: DMA Consumer Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index d6c563ab..8a05b614 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -5,7 +5,9 @@ --- $id: "http://devicetree.org/schemas/dt-core.yaml#" $schema: "http://devicetree.org/meta-schemas/base.yaml#" -title: Core devicetree node schema which applies to all nodes + +title: Core Devicetree Properties + description: "Schema for core devicetree bindings" maintainers: - Rob Herring diff --git a/dtschema/schemas/gpio/gpio-consumer.yaml b/dtschema/schemas/gpio/gpio-consumer.yaml index fbb5c9fd..a2a7236a 100644 --- a/dtschema/schemas/gpio/gpio-consumer.yaml +++ b/dtschema/schemas/gpio/gpio-consumer.yaml @@ -2,8 +2,11 @@ # Copyright 2018 Linaro Ltd. $id: "http://devicetree.org/schemas/gpio/gpio-consumer.yaml#" $schema: "http://devicetree.org/meta-schemas/base.yaml#" -title: GPIO consumer devicetree schema + +title: GPIO Consumer Common Properties + description: "Schema for GPIO consumer devicetree bindings" + maintainers: - Rob Herring diff --git a/dtschema/schemas/gpio/gpio-hog.yaml b/dtschema/schemas/gpio/gpio-hog.yaml index 8b15c859..66e16a00 100644 --- a/dtschema/schemas/gpio/gpio-hog.yaml +++ b/dtschema/schemas/gpio/gpio-hog.yaml @@ -2,8 +2,11 @@ # Copyright 2018 Linaro Ltd. $id: "http://devicetree.org/schemas/gpio/gpio-hog.yaml#" $schema: "http://devicetree.org/meta-schemas/base.yaml#" -title: GPIO hog devicetree schema + +title: GPIO Hog Nodes + description: "Schema for GPIO hog devicetree bindings" + maintainers: - Rob Herring diff --git a/dtschema/schemas/gpio/gpio.yaml b/dtschema/schemas/gpio/gpio.yaml index 4c17bc05..59f7b7ea 100644 --- a/dtschema/schemas/gpio/gpio.yaml +++ b/dtschema/schemas/gpio/gpio.yaml @@ -2,7 +2,8 @@ # Copyright 2018 Linaro Ltd. $id: "http://devicetree.org/schemas/gpio/gpio.yaml#" $schema: "http://devicetree.org/meta-schemas/base.yaml#" -title: GPIO devicetree schema + +title: GPIO Controller Common Properties description: "Schema for GPIO devicetree bindings" maintainers: - Rob Herring diff --git a/dtschema/schemas/graph.yaml b/dtschema/schemas/graph.yaml index 617bdc57..bca45051 100644 --- a/dtschema/schemas/graph.yaml +++ b/dtschema/schemas/graph.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/graph.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common bindings for device graphs +title: Device Graphs description: | The hierarchical organisation of the device tree is well suited to describe diff --git a/dtschema/schemas/hwlock/hwlock-consumer.yaml b/dtschema/schemas/hwlock/hwlock-consumer.yaml index bdb4c88c..5884548b 100644 --- a/dtschema/schemas/hwlock/hwlock-consumer.yaml +++ b/dtschema/schemas/hwlock/hwlock-consumer.yaml @@ -6,7 +6,7 @@ $id: http://devicetree.org/schemas/hwlock/hwlock-consumer.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common H/W Locks Consumer Binding +title: H/W Locks Consumer Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/iio/iio-consumer.yaml b/dtschema/schemas/iio/iio-consumer.yaml index c2b47b9d..819e5df5 100644 --- a/dtschema/schemas/iio/iio-consumer.yaml +++ b/dtschema/schemas/iio/iio-consumer.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/iio/iio-consumer.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Generic IIO consumer-bindings +title: IIO Consumer Common Properties maintainers: - Jonathan Cameron diff --git a/dtschema/schemas/iio/iio.yaml b/dtschema/schemas/iio/iio.yaml index fd654d62..5ce5e147 100644 --- a/dtschema/schemas/iio/iio.yaml +++ b/dtschema/schemas/iio/iio.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/iio/iio.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Generic IIO bindings +title: IIO Provider Common Properties select: true diff --git a/dtschema/schemas/interconnects.yaml b/dtschema/schemas/interconnects.yaml index 64a95570..2f63c15a 100644 --- a/dtschema/schemas/interconnects.yaml +++ b/dtschema/schemas/interconnects.yaml @@ -3,7 +3,7 @@ $id: "http://devicetree.org/schemas/interconnects.yaml#" $schema: "http://devicetree.org/meta-schemas/base.yaml#" -title: Interconnects consumer schema +title: Interconnects Consumer Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/interrupt-controller.yaml b/dtschema/schemas/interrupt-controller.yaml index 28bde688..4db97c43 100644 --- a/dtschema/schemas/interrupt-controller.yaml +++ b/dtschema/schemas/interrupt-controller.yaml @@ -3,7 +3,8 @@ # Copyright 2018 Arm Ltd. $id: "http://devicetree.org/schemas/interrupt-controller.yaml#" $schema: "http://devicetree.org/meta-schemas/base.yaml#" -title: Interrupt Controller devicetree node schema + +title: Interrupt Controller Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/interrupts.yaml b/dtschema/schemas/interrupts.yaml index 63f1039f..f147fd93 100644 --- a/dtschema/schemas/interrupts.yaml +++ b/dtschema/schemas/interrupts.yaml @@ -4,7 +4,9 @@ $id: "http://devicetree.org/schemas/interrupts.yaml#" $schema: "http://devicetree.org/meta-schemas/base.yaml#" -title: Interrupt consumer devicetree node schema + +title: Interrupt Consumer Common Properties + maintainers: - Rob Herring diff --git a/dtschema/schemas/iommu/iommu.yaml b/dtschema/schemas/iommu/iommu.yaml index d1b90c59..b3693b87 100644 --- a/dtschema/schemas/iommu/iommu.yaml +++ b/dtschema/schemas/iommu/iommu.yaml @@ -5,7 +5,7 @@ $id: http://devicetree.org/schemas/iommu/iommu.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common IOMMU Binding +title: IOMMU Consumer Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/isa/isa-bridge.yaml b/dtschema/schemas/isa/isa-bridge.yaml index f6f5087e..b8a4122d 100644 --- a/dtschema/schemas/isa/isa-bridge.yaml +++ b/dtschema/schemas/isa/isa-bridge.yaml @@ -5,7 +5,7 @@ $id: http://devicetree.org/schemas/isa/isa-bridge.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: ISA bus bridge schema +title: ISA Bus Bridges description: | Schema for ISA bridge nodes. This is for bridges with I/O space mapped into diff --git a/dtschema/schemas/isa/isa-bus.yaml b/dtschema/schemas/isa/isa-bus.yaml index 95a0e65f..f3bc9e6b 100644 --- a/dtschema/schemas/isa/isa-bus.yaml +++ b/dtschema/schemas/isa/isa-bus.yaml @@ -5,7 +5,7 @@ $id: http://devicetree.org/schemas/isa/isa-bus.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: ISA bus schema +title: ISA Bus Nodes description: | Common properties for ISA bus nodes diff --git a/dtschema/schemas/mbox/mbox-consumer.yaml b/dtschema/schemas/mbox/mbox-consumer.yaml index 2e47f4d3..45403099 100644 --- a/dtschema/schemas/mbox/mbox-consumer.yaml +++ b/dtschema/schemas/mbox/mbox-consumer.yaml @@ -6,7 +6,7 @@ $id: http://devicetree.org/schemas/mbox/mbox-consumer.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common Mailbox Consumer Binding +title: Mailbox Consumer Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/pci/pci-bus.yaml b/dtschema/schemas/pci/pci-bus.yaml index 31bc1b99..196c3b6d 100644 --- a/dtschema/schemas/pci/pci-bus.yaml +++ b/dtschema/schemas/pci/pci-bus.yaml @@ -5,7 +5,7 @@ $id: http://devicetree.org/schemas/pci/pci-bus.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: PCI bus schema +title: PCI Bus Nodes description: | Common properties for PCI host bridge nodes and PCI bus structure. diff --git a/dtschema/schemas/pci/pci-iommu.yaml b/dtschema/schemas/pci/pci-iommu.yaml index aac6b417..396653f4 100644 --- a/dtschema/schemas/pci/pci-iommu.yaml +++ b/dtschema/schemas/pci/pci-iommu.yaml @@ -5,7 +5,7 @@ $id: http://devicetree.org/schemas/pci/pci-iommu.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: PCI IOMMU mapping schema +title: PCI IOMMU Mapping Properties description: | This document describes the generic device tree binding for describing the diff --git a/dtschema/schemas/phy/phy-consumer.yaml b/dtschema/schemas/phy/phy-consumer.yaml index 2300fabb..a71860a6 100644 --- a/dtschema/schemas/phy/phy-consumer.yaml +++ b/dtschema/schemas/phy/phy-consumer.yaml @@ -6,7 +6,7 @@ $id: http://devicetree.org/schemas/phy/phy-consumer.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common PHY Consumer Binding +title: PHY Consumer Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/phy/phy-provider.yaml b/dtschema/schemas/phy/phy-provider.yaml index 5e9dc7ce..daca9679 100644 --- a/dtschema/schemas/phy/phy-provider.yaml +++ b/dtschema/schemas/phy/phy-provider.yaml @@ -3,7 +3,7 @@ $id: "http://devicetree.org/schemas/phy/phy-provider.yaml#" $schema: "http://devicetree.org/meta-schemas/base.yaml#" -title: Common PHY provider schema +title: PHY Provider Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/pinctrl/pinctrl-consumer.yaml b/dtschema/schemas/pinctrl/pinctrl-consumer.yaml index 56c73769..399aa56d 100644 --- a/dtschema/schemas/pinctrl/pinctrl-consumer.yaml +++ b/dtschema/schemas/pinctrl/pinctrl-consumer.yaml @@ -5,7 +5,7 @@ $id: http://devicetree.org/schemas/pinctrl/pinctrl-consumer.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Common Pin Controller consumer binding +title: Pin Controller Consumer Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/power-domain/power-domain-consumer.yaml b/dtschema/schemas/power-domain/power-domain-consumer.yaml index 9d24dd56..eabc5780 100644 --- a/dtschema/schemas/power-domain/power-domain-consumer.yaml +++ b/dtschema/schemas/power-domain/power-domain-consumer.yaml @@ -6,7 +6,7 @@ $id: http://devicetree.org/schemas/power-domain/power-domain-consumer.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common Power Domain Consumer Binding +title: Power Domain Consumer Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/pwm/pwm-consumer.yaml b/dtschema/schemas/pwm/pwm-consumer.yaml index fd3aa63c..e13cfbb2 100644 --- a/dtschema/schemas/pwm/pwm-consumer.yaml +++ b/dtschema/schemas/pwm/pwm-consumer.yaml @@ -6,7 +6,7 @@ $id: http://devicetree.org/schemas/pwm/pwm-consumer.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common PWM Consumer Binding +title: PWM Consumer Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/reset/reset.yaml b/dtschema/schemas/reset/reset.yaml index 4c1ad205..6c824046 100644 --- a/dtschema/schemas/reset/reset.yaml +++ b/dtschema/schemas/reset/reset.yaml @@ -5,7 +5,7 @@ $id: http://devicetree.org/schemas/reset/reset.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common Reset Binding +title: Reset Consumer Common Properties maintainers: - Rob Herring diff --git a/dtschema/schemas/serial.yaml b/dtschema/schemas/serial.yaml index b478e2ed..c94cd936 100644 --- a/dtschema/schemas/serial.yaml +++ b/dtschema/schemas/serial.yaml @@ -5,7 +5,7 @@ $id: http://devicetree.org/schemas/serial.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Common Serial binding +title: Serial Device Common Properties maintainers: - Rob Herring diff --git a/test/schemas/child-node-example.yaml b/test/schemas/child-node-example.yaml index 0296a4f6..64d7d795 100644 --- a/test/schemas/child-node-example.yaml +++ b/test/schemas/child-node-example.yaml @@ -6,7 +6,7 @@ $id: "http://devicetree.org/schemas/child-node-example.yaml#" $schema: "http://devicetree.org/meta-schemas/core.yaml#" -title: A one line title for a good binding +title: A Device with Child Nodes maintainers: - Rob Herring diff --git a/test/schemas/good-example.yaml b/test/schemas/good-example.yaml index b8493a97..3fd295af 100644 --- a/test/schemas/good-example.yaml +++ b/test/schemas/good-example.yaml @@ -6,7 +6,7 @@ $id: "http://devicetree.org/schemas/good-example.yaml#" $schema: "http://devicetree.org/meta-schemas/core.yaml#" -title: A one line title for a good binding +title: Test device with vendor properties of different types description: A more detailed description for a good binding example. From 3e9da892d23b4601fde503a7d9153ac8d20f95eb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 22 Nov 2022 13:23:20 -0600 Subject: [PATCH 314/505] Drop unnecessary quotes in schemas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop some unnecessary quotes treewide in schemas and meta-schemas. Scripted conversion with the following from Rafał: find ./ -name "*.yaml" -exec sed -i 's/\(\$id: \)"\(.*\)"$/\1\2/' {} \; find ./ -name "*.yaml" -exec sed -i 's/\(\$schema: \)"\(.*\)"$/\1\2/' {} \; find ./ -name "*.yaml" -exec sed -i 's/\(\$ref: \)"\([^#].*\)"$/\1\2/' {} \; find ./ -name "*.yaml" -exec sed -i 's/\(description: \)"\([^'\'']*\)"$/\1\2/' {} \; Reported-by: Rafał Miłecki Signed-off-by: Rob Herring --- dtschema/meta-schemas/base.yaml | 10 ++-- dtschema/meta-schemas/boolean.yaml | 2 +- dtschema/meta-schemas/cell.yaml | 2 +- dtschema/meta-schemas/clocks.yaml | 20 +++---- dtschema/meta-schemas/core.yaml | 56 +++++++++---------- dtschema/meta-schemas/dma.yaml | 4 +- dtschema/meta-schemas/gpios.yaml | 14 ++--- dtschema/meta-schemas/hwlock.yaml | 4 +- dtschema/meta-schemas/iio.yaml | 4 +- dtschema/meta-schemas/interrupts.yaml | 12 ++-- dtschema/meta-schemas/iommu.yaml | 4 +- dtschema/meta-schemas/items.yaml | 2 +- dtschema/meta-schemas/keywords.yaml | 2 +- dtschema/meta-schemas/mailbox.yaml | 2 +- dtschema/meta-schemas/nodes.yaml | 2 +- dtschema/meta-schemas/nvmem.yaml | 6 +- dtschema/meta-schemas/phy.yaml | 4 +- dtschema/meta-schemas/power-domain.yaml | 4 +- dtschema/meta-schemas/pwm.yaml | 4 +- dtschema/meta-schemas/reset.yaml | 4 +- dtschema/meta-schemas/string-array.yaml | 2 +- dtschema/meta-schemas/vendor-props.yaml | 2 +- dtschema/schemas/cache-controller.yaml | 14 ++--- dtschema/schemas/clock/clock.yaml | 24 ++++---- dtschema/schemas/cpus.yaml | 2 +- dtschema/schemas/dma/dma.yaml | 2 +- dtschema/schemas/dt-core.yaml | 46 +++++++-------- dtschema/schemas/gpio/gpio-consumer.yaml | 12 ++-- dtschema/schemas/gpio/gpio-hog.yaml | 18 +++--- dtschema/schemas/gpio/gpio.yaml | 16 +++--- dtschema/schemas/hwlock/hwlock-consumer.yaml | 4 +- dtschema/schemas/interconnects.yaml | 6 +- dtschema/schemas/interrupt-controller.yaml | 10 ++-- dtschema/schemas/interrupts.yaml | 12 ++-- dtschema/schemas/iommu/iommu.yaml | 2 +- dtschema/schemas/mbox/mbox-consumer.yaml | 6 +- dtschema/schemas/pci/pci-bus.yaml | 2 +- dtschema/schemas/phy/phy-consumer.yaml | 4 +- dtschema/schemas/phy/phy-provider.yaml | 4 +- .../schemas/pinctrl/pinctrl-consumer.yaml | 2 +- .../power-domain/power-domain-consumer.yaml | 4 +- dtschema/schemas/property-units.yaml | 56 +++++++++---------- dtschema/schemas/pwm/pwm-consumer.yaml | 4 +- dtschema/schemas/reset/reset.yaml | 4 +- dtschema/schemas/root-node.yaml | 2 +- dtschema/schemas/simple-bus.yaml | 2 +- dtschema/schemas/types.yaml | 4 +- example-schema.yaml | 4 +- test/schemas/bad-example.yaml | 4 +- test/schemas/child-node-example.yaml | 14 ++--- test/schemas/conditionals-allof-example.yaml | 4 +- test/schemas/conditionals-single-example.yaml | 4 +- test/schemas/good-example.yaml | 24 ++++---- 53 files changed, 241 insertions(+), 241 deletions(-) diff --git a/dtschema/meta-schemas/base.yaml b/dtschema/meta-schemas/base.yaml index e21d324d..1dd005c5 100644 --- a/dtschema/meta-schemas/base.yaml +++ b/dtschema/meta-schemas/base.yaml @@ -3,13 +3,13 @@ # Copyright 2018 Arm Ltd. %YAML 1.2 --- -$id: "http://devicetree.org/meta-schemas/base.yaml#" +$id: http://devicetree.org/meta-schemas/base.yaml# $schema: https://json-schema.org/draft/2019-09/schema -description: "Metaschema for devicetree binding documentation" +description: Metaschema for devicetree binding documentation allOf: - - $ref: "http://json-schema.org/draft-07/schema#" - - $ref: "http://devicetree.org/meta-schemas/keywords.yaml#" + - $ref: http://json-schema.org/draft-07/schema# + - $ref: http://devicetree.org/meta-schemas/keywords.yaml# properties: # listing all properties here to narrow the scope of what is allowed in @@ -39,7 +39,7 @@ properties: select: description: '"select" must contain a valid json-schema' allOf: - - $ref: "http://json-schema.org/draft-07/schema#" + - $ref: http://json-schema.org/draft-07/schema# - oneOf: - type: object properties: diff --git a/dtschema/meta-schemas/boolean.yaml b/dtschema/meta-schemas/boolean.yaml index 6cc638a3..be13a220 100644 --- a/dtschema/meta-schemas/boolean.yaml +++ b/dtschema/meta-schemas/boolean.yaml @@ -3,7 +3,7 @@ # Copyright 2018 Arm Ltd. %YAML 1.2 --- -$id: "http://devicetree.org/meta-schemas/boolean.yaml#" +$id: http://devicetree.org/meta-schemas/boolean.yaml# $schema: https://json-schema.org/draft/2019-09/schema properties: diff --git a/dtschema/meta-schemas/cell.yaml b/dtschema/meta-schemas/cell.yaml index 21253cdb..4929cc68 100644 --- a/dtschema/meta-schemas/cell.yaml +++ b/dtschema/meta-schemas/cell.yaml @@ -3,7 +3,7 @@ # Copyright 2018 Arm Ltd. %YAML 1.2 --- -$id: "http://devicetree.org/meta-schemas/cell.yaml#" +$id: http://devicetree.org/meta-schemas/cell.yaml# $schema: https://json-schema.org/draft/2019-09/schema array: diff --git a/dtschema/meta-schemas/clocks.yaml b/dtschema/meta-schemas/clocks.yaml index 572a5d70..3227d60a 100644 --- a/dtschema/meta-schemas/clocks.yaml +++ b/dtschema/meta-schemas/clocks.yaml @@ -3,29 +3,29 @@ # Copyright 2018 Arm Ltd. %YAML 1.2 --- -$id: "http://devicetree.org/meta-schemas/clocks.yaml#" +$id: http://devicetree.org/meta-schemas/clocks.yaml# $schema: https://json-schema.org/draft/2019-09/schema properties: clocks: oneOf: - - $ref: "cell.yaml#/array" - - $ref: "nodes.yaml" + - $ref: cell.yaml#/array + - $ref: nodes.yaml clock-ranges: - $ref: "boolean.yaml" + $ref: boolean.yaml clock-indices: - $ref: "cell.yaml#/array" + $ref: cell.yaml#/array assigned-clocks: - $ref: "cell.yaml#/array" + $ref: cell.yaml#/array assigned-clock-parents: - $ref: "cell.yaml#/array" + $ref: cell.yaml#/array assigned-clock-rates: - $ref: "cell.yaml#/array" + $ref: cell.yaml#/array clock-frequency: - $ref: "cell.yaml#/single" + $ref: cell.yaml#/single bus-frequency: - $ref: "cell.yaml#/single" + $ref: cell.yaml#/single dependentRequired: clock-output-names: ['#clock-cells'] diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index 0ab315e5..e1b6321c 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -3,12 +3,12 @@ # Copyright 2018-2019 Arm Ltd. %YAML 1.2 --- -$id: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/meta-schemas/core.yaml# $schema: https://json-schema.org/draft/2019-09/schema -description: "Metaschema for devicetree binding documentation" +description: Metaschema for devicetree binding documentation allOf: - - $ref: "http://devicetree.org/meta-schemas/base.yaml#" + - $ref: http://devicetree.org/meta-schemas/base.yaml# - description: Either unevaluatedProperties or additionalProperties must be present oneOf: - required: [ unevaluatedProperties ] @@ -18,41 +18,41 @@ definitions: all-properties: allOf: - $ref: "#/definitions/core-properties" - - $ref: "clocks.yaml#" - - $ref: "dma.yaml#" - - $ref: "gpios.yaml#" - - $ref: "hwlock.yaml#" - - $ref: "iio.yaml#" - - $ref: "interrupts.yaml#" - - $ref: "iommu.yaml#" - - $ref: "mailbox.yaml#" - - $ref: "nvmem.yaml#" - - $ref: "phy.yaml#" - - $ref: "power-domain.yaml#" - - $ref: "pwm.yaml#" - - $ref: "reset.yaml#" - - $ref: "mailbox.yaml#" - - $ref: "vendor-props.yaml#" + - $ref: clocks.yaml# + - $ref: dma.yaml# + - $ref: gpios.yaml# + - $ref: hwlock.yaml# + - $ref: iio.yaml# + - $ref: interrupts.yaml# + - $ref: iommu.yaml# + - $ref: mailbox.yaml# + - $ref: nvmem.yaml# + - $ref: phy.yaml# + - $ref: power-domain.yaml# + - $ref: pwm.yaml# + - $ref: reset.yaml# + - $ref: mailbox.yaml# + - $ref: vendor-props.yaml# core-properties: properties: ranges: - $ref: "cell.yaml#/array" + $ref: cell.yaml#/array reg: - $ref: "cell.yaml#/array" + $ref: cell.yaml#/array compatible: - $ref: "string-array.yaml" + $ref: string-array.yaml $nodename: - $ref: "string-array.yaml" + $ref: string-array.yaml memory-region: - $ref: "cell.yaml#/array" + $ref: cell.yaml#/array memory-region-names: - $ref: "string-array.yaml" + $ref: string-array.yaml patternProperties: '.*-names$': - $ref: "string-array.yaml" + $ref: string-array.yaml '^#.*-cells$': - $ref: "cell.yaml#/single" + $ref: cell.yaml#/single '-supply$': propertyNames: @@ -60,7 +60,7 @@ definitions: '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kelvin|kpascal)$': allOf: - - $ref: "cell.yaml#/array" + - $ref: cell.yaml#/array - description: Standard unit suffix properties don't need a type $ref propertyNames: not: @@ -87,7 +87,7 @@ definitions: required: - type then: - $ref: "nodes.yaml#" + $ref: nodes.yaml# - if: required: [ properties ] then: diff --git a/dtschema/meta-schemas/dma.yaml b/dtschema/meta-schemas/dma.yaml index fb76f4b4..cbfc77d3 100644 --- a/dtschema/meta-schemas/dma.yaml +++ b/dtschema/meta-schemas/dma.yaml @@ -2,12 +2,12 @@ # Copyright 2020 Arm Ltd. %YAML 1.2 --- -$id: "http://devicetree.org/meta-schemas/dma.yaml#" +$id: http://devicetree.org/meta-schemas/dma.yaml# $schema: https://json-schema.org/draft/2019-09/schema properties: dmas: - $ref: "cell.yaml#/array" + $ref: cell.yaml#/array dependentRequired: dma-names: [dmas] diff --git a/dtschema/meta-schemas/gpios.yaml b/dtschema/meta-schemas/gpios.yaml index b8424191..c071b724 100644 --- a/dtschema/meta-schemas/gpios.yaml +++ b/dtschema/meta-schemas/gpios.yaml @@ -3,24 +3,24 @@ # Copyright 2018 Arm Ltd. %YAML 1.2 --- -$id: "http://devicetree.org/meta-schemas/gpios.yaml#" +$id: http://devicetree.org/meta-schemas/gpios.yaml# $schema: https://json-schema.org/draft/2019-09/schema properties: gpio-controller: - $ref: "boolean.yaml" + $ref: boolean.yaml gpio-line-names: - $ref: "string-array.yaml" + $ref: string-array.yaml ngpios: - $ref: "cell.yaml#/single" + $ref: cell.yaml#/single gpio-ranges: - $ref: "cell.yaml#/array" + $ref: cell.yaml#/array gpios: - $ref: "cell.yaml#/array" + $ref: cell.yaml#/array patternProperties: '(? @@ -17,9 +17,9 @@ select: true properties: $nodename: - $ref: "types.yaml#/definitions/string" + $ref: types.yaml#/definitions/string compatible: - $ref: "types.yaml#/definitions/string-array" + $ref: types.yaml#/definitions/string-array items: # Keep in sync with make_compatible_schema() pattern: "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]+$" @@ -28,57 +28,57 @@ properties: Phandles to CPU nodes associated with the referring node. oneOf: - type: object - - $ref: "types.yaml#/definitions/phandle-array" + - $ref: types.yaml#/definitions/phandle-array items: maxItems: 1 label: - $ref: "types.yaml#/definitions/string" + $ref: types.yaml#/definitions/string dma-coherent: - $ref: "types.yaml#/definitions/flag" + $ref: types.yaml#/definitions/flag dma-noncoherent: - $ref: "types.yaml#/definitions/flag" + $ref: types.yaml#/definitions/flag dma-ranges: oneOf: - - $ref: "types.yaml#/definitions/flag" - - $ref: "types.yaml#/definitions/uint32-matrix" + - $ref: types.yaml#/definitions/flag + - $ref: types.yaml#/definitions/uint32-matrix ranges: oneOf: - - $ref: "types.yaml#/definitions/flag" - - $ref: "types.yaml#/definitions/uint32-matrix" + - $ref: types.yaml#/definitions/flag + - $ref: types.yaml#/definitions/uint32-matrix reg: - $ref: "types.yaml#/definitions/uint32-matrix" + $ref: types.yaml#/definitions/uint32-matrix reg-io-width: - $ref: "types.yaml#/definitions/uint32" + $ref: types.yaml#/definitions/uint32 minimum: 1 maximum: 0xf description: Typically, a single set bit indicating the access size, but some uses treat this as a bit mask of allowed sizes. reg-shift: - $ref: "types.yaml#/definitions/uint32" + $ref: types.yaml#/definitions/uint32 enum: [ 0, 1, 2 ] secure-status: - $ref: "types.yaml#/definitions/string" + $ref: types.yaml#/definitions/string enum: [ okay, disabled, reserved ] status: - $ref: "types.yaml#/definitions/string" + $ref: types.yaml#/definitions/string enum: [ okay, disabled, reserved ] phandle: - $ref: "types.yaml#/definitions/uint32" + $ref: types.yaml#/definitions/uint32 patternProperties: "^#.*-cells$": - $ref: "types.yaml#/definitions/uint32" + $ref: types.yaml#/definitions/uint32 maximum: 8 ".*-names$": - $ref: "types.yaml#/definitions/non-unique-string-array" + $ref: types.yaml#/definitions/non-unique-string-array ".*-supply$": if: not: { type: object } then: - $ref: "types.yaml#/definitions/phandle" + $ref: types.yaml#/definitions/phandle # property and node namespace overlaps. Catch both here "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]{0,63}$": @@ -94,7 +94,7 @@ patternProperties: # Anything with a '#' is single cell number "^#[a-zA-Z0-9,+\\-._]{0,63}$": - $ref: "types.yaml#/definitions/uint32" + $ref: types.yaml#/definitions/uint32 dependencies: "#size-cells": [ "#address-cells" ] diff --git a/dtschema/schemas/gpio/gpio-consumer.yaml b/dtschema/schemas/gpio/gpio-consumer.yaml index a2a7236a..1ac35244 100644 --- a/dtschema/schemas/gpio/gpio-consumer.yaml +++ b/dtschema/schemas/gpio/gpio-consumer.yaml @@ -1,11 +1,11 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2018 Linaro Ltd. -$id: "http://devicetree.org/schemas/gpio/gpio-consumer.yaml#" -$schema: "http://devicetree.org/meta-schemas/base.yaml#" +$id: http://devicetree.org/schemas/gpio/gpio-consumer.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# title: GPIO Consumer Common Properties -description: "Schema for GPIO consumer devicetree bindings" +description: Schema for GPIO consumer devicetree bindings maintainers: - Rob Herring @@ -17,17 +17,17 @@ select: properties: gpios: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array gpio: # 'gpio' can appear as a property or node name oneOf: - type: object - - $ref: "/schemas/types.yaml#/definitions/phandle-array" + - $ref: /schemas/types.yaml#/definitions/phandle-array patternProperties: "(? @@ -23,22 +23,22 @@ properties: pattern: "^(hog-[0-9]+|.+-hog(-[0-9]+)?)$" gpio-hog: - $ref: "/schemas/types.yaml#/definitions/flag" + $ref: /schemas/types.yaml#/definitions/flag gpios: - $ref: "/schemas/types.yaml#/definitions/uint32-matrix" + $ref: /schemas/types.yaml#/definitions/uint32-matrix input: - $ref: "/schemas/types.yaml#/definitions/flag" + $ref: /schemas/types.yaml#/definitions/flag line-name: - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string output-high: - $ref: "/schemas/types.yaml#/definitions/flag" + $ref: /schemas/types.yaml#/definitions/flag output-low: - $ref: "/schemas/types.yaml#/definitions/flag" + $ref: /schemas/types.yaml#/definitions/flag required: - gpio-hog diff --git a/dtschema/schemas/gpio/gpio.yaml b/dtschema/schemas/gpio/gpio.yaml index 59f7b7ea..87c381b2 100644 --- a/dtschema/schemas/gpio/gpio.yaml +++ b/dtschema/schemas/gpio/gpio.yaml @@ -1,10 +1,10 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2018 Linaro Ltd. -$id: "http://devicetree.org/schemas/gpio/gpio.yaml#" -$schema: "http://devicetree.org/meta-schemas/base.yaml#" +$id: http://devicetree.org/schemas/gpio/gpio.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# title: GPIO Controller Common Properties -description: "Schema for GPIO devicetree bindings" +description: Schema for GPIO devicetree bindings maintainers: - Rob Herring @@ -14,18 +14,18 @@ select: true properties: "#gpio-cells": true gpio-controller: - $ref: "/schemas/types.yaml#/definitions/flag" + $ref: /schemas/types.yaml#/definitions/flag gpio-line-names: - $ref: "/schemas/types.yaml#/definitions/non-unique-string-array" + $ref: /schemas/types.yaml#/definitions/non-unique-string-array ngpios: - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 gpio-reserved-ranges: - $ref: "/schemas/types.yaml#/definitions/uint32-matrix" + $ref: /schemas/types.yaml#/definitions/uint32-matrix items: minItems: 2 maxItems: 2 gpio-ranges: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array items: items: - description: pin controller phandle diff --git a/dtschema/schemas/hwlock/hwlock-consumer.yaml b/dtschema/schemas/hwlock/hwlock-consumer.yaml index 5884548b..b87d8107 100644 --- a/dtschema/schemas/hwlock/hwlock-consumer.yaml +++ b/dtschema/schemas/hwlock/hwlock-consumer.yaml @@ -16,10 +16,10 @@ select: true properties: hwlocks: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array hwlock-names: - $ref: "/schemas/types.yaml#/definitions/string-array" + $ref: /schemas/types.yaml#/definitions/string-array dependencies: hwlock-names: [ hwlocks ] diff --git a/dtschema/schemas/interconnects.yaml b/dtschema/schemas/interconnects.yaml index 2f63c15a..40ecf3c1 100644 --- a/dtschema/schemas/interconnects.yaml +++ b/dtschema/schemas/interconnects.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2021 Arm Ltd. -$id: "http://devicetree.org/schemas/interconnects.yaml#" -$schema: "http://devicetree.org/meta-schemas/base.yaml#" +$id: http://devicetree.org/schemas/interconnects.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# title: Interconnects Consumer Common Properties @@ -13,7 +13,7 @@ select: true properties: interconnects: - $ref: "types.yaml#/definitions/phandle-array" + $ref: types.yaml#/definitions/phandle-array dependencies: interconnect-names: [interconnects] diff --git a/dtschema/schemas/interrupt-controller.yaml b/dtschema/schemas/interrupt-controller.yaml index 4db97c43..9e3a1c86 100644 --- a/dtschema/schemas/interrupt-controller.yaml +++ b/dtschema/schemas/interrupt-controller.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2018 Linaro Ltd. # Copyright 2018 Arm Ltd. -$id: "http://devicetree.org/schemas/interrupt-controller.yaml#" -$schema: "http://devicetree.org/meta-schemas/base.yaml#" +$id: http://devicetree.org/schemas/interrupt-controller.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# title: Interrupt Controller Common Properties @@ -18,13 +18,13 @@ properties: "#address-cells": true interrupt-controller: - $ref: "types.yaml#/definitions/flag" + $ref: types.yaml#/definitions/flag interrupt-map: - $ref: "/schemas/types.yaml#/definitions/uint32-matrix" + $ref: /schemas/types.yaml#/definitions/uint32-matrix interrupt-map-mask: - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array wakeup-parent: $ref: types.yaml#/definitions/phandle diff --git a/dtschema/schemas/interrupts.yaml b/dtschema/schemas/interrupts.yaml index f147fd93..535918ce 100644 --- a/dtschema/schemas/interrupts.yaml +++ b/dtschema/schemas/interrupts.yaml @@ -2,8 +2,8 @@ # Copyright 2018 Linaro Ltd. # Copyright 2018 Arm Ltd. -$id: "http://devicetree.org/schemas/interrupts.yaml#" -$schema: "http://devicetree.org/meta-schemas/base.yaml#" +$id: http://devicetree.org/schemas/interrupts.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# title: Interrupt Consumer Common Properties @@ -15,13 +15,13 @@ select: true properties: interrupt-parent: - $ref: "types.yaml#/definitions/phandle" + $ref: types.yaml#/definitions/phandle interrupts: - $ref: "types.yaml#/definitions/uint32-matrix" + $ref: types.yaml#/definitions/uint32-matrix interrupt-names: - $ref: "/schemas/types.yaml#/definitions/string-array" + $ref: /schemas/types.yaml#/definitions/string-array interrupts-extended: - $ref: "types.yaml#/definitions/phandle-array" + $ref: types.yaml#/definitions/phandle-array dependencies: interrupt-names: oneOf: diff --git a/dtschema/schemas/iommu/iommu.yaml b/dtschema/schemas/iommu/iommu.yaml index b3693b87..e511871d 100644 --- a/dtschema/schemas/iommu/iommu.yaml +++ b/dtschema/schemas/iommu/iommu.yaml @@ -15,6 +15,6 @@ select: true properties: iommus: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array additionalProperties: true diff --git a/dtschema/schemas/mbox/mbox-consumer.yaml b/dtschema/schemas/mbox/mbox-consumer.yaml index 45403099..cb893938 100644 --- a/dtschema/schemas/mbox/mbox-consumer.yaml +++ b/dtschema/schemas/mbox/mbox-consumer.yaml @@ -16,13 +16,13 @@ select: true properties: mboxes: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array mbox-names: - $ref: "/schemas/types.yaml#/definitions/string-array" + $ref: /schemas/types.yaml#/definitions/string-array shmem: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array items: maxItems: 1 diff --git a/dtschema/schemas/pci/pci-bus.yaml b/dtschema/schemas/pci/pci-bus.yaml index 196c3b6d..d841b971 100644 --- a/dtschema/schemas/pci/pci-bus.yaml +++ b/dtschema/schemas/pci/pci-bus.yaml @@ -29,7 +29,7 @@ properties: ranges: oneOf: - - $ref: "/schemas/types.yaml#/definitions/flag" + - $ref: /schemas/types.yaml#/definitions/flag - minItems: 1 maxItems: 32 # Should be enough items: diff --git a/dtschema/schemas/phy/phy-consumer.yaml b/dtschema/schemas/phy/phy-consumer.yaml index a71860a6..8d9ff661 100644 --- a/dtschema/schemas/phy/phy-consumer.yaml +++ b/dtschema/schemas/phy/phy-consumer.yaml @@ -16,10 +16,10 @@ select: true properties: phys: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array phy-names: - $ref: "/schemas/types.yaml#/definitions/string-array" + $ref: /schemas/types.yaml#/definitions/string-array dependencies: phy-names: [ phys ] diff --git a/dtschema/schemas/phy/phy-provider.yaml b/dtschema/schemas/phy/phy-provider.yaml index daca9679..01ff62c5 100644 --- a/dtschema/schemas/phy/phy-provider.yaml +++ b/dtschema/schemas/phy/phy-provider.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2019 Arm Ltd. -$id: "http://devicetree.org/schemas/phy/phy-provider.yaml#" -$schema: "http://devicetree.org/meta-schemas/base.yaml#" +$id: http://devicetree.org/schemas/phy/phy-provider.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# title: PHY Provider Common Properties diff --git a/dtschema/schemas/pinctrl/pinctrl-consumer.yaml b/dtschema/schemas/pinctrl/pinctrl-consumer.yaml index 399aa56d..9c5216f7 100644 --- a/dtschema/schemas/pinctrl/pinctrl-consumer.yaml +++ b/dtschema/schemas/pinctrl/pinctrl-consumer.yaml @@ -20,7 +20,7 @@ properties: patternProperties: "pinctrl-[0-9]": - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array dependencies: pinctrl-names: [ pinctrl-0 ] diff --git a/dtschema/schemas/power-domain/power-domain-consumer.yaml b/dtschema/schemas/power-domain/power-domain-consumer.yaml index eabc5780..9fab167b 100644 --- a/dtschema/schemas/power-domain/power-domain-consumer.yaml +++ b/dtschema/schemas/power-domain/power-domain-consumer.yaml @@ -16,10 +16,10 @@ select: true properties: power-domains: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array power-domain-names: - $ref: "/schemas/types.yaml#/definitions/string-array" + $ref: /schemas/types.yaml#/definitions/string-array dependencies: power-domain-names: [ power-domains ] diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index 062711fb..7a697fe4 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -26,102 +26,102 @@ select: true # Please don't add to this. properties: opp-hz: - $ref: "types.yaml#/definitions/uint64-matrix" + $ref: types.yaml#/definitions/uint64-matrix patternProperties: "-bits$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: number of bits "-kBps$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: kilobytes per second "-percent$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: percentage "-bp$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: basis points (1/100 of a percent) # Time/Frequency "-mhz$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: megahertz "(^(?!opp)).*-hz$": - $ref: "types.yaml#/definitions/uint32-matrix" + $ref: types.yaml#/definitions/uint32-matrix description: hertz (preferred) "-sec$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: second "-ms$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: millisecond "-us$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: microsecond "-ns$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: nanosecond "-ps$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: picosecond # Distance "-mm$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: millimeter # Electricity "-microamp$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: microampere "-nanoamp$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: nanoampere "-microamp-hours$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: microampere hour "-ohms$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: ohm "-micro-ohms$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: microohm "-microwatt$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: microwatt "-milliwatt$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: milliwatt "-microwatt-hours$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: microwatt hour "-microvolt$": - $ref: "types.yaml#/definitions/int32-matrix" + $ref: types.yaml#/definitions/int32-matrix description: microvolt "-picofarads$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: picofarad "-femtofarads$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: femtofarad # Temperature "-celsius$": - $ref: "types.yaml#/definitions/int32-array" + $ref: types.yaml#/definitions/int32-array description: degree Celsius "-millicelsius$": - $ref: "types.yaml#/definitions/int32-array" + $ref: types.yaml#/definitions/int32-array description: millidegree Celsius "-kelvin$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: SI unit of thermodynamic temperature # Pressure "-kpascal$": - $ref: "types.yaml#/definitions/uint32-array" + $ref: types.yaml#/definitions/uint32-array description: kilopascal additionalProperties: true diff --git a/dtschema/schemas/pwm/pwm-consumer.yaml b/dtschema/schemas/pwm/pwm-consumer.yaml index e13cfbb2..0cb32b9e 100644 --- a/dtschema/schemas/pwm/pwm-consumer.yaml +++ b/dtschema/schemas/pwm/pwm-consumer.yaml @@ -16,10 +16,10 @@ select: true properties: pwms: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array pwm-names: - $ref: "/schemas/types.yaml#/definitions/string-array" + $ref: /schemas/types.yaml#/definitions/string-array dependencies: pwm-names: [ pwms ] diff --git a/dtschema/schemas/reset/reset.yaml b/dtschema/schemas/reset/reset.yaml index 6c824046..b51f4403 100644 --- a/dtschema/schemas/reset/reset.yaml +++ b/dtschema/schemas/reset/reset.yaml @@ -15,10 +15,10 @@ select: true properties: resets: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array reset-names: - $ref: "/schemas/types.yaml#/definitions/string-array" + $ref: /schemas/types.yaml#/definitions/string-array dependencies: reset-names: [ resets ] diff --git a/dtschema/schemas/root-node.yaml b/dtschema/schemas/root-node.yaml index 323f2371..b0901504 100644 --- a/dtschema/schemas/root-node.yaml +++ b/dtschema/schemas/root-node.yaml @@ -50,7 +50,7 @@ patternProperties: maxItems: 7 minItems: 1 maxItems: 1024 - - $ref: "types.yaml#/definitions/flag" + - $ref: types.yaml#/definitions/flag anyOf: - required: - reg diff --git a/dtschema/schemas/simple-bus.yaml b/dtschema/schemas/simple-bus.yaml index 8a78091a..a7847f40 100644 --- a/dtschema/schemas/simple-bus.yaml +++ b/dtschema/schemas/simple-bus.yaml @@ -49,7 +49,7 @@ patternProperties: maxItems: 7 minItems: 1 maxItems: 1024 - - $ref: "types.yaml#/definitions/flag" + - $ref: types.yaml#/definitions/flag anyOf: - required: - reg diff --git a/dtschema/schemas/types.yaml b/dtschema/schemas/types.yaml index 6113d3bf..1a605404 100644 --- a/dtschema/schemas/types.yaml +++ b/dtschema/schemas/types.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2018 Linaro Ltd. -$id: "http://devicetree.org/schemas/types.yaml#" -$schema: "http://devicetree.org/meta-schemas/base.yaml#" +$id: http://devicetree.org/schemas/types.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# title: Core devicetree property data types diff --git a/example-schema.yaml b/example-schema.yaml index 90fc78e7..353093ff 100644 --- a/example-schema.yaml +++ b/example-schema.yaml @@ -6,8 +6,8 @@ # 'maintainers' and 'select' # $id is a unique idenifier based on the filename -$id: "http://devicetree.org/schemas/example-schema.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/example-schema.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: An example schema annotated with jsonschema details diff --git a/test/schemas/bad-example.yaml b/test/schemas/bad-example.yaml index 0daa2fdd..043a09b5 100644 --- a/test/schemas/bad-example.yaml +++ b/test/schemas/bad-example.yaml @@ -3,8 +3,8 @@ # Copyright 2018 Arm Ltd. %YAML 1.2 --- -$id: "http://devicetree.org/schemas/bad-example.yaml" -$schema: "http://json-schema.org/draft-07/schema#" +$id: http://devicetree.org/schemas/bad-example.yaml +$schema: http://json-schema.org/draft-07/schema# title: 0 diff --git a/test/schemas/child-node-example.yaml b/test/schemas/child-node-example.yaml index 64d7d795..540e08bc 100644 --- a/test/schemas/child-node-example.yaml +++ b/test/schemas/child-node-example.yaml @@ -3,8 +3,8 @@ # Copyright 2018 Arm Ltd. %YAML 1.2 --- -$id: "http://devicetree.org/schemas/child-node-example.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/child-node-example.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: A Device with Child Nodes @@ -27,10 +27,10 @@ properties: type: object properties: vendor,required-property: - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 description: test vendor,optional-property: - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 description: test required: - vendor,required-property @@ -46,12 +46,12 @@ patternProperties: - const: a-child-compatible vendor,a-child-property: allOf: - - $ref: "/schemas/types.yaml#/definitions/uint32" + - $ref: /schemas/types.yaml#/definitions/uint32 - const: 2 description: test vendor,a-child-property2: allOf: - - $ref: "/schemas/types.yaml#/definitions/uint32" + - $ref: /schemas/types.yaml#/definitions/uint32 - oneOf: - description: | Testing for 'oneOf', otherwise this could just be an enum @@ -65,7 +65,7 @@ patternProperties: vendor,a-child-string-property: description: a child string property allOf: - - $ref: "/schemas/types.yaml#/definitions/string" + - $ref: /schemas/types.yaml#/definitions/string - const: "a-string" required: - vendor,a-child-property diff --git a/test/schemas/conditionals-allof-example.yaml b/test/schemas/conditionals-allof-example.yaml index 37899d90..f09524f8 100644 --- a/test/schemas/conditionals-allof-example.yaml +++ b/test/schemas/conditionals-allof-example.yaml @@ -2,8 +2,8 @@ # Copyright 2019 Maxime Ripard %YAML 1.2 --- -$id: "http://devicetree.org/schemas/conditionals-allof-example.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/conditionals-allof-example.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Test for multiple conditionals statements diff --git a/test/schemas/conditionals-single-example.yaml b/test/schemas/conditionals-single-example.yaml index f2dbe253..d43d56dd 100644 --- a/test/schemas/conditionals-single-example.yaml +++ b/test/schemas/conditionals-single-example.yaml @@ -2,8 +2,8 @@ # Copyright 2019 Maxime Ripard %YAML 1.2 --- -$id: "http://devicetree.org/schemas/conditionals-single-example.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/conditionals-single-example.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Test for a single conditionals statement diff --git a/test/schemas/good-example.yaml b/test/schemas/good-example.yaml index 3fd295af..13ed27a1 100644 --- a/test/schemas/good-example.yaml +++ b/test/schemas/good-example.yaml @@ -3,8 +3,8 @@ # Copyright 2018 Arm Ltd. %YAML 1.2 --- -$id: "http://devicetree.org/schemas/good-example.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/good-example.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Test device with vendor properties of different types @@ -82,44 +82,44 @@ properties: maxItems: 1 vendor,bool-prop: - $ref: "/schemas/types.yaml#/definitions/flag" + $ref: /schemas/types.yaml#/definitions/flag description: A vendor specific boolean property vendor,int-prop: - $ref: "/schemas/types.yaml#/definitions/uint32" + $ref: /schemas/types.yaml#/definitions/uint32 enum: [ 1, 2, 3 ] description: Vendor specific single cell integer property vendor,int-array-prop: - $ref: "/schemas/types.yaml#/definitions/uint32-array" + $ref: /schemas/types.yaml#/definitions/uint32-array items: minimum: 5 maximum: 10 description: Vendor specific integer array property vendor,int-array-prop-2: - $ref: "/schemas/types.yaml#/definitions/uint32-array" + $ref: /schemas/types.yaml#/definitions/uint32-array items: - const: 5 - const: 10 description: Vendor specific integer array property vendor,int-array-size-only-prop: - $ref: "/schemas/types.yaml#/definitions/uint32-array" + $ref: /schemas/types.yaml#/definitions/uint32-array minItems: 2 maxItems: 5 description: Vendor specific integer array property with only a size range. This can use either form of brackets. vendor,string-prop: - $ref: "/schemas/types.yaml#/definitions/string" + $ref: /schemas/types.yaml#/definitions/string enum: - foo - bar description: Vendor specific single string property vendor,string-list-prop: - $ref: "/schemas/types.yaml#/definitions/string-array" + $ref: /schemas/types.yaml#/definitions/string-array items: - const: foobar - const: foobaz @@ -158,18 +158,18 @@ properties: description: Vendor specific 64-bit integer array property vendor,phandle-prop: - $ref: "/schemas/types.yaml#/definitions/phandle" + $ref: /schemas/types.yaml#/definitions/phandle description: Vendor specific single cell phandle property vendor,phandle-array-prop: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array minItems: 2 items: maxItems: 1 description: Vendor specific array of phandles property vendor,phandle-with-fixed-cells: - $ref: "/schemas/types.yaml#/definitions/phandle-array" + $ref: /schemas/types.yaml#/definitions/phandle-array items: - items: - description: the phandle to something From 0314bdc9a33a06d25cd376895962395cb28ed62d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 29 Nov 2022 15:13:54 -0600 Subject: [PATCH 315/505] schemas: chosen: Allow 64-bit linux,initrd-start and linux,initrd-end linux,initrd-start and linux,initrd-end can be either 32 or 64 bit, so allow for both. Signed-off-by: Rob Herring --- dtschema/schemas/chosen.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dtschema/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml index ca09186a..86194ddf 100644 --- a/dtschema/schemas/chosen.yaml +++ b/dtschema/schemas/chosen.yaml @@ -120,14 +120,18 @@ properties: respectively, of the root node. linux,initrd-start: - $ref: types.yaml#/definitions/uint32 + oneOf: + - $ref: types.yaml#/definitions/uint32 + - $ref: types.yaml#/definitions/uint64 description: These properties hold the physical start and end address of an initrd that\'s loaded by the bootloader. Note that linux,initrd-start is inclusive, but linux,initrd-end is exclusive. linux,initrd-end: - $ref: types.yaml#/definitions/uint32 + oneOf: + - $ref: types.yaml#/definitions/uint32 + - $ref: types.yaml#/definitions/uint64 description: These properties hold the physical start and end address of an initrd that\'s loaded by the bootloader. Note that linux,initrd-start is inclusive, but From e503ec1115345bdfa06b96c9d6c4496457cbd75b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 1 Dec 2022 12:43:33 -0600 Subject: [PATCH 316/505] dt-validate: Also ignore 'unevaluatedProperties' errors for disabled nodes In some cases, disabled nodes have misleading 'unevaluatedProperties' errors. This is caused from 'required' failing in some cases. A simplified example is a schema like this: { "unevaluatedProperties": false, "allOf":[ { "properties": { "foo": true, "bar": true }, "required": [ "foo" ] } ] } An instance '{ "bar": 1 }' fails with "bar" is unevaluated. This is expected json-schema behavior. So we need to ignore 'unevaluatedProperties' as well on disabled nodes. In the process, let's use the error schema_path rather than parsing the error message text. Signed-off-by: Rob Herring --- tools/dt-validate | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/dt-validate b/tools/dt-validate index fb1d2413..15d077f0 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -56,12 +56,12 @@ class schema_group(): if disabled or (isinstance(error.instance, dict) and \ 'status' in error.instance and \ 'disabled' in error.instance['status']): - if 'required property' in error.message: + if {'required', 'unevaluatedProperties'} & set(error.schema_path): continue elif error.context: found = False for e in error.context: - if 'required property' in e.message: + if {'required', 'unevaluatedProperties'} & set(error.schema_path): found = True break if found: From d792db03850069bf0886baf05281c3817e027a53 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 1 Dec 2022 22:16:48 -0600 Subject: [PATCH 317/505] dt-validate: Fix disabled node error context check Fix a copy-n-paste error in checking the error context. Signed-off-by: Rob Herring --- tools/dt-validate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/dt-validate b/tools/dt-validate index 15d077f0..c55fd7ef 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -61,7 +61,7 @@ class schema_group(): elif error.context: found = False for e in error.context: - if {'required', 'unevaluatedProperties'} & set(error.schema_path): + if {'required', 'unevaluatedProperties'} & set(e.schema_path): found = True break if found: From 6926698599738c6f880874979591d6910d08dd26 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 5 Dec 2022 14:18:18 -0600 Subject: [PATCH 318/505] Add node properties for node schemas with only additionalProperties While rare, it is possible to have nodes with no properties defined. In this case, 'status' and other always allowed properties need to be added to the node schema. Reported-by: Geert Uytterhoeven Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index aa57b3c8..57049d92 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -503,7 +503,7 @@ def fixup_sub_schema(schema, is_prop): def fixup_node_props(schema): - if not {'properties', 'patternProperties', 'unevaluatedProperties'} & schema.keys(): + if not {'properties', 'patternProperties', 'unevaluatedProperties', 'additionalProperties'} & schema.keys(): return if ('additionalProperties' in schema and schema['additionalProperties'] is True) or \ ('unevaluatedProperties' in schema and schema['unevaluatedProperties'] is True): From 2fe869286cb4f4d607ca1d3b25160cb54ded9edd Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 4 Nov 2022 11:45:28 -0500 Subject: [PATCH 319/505] schemas: cache: 'cache-level' is only used for level 2 and up 0 or 1 are not valid for 'cache-level', so update the constraints. Signed-off-by: Rob Herring --- dtschema/schemas/cache-controller.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/dtschema/schemas/cache-controller.yaml b/dtschema/schemas/cache-controller.yaml index a5aca69f..b2a5cd02 100644 --- a/dtschema/schemas/cache-controller.yaml +++ b/dtschema/schemas/cache-controller.yaml @@ -16,6 +16,7 @@ properties: cache-level: $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 2 maximum: 32 cache-unified: From fd45a0f05e159ce1cca1cdfd6f182239ef5482c6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Nov 2022 16:32:09 -0500 Subject: [PATCH 320/505] schemas: Move cache property dependencies from cpus to cache-controller The cache property dependencies apply to all cache nodes, not just cpu nodes, so move them to cache-controller.yaml. Signed-off-by: Rob Herring --- dtschema/schemas/cache-controller.yaml | 7 +++++++ dtschema/schemas/cpus.yaml | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dtschema/schemas/cache-controller.yaml b/dtschema/schemas/cache-controller.yaml index b2a5cd02..bbb84929 100644 --- a/dtschema/schemas/cache-controller.yaml +++ b/dtschema/schemas/cache-controller.yaml @@ -38,6 +38,13 @@ patternProperties: "^(i-|d-|)cache-line-size$": $ref: /schemas/types.yaml#/definitions/uint32 +dependentRequired: + cache-size: [ cache-unified ] + cache-sets: [ cache-unified ] + cache-block-size: [ cache-unified ] + cache-line-size: [ cache-unified ] + cache-level: [ compatible ] + if: properties: $nodename: diff --git a/dtschema/schemas/cpus.yaml b/dtschema/schemas/cpus.yaml index 3423b220..110dcb41 100644 --- a/dtschema/schemas/cpus.yaml +++ b/dtschema/schemas/cpus.yaml @@ -139,10 +139,6 @@ patternProperties: properties: enable-method: const: spin-table - cache-size: [ cache-unified ] - cache-sets: [ cache-unified ] - cache-block-size: [ cache-unified ] - cache-line-size: [ cache-unified ] d-tlb-size: [ tlb-split ] d-tlb-sets: [ tlb-split ] i-tlb-size: [ tlb-split ] From 39b82fbe83629946e840b21caca453d87f2a6c59 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 7 Nov 2022 16:36:31 -0600 Subject: [PATCH 321/505] schemas: cache-controller: Add schema preventing split cache properties on unified caches If 'cache-unified' is present, then split cache properties should not be. Signed-off-by: Rob Herring --- dtschema/schemas/cache-controller.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dtschema/schemas/cache-controller.yaml b/dtschema/schemas/cache-controller.yaml index bbb84929..71c6df5b 100644 --- a/dtschema/schemas/cache-controller.yaml +++ b/dtschema/schemas/cache-controller.yaml @@ -45,6 +45,11 @@ dependentRequired: cache-line-size: [ cache-unified ] cache-level: [ compatible ] +dependentSchemas: + cache-unified: + patternProperties: + '^[id]-cache-': false + if: properties: $nodename: From 4b421a03d1753d332a21b532b9438fa4a8dd3311 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Nov 2022 17:11:32 -0500 Subject: [PATCH 322/505] schemas: Rework cache-controller.yaml to be common cache properties schema Make cache-controller.yaml a common schema only referenced by other schemas. Do this by dropping the node name requirement which is used to apply the schema. For starters, add a reference in cpus.yaml. Next we'll add a specific schema for nodes compatible with 'cache'. Signed-off-by: Rob Herring --- dtschema/schemas/cache-controller.yaml | 13 +++++++------ dtschema/schemas/cpus.yaml | 2 ++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/dtschema/schemas/cache-controller.yaml b/dtschema/schemas/cache-controller.yaml index 71c6df5b..550f1409 100644 --- a/dtschema/schemas/cache-controller.yaml +++ b/dtschema/schemas/cache-controller.yaml @@ -1,5 +1,6 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2019 Linaro Ltd. +# Copyright 2022 Arm Ltd. %YAML 1.2 --- $id: http://devicetree.org/schemas/cache-controller.yaml# @@ -11,9 +12,6 @@ maintainers: - Rob Herring properties: - $nodename: - pattern: "^(cache-controller|cpu)(@[0-9a-f,]+)*$" - cache-level: $ref: /schemas/types.yaml#/definitions/uint32 minimum: 2 @@ -51,9 +49,12 @@ dependentSchemas: '^[id]-cache-': false if: - properties: - $nodename: - pattern: "^cache-controller.*" + not: + properties: + device_type: + const: cpu + required: + - device_type then: required: - cache-level diff --git a/dtschema/schemas/cpus.yaml b/dtschema/schemas/cpus.yaml index 110dcb41..ed14691e 100644 --- a/dtschema/schemas/cpus.yaml +++ b/dtschema/schemas/cpus.yaml @@ -49,6 +49,8 @@ properties: patternProperties: '^cpu@[0-9a-f]+$': type: object + $ref: cache-controller.yaml# + properties: device_type: const: cpu From fd52a9634ea0528f8cfe8a37fad66dc69ab9afbe Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 1 Nov 2022 17:14:24 -0500 Subject: [PATCH 323/505] schemas: Add generic 'cache' node The DT spec defines cache nodes which are compatible with 'cache'. Add a schema for these nodes. Signed-off-by: Rob Herring --- dtschema/schemas/cache.yaml | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 dtschema/schemas/cache.yaml diff --git a/dtschema/schemas/cache.yaml b/dtschema/schemas/cache.yaml new file mode 100644 index 00000000..619ceb1e --- /dev/null +++ b/dtschema/schemas/cache.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2022 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/cache.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: Generic 'cache' Nodes + +description: Generic cache binding for caches nodes which only have common cache + properties. A cache with a register interface or other resources should have + its own compatible and schema. As L1 caches are described within CPU nodes, + this binding only applies to L2 and higher level caches. + +maintainers: + - Rob Herring + +select: + properties: + compatible: + const: cache + + required: + - compatible + +allOf: + - $ref: cache-controller.yaml# + +properties: + $nodename: + pattern: 'cache' + + compatible: + const: cache + + power-domains: + maxItems: 1 + +patternProperties: + '^l[3-9]-cache$': + type: object + description: Caches can have the next level cache as a child node + +required: + - cache-level + # In practice, all level 2 and higher caches are unified. + - cache-unified + +unevaluatedProperties: false + +... From f462ec46d29fee4cfd45f3a952e86f3c5c925561 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 2 Nov 2022 07:40:54 -0500 Subject: [PATCH 324/505] schemas: Split out 'cpu' node schema to separate file from 'cpus' schema In order to extend 'cpu' node schemas and have 'unevaluatedProperties' work correctly, the 'cpu' node schema needs to be separate. No functional change. Signed-off-by: Rob Herring --- dtschema/schemas/cpu.yaml | 134 +++++++++++++++++++++++++++++++++++++ dtschema/schemas/cpus.yaml | 98 +-------------------------- 2 files changed, 135 insertions(+), 97 deletions(-) create mode 100644 dtschema/schemas/cpu.yaml diff --git a/dtschema/schemas/cpu.yaml b/dtschema/schemas/cpu.yaml new file mode 100644 index 00000000..5d1be167 --- /dev/null +++ b/dtschema/schemas/cpu.yaml @@ -0,0 +1,134 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-clause +# Copyright (C) 2018-2019 SiFive, Inc. +# +# Description text is from the Devicetree Specification at +# https://www.devicetree.org/specifications/ +# which is +# Copyright 2008,2011 Power.org, Inc. +# Copyright 2008,2011 Freescale Semiconductor, Inc. +# Copyright 2008,2011 International Business Machines Corporation +# Copyright 2016,2017 Linaro,Ltd. +# Copyright 2016,2017 Arm,Ltd. +# +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/cpu.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: Common cpu node binding + +maintainers: + - Devicetree Specification Mailing List + +description: |+ + In Devicetree data files, the layout of CPUs is described in the + "cpus" node. This node in turn contains a number of subnodes + representing CPUs, which define properties for every cpu. + + Bindings for CPU nodes follow the Devicetree Specification, available from: + + https://www.devicetree.org/specifications/ + +select: false + +allOf: + - $ref: cache-controller.yaml# + +properties: + device_type: + const: cpu + + reg: + description: + Defines a unique CPU/thread ID for the CPU/threads represented + by the CPU node. + + compatible: true + + clock-frequency: + description: + Specifies the current clock speed of the CPU in Hertz. + + timebase-frequency: + oneOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - $ref: /schemas/types.yaml#/definitions/uint64 + minimum: 1 + description: + Specifies the current frequency at which the timebase and the + decrementer registers are updated (in Hertz). + + status: + $ref: types.yaml#/definitions/string + enum: [ okay, disabled, fail ] + description: + A standard property describing the state of a CPU. A CPU may be + running ("okay"), in a quiescent state ("disabled") or be not + operational or not exist ("fail"). + + enable-method: + $ref: /schemas/types.yaml#/definitions/string-array + description: + Describes the method by which a CPU in a disabled state is enabled. + This property is required for CPUs with a status property with a + value of "disabled". The value consists of one or more strings + that define the method to release this CPU. If a client program + recognizes any of the methods, it may use it. + + cpu-release-addr: + $ref: /schemas/types.yaml#/definitions/uint64 + description: + This value specifies the physical address of a spin table entry that + releases a secondary CPU from its spin loop. + + cache-op-block-size: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Specifies the block size in bytes upon which cache block instructions + operate. Required if different than the L1 cache block size. + + reservation-granule-size: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Specifies the reservation granule size supported by this processor + in bytes. + + mmu-type: + $ref: /schemas/types.yaml#/definitions/string + description: + Specifies the CPU's MMU type. + + tlb-split: + $ref: /schemas/types.yaml#/definitions/flag + description: + If present, specifies that the TLB has a split configuration, with + separate TLBs for instructions and data. If absent, specifies that + the TLB has a unified configuration. Required for a CPU with a + TLB in a split configuration. + +patternProperties: + "^(i-|d-|)tlb-(size|sets)$": + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + +anyOf: + - required: + - device_type + - required: + - reg + - required: + - compatible + +dependencies: + cpu-release-addr: + properties: + enable-method: + const: spin-table + d-tlb-size: [ tlb-split ] + d-tlb-sets: [ tlb-split ] + i-tlb-size: [ tlb-split ] + i-tlb-sets: [ tlb-split ] + +additionalProperties: true + +... diff --git a/dtschema/schemas/cpus.yaml b/dtschema/schemas/cpus.yaml index ed14691e..e72b1667 100644 --- a/dtschema/schemas/cpus.yaml +++ b/dtschema/schemas/cpus.yaml @@ -48,103 +48,7 @@ properties: patternProperties: '^cpu@[0-9a-f]+$': - type: object - $ref: cache-controller.yaml# - - properties: - device_type: - const: cpu - - reg: - description: - Defines a unique CPU/thread ID for the CPU/threads represented - by the CPU node. - - compatible: true - - clock-frequency: - description: - Specifies the current clock speed of the CPU in Hertz. - - timebase-frequency: - oneOf: - - $ref: /schemas/types.yaml#/definitions/uint32 - - $ref: /schemas/types.yaml#/definitions/uint64 - minimum: 1 - description: - Specifies the current frequency at which the timebase and the - decrementer registers are updated (in Hertz). - - status: - $ref: types.yaml#/definitions/string - enum: [ okay, disabled, fail ] - description: - A standard property describing the state of a CPU. A CPU may be - running ("okay"), in a quiescent state ("disabled") or be not - operational or not exist ("fail"). - - enable-method: - $ref: /schemas/types.yaml#/definitions/string-array - description: - Describes the method by which a CPU in a disabled state is enabled. - This property is required for CPUs with a status property with a - value of "disabled". The value consists of one or more strings - that define the method to release this CPU. If a client program - recognizes any of the methods, it may use it. - - cpu-release-addr: - $ref: /schemas/types.yaml#/definitions/uint64 - description: - This value specifies the physical address of a spin table entry that - releases a secondary CPU from its spin loop. - - cache-op-block-size: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Specifies the block size in bytes upon which cache block instructions - operate. Required if different than the L1 cache block size. - - reservation-granule-size: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Specifies the reservation granule size supported by this processor - in bytes. - - mmu-type: - $ref: /schemas/types.yaml#/definitions/string - description: - Specifies the CPU's MMU type. - - tlb-split: - $ref: /schemas/types.yaml#/definitions/flag - description: - If present, specifies that the TLB has a split configuration, with - separate TLBs for instructions and data. If absent, specifies that - the TLB has a unified configuration. Required for a CPU with a - TLB in a split configuration. - - patternProperties: - "^(i-|d-|)tlb-(size|sets)$": - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 1 - - anyOf: - - required: - - device_type - - required: - - reg - - required: - - compatible - - dependencies: - cpu-release-addr: - properties: - enable-method: - const: spin-table - d-tlb-size: [ tlb-split ] - d-tlb-sets: [ tlb-split ] - i-tlb-size: [ tlb-split ] - i-tlb-sets: [ tlb-split ] + $ref: cpu.yaml# required: - '#address-cells' From 4489555b11d904c0f10ba774b153d7b89d853315 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 6 Dec 2022 07:35:46 -0600 Subject: [PATCH 325/505] schemas: Temporarily disable cache schema Disable the cache schema until warning fixes have landed. Signed-off-by: Rob Herring --- dtschema/schemas/cache.yaml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/dtschema/schemas/cache.yaml b/dtschema/schemas/cache.yaml index 619ceb1e..acbc3b50 100644 --- a/dtschema/schemas/cache.yaml +++ b/dtschema/schemas/cache.yaml @@ -15,13 +15,8 @@ description: Generic cache binding for caches nodes which only have common cache maintainers: - Rob Herring -select: - properties: - compatible: - const: cache - - required: - - compatible +# Disable until warnings fixed +select: false allOf: - $ref: cache-controller.yaml# From f655743763eea8b049cbb3e9f221f4ff2d541c5c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 1 Dec 2022 16:50:59 +0100 Subject: [PATCH 326/505] schemas: relax phy-cells requirement for PHY-like nodes Several Devicetree nodes in Linux kernel are named "phy", but they do not have "#phy-cells" property. Instead their children have it. This leads to a lot of false positives, so relax the requirement and do not enforce having #phy-cells for every "phy" node. Signed-off-by: Krzysztof Kozlowski --- dtschema/schemas/phy/phy-provider.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dtschema/schemas/phy/phy-provider.yaml b/dtschema/schemas/phy/phy-provider.yaml index 01ff62c5..f513ad78 100644 --- a/dtschema/schemas/phy/phy-provider.yaml +++ b/dtschema/schemas/phy/phy-provider.yaml @@ -8,9 +8,11 @@ title: PHY Provider Common Properties maintainers: - Rob Herring +# always select the core schema +select: true + properties: - $nodename: - pattern: "^(|usb-|usb2-|usb3-|pci-|pcie-|sata-)phy(@[0-9a-f,]+)*$" + # Recommended node names: (|usb-|usb2-|usb3-|pci-|pcie-|sata-)phy "#phy-cells": true @@ -25,9 +27,6 @@ properties: minimum: 1 maximum: 32 -required: - - "#phy-cells" - dependentRequired: phy-type: [ '#phy-cells' ] From d19ad0634d68a7dcf5e0843a57e9039b5470e884 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 14 Dec 2022 15:53:54 -0600 Subject: [PATCH 327/505] dtschema: Rework variable size matrix fixup The current location to check known_variable_matrix_props is too far down in some cases. For example, the variable size may be expressed in a single schema using 'oneOf'. Signed-off-by: Rob Herring --- dtschema/lib.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 57049d92..28741ec6 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -215,11 +215,6 @@ def _is_matrix_schema(subschema): return False -known_variable_matrix_props = { - 'fsl,pins', -} - - # If we have a matrix with variable inner and outer dimensions, then drop the dimensions # because we have no way to reconstruct them. def _fixup_int_matrix(propname, subschema): @@ -229,8 +224,7 @@ def _fixup_int_matrix(propname, subschema): outer_dim = _get_array_range(subschema) inner_dim = _get_array_range(subschema.get('items', {})) - if propname in known_variable_matrix_props or \ - (outer_dim[0] != outer_dim[1] and inner_dim[0] != inner_dim[1]): + if outer_dim[0] != outer_dim[1] and inner_dim[0] != inner_dim[1]: subschema.pop('items', None) subschema.pop('maxItems', None) subschema.pop('minItems', None) @@ -469,6 +463,12 @@ def fixup_schema(schema): fixup_sub_schema(schema, True) +known_variable_matrix_props = { + 'fsl,pins', + 'qcom,board-id' +} + + def fixup_sub_schema(schema, is_prop): if not isinstance(schema, dict): return @@ -495,6 +495,13 @@ def fixup_sub_schema(schema, is_prop): continue for prop in v: + if prop in known_variable_matrix_props and isinstance(v[prop], dict): + ref = v[prop].pop('$ref', None) + schema[k][prop] = {} + if ref: + schema[k][prop]['$ref'] = ref + continue + walk_properties(prop, v[prop]) # Recurse to check for {properties,patternProperties} in each prop fixup_sub_schema(v[prop], True) From 5e4090ec1b8be330ba261db5d66bb0bc6a75191d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 22 Dec 2022 15:35:44 -0600 Subject: [PATCH 328/505] schemas: pinctrl: Add missing start/end anchors on "pinctrl-[0-9]" The pattern, "pinctrl-[0-9]", is missing start and end anchors so it will allow anything at the begining or end of the property name. There's a few cases of pinctrl-10 or more, so we need to allow for more than 1 digit. Signed-off-by: Rob Herring --- dtschema/schemas/pinctrl/pinctrl-consumer.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/pinctrl/pinctrl-consumer.yaml b/dtschema/schemas/pinctrl/pinctrl-consumer.yaml index 9c5216f7..c6dde464 100644 --- a/dtschema/schemas/pinctrl/pinctrl-consumer.yaml +++ b/dtschema/schemas/pinctrl/pinctrl-consumer.yaml @@ -19,7 +19,7 @@ properties: pinctrl-names: true patternProperties: - "pinctrl-[0-9]": + "^pinctrl-[0-9]+$": $ref: /schemas/types.yaml#/definitions/phandle-array dependencies: From 64055c132ec4002553c8702208716e09d1aa6305 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 8 Nov 2022 13:40:16 -0600 Subject: [PATCH 329/505] Drop support for YAML encoded DT files Validating YAML encoded DT files was problematic because it was dependent on DTS syntax encoding such as <> and bit size tags. Now validation has been using DTB files for some time, so drop the YAML support. Signed-off-by: Rob Herring --- README.md | 16 ---------------- dtschema/dtb.py | 1 - dtschema/lib.py | 30 +----------------------------- test/test-dt-validate.py | 15 --------------- tools/dt-doc-validate | 2 +- tools/dt-validate | 27 ++++++++++----------------- 6 files changed, 12 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index d4884748..bcc4b543 100644 --- a/README.md +++ b/README.md @@ -58,10 +58,6 @@ restricted by defining 'minItems', 'maxItems', and 'additionalItems'. For DeviceTree Schemas, a fixed size is desired in most cases, so these properties are added based on the size of 'items' list. -The YAML DeviceTree format also makes all string values an array and scalar -values a matrix (in order to define groupings) even when only a single value -is present. Single entries in schemas are fixed up to match this encoding. - ### *Devicetree Meta-Schemas* Found in `./dtschema/meta-schemas` @@ -77,18 +73,6 @@ As a developer you normally will not need to write metaschema files. Devicetree Meta-Schema files are normal YAML files using the jsonschema vocabulary. -### *YAML Devicetrees* - -*YAML Devicetrees* files are regular .dts files transcoded into a YAML -representation. -There is no special information in these files. They are an intermediate -format suitable for the schema validation tools. - -Direct validation of .dtb files is also supported and preferred over -YAML DT encoding. As the DTB format has no type information within it, -the Devicetree Schemas are used for their type information to decode -the DT property values. - ## Usage There are several tools available in the *tools/* directory. diff --git a/dtschema/dtb.py b/dtschema/dtb.py index abe0478b..47b7eff2 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -357,7 +357,6 @@ def fixup_phandles(dt, path=''): if k == 'interconnects': cells += _get_phandle_arg_size(path + ':' + k, i + cells, val[i + cells:], cellname) - val[i] = dtschema.sized_int(val[i], phandle=True) dt[k] += [val[i:i + cells]] #print(k, dt[k], file=sys.stderr) diff --git a/dtschema/lib.py b/dtschema/lib.py index 28741ec6..f1a93c54 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -25,48 +25,20 @@ re._MAXCACHE = 2048 -class tagged_list(list): - - tags = {u'!u8': 8, u'!u16': 16, u'!u32': 32, u'!u64': 64} - - def __init__(self, int_list, tag, tags=tags): - int_list = [sized_int(i, size=tags[tag]) for i in int_list] - super().__init__(int_list) - - @staticmethod - def constructor(loader, node): - return tagged_list(loader.construct_sequence(node), node.tag) - - class sized_int(int): def __new__(cls, value, *args, **kwargs): return int.__new__(cls, value) - def __init__(self, value, size=32, phandle=False): + def __init__(self, value, size=32): self.size = size - self.phandle = phandle - - @staticmethod - def constructor(loader, node): - return sized_int(loader.construct_yaml_int(node), phandle=True) rtyaml = ruamel.yaml.YAML(typ='rt') rtyaml.allow_duplicate_keys = False rtyaml.preserve_quotes = True -rtyaml.Constructor.add_constructor(u'!u8', tagged_list.constructor) -rtyaml.Constructor.add_constructor(u'!u16', tagged_list.constructor) -rtyaml.Constructor.add_constructor(u'!u32', tagged_list.constructor) -rtyaml.Constructor.add_constructor(u'!u64', tagged_list.constructor) -rtyaml.Constructor.add_constructor(u'!phandle', sized_int.constructor) yaml = ruamel.yaml.YAML(typ='safe') yaml.allow_duplicate_keys = False -yaml.Constructor.add_constructor(u'!u8', tagged_list.constructor) -yaml.Constructor.add_constructor(u'!u16', tagged_list.constructor) -yaml.Constructor.add_constructor(u'!u32', tagged_list.constructor) -yaml.Constructor.add_constructor(u'!u64', tagged_list.constructor) -yaml.Constructor.add_constructor(u'!phandle', sized_int.constructor) def path_to_obj(tree, path): diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index bd0ead08..6375604b 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -132,21 +132,6 @@ def check_subtree(self, nodename, subtree, fail): if isinstance(value, dict): self.check_subtree(name, value, fail) - def test_dt_yaml_validation(self): - '''Test that all DT files under ./test/ validate against the DT schema (YAML)''' - for filename in glob.iglob('test/*.dts'): - with self.subTest(schema=filename): - expect_fail = "-fail" in filename - tmpfile = tempfile.NamedTemporaryFile() - # The test files have lots of expected warnings, so send stderr to /dev/null - res = subprocess.run(['dtc', '-Oyaml', filename], stdout=tmpfile, stderr=subprocess.PIPE) - self.assertEqual(res.returncode, 0, msg='dtc failed:\n' + res.stderr.decode()) - - testtree = dtschema.load(tmpfile.name)[0] - for name,value in testtree.items(): - if isinstance(value, dict): - self.check_node(name, value, expect_fail) - def test_dtb_validation(self): '''Test that all DT files under ./test/ validate against the DT schema (DTB)''' for filename in glob.iglob('test/*.dts'): diff --git a/tools/dt-doc-validate b/tools/dt-doc-validate index b5885b62..657ea810 100755 --- a/tools/dt-doc-validate +++ b/tools/dt-doc-validate @@ -41,7 +41,7 @@ if __name__ == "__main__": ap = argparse.ArgumentParser(fromfile_prefix_chars='@', epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("yamldt", nargs='*', type=str, - help="Filename of YAML encoded devicetree input file") + help="Directory or filename of YAML encoded devicetree schema file") ap.add_argument('-v', '--verbose', help="verbose mode", action="store_true") ap.add_argument('-n', '--line-number', help="Print line and column numbers (slower)", action="store_true") ap.add_argument('-u', '--url-path', help="Additional search path for references") diff --git a/tools/dt-validate b/tools/dt-validate index c55fd7ef..72ad4cf1 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -12,7 +12,6 @@ signal.signal(signal.SIGINT, sigint_handler) import sys import os -import ruamel.yaml import jsonschema import argparse import glob @@ -70,14 +69,8 @@ class schema_group(): if schema['$id'] == 'generated-compatibles': if show_unmatched < 1: continue - if isinstance(node, ruamel.yaml.comments.CommentedBase): - line = node.lc.line - col = node.lc.col - else: - line = 0 - col = 0 - print("%s:%i:%i: %s: failed to match any schema with compatible: %s" % - (filename, line, col, fullname, node['compatible']), file=sys.stderr) + print("%s: %s: failed to match any schema with compatible: %s" % + (filename, fullname, node['compatible']), file=sys.stderr) continue print(dtschema.format_error(filename, error, nodename=nodename, verbose=verbose) + @@ -123,8 +116,8 @@ class schema_group(): if __name__ == "__main__": ap = argparse.ArgumentParser(fromfile_prefix_chars='@', epilog='Arguments can also be passed in a file prefixed with a "@" character.') - ap.add_argument("yamldt", nargs='*', - help="Filename or directory of YAML encoded devicetree input file(s)") + ap.add_argument("dtbs", nargs='*', + help="Filename or directory of devicetree DTB input file(s)") ap.add_argument('-s', '--schema', help="preparsed schema file or path to schema files") ap.add_argument('-p', '--preparse', help="preparsed schema file (deprecated, use '-s')") ap.add_argument('-l', '--limit', help="limit validation to schema files matching substring") @@ -134,7 +127,7 @@ if __name__ == "__main__": "Twice for all nodes", action="count") ap.add_argument('-M', '--show-matched', help="Print out matching schema for each node", action="store_true") - ap.add_argument('-n', '--line-number', help="Print line and column numbers (slower)", action="store_true") + ap.add_argument('-n', '--line-number', help="Obsolete", action="store_true") ap.add_argument('-v', '--verbose', help="verbose mode", action="store_true") ap.add_argument('-u', '--url-path', help="Additional search path for references") ap.add_argument('-V', '--version', help="Print version number", @@ -156,19 +149,19 @@ if __name__ == "__main__": else: sg = schema_group() - for d in args.yamldt: + for d in args.dtbs: if not os.path.isdir(d): continue - for filename in glob.iglob(d + "/**/*.yaml", recursive=True): - testtree = dtschema.load(filename, line_number=args.line_number) + for filename in glob.iglob(d + "/**/*.dtb", recursive=True): + testtree = dtschema.load(filename) if verbose: print("Check: " + filename) sg.check_trees(filename, testtree) - for filename in args.yamldt: + for filename in args.dtbs: if not os.path.isfile(filename): continue - testtree = dtschema.load(filename, line_number=args.line_number) + testtree = dtschema.load(filename) if verbose: print("Check: " + filename) sg.check_trees(filename, testtree) From b23d8ca9fe8fbb393e037d6b5b1164e0aec0d3a5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 22 Dec 2022 15:06:42 -0600 Subject: [PATCH 330/505] meta-schemas: Add more descriptions for hints Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 78f16a6b..bfc7d86b 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -150,6 +150,7 @@ properties: maxItems: minimum: 1 minItems: + description: An array property has at least 1 item or is not present minimum: 1 not: $ref: "#/definitions/sub-schemas" @@ -186,6 +187,7 @@ properties: additionalProperties: $ref: "#/definitions/sub-schemas" required: + description: "'required' must be valid DT property or node names" type: array uniqueItems: true items: From e59a935b672a8d95e07923f5a48fef4f6fbd30b5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 14 Dec 2022 15:55:17 -0600 Subject: [PATCH 331/505] schemas: Explicitly allow additional properties on child node schemas Add 'additionalProperties: true' for a couple of child node schemas. Signed-off-by: Rob Herring --- dtschema/schemas/root-node.yaml | 2 ++ dtschema/schemas/simple-bus.yaml | 1 + 2 files changed, 3 insertions(+) diff --git a/dtschema/schemas/root-node.yaml b/dtschema/schemas/root-node.yaml index b0901504..dc06e0c4 100644 --- a/dtschema/schemas/root-node.yaml +++ b/dtschema/schemas/root-node.yaml @@ -36,6 +36,8 @@ properties: patternProperties: "@(0|[1-9a-f][0-9a-f]*)$": type: object + additionalProperties: true + properties: reg: items: diff --git a/dtschema/schemas/simple-bus.yaml b/dtschema/schemas/simple-bus.yaml index a7847f40..5f3524ea 100644 --- a/dtschema/schemas/simple-bus.yaml +++ b/dtschema/schemas/simple-bus.yaml @@ -35,6 +35,7 @@ patternProperties: # All other properties should be child nodes with unit-address and 'reg' "@(0|[1-9a-f][0-9a-f]*)$": type: object + additionalProperties: true properties: reg: items: From 9a07fd84e3a6f16167b904e96d66cc4a17c81d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Grzelak?= Date: Thu, 12 Jan 2023 02:31:31 +0100 Subject: [PATCH 332/505] meta-schemas: cell: Add quotation marks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit YAML syntax treats # sign with leading space as a comment. Fix it by placing quotation mark around it. Signed-off-by: Michał Grzelak --- dtschema/meta-schemas/cell.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/cell.yaml b/dtschema/meta-schemas/cell.yaml index 4929cc68..3f61ed93 100644 --- a/dtschema/meta-schemas/cell.yaml +++ b/dtschema/meta-schemas/cell.yaml @@ -75,7 +75,7 @@ single: default: type: integer oneOf: - $ref: #/single + $ref: '#/single' propertyNames: enum: [ description, deprecated, const, enum, minimum, maximum, multipleOf, default, $ref, oneOf ] From eae25baa7c3c773f23ebea0121fe5dffa3bbccd3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 12 Jan 2023 11:53:28 -0600 Subject: [PATCH 333/505] dtb: Assume empty strings means the type is not string When there are multiple types including a string type, we test if the data can be decoded as strings. While empty strings are valid in general, we only call bytes_to_string() when a property name has multiple types. In that case, we need to assume empty strings means it is not a string. Otherwise, values such as a 32-bit 0 looks like 4 empty strings instead of an integer type. IIRC, we only needed to allow empty strings when bytes_to_string() was used in all cases for strings. Signed-off-by: Rob Herring --- dtschema/dtb.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 47b7eff2..3aa28100 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -41,7 +41,10 @@ def bytes_to_string(b): if count > 0 and not len(strings[-1]): for string in strings[:-1]: if not string: - continue + # While empty strings are valid, assume empty strings means + # not a string as we only get here when there are multiple + # types. + break if not string.isprintable(): break else: From 8b0abd43d8e4bd79328b6a6f581f7750e0d5abc8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 12 Jan 2023 10:08:07 -0600 Subject: [PATCH 334/505] dtschema: Fix walking duplicate node names when extracting types When extracting property types, we were bailing out when the same node name within a schema file occurred multiple times. So any new child properties and types were missed. Rework the logic to exit the loop and continue on rather than exiting the function. Signed-off-by: Rob Herring --- dtschema/lib.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index f1a93c54..c7b6cb9b 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -876,13 +876,11 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): p['dim'] = _merge_dim(p['dim'], dim) return if p['type'].startswith(prop_type): - # Already have the same or looser type + # Already have the same or looser type, just record the $id + new_prop = None if schema['$id'] not in p['$id']: p['$id'] += [schema['$id']] - # Descend into child schemas if we haven't seen this node already - if prop_type == 'node': - break - return + break elif p['type'] in prop_type: # Replace scalar type with array type new_prop['$id'] += p['$id'] @@ -892,7 +890,8 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): if dup_prop: props[propname].remove(dup_prop) - props[propname] += [new_prop] + if new_prop: + props[propname] += [new_prop] if subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: _extract_subschema_types(props, schema, subschema) From ad78307620bf229435abdc0a52a2c3340fe7cf7a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 19 Jan 2023 13:57:34 +0100 Subject: [PATCH 335/505] schemas: add basic OPP consumer bindings Several devices use Operating Performance Points and are consumers of the Performance or Power Domain controllers. Document common 'operating-points-v2' and 'required-opps' properties. In Linux kernel bindings the 'operating-points-v2' is a phandle-array but there is no single use with more than one phandle. Since one OPP table can store multiple values, it is unlikely that we ever need multiple tables per one device, thus make it a phandle. Signed-off-by: Krzysztof Kozlowski --- dtschema/schemas/opp/opp.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 dtschema/schemas/opp/opp.yaml diff --git a/dtschema/schemas/opp/opp.yaml b/dtschema/schemas/opp/opp.yaml new file mode 100644 index 00000000..4229a445 --- /dev/null +++ b/dtschema/schemas/opp/opp.yaml @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2023 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power-domain/opp.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: Operating Performance Points Consumer Common Properties + +maintainers: + - Rob Herring + +# always select the core schema +select: true + +properties: + operating-points-v2: + $ref: /schemas/types.yaml#/definitions/phandle + + required-opps: + $ref: /schemas/types.yaml#/definitions/phandle-array + minItems: 1 + maxItems: 8 + +additionalProperties: true From a0634fca88f16fdfd9476e7ee22d003d942a1680 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 13 Jan 2023 13:19:17 -0700 Subject: [PATCH 336/505] Correct typo in dt-doc-validate command The example here does not work. Fix it. Signed-off-by: Simon Glass --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bcc4b543..9d2f6e8e 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ them against the DT meta-schema. Example: ``` -dt-doc-validate -u test/schema test/schemas/good-example.yaml +dt-doc-validate -u test/schemas test/schemas/good-example.yaml ``` `tools/dt-mk-schema` From 63bd8472dfc6951eae1c95b27ac8cbc88f4cb3b0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 29 Sep 2022 11:22:00 -0600 Subject: [PATCH 337/505] schemas: Add schema for U-Boot driver model 'phase tags' U-Boot has some particular challenges with device tree and devices: - U-Boot has multiple build phases, such as a Secondary Program Loader (SPL) phase which typically runs in a pre-SDRAM environment where code and data space are limited. In particular, there may not be enough space for the full device tree blob. U-Boot uses various automated techniques to reduce the size from perhaps 40KB to 3KB. It is not always possible to handle these tags entirely at build time, since U-Boot proper must have the full device tree, even though we do not want it to process all nodes until after relocation. - Some U-Boot phases needs to run before the clocks are properly set up, where the CPU may be running very slowly. Therefore it is important to bind only those devices which are actually needed in that phase - U-Boot uses lazy initialisation for its devices, with 'bind' and 'probe' being separate steps. Even if a device is bound, it is not actually probed until it is used. This is necessary to keep the boot time reasonable, e.g. to under a second The phases of U-Boot in order are: TPL, VPL, SPL, U-Boot (first pre-relocation, then post-relocation). ALl but the last two are optional. For the above reasons, U-Boot only includes the full device tree in the final 'U-Boot proper' build. Even then, before relocation U-Boot only processes nodes which are marked as being needed. For this to work, U-Boot's driver model[1] provides a way to mark device tree nodes as applicable for a particular phase. This works by adding a tag to the node, e.g.: cru: clock-controller@ff760000 { bootph-all; compatible = "rockchip,rk3399-cru"; reg = <0x0 0xff760000 0x0 0x1000>; rockchip,grf = <&grf>; #clock-cells = <1>; #reset-cells = <1>; ... }; Here the "bootph-all" tag indicates that the node must be present in all phases, since the clock driver is required. There has been discussion over the years about whether this could be done in a property instead, e.g. options { bootph-all = <&cru> <&gpio_a> ...; ... }; Some problems with this: - we need to be able to merge several such tags from different .dtsi files since many boards have their own specific requirements - it is hard to find and cross-reference the affected nodes - it is more error-prone - it requires significant tool rework in U-Boot, including fdtgrep and the build system - is harder (slower, more code) to process since it involves scanning another node/property to find out what to do with a particular node - we don't want to add phandle arguments to the above since we are referring, e.g., to the clock device as a whole, not a paricular clock - the of-platdata feature[2], which converts device tree to C for even more constrained environments, would need to become aware of the /options node There is also the question about whether this needs to be U-Boot-specific, or whether the tags could be generic. From what I can tell, U-Boot is the only bootloader which seriously attempts to use a runtime device tree in all cases. For this version, an attempt is made to name the phases in a generic manner. It should also be noted that the approach provided here has stood the test of time, used in U-Boot for 8 years so far. So add the schema for this. This will allow a major class of schema exceptions to be dropped from the U-Boot source tree. This being sent to the mailing list since it might attract more review. A PR will be sent when this has had some review. That is why the file path is set up for https://github.com/devicetree-org/dt-schema rather than the Linux kernel. [1] https://u-boot.readthedocs.io/en/latest/develop/driver-model/index.html [2] https://u-boot.readthedocs.io/en/latest/develop/driver-model/of-plat.html Series-to: devicetree@vger.kernel.org Series-cc: u-boot, trini, Rob Herring Series-version: 7 Series-changes: 7 - Fix 'describes' typo - Add 'select: true' so that the schema is applied to every nodes - Drop | from descriptions Series-changes: 6 - Use 'bootph' instead of 'phase' - Use | instead of , in patternProperties - Drop mention of 40KB for device-tree size - Rework description of handling of parent nodes - Use separate properties for each boot phase - Update validation example at the top of bootphases.dts Series-changes: 5 - Fix instructions to run test - Update binding title - Use 'phase-' instead of 'phase,' Series-changes: 4 - Drop some unnecessary context from the commit message - Explain why parent nodes do not automatically inherit their children's tags - Rename the tags to use a phase,xxx format, explaining each one Series-changes: 3 - Fix an incorrect schema path in $id Series-changes: 2 - Expand docs to include a description of each tag - Fix some typos and unclear wording Signed-off-by: Simon Glass --- dtschema/lib.py | 5 ++ dtschema/schemas/bootph.yaml | 88 ++++++++++++++++++++++++++++++++++++ test/bootphases.dts | 22 +++++++++ 3 files changed, 115 insertions(+) create mode 100644 dtschema/schemas/bootph.yaml create mode 100644 test/bootphases.dts diff --git a/dtschema/lib.py b/dtschema/lib.py index c7b6cb9b..95a4f107 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -493,6 +493,11 @@ def fixup_node_props(schema): schema['properties'].setdefault('status', True) schema['properties'].setdefault('secure-status', True) schema['properties'].setdefault('$nodename', True) + schema['properties'].setdefault('bootph-pre-sram', True) + schema['properties'].setdefault('bootph-verify', True) + schema['properties'].setdefault('bootph-pre-ram', True) + schema['properties'].setdefault('bootph-some-ram', True) + schema['properties'].setdefault('bootph-all', True) keys = list() if 'properties' in schema: diff --git a/dtschema/schemas/bootph.yaml b/dtschema/schemas/bootph.yaml new file mode 100644 index 00000000..a3ccf06e --- /dev/null +++ b/dtschema/schemas/bootph.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2022 Google LLC +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/bootph.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Boot-phase-specific device nodes + +maintainers: + - Simon Glass + +description: | + Some programs run in memory-constrained environments yet want to make use + of device tree. + + The full device tree is often quite large relative to the available memory + of a boot phase, so cannot fit into every phase of the boot process. Even + when memory is not a problem, some phases may wish to limit which device + nodes are present, so as to reduce execution time. + + This binding supports adding tags to device tree nodes to allow them to be + marked according to the phases where they should be included. + + Without any tags, nodes are included only in the final phase, where all + memory is available. Any untagged nodes are dropped from previous phases + and are ignored before the final phase is reached. + + The build process produces a separate executable for each phase. It can + use fdtgrep to drop any nodes which are not needed for a particular build. + For example, the pre-sram build will drop any nodes which are not marked + with bootph-pre-sram or bootph-all tags. + + Note that phase builds may drop the tags, since they have served their + purpose by that point. So when looking at phase-specific device tree files + you may not see these tags. + + Multiple tags can be used in the same node. + + Tags in a child node are implied to be present in all parent nodes as well. + This is important, since some missing properties (such as "ranges", or + "compatible") can cause the child node to be ignored or incorrectly + parsed. + + That said, at present, fdtgrep applies tags only to the node they are + added to, not to any parents. This means U-Boot device tree files often + add the same tag to parent nodes, rather than relying on tooling to do + this. This is a limitation of fdtgrep and it will be addressed so that + 'Linux DTs' do not need to do this. + + The available tags are described as properties below, in order of phase + execution. + +select: true + +properties: + bootph-pre-sram: + type: boolean + description: + Enable this node when SRAM is not available. This phase must set up + some SRAM or cache-as-RAM so it can obtain data/BSS space to use + during execution. + + bootph-verify: + type: boolean + description: + Enable this node in the verification step, which decides which of the + available images should be run next. + + bootph-pre-ram: + type: boolean + description: + Enable this node in the phase that sets up SDRAM. + + bootph-some-ram: + type: boolean + description: + Enable this node in the phase that is run after SDRAM is working but + before all of it is available. Some RAM is available but it is limited + (e.g. it may be split into two pieces by the location of the running + program) because the program code is not yet relocated out of the way. + + bootph-all: + type: boolean + description: + Include this node in all phases (for U-Boot see enum u_boot_phase). + +additionalProperties: true diff --git a/test/bootphases.dts b/test/bootphases.dts new file mode 100644 index 00000000..037c626c --- /dev/null +++ b/test/bootphases.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright 2022 Google LLC + +// An attempt to provide a device tree to validate the phase properties + +// dtc -O dtb -o test.dtb test/bootphases.dts && tools/dt-validate test.dtb + + +/dts-v1/; + +/ { + model = "none"; + compatible = "foo"; + + #address-cells = <1>; + #size-cells = <1>; + + some-device { + compatible = "vendor,soc1-ip"; + bootph-pre-sram; + }; +}; From 244afdd68f228efcabc1d96a7dfa1c04ed93aa61 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 19 Jan 2023 13:29:26 -0600 Subject: [PATCH 338/505] schemas: opp: Fix $id value The path in $id is wrong, fix it. Signed-off-by: Rob Herring --- dtschema/schemas/opp/opp.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/opp/opp.yaml b/dtschema/schemas/opp/opp.yaml index 4229a445..32d0dbbb 100644 --- a/dtschema/schemas/opp/opp.yaml +++ b/dtschema/schemas/opp/opp.yaml @@ -2,7 +2,7 @@ # Copyright 2023 Linaro Ltd. %YAML 1.2 --- -$id: http://devicetree.org/schemas/power-domain/opp.yaml# +$id: http://devicetree.org/schemas/opp/opp.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# title: Operating Performance Points Consumer Common Properties From 37c57d188ca48df781fada496d9553eb755f0836 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 20 Jan 2023 19:45:24 +0100 Subject: [PATCH 339/505] workflows: add Python v3.11 to test matrix Test on newest Pyhon v3.11. Signed-off-by: Krzysztof Kozlowski --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50aeeb39..aee59a50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.7', '3.8', '3.9', '3.10'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] steps: - uses: actions/checkout@v2 From 42e93b1f28b067d13d4020928019e8a00d9a8d7c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 20 Jan 2023 19:58:27 +0100 Subject: [PATCH 340/505] workflows: consistently run pip via python Run pip always via python module - for consistency and actually for some cases where OS does not have pip binary in the path. Signed-off-by: Krzysztof Kozlowski --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aee59a50..0b6c549a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: sudo apt-get -qq -y install device-tree-compiler python -m pip install --upgrade pip python -m pip install flake8 - pip install . + python -m pip install . - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names From a84a9d092f9363632e8743c459a6330c62f905ac Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 20 Jan 2023 20:21:31 +0100 Subject: [PATCH 341/505] workflows: bump actions Bump checkout and setup-python Github actions to newer versions. Signed-off-by: Krzysztof Kozlowski --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0b6c549a..817c61cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,9 +11,9 @@ jobs: python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From 784179bf7d7fb0f239db179bc3dd4da92ea68b4f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 24 Jan 2023 15:25:36 -0600 Subject: [PATCH 342/505] dtschema: Handle local $refs for node schemas A $ref for a node schema causes us to stop walking the schema because the original subschema is modified after we return from handling it. Furthermore, a node schema with a $ref may not have an explicit 'type', so we need to check other things indicating a node schema. Signed-off-by: Rob Herring --- dtschema/lib.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 95a4f107..09fb4758 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -806,11 +806,11 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): # We only support local refs if '$ref' in subschema and subschema['$ref'].startswith('#/'): sch_path = subschema['$ref'].split('/')[1:] - subschema = schema + tmp_subschema = schema for p in sch_path: - subschema = subschema[p] - #print(propname, sch_path, subschema, file=sys.stderr) - _extract_prop_type(props, schema, propname, subschema, is_pattern) + tmp_subschema = tmp_subschema[p] + #print(propname, sch_path, tmp_subschema, file=sys.stderr) + _extract_prop_type(props, schema, propname, tmp_subschema, is_pattern) for k in subschema.keys() & {'allOf', 'oneOf', 'anyOf'}: for v in subschema[k]: @@ -821,7 +821,8 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): new_prop = {} prop_type = None - if 'type' in subschema and subschema['type'] == 'object': + if ('type' in subschema and subschema['type'] == 'object') or \ + subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: prop_type = 'node' else: try: From 7cade2ceaefae6f340e22ca9e472a550e724911f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Feb 2023 15:39:52 -0600 Subject: [PATCH 343/505] schemas: chosen: Add UEFI properties The /chosen UEFI have been documented since 2013 in the Linux kernel tree in Documentation/arm/uefi.rst. Add a proper schema for them. Signed-off-by: Rob Herring --- dtschema/schemas/chosen.yaml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/dtschema/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml index 86194ddf..6d5c3f15 100644 --- a/dtschema/schemas/chosen.yaml +++ b/dtschema/schemas/chosen.yaml @@ -222,6 +222,32 @@ properties: carrying the TPM measurement log. The address and the size are expressed in #address-cells and #size-cells, respectively of the root node. + linux,uefi-system-table: + $ref: types.yaml#/definitions/uint64 + description: + Physical address of the UEFI System Table. + + linux,uefi-mmap-start: + $ref: types.yaml#/definitions/uint64 + description: + Physical address of the UEFI memory map, populated by the UEFI + GetMemoryMap() call. + + linux,uefi-mmap-size: + $ref: types.yaml#/definitions/uint32 + description: + Size in bytes of the UEFI memory map pointed to by linux,uefi-mmap-start. + + linux,uefi-mmap-desc-size: + $ref: types.yaml#/definitions/uint32 + description: + Size in bytes of each entry in the UEFI memory map. + + linux,uefi-mmap-desc-ver: + $ref: types.yaml#/definitions/uint32 + description: + Version of the mmap descriptor format. + u-boot,bootconf: $ref: types.yaml#/definitions/string description: From f0fe7638383c865907328725f2a571ae0ffea3ba Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 21 Feb 2023 10:03:51 -0600 Subject: [PATCH 344/505] dtschema: fixup_node_props: Drop unnecessary key check We've added 'properties', so no need to check if it exists. Signed-off-by: Rob Herring --- dtschema/lib.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 09fb4758..0292f609 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -499,10 +499,7 @@ def fixup_node_props(schema): schema['properties'].setdefault('bootph-some-ram', True) schema['properties'].setdefault('bootph-all', True) - keys = list() - if 'properties' in schema: - keys.extend(schema['properties']) - + keys = list(schema['properties'].keys()) if 'patternProperties' in schema: keys.extend(schema['patternProperties']) From bb4b09d439b4ea5af610bd636a2b7c68da24b56a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 21 Feb 2023 10:05:06 -0600 Subject: [PATCH 345/505] dtschema: Allow 'dma-ranges' if 'ranges' is present 'dma-ranges' is valid any time 'ranges' is present. Signed-off-by: Rob Herring --- dtschema/lib.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dtschema/lib.py b/dtschema/lib.py index 0292f609..3ba46a58 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -499,6 +499,10 @@ def fixup_node_props(schema): schema['properties'].setdefault('bootph-some-ram', True) schema['properties'].setdefault('bootph-all', True) + # 'dma-ranges' allowed when 'ranges' is present + if 'ranges' in schema['properties']: + schema['properties'].setdefault('dma-ranges', True) + keys = list(schema['properties'].keys()) if 'patternProperties' in schema: keys.extend(schema['patternProperties']) From fa88cd30699734589813c86c2e249a438e97d65f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 8 Mar 2023 16:37:21 -0600 Subject: [PATCH 346/505] schemas: Move all address related properties into reg.yaml dt-core.yaml is just properties which don't fit anywhere else. As there's already a schema with some address related property constraints, let's just move all the address related properties there. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 20 ------------------- dtschema/schemas/reg.yaml | 37 ++++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index a01a9b72..b4cb0b1a 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -37,26 +37,6 @@ properties: $ref: types.yaml#/definitions/flag dma-noncoherent: $ref: types.yaml#/definitions/flag - dma-ranges: - oneOf: - - $ref: types.yaml#/definitions/flag - - $ref: types.yaml#/definitions/uint32-matrix - ranges: - oneOf: - - $ref: types.yaml#/definitions/flag - - $ref: types.yaml#/definitions/uint32-matrix - reg: - $ref: types.yaml#/definitions/uint32-matrix - reg-io-width: - $ref: types.yaml#/definitions/uint32 - minimum: 1 - maximum: 0xf - description: - Typically, a single set bit indicating the access size, but some uses treat - this as a bit mask of allowed sizes. - reg-shift: - $ref: types.yaml#/definitions/uint32 - enum: [ 0, 1, 2 ] secure-status: $ref: types.yaml#/definitions/string enum: [ okay, disabled, reserved ] diff --git a/dtschema/schemas/reg.yaml b/dtschema/schemas/reg.yaml index 8b153724..2c6a39e4 100644 --- a/dtschema/schemas/reg.yaml +++ b/dtschema/schemas/reg.yaml @@ -5,17 +5,44 @@ $id: http://devicetree.org/schemas/reg.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: reg property checks - -description: | - Common checks for 'reg' properties +title: Address related Common Properties maintainers: - Rob Herring select: true -properties: {} +properties: + '#address-cells': + maximum: 3 + + '#size-cells': + maximum: 2 + + dma-ranges: + oneOf: + - $ref: types.yaml#/definitions/flag + - $ref: types.yaml#/definitions/uint32-matrix + + ranges: + oneOf: + - $ref: types.yaml#/definitions/flag + - $ref: types.yaml#/definitions/uint32-matrix + + reg: + $ref: types.yaml#/definitions/uint32-matrix + + reg-io-width: + $ref: types.yaml#/definitions/uint32 + minimum: 1 + maximum: 0xf + description: + Typically, a single set bit indicating the access size, but some uses treat + this as a bit mask of allowed sizes. + + reg-shift: + $ref: types.yaml#/definitions/uint32 + enum: [ 0, 1, 2 ] additionalProperties: true From 01ae3e23c37800a0a86d7bae9a9d71cfd1422604 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 8 Mar 2023 16:40:18 -0600 Subject: [PATCH 347/505] schemas: Add 'firmware-name' property 'firmware-name' is a commonly used property to define devices' firmware filenames. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index b4cb0b1a..6a77827a 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -37,6 +37,12 @@ properties: $ref: types.yaml#/definitions/flag dma-noncoherent: $ref: types.yaml#/definitions/flag + firmware-name: + $ref: types.yaml#/definitions/string-array + description: + The filename for a device's firmware file. It is typically a single + entry, but some devices have multiple firmware files. It can also + be just a stem name used to construct the full firmware filename(s). secure-status: $ref: types.yaml#/definitions/string enum: [ okay, disabled, reserved ] From 46ae5a07fe9cae9452c5e75d47608c19407edc5b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 8 Mar 2023 16:57:50 -0600 Subject: [PATCH 348/505] schemas: Move '#size-cells' dependency to reg.yaml Missed this as part of moving the address related properties to reg.yaml. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 3 --- dtschema/schemas/reg.yaml | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 6a77827a..e93baf4c 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -82,9 +82,6 @@ patternProperties: "^#[a-zA-Z0-9,+\\-._]{0,63}$": $ref: types.yaml#/definitions/uint32 -dependencies: - "#size-cells": [ "#address-cells" ] - additionalProperties: false ... diff --git a/dtschema/schemas/reg.yaml b/dtschema/schemas/reg.yaml index 2c6a39e4..a06e48be 100644 --- a/dtschema/schemas/reg.yaml +++ b/dtschema/schemas/reg.yaml @@ -46,6 +46,9 @@ properties: additionalProperties: true +dependencies: + "#size-cells": [ "#address-cells" ] + allOf: - if: properties: From c83dd2cb836e252ef5b3b6265223298b93d48539 Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Sun, 12 Mar 2023 14:56:42 +0100 Subject: [PATCH 349/505] schemas: i2c: Add the clock stretching property The I2C specification allows for the clock line to be held low for a specified timeout to force the slave device into a 'wait' mode. This feature is known as 'Clock stretching' and is optional. In the NXP I2C specification, clock stretching is described as the process of pausing a transaction by holding the SCL line LOW. The transaction can only continue when the line is released HIGH again.[*] However, most target devices do not include an SCL driver and are therefore unable to stretch the clock. Add the following properties: - i2c-scl-clk-low-timeout-us: This property specifies the duration, in microseconds, for which the clock is kept low and a client needs to detect a forced waiting state. - i2c-scl-has-clk-low-timeout: This property specifies whether the I2C controller implements the clock stretching property. It's important to note that this feature should not be confused with the SMBUS clock timeout, which serves a similar function but specifies a timeout of 25-35ms. The I2C specification does not recommend any specific timeout. [*] NXP, UM10204 - I2C-bus specification and user manual Rev. 7.0, 1 October 2021, chapter 3.1.9. Signed-off-by: Andi Shyti Reviewed-by: Krzysztof Kozlowski --- dtschema/schemas/i2c/i2c-controller.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index 1f97a736..8cf9171a 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -44,6 +44,18 @@ properties: Number of nanoseconds the SCL signal takes to rise; t(r) in the I2C specification. + i2c-scl-clk-low-timeout-us: + description: + Number of microseconds the clock line needs to be pulled down in order + to force a waiting state. + + i2c-scl-has-clk-low-timeout: + type: boolean + description: + Indicates whether the controller implements the feature of wait + induction through SCL low, with the timeout being implemented + internally by the controller. + i2c-sda-falling-time-ns: description: Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C @@ -121,6 +133,12 @@ properties: States that no other devices are present on this bus other than the ones listed in the devicetree. +allOf: + - not: + required: + - i2c-scl-clk-low-timeout-us + - i2c-scl-has-clk-low-timeout + patternProperties: '@[0-9a-f]+$': type: object From f5d34c25b9e5c982233198aca47349ab2f605ca5 Mon Sep 17 00:00:00 2001 From: Serge Semin Date: Thu, 23 Mar 2023 18:09:47 +0300 Subject: [PATCH 350/505] meta-schemas: Allow 'not' keyword Root- and sub-node schemas are supposed to be allowed to use the 'not' keyword directly to express a schema against which the instance isn't supposed to be successfully validated. It shall work in the same way as the allOf, anyOf, oneOf-based validation except the keyword implies a single sub-schema against which an instance will be anti-evaluated. Signed-off-by: Serge Semin Signed-off-by: Rob Herring --- dtschema/meta-schemas/base.yaml | 2 +- dtschema/meta-schemas/nodes.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/base.yaml b/dtschema/meta-schemas/base.yaml index 1dd005c5..96d0a82f 100644 --- a/dtschema/meta-schemas/base.yaml +++ b/dtschema/meta-schemas/base.yaml @@ -50,7 +50,7 @@ properties: propertyNames: enum: [ $id, $schema, title, description, examples, required, allOf, anyOf, oneOf, definitions, $defs, additionalProperties, dependencies, dependentRequired, - dependentSchemas, patternProperties, properties, if, then, else, + dependentSchemas, patternProperties, properties, not, if, then, else, unevaluatedProperties, deprecated, maintainers, select, $ref ] required: diff --git a/dtschema/meta-schemas/nodes.yaml b/dtschema/meta-schemas/nodes.yaml index 7568169a..0b2c8f75 100644 --- a/dtschema/meta-schemas/nodes.yaml +++ b/dtschema/meta-schemas/nodes.yaml @@ -26,6 +26,7 @@ propertyNames: - unevaluatedProperties - deprecated - required + - not - allOf - anyOf - oneOf From 7ec2e6099ff684b0de0a7890e7b91807098403f3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 6 Apr 2023 13:05:42 -0500 Subject: [PATCH 351/505] dt-extract-example: Move the generated interrupt provider to its own node An example with an 'interrupt-controller' node has dtc warnings because there is an 'interrupt-controller' property. Move the fake interrupt controller to its own node to avoid this problem. Signed-off-by: Rob Herring --- tools/dt-extract-example | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/dt-extract-example b/tools/dt-extract-example index 8bee24a0..a8b5aaba 100755 --- a/tools/dt-extract-example +++ b/tools/dt-extract-example @@ -17,8 +17,11 @@ import ruamel.yaml import argparse interrupt_template = """ - interrupt-controller; - #interrupt-cells = < {int_cells} >; + interrupt-parent = <&fake_intc{index}>; + fake_intc{index}: fake-interrupt-controller {{ + interrupt-controller; + #interrupt-cells = < {int_cells} >; + }}; """ example_template = """ @@ -81,7 +84,7 @@ if __name__ == "__main__": example_dts += example_start ex = ' '.join(ex.splitlines(True)) if int_cells > 0: - int_props = interrupt_template.format(int_cells=int_cells) + int_props = interrupt_template.format(int_cells=int_cells, index=idx) else: int_props = "" example_dts += example_template.format(example=ex, example_num=idx, interrupt=int_props) From cf9b2bd6a9b3d1dad528a0ab8318eab7a1688f15 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 5 Apr 2023 08:33:04 -0500 Subject: [PATCH 352/505] schemas: PCI: Add missing descriptions and properties Copy over the missing descriptions and the one missing property, external-facing, from the Linux kernel pci.txt binding doc. Signed-off-by: Rob Herring --- dtschema/schemas/pci/pci-bus.yaml | 46 ++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/dtschema/schemas/pci/pci-bus.yaml b/dtschema/schemas/pci/pci-bus.yaml index d841b971..d8ba804a 100644 --- a/dtschema/schemas/pci/pci-bus.yaml +++ b/dtschema/schemas/pci/pci-bus.yaml @@ -49,7 +49,25 @@ properties: - 0xc2000000 - 0xc3000000 - reg: true + reg: + description: | + On PCI-PCI bridge nodes, as defined in the IEEE Std 1275-1994 + document, it is a five-cell address encoded as (phys.hi phys.mid + phys.lo size.hi size.lo). phys.hi should contain the device's BDF as + 0b00000000 bbbbbbbb dddddfff 00000000. The other cells should be zero. + + The bus number is defined by firmware, through the standard bridge + configuration mechanism. If this port is a switch port, then firmware + allocates the bus number and writes it into the Secondary Bus Number + register of the bridge directly above this port. Otherwise, the bus + number of a root port is the first number in the bus-range property, + defaulting to zero. + + If firmware leaves the ARI Forwarding Enable bit set in the bridge + above this port, then phys.hi contains the 8-bit function number as + 0b00000000 bbbbbbbb ffffffff 00000000. Note that the PCIe specification + recommends that firmware only leaves ARI enabled when it knows that the + OS is ARI-aware. dma-ranges: oneOf: @@ -83,6 +101,15 @@ properties: items: maximum: 255 + external-facing: + description: + When present, the port is externally facing. All bridges and endpoints + downstream of this port are external to the machine. The OS can, for + example, use this information to identify devices that cannot be + trusted with relaxed DMA protection, as users could easily attach + malicious devices to this port. + type: boolean + "#interrupt-cells": const: 1 @@ -107,9 +134,21 @@ properties: maximum: 7 linux,pci-domain: + description: + If present this property assigns a fixed PCI domain number to a host bridge, + otherwise an unstable (across boots) unique number will be assigned. + It is required to either not set this property at all or set it for all + host bridges in the system, otherwise potentially conflicting domain numbers + may be assigned to root buses behind different host bridges. The domain + number for each host bridge in the system must be unique. $ref: /schemas/types.yaml#/definitions/uint32 max-link-speed: + description: + If present this property specifies PCI generation number for link + capability. Host drivers could add this as a strategy to avoid + unnecessary operation for unsupported link speed, for instance, trying to + do training for unsupported link speed, etc. $ref: /schemas/types.yaml#/definitions/uint32 enum: [ 1, 2, 3, 4 ] @@ -145,6 +184,11 @@ properties: maxItems: 1 supports-clkreq: + description: + If present this property specifies that CLKREQ signal routing exists from + root port to downstream device and host bridge drivers can do programming + which depends on CLKREQ signal existence. For example, programming root port + not to advertise ASPM L1 Sub-States support if there is no CLKREQ signal. type: boolean aspm-no-l0s: From 042514cd138014683559dcff4006b2362ac3398f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 11 Apr 2023 15:05:09 -0500 Subject: [PATCH 353/505] Revert "schemas: Temporarily disable cache schema" This reverts commit 4489555b11d904c0f10ba774b153d7b89d853315. The necessary fixes for new warnings are now upstream. Signed-off-by: Rob Herring --- dtschema/schemas/cache.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dtschema/schemas/cache.yaml b/dtschema/schemas/cache.yaml index acbc3b50..619ceb1e 100644 --- a/dtschema/schemas/cache.yaml +++ b/dtschema/schemas/cache.yaml @@ -15,8 +15,13 @@ description: Generic cache binding for caches nodes which only have common cache maintainers: - Rob Herring -# Disable until warnings fixed -select: false +select: + properties: + compatible: + const: cache + + required: + - compatible allOf: - $ref: cache-controller.yaml# From f4456f0318242600f01348ac7396c59e4e22b868 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 11 Apr 2023 15:00:12 -0500 Subject: [PATCH 354/505] dtschema: Relax meta-schema checks on referenced schemas There's no need to pass the dtschema meta-schema checks on referenced schemas. They should already be checked on their own with the dtschema meta-schema. This will prevent new meta-schema checks from dropping referenced schemas. Signed-off-by: Rob Herring --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 3ba46a58..cb364a20 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1110,7 +1110,7 @@ def http_handler(uri): raise RefResolutionError('Unable to find schema file matching $id: ' + uri) try: - DTValidator.check_schema(schema) + DTValidator.check_schema(schema, strict=False) except Exception as exc: raise RefResolutionError('Error in referenced schema matching $id: ' + uri) From 7bdec7b91e72ffda4303c36e6701cf77c4070fb6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 18 Nov 2022 13:00:47 -0600 Subject: [PATCH 355/505] meta-schemas: Improve non-patterns in patternProperties check Also ensure that patterns have some form of regex characters in them. This catches cases like 'foo' which is really the same as '^.*foo.*$'. Just a plain string is ambiguous as to what the intention was, so let's require it to be explicit. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index bfc7d86b..1cdede49 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -169,6 +169,7 @@ properties: propertyNames: allOf: - description: Fixed strings belong in 'properties', not 'patternProperties' + pattern: '[\^$()*@]' not: pattern: '^\^[a-zA-Z0-9,\-._#]+\$$' - description: A json-schema keyword was found instead of a DT property name. From 188cca9ae852edf1f21906c6a2912d52dd90144b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 11 Apr 2023 17:21:49 -0500 Subject: [PATCH 356/505] Limit jsonschema version to less than 4.18 The current alpha for jsonschema 4.18 breaks our custom reference resolution. The API is going to be deprecated as well. Limit the version until we know jsonschema is fixed or dtschema is updated. From now on, pin the max version because this wouldn't be the first time a minor version broke us. :( Signed-off-by: Rob Herring --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 62db8afc..70419838 100755 --- a/setup.py +++ b/setup.py @@ -50,7 +50,7 @@ install_requires=[ 'ruamel.yaml>0.15.69', - 'jsonschema>=4.1.2', + 'jsonschema >=4.1.2, <4.18', 'rfc3987', 'pylibfdt', ], From 41e119297110dc0b8afe4f912ccc49b958ff595a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Apr 2023 09:14:23 -0500 Subject: [PATCH 357/505] dtb: Drop unused pprint import Signed-off-by: Rob Herring --- dtschema/dtb.py | 1 - 1 file changed, 1 deletion(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 3aa28100..baaae0da 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -4,7 +4,6 @@ import sys import struct -import pprint import libfdt from libfdt import QUIET_NOTFOUND From 9e4dd3b9f515dd1bbba416d0cd1f1f7eb01d7d59 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 13 Apr 2023 11:15:09 -0500 Subject: [PATCH 358/505] dtschema: Drop unnecessary quote checking Drop the unnecessary quotes checking as yamllint can do the same thing and is much more flexible. Signed-off-by: Rob Herring --- dtschema/lib.py | 40 ---------------------------------------- tools/dt-doc-validate | 1 - 2 files changed, 41 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index cb364a20..83328735 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1264,46 +1264,6 @@ def check_schema_refs(self, filename, schema): check_id_path(filename, schema['$id']) - @classmethod - def _check_str(self, err_msg, schema, key, v): - if not (isinstance(v, ruamel.yaml.scalarstring.SingleQuotedScalarString) or - isinstance(v, ruamel.yaml.scalarstring.DoubleQuotedScalarString)): - return - - # Only checking const and list values - if key and key != 'const': - return - - if v[0] in '#/"': - return - - # Flow style with ',' needs quoting - if schema.fa.flow_style() and ',' in v: - return - - if isinstance(schema, ruamel.yaml.comments.CommentedBase): - if isinstance(schema, dict): - line = schema.lc.key(key)[0] - else: - line = schema.lc.line - line += 1 - else: - line = None - - print(err_msg + str(line) + ": quotes are not necessary: " + v, file=sys.stderr) - - @classmethod - def check_quotes(self, err_msg, schema): - if isinstance(schema, dict): - for k, v in schema.items(): - self._check_str(err_msg, schema, k, v) - self.check_quotes(err_msg, v) - - if isinstance(schema, list): - for s in schema: - self._check_str(err_msg, schema, None, s) - self.check_quotes(err_msg, s) - def format_error(filename, error, prefix="", nodename=None, verbose=False): src = prefix + os.path.abspath(filename) + ':' diff --git a/tools/dt-doc-validate b/tools/dt-doc-validate index 657ea810..3c5a607b 100755 --- a/tools/dt-doc-validate +++ b/tools/dt-doc-validate @@ -33,7 +33,6 @@ def check_doc(filename): ret = 1 dtschema.DTValidator.check_schema_refs(filename, testtree) - dtschema.DTValidator.check_quotes(filename + ":", testtree) return ret From 31cc52ae483ed2bd35452acfcf31e6ce114be27a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 13 Apr 2023 21:14:16 -0500 Subject: [PATCH 359/505] dtschema: Move fixups to separate file lib.py is getting pretty long, so start splitting it into separate files starting with all the schema fixup processing. Signed-off-by: Rob Herring --- dtschema/__init__.py | 5 + dtschema/fixups.py | 484 +++++++++++++++++++++++++++++++++++++++++++ dtschema/lib.py | 475 +----------------------------------------- 3 files changed, 490 insertions(+), 474 deletions(-) create mode 100644 dtschema/fixups.py diff --git a/dtschema/__init__.py b/dtschema/__init__.py index 28751f71..28523c3b 100644 --- a/dtschema/__init__.py +++ b/dtschema/__init__.py @@ -6,6 +6,7 @@ DTValidator, format_error, extract_compatibles, + extract_node_compatibles, extract_types, get_undocumented_compatibles, property_get_type, @@ -14,6 +15,10 @@ sized_int, ) +from dtschema.fixups import ( + fixup_schema, +) + from dtschema.version import ( __version__ ) diff --git a/dtschema/fixups.py b/dtschema/fixups.py new file mode 100644 index 00000000..81dc64b8 --- /dev/null +++ b/dtschema/fixups.py @@ -0,0 +1,484 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2018 Linaro Ltd. +# Copyright 2018-2023 Arm Ltd. +# Python library for Devicetree schema validation +import re +import copy + +import dtschema +from dtschema.lib import _get_array_range +from dtschema.lib import _is_int_schema +from dtschema.lib import _is_string_schema + + +def _extract_single_schemas(subschema): + scalar_keywords = ('const', 'enum', 'pattern', 'minimum', 'maximum') + return {k: subschema.pop(k) for k in scalar_keywords if k in subschema} + + +def _fixup_string_to_array(propname, subschema): + # nothing to do if we don't have a set of string schema + if not _is_string_schema(subschema): + return + + subschema['items'] = [_extract_single_schemas(subschema)] + + +def _fixup_reg_schema(propname, subschema): + # nothing to do if we don't have a set of string schema + if propname != 'reg': + return + + if 'items' in subschema: + if isinstance(subschema['items'], list): + item_schema = subschema['items'][0] + else: + item_schema = subschema['items'] + if not _is_int_schema(item_schema): + return + elif _is_int_schema(subschema): + item_schema = subschema + else: + return + + subschema['items'] = [ {'items': [ _extract_single_schemas(item_schema) ] } ] + + +def _is_matrix_schema(subschema): + if 'items' not in subschema: + return False + + if isinstance(subschema['items'], list): + for l in subschema['items']: + if l.keys() & {'items', 'maxItems', 'minItems'}: + return True + elif subschema['items'].keys() & {'items', 'maxItems', 'minItems'}: + return True + + return False + + +# If we have a matrix with variable inner and outer dimensions, then drop the dimensions +# because we have no way to reconstruct them. +def _fixup_int_matrix(propname, subschema): + if not _is_matrix_schema(subschema): + return + + outer_dim = _get_array_range(subschema) + inner_dim = _get_array_range(subschema.get('items', {})) + + if outer_dim[0] != outer_dim[1] and inner_dim[0] != inner_dim[1]: + subschema.pop('items', None) + subschema.pop('maxItems', None) + subschema.pop('minItems', None) + subschema['type'] = 'array' + + +int_array_re = re.compile('int(8|16|32|64)-array') +unit_types_re = re.compile('-(kBps|bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|microvolt|picofarads|(milli)?celsius|kelvin|kpascal)$') + +# Remove this once we remove array to matrix fixups +known_array_props = { + 'assigned-clock-rates', + 'linux,keycodes', + 'max8997,pmic-buck1-dvs-voltage', + 'max8997,pmic-buck2-dvs-voltage', + 'max8997,pmic-buck5-dvs-voltage', +} + + +def is_int_array_schema(propname, subschema): + if 'allOf' in subschema: + # Find 'items'. It may be under the 'allOf' or at the same level + for item in subschema['allOf']: + if 'items' in item: + subschema = item + continue + if '$ref' in item: + return int_array_re.search(item['$ref']) + if '$ref' in subschema: + return int_array_re.search(subschema['$ref']) + elif unit_types_re.search(propname) or propname in known_array_props: + return True + + return 'items' in subschema and \ + ((isinstance(subschema['items'], list) and _is_int_schema(subschema['items'][0])) or + (isinstance(subschema['items'], dict) and _is_int_schema(subschema['items']))) + + +# Fixup an int array that only defines the number of items. +# In this case, we allow either form [[ 0, 1, 2]] or [[0], [1], [2]] +def _fixup_int_array_min_max_to_matrix(propname, subschema): + if not is_int_array_schema(propname, subschema): + return + + if 'allOf' in subschema: + # Find 'min/maxItems'. It may be under the 'allOf' or at the same level + for item in subschema['allOf']: + if item.keys() & {'minItems', 'maxItems'}: + subschema = item + break + + if 'items' in subschema and isinstance(subschema['items'], list): + return + + if _is_matrix_schema(subschema): + return + + if subschema.get('maxItems') == 1: + return + + tmpsch = {} + if 'minItems' in subschema: + tmpsch['minItems'] = subschema.pop('minItems') + if 'maxItems' in subschema: + tmpsch['maxItems'] = subschema.pop('maxItems') + + if tmpsch: + subschema['oneOf'] = [copy.deepcopy(tmpsch), {'items': [copy.deepcopy(tmpsch)]}] + subschema['oneOf'][0].update({'items': {'maxItems': 1}}) + + # if minItems can be 1, then both oneOf clauses can be true so increment + # minItems in one clause to prevent that. + if subschema['oneOf'][0].get('minItems') == 1: + subschema['oneOf'][0]['minItems'] += 1 + + # Since we added an 'oneOf' the tree walking code won't find it and we need to do fixups + _fixup_items_size(subschema['oneOf']) + + +def _fixup_remove_empty_items(subschema): + if 'items' not in subschema: + return + elif isinstance(subschema['items'], dict): + _fixup_remove_empty_items(subschema['items']) + return + + for item in subschema['items']: + item.pop('description', None) + _fixup_remove_empty_items(item) + if item != {}: + break + else: + subschema.setdefault('type', 'array') + subschema.setdefault('maxItems', len(subschema['items'])) + subschema.setdefault('minItems', len(subschema['items'])) + del subschema['items'] + + +def _fixup_int_array_items_to_matrix(propname, subschema): + itemkeys = ('items', 'minItems', 'maxItems', 'uniqueItems', 'default') + if not is_int_array_schema(propname, subschema): + return + + if 'allOf' in subschema: + # Find 'items'. It may be under the 'allOf' or at the same level + for item in subschema['allOf']: + if 'items' in item: + subschema = item + break + + if 'items' not in subschema or _is_matrix_schema(subschema): + return + + if isinstance(subschema['items'], dict): + subschema['items'] = {k: subschema.pop(k) for k in itemkeys if k in subschema} + + if isinstance(subschema['items'], list): + subschema['items'] = [{k: subschema.pop(k) for k in itemkeys if k in subschema}] + + +def _fixup_scalar_to_array(propname, subschema): + if not _is_int_schema(subschema): + return + + subschema['items'] = [{'items': [_extract_single_schemas(subschema)]}] + + +def _fixup_items_size(schema): + # Make items list fixed size-spec + if isinstance(schema, list): + for l in schema: + _fixup_items_size(l) + elif isinstance(schema, dict): + schema.pop('description', None) + if 'items' in schema: + schema['type'] = 'array' + + if isinstance(schema['items'], list): + c = len(schema['items']) + if 'minItems' not in schema: + schema['minItems'] = c + if 'maxItems' not in schema: + schema['maxItems'] = c + + _fixup_items_size(schema['items']) + + elif 'maxItems' in schema and 'minItems' not in schema: + schema['minItems'] = schema['maxItems'] + elif 'minItems' in schema and 'maxItems' not in schema: + schema['maxItems'] = schema['minItems'] + + +def fixup_schema_to_201909(schema): + if not isinstance(schema, dict): + return + + # dependencies is now split into dependentRequired and dependentSchema + try: + val = schema.pop('dependencies') + for k, v in val.items(): + if isinstance(v, list): + schema.setdefault('dependentRequired', {}) + schema['dependentRequired'][k] = v + else: + schema.setdefault('dependentSchemas', {}) + schema['dependentSchemas'][k] = v + except: + pass + + +def fixup_schema_to_202012(schema): + if not isinstance(schema, dict): + return + + fixup_schema_to_201909(schema) + + try: + if isinstance(schema['items'], list): + schema['prefixItems'] = schema.pop('items') + for i in schema['prefixItems']: + fixup_schema_to_202012(i) + if isinstance(schema['items'], dict): + fixup_schema_to_202012(schema['items']) + except: + pass + + try: + val = schema.pop('additionalItems') + schema['unevaluatedItems'] = val + except: + pass + + +def fixup_vals(propname, schema): + # Now we should be a the schema level to do actual fixups + #print(schema) + + schema.pop('description', None) + + _fixup_reg_schema(propname, schema) + _fixup_remove_empty_items(schema) + _fixup_int_matrix(propname, schema) + _fixup_int_array_min_max_to_matrix(propname, schema) + _fixup_int_array_items_to_matrix(propname, schema) + _fixup_string_to_array(propname, schema) + _fixup_scalar_to_array(propname, schema) + _fixup_items_size(schema) + + fixup_schema_to_201909(schema) + + +def walk_properties(propname, schema): + if not isinstance(schema, dict): + return + # Recurse until we don't hit a conditional + # Note we expect to encounter conditionals first. + # For example, a conditional below 'items' is not supported + for cond in ['allOf', 'oneOf', 'anyOf']: + if cond in schema.keys(): + for l in schema[cond]: + walk_properties(propname, l) + + if 'then' in schema.keys(): + walk_properties(propname, schema['then']) + + fixup_vals(propname, schema) + + +def fixup_interrupts(schema): + # Supporting 'interrupts' implies 'interrupts-extended' is also supported. + if 'properties' not in schema: + return + + # Any node with 'interrupts' can have 'interrupt-parent' + if schema['properties'].keys() & {'interrupts', 'interrupt-controller'} and \ + 'interrupt-parent' not in schema['properties']: + schema['properties']['interrupt-parent'] = True + + if 'interrupts' not in schema['properties'] or 'interrupts-extended' in schema['properties']: + return + + schema['properties']['interrupts-extended'] = copy.deepcopy(schema['properties']['interrupts']) + + if not ('required' in schema and 'interrupts' in schema['required']): + return + + # Currently no better way to express either 'interrupts' or 'interrupts-extended' + # is required. If this fails validation, the error reporting is the whole + # schema file fails validation + reqlist = [{'required': ['interrupts']}, {'required': ['interrupts-extended']}] + if 'oneOf' in schema: + if 'allOf' not in schema: + schema['allOf'] = [] + schema['allOf'].append({'oneOf': reqlist}) + else: + schema['oneOf'] = reqlist + schema['required'].remove('interrupts') + + +known_variable_matrix_props = { + 'fsl,pins', + 'qcom,board-id' +} + + +def fixup_sub_schema(schema, is_prop): + if not isinstance(schema, dict): + return + + schema.pop('description', None) + fixup_interrupts(schema) + if is_prop: + fixup_node_props(schema) + + # 'additionalProperties: true' doesn't work with 'unevaluatedProperties', so + # remove it. It's in the schemas for common (incomplete) schemas. + if 'additionalProperties' in schema and schema['additionalProperties'] == True: + schema.pop('additionalProperties', None) + + for k, v in schema.items(): + if k in ['select', 'if', 'then', 'else', 'additionalProperties', 'not']: + fixup_sub_schema(v, False) + + if k in ['allOf', 'anyOf', 'oneOf']: + for subschema in v: + fixup_sub_schema(subschema, True) + + if k not in ['dependentRequired', 'dependentSchemas', 'dependencies', 'properties', 'patternProperties', '$defs']: + continue + + for prop in v: + if prop in known_variable_matrix_props and isinstance(v[prop], dict): + ref = v[prop].pop('$ref', None) + schema[k][prop] = {} + if ref: + schema[k][prop]['$ref'] = ref + continue + + walk_properties(prop, v[prop]) + # Recurse to check for {properties,patternProperties} in each prop + fixup_sub_schema(v[prop], True) + + fixup_schema_to_201909(schema) + + +def fixup_node_props(schema): + if not {'properties', 'patternProperties', 'unevaluatedProperties', 'additionalProperties'} & schema.keys(): + return + if ('additionalProperties' in schema and schema['additionalProperties'] is True) or \ + ('unevaluatedProperties' in schema and schema['unevaluatedProperties'] is True): + return + + schema.setdefault('properties', dict()) + schema['properties'].setdefault('phandle', True) + schema['properties'].setdefault('status', True) + schema['properties'].setdefault('secure-status', True) + schema['properties'].setdefault('$nodename', True) + schema['properties'].setdefault('bootph-pre-sram', True) + schema['properties'].setdefault('bootph-verify', True) + schema['properties'].setdefault('bootph-pre-ram', True) + schema['properties'].setdefault('bootph-some-ram', True) + schema['properties'].setdefault('bootph-all', True) + + # 'dma-ranges' allowed when 'ranges' is present + if 'ranges' in schema['properties']: + schema['properties'].setdefault('dma-ranges', True) + + keys = list(schema['properties'].keys()) + if 'patternProperties' in schema: + keys.extend(schema['patternProperties']) + + for key in keys: + if re.match(r'^pinctrl-[0-9]', key): + break + else: + schema['properties'].setdefault('pinctrl-names', True) + schema.setdefault('patternProperties', dict()) + schema['patternProperties']['pinctrl-[0-9]+'] = True + + if "clocks" in keys and "assigned-clocks" not in keys: + schema['properties']['assigned-clocks'] = True + schema['properties']['assigned-clock-rates'] = True + schema['properties']['assigned-clock-parents'] = True + + +# Convert to standard types from ruamel's CommentedMap/Seq +def convert_to_dict(schema): + if isinstance(schema, dict): + result = {} + for k, v in schema.items(): + result[k] = convert_to_dict(v) + elif isinstance(schema, list): + result = [] + for item in schema: + result.append(convert_to_dict(item)) + else: + result = schema + + return result + + +def add_select_schema(schema): + '''Get a schema to be used in select tests. + + If the provided schema has a 'select' property, then use that as the select schema. + If it has a compatible property, then create a select schema from that. + If it has a $nodename property, then create a select schema from that. + If it has none of those, then return a match-nothing schema + ''' + if "select" in schema: + return + + if 'properties' not in schema: + schema['select'] = False + return + + if 'compatible' in schema['properties']: + compatible_list = dtschema.extract_node_compatibles(schema['properties']['compatible']) + + if len(compatible_list): + try: + compatible_list.remove('syscon') + except: + pass + try: + compatible_list.remove('simple-mfd') + except: + pass + + if len(compatible_list) != 0: + schema['select'] = { + 'required': ['compatible'], + 'properties': {'compatible': {'contains': {'enum': sorted(compatible_list)}}}} + + return + + if '$nodename' in schema['properties'] and schema['properties']['$nodename'] is not True: + schema['select'] = { + 'required': ['$nodename'], + 'properties': {'$nodename': convert_to_dict(schema['properties']['$nodename'])}} + + return + + schema['select'] = False + + +def fixup_schema(schema): + # Remove parts not necessary for validation + schema.pop('examples', None) + schema.pop('maintainers', None) + schema.pop('historical', None) + + add_select_schema(schema) + fixup_sub_schema(schema, True) diff --git a/dtschema/lib.py b/dtschema/lib.py index 83328735..610da43a 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -8,7 +8,6 @@ import ruamel.yaml import re import pprint -import copy import json import jsonschema @@ -141,386 +140,6 @@ def _is_string_schema(subschema): return False -def _extract_single_schemas(subschema): - return {k: subschema.pop(k) for k in ('const', 'enum', 'pattern', 'minimum', 'maximum') if k in subschema} - - -def _fixup_string_to_array(propname, subschema): - # nothing to do if we don't have a set of string schema - if not _is_string_schema(subschema): - return - - subschema['items'] = [_extract_single_schemas(subschema)] - - -def _fixup_reg_schema(propname, subschema): - # nothing to do if we don't have a set of string schema - if propname != 'reg': - return - - if 'items' in subschema: - if isinstance(subschema['items'], list): - item_schema = subschema['items'][0] - else: - item_schema = subschema['items'] - if not _is_int_schema(item_schema): - return - elif _is_int_schema(subschema): - item_schema = subschema - else: - return - - subschema['items'] = [ {'items': [ _extract_single_schemas(item_schema) ] } ] - - -def _is_matrix_schema(subschema): - if 'items' not in subschema: - return False - - if isinstance(subschema['items'], list): - for l in subschema['items']: - if l.keys() & {'items', 'maxItems', 'minItems'}: - return True - elif subschema['items'].keys() & {'items', 'maxItems', 'minItems'}: - return True - - return False - - -# If we have a matrix with variable inner and outer dimensions, then drop the dimensions -# because we have no way to reconstruct them. -def _fixup_int_matrix(propname, subschema): - if not _is_matrix_schema(subschema): - return - - outer_dim = _get_array_range(subschema) - inner_dim = _get_array_range(subschema.get('items', {})) - - if outer_dim[0] != outer_dim[1] and inner_dim[0] != inner_dim[1]: - subschema.pop('items', None) - subschema.pop('maxItems', None) - subschema.pop('minItems', None) - subschema['type'] = 'array' - - -int_array_re = re.compile('int(8|16|32|64)-array') -unit_types_re = re.compile('-(kBps|bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|microvolt|picofarads|(milli)?celsius|kelvin|kpascal)$') - -# Remove this once we remove array to matrix fixups -known_array_props = { - 'assigned-clock-rates', - 'linux,keycodes', - 'max8997,pmic-buck1-dvs-voltage', - 'max8997,pmic-buck2-dvs-voltage', - 'max8997,pmic-buck5-dvs-voltage', -} - - -def is_int_array_schema(propname, subschema): - if 'allOf' in subschema: - # Find 'items'. It may be under the 'allOf' or at the same level - for item in subschema['allOf']: - if 'items' in item: - subschema = item - continue - if '$ref' in item: - return int_array_re.search(item['$ref']) - if '$ref' in subschema: - return int_array_re.search(subschema['$ref']) - elif unit_types_re.search(propname) or propname in known_array_props: - return True - - return 'items' in subschema and \ - ((isinstance(subschema['items'], list) and _is_int_schema(subschema['items'][0])) or - (isinstance(subschema['items'], dict) and _is_int_schema(subschema['items']))) - - -# Fixup an int array that only defines the number of items. -# In this case, we allow either form [[ 0, 1, 2]] or [[0], [1], [2]] -def _fixup_int_array_min_max_to_matrix(propname, subschema): - if not is_int_array_schema(propname, subschema): - return - - if 'allOf' in subschema: - # Find 'min/maxItems'. It may be under the 'allOf' or at the same level - for item in subschema['allOf']: - if item.keys() & {'minItems', 'maxItems'}: - subschema = item - break - - if 'items' in subschema and isinstance(subschema['items'], list): - return - - if _is_matrix_schema(subschema): - return - - if subschema.get('maxItems') == 1: - return - - tmpsch = {} - if 'minItems' in subschema: - tmpsch['minItems'] = subschema.pop('minItems') - if 'maxItems' in subschema: - tmpsch['maxItems'] = subschema.pop('maxItems') - - if tmpsch: - subschema['oneOf'] = [copy.deepcopy(tmpsch), {'items': [copy.deepcopy(tmpsch)]}] - subschema['oneOf'][0].update({'items': {'maxItems': 1}}) - - # if minItems can be 1, then both oneOf clauses can be true so increment - # minItems in one clause to prevent that. - if subschema['oneOf'][0].get('minItems') == 1: - subschema['oneOf'][0]['minItems'] += 1 - - # Since we added an 'oneOf' the tree walking code won't find it and we need to do fixups - _fixup_items_size(subschema['oneOf']) - - -def _fixup_remove_empty_items(subschema): - if 'items' not in subschema: - return - elif isinstance(subschema['items'], dict): - _fixup_remove_empty_items(subschema['items']) - return - - for item in subschema['items']: - item.pop('description', None) - _fixup_remove_empty_items(item) - if item != {}: - break - else: - subschema.setdefault('type', 'array') - subschema.setdefault('maxItems', len(subschema['items'])) - subschema.setdefault('minItems', len(subschema['items'])) - del subschema['items'] - - -def _fixup_int_array_items_to_matrix(propname, subschema): - itemkeys = ('items', 'minItems', 'maxItems', 'uniqueItems', 'default') - if not is_int_array_schema(propname, subschema): - return - - if 'allOf' in subschema: - # Find 'items'. It may be under the 'allOf' or at the same level - for item in subschema['allOf']: - if 'items' in item: - subschema = item - break - - if 'items' not in subschema or _is_matrix_schema(subschema): - return - - if isinstance(subschema['items'], dict): - subschema['items'] = {k: subschema.pop(k) for k in itemkeys if k in subschema} - - if isinstance(subschema['items'], list): - subschema['items'] = [{k: subschema.pop(k) for k in itemkeys if k in subschema}] - - -def _fixup_scalar_to_array(propname, subschema): - if not _is_int_schema(subschema): - return - - subschema['items'] = [{'items': [_extract_single_schemas(subschema)]}] - - -def _fixup_items_size(schema): - # Make items list fixed size-spec - if isinstance(schema, list): - for l in schema: - _fixup_items_size(l) - elif isinstance(schema, dict): - schema.pop('description', None) - if 'items' in schema: - schema['type'] = 'array' - - if isinstance(schema['items'], list): - c = len(schema['items']) - if 'minItems' not in schema: - schema['minItems'] = c - if 'maxItems' not in schema: - schema['maxItems'] = c - - _fixup_items_size(schema['items']) - - elif 'maxItems' in schema and 'minItems' not in schema: - schema['minItems'] = schema['maxItems'] - elif 'minItems' in schema and 'maxItems' not in schema: - schema['maxItems'] = schema['minItems'] - - -def fixup_schema_to_201909(schema): - if not isinstance(schema, dict): - return - - # dependencies is now split into dependentRequired and dependentSchema - try: - val = schema.pop('dependencies') - for k, v in val.items(): - if isinstance(v, list): - schema.setdefault('dependentRequired', {}) - schema['dependentRequired'][k] = v - else: - schema.setdefault('dependentSchemas', {}) - schema['dependentSchemas'][k] = v - except: - pass - - -def fixup_schema_to_202012(schema): - if not isinstance(schema, dict): - return - - fixup_schema_to_201909(schema) - - try: - if isinstance(schema['items'], list): - schema['prefixItems'] = schema.pop('items') - for i in schema['prefixItems']: - fixup_schema_to_202012(i) - if isinstance(schema['items'], dict): - fixup_schema_to_202012(schema['items']) - except: - pass - - try: - val = schema.pop('additionalItems') - schema['unevaluatedItems'] = val - except: - pass - - -def fixup_vals(propname, schema): - # Now we should be a the schema level to do actual fixups - #print(schema) - - schema.pop('description', None) - - _fixup_reg_schema(propname, schema) - _fixup_remove_empty_items(schema) - _fixup_int_matrix(propname, schema) - _fixup_int_array_min_max_to_matrix(propname, schema) - _fixup_int_array_items_to_matrix(propname, schema) - _fixup_string_to_array(propname, schema) - _fixup_scalar_to_array(propname, schema) - _fixup_items_size(schema) - - fixup_schema_to_201909(schema) - - -def walk_properties(propname, schema): - if not isinstance(schema, dict): - return - # Recurse until we don't hit a conditional - # Note we expect to encounter conditionals first. - # For example, a conditional below 'items' is not supported - for cond in ['allOf', 'oneOf', 'anyOf']: - if cond in schema.keys(): - for l in schema[cond]: - walk_properties(propname, l) - - if 'then' in schema.keys(): - walk_properties(propname, schema['then']) - - fixup_vals(propname, schema) - - -def fixup_schema(schema): - # Remove parts not necessary for validation - schema.pop('examples', None) - schema.pop('maintainers', None) - schema.pop('historical', None) - - add_select_schema(schema) - fixup_sub_schema(schema, True) - - -known_variable_matrix_props = { - 'fsl,pins', - 'qcom,board-id' -} - - -def fixup_sub_schema(schema, is_prop): - if not isinstance(schema, dict): - return - - schema.pop('description', None) - fixup_interrupts(schema) - if is_prop: - fixup_node_props(schema) - - # 'additionalProperties: true' doesn't work with 'unevaluatedProperties', so - # remove it. It's in the schemas for common (incomplete) schemas. - if 'additionalProperties' in schema and schema['additionalProperties'] == True: - schema.pop('additionalProperties', None) - - for k, v in schema.items(): - if k in ['select', 'if', 'then', 'else', 'additionalProperties', 'not']: - fixup_sub_schema(v, False) - - if k in ['allOf', 'anyOf', 'oneOf']: - for subschema in v: - fixup_sub_schema(subschema, True) - - if k not in ['dependentRequired', 'dependentSchemas', 'dependencies', 'properties', 'patternProperties', '$defs']: - continue - - for prop in v: - if prop in known_variable_matrix_props and isinstance(v[prop], dict): - ref = v[prop].pop('$ref', None) - schema[k][prop] = {} - if ref: - schema[k][prop]['$ref'] = ref - continue - - walk_properties(prop, v[prop]) - # Recurse to check for {properties,patternProperties} in each prop - fixup_sub_schema(v[prop], True) - - fixup_schema_to_201909(schema) - - -def fixup_node_props(schema): - if not {'properties', 'patternProperties', 'unevaluatedProperties', 'additionalProperties'} & schema.keys(): - return - if ('additionalProperties' in schema and schema['additionalProperties'] is True) or \ - ('unevaluatedProperties' in schema and schema['unevaluatedProperties'] is True): - return - - schema.setdefault('properties', dict()) - schema['properties'].setdefault('phandle', True) - schema['properties'].setdefault('status', True) - schema['properties'].setdefault('secure-status', True) - schema['properties'].setdefault('$nodename', True) - schema['properties'].setdefault('bootph-pre-sram', True) - schema['properties'].setdefault('bootph-verify', True) - schema['properties'].setdefault('bootph-pre-ram', True) - schema['properties'].setdefault('bootph-some-ram', True) - schema['properties'].setdefault('bootph-all', True) - - # 'dma-ranges' allowed when 'ranges' is present - if 'ranges' in schema['properties']: - schema['properties'].setdefault('dma-ranges', True) - - keys = list(schema['properties'].keys()) - if 'patternProperties' in schema: - keys.extend(schema['patternProperties']) - - for key in keys: - if re.match(r'^pinctrl-[0-9]', key): - break - else: - schema['properties'].setdefault('pinctrl-names', True) - schema.setdefault('patternProperties', dict()) - schema['patternProperties']['pinctrl-[0-9]+'] = True - - if "clocks" in keys and "assigned-clocks" not in keys: - schema['properties']['assigned-clocks'] = True - schema['properties']['assigned-clock-rates'] = True - schema['properties']['assigned-clock-parents'] = True - - def extract_node_compatibles(schema): if not isinstance(schema, dict): return set() @@ -565,98 +184,6 @@ def item_generator(json_input, lookup_key): yield item_val -# Convert to standard types from ruamel's CommentedMap/Seq -def convert_to_dict(schema): - if isinstance(schema, dict): - result = {} - for k, v in schema.items(): - result[k] = convert_to_dict(v) - elif isinstance(schema, list): - result = [] - for item in schema: - result.append(convert_to_dict(item)) - else: - result = schema - - return result - - -def add_select_schema(schema): - '''Get a schema to be used in select tests. - - If the provided schema has a 'select' property, then use that as the select schema. - If it has a compatible property, then create a select schema from that. - If it has a $nodename property, then create a select schema from that. - If it has none of those, then return a match-nothing schema - ''' - if "select" in schema: - return - - if 'properties' not in schema: - schema['select'] = False - return - - if 'compatible' in schema['properties']: - compatible_list = extract_node_compatibles(schema['properties']['compatible']) - - if len(compatible_list): - try: - compatible_list.remove('syscon') - except: - pass - try: - compatible_list.remove('simple-mfd') - except: - pass - - if len(compatible_list) != 0: - schema['select'] = { - 'required': ['compatible'], - 'properties': {'compatible': {'contains': {'enum': sorted(compatible_list)}}}} - - return - - if '$nodename' in schema['properties'] and schema['properties']['$nodename'] is not True: - schema['select'] = { - 'required': ['$nodename'], - 'properties': {'$nodename': convert_to_dict(schema['properties']['$nodename'])}} - - return - - schema['select'] = False - - -def fixup_interrupts(schema): - # Supporting 'interrupts' implies 'interrupts-extended' is also supported. - if 'properties' not in schema: - return - - # Any node with 'interrupts' can have 'interrupt-parent' - if schema['properties'].keys() & {'interrupts', 'interrupt-controller'} and \ - 'interrupt-parent' not in schema['properties']: - schema['properties']['interrupt-parent'] = True - - if 'interrupts' not in schema['properties'] or 'interrupts-extended' in schema['properties']: - return - - schema['properties']['interrupts-extended'] = copy.deepcopy(schema['properties']['interrupts']) - - if not ('required' in schema and 'interrupts' in schema['required']): - return - - # Currently no better way to express either 'interrupts' or 'interrupts-extended' - # is required. If this fails validation, the error reporting is the whole - # schema file fails validation - reqlist = [{'required': ['interrupts']}, {'required': ['interrupts-extended']}] - if 'oneOf' in schema: - if 'allOf' not in schema: - schema['allOf'] = [] - schema['allOf'].append({'oneOf': reqlist}) - else: - schema['oneOf'] = reqlist - schema['required'].remove('interrupts') - - def make_compatible_schema(schemas): compat_sch = [{'enum': []}] compatible_list = set() @@ -1236,7 +763,7 @@ def check_schema(cls, schema, strict=True): val = cls.DTVal(meta_schema, resolver=cls.resolver) for error in val.iter_errors(schema): raise jsonschema.SchemaError.create_from(error) - fixup_schema(schema) + dtschema.fixup_schema(schema) @classmethod def _check_schema_refs(self, schema): From 85e967f655a98fa24e1616ad643cd9b747c3267c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 7 May 2023 19:12:19 +0200 Subject: [PATCH 360/505] schemas: iio: add label Linux IIO core code parses label property which is already used in several IIO devices. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230507171219.232216-1-krzk@kernel.org Signed-off-by: Rob Herring --- dtschema/schemas/iio/iio.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dtschema/schemas/iio/iio.yaml b/dtschema/schemas/iio/iio.yaml index 5ce5e147..727ca0f9 100644 --- a/dtschema/schemas/iio/iio.yaml +++ b/dtschema/schemas/iio/iio.yaml @@ -30,6 +30,10 @@ properties: with a single IIO output and 1 for nodes with multiple IIO outputs. A few unusual devices have a 2 level mapping. + label: + description: + Unique name to identify which IIO channel or device this is. + mount-matrix: $ref: /schemas/types.yaml#/definitions/non-unique-string-array minItems: 9 From 3db9af12df884c6049391e2249f4adb5bc2650a1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Apr 2023 16:33:14 -0500 Subject: [PATCH 361/505] meta-schemas: add $defs schema checking '$defs' should be structured just like 'properties' with names that don't match json-schema vocabulary and underneath the names should be a schema. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 1cdede49..00e84355 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -103,6 +103,15 @@ dependentRequired: - then properties: + $defs: + propertyNames: + description: A json-schema keyword was found in $defs key. + not: + $ref: "#/definitions/json-schema-prop-names" + additionalProperties: + description: $defs entries must contain schemas + type: object + $ref: "#/definitions/sub-schemas" $ref: description: References must start with '/schemas' or be relative to current From 4ddf315e38287f680b0d028b842a269de1481279 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 24 Apr 2023 18:07:47 -0500 Subject: [PATCH 362/505] meta-schemas: Ensure DT property names contain either an object or boolean There's a case of a DT property being an array rather than a schema or boolean. Add a check to prevent that. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 00e84355..959c605a 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -195,6 +195,7 @@ properties: not: $ref: "#/definitions/json-schema-prop-names" additionalProperties: + type: [ object, boolean ] $ref: "#/definitions/sub-schemas" required: description: "'required' must be valid DT property or node names" From bc164f9dc87e38a7571c1a4f22bed9c17b219ce0 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 13 May 2022 09:08:19 -0500 Subject: [PATCH 363/505] Split DTValidator class into 2 classes The DTValidator class was originally patterned after jsonschema's Validator class. That has proven to be problematic as later deemed non-public APIs were used and then changed. Furthermore as dtschema has evolved, the checking of schemas and devicetrees have diverged. Primarily, the DT validation requires preprocessing schemas and having all the schemas up front to have type information for DTB decoding. To better match the uses, split out the schema validation into a separate DTSchema class and the DTValidator class becomes the class for validating DTs. As lib.py has grown pretty long, both classes are moved to their own files. This serves as prep work to move from jsonschema's soon to be deprecated RefResolver to referencing library. It's a big diff, but not easy or really worth trying to do it in small steps. Signed-off-by: Rob Herring --- dtschema/__init__.py | 23 +- dtschema/dtb.py | 36 +- dtschema/lib.py | 688 +------------------------------------- dtschema/schema.py | 193 +++++++++++ dtschema/validator.py | 475 ++++++++++++++++++++++++++ test/test-dt-validate.py | 83 ++--- tools/dt-check-compatible | 4 +- tools/dt-doc-validate | 18 +- tools/dt-extract-props | 4 +- tools/dt-mk-schema | 2 +- tools/dt-validate | 111 +++--- tools/dtb2py | 4 +- 12 files changed, 795 insertions(+), 846 deletions(-) create mode 100644 dtschema/schema.py create mode 100644 dtschema/validator.py diff --git a/dtschema/__init__.py b/dtschema/__init__.py index 28523c3b..9cf58336 100644 --- a/dtschema/__init__.py +++ b/dtschema/__init__.py @@ -1,17 +1,10 @@ from dtschema.lib import ( - add_schema_path, - load_schema, - load, - set_schemas, - DTValidator, format_error, extract_compatibles, extract_node_compatibles, - extract_types, - get_undocumented_compatibles, - property_get_type, - property_get_type_dim, - property_has_fixed_dimensions, + _is_int_schema, + _is_string_schema, + _get_array_range, sized_int, ) @@ -19,6 +12,16 @@ fixup_schema, ) +from dtschema.schema import ( + DTSchema, +) + +from dtschema.validator import ( + DTValidator, +) + from dtschema.version import ( __version__ ) + +import dtschema.dtb diff --git a/dtschema/dtb.py b/dtschema/dtb.py index baaae0da..2eb97233 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -66,7 +66,7 @@ def get_stride(len, dim): return 0 -def prop_value(nodename, p): +def prop_value(validator, nodename, p): # First, check for a boolean type if not len(p): return True @@ -78,7 +78,7 @@ def prop_value(nodename, p): if nodename in {'__fixups__', 'aliases'}: return data[:-1].decode(encoding='ascii').split('\0') - prop_types = set(dtschema.property_get_type(p.name)) + prop_types = set(validator.property_get_type(p.name)) prop_types -= {'node'} # Filter out types impossible for the size of the property @@ -162,7 +162,7 @@ def prop_value(nodename, p): val_int += [dtschema.sized_int(i[0], size=(type_struct.size * 8))] if 'matrix' in fmt or 'phandle-array' in fmt: - dim = dtschema.property_get_type_dim(p.name) + dim = validator.property_get_type_dim(p.name) if dim: if max(dim[1]) and dim[1][0] == dim[1][1]: stride = dim[1][1] @@ -184,12 +184,12 @@ def prop_value(nodename, p): return [val_int] -def node_props(fdt, nodename, offset): +def node_props(validator, fdt, nodename, offset): props_dict = {} poffset = fdt.first_property_offset(offset, QUIET_NOTFOUND) while poffset >= 0: p = fdt.get_property_by_offset(poffset) - props_dict[p.name] = prop_value(nodename, p) + props_dict[p.name] = prop_value(validator, nodename, p) poffset = fdt.next_property_offset(poffset, QUIET_NOTFOUND) @@ -200,10 +200,10 @@ def node_props(fdt, nodename, offset): phandle_loc = [] -def process_fixups(fdt, nodename, offset): +def process_fixups(validator, fdt, nodename, offset): if nodename != '__fixups__': return - props = node_props(fdt, nodename, offset) + props = node_props(validator, fdt, nodename, offset) global phandle_loc phandle_loc += [s for l in props.values() for s in l] @@ -231,9 +231,9 @@ def process_local_fixups(fdt, nodename, path, offset): offset = fdt.next_subnode(offset, QUIET_NOTFOUND) -def fdt_scan_node(fdt, nodename, offset): +def fdt_scan_node(validator, fdt, nodename, offset): if nodename == '__fixups__': - process_fixups(fdt, nodename, offset) + process_fixups(validator, fdt, nodename, offset) return if nodename == '__local_fixups__': process_local_fixups(fdt, '', '', offset) @@ -241,7 +241,7 @@ def fdt_scan_node(fdt, nodename, offset): if nodename.startswith('__'): return - node_dict = node_props(fdt, nodename, offset) + node_dict = node_props(validator, fdt, nodename, offset) if 'phandle' in node_dict: #print('phandle', node_dict['phandle']) phandles[node_dict['phandle'][0][0]] = node_dict @@ -249,7 +249,7 @@ def fdt_scan_node(fdt, nodename, offset): offset = fdt.first_subnode(offset, QUIET_NOTFOUND) while offset >= 0: nodename = fdt.get_name(offset) - node = fdt_scan_node(fdt, nodename, offset) + node = fdt_scan_node(validator, fdt, nodename, offset) if node is not None: node_dict[nodename] = node @@ -317,14 +317,14 @@ def _get_phandle_arg_size(prop_path, idx, cells, cellname): return _get_cells_size(node, cellname) + 1 -def fixup_phandles(dt, path=''): +def fixup_phandles(validator, dt, path=''): for k, v in dt.items(): if isinstance(v, dict): - fixup_phandles(v, path=path + '/' + k) + fixup_phandles(validator, v, path=path + '/' + k) continue - elif not {'phandle-array'} & set(dtschema.property_get_type(k)): + elif not {'phandle-array'} & set(validator.property_get_type(k)): continue - elif dtschema.property_has_fixed_dimensions(k): + elif validator.property_has_fixed_dimensions(k): continue elif not isinstance(v, list) or (len(v) > 1 or not isinstance(v[0], list)): # Not a matrix or already split, nothing to do @@ -473,17 +473,17 @@ def fixup_addresses(dt, ac, sc): i += ac + child_cells -def fdt_unflatten(dtb): +def fdt_unflatten(validator, dtb): fdt = libfdt.Fdt(dtb) offset = fdt.first_subnode(-1, QUIET_NOTFOUND) - dt = fdt_scan_node(fdt, '/', offset) + dt = fdt_scan_node(validator, fdt, '/', offset) #print(phandle_loc) fixup_gpios(dt) fixup_interrupts(dt, 1) fixup_addresses(dt, 2, 1) - fixup_phandles(dt) + fixup_phandles(validator, dt) # pprint.pprint(dt, compact=True) return dt diff --git a/dtschema/lib.py b/dtschema/lib.py index 610da43a..4883ab96 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -1,23 +1,10 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2018 Linaro Ltd. -# Copyright 2018 Arm Ltd. +# Copyright 2018-2023 Arm Ltd. # Python library for Devicetree schema validation -import sys import os -import glob -import ruamel.yaml import re import pprint -import json - -import jsonschema - -from jsonschema.exceptions import RefResolutionError - -import dtschema.dtb - -schema_base_url = "http://devicetree.org/" -schema_basedir = os.path.dirname(os.path.abspath(__file__)) # We use a lot of regex's in schema and exceeding the cache size has noticeable # peformance impact. @@ -32,86 +19,6 @@ def __init__(self, value, size=32): self.size = size -rtyaml = ruamel.yaml.YAML(typ='rt') -rtyaml.allow_duplicate_keys = False -rtyaml.preserve_quotes = True - -yaml = ruamel.yaml.YAML(typ='safe') -yaml.allow_duplicate_keys = False - - -def path_to_obj(tree, path): - for pc in path: - tree = tree[pc] - return tree - - -def get_line_col(tree, path, obj=None): - if isinstance(obj, ruamel.yaml.comments.CommentedBase): - return obj.lc.line, obj.lc.col - obj = path_to_obj(tree, path) - if isinstance(obj, ruamel.yaml.comments.CommentedBase): - return obj.lc.line, obj.lc.col - if len(path) < 1: - return -1, -1 - obj = path_to_obj(tree, list(path)[:-1]) - if isinstance(obj, ruamel.yaml.comments.CommentedBase): - if path[-1] == '$nodename': - return -1, -1 - return obj.lc.key(path[-1]) - return -1, -1 - - -schema_user_paths = [] - - -def add_schema_path(path): - if os.path.isdir(path): - schema_user_paths.append(os.path.abspath(path)) - - -def check_id_path(filename, id): - id = id.replace('http://devicetree.org/schemas/', '') - id = id.replace('#', '') - - base = os.path.abspath(filename) - - for p in schema_user_paths: - base = base.replace(p + '/', '') - - base = base.replace(os.path.join(schema_basedir, 'schemas/'), '') - base = base.replace(os.path.abspath('schemas/') + '/', '') - - if not id == base: - print(filename + - ": $id: relative path/filename doesn't match actual path or filename\n\texpected: http://devicetree.org/schemas/" + - base + '#', - file=sys.stderr) - - -def do_load(filename): - with open(filename, 'r', encoding='utf-8') as f: - if filename.endswith('.json'): - return json.load(f) - - return yaml.load(f.read()) - - -def load_schema(schema): - for path in schema_user_paths: - if schema.startswith('schemas/'): - schema_file = schema.partition('/')[2] - else: - schema_file = schema - schema_file = os.path.join(path, schema_file) - if not os.path.isfile(schema_file): - continue - - return do_load(schema_file) - - return do_load(os.path.join(schema_basedir, schema)) - - def _value_is_type(subschema, key, type): if key not in subschema: return False @@ -184,115 +91,6 @@ def item_generator(json_input, lookup_key): yield item_val -def make_compatible_schema(schemas): - compat_sch = [{'enum': []}] - compatible_list = set() - for sch in schemas.values(): - compatible_list |= extract_compatibles(sch) - - # Allow 'foo' values for examples - compat_sch += [{'pattern': '^foo'}] - - prog = re.compile('.*[\^\[{\(\$].*') - for c in compatible_list: - if prog.match(c): - # Exclude the generic pattern - if c != '^[a-zA-Z0-9][a-zA-Z0-9,+\-._]+$': - compat_sch += [{'pattern': c}] - else: - compat_sch[0]['enum'].append(c) - - compat_sch[0]['enum'].sort() - schemas['generated-compatibles'] = { - '$id': 'generated-compatibles', - '$filename': 'Generated schema of documented compatible strings', - 'select': True, - 'properties': { - 'compatible': { - 'items': { - 'anyOf': compat_sch - } - } - } - } - - -def get_undocumented_compatibles(compatible_list): - global schema_cache - undoc_compats = [] - - validator = dtschema.DTValidator(schema_cache['generated-compatibles']) - for compat in compatible_list: - if not validator.is_valid({"compatible": [ compat ]}): - undoc_compats += [ compat ] - - return undoc_compats - - -def process_schema(filename): - try: - schema = load_schema(filename) - except ruamel.yaml.YAMLError: - print(filename + ": ignoring, error parsing file", file=sys.stderr) - return - - # Check that the validation schema is valid - try: - DTValidator.check_schema(schema, strict=False) - except jsonschema.SchemaError as exc: - print(filename + ": ignoring, error in schema: " + ': '.join(str(x) for x in exc.path), - file=sys.stderr) - #print(exc.message) - return - - if 'select' not in schema: - print(filename + ": warning: no 'select' found in schema found", file=sys.stderr) - return - - schema["type"] = "object" - schema["$filename"] = filename - return schema - - -def process_schemas(schema_paths, core_schema=True): - schemas = {} - - for filename in schema_paths: - if not os.path.isfile(filename): - continue - sch = process_schema(os.path.abspath(filename)) - if not sch or '$id' not in sch: - continue - if sch['$id'] in schemas: - print(os.path.abspath(filename) + ": duplicate '$id' value '" + sch['$id'] + "'", file=sys.stderr) - else: - schemas[sch['$id']] = sch - - if core_schema: - schema_paths.append(os.path.join(schema_basedir, 'schemas/')) - - for path in schema_paths: - count = 0 - if not os.path.isdir(path): - continue - - for filename in glob.iglob(os.path.join(os.path.abspath(path), "**/*.yaml"), recursive=True): - sch = process_schema(os.path.abspath(filename)) - if sch: - count += 1 - if sch['$id'] in schemas: - print(os.path.abspath(filename) + ": duplicate '$id' value '" + sch['$id'] + "'", file=sys.stderr) - else: - schemas[sch['$id']] = sch - - if count == 0: - print("warning: no schema found in path: %s" % path, file=sys.stderr) - - make_compatible_schema(schemas) - - return schemas - - def _get_array_range(subschema): if isinstance(subschema, list): if len(subschema) != 1: @@ -308,490 +106,6 @@ def _get_array_range(subschema): return (min, max) -def _merge_dim(dim1, dim2): - d = [] - for i in range(0, 2): - if dim1[i] == (0, 0): - d.insert(i, dim2[i]) - elif dim2[i] == (0, 0): - d.insert(i, dim1[i]) - else: - d.insert(i, (min(dim1[i] + dim2[i]), max(dim1[i] + dim2[i]))) - - return tuple(d) - - -type_re = re.compile('(flag|u?int(8|16|32|64)(-(array|matrix))?|string(-array)?|phandle(-array)?)') - - -def _extract_prop_type(props, schema, propname, subschema, is_pattern): - if not isinstance(subschema, dict): - return - - if propname.startswith('$'): - return - - # We only support local refs - if '$ref' in subschema and subschema['$ref'].startswith('#/'): - sch_path = subschema['$ref'].split('/')[1:] - tmp_subschema = schema - for p in sch_path: - tmp_subschema = tmp_subschema[p] - #print(propname, sch_path, tmp_subschema, file=sys.stderr) - _extract_prop_type(props, schema, propname, tmp_subschema, is_pattern) - - for k in subschema.keys() & {'allOf', 'oneOf', 'anyOf'}: - for v in subschema[k]: - _extract_prop_type(props, schema, propname, v, is_pattern) - - props.setdefault(propname, []) - - new_prop = {} - prop_type = None - - if ('type' in subschema and subschema['type'] == 'object') or \ - subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: - prop_type = 'node' - else: - try: - prop_type = type_re.search(subschema['$ref']).group(0) - except: - if 'type' in subschema and subschema['type'] == 'boolean': - prop_type = 'flag' - elif 'items' in subschema: - items = subschema['items'] - if (isinstance(items, list) and _is_string_schema(items[0])) or \ - (isinstance(items, dict) and _is_string_schema(items)): - # implicit string type - prop_type = 'string-array' - elif not (isinstance(items, list) and len(items) == 1 and \ - 'items' in items and isinstance(items['items'], list) and len(items['items']) == 1): - # Keep in sync with property-units.yaml - if re.search('-microvolt$', propname): - prop_type = 'int32-matrix' - elif re.search('(^(?!opp)).*-hz$', propname): - prop_type = 'uint32-matrix' - else: - prop_type = None - else: - prop_type = None - elif '$ref' in subschema and re.search(r'\.yaml#?$', subschema['$ref']): - prop_type = 'node' - else: - prop_type = None - - new_prop['type'] = prop_type - new_prop['$id'] = [schema['$id']] - if is_pattern: - new_prop['regex'] = re.compile(propname) - - if not prop_type: - if len(props[propname]) == 0: - props[propname] += [new_prop] - return - - # handle matrix dimensions - if prop_type == 'phandle-array' or prop_type.endswith('-matrix'): - dim = (_get_array_range(subschema), _get_array_range(subschema.get('items', {}))) - new_prop['dim'] = dim - else: - dim = ((0, 0), (0, 0)) - - dup_prop = None - for p in props[propname]: - if p['type'] is None: - dup_prop = p - break - if dim != ((0, 0), (0, 0)) and (p['type'] == 'phandle-array' or p['type'].endswith('-matrix')): - if not 'dim' in p: - p['dim'] = dim - elif p['dim'] != dim: - # Conflicting dimensions - p['dim'] = _merge_dim(p['dim'], dim) - return - if p['type'].startswith(prop_type): - # Already have the same or looser type, just record the $id - new_prop = None - if schema['$id'] not in p['$id']: - p['$id'] += [schema['$id']] - break - elif p['type'] in prop_type: - # Replace scalar type with array type - new_prop['$id'] += p['$id'] - dup_prop = p - break - - if dup_prop: - props[propname].remove(dup_prop) - - if new_prop: - props[propname] += [new_prop] - - if subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: - _extract_subschema_types(props, schema, subschema) - - -def _extract_subschema_types(props, schema, subschema): - if not isinstance(subschema, dict): - return - - if 'additionalProperties' in subschema: - _extract_subschema_types(props, schema, subschema['additionalProperties']) - - for k in subschema.keys() & {'properties', 'patternProperties'}: - if isinstance(subschema[k], dict): - for p,v in subschema[k].items(): - _extract_prop_type(props, schema, p, v, k == 'patternProperties') - - -def extract_types(): - global schema_cache - - props = {} - for sch in schema_cache.values(): - _extract_subschema_types(props, sch, sch) - - return props - - -def get_prop_types(want_missing_types=False, want_node_types=False): - pat_props = {} - - props = dtschema.extract_types() - - # hack to remove aliases and generic patterns - del props['^[a-z][a-z0-9\-]*$'] - props.pop('^[a-zA-Z][a-zA-Z0-9\\-_]{0,63}$', None) - props.pop('^.*$', None) - props.pop('.*', None) - - # Remove node types - if not want_node_types: - for val in props.values(): - val[:] = [t for t in val if t['type'] != 'node'] - - # Remove all properties without a type - if not want_missing_types: - for val in props.values(): - val[:] = [t for t in val if t['type'] is not None] - - # Delete any entries now empty due to above operations - for key in [key for key in props if len(props[key]) == 0]: del props[key] - - # Split out pattern properties - for key in [key for key in props if len(props[key]) and 'regex' in props[key][0] ]: - # Only want patternProperties with type and some amount of fixed string - if re.search(r'[0-9a-zA-F-]{3}', key): - #print(key, props[key], file=sys.stderr) - pat_props[key] = props[key] - del props[key] - - return [ props, pat_props ] - - -props = None -pat_props = None - - -def property_get_type(propname): - global props - global pat_props - - if not props: - props, pat_props = get_prop_types() - - type = set() - if propname in props: - for v in props[propname]: - if v['type']: - type.add(v['type']) - if len(type) == 0: - for v in pat_props.values(): - if v[0]['type'] and v[0]['type'] not in type and v[0]['regex'].search(propname): - type.add(v[0]['type']) - - # Don't return 'node' as a type if there's other types - if len(type) > 1 and 'node' in type: - type -= {'node'} - return type - - -def property_get_type_dim(propname): - global props - global pat_props - - if not props: - props, pat_props = get_prop_types() - - if propname in props: - for v in props[propname]: - if 'dim' in v: - return v['dim'] - - for v in pat_props.values(): - if v[0]['type'] and 'dim' in v[0] and v[0]['regex'].search(propname): - return v[0]['dim'] - - return None - - -def property_has_fixed_dimensions(propname): - dim = property_get_type_dim(propname) - if dim and dim[0][0] == dim[0][1] or dim[1][0] == dim[1][1]: - return True - - return False - - -def load(filename, line_number=False): - try: - if not filename.endswith('.yaml'): - with open(filename, 'rb') as f: - return [ dtschema.dtb.fdt_unflatten(f.read()) ] - except: - if filename.endswith('.dtb'): - raise - - with open(filename, 'r', encoding='utf-8') as f: - if line_number: - return rtyaml.load(f.read()) - else: - return yaml.load(f.read()) - - -def make_property_type_cache(): - global schema_cache - - props, pat_props = get_prop_types() - - for val in props.values(): - val[:] = [t for t in val if 'regex' not in t] - for t in val: del t['$id'] - - schema_cache['generated-types'] = { - '$id': 'generated-types', - '$filename': 'Generated property types', - 'select': False, - 'properties': {k: props[k] for k in sorted(props)} - } - - for val in pat_props.values(): - for t in val: - t.pop('regex', None) - del t['$id'] - - schema_cache['generated-pattern-types'] = { - '$id': 'generated-pattern-types', - '$filename': 'Generated property types', - 'select': False, - 'properties': {k: pat_props[k] for k in sorted(pat_props)} - } - - -schema_cache = {} - -def set_schemas(schema_files, core_schema=True): - global schema_cache, pat_props, props - - if len(schema_files) == 1 and os.path.isfile(schema_files[0]): - # a processed schema file - schema_cache = dtschema.load_schema(os.path.abspath(schema_files[0])) - # Convert old format to new - if isinstance(schema_cache, list): - d = {} - for sch in schema_cache: - if not isinstance(sch, dict): - return None - d[sch['$id']] = sch - schema_cache = d - - if 'generated-types' in schema_cache: - props = schema_cache['generated-types']['properties'] - if 'generated-pattern-types' in schema_cache: - pat_props = schema_cache['generated-pattern-types']['properties'] - for k in pat_props: - pat_props[k][0]['regex'] = re.compile(k) - else: - schema_cache = process_schemas(schema_files, core_schema) - make_property_type_cache() - - return schema_cache - -def http_handler(uri): - global schema_cache - '''Custom handler for http://devicetre.org YAML references''' - try: - if schema_base_url in uri: - my_uri = uri + '#' - if my_uri in schema_cache: - return schema_cache[my_uri] - # If we have a schema_cache, then the schema should have been there unless the schema had errors - if len(schema_cache): - return False - if 'meta-schemas' in uri: - return load_schema(uri.replace(schema_base_url, '')) - - try: - schema = load_schema(uri.replace(schema_base_url, '')) - except Exception as exc: - raise RefResolutionError('Unable to find schema file matching $id: ' + uri) - - try: - DTValidator.check_schema(schema, strict=False) - except Exception as exc: - raise RefResolutionError('Error in referenced schema matching $id: ' + uri) - - return schema - - from urllib.request import urlopen - - return yaml.load(urlopen(uri).read().decode('utf-8')) - except FileNotFoundError as e: - print('Unknown file referenced:', e, file=sys.stderr) - exit(-1) - - -handlers = {"http": http_handler} - - -def typeSize(validator, typeSize, instance, schema): - try: - size = instance[0][0].size - except: - size = 32 - - if typeSize != size: - yield jsonschema.ValidationError("size is %r, expected %r" % (size, typeSize)) - - -class DTValidator(): - '''Custom Validator for Devicetree Schemas - - Overrides the Draft7 metaschema with the devicetree metaschema. This - validator is used in exactly the same way as the Draft7Validator. Schema - files can be validated with the .check_schema() method, and .validate() - will check the data in a devicetree file. - ''' - resolver = jsonschema.RefResolver('', None, handlers=handlers) - format_checker = jsonschema.FormatChecker() - DTVal = jsonschema.validators.extend(jsonschema.Draft201909Validator, {'typeSize': typeSize}, version='DT') - - def __init__(self, *args, **kwargs): - kwargs.setdefault('resolver', self.resolver) - kwargs.setdefault('format_checker', self.format_checker) - self.validator = self.DTVal(*args, **kwargs) - - @classmethod - def annotate_error(self, error, schema, path): - error.note = None - error.schema_file = None - - for e in error.context: - self.annotate_error(e, schema, path + e.schema_path) - - scope = schema['$id'] - self.resolver.push_scope(scope) - ref_depth = 1 - - lastp = '' - for p in path: - # json-schema 3.2.0 includes 'if' in schema path - if lastp != 'properties' and p == 'if': - continue - lastp = p - - while '$ref' in schema and isinstance(schema['$ref'], str): - ref = self.resolver.resolve(schema['$ref']) - schema = ref[1] - self.resolver.push_scope(ref[0]) - ref_depth += 1 - - if '$id' in schema and isinstance(schema['$id'], str): - error.schema_file = schema['$id'] - - schema = schema[p] - - if isinstance(schema, dict): - if 'description' in schema and isinstance(schema['description'], str): - error.note = schema['description'] - - while ref_depth > 0: - self.resolver.pop_scope() - ref_depth -= 1 - - if isinstance(error.schema, dict) and 'description' in error.schema: - error.note = error.schema['description'] - - @classmethod - def iter_schema_errors(cls, schema): - try: - meta_schema = cls.resolver.resolve_from_url(schema['$schema']) - except (KeyError, TypeError, jsonschema.RefResolutionError, jsonschema.SchemaError): - error = jsonschema.SchemaError("Missing or invalid $schema keyword") - error.linecol = (-1,-1) - yield error - return - val = cls.DTVal(meta_schema, resolver=cls.resolver) - for error in val.iter_errors(schema): - cls.annotate_error(error, meta_schema, error.schema_path) - error.linecol = get_line_col(schema, error.path) - yield error - - def iter_errors(self, instance, _schema=None): - for error in self.validator.iter_errors(instance, _schema): - yield error - - def validate(self, *args, **kwargs): - for error in self.iter_errors(*args, **kwargs): - raise error - - def is_valid(self, instance): - error = next(self.iter_errors(instance), None) - return error is None - - @classmethod - def check_schema(cls, schema, strict=True): - """ - Test if schema is valid and apply fixups - 'strict' determines whether the full DT meta-schema is used or just the draft7 meta-schema - """ - if strict: - meta_schema = cls.resolver.resolve_from_url(schema['$schema']) - else: - # Using the draft7 metaschema because 2019-09 with $recursiveRef seems broken - meta_schema = jsonschema.Draft7Validator.META_SCHEMA - val = cls.DTVal(meta_schema, resolver=cls.resolver) - for error in val.iter_errors(schema): - raise jsonschema.SchemaError.create_from(error) - dtschema.fixup_schema(schema) - - @classmethod - def _check_schema_refs(self, schema): - if isinstance(schema, dict) and '$ref' in schema: - self.resolver.resolve(schema['$ref']) - elif isinstance(schema, dict): - for k, v in schema.items(): - self._check_schema_refs(v) - elif isinstance(schema, (list, tuple)): - for i in range(len(schema)): - self._check_schema_refs(schema[i]) - - @classmethod - def check_schema_refs(self, filename, schema): - if '$id' not in schema: - return - scope = schema['$id'] - if scope: - self.resolver.push_scope(scope) - - try: - self._check_schema_refs(schema) - except jsonschema.RefResolutionError as exc: - print(filename + ':', exc, file=sys.stderr) - - check_id_path(filename, schema['$id']) - - def format_error(filename, error, prefix="", nodename=None, verbose=False): src = prefix + os.path.abspath(filename) + ':' diff --git a/dtschema/schema.py b/dtschema/schema.py new file mode 100644 index 00000000..ff8cbd1b --- /dev/null +++ b/dtschema/schema.py @@ -0,0 +1,193 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2018 Linaro Ltd. +# Copyright 2018-2023 Arm Ltd. +# Python library for Devicetree schema validation +import sys +import os +import ruamel.yaml +import re +import copy +import jsonschema + +import dtschema + +from jsonschema.exceptions import RefResolutionError + +schema_base_url = "http://devicetree.org/" +schema_basedir = os.path.dirname(os.path.abspath(__file__)) + +rtyaml = ruamel.yaml.YAML(typ='rt') +rtyaml.allow_duplicate_keys = False +rtyaml.preserve_quotes = True + +yaml = ruamel.yaml.YAML(typ='safe') +yaml.allow_duplicate_keys = False + + +def path_to_obj(tree, path): + for pc in path: + tree = tree[pc] + return tree + + +def get_line_col(tree, path, obj=None): + if isinstance(obj, ruamel.yaml.comments.CommentedBase): + return obj.lc.line, obj.lc.col + obj = path_to_obj(tree, path) + if isinstance(obj, ruamel.yaml.comments.CommentedBase): + return obj.lc.line, obj.lc.col + if len(path) < 1: + return -1, -1 + obj = path_to_obj(tree, list(path)[:-1]) + if isinstance(obj, ruamel.yaml.comments.CommentedBase): + if path[-1] == '$nodename': + return -1, -1 + return obj.lc.key(path[-1]) + return -1, -1 + + +def typeSize(validator, typeSize, instance, schema): + try: + size = instance[0][0].size + except: + size = 32 + + if typeSize != size: + yield jsonschema.ValidationError("size is %r, expected %r" % (size, typeSize)) + + +class DTSchema(dict): + DtValidator = jsonschema.validators.extend( + jsonschema.Draft201909Validator, + format_checker=jsonschema.FormatChecker(), + version='DT') + + def __init__(self, schema_file, line_numbers=False): + self.paths = [(schema_base_url, schema_basedir + '/')] + with open(schema_file, 'r', encoding='utf-8') as f: + if line_numbers: + schema = rtyaml.load(f.read()) + else: + schema = yaml.load(f.read()) + + self.filename = os.path.abspath(schema_file) + + id = schema['$id'].rstrip('#') + match = re.search('(.*/schemas/)(.+)$', id) + self.base_path = os.path.abspath(schema_file)[:-len(match[2])] + + super().__init__(schema) + + def http_handler(self, uri): + '''Custom handler for http://devicetree.org references''' + uri = uri.rstrip('#') + for p in self.paths: + filename = uri.replace(p[0], p[1]) + if not os.path.isfile(filename): + continue + with open(filename, 'r', encoding='utf-8') as f: + return yaml.load(f.read()) + + raise RefResolutionError('Error in referenced schema matching $id: ' + uri) + + def annotate_error(self, error, schema, path): + error.note = None + error.schema_file = None + + for e in error.context: + self.annotate_error(e, schema, path + e.schema_path) + + scope = self.validator.ID_OF(schema) + self.validator.resolver.push_scope(scope) + ref_depth = 1 + + lastp = '' + for p in path: + # json-schema 3.2.0 includes 'if' in schema path + if lastp != 'properties' and p == 'if': + continue + lastp = p + + while '$ref' in schema and isinstance(schema['$ref'], str): + ref = self.validator.resolver.resolve(schema['$ref']) + schema = ref[1] + self.validator.resolver.push_scope(ref[0]) + ref_depth += 1 + + if '$id' in schema and isinstance(schema['$id'], str): + error.schema_file = schema['$id'] + + if p in schema: + schema = schema[p] + + if isinstance(schema, dict): + if 'description' in schema and isinstance(schema['description'], str): + error.note = schema['description'] + + while ref_depth > 0: + self.validator.resolver.pop_scope() + ref_depth -= 1 + + if isinstance(error.schema, dict) and 'description' in error.schema: + error.note = error.schema['description'] + + def iter_errors(self): + self.resolver = jsonschema.RefResolver.from_schema(self, + handlers={'http': self.http_handler}) + meta_schema = self.resolver.resolve_from_url(self['$schema']) + self.validator = self.DtValidator(meta_schema, resolver=self.resolver) + + for error in self.validator.iter_errors(self): + scherr = jsonschema.exceptions.SchemaError.create_from(error) + self.annotate_error(scherr, meta_schema, scherr.schema_path) + scherr.linecol = get_line_col(self, scherr.path) + yield scherr + + def is_valid(self, strict=False): + ''' Check if schema passes validation against json-schema.org schema ''' + if strict: + for error in self.iter_errors(): + raise error + else: + for error in self.DtValidator(self.DtValidator.META_SCHEMA).iter_errors(self): + scherr = jsonschema.exceptions.SchemaError.create_from(error) + raise scherr + + def fixup(self): + processed_schema = copy.deepcopy(dict(self)) + dtschema.fixups.fixup_schema(processed_schema) + return processed_schema + + def _check_schema_refs(self, schema): + if isinstance(schema, dict) and '$ref' in schema: + self.resolver.resolve(schema['$ref']) + elif isinstance(schema, dict): + for k, v in schema.items(): + self._check_schema_refs(v) + elif isinstance(schema, (list, tuple)): + for i in range(len(schema)): + self._check_schema_refs(schema[i]) + + def check_schema_refs(self): + id = self['$id'].rstrip('#') + base1 = re.search('schemas/(.+)$', id)[1] + base2 = self.filename.replace(self.filename[:-len(base1)], '') + if not base1 == base2: + print(f"{self.filename}: $id: Cannot determine base path from $id, relative path/filename doesn't match actual path or filename\n", + f"\t $id: {id}\n", + f"\tfile: {self.filename}", + file=sys.stderr) + return + + self.paths = [ + (schema_base_url + 'schemas/', self.base_path), + (schema_base_url + 'schemas/', schema_basedir + '/schemas/'), + ] + scope = self.validator.ID_OF(self) + if scope: + self.resolver.push_scope(scope) + + try: + self._check_schema_refs(self) + except jsonschema.RefResolutionError as exc: + print(self.filename + ':', exc, file=sys.stderr) diff --git a/dtschema/validator.py b/dtschema/validator.py new file mode 100644 index 00000000..b7e4bce5 --- /dev/null +++ b/dtschema/validator.py @@ -0,0 +1,475 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2018 Linaro Ltd. +# Copyright 2018-2023 Arm Ltd. + +import os +import sys +import re +import copy +import glob +import json +import jsonschema +import ruamel.yaml + +from jsonschema.exceptions import RefResolutionError + +import dtschema +from dtschema.lib import _is_string_schema +from dtschema.lib import _get_array_range +from dtschema.schema import DTSchema + +schema_basedir = os.path.dirname(os.path.abspath(__file__)) + + +def _merge_dim(dim1, dim2): + d = [] + for i in range(0, 2): + if dim1[i] == (0, 0): + d.insert(i, dim2[i]) + elif dim2[i] == (0, 0): + d.insert(i, dim1[i]) + else: + d.insert(i, (min(dim1[i] + dim2[i]), max(dim1[i] + dim2[i]))) + + return tuple(d) + + +type_re = re.compile('(flag|u?int(8|16|32|64)(-(array|matrix))?|string(-array)?|phandle(-array)?)') + + +def _extract_prop_type(props, schema, propname, subschema, is_pattern): + if not isinstance(subschema, dict): + return + + if propname.startswith('$'): + return + + # We only support local refs + if '$ref' in subschema and subschema['$ref'].startswith('#/'): + sch_path = subschema['$ref'].split('/')[1:] + tmp_subschema = schema + for p in sch_path: + tmp_subschema = tmp_subschema[p] + #print(propname, sch_path, tmp_subschema, file=sys.stderr) + _extract_prop_type(props, schema, propname, tmp_subschema, is_pattern) + + for k in subschema.keys() & {'allOf', 'oneOf', 'anyOf'}: + for v in subschema[k]: + _extract_prop_type(props, schema, propname, v, is_pattern) + + props.setdefault(propname, []) + + new_prop = {} + prop_type = None + + if ('type' in subschema and subschema['type'] == 'object') or \ + subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: + prop_type = 'node' + else: + try: + prop_type = type_re.search(subschema['$ref']).group(0) + except: + if 'type' in subschema and subschema['type'] == 'boolean': + prop_type = 'flag' + elif 'items' in subschema: + items = subschema['items'] + if (isinstance(items, list) and _is_string_schema(items[0])) or \ + (isinstance(items, dict) and _is_string_schema(items)): + # implicit string type + prop_type = 'string-array' + elif not (isinstance(items, list) and len(items) == 1 and + 'items' in items and isinstance(items['items'], list) and + len(items['items']) == 1): + # Keep in sync with property-units.yaml + if re.search('-microvolt$', propname): + prop_type = 'int32-matrix' + elif re.search('(^(?!opp)).*-hz$', propname): + prop_type = 'uint32-matrix' + else: + prop_type = None + else: + prop_type = None + elif '$ref' in subschema and re.search(r'\.yaml#?$', subschema['$ref']): + prop_type = 'node' + else: + prop_type = None + + new_prop['type'] = prop_type + new_prop['$id'] = [schema['$id']] + if is_pattern: + new_prop['regex'] = re.compile(propname) + + if not prop_type: + if len(props[propname]) == 0: + props[propname] += [new_prop] + return + + # handle matrix dimensions + if prop_type == 'phandle-array' or prop_type.endswith('-matrix'): + dim = (_get_array_range(subschema), _get_array_range(subschema.get('items', {}))) + new_prop['dim'] = dim + else: + dim = ((0, 0), (0, 0)) + + dup_prop = None + for p in props[propname]: + if p['type'] is None: + dup_prop = p + break + if dim != ((0, 0), (0, 0)) and \ + (p['type'] == 'phandle-array' or p['type'].endswith('-matrix')): + if 'dim' not in p: + p['dim'] = dim + elif p['dim'] != dim: + # Conflicting dimensions + p['dim'] = _merge_dim(p['dim'], dim) + return + if p['type'].startswith(prop_type): + # Already have the same or looser type, just record the $id + new_prop = None + if schema['$id'] not in p['$id']: + p['$id'] += [schema['$id']] + break + elif p['type'] in prop_type: + # Replace scalar type with array type + new_prop['$id'] += p['$id'] + dup_prop = p + break + + if dup_prop: + props[propname].remove(dup_prop) + + if new_prop: + props[propname] += [new_prop] + + if subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: + _extract_subschema_types(props, schema, subschema) + + +def _extract_subschema_types(props, schema, subschema): + if not isinstance(subschema, dict): + return + + if 'additionalProperties' in subschema: + _extract_subschema_types(props, schema, subschema['additionalProperties']) + + for k in subschema.keys() & {'properties', 'patternProperties'}: + if isinstance(subschema[k], dict): + for p, v in subschema[k].items(): + _extract_prop_type(props, schema, p, v, k == 'patternProperties') + + +def extract_types(schemas): + props = {} + for sch in schemas.values(): + _extract_subschema_types(props, sch, sch) + + return props + + +def get_prop_types(schemas, want_missing_types=False, want_node_types=False): + pat_props = {} + + props = extract_types(schemas) + + # hack to remove aliases and generic patterns + del props['^[a-z][a-z0-9\-]*$'] + props.pop('^[a-zA-Z][a-zA-Z0-9\\-_]{0,63}$', None) + props.pop('^.*$', None) + props.pop('.*', None) + + # Remove node types + if not want_node_types: + for val in props.values(): + val[:] = [t for t in val if t['type'] != 'node'] + + # Remove all properties without a type + if not want_missing_types: + for val in props.values(): + val[:] = [t for t in val if t['type'] is not None] + + # Delete any entries now empty due to above operations + for key in [key for key in props if len(props[key]) == 0]: + del props[key] + + # Split out pattern properties + for key in [key for key in props if len(props[key]) and 'regex' in props[key][0]]: + # Only want patternProperties with type and some amount of fixed string + if re.search(r'[0-9a-zA-F-]{3}', key): + #print(key, props[key], file=sys.stderr) + pat_props[key] = props[key] + del props[key] + + return [props, pat_props] + + +def make_compatible_schema(schemas): + compat_sch = [{'enum': []}] + compatible_list = set() + for sch in schemas.values(): + compatible_list |= dtschema.extract_compatibles(sch) + + # Allow 'foo' values for examples + compat_sch += [{'pattern': '^foo'}] + + prog = re.compile('.*[\^\[{\(\$].*') + for c in compatible_list: + if prog.match(c): + # Exclude the generic pattern + if c != '^[a-zA-Z0-9][a-zA-Z0-9,+\-._]+$': + compat_sch += [{'pattern': c}] + else: + compat_sch[0]['enum'].append(c) + + compat_sch[0]['enum'].sort() + schemas['generated-compatibles'] = { + '$id': 'http://devicetree.org/schemas/generated-compatibles', + '$filename': 'Generated schema of documented compatible strings', + 'select': True, + 'properties': { + 'compatible': { + 'items': { + 'anyOf': compat_sch + } + } + } + } + + +def process_schema(filename): + try: + dtsch = DTSchema(filename) + except: + print(filename + ": ignoring, error parsing file", file=sys.stderr) + return + + # Check that the validation schema is valid + try: + dtsch.is_valid() + except jsonschema.SchemaError as exc: + print(filename + ": ignoring, error in schema: " + ': '.join(str(x) for x in exc.path), + file=sys.stderr) + #print(exc.message) + return + + schema = dtsch.fixup() + if 'select' not in schema: + print(filename + ": warning: no 'select' found in schema found", file=sys.stderr) + return + + schema["type"] = "object" + schema["$filename"] = filename + return schema + + +def process_schemas(schema_paths, core_schema=True): + schemas = {} + + for filename in schema_paths: + if not os.path.isfile(filename): + continue + sch = process_schema(os.path.abspath(filename)) + if not sch or '$id' not in sch: + continue + if sch['$id'] in schemas: + print(os.path.abspath(filename) + ": duplicate '$id' value '" + sch['$id'] + "'", file=sys.stderr) + else: + schemas[sch['$id']] = sch + + if core_schema: + schema_paths.append(os.path.join(schema_basedir, 'schemas/')) + + for path in schema_paths: + count = 0 + if not os.path.isdir(path): + continue + + for filename in glob.iglob(os.path.join(os.path.abspath(path), "**/*.yaml"), recursive=True): + sch = process_schema(os.path.abspath(filename)) + if sch: + count += 1 + if sch['$id'] in schemas: + print(os.path.abspath(filename) + ": duplicate '$id' value '" + sch['$id'] + "'", file=sys.stderr) + else: + schemas[sch['$id']] = sch + + if count == 0: + print("warning: no schema found in path: %s" % path, file=sys.stderr) + + return schemas + + +def typeSize(validator, typeSize, instance, schema): + try: + size = instance[0][0].size + except: + size = 32 + + if typeSize != size: + yield jsonschema.ValidationError("size is %r, expected %r" % (size, typeSize)) + + +class DTValidator: + '''Custom Validator for Devicetree Schemas + + Overrides the Draft7 metaschema with the devicetree metaschema. This + validator is used in exactly the same way as the Draft7Validator. Schema + files can be validated with the .check_schema() method, and .validate() + will check the data in a devicetree file. + ''' + DtValidator = jsonschema.validators.extend(jsonschema.Draft201909Validator, {'typeSize': typeSize}) + + def __init__(self, schema_files, filter=None): + self.schemas = {} + self.resolver = jsonschema.RefResolver('', None, handlers={'http': self.http_handler}) + + yaml = ruamel.yaml.YAML(typ='safe') + + if len(schema_files) == 1 and os.path.isfile(schema_files[0]): + # a processed schema file + with open(schema_files[0], 'r', encoding='utf-8') as f: + if schema_files[0].endswith('.json'): + schema_cache = json.load(f) + else: + schema_cache = yaml.load(f.read()) + + # Convert old format to new + if isinstance(schema_cache, list): + d = {} + for sch in schema_cache: + if not isinstance(sch, dict): + return None + d[sch['$id']] = sch + schema_cache = d + + if 'generated-types' in schema_cache: + self.props = schema_cache['generated-types']['properties'] + if 'generated-pattern-types' in schema_cache: + self.pat_props = copy.deepcopy(schema_cache['generated-pattern-types']['properties']) + for k in self.pat_props: + self.pat_props[k][0]['regex'] = re.compile(k) + + self.schemas = schema_cache + else: + self.schemas = process_schemas(schema_files) + self.make_property_type_cache() + make_compatible_schema(self.schemas) + for k in self.pat_props: + self.pat_props[k][0]['regex'] = re.compile(k) + + def http_handler(self, uri): + '''Custom handler for http://devicetree.org references''' + try: + uri += '#' + if uri in self.schemas: + return self.schemas[uri] + else: + # If we have a schema_cache, then the schema should have been there unless the schema had errors + if len(self.schemas): + return False + except: + raise RefResolutionError('Error in referenced schema matching $id: ' + uri) + + def annotate_error(self, id, error): + error.schema_file = id + error.linecol = -1, -1 + error.note = None + + def iter_errors(self, instance, filter=None): + for id, schema in self.schemas.items(): + if 'select' not in schema: + continue + if filter and filter not in id: + continue + sch = {'if': schema['select'], 'then': schema} + for error in self.DtValidator(sch, + resolver=self.resolver, + ).iter_errors(instance): + self.annotate_error(id, error) + yield error + + def validate(self, instance, filter=None): + for error in self.iter_errors(instance, filter=filter): + raise error + + def get_undocumented_compatibles(self, compatible_list): + undoc_compats = [] + + validator = self.DtValidator(self.schemas['generated-compatibles']) + for compat in compatible_list: + if not validator.is_valid({"compatible": [compat]}): + undoc_compats += [compat] + + return undoc_compats + + def make_property_type_cache(self): + self.props, self.pat_props = get_prop_types(self.schemas) + + for val in self.props.values(): + for t in val: + del t['$id'] + + self.schemas['generated-types'] = { + '$id': 'generated-types', + '$filename': 'Generated property types', + 'select': False, + 'properties': {k: self.props[k] for k in sorted(self.props)} + } + + pat_props = copy.deepcopy(self.pat_props) + for val in pat_props.values(): + for t in val: + t.pop('regex', None) + del t['$id'] + + self.schemas['generated-pattern-types'] = { + '$id': 'generated-pattern-types', + '$filename': 'Generated pattern property types', + 'select': False, + 'properties': {k: pat_props[k] for k in sorted(pat_props)} + } + + def property_get_all(self): + all_props = copy.deepcopy({**self.props, **self.pat_props}) + for p, v in all_props.items(): + v[0].pop('regex', None) + + return all_props + + def property_get_type(self, propname): + ptype = set() + if propname in self.props: + for v in self.props[propname]: + if v['type']: + ptype.add(v['type']) + if len(ptype) == 0: + for v in self.pat_props.values(): + if v[0]['type'] and v[0]['type'] not in ptype and v[0]['regex'].search(propname): + ptype.add(v[0]['type']) + + # Don't return 'node' as a type if there's other types + if len(ptype) > 1 and 'node' in ptype: + ptype -= {'node'} + return ptype + + def property_get_type_dim(self, propname): + if propname in self.props: + for v in self.props[propname]: + if 'dim' in v: + return v['dim'] + + for v in self.pat_props.values(): + if v[0]['type'] and 'dim' in v[0] and v[0]['regex'].search(propname): + return v[0]['dim'] + + return None + + def property_has_fixed_dimensions(self, propname): + dim = self.property_get_type_dim(propname) + if dim and dim[0][0] == dim[0][1] or dim[1][0] == dim[1][1]: + return True + + return False + + def decode_dtb(self, dtb): + return [dtschema.dtb.fdt_unflatten(self, dtb)] diff --git a/test/test-dt-validate.py b/test/test-dt-validate.py index 6375604b..77497cd9 100755 --- a/test/test-dt-validate.py +++ b/test/test-dt-validate.py @@ -10,6 +10,7 @@ import unittest import os +import copy import glob import sys import subprocess @@ -17,37 +18,44 @@ basedir = os.path.dirname(__file__) import jsonschema +import ruamel.yaml import dtschema dtschema_dir = os.path.dirname(dtschema.__file__) +yaml = ruamel.yaml.YAML(typ='safe') + +def load(filename): + with open(filename, 'r', encoding='utf-8') as f: + return yaml.load(f.read()) + class TestDTMetaSchema(unittest.TestCase): def setUp(self): - self.schema = dtschema.load(os.path.join(basedir, 'schemas/good-example.yaml')) - self.bad_schema = dtschema.load(os.path.join(basedir, 'schemas/bad-example.yaml')) + self.schema = dtschema.DTSchema(os.path.join(basedir, 'schemas/good-example.yaml')) + self.bad_schema = dtschema.DTSchema(os.path.join(basedir, 'schemas/bad-example.yaml')) def test_all_metaschema_valid(self): '''The metaschema must all be a valid Draft2019-09 schema''' for filename in glob.iglob(os.path.join(dtschema_dir, 'meta-schemas/**/*.yaml'), recursive=True): with self.subTest(schema=filename): - schema = dtschema.load_schema(filename) + schema = load(filename) jsonschema.Draft201909Validator.check_schema(schema) def test_required_properties(self): - dtschema.DTValidator.check_schema(self.schema) + self.schema.is_valid(strict=True) def test_required_property_missing(self): for key in self.schema.keys(): if key in ['$schema', 'properties', 'required', 'description', 'examples', 'additionalProperties']: continue with self.subTest(k=key): - schema_tmp = self.schema.copy() + schema_tmp = copy.deepcopy(self.schema) del schema_tmp[key] - self.assertRaises(jsonschema.SchemaError, dtschema.DTValidator.check_schema, schema_tmp) + self.assertRaises(jsonschema.SchemaError, schema_tmp.is_valid, strict=True) def test_bad_schema(self): '''bad-example.yaml is all bad. There is no condition where it should pass validation''' - self.assertRaises(jsonschema.SchemaError, dtschema.DTValidator.check_schema, self.bad_schema) + self.assertRaises(jsonschema.SchemaError, self.bad_schema.is_valid, strict=True) def test_bad_properties(self): for key in self.bad_schema.keys(): @@ -55,32 +63,31 @@ def test_bad_properties(self): continue with self.subTest(k=key): - schema_tmp = self.schema.copy() + schema_tmp = copy.deepcopy(self.schema) schema_tmp[key] = self.bad_schema[key] - self.assertRaises(jsonschema.SchemaError, dtschema.DTValidator.check_schema, schema_tmp) + self.assertRaises(jsonschema.SchemaError, schema_tmp.is_valid, strict=True) bad_props = self.bad_schema['properties'] - schema_tmp = self.schema.copy() + schema_tmp = copy.deepcopy(self.schema) for key in bad_props.keys(): with self.subTest(k="properties/"+key): schema_tmp['properties'] = self.schema['properties'].copy() schema_tmp['properties'][key] = bad_props[key] - self.assertRaises(jsonschema.SchemaError, dtschema.DTValidator.check_schema, schema_tmp) + self.assertRaises(jsonschema.SchemaError, schema_tmp.is_valid, strict=True) class TestDTSchema(unittest.TestCase): def test_binding_schemas_valid(self): '''Test that all schema files under ./dtschema/schemas/ validate against the DT metaschema''' for filename in glob.iglob(os.path.join(dtschema_dir, 'schemas/**/*.yaml'), recursive=True): with self.subTest(schema=filename): - schema = dtschema.load_schema(filename) - dtschema.DTValidator.check_schema(schema) + dtschema.DTSchema(filename).is_valid(strict=True) def test_binding_schemas_id_is_unique(self): '''Test that all schema files under ./dtschema/schemas/ validate against the DT metaschema''' ids = [] for filename in glob.iglob(os.path.join(dtschema_dir, 'schemas/**/*.yaml'), recursive=True): with self.subTest(schema=filename): - schema = dtschema.load_schema(filename) + schema = load(filename) self.assertEqual(ids.count(schema['$id']), 0) ids.append(schema['$id']) @@ -91,46 +98,26 @@ def test_binding_schemas_valid_draft7(self): ''' for filename in glob.iglob(os.path.join(dtschema_dir, 'schemas/**/*.yaml'), recursive=True): with self.subTest(schema=filename): - schema = dtschema.load_schema(filename) + schema = load(filename) jsonschema.Draft7Validator.check_schema(schema) class TestDTValidate(unittest.TestCase): def setUp(self): - self.schemas = list() - - self.schemas = dtschema.set_schemas([ os.path.join(os.path.abspath(basedir), "schemas/")]) - - for schema in self.schemas.values(): - schema["$select_validator"] = dtschema.DTValidator(schema['select']) + self.validator = dtschema.DTValidator([ os.path.join(os.path.abspath(basedir), "schemas/")]) - def check_node(self, nodename, node, fail): + def check_node(self, nodename, node): if nodename == "/" or nodename.startswith('__'): return node['$nodename'] = [ nodename ] - node_matched = True - if fail: - node_matched = False - with self.assertRaises(jsonschema.ValidationError, msg=nodename): - for schema in self.schemas.values(): - if schema['$select_validator'].is_valid(node): - node_matched = True - dtschema.DTValidator(schema).validate(node) - else: - node_matched = False - for schema in self.schemas.values(): - if schema['$select_validator'].is_valid(node): - node_matched = True - self.assertIsNone(dtschema.DTValidator(schema).validate(node)) - - self.assertTrue(node_matched, msg=nodename) - - def check_subtree(self, nodename, subtree, fail): - self.check_node(nodename, subtree, fail) + self.validator.validate(node) + + def check_subtree(self, nodename, subtree): + self.check_node(nodename, subtree) for name,value in subtree.items(): if isinstance(value, dict): - self.check_subtree(name, value, fail) + self.check_subtree(name, value) def test_dtb_validation(self): '''Test that all DT files under ./test/ validate against the DT schema (DTB)''' @@ -138,11 +125,15 @@ def test_dtb_validation(self): with self.subTest(schema=filename): expect_fail = "-fail" in filename res = subprocess.run(['dtc', '-Odtb', filename], capture_output=True) - testtree = dtschema.dtb.fdt_unflatten(res.stdout) + testtree = self.validator.decode_dtb(res.stdout) self.assertEqual(res.returncode, 0, msg='dtc failed:\n' + res.stderr.decode()) - for name, value in testtree.items(): - if isinstance(value, dict): - self.check_node(name, value, expect_fail) + + if expect_fail: + with self.assertRaises(jsonschema.ValidationError): + self.check_subtree('/', testtree[0]) + else: + self.assertIsNone(self.check_subtree('/', testtree[0])) + if __name__ == '__main__': diff --git a/tools/dt-check-compatible b/tools/dt-check-compatible index 433dbe24..10531902 100755 --- a/tools/dt-check-compatible +++ b/tools/dt-check-compatible @@ -30,9 +30,7 @@ if __name__ == "__main__": if args.schema != "" and not os.path.exists(args.schema): exit(-1) - dtschema.set_schemas([args.schema]) - - undoc_compats = dtschema.get_undocumented_compatibles(args.compatible_str) + undoc_compats = dtschema.DTValidator([args.schema]).get_undocumented_compatibles(args.compatible_str) if args.invert_match: print(*undoc_compats, sep="\n") diff --git a/tools/dt-doc-validate b/tools/dt-doc-validate index 3c5a607b..2a8235a5 100755 --- a/tools/dt-doc-validate +++ b/tools/dt-doc-validate @@ -22,17 +22,22 @@ line_number = False def check_doc(filename): ret = 0 try: - testtree = dtschema.load(filename, line_number=line_number) + dtsch = dtschema.DTSchema(filename, line_numbers=line_number) except ruamel.yaml.YAMLError as exc: print(filename + ":" + str(exc.problem_mark.line + 1) + ":" + str(exc.problem_mark.column + 1) + ":", exc.problem, file=sys.stderr) return 1 - for error in sorted(dtschema.DTValidator.iter_schema_errors(testtree), key=lambda e: e.linecol): - print(dtschema.format_error(filename, error, verbose=args.verbose), file=sys.stderr) - ret = 1 + try: + for error in sorted(dtsch.iter_errors(), key=lambda e: e.linecol): + print(dtschema.format_error(filename, error, verbose=args.verbose), file=sys.stderr) + ret = 1 + except: + raise + print(filename + ': error checking schema file', file=sys.stderr) + return 1 - dtschema.DTValidator.check_schema_refs(filename, testtree) + dtsch.check_schema_refs() return ret @@ -50,9 +55,6 @@ if __name__ == "__main__": line_number=args.line_number - if args.url_path: - dtschema.add_schema_path(args.url_path) - ret = 0 for f in args.yamldt: if os.path.isdir(f): diff --git a/tools/dt-extract-props b/tools/dt-extract-props index 1fa73969..7952909a 100755 --- a/tools/dt-extract-props +++ b/tools/dt-extract-props @@ -28,8 +28,8 @@ if __name__ == "__main__": action="version", version=dtschema.__version__) args = ap.parse_args() - dtschema.set_schemas(args.schema_files) - props = dtschema.extract_types() + dtval = dtschema.DTValidator(args.schema_files) + props = dtval.property_get_all() if args.duplicates: tmp_props = {} diff --git a/tools/dt-mk-schema b/tools/dt-mk-schema index 1dc22611..7439a792 100755 --- a/tools/dt-mk-schema +++ b/tools/dt-mk-schema @@ -35,7 +35,7 @@ if __name__ == "__main__": action="version", version=dtschema.__version__) args = ap.parse_args() - schemas = dtschema.set_schemas(args.schemas, core_schema=(not args.useronly)) + schemas = dtschema.DTValidator(args.schemas).schemas if not schemas: exit(-1) diff --git a/tools/dt-validate b/tools/dt-validate index 72ad4cf1..84924848 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -27,7 +27,7 @@ class schema_group(): if schema_file != "" and not os.path.exists(schema_file): exit(-1) - self.schemas = dtschema.set_schemas([schema_file]) + self.validator = dtschema.DTValidator([schema_file]) def check_node(self, tree, node, disabled, nodename, fullname, filename): # Hack to save some time validating examples @@ -35,56 +35,42 @@ class schema_group(): return node['$nodename'] = [ nodename ] - node_matched = False - matched_schemas = [] - for schema in self.schemas.values(): - if '$select_validator' in schema and schema['$select_validator'].is_valid(node): - # We have a match if a conditional schema is selected - if schema['select'] != True: - matched_schemas.append(schema['$id']) - node_matched = True - try: - for error in dtschema.DTValidator(schema).iter_errors(node): - - # Disabled nodes might not have all the required - # properties filled in, such as a regulator or a - # GPIO meant to be filled at the DTS level on - # boards using that particular node. Thus, if the - # node is marked as disabled, let's just ignore - # any error message reporting a missing property. - if disabled or (isinstance(error.instance, dict) and \ - 'status' in error.instance and \ - 'disabled' in error.instance['status']): - if {'required', 'unevaluatedProperties'} & set(error.schema_path): - continue - elif error.context: - found = False - for e in error.context: - if {'required', 'unevaluatedProperties'} & set(e.schema_path): - found = True - break - if found: - continue - - if schema['$id'] == 'generated-compatibles': - if show_unmatched < 1: - continue - print("%s: %s: failed to match any schema with compatible: %s" % - (filename, fullname, node['compatible']), file=sys.stderr) - continue - print(dtschema.format_error(filename, error, nodename=nodename, verbose=verbose) + - '\n\tFrom schema: ' + schema['$filename'], - file=sys.stderr) - except RecursionError as e: - print(ap.prog + ": recursion error: Check for prior errors in a referenced schema", file=sys.stderr) + try: + for error in self.validator.iter_errors(node, filter=match_schema_file): + + # Disabled nodes might not have all the required + # properties filled in, such as a regulator or a + # GPIO meant to be filled at the DTS level on + # boards using that particular node. Thus, if the + # node is marked as disabled, let's just ignore + # any error message reporting a missing property. + if disabled or (isinstance(error.instance, dict) and \ + 'status' in error.instance and \ + 'disabled' in error.instance['status']): + + if {'required', 'unevaluatedProperties'} & set(error.schema_path): + continue + elif error.context: + found = False + for e in error.context: + if {'required', 'unevaluatedProperties'} & set(e.schema_path): + found = True + break + if found: + continue - if show_matched and matched_schemas: - print("%s: %s: matched on schema(s)\n\t" % (filename, fullname) + - '\n\t'.join(matched_schemas), file=sys.stderr) + if error.schema_file == 'generated-compatibles': + if not show_unmatched: + continue + print(f"{filename}: {fullname}: failed to match any schema with compatible: {node['compatible']}", + file=sys.stderr) + continue - if show_unmatched >= 2 and not node_matched: - print("%s: %s: failed to match any schema" % (filename, fullname), file=sys.stderr) + print(dtschema.format_error(filename, error, nodename=nodename, verbose=verbose), + file=sys.stderr) + except RecursionError as e: + print(ap.prog + ": recursion error: Check for prior errors in a referenced schema", file=sys.stderr) def check_subtree(self, tree, subtree, disabled, nodename, fullname, filename): if nodename.startswith('__'): @@ -102,14 +88,10 @@ class schema_group(): if isinstance(value, dict): self.check_subtree(tree, value, disabled, name, fullname + name, filename) - def check_trees(self, filename, dt): + def check_dtb(self, filename): """Check the given DT against all schemas""" - - for schema in self.schemas.values(): - if match_schema_file and match_schema_file not in schema['$filename']: - continue - schema["$select_validator"] = dtschema.DTValidator(schema['select']) - + with open(filename, 'rb') as f: + dt = sg.validator.decode_dtb(f.read()) for subtree in dt: self.check_subtree(dt, subtree, False, "/", "/", filename) @@ -121,12 +103,9 @@ if __name__ == "__main__": ap.add_argument('-s', '--schema', help="preparsed schema file or path to schema files") ap.add_argument('-p', '--preparse', help="preparsed schema file (deprecated, use '-s')") ap.add_argument('-l', '--limit', help="limit validation to schema files matching substring") - ap.add_argument('-m', '--show-unmatched', default=0, - help="Print out nodes which don't match any schema.\n" \ - "Once for only nodes with 'compatible'\n" \ - "Twice for all nodes", action="count") - ap.add_argument('-M', '--show-matched', - help="Print out matching schema for each node", action="store_true") + ap.add_argument('-m', '--show-unmatched', + help="Print out node 'compatible' strings which don't match any schema.", + action="store_true") ap.add_argument('-n', '--line-number', help="Obsolete", action="store_true") ap.add_argument('-v', '--verbose', help="verbose mode", action="store_true") ap.add_argument('-u', '--url-path', help="Additional search path for references") @@ -136,12 +115,8 @@ if __name__ == "__main__": verbose = args.verbose show_unmatched = args.show_unmatched - show_matched = args.show_matched match_schema_file = args.limit - if args.url_path: - dtschema.add_schema_path(args.url_path) - if args.preparse: sg = schema_group(args.preparse) elif args.schema: @@ -153,15 +128,13 @@ if __name__ == "__main__": if not os.path.isdir(d): continue for filename in glob.iglob(d + "/**/*.dtb", recursive=True): - testtree = dtschema.load(filename) if verbose: print("Check: " + filename) - sg.check_trees(filename, testtree) + sg.check_dtb(filename) for filename in args.dtbs: if not os.path.isfile(filename): continue - testtree = dtschema.load(filename) if verbose: print("Check: " + filename) - sg.check_trees(filename, testtree) + sg.check_dtb(filename) diff --git a/tools/dtb2py b/tools/dtb2py index 61a54d59..51d24868 100755 --- a/tools/dtb2py +++ b/tools/dtb2py @@ -26,9 +26,9 @@ if __name__ == "__main__": schemas = [args.schema] else: schemas = [] - dtschema.set_schemas(schemas) - dt = dtschema.load(args.dtbfile) + with open(args.dtbfile, 'rb') as f: + dt = dtschema.DTValidator(schemas).decode_dtb(f.read()) try: pprint.pprint(dt, compact=True) From 26b0e53f01262e5e7d44ab71c3dab4f376bbde78 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 13 Jun 2023 13:32:54 -0600 Subject: [PATCH 364/505] dtschema: Use format strings for printing Use the preferred, newish format strings for printing strings. Signed-off-by: Rob Herring --- dtschema/schema.py | 2 +- dtschema/validator.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dtschema/schema.py b/dtschema/schema.py index ff8cbd1b..aa2031d2 100644 --- a/dtschema/schema.py +++ b/dtschema/schema.py @@ -190,4 +190,4 @@ def check_schema_refs(self): try: self._check_schema_refs(self) except jsonschema.RefResolutionError as exc: - print(self.filename + ':', exc, file=sys.stderr) + print(f"{self.filename}:\n{exc}", file=sys.stderr) diff --git a/dtschema/validator.py b/dtschema/validator.py index b7e4bce5..55aaae6a 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -240,21 +240,21 @@ def process_schema(filename): try: dtsch = DTSchema(filename) except: - print(filename + ": ignoring, error parsing file", file=sys.stderr) + print(f"{filename}: ignoring, error parsing file", file=sys.stderr) return # Check that the validation schema is valid try: dtsch.is_valid() except jsonschema.SchemaError as exc: - print(filename + ": ignoring, error in schema: " + ': '.join(str(x) for x in exc.path), + print(f"{filename}: ignoring, error in schema: " + ': '.join(str(x) for x in exc.path), file=sys.stderr) #print(exc.message) return schema = dtsch.fixup() if 'select' not in schema: - print(filename + ": warning: no 'select' found in schema found", file=sys.stderr) + print(f"{filename}: warning: no 'select' found in schema found", file=sys.stderr) return schema["type"] = "object" @@ -272,7 +272,7 @@ def process_schemas(schema_paths, core_schema=True): if not sch or '$id' not in sch: continue if sch['$id'] in schemas: - print(os.path.abspath(filename) + ": duplicate '$id' value '" + sch['$id'] + "'", file=sys.stderr) + print(f"{os.path.abspath(filename)}: duplicate '$id' value '{sch['$id']}'", file=sys.stderr) else: schemas[sch['$id']] = sch @@ -289,12 +289,12 @@ def process_schemas(schema_paths, core_schema=True): if sch: count += 1 if sch['$id'] in schemas: - print(os.path.abspath(filename) + ": duplicate '$id' value '" + sch['$id'] + "'", file=sys.stderr) + print(f"{os.path.abspath(filename)}: duplicate '$id' value '{sch['$id']}'", file=sys.stderr) else: schemas[sch['$id']] = sch if count == 0: - print("warning: no schema found in path: %s" % path, file=sys.stderr) + print(f"warning: no schema found in path: {path}", file=sys.stderr) return schemas From e3dfc1e5745d9e0efee660ff4f528e7048f0ab1e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 15 Jun 2023 13:07:28 -0600 Subject: [PATCH 365/505] schemas: Use 'oneOf' rather than if/then for *-supply properties Use 'oneOf' rather than if/then for *-supply properties so that the property type can be extracted. For most bindings, we don't want properties defined in an if/then schema, so the same should apply here. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index e93baf4c..6bf8f5aa 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -61,10 +61,9 @@ patternProperties: $ref: types.yaml#/definitions/non-unique-string-array ".*-supply$": - if: - not: { type: object } - then: - $ref: types.yaml#/definitions/phandle + oneOf: + - type: object + - $ref: types.yaml#/definitions/phandle # property and node namespace overlaps. Catch both here "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]{0,63}$": From 822ce6a71255e7ff6f5c36be1a84129c48546ec3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 3 Nov 2022 15:13:50 -0500 Subject: [PATCH 366/505] schemas: cpu: Add some missing common properties The CPU schema is missing several common properties used across architectures. Add them in preparation to turn on 'unevaluatedProperties' checks in the architecture specific schemas. Signed-off-by: Rob Herring --- dtschema/schemas/cpu.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dtschema/schemas/cpu.yaml b/dtschema/schemas/cpu.yaml index 5d1be167..cb2d2665 100644 --- a/dtschema/schemas/cpu.yaml +++ b/dtschema/schemas/cpu.yaml @@ -45,10 +45,18 @@ properties: compatible: true + '#cooling-cells': + const: 2 + clock-frequency: description: Specifies the current clock speed of the CPU in Hertz. + clocks: true + clock-names: true + + cpu-supply: true + timebase-frequency: oneOf: - $ref: /schemas/types.yaml#/definitions/uint32 @@ -93,11 +101,15 @@ properties: Specifies the reservation granule size supported by this processor in bytes. + numa-node-id: true + mmu-type: $ref: /schemas/types.yaml#/definitions/string description: Specifies the CPU's MMU type. + operating-points-v2: true + tlb-split: $ref: /schemas/types.yaml#/definitions/flag description: @@ -106,6 +118,12 @@ properties: the TLB has a unified configuration. Required for a CPU with a TLB in a split configuration. + l2-cache: + oneOf: + - type: object + - $ref: /schemas/types.yaml#/definitions/phandle + deprecated: true + patternProperties: "^(i-|d-|)tlb-(size|sets)$": $ref: /schemas/types.yaml#/definitions/uint32 From bd525a45d5855d8e5e55148ed42bae8b027682d8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 17 Nov 2022 13:37:14 -0600 Subject: [PATCH 367/505] meta-schemas: Disallow 'binding' or 'schema' in schema 'title' All schemas are bindings/schemas so no need to state that in 'title'. The title should be one line on what the binding contains or h/w it is for. Signed-off-by: Rob Herring --- dtschema/meta-schemas/base.yaml | 6 ++++++ dtschema/schemas/cpu.yaml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/base.yaml b/dtschema/meta-schemas/base.yaml index 96d0a82f..01ac175a 100644 --- a/dtschema/meta-schemas/base.yaml +++ b/dtschema/meta-schemas/base.yaml @@ -25,6 +25,12 @@ properties: - "http://devicetree.org/meta-schemas/base.yaml#" title: maxLength: 100 + description: + Everything is a binding/schema, no need to say it. Describe what + hardware the binding is for. + not: + pattern: '([Bb]inding| [Ss]chema)' + examples: type: array items: diff --git a/dtschema/schemas/cpu.yaml b/dtschema/schemas/cpu.yaml index cb2d2665..ccde5ca3 100644 --- a/dtschema/schemas/cpu.yaml +++ b/dtschema/schemas/cpu.yaml @@ -15,7 +15,7 @@ $id: http://devicetree.org/schemas/cpu.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: Common cpu node binding +title: CPU node common properties maintainers: - Devicetree Specification Mailing List From 6fc2e30810f6cfef1d756cb146f5a68b0f1973d0 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 21 Jun 2023 15:07:39 -0600 Subject: [PATCH 368/505] meta-schemas: Ensure "enum" contains only strings or integers Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 959c605a..00b34065 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -144,8 +144,14 @@ properties: const: type: [ integer, string ] enum: + description: '"enum" must be an array of either integers or strings' type: array uniqueItems: true + oneOf: + - items: + type: integer + - items: + type: string if: $ref: "#/definitions/sub-schemas" items: From 470b5221de68a7a21e59698c2d4bc25b49ca11cb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 23 Jun 2023 16:12:01 -0600 Subject: [PATCH 369/505] fixups: Handle 'multipleOf' keyword in schemas The fixups were failing to handle 'multipleOf' in scalar schemas resulting in 'multipleOf' having no effect. Signed-off-by: Rob Herring --- dtschema/fixups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index 81dc64b8..c8434f23 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -12,7 +12,7 @@ def _extract_single_schemas(subschema): - scalar_keywords = ('const', 'enum', 'pattern', 'minimum', 'maximum') + scalar_keywords = ('const', 'enum', 'pattern', 'minimum', 'maximum', 'multipleOf') return {k: subschema.pop(k) for k in scalar_keywords if k in subschema} From 33cbf965af9701c459056b004a82853a510652fb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 26 Jun 2023 14:48:42 -0600 Subject: [PATCH 370/505] schemas: Allow '/' in compatible strings '/' is already in use, so allow it in compatible strings. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 6bf8f5aa..3c7c1ba4 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -22,7 +22,7 @@ properties: $ref: types.yaml#/definitions/string-array items: # Keep in sync with make_compatible_schema() - pattern: "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]+$" + pattern: "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._/]+$" cpus: description: Phandles to CPU nodes associated with the referring node. From 2945ab5df7f63df5b9be47391966aa605badeb4e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 26 Jun 2023 14:52:41 -0600 Subject: [PATCH 371/505] schemas: Allow node names starting with number It's valid for node names to start with a number (though not best practice). Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 3c7c1ba4..02f6fa98 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -70,7 +70,7 @@ patternProperties: type: [object, array, boolean, 'null'] # Anything with a '@' is definitely a node - "^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-fA-F]+(,[0-9a-fA-F]+)*$": + "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-fA-F]+(,[0-9a-fA-F]+)*$": type: object # Anything beginnning and ending with '__' is a generated node From 1ea798aa38383471512f545fe0ff17c67ea0cf27 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 26 Jun 2023 14:57:11 -0600 Subject: [PATCH 372/505] schemas: Allow 'status' for node names 'status' is used for some node names, so allow that in the schema. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 02f6fa98..28b695be 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -47,8 +47,10 @@ properties: $ref: types.yaml#/definitions/string enum: [ okay, disabled, reserved ] status: - $ref: types.yaml#/definitions/string - enum: [ okay, disabled, reserved ] + oneOf: + - type: object + - $ref: types.yaml#/definitions/string + enum: [ okay, disabled, reserved ] phandle: $ref: types.yaml#/definitions/uint32 From a4fe59b11b65ab0e6a1b2d81bb97d93cfc4ca322 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 26 Jun 2023 14:59:53 -0600 Subject: [PATCH 373/505] schemas: Allow 'fail' value for 'status' 'fail' is a defined value for 'status' in the DT spec, so allow it. 'fail-sss' where 'sss' is an error code is also defined, but there don't seem to be any users of it. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 28b695be..92fd04e1 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -45,12 +45,12 @@ properties: be just a stem name used to construct the full firmware filename(s). secure-status: $ref: types.yaml#/definitions/string - enum: [ okay, disabled, reserved ] + enum: [ okay, disabled, reserved, fail ] status: oneOf: - type: object - $ref: types.yaml#/definitions/string - enum: [ okay, disabled, reserved ] + enum: [ okay, disabled, reserved, fail ] phandle: $ref: types.yaml#/definitions/uint32 From 90ce246ba902102e66da8d587faae209818de99c Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Tue, 15 Nov 2022 17:09:01 +0200 Subject: [PATCH 374/505] Revert "Partially Revert "dtschema: add nanoamp unit"" A patch has been sent upstream to remove the $ref from -nanoamp properties. This reverts commit f5f03f655760e165c250aceac829fc3c4eddd43f. Signed-off-by: Cosmin Tanislav --- dtschema/meta-schemas/core.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index e1b6321c..9b375073 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -58,7 +58,7 @@ definitions: propertyNames: enum: [ description, deprecated ] - '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kelvin|kpascal)$': + '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|nanoamp|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kelvin|kpascal)$': allOf: - $ref: cell.yaml#/array - description: Standard unit suffix properties don't need a type $ref From 08ab41a21587b37efb6655a38de422ba82f26594 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 27 Jun 2023 16:11:57 -0600 Subject: [PATCH 375/505] Fix undocumented compatible check Despite the comment to keep make_compatible_schema() in sync with the common "compatible" schema, commit 33cbf965af97 ("schemas: Allow '/' in compatible strings") failed to do that. Fixes: 33cbf965af97 ("schemas: Allow '/' in compatible strings") Signed-off-by: Rob Herring --- dtschema/validator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index 55aaae6a..8d53b50b 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -216,7 +216,7 @@ def make_compatible_schema(schemas): for c in compatible_list: if prog.match(c): # Exclude the generic pattern - if c != '^[a-zA-Z0-9][a-zA-Z0-9,+\-._]+$': + if c != '^[a-zA-Z0-9][a-zA-Z0-9,+\-._/]+$': compat_sch += [{'pattern': c}] else: compat_sch[0]['enum'].append(c) From fd2e633f8c712ce95eb2297ef73d964719857e01 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 27 Jun 2023 16:36:30 +0200 Subject: [PATCH 376/505] schemas: property-units: Allow negative values for % units Some hardware has negative percentage adjustments. Allow it. Signed-off-by: Konrad Dybcio --- dtschema/schemas/property-units.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index 7a697fe4..1761b907 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -38,11 +38,11 @@ patternProperties: description: kilobytes per second "-percent$": - $ref: types.yaml#/definitions/uint32-array + $ref: types.yaml#/definitions/int32-array description: percentage "-bp$": - $ref: types.yaml#/definitions/uint32-array + $ref: types.yaml#/definitions/int32-array description: basis points (1/100 of a percent) # Time/Frequency From 87f43e667b442db14ab7d548b9767c2464ea84e7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Jul 2023 09:25:04 -0600 Subject: [PATCH 377/505] dt-validate: Fix schema limiting containing schema base path components Since commit bc164f9dc87e ("Split DTValidator class into 2 classes"), the schema filtering has used the $id value rather than the file path. This has broken users providing some of the base path. This case will also pass in a schema base path which is otherwise not needed any more. Use the schema base path to strip it from the filter/limit pattern. Signed-off-by: Rob Herring --- tools/dt-validate | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/dt-validate b/tools/dt-validate index 84924848..22f3d346 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -117,6 +117,12 @@ if __name__ == "__main__": show_unmatched = args.show_unmatched match_schema_file = args.limit + # Maintain prior behaviour which accepted file paths by stripping the file path + if args.url_path and args.limit: + for d in args.url_path.split(os.path.sep): + if d and match_schema_file.startswith(d): + match_schema_file = match_schema_file[(len(d) + 1):] + if args.preparse: sg = schema_group(args.preparse) elif args.schema: From 35e8abab800be4ab8723b10d63a18e56ed90d3ed Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 20 Jul 2023 10:11:34 -0600 Subject: [PATCH 378/505] dt-validate: Update help text that --limit option matches on schema $id The --limit option should be a value that matches on a schema $id value rather than a file path. That behavior is still supported but only if the --url-path option is given. As the --url-path option is otherwise unused now, mark it as deprecated. Signed-off-by: Rob Herring --- tools/dt-validate | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/dt-validate b/tools/dt-validate index 22f3d346..2f3fa612 100755 --- a/tools/dt-validate +++ b/tools/dt-validate @@ -102,13 +102,13 @@ if __name__ == "__main__": help="Filename or directory of devicetree DTB input file(s)") ap.add_argument('-s', '--schema', help="preparsed schema file or path to schema files") ap.add_argument('-p', '--preparse', help="preparsed schema file (deprecated, use '-s')") - ap.add_argument('-l', '--limit', help="limit validation to schema files matching substring") + ap.add_argument('-l', '--limit', help="limit validation to schemas with $id matching LIMIT substring") ap.add_argument('-m', '--show-unmatched', help="Print out node 'compatible' strings which don't match any schema.", action="store_true") ap.add_argument('-n', '--line-number', help="Obsolete", action="store_true") ap.add_argument('-v', '--verbose', help="verbose mode", action="store_true") - ap.add_argument('-u', '--url-path', help="Additional search path for references") + ap.add_argument('-u', '--url-path', help="Additional search path for references (deprecated)") ap.add_argument('-V', '--version', help="Print version number", action="version", version=dtschema.__version__) args = ap.parse_args() From 5a35adcbbfc49cac2e49e299c7788ba2f537565b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 24 Jul 2023 18:00:41 -0600 Subject: [PATCH 379/505] fixups: Fix adding node properties under additionalProperties Nodes with only an "additionalProperties" schema were not getting descended into, so the always allowed, automatic properties such as "status" and "phandle" were not getting added for those child nodes. This pattern is used when a child node can have any name. Signed-off-by: Rob Herring --- dtschema/fixups.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index c8434f23..8102bb2b 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -348,9 +348,12 @@ def fixup_sub_schema(schema, is_prop): schema.pop('additionalProperties', None) for k, v in schema.items(): - if k in ['select', 'if', 'then', 'else', 'additionalProperties', 'not']: + if k in ['select', 'if', 'then', 'else', 'not']: fixup_sub_schema(v, False) + if k in ['additionalProperties']: + fixup_sub_schema(v, True) + if k in ['allOf', 'anyOf', 'oneOf']: for subschema in v: fixup_sub_schema(subschema, True) From 51974a03ce242fc9b573eafe0d3791a89a4c522f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 25 Jul 2023 11:28:50 -0600 Subject: [PATCH 380/505] meta-schemas: Allow 'additionalProperties' schema on its own If 'additionalProperties' is a schema rather than true/false, allow it on its own. It is used when any child node name is allowed. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 00b34065..69840569 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -87,10 +87,15 @@ dependentSchemas: $ref: "#/definitions/scalar-prop-list" additionalProperties: description: "'additionalProperties' depends on 'properties' or 'patternProperties'" - anyOf: - - required: [ type ] - - required: [ properties ] - - required: [ patternProperties ] + if: + properties: + additionalProperties: + type: boolean + then: + anyOf: + - required: [ type ] + - required: [ properties ] + - required: [ patternProperties ] dependentRequired: # Ensure only valid combinations of if/then/else are present From c1e73ebea9fc07f7d7848f304301f755f1278a67 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 25 Jul 2023 17:10:56 -0600 Subject: [PATCH 381/505] fixups: Further refine implicit node properties handling We only need to add implicit node properties if "additionalProperties" or "unevaluatedProperties" are present and not True. Otherwise, there is no restriction on undefined properties. With this, we can drop the 'is_prop' param from fixup_sub_schema(). Signed-off-by: Rob Herring --- dtschema/fixups.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index 8102bb2b..e3652863 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -333,14 +333,13 @@ def fixup_interrupts(schema): } -def fixup_sub_schema(schema, is_prop): +def fixup_sub_schema(schema): if not isinstance(schema, dict): return schema.pop('description', None) fixup_interrupts(schema) - if is_prop: - fixup_node_props(schema) + fixup_node_props(schema) # 'additionalProperties: true' doesn't work with 'unevaluatedProperties', so # remove it. It's in the schemas for common (incomplete) schemas. @@ -348,15 +347,12 @@ def fixup_sub_schema(schema, is_prop): schema.pop('additionalProperties', None) for k, v in schema.items(): - if k in ['select', 'if', 'then', 'else', 'not']: - fixup_sub_schema(v, False) - - if k in ['additionalProperties']: - fixup_sub_schema(v, True) + if k in ['select', 'if', 'then', 'else', 'not', 'additionalProperties']: + fixup_sub_schema(v) if k in ['allOf', 'anyOf', 'oneOf']: for subschema in v: - fixup_sub_schema(subschema, True) + fixup_sub_schema(subschema) if k not in ['dependentRequired', 'dependentSchemas', 'dependencies', 'properties', 'patternProperties', '$defs']: continue @@ -371,15 +367,15 @@ def fixup_sub_schema(schema, is_prop): walk_properties(prop, v[prop]) # Recurse to check for {properties,patternProperties} in each prop - fixup_sub_schema(v[prop], True) + fixup_sub_schema(v[prop]) fixup_schema_to_201909(schema) def fixup_node_props(schema): - if not {'properties', 'patternProperties', 'unevaluatedProperties', 'additionalProperties'} & schema.keys(): - return - if ('additionalProperties' in schema and schema['additionalProperties'] is True) or \ + # If no restrictions on undefined properties, then no need to add any implicit properties + if (not {'unevaluatedProperties', 'additionalProperties'} & schema.keys()) or \ + ('additionalProperties' in schema and schema['additionalProperties'] is True) or \ ('unevaluatedProperties' in schema and schema['unevaluatedProperties'] is True): return @@ -484,4 +480,4 @@ def fixup_schema(schema): schema.pop('historical', None) add_select_schema(schema) - fixup_sub_schema(schema, True) + fixup_sub_schema(schema) From 3832d87b42efeead08b4b29080ceb638542fa482 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 27 Jul 2023 15:15:11 -0600 Subject: [PATCH 382/505] schema: Print the correct meta-schema in error messages Commit bc164f9dc87e ("Split DTValidator class into 2 classes") broke printing the correct meta-schema in error messages. The check for 'p in schema' is wrong because p can be a list index value. Signed-off-by: Rob Herring --- dtschema/schema.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dtschema/schema.py b/dtschema/schema.py index aa2031d2..9ffbd79e 100644 --- a/dtschema/schema.py +++ b/dtschema/schema.py @@ -117,8 +117,7 @@ def annotate_error(self, error, schema, path): if '$id' in schema and isinstance(schema['$id'], str): error.schema_file = schema['$id'] - if p in schema: - schema = schema[p] + schema = schema[p] if isinstance(schema, dict): if 'description' in schema and isinstance(schema['description'], str): From fd1ee337d7ce314ada8b3b3c07c258ecbb328318 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 27 Jul 2023 15:08:36 -0600 Subject: [PATCH 383/505] schema: Drop jsonschema 3.2.0 schema path work-around jsonschema version >=4.1.2 has been required for some time. Drop the work-around for the schema paths containing 'if'. Signed-off-by: Rob Herring --- dtschema/schema.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dtschema/schema.py b/dtschema/schema.py index 9ffbd79e..054da612 100644 --- a/dtschema/schema.py +++ b/dtschema/schema.py @@ -101,13 +101,7 @@ def annotate_error(self, error, schema, path): self.validator.resolver.push_scope(scope) ref_depth = 1 - lastp = '' for p in path: - # json-schema 3.2.0 includes 'if' in schema path - if lastp != 'properties' and p == 'if': - continue - lastp = p - while '$ref' in schema and isinstance(schema['$ref'], str): ref = self.validator.resolver.resolve(schema['$ref']) schema = ref[1] From e87ba2f515392c2a4694642063efb43023331ff6 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 4 Aug 2023 09:31:57 -0600 Subject: [PATCH 384/505] meta-schemas: Ensure schema contraint types match the type referenced Add a meta-schema to ensure an integer type has integer constraints and a string type has string constraints. This prevents trying to use defines for integer constraints. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 1 + dtschema/meta-schemas/types.yaml | 39 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 dtschema/meta-schemas/types.yaml diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 69840569..243d4453 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -54,6 +54,7 @@ definitions: allOf: - $ref: "#" - $ref: items.yaml# + - $ref: types.yaml# propertyNames: # The subset of keywords allowed for sub-schema anyOf: diff --git a/dtschema/meta-schemas/types.yaml b/dtschema/meta-schemas/types.yaml new file mode 100644 index 00000000..d653c137 --- /dev/null +++ b/dtschema/meta-schemas/types.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2023 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/meta-schemas/types.yaml# +$schema: https://json-schema.org/draft/2019-09/schema + +description: Checks for schemas with a defined type + +allOf: + - if: + properties: + $ref: + pattern: 'u?int(8|16|32|64)$' + required: + - $ref + then: + description: An integer type must have integer constraints + properties: + const: + type: integer + enum: + items: + type: integer + - if: + properties: + $ref: + pattern: 'string$' + required: + - $ref + then: + description: A string type must have string constraints + properties: + const: + type: string + enum: + items: + type: string + From d5e5147b98ffe2bf8b9ed51763a0edb055064eaa Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 9 Aug 2023 13:28:23 -0600 Subject: [PATCH 385/505] Convert setup.py to pyproject.toml Use of setup.py has been superseeded by pyproject.toml (and setup.cfg before that). Now with the latest versions of pip/setuptools in Debian, there's a warning when running editable install: DeprecationWarning: pkg_resources is deprecated as an API. When last looked at pyproject.toml, editable installs weren't supported, but they are now. So let's move over to the latest and greatest to avoid this warning. Signed-off-by: Rob Herring --- pyproject.toml | 46 ++++++++++++++++++++++++++++++++++++ setup.py | 63 -------------------------------------------------- 2 files changed, 46 insertions(+), 63 deletions(-) create mode 100644 pyproject.toml delete mode 100755 setup.py diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..6fc9bb7a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,46 @@ +[build-system] +requires = ["setuptools>=61", "setuptools_scm[toml]>=6.2"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +write_to = "dtschema/version.py" + +[project] +name = "dtschema" +description = "DeviceTree validation schema and tools" +readme = "README.md" +requires-python = ">=3.7" +license = {file = "LICENSE.txt"} +authors = [ + {name = "Rob Herring", email = "robh@kernel.org"}, +] + +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Intended Audience :: Developers", +] +dynamic = ["version"] + +dependencies = [ + "ruamel.yaml>0.15.69", + "jsonschema>=4.1.2,<4.18", + "rfc3987", + "pylibfdt", +] + +[project.urls] +Homepage="https://github.com/devicetree-org/dt-schema" +Source="https://github.com/devicetree-org/dt-schema" + +[tool.setuptools] +script-files = [ + 'tools/dt-check-compatible', + 'tools/dt-validate', + 'tools/dt-doc-validate', + 'tools/dt-mk-schema', + 'tools/dt-extract-example', + 'tools/dt-extract-props', + 'tools/dtb2py' +] diff --git a/setup.py b/setup.py deleted file mode 100755 index 70419838..00000000 --- a/setup.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: BSD-2-Clause -# Copyright 2018 Linaro Ltd. - -import setuptools -import glob -import os - -with open("README.md", "r") as fh: - long_description = fh.read() - -data_files = [] -os.chdir('dtschema') -for filename in glob.iglob("schemas/**/*.yaml", recursive=True): - data_files.append(filename) -for filename in glob.iglob("meta-schemas/**/*.yaml", recursive=True): - data_files.append(filename) -os.chdir('..') - -setuptools.setup( - name="dtschema", - use_scm_version={ - 'write_to': 'dtschema/version.py', - 'write_to_template': '__version__ = "{version}"', - }, - setup_requires = ['setuptools_scm'], - author="Rob Herring", - author_email="robh@kernel.org", - description="DeviceTree validation schema and tools", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/devicetree-org/dt-schema", - license="BSD", - license_files=["LICENSE.txt"], - - packages=['dtschema'], - package_data={'dtschema': data_files}, - - scripts=[ - 'tools/dt-check-compatible', - 'tools/dt-validate', - 'tools/dt-doc-validate', - 'tools/dt-mk-schema', - 'tools/dt-extract-example', - 'tools/dt-extract-props', - 'tools/dtb2py' - ], - - python_requires='>=3.5', - - install_requires=[ - 'ruamel.yaml>0.15.69', - 'jsonschema >=4.1.2, <4.18', - 'rfc3987', - 'pylibfdt', - ], - - classifiers=[ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", - ], -) From 3815da51a138619f443abcf2f821ca0a6fd57949 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 8 May 2023 12:50:06 +0530 Subject: [PATCH 386/505] dt-bindings: u-boot: Add variables for bootscript location Add bootscr-address and bootscr-ram-offset properties to help in easier picking of boot script file when automated flows are used. The bootscr-address holds the full 64 bit address of the bootscript file. The bootscr-ram-offset holds the offset address of the bootscript file from the start of the ram base in systems with RAM detection. Co-develop-by: Algapally Santosh Sagar Signed-off-by: Algapally Santosh Sagar Signed-off-by: Michal Simek --- dtschema/schemas/options/u-boot.yaml | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/dtschema/schemas/options/u-boot.yaml b/dtschema/schemas/options/u-boot.yaml index 71dfda71..c9894ff5 100644 --- a/dtschema/schemas/options/u-boot.yaml +++ b/dtschema/schemas/options/u-boot.yaml @@ -71,6 +71,28 @@ properties: 2: use simplified command line (e.g. avoid hush) 3... reserved + bootscr-address: + $ref: /schemas/types.yaml#/definitions/uint64 + default: 0x0 + description: + Holds the full address of the boot script file. It helps in making + automated flow easier by fetching the 64bit address directly from DT. + Value should be automatically copied to the U-Boot 'scriptaddr' variable. + When it is defined, bootscr-ram-offset property should be ignored. + Actually only one of them should be present in the DT. + + bootscr-ram-offset: + $ref: /schemas/types.yaml#/definitions/uint64 + default: 0x0 + description: + Holds the boot script file offset from the start of the ram base address. + Platforms with run-time RAM-detection algorithms should use this property + because it is not clear exactly where the script address should be placed. + Using it will provide the option to specify boot script offset from + detected RAM start. The U-Boot 'scriptaddr' variable should be composed as + detected RAM start plus value of bootscr-ram-offset property. + It should be used only when bootscr-address is not defined. + silent-console: $ref: /schemas/types.yaml#/definitions/uint32 default: 0 @@ -91,6 +113,13 @@ properties: required: - compatible +if: + required: + - bootscr-address +then: + properties: + bootscr-ram-offset: false + additionalProperties: false examples: @@ -101,6 +130,7 @@ examples: bootcmd = "vboot go auto"; bootdelay-sec = <(-1)>; bootsecure = <1>; + bootscr-address = /bits/ 64 <0x1000>; silent-console = <1>; }; }; From 58bc36a1c531be6eaf0354e34c518c46efc8cad7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 29 Aug 2023 15:28:44 -0500 Subject: [PATCH 387/505] validator: Avoid infinite recursion when walking $refs to extract property types With a new schema using recursive $ref's, I managed to hit a RecursionError. The simple fix is to just bail out when we hit the limit. Ideally, we'd detect this sooner, but it should be rare enough. Signed-off-by: Rob Herring --- dtschema/validator.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index 8d53b50b..74ae6479 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -51,7 +51,11 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): for p in sch_path: tmp_subschema = tmp_subschema[p] #print(propname, sch_path, tmp_subschema, file=sys.stderr) - _extract_prop_type(props, schema, propname, tmp_subschema, is_pattern) + try: + _extract_prop_type(props, schema, propname, tmp_subschema, is_pattern) + except RecursionError: + # We should probably detect this + pass for k in subschema.keys() & {'allOf', 'oneOf', 'anyOf'}: for v in subschema[k]: From 3d59c52d6cd1141a6eca32072c8fa9d89fee08c2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 29 Aug 2023 14:29:19 -0500 Subject: [PATCH 388/505] schemas: Add cpu-map node binding Add the cpu-map node binding schema. It is based on the free form text binding in Linux kernel cpu-topology.txt. Signed-off-by: Rob Herring --- dtschema/schemas/cpu-map.yaml | 255 ++++++++++++++++++++++++++++++++++ dtschema/schemas/cpus.yaml | 3 + 2 files changed, 258 insertions(+) create mode 100644 dtschema/schemas/cpu-map.yaml diff --git a/dtschema/schemas/cpu-map.yaml b/dtschema/schemas/cpu-map.yaml new file mode 100644 index 00000000..c68ec0ad --- /dev/null +++ b/dtschema/schemas/cpu-map.yaml @@ -0,0 +1,255 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-clause +# Copyright 2013,2023 Arm, Ltd. +# +# Based on cpu-topology.txt binding from Linux kernel +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/cpu-map.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: CPU Topology nodes + +maintainers: + - devicetree-spec@vger.kernel.org + +description: | + In a SMP system, the hierarchy of CPUs is defined through three entities that + are used to describe the layout of physical CPUs in the system: + + - socket + - cluster + - core + - thread + + The bottom hierarchy level sits at core or thread level depending on whether + symmetric multi-threading (SMT) is supported or not. + + For instance in a system where CPUs support SMT, "cpu" nodes represent all + threads existing in the system and map to the hierarchy level "thread" above. + In systems where SMT is not supported "cpu" nodes represent all cores present + in the system and map to the hierarchy level "core" above. + + CPU topology bindings allow one to associate cpu nodes with hierarchical groups + corresponding to the system hierarchy; syntactically they are defined as device + tree nodes. + + Currently, only ARM/RISC-V intend to use this cpu topology binding but it may be + used for any other architecture as well. + + The cpu nodes, as per bindings defined in [4], represent the devices that + correspond to physical CPUs and are to be mapped to the hierarchy levels. + + A topology description containing phandles to cpu nodes that are not compliant + with bindings standardized in [4] is therefore considered invalid. + + =========================================== + 2 - cpu-map node + =========================================== + + The ARM/RISC-V CPU topology is defined within the cpu-map node, which is a direct + child of the cpus node and provides a container where the actual topology + nodes are listed. + + The cpu-map node can only contain 4 types of child nodes: + + - socket node + - cluster node + - core node + - thread node + + The nodes describing the CPU topology (socket/cluster/core/thread) can + only be defined within the cpu-map node and every core/thread in the + system must be defined within the topology. Any other configuration is + invalid and therefore must be ignored. + + =========================================== + 2.1 - cpu-map child nodes naming convention + =========================================== + + cpu-map child nodes must follow a naming convention where the node name + must be "socketN", "clusterN", "coreN", "threadN" depending on the node type + (ie socket/cluster/core/thread) (where N = {0, 1, ...} is the node number; nodes + which are siblings within a single common parent node must be given a unique and + sequential N value, starting from 0). + cpu-map child nodes which do not share a common parent node can have the same + name (ie same number N as other cpu-map child nodes at different device tree + levels) since name uniqueness will be guaranteed by the device tree hierarchy. + + =========================================== + [1] ARM Linux kernel documentation + Documentation/devicetree/bindings/arm/cpus.yaml + [2] Devicetree NUMA binding description + Documentation/devicetree/bindings/numa.txt + [3] RISC-V Linux kernel documentation + Documentation/devicetree/bindings/riscv/cpus.yaml + [4] https://www.devicetree.org/specifications/ + +$defs: + cluster: + type: object + oneOf: + - additionalProperties: false + patternProperties: + '^cluster[0-9]+$': + $ref: '#/$defs/cluster' + - additionalProperties: false + patternProperties: + '^core[0-9]+$': + $ref: '#/$defs/core' + + core: + type: object + oneOf: + - additionalProperties: false + patternProperties: + '^thread[0-9]+$': + $ref: '#/$defs/core' + - additionalProperties: false + properties: + cpu: + $ref: /schemas/types.yaml#/definitions/phandle + required: + - cpu + +properties: + $nodename: + const: cpu-map + +patternProperties: + '^(socket|cluster)[0-9]+$': + $ref: '#/$defs/cluster' + description: | + The cpu-map node's child nodes can be: + + - one or more cluster nodes or + - one or more socket nodes in a multi-socket system. A system can + contain single or multiple physical socket. + The association of sockets and NUMA nodes is beyond the scope of this + binding, please refer [2] for NUMA bindings. + +additionalProperties: false + +examples: + - | + # 16-cpu system, two clusters of clusters in a single physical socket + cpu-map { + socket0 { + cluster0 { + cluster0 { + core0 { + thread0 { + cpu = <&CPU0>; + }; + thread1 { + cpu = <&CPU1>; + }; + }; + + core1 { + thread0 { + cpu = <&CPU2>; + }; + thread1 { + cpu = <&CPU3>; + }; + }; + }; + + cluster1 { + core0 { + thread0 { + cpu = <&CPU4>; + }; + thread1 { + cpu = <&CPU5>; + }; + }; + + core1 { + thread0 { + cpu = <&CPU6>; + }; + thread1 { + cpu = <&CPU7>; + }; + }; + }; + }; + + cluster1 { + cluster0 { + core0 { + thread0 { + cpu = <&CPU8>; + }; + thread1 { + cpu = <&CPU9>; + }; + }; + core1 { + thread0 { + cpu = <&CPU10>; + }; + thread1 { + cpu = <&CPU11>; + }; + }; + }; + + cluster1 { + core0 { + thread0 { + cpu = <&CPU12>; + }; + thread1 { + cpu = <&CPU13>; + }; + }; + core1 { + thread0 { + cpu = <&CPU14>; + }; + thread1 { + cpu = <&CPU15>; + }; + }; + }; + }; + }; + }; + + - | + # 2 Clusters of 4 cores each with no SMT + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + core2 { + cpu = <&CPU2>; + }; + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + core1 { + cpu = <&CPU5>; + }; + core2 { + cpu = <&CPU6>; + }; + core3 { + cpu = <&CPU7>; + }; + }; + }; + +... diff --git a/dtschema/schemas/cpus.yaml b/dtschema/schemas/cpus.yaml index e72b1667..a480dd3a 100644 --- a/dtschema/schemas/cpus.yaml +++ b/dtschema/schemas/cpus.yaml @@ -46,6 +46,9 @@ properties: '#size-cells': const: 0 + cpu-map: + $ref: /schemas/cpu-map.yaml# + patternProperties: '^cpu@[0-9a-f]+$': $ref: cpu.yaml# From 8c3fe539456b42876595a44db9912b598f4b8a14 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 29 Aug 2023 15:46:35 -0500 Subject: [PATCH 389/505] schemas: Add numa-distance-map-v1 binding Add a schema for 'distance-map' nodes based on numa.txt binding in the Linux kernel. Signed-off-by: Rob Herring --- dtschema/schemas/numa-distance-map-v1.yaml | 103 +++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 dtschema/schemas/numa-distance-map-v1.yaml diff --git a/dtschema/schemas/numa-distance-map-v1.yaml b/dtschema/schemas/numa-distance-map-v1.yaml new file mode 100644 index 00000000..4646f6c5 --- /dev/null +++ b/dtschema/schemas/numa-distance-map-v1.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-clause +# Copyright 2023 Arm, Ltd. +# +# Based on numa.txt binding from Linux kernel +# Copyright 2016 Cavium Networks, Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/numa-distance-map-v1.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NUMA distance-map node + +maintainers: + - devicetree-spec@vger.kernel.org + +description: | + Systems employing a Non Uniform Memory Access (NUMA) architecture contain + collections of hardware resources including processors, memory, and I/O buses, + that comprise what is commonly known as a NUMA node. + Processor accesses to memory within the local NUMA node is generally faster + than processor accesses to memory outside of the local NUMA node. + DT defines interfaces that allow the platform to convey NUMA node + topology information to OS. + + The optional device tree node "distance-map" describes the relative distance + (memory latency) between all numa nodes. There must be only one device node + distance-map which must reside in the root node. If the distance-map node is + not present, a default distance-matrix is used. + +properties: + $nodename: + const: distance-map + + compatible: + const: numa-distance-map-v1 + + distance-matrix: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + items: + items: + - description: 1st NUMA node ID + - description: 2nd NUMA node ID + - description: distance from 1st to 2nd NUMA node + minimum: 10 + description: | + Defines a matrix to describe the relative distances between all numa + nodes. It is represented as a list of node pairs and their relative + distance. + + Note: + 1. Each entry represents distance from first node to second node. + The distances are equal in either direction. + 2. The distance from a node to self (local distance) is represented + with value 10 and all internode distance should be represented with + a value greater than 10. + 3. distance-matrix should have entries in lexicographical ascending + order of nodes. + + Example: + 4 nodes connected in mesh/ring topology as below, + + 0_______20______1 + | | + | | + 20 20 + | | + | | + |_______________| + 3 20 2 + + If relative distance for each hop is 20, + then internode distance would be, + 0 -> 1 = 20 + 1 -> 2 = 20 + 2 -> 3 = 20 + 3 -> 0 = 20 + 0 -> 2 = 40 + 1 -> 3 = 40 + +additionalProperties: false + +examples: + - | + distance-map { + compatible = "numa-distance-map-v1"; + distance-matrix = <0 0 10>, + <0 1 20>, + <0 2 40>, + <0 3 20>, + <1 0 20>, + <1 1 10>, + <1 2 20>, + <1 3 40>, + <2 0 40>, + <2 1 20>, + <2 2 10>, + <2 3 20>, + <3 0 20>, + <3 1 40>, + <3 2 20>, + <3 3 10>; + }; +... From 8e9bbadcdc4318548d8df316945e87db88e62a86 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 30 Aug 2023 06:53:23 -0500 Subject: [PATCH 390/505] validator: Take 2 on avoiding infinite recursion Trapping on RecursionError doesn't work on cpython <=3.8 as a stack overflow occurs. Instead, handle this properly and stop recursion if the property is already added from the same schema. Signed-off-by: Rob Herring --- dtschema/validator.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index 74ae6479..a2f607ce 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -46,16 +46,16 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): # We only support local refs if '$ref' in subschema and subschema['$ref'].startswith('#/'): + if propname in props: + for p in props[propname]: + if schema['$id'] in p['$id']: + return sch_path = subschema['$ref'].split('/')[1:] tmp_subschema = schema for p in sch_path: tmp_subschema = tmp_subschema[p] #print(propname, sch_path, tmp_subschema, file=sys.stderr) - try: - _extract_prop_type(props, schema, propname, tmp_subschema, is_pattern) - except RecursionError: - # We should probably detect this - pass + _extract_prop_type(props, schema, propname, tmp_subschema, is_pattern) for k in subschema.keys() & {'allOf', 'oneOf', 'anyOf'}: for v in subschema[k]: From c9d412a42b0b52eae32e312095462ae4ca5be95d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 30 Aug 2023 17:17:49 -0600 Subject: [PATCH 391/505] Add reserved-memory Bring in this file from Linux v6.5 Signed-off-by: Simon Glass Link: https://lore.kernel.org/r/20230830231758.2561402-1-sjg@chromium.org Signed-off-by: Rob Herring --- .../reserved-memory/reserved-memory.yaml | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 dtschema/schemas/reserved-memory/reserved-memory.yaml diff --git a/dtschema/schemas/reserved-memory/reserved-memory.yaml b/dtschema/schemas/reserved-memory/reserved-memory.yaml new file mode 100644 index 00000000..c680e397 --- /dev/null +++ b/dtschema/schemas/reserved-memory/reserved-memory.yaml @@ -0,0 +1,181 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/reserved-memory/reserved-memory.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: /reserved-memory Child Node Common + +maintainers: + - devicetree-spec@vger.kernel.org + +description: > + Reserved memory is specified as a node under the /reserved-memory node. The + operating system shall exclude reserved memory from normal usage one can + create child nodes describing particular reserved (excluded from normal use) + memory regions. Such memory regions are usually designed for the special + usage by various device drivers. + + Each child of the reserved-memory node specifies one or more regions + of reserved memory. Each child node may either use a 'reg' property to + specify a specific range of reserved memory, or a 'size' property with + optional constraints to request a dynamically allocated block of + memory. + + Following the generic-names recommended practice, node names should + reflect the purpose of the node (ie. "framebuffer" or "dma-pool"). + Unit address (@
) should be appended to the name if the node + is a static allocation. + +properties: + reg: true + + size: + oneOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - $ref: /schemas/types.yaml#/definitions/uint64 + description: > + Length based on parent's \#size-cells. Size in bytes of memory to + reserve. + + alignment: + oneOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - $ref: /schemas/types.yaml#/definitions/uint64 + description: > + Length based on parent's \#size-cells. Address boundary for + alignment of allocation. + + alloc-ranges: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: > + Address and Length pairs. Specifies regions of memory that are + acceptable to allocate from. + + iommu-addresses: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: > + A list of phandle and specifier pairs that describe static IO virtual + address space mappings and carveouts associated with a given reserved + memory region. The phandle in the first cell refers to the device for + which the mapping or carveout is to be created. + + The specifier consists of an address/size pair and denotes the IO + virtual address range of the region for the given device. The exact + format depends on the values of the "#address-cells" and "#size-cells" + properties of the device referenced via the phandle. + + When used in combination with a "reg" property, an IOVA mapping is to + be established for this memory region. One example where this can be + useful is to create an identity mapping for physical memory that the + firmware has configured some hardware to access (such as a bootsplash + framebuffer). + + If no "reg" property is specified, the "iommu-addresses" property + defines carveout regions in the IOVA space for the given device. This + can be useful if a certain memory region should not be mapped through + the IOMMU. + + no-map: + type: boolean + description: > + Indicates the operating system must not create a virtual mapping + of the region as part of its standard mapping of system memory, + nor permit speculative access to it under any circumstances other + than under the control of the device driver using the region. + + reusable: + type: boolean + description: > + The operating system can use the memory in this region with the + limitation that the device driver(s) owning the region need to be + able to reclaim it back. Typically that means that the operating + system can use that region to store volatile or cached data that + can be otherwise regenerated or migrated elsewhere. + +allOf: + - if: + required: + - no-map + + then: + not: + required: + - reusable + + - if: + required: + - reusable + + then: + not: + required: + - no-map + +oneOf: + - oneOf: + - required: + - reg + + - required: + - size + + - oneOf: + # IOMMU reservations + - required: + - iommu-addresses + + # IOMMU mappings + - required: + - reg + - iommu-addresses + +additionalProperties: true + +examples: + - | + / { + compatible = "foo"; + model = "foo"; + + #address-cells = <2>; + #size-cells = <2>; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + adsp_resv: reservation-adsp { + /* + * Restrict IOVA mappings for ADSP buffers to the 512 MiB region + * from 0x40000000 - 0x5fffffff. Anything outside is reserved by + * the ADSP for I/O memory and private memory allocations. + */ + iommu-addresses = <&adsp 0x0 0x00000000 0x00 0x40000000>, + <&adsp 0x0 0x60000000 0xff 0xa0000000>; + }; + + fb: framebuffer@90000000 { + reg = <0x0 0x90000000 0x0 0x00800000>; + iommu-addresses = <&dc0 0x0 0x90000000 0x0 0x00800000>; + }; + }; + + bus@0 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x40000000>; + + adsp: adsp@2990000 { + reg = <0x2990000 0x2000>; + memory-region = <&adsp_resv>; + }; + + dc0: display@15200000 { + reg = <0x15200000 0x10000>; + memory-region = <&fb>; + }; + }; + }; +... From 7871a3eca2b379406476e687e9a04aab77b17aa1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 30 Aug 2023 17:17:50 -0600 Subject: [PATCH 392/505] Bring in some other reserved-memory files Add schema yaml files from v6.5 which are not vendor-specific, nor Linux-specific. Signed-off-by: Simon Glass Link: https://lore.kernel.org/r/20230830231758.2561402-2-sjg@chromium.org Signed-off-by: Rob Herring --- .../schemas/reserved-memory/framebuffer.yaml | 52 ++++++++++ .../reserved-memory/memory-region.yaml | 40 ++++++++ .../reserved-memory/shared-dma-pool.yaml | 97 +++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100644 dtschema/schemas/reserved-memory/framebuffer.yaml create mode 100644 dtschema/schemas/reserved-memory/memory-region.yaml create mode 100644 dtschema/schemas/reserved-memory/shared-dma-pool.yaml diff --git a/dtschema/schemas/reserved-memory/framebuffer.yaml b/dtschema/schemas/reserved-memory/framebuffer.yaml new file mode 100644 index 00000000..851ec24d --- /dev/null +++ b/dtschema/schemas/reserved-memory/framebuffer.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/reserved-memory/framebuffer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: /reserved-memory framebuffer node + +maintainers: + - devicetree-spec@vger.kernel.org + +allOf: + - $ref: reserved-memory.yaml + +properties: + compatible: + const: framebuffer + description: > + This indicates a region of memory meant to be used as a framebuffer for + a set of display devices. It can be used by an operating system to keep + the framebuffer from being overwritten and use it as the backing memory + for a display device (such as simple-framebuffer). + +unevaluatedProperties: false + +examples: + - | + / { + compatible = "foo"; + model = "foo"; + #address-cells = <1>; + #size-cells = <1>; + + chosen { + framebuffer { + compatible = "simple-framebuffer"; + memory-region = <&fb>; + }; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + fb: framebuffer@80000000 { + compatible = "framebuffer"; + reg = <0x80000000 0x007e9000>; + }; + }; + }; +... diff --git a/dtschema/schemas/reserved-memory/memory-region.yaml b/dtschema/schemas/reserved-memory/memory-region.yaml new file mode 100644 index 00000000..592f180e --- /dev/null +++ b/dtschema/schemas/reserved-memory/memory-region.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/reserved-memory/memory-region.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Reserved Memory Region + +maintainers: + - devicetree-spec@vger.kernel.org + +description: | + Regions in the /reserved-memory node may be referenced by other device + nodes by adding a memory-region property to the device node. + +select: true + +properties: + memory-region: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: > + Phandle to a /reserved-memory child node assigned to the device. + + memory-region-names: + $ref: /schemas/types.yaml#/definitions/string-array + description: > + A list of names, one for each corresponding entry in the + memory-region property + +additionalProperties: true + +examples: + - | + fb0: video@12300000 { + /* ... */ + reg = <0x12300000 0x1000>; + memory-region = <&display_reserved>; + }; + +... diff --git a/dtschema/schemas/reserved-memory/shared-dma-pool.yaml b/dtschema/schemas/reserved-memory/shared-dma-pool.yaml new file mode 100644 index 00000000..457de092 --- /dev/null +++ b/dtschema/schemas/reserved-memory/shared-dma-pool.yaml @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/reserved-memory/shared-dma-pool.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: /reserved-memory DMA pool + +maintainers: + - devicetree-spec@vger.kernel.org + +allOf: + - $ref: reserved-memory.yaml + +properties: + compatible: + oneOf: + - const: shared-dma-pool + description: > + This indicates a region of memory meant to be used as a shared + pool of DMA buffers for a set of devices. It can be used by an + operating system to instantiate the necessary pool management + subsystem if necessary. + + - const: restricted-dma-pool + description: > + This indicates a region of memory meant to be used as a pool + of restricted DMA buffers for a set of devices. The memory + region would be the only region accessible to those devices. + When using this, the no-map and reusable properties must not + be set, so the operating system can create a virtual mapping + that will be used for synchronization. The main purpose for + restricted DMA is to mitigate the lack of DMA access control + on systems without an IOMMU, which could result in the DMA + accessing the system memory at unexpected times and/or + unexpected addresses, possibly leading to data leakage or + corruption. The feature on its own provides a basic level of + protection against the DMA overwriting buffer contents at + unexpected times. However, to protect against general data + leakage and system memory corruption, the system needs to + provide way to lock down the memory access, e.g., MPU. Note + that since coherent allocation needs remapping, one must set + up another device coherent pool by shared-dma-pool and use + dma_alloc_from_dev_coherent instead for atomic coherent + allocation. + + linux,cma-default: + type: boolean + description: > + If this property is present, then Linux will use the region for + the default pool of the contiguous memory allocator. + + linux,dma-default: + type: boolean + description: > + If this property is present, then Linux will use the region for + the default pool of the consistent DMA allocator. + +if: + properties: + compatible: + contains: + const: restricted-dma-pool +then: + properties: + no-map: false + reusable: false + +unevaluatedProperties: false + +examples: + - | + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x4000000>; + alignment = <0x2000>; + linux,cma-default; + }; + + display_reserved: framebuffer@78000000 { + reg = <0x78000000 0x800000>; + }; + + restricted_dma_reserved: restricted-dma-pool@50000000 { + compatible = "restricted-dma-pool"; + reg = <0x50000000 0x4000000>; + }; + }; + +... From 68c16a4564e21f402f7058b5407a2d3baef4f202 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 8 Sep 2023 11:40:07 -0500 Subject: [PATCH 393/505] schema.py: Remove stray typeSize() Remove duplicate typeSize method which is not used in schema.py, but lives in validator.py. Signed-off-by: Rob Herring --- dtschema/schema.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/dtschema/schema.py b/dtschema/schema.py index 054da612..3cae9afa 100644 --- a/dtschema/schema.py +++ b/dtschema/schema.py @@ -46,16 +46,6 @@ def get_line_col(tree, path, obj=None): return -1, -1 -def typeSize(validator, typeSize, instance, schema): - try: - size = instance[0][0].size - except: - size = 32 - - if typeSize != size: - yield jsonschema.ValidationError("size is %r, expected %r" % (size, typeSize)) - - class DTSchema(dict): DtValidator = jsonschema.validators.extend( jsonschema.Draft201909Validator, From 9d5cd6a103a55bbf1d5951762e8cee7ab7bbdf7b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 8 Sep 2023 09:31:07 -0500 Subject: [PATCH 394/505] validator: Refactor process_schemas() common parts We have identical code to process a schema and then handle the result. Refactor process_schemas() with a new method to implement this part. While we're here, improve the warning message about duplicate $id value to indicate what we do with the duplicate (ignore it). Signed-off-by: Rob Herring --- dtschema/validator.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index a2f607ce..eed39439 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -266,19 +266,26 @@ def process_schema(filename): return schema +def _add_schema(schemas, filename): + sch = process_schema(os.path.abspath(filename)) + if not sch or '$id' not in sch: + return False + if sch['$id'] in schemas: + print(f"{sch['$filename']}: warning: ignoring duplicate '$id' value '{sch['$id']}'", file=sys.stderr) + return False + else: + schemas[sch['$id']] = sch + + return True + + def process_schemas(schema_paths, core_schema=True): schemas = {} for filename in schema_paths: if not os.path.isfile(filename): continue - sch = process_schema(os.path.abspath(filename)) - if not sch or '$id' not in sch: - continue - if sch['$id'] in schemas: - print(f"{os.path.abspath(filename)}: duplicate '$id' value '{sch['$id']}'", file=sys.stderr) - else: - schemas[sch['$id']] = sch + _add_schema(schemas, filename) if core_schema: schema_paths.append(os.path.join(schema_basedir, 'schemas/')) @@ -289,13 +296,8 @@ def process_schemas(schema_paths, core_schema=True): continue for filename in glob.iglob(os.path.join(os.path.abspath(path), "**/*.yaml"), recursive=True): - sch = process_schema(os.path.abspath(filename)) - if sch: + if _add_schema(schemas, filename): count += 1 - if sch['$id'] in schemas: - print(f"{os.path.abspath(filename)}: duplicate '$id' value '{sch['$id']}'", file=sys.stderr) - else: - schemas[sch['$id']] = sch if count == 0: print(f"warning: no schema found in path: {path}", file=sys.stderr) From 033d0b1430e0670ddeb58f60fbff0ecefccaa925 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 12 Sep 2023 13:48:34 -0500 Subject: [PATCH 395/505] Add '-bps' as a standard unit suffix for bits per second Signed-off-by: Rob Herring --- dtschema/fixups.py | 2 +- dtschema/meta-schemas/core.yaml | 2 +- dtschema/meta-schemas/vendor-props.yaml | 2 +- dtschema/schemas/property-units.yaml | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index e3652863..dae98b87 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -75,7 +75,7 @@ def _fixup_int_matrix(propname, subschema): int_array_re = re.compile('int(8|16|32|64)-array') -unit_types_re = re.compile('-(kBps|bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|microvolt|picofarads|(milli)?celsius|kelvin|kpascal)$') +unit_types_re = re.compile('-(bps|kBps|bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|microvolt|picofarads|(milli)?celsius|kelvin|kpascal)$') # Remove this once we remove array to matrix fixups known_array_props = { diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index 9b375073..1cfff770 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -58,7 +58,7 @@ definitions: propertyNames: enum: [ description, deprecated ] - '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|nanoamp|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kelvin|kpascal)$': + '-(bits|bps|kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|nanoamp|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kelvin|kpascal)$': allOf: - $ref: cell.yaml#/array - description: Standard unit suffix properties don't need a type $ref diff --git a/dtschema/meta-schemas/vendor-props.yaml b/dtschema/meta-schemas/vendor-props.yaml index 4381911c..2471ff7d 100644 --- a/dtschema/meta-schemas/vendor-props.yaml +++ b/dtschema/meta-schemas/vendor-props.yaml @@ -15,7 +15,7 @@ patternProperties: '-(gpio|gpios)$': true '-supply$': true '^rcar_sound,': true - '-(bits|-kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm)$': true + '-(bits|bps|kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm)$': true '-(nanoamp|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours)$': true '-(microvolt|(femto|pico)farads|celsius|millicelsius|kelvin|kpascal)$': true diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index 1761b907..21871b1c 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -33,6 +33,10 @@ patternProperties: $ref: types.yaml#/definitions/uint32-array description: number of bits + "-bps$": + $ref: types.yaml#/definitions/uint32 + description: bits per second + "-kBps$": $ref: types.yaml#/definitions/uint32-array description: kilobytes per second From 5e5e6591c7471f2a2f2ac308cdf728cfad730be1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 19 Sep 2023 15:43:37 -0500 Subject: [PATCH 396/505] schemas: Add singular "cpu" property Add a "cpu" property as the singular form of "cpus" property. Like "cpus", we need to allow for node names as well. Signed-off-by: Rob Herring --- dtschema/schemas/dt-core.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 92fd04e1..dbace2f5 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -23,6 +23,12 @@ properties: items: # Keep in sync with make_compatible_schema() pattern: "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._/]+$" + cpu: + description: + Phandles to a CPU node associated with the referring node. + oneOf: + - type: object + - $ref: types.yaml#/definitions/phandle cpus: description: Phandles to CPU nodes associated with the referring node. From 772a5580c741e0acd1482a03479eb98002428760 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 27 Sep 2023 16:08:00 -0500 Subject: [PATCH 397/505] validator: Support getting property type based on a $ref to /properties/ path If a property is just a $ref to another property's schema, then it is the same type. So let's check if that property name has a type already. Note that this depends on the order properties are processed and may not help. Signed-off-by: Rob Herring --- dtschema/validator.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index eed39439..d4f13786 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -44,18 +44,26 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): if propname.startswith('$'): return + new_prop = {} + prop_type = None + # We only support local refs - if '$ref' in subschema and subschema['$ref'].startswith('#/'): - if propname in props: - for p in props[propname]: - if schema['$id'] in p['$id']: - return - sch_path = subschema['$ref'].split('/')[1:] - tmp_subschema = schema - for p in sch_path: - tmp_subschema = tmp_subschema[p] - #print(propname, sch_path, tmp_subschema, file=sys.stderr) - _extract_prop_type(props, schema, propname, tmp_subschema, is_pattern) + if '$ref' in subschema: + if subschema['$ref'].startswith('#/'): + if propname in props: + for p in props[propname]: + if schema['$id'] in p['$id']: + return + sch_path = subschema['$ref'].split('/')[1:] + tmp_subschema = schema + for p in sch_path: + tmp_subschema = tmp_subschema[p] + #print(propname, sch_path, tmp_subschema, file=sys.stderr) + _extract_prop_type(props, schema, propname, tmp_subschema, is_pattern) + elif '/properties/' in subschema['$ref']: + ref_prop = subschema['$ref'].split('/')[-1] + if ref_prop in props: + prop_type = props[ref_prop][0]['type'] for k in subschema.keys() & {'allOf', 'oneOf', 'anyOf'}: for v in subschema[k]: @@ -63,9 +71,6 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): props.setdefault(propname, []) - new_prop = {} - prop_type = None - if ('type' in subschema and subschema['type'] == 'object') or \ subschema.keys() & {'properties', 'patternProperties', 'additionalProperties'}: prop_type = 'node' @@ -95,8 +100,6 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): prop_type = None elif '$ref' in subschema and re.search(r'\.yaml#?$', subschema['$ref']): prop_type = 'node' - else: - prop_type = None new_prop['type'] = prop_type new_prop['$id'] = [schema['$id']] From 8e378d1db8dd61a0dde85609f8b77d291f25c087 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 27 Sep 2023 16:11:34 -0500 Subject: [PATCH 398/505] validator: Rework property type extraction to save properties without a type The current checking for properties having a type only checks vendor specific properties. This mostly works, but misses any property without a vendor prefix. It also doesn't allow vendor properties defining a type in one schema and then adding constraints in another. Instead, let's keep properties which don't have a type. First, we need to track any properties in the form of 'propname: true' and present a consistent result for no type. With this, we need to rework our processing of properties and splitting out of pattern properties. Signed-off-by: Rob Herring --- dtschema/validator.py | 49 ++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index d4f13786..da6c6358 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -38,10 +38,15 @@ def _merge_dim(dim1, dim2): def _extract_prop_type(props, schema, propname, subschema, is_pattern): - if not isinstance(subschema, dict): + if propname.startswith('$'): return - if propname.startswith('$'): + if not isinstance(subschema, dict): + if subschema is True: + default_type = {'type': None, '$id': [schema['$id']]} + if is_pattern: + default_type['regex'] = re.compile(propname) + props.setdefault(propname, [default_type]) return new_prop = {} @@ -173,40 +178,34 @@ def extract_types(schemas): return props - -def get_prop_types(schemas, want_missing_types=False, want_node_types=False): +def get_prop_types(schemas): pat_props = {} props = extract_types(schemas) # hack to remove aliases and generic patterns del props['^[a-z][a-z0-9\-]*$'] - props.pop('^[a-zA-Z][a-zA-Z0-9\\-_]{0,63}$', None) - props.pop('^.*$', None) - props.pop('.*', None) - # Remove node types - if not want_node_types: - for val in props.values(): - val[:] = [t for t in val if t['type'] != 'node'] - - # Remove all properties without a type - if not want_missing_types: - for val in props.values(): - val[:] = [t for t in val if t['type'] is not None] - - # Delete any entries now empty due to above operations + # Remove all node types + for val in props.values(): + val[:] = [t for t in val if t['type'] != 'node'] for key in [key for key in props if len(props[key]) == 0]: del props[key] # Split out pattern properties - for key in [key for key in props if len(props[key]) and 'regex' in props[key][0]]: + for key in [key for key in props if 'regex' in props[key][0]]: # Only want patternProperties with type and some amount of fixed string - if re.search(r'[0-9a-zA-F-]{3}', key): - #print(key, props[key], file=sys.stderr) + if props[key][0]['type'] is not None: pat_props[key] = props[key] del props[key] + # Delete any entries without a type, but matching a patternProperty + for key in [key for key in props if props[key][0]['type'] is None]: + for pat, val in pat_props.items(): + if val[0]['type'] and val[0]['regex'].search(key): + del props[key] + break + return [props, pat_props] @@ -411,9 +410,17 @@ def get_undocumented_compatibles(self, compatible_list): return undoc_compats + def check_missing_property_types(self): + for p, val in self.props.items(): + if val[0]['type'] is None: + for id in val[0]['$id']: + print(f"{self.schemas[id]['$filename']}: {p}: missing type definition", file=sys.stderr) + def make_property_type_cache(self): self.props, self.pat_props = get_prop_types(self.schemas) + self.check_missing_property_types() + for val in self.props.values(): for t in val: del t['$id'] From df71e72caaca29258b3dfd8bec156ca88e7d41b7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 27 Sep 2023 16:25:12 -0500 Subject: [PATCH 399/505] meta-schemas: Relax vendor-props meta-schema type checks Now that we check globally for properties with missing type, there's not a need to enforce that in the meta-schema. Doing it in the meta-schema is not very flexible as it doesn't allow defining a property in one place and adding just constraints in another place except for places we allow it (if/then/else schemas) or fail to walk (additionalProperties). Now an error from the global check will cause a schema author to add 'type' or a $ref. Then when one of those are present, the meta-schema will require 'description'. Signed-off-by: Rob Herring --- dtschema/meta-schemas/vendor-props.yaml | 60 +++++++------------------ test/schemas/bad-example.yaml | 2 +- 2 files changed, 16 insertions(+), 46 deletions(-) diff --git a/dtschema/meta-schemas/vendor-props.yaml b/dtschema/meta-schemas/vendor-props.yaml index 2471ff7d..b778fbf9 100644 --- a/dtschema/meta-schemas/vendor-props.yaml +++ b/dtschema/meta-schemas/vendor-props.yaml @@ -25,58 +25,28 @@ patternProperties: - description additionalProperties: - type: object + type: [boolean, object] description: Vendor specific properties must have a type and description unless they have a defined, common suffix. - oneOf: - - description: 'A vendor boolean property can use "type: boolean"' - properties: - description: true - type: - const: boolean - deprecated: true - required: - - type - - description - additionalProperties: false - - description: A vendor string property with exact values has an implicit - type - properties: # A string property with exact values - description: true - enum: - items: - type: string - const: - type: string - deprecated: true - required: - - description - oneOf: - - required: [ enum ] - - required: [ const ] - additionalProperties: false + properties: + type: + description: 'A vendor boolean property can use "type: boolean"' + const: boolean + + dependentRequired: + type: [description] - - description: A vendor property needs a $ref to types.yaml - properties: # A property with a type and additional constraints + anyOf: + - properties: $ref: + description: A vendor property needs a $ref to types.yaml pattern: "types.yaml#\/definitions\/" - allOf: - items: - - properties: - $ref: - pattern: "types.yaml#\/definitions\/" - required: - - $ref - required: - - description - oneOf: - - required: [ $ref ] - - required: [ allOf ] - - description: A vendor property can have a $ref to a a $defs schema - properties: # A property with a type and additional constraints + dependentRequired: + $ref: [description] + - properties: $ref: + description: A vendor property can have a $ref to a a $defs schema pattern: "^#\/(definitions|\\$defs)\/" - required: [ $ref ] ... diff --git a/test/schemas/bad-example.yaml b/test/schemas/bad-example.yaml index 043a09b5..a4131a1e 100644 --- a/test/schemas/bad-example.yaml +++ b/test/schemas/bad-example.yaml @@ -76,7 +76,7 @@ properties: description: 0 vendor,property: - enum: [ 0, 1, 2 ] + type: boolean required: - model From 0808da27d7758b9f95518ccb919dff2024cc7d0e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 13 Oct 2023 10:42:49 -0500 Subject: [PATCH 400/505] meta-schemas: Also match fixed patternProperties with a '@' character A pattern such as '^port@0$' was not getting flagged as a fixed string. That's due to the missing '@' character. Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 243d4453..03477346 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -192,7 +192,7 @@ properties: - description: Fixed strings belong in 'properties', not 'patternProperties' pattern: '[\^$()*@]' not: - pattern: '^\^[a-zA-Z0-9,\-._#]+\$$' + pattern: '^\^[a-zA-Z0-9,\-._#@]+\$$' - description: A json-schema keyword was found instead of a DT property name. not: $ref: "#/definitions/json-schema-prop-names" From 5d76ad1e7b668ab5c2a3629b24e278a66d52f8fc Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 26 Sep 2023 13:42:38 -0600 Subject: [PATCH 401/505] schemas: memory: Add ECC properties Some memories provide ECC detection and/or correction. For software which wants to check memory, it is helpful to see which regions provide this feature. Add this as a property of the /memory nodes, since it presumably follows the hardware-level memory system. Signed-off-by: Simon Glass Link: https://lore.kernel.org/r/20230926194242.2732127-1-sjg@chromium.org Signed-off-by: Rob Herring --- dtschema/schemas/memory.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dtschema/schemas/memory.yaml b/dtschema/schemas/memory.yaml index 1d744109..b3bf3c91 100644 --- a/dtschema/schemas/memory.yaml +++ b/dtschema/schemas/memory.yaml @@ -35,6 +35,19 @@ patternProperties: For the purpose of identification, each NUMA node is associated with a unique token known as a node id. + ecc-detection-bits: + default: 0 + description: | + If present, this indicates the number of bits of memory error which + can be detected and reported by the Error-Correction Code (ECC) memory + subsystem (typically 0, 1 or 2). + + ecc-correction-bits: + default: 0 + description: | + If present, this indicates the number of bits of memory error which + can be corrected by the Error-Correction Code (ECC) memory subsystem + (typically 0, 1 or 2). required: - device_type From d873ca75dc73d9a84ad9eafd92c9663e1b853d08 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 19 Oct 2023 10:32:25 -0500 Subject: [PATCH 402/505] schema: Fix schema error path walking, again If a sub-schema contains $ref and another keyword that's the actual schema path, the $ref path was taken by mistake. Make sure the path keyword is not in the sub-schema when walking $ref's. Signed-off-by: Rob Herring --- dtschema/schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schema.py b/dtschema/schema.py index 3cae9afa..96ace89b 100644 --- a/dtschema/schema.py +++ b/dtschema/schema.py @@ -92,7 +92,7 @@ def annotate_error(self, error, schema, path): ref_depth = 1 for p in path: - while '$ref' in schema and isinstance(schema['$ref'], str): + while p not in schema and '$ref' in schema and isinstance(schema['$ref'], str): ref = self.validator.resolver.resolve(schema['$ref']) schema = ref[1] self.validator.resolver.push_scope(ref[0]) From 411c305105dd127331f54c32a59e4e648b726138 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 24 Oct 2023 16:16:18 -0500 Subject: [PATCH 403/505] meta-schemas: Check sub-schemas of "dependencies" and "dependentSchemas" "dependencies" (optionally) and "dependentSchemas" are a map of property names with sub-schemas under them. Make the meta-schema descend into them so that we check for common issues such as typos in json-schema keywords. Reported-by: Geert Uytterhoeven Signed-off-by: Rob Herring --- dtschema/meta-schemas/keywords.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 03477346..1c1faafe 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -143,8 +143,14 @@ properties: $ref: "#/definitions/sub-schemas" contains: $ref: "#/definitions/sub-schemas" + dependencies: + additionalProperties: + $ref: "#/definitions/sub-schemas" dependentRequired: uniqueItems: true + dependentSchemas: + additionalProperties: + $ref: "#/definitions/sub-schemas" else: $ref: "#/definitions/sub-schemas" const: From 2d5d20e348c86774801fc1fab042f2cfccd38b22 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 23 Oct 2023 18:03:57 -0500 Subject: [PATCH 404/505] fixups: Pass the schema path to fixups There's a need to know more than just the property name for some fixups. Instead of just passing the property name around, maintain the full schema path and pass that to fixups. Note that our path here doesn't include list indices for simplicity. There's a few fixups which didn't need the property name, so just drop the parameter in those cases. Signed-off-by: Rob Herring --- dtschema/fixups.py | 57 +++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index dae98b87..8d59243b 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -16,7 +16,7 @@ def _extract_single_schemas(subschema): return {k: subschema.pop(k) for k in scalar_keywords if k in subschema} -def _fixup_string_to_array(propname, subschema): +def _fixup_string_to_array(subschema): # nothing to do if we don't have a set of string schema if not _is_string_schema(subschema): return @@ -24,9 +24,9 @@ def _fixup_string_to_array(propname, subschema): subschema['items'] = [_extract_single_schemas(subschema)] -def _fixup_reg_schema(propname, subschema): +def _fixup_reg_schema(subschema, path=[]): # nothing to do if we don't have a set of string schema - if propname != 'reg': + if 'reg' not in path: return if 'items' in subschema: @@ -60,7 +60,7 @@ def _is_matrix_schema(subschema): # If we have a matrix with variable inner and outer dimensions, then drop the dimensions # because we have no way to reconstruct them. -def _fixup_int_matrix(propname, subschema): +def _fixup_int_matrix(subschema): if not _is_matrix_schema(subschema): return @@ -87,7 +87,7 @@ def _fixup_int_matrix(propname, subschema): } -def is_int_array_schema(propname, subschema): +def is_int_array_schema(subschema, path=[]): if 'allOf' in subschema: # Find 'items'. It may be under the 'allOf' or at the same level for item in subschema['allOf']: @@ -98,8 +98,9 @@ def is_int_array_schema(propname, subschema): return int_array_re.search(item['$ref']) if '$ref' in subschema: return int_array_re.search(subschema['$ref']) - elif unit_types_re.search(propname) or propname in known_array_props: - return True + else: + if [p for p in path if unit_types_re.search(p)] or set(path) & known_array_props: + return True return 'items' in subschema and \ ((isinstance(subschema['items'], list) and _is_int_schema(subschema['items'][0])) or @@ -108,8 +109,8 @@ def is_int_array_schema(propname, subschema): # Fixup an int array that only defines the number of items. # In this case, we allow either form [[ 0, 1, 2]] or [[0], [1], [2]] -def _fixup_int_array_min_max_to_matrix(propname, subschema): - if not is_int_array_schema(propname, subschema): +def _fixup_int_array_min_max_to_matrix(subschema, path=[]): + if not is_int_array_schema(subschema, path=path): return if 'allOf' in subschema: @@ -166,9 +167,9 @@ def _fixup_remove_empty_items(subschema): del subschema['items'] -def _fixup_int_array_items_to_matrix(propname, subschema): +def _fixup_int_array_items_to_matrix(subschema, path=[]): itemkeys = ('items', 'minItems', 'maxItems', 'uniqueItems', 'default') - if not is_int_array_schema(propname, subschema): + if not is_int_array_schema(subschema, path=path): return if 'allOf' in subschema: @@ -188,7 +189,7 @@ def _fixup_int_array_items_to_matrix(propname, subschema): subschema['items'] = [{k: subschema.pop(k) for k in itemkeys if k in subschema}] -def _fixup_scalar_to_array(propname, subschema): +def _fixup_scalar_to_array(subschema): if not _is_int_schema(subschema): return @@ -261,25 +262,25 @@ def fixup_schema_to_202012(schema): pass -def fixup_vals(propname, schema): +def fixup_vals(schema, path=[]): # Now we should be a the schema level to do actual fixups #print(schema) schema.pop('description', None) - _fixup_reg_schema(propname, schema) + _fixup_reg_schema(schema, path=path) _fixup_remove_empty_items(schema) - _fixup_int_matrix(propname, schema) - _fixup_int_array_min_max_to_matrix(propname, schema) - _fixup_int_array_items_to_matrix(propname, schema) - _fixup_string_to_array(propname, schema) - _fixup_scalar_to_array(propname, schema) + _fixup_int_matrix(schema) + _fixup_int_array_min_max_to_matrix(schema, path=path) + _fixup_int_array_items_to_matrix(schema, path=path) + _fixup_string_to_array(schema) + _fixup_scalar_to_array(schema) _fixup_items_size(schema) fixup_schema_to_201909(schema) -def walk_properties(propname, schema): +def walk_properties(schema, path=[]): if not isinstance(schema, dict): return # Recurse until we don't hit a conditional @@ -288,12 +289,12 @@ def walk_properties(propname, schema): for cond in ['allOf', 'oneOf', 'anyOf']: if cond in schema.keys(): for l in schema[cond]: - walk_properties(propname, l) + walk_properties(l, path=path + [cond]) if 'then' in schema.keys(): - walk_properties(propname, schema['then']) + walk_properties(schema['then'], path=path + ['then']) - fixup_vals(propname, schema) + fixup_vals(schema, path=path) def fixup_interrupts(schema): @@ -333,7 +334,7 @@ def fixup_interrupts(schema): } -def fixup_sub_schema(schema): +def fixup_sub_schema(schema, path=[]): if not isinstance(schema, dict): return @@ -348,11 +349,11 @@ def fixup_sub_schema(schema): for k, v in schema.items(): if k in ['select', 'if', 'then', 'else', 'not', 'additionalProperties']: - fixup_sub_schema(v) + fixup_sub_schema(v, path=path + [k]) if k in ['allOf', 'anyOf', 'oneOf']: for subschema in v: - fixup_sub_schema(subschema) + fixup_sub_schema(subschema, path=path + [k]) if k not in ['dependentRequired', 'dependentSchemas', 'dependencies', 'properties', 'patternProperties', '$defs']: continue @@ -365,9 +366,9 @@ def fixup_sub_schema(schema): schema[k][prop]['$ref'] = ref continue - walk_properties(prop, v[prop]) + walk_properties(v[prop], path=path + [k, prop]) # Recurse to check for {properties,patternProperties} in each prop - fixup_sub_schema(v[prop]) + fixup_sub_schema(v[prop], path=path + [k, prop]) fixup_schema_to_201909(schema) From 79243b1c3dd4f0c1e73c840ecd3148c72d736f72 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 23 Oct 2023 18:09:40 -0500 Subject: [PATCH 405/505] fixups: Skip defaulting minItems/maxItems to the same size on if/then/else schemas The intent was that if/then/else schemas are not complete, but add to the top-level schema. A common pattern is increasing the minimum or decreasing the maximum number of entries for a property. Adding an implicit minItems/maxItems defeats this. Now that we have the full schema path available, skip doing this for if/then/else schemas. Signed-off-by: Rob Herring --- dtschema/fixups.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index 8d59243b..f69a2a55 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -196,11 +196,11 @@ def _fixup_scalar_to_array(subschema): subschema['items'] = [{'items': [_extract_single_schemas(subschema)]}] -def _fixup_items_size(schema): +def _fixup_items_size(schema, path=[]): # Make items list fixed size-spec if isinstance(schema, list): for l in schema: - _fixup_items_size(l) + _fixup_items_size(l, path=path) elif isinstance(schema, dict): schema.pop('description', None) if 'items' in schema: @@ -213,12 +213,13 @@ def _fixup_items_size(schema): if 'maxItems' not in schema: schema['maxItems'] = c - _fixup_items_size(schema['items']) + _fixup_items_size(schema['items'], path=path + ['items']) - elif 'maxItems' in schema and 'minItems' not in schema: - schema['minItems'] = schema['maxItems'] - elif 'minItems' in schema and 'maxItems' not in schema: - schema['maxItems'] = schema['minItems'] + elif not {'then', 'else'} & set(path): + if 'maxItems' in schema and 'minItems' not in schema: + schema['minItems'] = schema['maxItems'] + elif 'minItems' in schema and 'maxItems' not in schema: + schema['maxItems'] = schema['minItems'] def fixup_schema_to_201909(schema): @@ -275,7 +276,7 @@ def fixup_vals(schema, path=[]): _fixup_int_array_items_to_matrix(schema, path=path) _fixup_string_to_array(schema) _fixup_scalar_to_array(schema) - _fixup_items_size(schema) + _fixup_items_size(schema, path=path) fixup_schema_to_201909(schema) From b3f210b24b58d8ff21f2b686a8bb5912bdfac78b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 26 Oct 2023 11:46:35 -0500 Subject: [PATCH 406/505] schemas: Add IOMMU consumer "pasid-num-bits" and "dma-can-stall" properties Add optional IOMMU consumer properties. These are copied from Documentation/devicetree/bindings/iommu/iommu.txt in the Linux kernel. Descriptions were written by Jean-Philippe Brucker. Co-developed-by: Jean-Philippe Brucker Signed-off-by: Rob Herring --- dtschema/schemas/iommu/iommu.yaml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/dtschema/schemas/iommu/iommu.yaml b/dtschema/schemas/iommu/iommu.yaml index e511871d..68667d8c 100644 --- a/dtschema/schemas/iommu/iommu.yaml +++ b/dtschema/schemas/iommu/iommu.yaml @@ -17,4 +17,30 @@ properties: iommus: $ref: /schemas/types.yaml#/definitions/phandle-array + pasid-num-bits: + description: + Some masters support multiple address spaces for DMA, by tagging DMA + transactions with an address space identifier. By default, this is 0, + which means that the device only has one address space. + default: 0 + + dma-can-stall: + type: boolean + description: > + When present, the master can wait for a transaction to complete for an + indefinite amount of time. Upon translation fault some IOMMUs, instead of + aborting the translation immediately, may first notify the driver and keep + the transaction in flight. This allows the OS to inspect the fault and, + for example, make physical pages resident before updating the mappings and + completing the transaction. Such IOMMU accepts a limited number of + simultaneous stalled transactions before having to either put + back-pressure on the master, or abort new faulting transactions. + + Firmware has to opt-in stalling, because most buses and masters don't + support it. In particular it isn't compatible with PCI, where transactions + have to complete before a time limit. More generally it won't work in + systems and masters that haven't been designed for stalling. For example + the OS, in order to handle a stalled transaction, may attempt to retrieve + pages from secondary storage in a stalled domain, leading to a deadlock. + additionalProperties: true From 7a2305db761e0df27878f63077a385e9cba4976d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Nov 2023 09:10:15 -0600 Subject: [PATCH 407/505] Rework CLI tools to use modern install method Modern python installs (i.e. using pyproject.toml) want to install CLI tools by just pointing to a module method and generating the executables on install. In order to support this, move the installed tools to the dtschema module directory renaming them to be modules. This fixes allowing modifications to the tools on editable installs. The conversion to pyproject.toml inadvertently broke this. Signed-off-by: Rob Herring --- .../check_compatible.py | 2 +- .../doc_validate.py | 2 +- tools/dtb2py => dtschema/dtb2py.py | 2 +- tools/dt-validate => dtschema/dtb_validate.py | 4 ++-- .../extract_compatibles.py | 3 +-- .../extract_example.py | 2 +- .../extract_props.py | 2 +- tools/dt-mk-schema => dtschema/mk_schema.py | 5 ++--- pyproject.toml | 20 +++++++++---------- 9 files changed, 19 insertions(+), 23 deletions(-) rename tools/dt-check-compatible => dtschema/check_compatible.py (97%) rename tools/dt-doc-validate => dtschema/doc_validate.py (98%) rename tools/dtb2py => dtschema/dtb2py.py (97%) rename tools/dt-validate => dtschema/dtb_validate.py (98%) rename tools/extract-compatibles => dtschema/extract_compatibles.py (97%) rename tools/dt-extract-example => dtschema/extract_example.py (98%) rename tools/dt-extract-props => dtschema/extract_props.py (98%) rename tools/dt-mk-schema => dtschema/mk_schema.py (96%) diff --git a/tools/dt-check-compatible b/dtschema/check_compatible.py similarity index 97% rename from tools/dt-check-compatible rename to dtschema/check_compatible.py index 10531902..84ff134a 100755 --- a/tools/dt-check-compatible +++ b/dtschema/check_compatible.py @@ -15,7 +15,7 @@ def sigint_handler(signum, frame): import dtschema -if __name__ == "__main__": +def main(): ap = argparse.ArgumentParser(fromfile_prefix_chars='@', epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("compatible_str", nargs='+', diff --git a/tools/dt-doc-validate b/dtschema/doc_validate.py similarity index 98% rename from tools/dt-doc-validate rename to dtschema/doc_validate.py index 2a8235a5..cd7fcac9 100755 --- a/tools/dt-doc-validate +++ b/dtschema/doc_validate.py @@ -41,7 +41,7 @@ def check_doc(filename): return ret -if __name__ == "__main__": +def main(): ap = argparse.ArgumentParser(fromfile_prefix_chars='@', epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("yamldt", nargs='*', type=str, diff --git a/tools/dtb2py b/dtschema/dtb2py.py similarity index 97% rename from tools/dtb2py rename to dtschema/dtb2py.py index 51d24868..5535f156 100755 --- a/tools/dtb2py +++ b/dtschema/dtb2py.py @@ -11,7 +11,7 @@ strict = False -if __name__ == "__main__": +def main(): ap = argparse.ArgumentParser() ap.add_argument("dtbfile", type=str, help="Schema directories and/or files") ap.add_argument('-s', '--schema', help="path to additional additional schema files") diff --git a/tools/dt-validate b/dtschema/dtb_validate.py similarity index 98% rename from tools/dt-validate rename to dtschema/dtb_validate.py index 2f3fa612..e20ff2cf 100755 --- a/tools/dt-validate +++ b/dtschema/dtb_validate.py @@ -91,11 +91,11 @@ def check_subtree(self, tree, subtree, disabled, nodename, fullname, filename): def check_dtb(self, filename): """Check the given DT against all schemas""" with open(filename, 'rb') as f: - dt = sg.validator.decode_dtb(f.read()) + dt = self.validator.decode_dtb(f.read()) for subtree in dt: self.check_subtree(dt, subtree, False, "/", "/", filename) -if __name__ == "__main__": +def main(): ap = argparse.ArgumentParser(fromfile_prefix_chars='@', epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("dtbs", nargs='*', diff --git a/tools/extract-compatibles b/dtschema/extract_compatibles.py similarity index 97% rename from tools/extract-compatibles rename to dtschema/extract_compatibles.py index f84d3084..6c0d07dc 100755 --- a/tools/extract-compatibles +++ b/dtschema/extract_compatibles.py @@ -23,8 +23,7 @@ def item_generator(json_input, lookup_key): for item_val in item_generator(item, lookup_key): yield item_val -if __name__ == "__main__": - +def main(): ap = argparse.ArgumentParser() ap.add_argument("yamlfile", type=str, help="Filename of YAML encoded schema input file") diff --git a/tools/dt-extract-example b/dtschema/extract_example.py similarity index 98% rename from tools/dt-extract-example rename to dtschema/extract_example.py index a8b5aaba..7c2c73f1 100755 --- a/tools/dt-extract-example +++ b/dtschema/extract_example.py @@ -51,7 +51,7 @@ def sigint_handler(signum, frame): yaml = ruamel.yaml.YAML(typ='safe') -if __name__ == "__main__": +def main(): ex = '// empty' ap = argparse.ArgumentParser() ap.add_argument("yamlfile", type=str, diff --git a/tools/dt-extract-props b/dtschema/extract_props.py similarity index 98% rename from tools/dt-extract-props rename to dtschema/extract_props.py index 7952909a..4c82eaad 100755 --- a/tools/dt-extract-props +++ b/dtschema/extract_props.py @@ -18,7 +18,7 @@ def sigint_handler(signum, frame): strict = False -if __name__ == "__main__": +def main(): ap = argparse.ArgumentParser() ap.add_argument("schema_files", type=str, nargs='*', help="preparsed schema file or list of additional schema files/directories") diff --git a/tools/dt-mk-schema b/dtschema/mk_schema.py similarity index 96% rename from tools/dt-mk-schema rename to dtschema/mk_schema.py index 7439a792..e0b7f22d 100755 --- a/tools/dt-mk-schema +++ b/dtschema/mk_schema.py @@ -20,8 +20,7 @@ def sigint_handler(signum, frame): import json - -if __name__ == "__main__": +def main(): ap = argparse.ArgumentParser(fromfile_prefix_chars='@', epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("-o", "--outfile", type=str, @@ -37,7 +36,7 @@ def sigint_handler(signum, frame): schemas = dtschema.DTValidator(args.schemas).schemas if not schemas: - exit(-1) + return -1 if args.outfile: f = open(args.outfile, 'w', encoding='utf-8') diff --git a/pyproject.toml b/pyproject.toml index 6fc9bb7a..2192a685 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,17 +30,15 @@ dependencies = [ "pylibfdt", ] +[project.scripts] +dt-check-compatible = "dtschema.check_compatible:main" +dt-doc-validate = "dtschema.doc_validate:main" +dt-extract-example = "dtschema.extract_example:main" +dt-extract-props = "dtschema.extract_props:main" +dt-mk-schema = "dtschema.mk_schema:main" +dt-validate = "dtschema.dtb_validate:main" +dtb2py = "dtschema.dtb2py:main" + [project.urls] Homepage="https://github.com/devicetree-org/dt-schema" Source="https://github.com/devicetree-org/dt-schema" - -[tool.setuptools] -script-files = [ - 'tools/dt-check-compatible', - 'tools/dt-validate', - 'tools/dt-doc-validate', - 'tools/dt-mk-schema', - 'tools/dt-extract-example', - 'tools/dt-extract-props', - 'tools/dtb2py' -] From a8b75017a20ff4d69aaccc781062e175f01cd7fc Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Nov 2023 15:31:40 -0600 Subject: [PATCH 408/505] Fix variable accesses to main() method The change of the CLI tools to a main() method changes the scope of some variables. Fix these. Signed-off-by: Rob Herring --- dtschema/doc_validate.py | 7 ++++++- dtschema/dtb_validate.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dtschema/doc_validate.py b/dtschema/doc_validate.py index cd7fcac9..1f81391a 100755 --- a/dtschema/doc_validate.py +++ b/dtschema/doc_validate.py @@ -18,6 +18,7 @@ def sigint_handler(signum, frame): import glob line_number = False +verbose = False def check_doc(filename): ret = 0 @@ -30,7 +31,7 @@ def check_doc(filename): try: for error in sorted(dtsch.iter_errors(), key=lambda e: e.linecol): - print(dtschema.format_error(filename, error, verbose=args.verbose), file=sys.stderr) + print(dtschema.format_error(filename, error, verbose=verbose), file=sys.stderr) ret = 1 except: raise @@ -42,6 +43,9 @@ def check_doc(filename): return ret def main(): + global verbose + global line_number + ap = argparse.ArgumentParser(fromfile_prefix_chars='@', epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("yamldt", nargs='*', type=str, @@ -54,6 +58,7 @@ def main(): args = ap.parse_args() line_number=args.line_number + verbose = args.verbose ret = 0 for f in args.yamldt: diff --git a/dtschema/dtb_validate.py b/dtschema/dtb_validate.py index e20ff2cf..6e988e85 100755 --- a/dtschema/dtb_validate.py +++ b/dtschema/dtb_validate.py @@ -70,7 +70,7 @@ def check_node(self, tree, node, disabled, nodename, fullname, filename): print(dtschema.format_error(filename, error, nodename=nodename, verbose=verbose), file=sys.stderr) except RecursionError as e: - print(ap.prog + ": recursion error: Check for prior errors in a referenced schema", file=sys.stderr) + print(os.path.basename(sys.argv[0]) + ": recursion error: Check for prior errors in a referenced schema", file=sys.stderr) def check_subtree(self, tree, subtree, disabled, nodename, fullname, filename): if nodename.startswith('__'): From b25b467e5b47a7c16e91f424ed7381818c312e7d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Nov 2023 16:16:11 -0600 Subject: [PATCH 409/505] dt-validate: More global variable fixes More fallout from the move to main() method. Signed-off-by: Rob Herring --- dtschema/dtb_validate.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dtschema/dtb_validate.py b/dtschema/dtb_validate.py index 6e988e85..46146dec 100755 --- a/dtschema/dtb_validate.py +++ b/dtschema/dtb_validate.py @@ -96,6 +96,10 @@ def check_dtb(self, filename): self.check_subtree(dt, subtree, False, "/", "/", filename) def main(): + global verbose + global show_unmatched + global match_schema_file + ap = argparse.ArgumentParser(fromfile_prefix_chars='@', epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("dtbs", nargs='*', From 06ef4614f4b98afe4944018334279604973582a5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Nov 2023 15:57:33 -0600 Subject: [PATCH 410/505] Consolidate SIGINT handling We have SIGINT handling so that a Ctrl-C exits without a backtrace. There's not really any reason to have the same thing in each CLI command. This also fixes flake warnings about imports being first. Signed-off-by: Rob Herring --- dtschema/__init__.py | 7 +++++++ dtschema/check_compatible.py | 7 ------- dtschema/doc_validate.py | 6 ------ dtschema/dtb_validate.py | 7 ------- dtschema/extract_example.py | 2 +- dtschema/extract_props.py | 7 ------- dtschema/mk_schema.py | 7 ------- 7 files changed, 8 insertions(+), 35 deletions(-) diff --git a/dtschema/__init__.py b/dtschema/__init__.py index 9cf58336..676d497c 100644 --- a/dtschema/__init__.py +++ b/dtschema/__init__.py @@ -1,3 +1,10 @@ +import signal + +def sigint_handler(signum, frame): + sys.exit(-2) + +signal.signal(signal.SIGINT, sigint_handler) + from dtschema.lib import ( format_error, extract_compatibles, diff --git a/dtschema/check_compatible.py b/dtschema/check_compatible.py index 84ff134a..4d91f2d8 100755 --- a/dtschema/check_compatible.py +++ b/dtschema/check_compatible.py @@ -2,13 +2,6 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2022 Arm Ltd. -import signal - -def sigint_handler(signum, frame): - sys.exit(-2) - -signal.signal(signal.SIGINT, sigint_handler) - import sys import os import argparse diff --git a/dtschema/doc_validate.py b/dtschema/doc_validate.py index 1f81391a..91797298 100755 --- a/dtschema/doc_validate.py +++ b/dtschema/doc_validate.py @@ -3,12 +3,6 @@ # Copyright 2018 Linaro Ltd. # Copyright 2018 Arm Ltd. -import signal - -def sigint_handler(signum, frame): - sys.exit(-2) - -signal.signal(signal.SIGINT, sigint_handler) import os import sys diff --git a/dtschema/dtb_validate.py b/dtschema/dtb_validate.py index 46146dec..3601a848 100755 --- a/dtschema/dtb_validate.py +++ b/dtschema/dtb_validate.py @@ -3,13 +3,6 @@ # Copyright 2018 Linaro Ltd. # Copyright 2018 Arm Ltd. -import signal - -def sigint_handler(signum, frame): - sys.exit(-2) - -signal.signal(signal.SIGINT, sigint_handler) - import sys import os import jsonschema diff --git a/dtschema/extract_example.py b/dtschema/extract_example.py index 7c2c73f1..87026b82 100755 --- a/dtschema/extract_example.py +++ b/dtschema/extract_example.py @@ -6,7 +6,7 @@ import signal def sigint_handler(signum, frame): - exit(130) + sys.exit(-2) signal.signal(signal.SIGINT, sigint_handler) diff --git a/dtschema/extract_props.py b/dtschema/extract_props.py index 4c82eaad..7f370c1c 100755 --- a/dtschema/extract_props.py +++ b/dtschema/extract_props.py @@ -2,13 +2,6 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2022 Arm Ltd. -import signal - -def sigint_handler(signum, frame): - sys.exit(-2) - -signal.signal(signal.SIGINT, sigint_handler) - import argparse import os import sys diff --git a/dtschema/mk_schema.py b/dtschema/mk_schema.py index e0b7f22d..4a79ae15 100755 --- a/dtschema/mk_schema.py +++ b/dtschema/mk_schema.py @@ -3,13 +3,6 @@ # Copyright 2018 Linaro Ltd. # Copyright 2018 Arm Ltd. -import signal - -def sigint_handler(signum, frame): - sys.exit(-2) - -signal.signal(signal.SIGINT, sigint_handler) - import os import sys import ruamel.yaml From 368da1fa15f4193629175bcc938857fc909d486b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Nov 2023 16:00:10 -0600 Subject: [PATCH 411/505] Clean-up flake warnings about imports Reorder and drop unused imports. Signed-off-by: Rob Herring --- dtschema/check_compatible.py | 1 - dtschema/doc_validate.py | 5 +++-- dtschema/dtb_validate.py | 1 - dtschema/extract_compatibles.py | 4 ++-- dtschema/extract_example.py | 13 +++++++------ dtschema/mk_schema.py | 8 +++----- 6 files changed, 15 insertions(+), 17 deletions(-) diff --git a/dtschema/check_compatible.py b/dtschema/check_compatible.py index 4d91f2d8..298dfd3e 100755 --- a/dtschema/check_compatible.py +++ b/dtschema/check_compatible.py @@ -2,7 +2,6 @@ # SPDX-License-Identifier: BSD-2-Clause # Copyright 2022 Arm Ltd. -import sys import os import argparse diff --git a/dtschema/doc_validate.py b/dtschema/doc_validate.py index 91797298..621e0f5a 100755 --- a/dtschema/doc_validate.py +++ b/dtschema/doc_validate.py @@ -6,11 +6,12 @@ import os import sys -import ruamel.yaml -import dtschema import argparse import glob +import ruamel.yaml +import dtschema + line_number = False verbose = False diff --git a/dtschema/dtb_validate.py b/dtschema/dtb_validate.py index 3601a848..20f214a1 100755 --- a/dtschema/dtb_validate.py +++ b/dtschema/dtb_validate.py @@ -5,7 +5,6 @@ import sys import os -import jsonschema import argparse import glob diff --git a/dtschema/extract_compatibles.py b/dtschema/extract_compatibles.py index 6c0d07dc..46545605 100755 --- a/dtschema/extract_compatibles.py +++ b/dtschema/extract_compatibles.py @@ -4,10 +4,10 @@ # Copyright 2018 Arm Ltd. import os -import sys -import ruamel.yaml import argparse +import ruamel.yaml + yaml = ruamel.yaml.YAML() def item_generator(json_input, lookup_key): diff --git a/dtschema/extract_example.py b/dtschema/extract_example.py index 87026b82..322737b5 100755 --- a/dtschema/extract_example.py +++ b/dtschema/extract_example.py @@ -3,18 +3,19 @@ # Copyright 2018 Linaro Ltd. # Copyright 2019-2022 Arm Ltd. +import re +import sys +import argparse import signal +import ruamel.yaml + + def sigint_handler(signum, frame): sys.exit(-2) -signal.signal(signal.SIGINT, sigint_handler) -import os -import re -import sys -import ruamel.yaml -import argparse +signal.signal(signal.SIGINT, sigint_handler) interrupt_template = """ interrupt-parent = <&fake_intc{index}>; diff --git a/dtschema/mk_schema.py b/dtschema/mk_schema.py index 4a79ae15..ae41388c 100755 --- a/dtschema/mk_schema.py +++ b/dtschema/mk_schema.py @@ -3,15 +3,13 @@ # Copyright 2018 Linaro Ltd. # Copyright 2018 Arm Ltd. -import os import sys -import ruamel.yaml -import dtschema import argparse -import glob -import jsonschema import json +import ruamel.yaml +import dtschema + def main(): ap = argparse.ArgumentParser(fromfile_prefix_chars='@', From 3225b75d0c5c7a4c65223492edb6300b8b14e84e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Nov 2023 16:16:47 -0600 Subject: [PATCH 412/505] flake whitespace cleanups Signed-off-by: Rob Herring --- dtschema/check_compatible.py | 1 + dtschema/doc_validate.py | 4 +++- dtschema/dtb_validate.py | 12 +++++++----- dtschema/extract_compatibles.py | 4 +++- dtschema/extract_example.py | 4 +++- dtschema/extract_props.py | 5 +++-- dtschema/fixups.py | 2 +- 7 files changed, 21 insertions(+), 11 deletions(-) diff --git a/dtschema/check_compatible.py b/dtschema/check_compatible.py index 298dfd3e..0115145c 100755 --- a/dtschema/check_compatible.py +++ b/dtschema/check_compatible.py @@ -7,6 +7,7 @@ import dtschema + def main(): ap = argparse.ArgumentParser(fromfile_prefix_chars='@', epilog='Arguments can also be passed in a file prefixed with a "@" character.') diff --git a/dtschema/doc_validate.py b/dtschema/doc_validate.py index 621e0f5a..6d060016 100755 --- a/dtschema/doc_validate.py +++ b/dtschema/doc_validate.py @@ -15,6 +15,7 @@ line_number = False verbose = False + def check_doc(filename): ret = 0 try: @@ -37,6 +38,7 @@ def check_doc(filename): return ret + def main(): global verbose global line_number @@ -52,7 +54,7 @@ def main(): action="version", version=dtschema.__version__) args = ap.parse_args() - line_number=args.line_number + line_number = args.line_number verbose = args.verbose ret = 0 diff --git a/dtschema/dtb_validate.py b/dtschema/dtb_validate.py index 20f214a1..b8e3e530 100755 --- a/dtschema/dtb_validate.py +++ b/dtschema/dtb_validate.py @@ -14,6 +14,7 @@ show_unmatched = False match_schema_file = None + class schema_group(): def __init__(self, schema_file=""): if schema_file != "" and not os.path.exists(schema_file): @@ -26,7 +27,7 @@ def check_node(self, tree, node, disabled, nodename, fullname, filename): if 'example-0' in node or 'example-' in nodename: return - node['$nodename'] = [ nodename ] + node['$nodename'] = [nodename] try: for error in self.validator.iter_errors(node, filter=match_schema_file): @@ -37,9 +38,9 @@ def check_node(self, tree, node, disabled, nodename, fullname, filename): # boards using that particular node. Thus, if the # node is marked as disabled, let's just ignore # any error message reporting a missing property. - if disabled or (isinstance(error.instance, dict) and \ - 'status' in error.instance and \ - 'disabled' in error.instance['status']): + if disabled or (isinstance(error.instance, dict) and + 'status' in error.instance and + 'disabled' in error.instance['status']): if {'required', 'unevaluatedProperties'} & set(error.schema_path): continue @@ -76,7 +77,7 @@ def check_subtree(self, tree, subtree, disabled, nodename, fullname, filename): self.check_node(tree, subtree, disabled, nodename, fullname, filename) if fullname != "/": fullname += "/" - for name,value in subtree.items(): + for name, value in subtree.items(): if isinstance(value, dict): self.check_subtree(tree, value, disabled, name, fullname + name, filename) @@ -87,6 +88,7 @@ def check_dtb(self, filename): for subtree in dt: self.check_subtree(dt, subtree, False, "/", "/", filename) + def main(): global verbose global show_unmatched diff --git a/dtschema/extract_compatibles.py b/dtschema/extract_compatibles.py index 46545605..bf9fe402 100755 --- a/dtschema/extract_compatibles.py +++ b/dtschema/extract_compatibles.py @@ -10,6 +10,7 @@ yaml = ruamel.yaml.YAML() + def item_generator(json_input, lookup_key): if isinstance(json_input, dict): for k, v in json_input.items(): @@ -23,6 +24,7 @@ def item_generator(json_input, lookup_key): for item_val in item_generator(item, lookup_key): yield item_val + def main(): ap = argparse.ArgumentParser() ap.add_argument("yamlfile", type=str, @@ -33,7 +35,7 @@ def main(): testtree = yaml.load(open(args.yamlfile, encoding='utf-8').read()) - compatible_list = [ ] + compatible_list = [] for l in item_generator(testtree['properties']['compatible'], 'enum'): for _l in l: if _l not in compatible_list: diff --git a/dtschema/extract_example.py b/dtschema/extract_example.py index 322737b5..e424ad6b 100755 --- a/dtschema/extract_example.py +++ b/dtschema/extract_example.py @@ -17,6 +17,7 @@ def sigint_handler(signum, frame): signal.signal(signal.SIGINT, sigint_handler) + interrupt_template = """ interrupt-parent = <&fake_intc{index}>; fake_intc{index}: fake-interrupt-controller {{ @@ -52,6 +53,7 @@ def sigint_handler(signum, frame): yaml = ruamel.yaml.YAML(typ='safe') + def main(): ex = '// empty' ap = argparse.ArgumentParser() @@ -71,7 +73,7 @@ def main(): example_dts = example_header if 'examples' in binding.keys(): - for idx,ex in enumerate(binding['examples']): + for idx, ex in enumerate(binding['examples']): # Check if example contains a root node "/{" root_node = re.search('/\s*{', ex) diff --git a/dtschema/extract_props.py b/dtschema/extract_props.py index 7f370c1c..1e84aa66 100755 --- a/dtschema/extract_props.py +++ b/dtschema/extract_props.py @@ -11,6 +11,7 @@ strict = False + def main(): ap = argparse.ArgumentParser() ap.add_argument("schema_files", type=str, nargs='*', @@ -26,7 +27,7 @@ def main(): if args.duplicates: tmp_props = {} - for k,v in props.items(): + for k, v in props.items(): if len(v) > 1: tmp_props[k] = v @@ -36,7 +37,7 @@ def main(): prop_types = props else: prop_types = {} - for k,v in props.items(): + for k, v in props.items(): prop_types[k] = [] for l in v: if 'type' in l: diff --git a/dtschema/fixups.py b/dtschema/fixups.py index f69a2a55..efda5957 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -41,7 +41,7 @@ def _fixup_reg_schema(subschema, path=[]): else: return - subschema['items'] = [ {'items': [ _extract_single_schemas(item_schema) ] } ] + subschema['items'] = [{'items': [_extract_single_schemas(item_schema)]}] def _is_matrix_schema(subschema): From 58feadbc6f7f6c1c08ecd3e5e597d2f4757bded8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sat, 11 Nov 2023 08:48:20 -0600 Subject: [PATCH 413/505] Add missing sys import for signal handler Signed-off-by: Rob Herring --- dtschema/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dtschema/__init__.py b/dtschema/__init__.py index 676d497c..ff332859 100644 --- a/dtschema/__init__.py +++ b/dtschema/__init__.py @@ -1,4 +1,5 @@ import signal +import sys def sigint_handler(signum, frame): sys.exit(-2) From 87135f99f1c5544263380c560b85718db005a120 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 20 Nov 2023 09:45:28 -0700 Subject: [PATCH 414/505] fixups: Drop supporting 2nd form of int array encoding Since dropping YAML encoded DTs, there's now only one encoding of arrays which is [[ 1, 2, 3 ]]. Therefore the fixup to support both forms can be dropped. The fixup now makes the outer array 1 item and minItems/maxItems in the schema always applies to the inner array. Signed-off-by: Rob Herring --- dtschema/fixups.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index efda5957..b6ce7667 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -108,7 +108,6 @@ def is_int_array_schema(subschema, path=[]): # Fixup an int array that only defines the number of items. -# In this case, we allow either form [[ 0, 1, 2]] or [[0], [1], [2]] def _fixup_int_array_min_max_to_matrix(subschema, path=[]): if not is_int_array_schema(subschema, path=path): return @@ -136,17 +135,8 @@ def _fixup_int_array_min_max_to_matrix(subschema, path=[]): tmpsch['maxItems'] = subschema.pop('maxItems') if tmpsch: - subschema['oneOf'] = [copy.deepcopy(tmpsch), {'items': [copy.deepcopy(tmpsch)]}] - subschema['oneOf'][0].update({'items': {'maxItems': 1}}) - - # if minItems can be 1, then both oneOf clauses can be true so increment - # minItems in one clause to prevent that. - if subschema['oneOf'][0].get('minItems') == 1: - subschema['oneOf'][0]['minItems'] += 1 - - # Since we added an 'oneOf' the tree walking code won't find it and we need to do fixups - _fixup_items_size(subschema['oneOf']) - + subschema['items'] = tmpsch + subschema['maxItems'] = 1 def _fixup_remove_empty_items(subschema): if 'items' not in subschema: From e0b70cde27cbb8c312663acf1392beaeaab9811e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 20 Nov 2023 10:03:25 -0700 Subject: [PATCH 415/505] fixups: Apply int array to matrix fixup even for 1 item There was a corner case where an array with 1 item was defined: $ref: /schemas/types.yaml#/definitions/uint32-array maxItems: 1 While that's not really valid because 1 item is just an uint32, not an array, the schema didn't work correctly either. With the fixup skipped, maxItems applied to the outer array (which is always 1 item for arrays) when the intent was for the inner array. Since support of 2 forms of array encoding has been dropped, we can also just drop the maxItems check. Signed-off-by: Rob Herring --- dtschema/fixups.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index b6ce7667..d7b99de9 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -125,9 +125,6 @@ def _fixup_int_array_min_max_to_matrix(subschema, path=[]): if _is_matrix_schema(subschema): return - if subschema.get('maxItems') == 1: - return - tmpsch = {} if 'minItems' in subschema: tmpsch['minItems'] = subschema.pop('minItems') From 84f7cc9518f3719233a34d0d3324e6d57527b107 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sat, 18 Nov 2023 15:39:49 +0100 Subject: [PATCH 416/505] meta-schemas: Allow '#' anywhere in required DT property names Commit 0e28a44059a6 ("meta-schemas: Allow '#' anywhere is DT property names") amended the 'propertyNames' regex to allow names such as 'marvell,#interrupts'. Make the same amendment to the 'required' regex for consistency to avoid errors like: Documentation/devicetree/bindings/security/tpm/ibm,vtpm.yaml: required:4: 'ibm,#dma-address-cells' does not match '^([a-zA-Z#][a-zA-Z0-9,+\\-._@]{0,63}|\\$nodename)$' hint: 'required' must be valid DT property or node names from schema $id: http://devicetree.org/meta-schemas/keywords.yaml# Signed-off-by: Lukas Wunner --- dtschema/meta-schemas/keywords.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index 1c1faafe..f3c60b4a 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -220,7 +220,7 @@ properties: type: array uniqueItems: true items: - pattern: '^([a-zA-Z#][a-zA-Z0-9,+\-._@]{0,63}|\$nodename)$' + pattern: '^([a-zA-Z#][a-zA-Z0-9#,+\-._@]{0,63}|\$nodename)$' select: $ref: "#/definitions/sub-schemas" then: From 67806650089d8bede1c3c20cf7ececba25ec357e Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Mon, 20 Nov 2023 23:58:12 +0100 Subject: [PATCH 417/505] schemas: Allow '#' anywhere in DT property names Commit 0e28a44059a6 ("meta-schemas: Allow '#' anywhere is DT property names") amended the 'propertyNames' regex to allow names such as 'marvell,#interrupts'. Make the same amendment to the allowed patternProperties for consistency to avoid errors like: Documentation/devicetree/bindings/tpm/ibm,vtpm.example.dtb: vtpm@30000003: 'ibm,#dma-address-cells', 'ibm,#dma-size-cells' do not match any of the regexes: '.*-names$', '.*-supply$', '^#.*-cells$', '^#[a-zA-Z0-9,+\\-._]{0,63}$', '^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]{0,63}$', '^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-fA-F]+(,[0-9a-fA-F]+)*$', '^__.*__$', 'pinctrl-[0-9]+' from schema $id: http://devicetree.org/schemas/dt-core.yaml# Signed-off-by: Lukas Wunner --- dtschema/schemas/dt-core.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index dbace2f5..aad85c67 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -74,7 +74,7 @@ patternProperties: - $ref: types.yaml#/definitions/phandle # property and node namespace overlaps. Catch both here - "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]{0,63}$": + "^[a-zA-Z0-9][a-zA-Z0-9#,+\\-._]{0,63}$": type: [object, array, boolean, 'null'] # Anything with a '@' is definitely a node From 3c36915df7b79c6f9c55591374561148674b91bc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Nov 2023 08:56:34 +0100 Subject: [PATCH 418/505] schemas: allow negative kpascal pressure The standard pressure -kpascal property couold hold negative values, e.g. in gauge pressure (relative to atmospheric) or differential values for two inputs. Change the type to int32 to reflect that. Signed-off-by: Krzysztof Kozlowski --- dtschema/schemas/property-units.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index 21871b1c..ac0d885e 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -125,7 +125,7 @@ patternProperties: # Pressure "-kpascal$": - $ref: types.yaml#/definitions/uint32-array + $ref: types.yaml#/definitions/int32-array description: kilopascal additionalProperties: true From 2a1708dcf4ff0b25c4ec46304d6d6cc655c3e635 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Nov 2023 09:00:57 +0100 Subject: [PATCH 419/505] schemas: add -pascal standard unit suffix Certain sensors use Pascal units. Signed-off-by: Krzysztof Kozlowski --- dtschema/fixups.py | 2 +- dtschema/meta-schemas/core.yaml | 2 +- dtschema/meta-schemas/vendor-props.yaml | 2 +- dtschema/schemas/property-units.yaml | 3 +++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index d7b99de9..4e158697 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -75,7 +75,7 @@ def _fixup_int_matrix(subschema): int_array_re = re.compile('int(8|16|32|64)-array') -unit_types_re = re.compile('-(bps|kBps|bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|microvolt|picofarads|(milli)?celsius|kelvin|kpascal)$') +unit_types_re = re.compile('-(bps|kBps|bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|microvolt|picofarads|(milli)?celsius|kelvin|k?pascal)$') # Remove this once we remove array to matrix fixups known_array_props = { diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index 1cfff770..51d7f6c8 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -58,7 +58,7 @@ definitions: propertyNames: enum: [ description, deprecated ] - '-(bits|bps|kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|nanoamp|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kelvin|kpascal)$': + '-(bits|bps|kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|nanoamp|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kelvin|k?pascal)$': allOf: - $ref: cell.yaml#/array - description: Standard unit suffix properties don't need a type $ref diff --git a/dtschema/meta-schemas/vendor-props.yaml b/dtschema/meta-schemas/vendor-props.yaml index b778fbf9..fcc37269 100644 --- a/dtschema/meta-schemas/vendor-props.yaml +++ b/dtschema/meta-schemas/vendor-props.yaml @@ -17,7 +17,7 @@ patternProperties: '^rcar_sound,': true '-(bits|bps|kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm)$': true '-(nanoamp|microamp|microamp-hours|ohms|micro-ohms|microwatt-hours)$': true - '-(microvolt|(femto|pico)farads|celsius|millicelsius|kelvin|kpascal)$': true + '-(microvolt|(femto|pico)farads|celsius|millicelsius|kelvin|k?pascal)$': true ",.*-names$": type: object diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index ac0d885e..4532d76d 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -124,6 +124,9 @@ patternProperties: description: SI unit of thermodynamic temperature # Pressure + "-pascal$": + $ref: types.yaml#/definitions/int32-array + description: pascal "-kpascal$": $ref: types.yaml#/definitions/int32-array description: kilopascal From 414a9f792ff7ae20a54a560bd2e2160b70f7d566 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 21 Nov 2023 11:02:35 +0100 Subject: [PATCH 420/505] schemas: Add a schema for thermal consumer This adds a schema for thermal-zones consumers, useful for smart voltage scaling drivers that need to adjust CPU/GPU/other voltages based on chip quality and temperature of one or multiple zones, and for battery charge drivers that need to scale the charging current based on board dependant thermal zones readings (for example, battery temperature, device skin temperature, etc). Signed-off-by: AngeloGioacchino Del Regno --- dtschema/schemas/thermal/thermal.yaml | 34 +++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 dtschema/schemas/thermal/thermal.yaml diff --git a/dtschema/schemas/thermal/thermal.yaml b/dtschema/schemas/thermal/thermal.yaml new file mode 100644 index 00000000..700be437 --- /dev/null +++ b/dtschema/schemas/thermal/thermal.yaml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2023 Collabora Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/thermal.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: Thermal Consumer Common Properties + +maintainers: + - Rob Herring + +# always select the core schema +select: true + +properties: + thermal-zones: + anyOf: + - type: object # for nodes named 'thermal-zones' + - $ref: /schemas/types.yaml#/definitions/phandle-array + description: List of thermal zone phandles, one for each + thermal zone input to the device. + + thermal-zone-names: + $ref: /schemas/types.yaml#/definitions/string-array + description: List of thermal zone name strings sorted in the + same order as the thermal-zones property. Consumer drivers + will use thermal-zone-names to match thermal zone input + names with thermal zone specifiers. + +dependentRequired: + thermal-zone-names: [ thermal-zones ] + +additionalProperties: true From 1a837a244a8c186755718e392d0b699d86ee432e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 6 Dec 2023 09:37:34 -0600 Subject: [PATCH 421/505] fixups: Fix handling of required "interrupts" without "properties" in schema In subschemas with "{required: [ interrupts ]}", we fail to do the "interrupts-extended" fixup because there is not any "properties" entry. Therefore, we need to do the fixup for "required" regardless unless it is under a "oneOf" already (otherwise, we'd keep recursing applying the same fixup). Also, if "required" becomes empty, remove it. Signed-off-by: Rob Herring --- dtschema/fixups.py | 53 +++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index 4e158697..07840401 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -285,35 +285,34 @@ def walk_properties(schema, path=[]): fixup_vals(schema, path=path) -def fixup_interrupts(schema): +def fixup_interrupts(schema, path): # Supporting 'interrupts' implies 'interrupts-extended' is also supported. - if 'properties' not in schema: - return - - # Any node with 'interrupts' can have 'interrupt-parent' - if schema['properties'].keys() & {'interrupts', 'interrupt-controller'} and \ - 'interrupt-parent' not in schema['properties']: - schema['properties']['interrupt-parent'] = True - - if 'interrupts' not in schema['properties'] or 'interrupts-extended' in schema['properties']: - return + if 'properties' in schema: + # Any node with 'interrupts' can have 'interrupt-parent' + if schema['properties'].keys() & {'interrupts', 'interrupt-controller'} and \ + 'interrupt-parent' not in schema['properties']: + schema['properties']['interrupt-parent'] = True - schema['properties']['interrupts-extended'] = copy.deepcopy(schema['properties']['interrupts']) - - if not ('required' in schema and 'interrupts' in schema['required']): - return + if 'interrupts' not in schema['properties'] or 'interrupts-extended' in schema['properties']: + return - # Currently no better way to express either 'interrupts' or 'interrupts-extended' - # is required. If this fails validation, the error reporting is the whole - # schema file fails validation - reqlist = [{'required': ['interrupts']}, {'required': ['interrupts-extended']}] - if 'oneOf' in schema: - if 'allOf' not in schema: - schema['allOf'] = [] - schema['allOf'].append({'oneOf': reqlist}) - else: - schema['oneOf'] = reqlist - schema['required'].remove('interrupts') + schema['properties']['interrupts-extended'] = copy.deepcopy(schema['properties']['interrupts']) + + if 'required' in schema and 'interrupts' in schema['required'] and \ + (len(path) == 0 or path[-1] != 'oneOf'): + # Currently no better way to express either 'interrupts' or 'interrupts-extended' + # is required. If this fails validation, the error reporting is the whole + # schema file fails validation + reqlist = [{'required': ['interrupts']}, {'required': ['interrupts-extended']}] + if 'oneOf' in schema: + if 'allOf' not in schema: + schema['allOf'] = [] + schema['allOf'].append({'oneOf': reqlist}) + else: + schema['oneOf'] = reqlist + schema['required'].remove('interrupts') + if len(schema['required']) == 0: + schema.pop('required') known_variable_matrix_props = { @@ -327,7 +326,7 @@ def fixup_sub_schema(schema, path=[]): return schema.pop('description', None) - fixup_interrupts(schema) + fixup_interrupts(schema, path) fixup_node_props(schema) # 'additionalProperties: true' doesn't work with 'unevaluatedProperties', so From f3a5967cd3aba6eadb1899165aca934bc13a35e8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 13 Dec 2023 14:43:33 -0600 Subject: [PATCH 422/505] dtb: Only apply gpio fixups if a list (i.e. skip booleans) A boolean property matching the pattern of standard gpio properties causes a splat since the value is not a list. While that would be rejected upstream, the dtb decoding is the wrong place to do that. Signed-off-by: Rob Herring --- dtschema/dtb.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 2eb97233..8f6ef2fb 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -372,7 +372,8 @@ def fixup_gpios(dt): if isinstance(v, dict): fixup_gpios(v) elif (k.endswith('-gpios') or k.endswith('-gpio') or k in {'gpio', 'gpios'}) and \ - not k.endswith(',nr-gpios'): + not k.endswith(',nr-gpios') and \ + isinstance(v, list): i = 0 dt[k] = [] val = v[0] From 22b6f908725d521268a60e151e5f5c0e9d8f7bc5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 15 Dec 2023 15:04:58 -0600 Subject: [PATCH 423/505] validator: Don't rely on file name extension for JSON vs. YAML Signed-off-by: Rob Herring --- dtschema/validator.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index da6c6358..8db54f1d 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -331,15 +331,19 @@ def __init__(self, schema_files, filter=None): self.schemas = {} self.resolver = jsonschema.RefResolver('', None, handlers={'http': self.http_handler}) - yaml = ruamel.yaml.YAML(typ='safe') - if len(schema_files) == 1 and os.path.isfile(schema_files[0]): # a processed schema file with open(schema_files[0], 'r', encoding='utf-8') as f: - if schema_files[0].endswith('.json'): + try: schema_cache = json.load(f) - else: - schema_cache = yaml.load(f.read()) + except json.decoder.JSONDecodeError: + try: + f.seek(0) + yaml = ruamel.yaml.YAML(typ='safe') + schema_cache = yaml.load(f.read()) + except: + print("preprocessed schema file is not valid JSON or YAML\n", file=sys.stderr) + raise # Convert old format to new if isinstance(schema_cache, list): From 6774d386e3fb42c2a556d7217af63938d76737cb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 15 Dec 2023 15:13:24 -0600 Subject: [PATCH 424/505] validator: Fix loading of a single schema file Normally a single file is a processed schema, but sometimes for testing we want to pass in a single schema to check the processed output. Signed-off-by: Rob Herring --- dtschema/validator.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dtschema/validator.py b/dtschema/validator.py index 8db54f1d..6137dfee 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -330,6 +330,7 @@ class DTValidator: def __init__(self, schema_files, filter=None): self.schemas = {} self.resolver = jsonschema.RefResolver('', None, handlers={'http': self.http_handler}) + schema_cache = None if len(schema_files) == 1 and os.path.isfile(schema_files[0]): # a processed schema file @@ -345,6 +346,11 @@ def __init__(self, schema_files, filter=None): print("preprocessed schema file is not valid JSON or YAML\n", file=sys.stderr) raise + # Ensure the cache is a processed schema and not just a single schema file + if '$id' in schema_cache: + schema_cache = None + + if schema_cache: # Convert old format to new if isinstance(schema_cache, list): d = {} From f00d69fe52216645d0f82688d3f4ceb8e48f2477 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 27 Dec 2023 11:56:46 -0600 Subject: [PATCH 425/505] validator: Exclude "compatible" patterns with wildcards Some schemas have patterns for "compatible" which are not complete patterns. One example is a schema for an SoC family which establishes naming patterns for its compatible strings, but doesn't define any full compatible strings. Any full pattern should have start and end anchors and not have ".*" or ".+", so skip any patterns matching those criteria for the generated schema of all compatible strings. Fixes issue #122. Signed-off-by: Rob Herring --- dtschema/validator.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index 6137dfee..dfcdacfe 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -222,7 +222,9 @@ def make_compatible_schema(schemas): for c in compatible_list: if prog.match(c): # Exclude the generic pattern - if c != '^[a-zA-Z0-9][a-zA-Z0-9,+\-._/]+$': + if c != '^[a-zA-Z0-9][a-zA-Z0-9,+\-._/]+$' and \ + not re.search(r'\.[+*]', c) and \ + c.startswith('^') and c.endswith('$'): compat_sch += [{'pattern': c}] else: compat_sch[0]['enum'].append(c) From fb80ec43c2044d32cf576ef7c660eedf9c38f9ae Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 2 Jan 2024 21:23:48 -0700 Subject: [PATCH 426/505] schema: Use draft7 meta-schema (again) When splitting the schema and validator classes, we inadvertently switched from draft7 meta-schema to draft2019-09 meta-schema which doesn't fully work due to incomplete $recursiveRef support in jsonschema module. That's now fixed, but only in newer versions we don't yet support. Signed-off-by: Rob Herring --- dtschema/schema.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dtschema/schema.py b/dtschema/schema.py index 96ace89b..0da09e7d 100644 --- a/dtschema/schema.py +++ b/dtschema/schema.py @@ -132,7 +132,9 @@ def is_valid(self, strict=False): for error in self.iter_errors(): raise error else: - for error in self.DtValidator(self.DtValidator.META_SCHEMA).iter_errors(self): + # Using the draft7 metaschema because 2019-09 with $recursiveRef seems broken + # Probably fixed with referencing library + for error in self.DtValidator(jsonschema.Draft7Validator.META_SCHEMA).iter_errors(self): scherr = jsonschema.exceptions.SchemaError.create_from(error) raise scherr From 0053468e902843be55e7d42b7b6855a0d516a6ec Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 9 Jan 2024 21:53:51 +0100 Subject: [PATCH 427/505] dtb: expect nvmem-cell-cells The 'nvmem-cells' has corresponding '#nvmem-cell-cells' property defining number cells, thus allow checks for phandle arguments. Link: https://lore.kernel.org/linux-devicetree/20240109213739.558287-1-krzysztof.kozlowski@linaro.org/T/#u Signed-off-by: Krzysztof Kozlowski --- dtschema/dtb.py | 1 - 1 file changed, 1 deletion(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 8f6ef2fb..99f1ff1d 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -272,7 +272,6 @@ def fdt_scan_node(validator, fdt, nodename, offset): 'msi-ranges': '#interrupt-cells', 'gpio-ranges': 3, - 'nvmem-cells': None, 'memory-region': None, } From ff9403d10238844d3404727b36463a5cf01e7022 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 16 Jan 2024 14:47:05 -0600 Subject: [PATCH 428/505] Rework matrix dimension handling The handling of variable matrix dimensions was less than ideal. So much so, we just deleted constraints in _fixup_int_matrix(). Rework the extracting dimensions from property schemas, and the handling to improve finding a suitable fixed dimension. Signed-off-by: Rob Herring --- dtschema/dtb.py | 46 +++++++++++++++++++------------------------ dtschema/fixups.py | 17 ---------------- dtschema/validator.py | 20 +++++++++++-------- 3 files changed, 32 insertions(+), 51 deletions(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 99f1ff1d..f36ff344 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -52,19 +52,25 @@ def bytes_to_string(b): return None -def get_stride(len, dim): - match = 0 - if min(dim) == 0: - return 0 - for d in range(dim[0], dim[1] + 1): - if not len % d: - match += 1 - stride = d - if match == 1: - return stride +def get_stride(prop_len, dim): + + # If multiple dimensions, check if one and only one dimension fits + match = [] + for outer in range(dim[0][0], dim[0][1] + 1): + for inner in range(dim[1][0], dim[1][1] + 1): + if outer * inner == prop_len: + match += [inner] + + if len(match) > 0: + return match[0] - return 0 + if dim[1][0] > 0 and dim[1][0] == dim[1][1]: + return dim[1][0] + if dim[0][0] > 0 and dim[0][0] == dim[0][1]: + return int(prop_len / dim[0][0]) + + return prop_len def prop_value(validator, nodename, p): # First, check for a boolean type @@ -164,21 +170,9 @@ def prop_value(validator, nodename, p): if 'matrix' in fmt or 'phandle-array' in fmt: dim = validator.property_get_type_dim(p.name) if dim: - if max(dim[1]) and dim[1][0] == dim[1][1]: - stride = dim[1][1] - elif max(dim[0]) and dim[0][0] == dim[0][1]: - stride, rem = divmod(len(val_int), dim[0][1]) - if rem: - stride = len(val_int) - else: - # If multiple dimensions, check if one and only one dimension fits - stride = get_stride(len(val_int), dim[1]) - #if stride == 0: - # stride = get_stride(len(val_int), dim[0]) - if stride == 0: - stride = len(val_int) - - #print(p.name, dim, stride) + stride = get_stride(len(val_int), dim) + + #print(p.name, dim, stride, len(val_int)) return [val_int[i:i+stride] for i in range(0, len(val_int), stride)] return [val_int] diff --git a/dtschema/fixups.py b/dtschema/fixups.py index 07840401..f57d4eb6 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -58,22 +58,6 @@ def _is_matrix_schema(subschema): return False -# If we have a matrix with variable inner and outer dimensions, then drop the dimensions -# because we have no way to reconstruct them. -def _fixup_int_matrix(subschema): - if not _is_matrix_schema(subschema): - return - - outer_dim = _get_array_range(subschema) - inner_dim = _get_array_range(subschema.get('items', {})) - - if outer_dim[0] != outer_dim[1] and inner_dim[0] != inner_dim[1]: - subschema.pop('items', None) - subschema.pop('maxItems', None) - subschema.pop('minItems', None) - subschema['type'] = 'array' - - int_array_re = re.compile('int(8|16|32|64)-array') unit_types_re = re.compile('-(bps|kBps|bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|microvolt|picofarads|(milli)?celsius|kelvin|k?pascal)$') @@ -258,7 +242,6 @@ def fixup_vals(schema, path=[]): _fixup_reg_schema(schema, path=path) _fixup_remove_empty_items(schema) - _fixup_int_matrix(schema) _fixup_int_array_min_max_to_matrix(schema, path=path) _fixup_int_array_items_to_matrix(schema, path=path) _fixup_string_to_array(schema) diff --git a/dtschema/validator.py b/dtschema/validator.py index dfcdacfe..b2c1a021 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -24,12 +24,7 @@ def _merge_dim(dim1, dim2): d = [] for i in range(0, 2): - if dim1[i] == (0, 0): - d.insert(i, dim2[i]) - elif dim2[i] == (0, 0): - d.insert(i, dim1[i]) - else: - d.insert(i, (min(dim1[i] + dim2[i]), max(dim1[i] + dim2[i]))) + d.insert(i, (min(dim1[i][0], dim2[i][0]), max(dim1[i][1], dim2[i][1]))) return tuple(d) @@ -118,7 +113,15 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): # handle matrix dimensions if prop_type == 'phandle-array' or prop_type.endswith('-matrix'): - dim = (_get_array_range(subschema), _get_array_range(subschema.get('items', {}))) + outer = _get_array_range(subschema) + if 'items' in subschema: + if isinstance(subschema['items'], list): + inner = _get_array_range(subschema['items'][0]) + else: + inner = _get_array_range(subschema.get('items', {})) + else: + inner = (0, 0) + dim = (outer, inner) new_prop['dim'] = dim else: dim = ((0, 0), (0, 0)) @@ -494,7 +497,8 @@ def property_get_type_dim(self, propname): def property_has_fixed_dimensions(self, propname): dim = self.property_get_type_dim(propname) - if dim and dim[0][0] == dim[0][1] or dim[1][0] == dim[1][1]: + if dim and ((dim[0][0] > 0 and dim[0][0] == dim[0][1]) or \ + (dim[1][0] > 0 and dim[1][0] == dim[1][1])): return True return False From 3282a891060aace02e3eed4789739768060cea32 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Mon, 11 Dec 2023 12:52:53 +0100 Subject: [PATCH 429/505] schemas: iio: add io-backends schema IIO backends are devices connected to another IIO devices (consumers of the backends) providing services so that the consumer IIO device can be fully functional. One typical example of such an Hardware arrangement would be an high speed ADC that is connected to an FPGA IP core (through a serial data interface as LVDS) capable of handling the high sample rates. Examples of the provided services would be channel enablement/disablement. '#io-backend-cells' is also being added to the iio schema. While at it, fixed a typo in the top level description 'thes -> they'. Acked-by: Olivier Moysan Acked-by: Jonathan Cameron Signed-off-by: Nuno Sa --- dtschema/schemas/iio/iio-consumer.yaml | 15 ++++++++++++++- dtschema/schemas/iio/iio.yaml | 6 ++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/dtschema/schemas/iio/iio-consumer.yaml b/dtschema/schemas/iio/iio-consumer.yaml index 819e5df5..ad2cbd81 100644 --- a/dtschema/schemas/iio/iio-consumer.yaml +++ b/dtschema/schemas/iio/iio-consumer.yaml @@ -14,12 +14,13 @@ description: provided by an IIO device may use. As well, direct readings of channels on an IIO Device, an IIO device - can provide services to consumer devices. Thes are in the form of channel + can provide services to consumer devices. They are in the form of channel readings and properties. For example, an ADC might provide 3 channels to an analog accelerometer so that an accelerometer driver can use them to read the voltages that correspond to the accelerations on the 3 axis and apply appropriate calibration to provide useful outputs. + It also describes properties of a consumer of an IIO backend device. select: true properties: @@ -30,7 +31,19 @@ properties: to the device. Note: if the IIO provider specifies '0' for #io-channel-cells, then only the phandle portion of the pair will appear. + io-backends: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + List of phandles for IIO backends. IIO backends are devices connected to + another IIO devices (consumers of the backends) providing services so + that the consumer IIO device can be fully functional. One typical example + of such an Hardware arrangement would be an high speed ADC that is + connected to an FPGA IP core (through a serial data interface as LVDS) + capable of handling the high sample rates. Examples of the provided + services would be channel enablement/disablement. + dependencies: io-channel-names: [io-channels] + io-backend-names: [io-backends] additionalProperties: true diff --git a/dtschema/schemas/iio/iio.yaml b/dtschema/schemas/iio/iio.yaml index 727ca0f9..c18e935e 100644 --- a/dtschema/schemas/iio/iio.yaml +++ b/dtschema/schemas/iio/iio.yaml @@ -30,6 +30,12 @@ properties: with a single IIO output and 1 for nodes with multiple IIO outputs. A few unusual devices have a 2 level mapping. + "#io-backend-cells": + enum: [0, 1] + description: + Number of cells in an IIO backend; Typically 0 for nodes + with a single backend and 1 for nodes with multiple backends. + label: description: Unique name to identify which IIO channel or device this is. From c4c9967d2f306dd3f88db0c885dfd7605bb938be Mon Sep 17 00:00:00 2001 From: Agathe Porte Date: Tue, 23 Jan 2024 19:28:04 +0100 Subject: [PATCH 430/505] Fix SyntaxWarning: invalid escape sequence This commit fixes the following warnings: extract_example.py: SyntaxWarning: invalid escape sequence '\s' root_node = re.search('/\s*{', ex) extract_example.py: SyntaxWarning: invalid escape sequence '\s' int_val = re.search('\sinterrupts\s*=\s*<([0-9a-zA-Z |()_]+)>', ex).group(1) validator.py: SyntaxWarning: invalid escape sequence '\-' del props['^[a-z][a-z0-9\-]*$'] validator.py: SyntaxWarning: invalid escape sequence '\^' prog = re.compile('.*[\^\[{\(\$].*') validator.py: SyntaxWarning: invalid escape sequence '\-' if c != '^[a-zA-Z0-9][a-zA-Z0-9,+\-._/]+$': Signed-off-by: Agathe Porte --- dtschema/extract_example.py | 4 ++-- dtschema/validator.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dtschema/extract_example.py b/dtschema/extract_example.py index e424ad6b..79bf5ca1 100755 --- a/dtschema/extract_example.py +++ b/dtschema/extract_example.py @@ -75,11 +75,11 @@ def main(): if 'examples' in binding.keys(): for idx, ex in enumerate(binding['examples']): # Check if example contains a root node "/{" - root_node = re.search('/\s*{', ex) + root_node = re.search(r'/\s*{', ex) if not root_node: try: - int_val = re.search('\sinterrupts\s*=\s*<([0-9a-zA-Z |()_]+)>', ex).group(1) + int_val = re.search(r'\sinterrupts\s*=\s*<([0-9a-zA-Z |()_]+)>', ex).group(1) int_val = re.sub(r'\(.+|\)', r'0', int_val) int_cells = len(int_val.strip().split()) except: diff --git a/dtschema/validator.py b/dtschema/validator.py index b2c1a021..b2d3da3c 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -187,7 +187,7 @@ def get_prop_types(schemas): props = extract_types(schemas) # hack to remove aliases and generic patterns - del props['^[a-z][a-z0-9\-]*$'] + del props[r'^[a-z][a-z0-9\-]*$'] # Remove all node types for val in props.values(): @@ -221,11 +221,11 @@ def make_compatible_schema(schemas): # Allow 'foo' values for examples compat_sch += [{'pattern': '^foo'}] - prog = re.compile('.*[\^\[{\(\$].*') + prog = re.compile(r'.*[\^\[{\(\$].*') for c in compatible_list: if prog.match(c): # Exclude the generic pattern - if c != '^[a-zA-Z0-9][a-zA-Z0-9,+\-._/]+$' and \ + if c != r'^[a-zA-Z0-9][a-zA-Z0-9,+\-._/]+$' and \ not re.search(r'\.[+*]', c) and \ c.startswith('^') and c.endswith('$'): compat_sch += [{'pattern': c}] From b44adba245ad39a3aba9627e41287b57ef86e09f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 24 Jan 2024 11:27:53 -0600 Subject: [PATCH 431/505] dtb: Remove phandle types for impossible lengths Also remove phandle types for any impossible lengths. Signed-off-by: Rob Herring --- dtschema/dtb.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index f36ff344..59a6abfa 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -90,13 +90,13 @@ def prop_value(validator, nodename, p): # Filter out types impossible for the size of the property if len(prop_types) > 1: if len(p) > 4: - prop_types -= {'int32', 'uint32'} + prop_types -= {'int32', 'uint32', 'phandle'} else: - prop_types -= {'int64', 'uint64', 'int64-array', 'uint64-array'} + prop_types -= {'int64', 'uint64', 'int64-array', 'uint64-array', 'phandle-array'} if len(p) > 2: prop_types -= {'int16', 'uint16'} else: - prop_types -= {'int32', 'uint32', 'int32-array', 'uint32-array'} + prop_types -= {'int32', 'uint32', 'int32-array', 'uint32-array', 'phandle', 'phandle-array'} if len(p) > 1: prop_types -= {'int8', 'uint8'} else: From 98a2d18fd24372bc24fe0ff79fcd450c6d4221b3 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 23 Jan 2024 08:46:01 -0600 Subject: [PATCH 432/505] validator: Set minimum dimension when max is 1 The minimum dimension should be 1 if the maximum is already constrained to 1. Signed-off-by: Rob Herring --- dtschema/validator.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index b2d3da3c..ab70dc67 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -24,7 +24,11 @@ def _merge_dim(dim1, dim2): d = [] for i in range(0, 2): - d.insert(i, (min(dim1[i][0], dim2[i][0]), max(dim1[i][1], dim2[i][1]))) + minimum = min(dim1[i][0], dim2[i][0]) + maximum = max(dim1[i][1], dim2[i][1]) + if maximum == 1: + minimum = 1 + d.insert(i, (minimum, maximum)) return tuple(d) From 340996d36c4453cbfc6e4ced45c309904f499b45 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 23 Jan 2024 11:18:34 -0600 Subject: [PATCH 433/505] validator: Make undefined dimension 'None' Instead of ((0, 0), (0, 0)) for undefined dimensions just use 'None'. Signed-off-by: Rob Herring --- dtschema/validator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index ab70dc67..14d908e8 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -128,14 +128,14 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): dim = (outer, inner) new_prop['dim'] = dim else: - dim = ((0, 0), (0, 0)) + dim = None dup_prop = None for p in props[propname]: if p['type'] is None: dup_prop = p break - if dim != ((0, 0), (0, 0)) and \ + if dim and \ (p['type'] == 'phandle-array' or p['type'].endswith('-matrix')): if 'dim' not in p: p['dim'] = dim From 0277970a719ce944f9a193b6856d227f1606f6dd Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 23 Jan 2024 11:28:40 -0600 Subject: [PATCH 434/505] validator: Simplify merging dimensions If the type is a matrix/phandle-array, there is always a 'dim' element and _merge_dim() works if the dimensions are equal. Also, record the $id which prevent infinite recursion. Signed-off-by: Rob Herring --- dtschema/validator.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index 14d908e8..430aa999 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -137,12 +137,11 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): break if dim and \ (p['type'] == 'phandle-array' or p['type'].endswith('-matrix')): - if 'dim' not in p: - p['dim'] = dim - elif p['dim'] != dim: - # Conflicting dimensions - p['dim'] = _merge_dim(p['dim'], dim) - return + p['dim'] = _merge_dim(p['dim'], dim) + if schema['$id'] not in p['$id']: + p['$id'] += [schema['$id']] + new_prop = None + break if p['type'].startswith(prop_type): # Already have the same or looser type, just record the $id new_prop = None From 3fc752e82d8a61e7b59292b6b8d3fc1d49781086 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 24 Jan 2024 11:33:43 -0600 Subject: [PATCH 435/505] validator: Stop merging scalar types to matrix types There's a problem with properties which are defined as a single value and matrix/phandle-array. The matrix dimensions may not cover the single value case. In order to handle this, record the differing type rather than trying to merge the types. Then when decoding the property, we can make a better decision on the type. For string and string-array, they can still be merged. May have to revisit this when we drop making everything a matrix. Signed-off-by: Rob Herring --- dtschema/validator.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index 430aa999..2d8e88ba 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -142,16 +142,18 @@ def _extract_prop_type(props, schema, propname, subschema, is_pattern): p['$id'] += [schema['$id']] new_prop = None break - if p['type'].startswith(prop_type): - # Already have the same or looser type, just record the $id + if p['type'] == prop_type: new_prop = None if schema['$id'] not in p['$id']: p['$id'] += [schema['$id']] break - elif p['type'] in prop_type: - # Replace scalar type with array type - new_prop['$id'] += p['$id'] - dup_prop = p + if 'string' in prop_type and 'string' in p['type']: + # Extend string to string-array + if prop_type == 'string-array': + p['type'] = prop_type + if schema['$id'] not in p['$id']: + p['$id'] += [schema['$id']] + new_prop = None break if dup_prop: From 97c59117a99e9e69c8b19d18be6d302715539f29 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 28 Apr 2023 10:00:01 -0500 Subject: [PATCH 436/505] schemas: Split up PCI binding The pci-bus.yaml binding is mostly for host bridges. However, there is a need to define a binding schema for PCI-PCI bridges and PCI devices. Much of the pci-bus.yaml applies to PCI-PCI bridges as well. Split the binding into separate bus, device, host-bridge and PCI-PCI bridge bindings. A complication is that pci-bus.yaml is already widely referenced, so we need to preserve its name and all the host bridge properties. Just leaving pci-bus.yaml as the host bridge binding would be confusing. Instead, move everything to the new binding files and make pci-bus.yaml just a reference to pci-host-bridge.yaml. Signed-off-by: Rob Herring --- dtschema/schemas/pci/pci-bus-common.yaml | 165 ++++++++++++++++ dtschema/schemas/pci/pci-bus.yaml | 226 +--------------------- dtschema/schemas/pci/pci-device.yaml | 60 ++++++ dtschema/schemas/pci/pci-host-bridge.yaml | 60 ++++++ dtschema/schemas/pci/pci-pci-bridge.yaml | 31 +++ 5 files changed, 325 insertions(+), 217 deletions(-) create mode 100644 dtschema/schemas/pci/pci-bus-common.yaml create mode 100644 dtschema/schemas/pci/pci-device.yaml create mode 100644 dtschema/schemas/pci/pci-host-bridge.yaml create mode 100644 dtschema/schemas/pci/pci-pci-bridge.yaml diff --git a/dtschema/schemas/pci/pci-bus-common.yaml b/dtschema/schemas/pci/pci-bus-common.yaml new file mode 100644 index 00000000..5d5f0588 --- /dev/null +++ b/dtschema/schemas/pci/pci-bus-common.yaml @@ -0,0 +1,165 @@ +# SPDX-License-Identifier: (GPL2.0-only OR BSD-2-Clause) +# Copyright 2018 Linaro Ltd. +# Copyright 2024 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/pci-bus-common.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: PCI Bus Common Properties + +description: | + Common properties for PCI bus structure. + + PCI bus bridges have standardized Device Tree bindings: + + PCI Bus Binding to: IEEE Std 1275-1994 + http://www.devicetree.org/open-firmware/bindings/pci/pci2_1.pdf + + And for the interrupt mapping part: + + Open Firmware Recommended Practice: Interrupt Mapping + http://www.devicetree.org/open-firmware/practice/imap/imap0_9d.pdf + +maintainers: + - Rob Herring + +properties: + $nodename: + pattern: "^pcie?@" + + ranges: + oneOf: + - type: boolean + - minItems: 1 + maxItems: 32 # Should be enough + items: + minItems: 5 + maxItems: 8 + additionalItems: true + items: + - enum: + - 0x01000000 + - 0x02000000 + - 0x03000000 + - 0x42000000 + - 0x43000000 + - 0x81000000 + - 0x82000000 + - 0x83000000 + - 0xc2000000 + - 0xc3000000 + + dma-ranges: + oneOf: + - type: boolean + - minItems: 1 + maxItems: 32 # Should be enough + items: + minItems: 5 + maxItems: 8 + additionalItems: true + items: + - enum: + - 0x02000000 + - 0x03000000 + - 0x42000000 + - 0x43000000 + + "#address-cells": + const: 3 + + "#size-cells": + const: 2 + + device_type: + const: pci + + bus-range: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + maxItems: 2 + items: + maximum: 255 + + external-facing: + description: + When present, the port is externally facing. All bridges and endpoints + downstream of this port are external to the machine. The OS can, for + example, use this information to identify devices that cannot be + trusted with relaxed DMA protection, as users could easily attach + malicious devices to this port. + type: boolean + + "#interrupt-cells": + const: 1 + + interrupt-map: true +# minItems: 1 +# maxItems: 88 # 22 IDSEL x 4 IRQs +# items: +# minItems: 6 # 3 addr cells, 1 PCI IRQ cell, 1 phandle, 1+ parent addr and IRQ cells +# maxItems: 16 + + interrupt-map-mask: + items: + - description: PCI high address cell + minimum: 0 + maximum: 0xff00 + - description: PCI mid address cell + const: 0 + - description: PCI low address cell + const: 0 + - description: PCI IRQ cell + minimum: 0 + maximum: 7 + + max-link-speed: + description: + If present this property specifies PCI generation number for link + capability. Host drivers could add this as a strategy to avoid + unnecessary operation for unsupported link speed, for instance, trying to + do training for unsupported link speed, etc. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 1, 2, 3, 4 ] + + num-lanes: + description: The number of PCIe lanes + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 1, 2, 4, 8, 16, 32 ] + + reset-gpios: + description: GPIO controlled connection to PERST# signal + maxItems: 1 + + slot-power-limit-milliwatt: + description: + If present, specifies slot power limit in milliwatts. + This property is invalid in host bridge nodes. + maxItems: 1 + + supports-clkreq: + description: + If present this property specifies that CLKREQ signal routing exists from + root port to downstream device and host bridge drivers can do programming + which depends on CLKREQ signal existence. For example, programming root port + not to advertise ASPM L1 Sub-States support if there is no CLKREQ signal. + type: boolean + + aspm-no-l0s: + description: Disables ASPM L0s capability + type: boolean + +patternProperties: + "@1?[0-9a-f](,[0-7])?$": + type: object + $ref: pci-device.yaml# + additionalProperties: true + +required: + - device_type + - ranges + - "#address-cells" + - "#size-cells" + +additionalProperties: true diff --git a/dtschema/schemas/pci/pci-bus.yaml b/dtschema/schemas/pci/pci-bus.yaml index d8ba804a..f7e2ea2f 100644 --- a/dtschema/schemas/pci/pci-bus.yaml +++ b/dtschema/schemas/pci/pci-bus.yaml @@ -1,232 +1,24 @@ # SPDX-License-Identifier: (GPL2.0-only OR BSD-2-Clause) # Copyright 2018 Linaro Ltd. +# Copyright 2024 Arm Ltd. %YAML 1.2 --- $id: http://devicetree.org/schemas/pci/pci-bus.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# -title: PCI Bus Nodes +title: PCI Host Bridge nodes -description: | - Common properties for PCI host bridge nodes and PCI bus structure. - - PCI bus bridges have standardized Device Tree bindings: - - PCI Bus Binding to: IEEE Std 1275-1994 - http://www.devicetree.org/open-firmware/bindings/pci/pci2_1.pdf - - And for the interrupt mapping part: - - Open Firmware Recommended Practice: Interrupt Mapping - http://www.devicetree.org/open-firmware/practice/imap/imap0_9d.pdf +description: + For compatibility with existing references from host bridge bindings. New + users should reference pci-host-bridge.yaml instead. maintainers: - Rob Herring -properties: - $nodename: - pattern: "^pcie?@" - - ranges: - oneOf: - - $ref: /schemas/types.yaml#/definitions/flag - - minItems: 1 - maxItems: 32 # Should be enough - items: - minItems: 5 - maxItems: 7 - additionalItems: true - items: - - enum: - - 0x01000000 - - 0x02000000 - - 0x03000000 - - 0x42000000 - - 0x43000000 - - 0x81000000 - - 0x82000000 - - 0x83000000 - - 0xc2000000 - - 0xc3000000 - - reg: - description: | - On PCI-PCI bridge nodes, as defined in the IEEE Std 1275-1994 - document, it is a five-cell address encoded as (phys.hi phys.mid - phys.lo size.hi size.lo). phys.hi should contain the device's BDF as - 0b00000000 bbbbbbbb dddddfff 00000000. The other cells should be zero. - - The bus number is defined by firmware, through the standard bridge - configuration mechanism. If this port is a switch port, then firmware - allocates the bus number and writes it into the Secondary Bus Number - register of the bridge directly above this port. Otherwise, the bus - number of a root port is the first number in the bus-range property, - defaulting to zero. - - If firmware leaves the ARI Forwarding Enable bit set in the bridge - above this port, then phys.hi contains the 8-bit function number as - 0b00000000 bbbbbbbb ffffffff 00000000. Note that the PCIe specification - recommends that firmware only leaves ARI enabled when it knows that the - OS is ARI-aware. - - dma-ranges: - oneOf: - - type: boolean - - minItems: 1 - maxItems: 32 # Should be enough - items: - minItems: 5 - maxItems: 7 - additionalItems: true - items: - - enum: - - 0x02000000 - - 0x03000000 - - 0x42000000 - - 0x43000000 - - "#address-cells": - const: 3 - - "#size-cells": - const: 2 - - device_type: - const: pci - - bus-range: - $ref: /schemas/types.yaml#/definitions/uint32-array - minItems: 2 - maxItems: 2 - items: - maximum: 255 - - external-facing: - description: - When present, the port is externally facing. All bridges and endpoints - downstream of this port are external to the machine. The OS can, for - example, use this information to identify devices that cannot be - trusted with relaxed DMA protection, as users could easily attach - malicious devices to this port. - type: boolean - - "#interrupt-cells": - const: 1 +$ref: pci-host-bridge.yaml# - interrupt-map: true -# minItems: 1 -# maxItems: 88 # 22 IDSEL x 4 IRQs -# items: -# minItems: 6 # 3 addr cells, 1 PCI IRQ cell, 1 phandle, 1+ parent addr and IRQ cells -# maxItems: 16 - - interrupt-map-mask: - items: - - description: PCI high address cell - minimum: 0 - maximum: 0xf800 - - description: PCI mid address cell - const: 0 - - description: PCI low address cell - const: 0 - - description: PCI IRQ cell - minimum: 0 - maximum: 7 - - linux,pci-domain: - description: - If present this property assigns a fixed PCI domain number to a host bridge, - otherwise an unstable (across boots) unique number will be assigned. - It is required to either not set this property at all or set it for all - host bridges in the system, otherwise potentially conflicting domain numbers - may be assigned to root buses behind different host bridges. The domain - number for each host bridge in the system must be unique. - $ref: /schemas/types.yaml#/definitions/uint32 - - max-link-speed: - description: - If present this property specifies PCI generation number for link - capability. Host drivers could add this as a strategy to avoid - unnecessary operation for unsupported link speed, for instance, trying to - do training for unsupported link speed, etc. - $ref: /schemas/types.yaml#/definitions/uint32 - enum: [ 1, 2, 3, 4 ] - - msi-map: - $ref: /schemas/types.yaml#/definitions/uint32-matrix - items: - minItems: 3 - items: - - description: The RID base matched by the entry - - description: phandle to msi-controller node - - description: (optional) The msi-specifier produced for the first RID matched - by the entry. Currently, msi-specifier is 0 or 1 cells. - - description: The length of consecutive RIDs following the RID base - - msi-map-mask: - description: A mask to be applied to each Requester ID prior to being - mapped to an msi-specifier per the msi-map property. - $ref: /schemas/types.yaml#/definitions/uint32 - - num-lanes: - description: The number of PCIe lanes - $ref: /schemas/types.yaml#/definitions/uint32 - enum: [ 1, 2, 4, 8, 16, 32 ] - - reset-gpios: - description: GPIO controlled connection to PERST# signal - maxItems: 1 - - slot-power-limit-milliwatt: - description: - If present, specifies slot power limit in milliwatts. - This property is invalid in host bridge nodes. - maxItems: 1 - - supports-clkreq: - description: - If present this property specifies that CLKREQ signal routing exists from - root port to downstream device and host bridge drivers can do programming - which depends on CLKREQ signal existence. For example, programming root port - not to advertise ASPM L1 Sub-States support if there is no CLKREQ signal. - type: boolean - - aspm-no-l0s: - description: Disables ASPM L0s capability - type: boolean - - vendor-id: - description: The PCI vendor ID - $ref: /schemas/types.yaml#/definitions/uint32 - - device-id: - description: The PCI device ID - $ref: /schemas/types.yaml#/definitions/uint32 - -patternProperties: - "^[a-zA-Z][a-zA-Z0-9,+\\-._]{0,63}@1?[0-9a-f](,[0-7])?$": - type: object - properties: - compatible: - contains: - pattern: "^(pci[0-9a-f]{3,4},[0-9a-f]{1,4}|pciclass,[0-9a-f]{4,6})$" - reg: - items: - minItems: 5 - maxItems: 5 - minItems: 1 - maxItems: 6 # Up to 6 BARs - required: - - reg - -required: - - device_type - - ranges - - reg - - "#address-cells" - - "#size-cells" - -dependentRequired: - msi-map-mask: [ msi-map ] +properties: + # Remove when existing users fixed + reg: true additionalProperties: true diff --git a/dtschema/schemas/pci/pci-device.yaml b/dtschema/schemas/pci/pci-device.yaml new file mode 100644 index 00000000..1b6525c5 --- /dev/null +++ b/dtschema/schemas/pci/pci-device.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL2.0-only OR BSD-2-Clause) +# Copyright 2018 Linaro Ltd. +# Copyright 2024 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/pci-device.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: PCI Device Node Common Properties + +description: | + Common properties for PCI device nodes. Based on: + + PCI Bus Binding to: IEEE Std 1275-1994 + http://www.devicetree.org/open-firmware/bindings/pci/pci2_1.pdf + +maintainers: + - Rob Herring + +properties: + compatible: + contains: + pattern: '^(pci[0-9a-f]{2,4},[0-9a-f]{1,4}|pciclass,[01][0-9a-f]{3}([0-9a-f]{2})?)$' + + reg: + description: + The first entry must be the configuration space. The bus number + generally 0/ignored for FDT. See section 4.1.1 in PCI bus binding + for further information. + additionalItems: true + items: + - description: Configuration Space for the device + items: + - maximum: 0x00ffff00 # Should be 0xff00 + multipleOf: 0x100 + - const: 0 + - const: 0 + - const: 0 + - const: 0 + + interrupts: + items: + - items: + - enum: [1, 2, 3, 4] # INTA, INTB, INTC, INTD + + assigned-addresses: + $ref: /schemas/types.yaml#/definitions/uint32-array + + vendor-id: + description: The PCI vendor ID + $ref: /schemas/types.yaml#/definitions/uint32 + + device-id: + description: The PCI device ID + $ref: /schemas/types.yaml#/definitions/uint32 + +required: + - reg + +additionalProperties: true diff --git a/dtschema/schemas/pci/pci-host-bridge.yaml b/dtschema/schemas/pci/pci-host-bridge.yaml new file mode 100644 index 00000000..fbbb8298 --- /dev/null +++ b/dtschema/schemas/pci/pci-host-bridge.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL2.0-only OR BSD-2-Clause) +# Copyright 2018 Linaro Ltd. +# Copyright 2024 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/pci-host-bridge.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: PCI Host Bridge Nodes + +description: | + Common properties for PCI host bridge nodes. PCI host bridges implement the + PCI bus binding plus additional properties for mapping host resources into + PCI space. + +maintainers: + - Rob Herring + +allOf: + - $ref: pci-bus-common.yaml# + - $ref: pci-iommu.yaml# + +properties: + linux,pci-domain: + description: + If present this property assigns a fixed PCI domain number to a host bridge, + otherwise an unstable (across boots) unique number will be assigned. + It is required to either not set this property at all or set it for all + host bridges in the system, otherwise potentially conflicting domain numbers + may be assigned to root buses behind different host bridges. The domain + number for each host bridge in the system must be unique. + $ref: /schemas/types.yaml#/definitions/uint32 + + msi-map: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + items: + items: + - description: The RID base matched by the entry + - description: phandle to msi-controller node + - description: (optional) The msi-specifier produced for the first RID matched + by the entry. Currently, msi-specifier is 0 or 1 cells. + - description: The length of consecutive RIDs following the RID base + + msi-map-mask: + description: A mask to be applied to each Requester ID prior to being + mapped to an msi-specifier per the msi-map property. + $ref: /schemas/types.yaml#/definitions/uint32 + + vendor-id: + description: The PCI vendor ID + $ref: /schemas/types.yaml#/definitions/uint32 + + device-id: + description: The PCI device ID + $ref: /schemas/types.yaml#/definitions/uint32 + +dependentRequired: + msi-map-mask: [ msi-map ] + +additionalProperties: true diff --git a/dtschema/schemas/pci/pci-pci-bridge.yaml b/dtschema/schemas/pci/pci-pci-bridge.yaml new file mode 100644 index 00000000..172399b9 --- /dev/null +++ b/dtschema/schemas/pci/pci-pci-bridge.yaml @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: (GPL2.0-only OR BSD-2-Clause) +# Copyright 2018 Linaro Ltd. +# Copyright 2024 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/pci-pci-bridge.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: PCI-PCI Bridge Nodes + +description: | + PCI-PCI Bridge nodes are both a PCI device and a PCI bus. + + PCI-PCI bridges have standardized Device Tree bindings: + + PCI Bus Binding to: IEEE Std 1275-1994 + http://www.devicetree.org/open-firmware/bindings/pci/pci2_1.pdf + +maintainers: + - Rob Herring + +allOf: + - $ref: pci-device.yaml# + - $ref: pci-bus-common.yaml# + +properties: + compatible: + contains: + const: pciclass,0604 + +unevaluatedProperties: false From e170c2a0c3208e4b8399b5f946818e2e34c85c7e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 24 Jan 2024 15:56:37 -0600 Subject: [PATCH 437/505] schemas: pci: Add standard PCIe slot supplies Add regulator supply properties for the standard PCIe slot voltage rails 12V, 3.3V, and 3.3V AUX. Signed-off-by: Rob Herring --- dtschema/schemas/pci/pci-bus-common.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dtschema/schemas/pci/pci-bus-common.yaml b/dtschema/schemas/pci/pci-bus-common.yaml index 5d5f0588..dfd5c32e 100644 --- a/dtschema/schemas/pci/pci-bus-common.yaml +++ b/dtschema/schemas/pci/pci-bus-common.yaml @@ -150,6 +150,15 @@ properties: description: Disables ASPM L0s capability type: boolean + vpcie12v-supply: + description: 12v regulator phandle for the slot + + vpcie3v3-supply: + description: 3.3v regulator phandle for the slot + + vpcie3v3aux-supply: + description: 3.3v AUX regulator phandle for the slot + patternProperties: "@1?[0-9a-f](,[0-7])?$": type: object From 4548397d7522bc90b241a234ec312e240e6b37a9 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Fri, 2 Feb 2024 15:45:20 +0530 Subject: [PATCH 438/505] schemas: pci: bridge: Document "supports-d3" property Even though the PCIe spec states that all PCIe devices should support D0 and D3 states (both D3 hot and D3 cold), PCIe bridges do not follow that in practice. Spec r3.0, section 5.3.1: "All Functions must support the D0 and D3 states (both D3 hot and D3 cold ). The D1 and D2 states are optional." Also, unlike D1 and D2, D3 support cannot be determined using the standard Power Management Control/Status (PMCSR) Register. So the OS needs to know the D3 support using platform specific ways. Hence, for DT based platforms, let's add a new property called "supports-d3" that specifies that the PCI bridge is D3 capable. Signed-off-by: Manivannan Sadhasivam --- dtschema/schemas/pci/pci-pci-bridge.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dtschema/schemas/pci/pci-pci-bridge.yaml b/dtschema/schemas/pci/pci-pci-bridge.yaml index 172399b9..d8de2504 100644 --- a/dtschema/schemas/pci/pci-pci-bridge.yaml +++ b/dtschema/schemas/pci/pci-pci-bridge.yaml @@ -28,4 +28,10 @@ properties: contains: const: pciclass,0604 + supports-d3: + description: + If present, this property specifies that the bridge supports transitioning + to D3 states. + type: boolean + unevaluatedProperties: false From 9975007b67806a11f216b642e839c3301b62e38e Mon Sep 17 00:00:00 2001 From: Artur Weber Date: Mon, 19 Feb 2024 15:36:24 +0100 Subject: [PATCH 439/505] schemas: chosen: Allow 32-bit memory ranges for memory range properties These properties were moved from 64-bit-specific schemas, but were never updated to allow non-64-bit memory ranges. Since there is nothing 64-bit-specific about them, update their definitions to allow 32-bit memory ranges. Signed-off-by: Artur Weber --- dtschema/schemas/chosen.yaml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/dtschema/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml index 6d5c3f15..3aa28dfd 100644 --- a/dtschema/schemas/chosen.yaml +++ b/dtschema/schemas/chosen.yaml @@ -75,7 +75,9 @@ properties: a different secondary CPU release mechanism). linux,elfcorehdr: - $ref: types.yaml#/definitions/uint64-array + oneOf: + - $ref: types.yaml#/definitions/uint32-array + - $ref: types.yaml#/definitions/uint64-array maxItems: 2 description: | This property holds the memory range, the address and the size, of the @@ -93,7 +95,9 @@ properties: respectively, of the root node. linux,usable-memory-range: - $ref: types.yaml#/definitions/uint64-array + oneOf: + - $ref: types.yaml#/definitions/uint32-array + - $ref: types.yaml#/definitions/uint64-array maxItems: 2 description: | This property holds a base address and size, describing a limited region @@ -187,7 +191,9 @@ properties: should only use the "stdout-path" property. linux,ima-kexec-buffer: - $ref: types.yaml#definitions/uint64-array + oneOf: + - $ref: types.yaml#/definitions/uint32-array + - $ref: types.yaml#/definitions/uint64-array maxItems: 2 description: | This property(currently used by powerpc, arm64) holds the memory range, @@ -205,7 +211,9 @@ properties: #address-cells and #size-cells, respectively of the root node. linux,tpm-kexec-buffer: - $ref: types.yaml#definitions/uint64-array + oneOf: + - $ref: types.yaml#/definitions/uint32-array + - $ref: types.yaml#/definitions/uint64-array maxItems: 2 description: | This property (currently used by powerpc64) holds the memory range, From eb9f5d3210896c1c21304996fb88df6f6ab401f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Lebrun?= Date: Wed, 21 Feb 2024 17:42:18 +0100 Subject: [PATCH 440/505] schemas: i2c: Add transfer timeout property to controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 'i2c-transfer-timeout-us' property to i2c-controller.yaml signaling the number of microseconds to wait before considering an I2C transfer has failed. Unit is microseconds (µs). Reviewed-by: Wolfram Sang Signed-off-by: Théo Lebrun --- dtschema/schemas/i2c/i2c-controller.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index 8cf9171a..09b256f0 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -49,6 +49,11 @@ properties: Number of microseconds the clock line needs to be pulled down in order to force a waiting state. + i2c-transfer-timeout-us: + description: + Number of microseconds to wait before considering an I2C transfer has + failed. + i2c-scl-has-clk-low-timeout: type: boolean description: From 6f5e15ccdf48cb31951d364cea556201a3862a4e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 23 Feb 2024 09:38:17 -0700 Subject: [PATCH 441/505] Revert "schemas: i2c-controller: Add 'no-detect' property" This reverts commit ba55f96c6d8d8c58f375393bca0c251574986c40. This property was accepted, but then users of it were rejected[1][2]. Wolfram Sang pointed this out: "no-detect" is broken. At the least, it should be named something like "bus-fully-described" and then the OS can decide to leave out auto-detection mechanisms. If you are interested in the latter, you can simply disable class based instantiation on the host controller. No need to describe this in DT. [1] https://lore.kernel.org/all/20220405121627.1560949-2-vincent.whitchurch@axis.com/ [2] https://lore.kernel.org/all/20220429130749.3032462-1-vincent.whitchurch@axis.com/ Signed-off-by: Rob Herring --- dtschema/schemas/i2c/i2c-controller.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index 09b256f0..eda59391 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -132,12 +132,6 @@ properties: description: states that the optional SMBus-Alert feature apply to this bus. - no-detect: - type: boolean - description: - States that no other devices are present on this bus other than the ones - listed in the devicetree. - allOf: - not: required: From 46f3343975359faa0c64559f986af9fb16dc5a2f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 23 Feb 2024 09:56:09 -0700 Subject: [PATCH 442/505] schemas: i2c: Update the bus frequency range 1000 was never really any spec'ed minimum, so let's drop it to 1Hz. There's now a 5MHz high speed mode, so bump the max to that. Signed-off-by: Rob Herring --- dtschema/schemas/i2c/i2c-controller.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index eda59391..96700820 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -27,8 +27,8 @@ properties: const: 0 clock-frequency: - minimum: 1000 - maximum: 3000000 + minimum: 1 + maximum: 5000000 i2c-scl-falling-time-ns: description: From 229ba6b76e7a81f0ad4b272d71d37d6d8335a480 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 14 Feb 2024 10:05:52 -0600 Subject: [PATCH 443/505] check_compatible: Add quiet mode and set return value Signed-off-by: Rob Herring --- dtschema/check_compatible.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/dtschema/check_compatible.py b/dtschema/check_compatible.py index 0115145c..8e8b1479 100755 --- a/dtschema/check_compatible.py +++ b/dtschema/check_compatible.py @@ -13,6 +13,8 @@ def main(): epilog='Arguments can also be passed in a file prefixed with a "@" character.') ap.add_argument("compatible_str", nargs='+', help="1 or more compatible strings to check for a match") + ap.add_argument('-q', '--quiet', action="store_true", + help="Suppress printing matches") ap.add_argument('-v', '--invert-match', action="store_true", help="invert sense of matching, printing compatible which don't match") ap.add_argument('-V', '--version', help="Print version number", @@ -26,6 +28,15 @@ def main(): undoc_compats = dtschema.DTValidator([args.schema]).get_undocumented_compatibles(args.compatible_str) if args.invert_match: - print(*undoc_compats, sep="\n") + if len(undoc_compats) > 0: + if not args.quiet: + print(*undoc_compats, sep="\n") + return 0 else: - print(*set(args.compatible_str).difference(undoc_compats), sep="\n") + matches = set(args.compatible_str).difference(undoc_compats) + if len(matches) > 0: + if not args.quiet: + print(*matches, sep="\n") + return 0 + + return -1 From da1dcddb5e696f081ab815dd8e635a09b7d6186e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 4 Mar 2024 16:51:50 -0600 Subject: [PATCH 444/505] dtb: Skip decoding strings if not nul terminated If a property is defined to be a string, make sure it is nul terminated before decoding it. This fixes a case where <1> int was decoded into ['', '', '', '']. This still will not fix the case where there's the last byte is nul. There's only so much we can do for garbage in. Signed-off-by: Rob Herring --- dtschema/dtb.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 59a6abfa..135982d4 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -137,6 +137,9 @@ def prop_value(validator, nodename, p): return data if fmt.startswith('string'): + if not data.endswith(b'\0'): + # Wrong data type?, skip decoding to force errors + return data return data[:-1].decode(encoding='ascii').split('\0') if {'flag'} & prop_types: From 2bd4676206e35ecd209ece06b478c1f1fa7a38ce Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 6 Mar 2024 18:28:16 -0600 Subject: [PATCH 445/505] schemas: Ensure -names properties' entries are unique The common '.*-names' schema doesn't enforce that entries are unique as there are a few oddballs. For all the normal cases, we need to enforce the entries are unique by setting the type to "string-array". Unfortunately, some oddball cases for 'dma-names' slipped in, so that one can't be enforced. Signed-off-by: Rob Herring --- dtschema/schemas/iio/iio-consumer.yaml | 6 ++++++ dtschema/schemas/interconnects.yaml | 3 +++ dtschema/schemas/pinctrl/pinctrl-consumer.yaml | 3 ++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/dtschema/schemas/iio/iio-consumer.yaml b/dtschema/schemas/iio/iio-consumer.yaml index ad2cbd81..7a285a66 100644 --- a/dtschema/schemas/iio/iio-consumer.yaml +++ b/dtschema/schemas/iio/iio-consumer.yaml @@ -31,6 +31,9 @@ properties: to the device. Note: if the IIO provider specifies '0' for #io-channel-cells, then only the phandle portion of the pair will appear. + io-channel-names: + $ref: /schemas/types.yaml#/definitions/string-array + io-backends: $ref: /schemas/types.yaml#/definitions/phandle-array description: @@ -42,6 +45,9 @@ properties: capable of handling the high sample rates. Examples of the provided services would be channel enablement/disablement. + io-backend-names: + $ref: /schemas/types.yaml#/definitions/string-array + dependencies: io-channel-names: [io-channels] io-backend-names: [io-backends] diff --git a/dtschema/schemas/interconnects.yaml b/dtschema/schemas/interconnects.yaml index 40ecf3c1..6bf40d4c 100644 --- a/dtschema/schemas/interconnects.yaml +++ b/dtschema/schemas/interconnects.yaml @@ -15,6 +15,9 @@ properties: interconnects: $ref: types.yaml#/definitions/phandle-array + interconnect-names: + $ref: /schemas/types.yaml#/definitions/string-array + dependencies: interconnect-names: [interconnects] diff --git a/dtschema/schemas/pinctrl/pinctrl-consumer.yaml b/dtschema/schemas/pinctrl/pinctrl-consumer.yaml index c6dde464..648c7547 100644 --- a/dtschema/schemas/pinctrl/pinctrl-consumer.yaml +++ b/dtschema/schemas/pinctrl/pinctrl-consumer.yaml @@ -16,7 +16,8 @@ select: true properties: pinctrl-0: true - pinctrl-names: true + pinctrl-names: + $ref: /schemas/types.yaml#/definitions/string-array patternProperties: "^pinctrl-[0-9]+$": From 43f51560bca30331f5156c783d19d218a648aac7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 7 Mar 2024 17:02:19 -0600 Subject: [PATCH 446/505] schemas: dma: Ensure 'dma-names' entries are unique (mostly) 'dma-names' has to be treated special as there's some Renesas bindings which abuse dmas/dma-names to have multiple providers for the same thing. IOW, the platform has 2 DMA controllers and a device can use either one. This should have probably been handled with some form of nexus node instead. In order to prevent this in other cases, only allow 'tx' and 'rx' to be repeated. Signed-off-by: Rob Herring --- dtschema/schemas/dma/dma.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dtschema/schemas/dma/dma.yaml b/dtschema/schemas/dma/dma.yaml index 069f709a..1adef872 100644 --- a/dtschema/schemas/dma/dma.yaml +++ b/dtschema/schemas/dma/dma.yaml @@ -17,7 +17,13 @@ properties: dmas: $ref: /schemas/types.yaml#/definitions/phandle-array - dma-names: true + dma-names: + anyOf: + - uniqueItems: true + - items: + # Hack around Renesas bindings which repeat entries to support + # multiple possible DMA providers + enum: [rx, tx] dependencies: dma-names: [ dmas ] From 5c8869ecb534cecd398b8fd629f1421fdd6cbf5b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 8 Mar 2024 11:53:50 -0600 Subject: [PATCH 447/505] dtb: Filter out types with the wrong length multiple If we have a property which can be a string or non-string type and its value has empty strings in it, it gets incorrectly decoded a a non-string. There's not a great way to solve this heuristic. Perhaps we could count the number of non-zero length strings and pick string type if it is above some percentage. For now, when the length is not a multiple that fits the integer types, we can for sure remove those integer types. If a string property happens to have a length matching a integer multiple, then there's still a problem. Signed-off-by: Rob Herring --- dtschema/dtb.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 135982d4..958cefb8 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -89,6 +89,13 @@ def prop_value(validator, nodename, p): # Filter out types impossible for the size of the property if len(prop_types) > 1: + if len(p) % 8: + prop_types -= {'int64', 'uint64', 'int64-array', 'uint64-array'} + if len(p) % 4: + prop_types -= {'int32', 'uint32', 'int32-array', 'uint32-array', 'phandle', 'phandle-array'} + if len(p) % 2: + prop_types -= {'int16', 'uint16', 'int16-array', 'uint16-array'} + if len(p) > 4: prop_types -= {'int32', 'uint32', 'phandle'} else: From 08eff8e6167e9e0bc1694af6c298b4584105a057 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 8 Mar 2024 11:13:57 -0600 Subject: [PATCH 448/505] Add a dedicated type for address properties There are a few properties which are sized based on "#address-cells" and "#size-cells". "reg" is of course the most common, but there's a growing number in /chosen. As these properties need special parsing to decode, give them a dedicated type. Signed-off-by: Rob Herring --- dtschema/dtb.py | 11 ++++++----- dtschema/schemas/reg.yaml | 2 +- dtschema/schemas/types.yaml | 6 ++++++ dtschema/validator.py | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 958cefb8..a11089c7 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -28,7 +28,8 @@ 'uint32': u32, 'int64': s64, 'uint64': u64, - 'phandle': u32 + 'phandle': u32, + 'address': u32 } @@ -451,15 +452,15 @@ def fixup_interrupts(dt, icells): i += cells -def fixup_addresses(dt, ac, sc): +def fixup_addresses(validator, dt, ac, sc): for k, v in dt.items(): if isinstance(v, dict): if '#address-cells' in dt: ac = _get_cells_size(dt,'#address-cells') if '#size-cells' in dt: sc = _get_cells_size(dt, '#size-cells') - fixup_addresses(v, ac, sc) - elif k == 'reg': + fixup_addresses(validator, v, ac, sc) + elif 'address' in validator.property_get_type(k): i = 0 dt[k] = [] val = v[0] @@ -486,7 +487,7 @@ def fdt_unflatten(validator, dtb): #print(phandle_loc) fixup_gpios(dt) fixup_interrupts(dt, 1) - fixup_addresses(dt, 2, 1) + fixup_addresses(validator, dt, 2, 1) fixup_phandles(validator, dt) # pprint.pprint(dt, compact=True) diff --git a/dtschema/schemas/reg.yaml b/dtschema/schemas/reg.yaml index a06e48be..c7cc87d2 100644 --- a/dtschema/schemas/reg.yaml +++ b/dtschema/schemas/reg.yaml @@ -30,7 +30,7 @@ properties: - $ref: types.yaml#/definitions/uint32-matrix reg: - $ref: types.yaml#/definitions/uint32-matrix + $ref: types.yaml#/definitions/address reg-io-width: $ref: types.yaml#/definitions/uint32 diff --git a/dtschema/schemas/types.yaml b/dtschema/schemas/types.yaml index 1a605404..568efb33 100644 --- a/dtschema/schemas/types.yaml +++ b/dtschema/schemas/types.yaml @@ -349,3 +349,9 @@ definitions: const: 0 additionalItems: $ref: "#/definitions/cell" + + address: + $ref: "#/definitions/uint32-matrix" + items: + minItems: 1 + maxItems: 5 # At most 3 address cells and 2 size cells diff --git a/dtschema/validator.py b/dtschema/validator.py index 2d8e88ba..e2c99186 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -33,7 +33,7 @@ def _merge_dim(dim1, dim2): return tuple(d) -type_re = re.compile('(flag|u?int(8|16|32|64)(-(array|matrix))?|string(-array)?|phandle(-array)?)') +type_re = re.compile('(address|flag|u?int(8|16|32|64)(-(array|matrix))?|string(-array)?|phandle(-array)?)') def _extract_prop_type(props, schema, propname, subschema, is_pattern): From c95c9ad63c51f8d9cfb258e6f17a8001efab6d64 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 8 Mar 2024 11:22:30 -0600 Subject: [PATCH 449/505] schemas: chosen: Change address+size properties' type to 'address' The existing schemas for address+size properties aren't really correct and differ compared to 'reg'. They also aren't getting decoded to the correct sizes which results in false warnings. Use the new 'address' type for all the address+size properties in /chosen. Signed-off-by: Rob Herring --- dtschema/schemas/chosen.yaml | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/dtschema/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml index 3aa28dfd..5e73d77e 100644 --- a/dtschema/schemas/chosen.yaml +++ b/dtschema/schemas/chosen.yaml @@ -75,10 +75,8 @@ properties: a different secondary CPU release mechanism). linux,elfcorehdr: - oneOf: - - $ref: types.yaml#/definitions/uint32-array - - $ref: types.yaml#/definitions/uint64-array - maxItems: 2 + $ref: types.yaml#/definitions/address + maxItems: 1 description: | This property holds the memory range, the address and the size, of the elf core header which mainly describes the panicked kernel\'s memory @@ -95,10 +93,8 @@ properties: respectively, of the root node. linux,usable-memory-range: - oneOf: - - $ref: types.yaml#/definitions/uint32-array - - $ref: types.yaml#/definitions/uint64-array - maxItems: 2 + $ref: types.yaml#/definitions/address + maxItems: 1 description: | This property holds a base address and size, describing a limited region in which memory may be considered available for use by the kernel. Memory @@ -124,18 +120,16 @@ properties: respectively, of the root node. linux,initrd-start: - oneOf: - - $ref: types.yaml#/definitions/uint32 - - $ref: types.yaml#/definitions/uint64 + $ref: types.yaml#/definitions/address + maxItems: 1 description: These properties hold the physical start and end address of an initrd that\'s loaded by the bootloader. Note that linux,initrd-start is inclusive, but linux,initrd-end is exclusive. linux,initrd-end: - oneOf: - - $ref: types.yaml#/definitions/uint32 - - $ref: types.yaml#/definitions/uint64 + $ref: types.yaml#/definitions/address + maxItems: 1 description: These properties hold the physical start and end address of an initrd that\'s loaded by the bootloader. Note that linux,initrd-start is inclusive, but @@ -191,10 +185,8 @@ properties: should only use the "stdout-path" property. linux,ima-kexec-buffer: - oneOf: - - $ref: types.yaml#/definitions/uint32-array - - $ref: types.yaml#/definitions/uint64-array - maxItems: 2 + $ref: types.yaml#/definitions/address + maxItems: 1 description: | This property(currently used by powerpc, arm64) holds the memory range, "the address and the size", of the Integrity Measurement Architecture(IMA) @@ -211,10 +203,8 @@ properties: #address-cells and #size-cells, respectively of the root node. linux,tpm-kexec-buffer: - oneOf: - - $ref: types.yaml#/definitions/uint32-array - - $ref: types.yaml#/definitions/uint64-array - maxItems: 2 + $ref: types.yaml#/definitions/address + maxItems: 1 description: | This property (currently used by powerpc64) holds the memory range, "the address and the size", of the TPM's measurement log that is being From 5fdf9654d5069ef0ec430525d98cf3c04086405d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 12 Mar 2024 14:01:39 -0600 Subject: [PATCH 450/505] fixups: Fix dropping of array 'items' schema In the case of a schema having the schema form of 'items', _fixup_int_array_min_max_to_matrix() is just dropping 'items' schema. That also then causes 'minItems' or 'maxItems' to get added which we normally only do if 'items' is a list. Signed-off-by: Rob Herring --- dtschema/fixups.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index f57d4eb6..e009fdc7 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -114,6 +114,8 @@ def _fixup_int_array_min_max_to_matrix(subschema, path=[]): tmpsch['minItems'] = subschema.pop('minItems') if 'maxItems' in subschema: tmpsch['maxItems'] = subschema.pop('maxItems') + if 'items' in subschema: + tmpsch['items'] = subschema.pop('items') if tmpsch: subschema['items'] = tmpsch From fc1eff6127b80e2b44358ed0577e82c6a5f62bcc Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Thu, 7 Mar 2024 22:56:33 -0800 Subject: [PATCH 451/505] schemas: Add schema for post-init-providers The post-init-providers property can be used to break a dependency cycle by marking some provider(s) as a post-device-initialization provider(s). This allows an OS to do a better job at ordering initialization and suspend/resume of the devices in a dependency cycle. Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20240308065633.2180623-1-saravanak@google.com Signed-off-by: Rob Herring --- dtschema/schemas/post-init-providers.yaml | 105 ++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 dtschema/schemas/post-init-providers.yaml diff --git a/dtschema/schemas/post-init-providers.yaml b/dtschema/schemas/post-init-providers.yaml new file mode 100644 index 00000000..fd2c3365 --- /dev/null +++ b/dtschema/schemas/post-init-providers.yaml @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2024, Google LLC. All rights reserved. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/post-init-providers.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Post-device-initialization providers + +maintainers: + - Saravana Kannan + +description: | + This property is used to indicate that the device(s) pointed to by the + property are not needed for the initialization of the device that lists this + property. This property does not make a device (that's previously not a + provider) into a provider. It simply downgrades an existing provider to a + post-device-initialization provider. + + A device can list its providers in devicetree using one or more of the + standard devicetree bindings. By default, it is assumed that the provider + device can be initialized before the consumer device is initialized. + + However, that assumption cannot be made when there are cyclic dependencies + between devices. Since each device is a provider (directly or indirectly) of + the others in the cycle, there is no guaranteed safe order for initializing + the devices in a cycle. We can try to initialize them in an arbitrary order + and eventually successfully initialize all of them, but that doesn't always + work well. + + For example, say, + * The device tree has the following cyclic dependency X -> Y -> Z -> X (where + -> denotes "depends on"). + * But X is not needed to fully initialize Z (X might be needed only when a + specific functionality is requested after initialization of Z). + + If all the other -> are mandatory initialization dependencies, then trying to + initialize the devices in a loop (or arbitrarily) will always eventually end + up with the devices being initialized in the order Z, Y and X. + + However, if Y is an optional provider for X (where X provides limited + functionality when Y is not initialized and providing its services), then + trying to initialize the devices in a loop (or arbitrarily) could end up with + the devices being initialized in the following order: + + * Z, Y and X - All devices provide full functionality + * Z, X and Y - X provides partial functionality + * X, Z and Y - X provides partial functionality + + However, we always want to initialize the devices in the order Z, Y and X + since that provides the full functionality without interruptions. + + One alternate option that might be suggested is to have the driver for X + notice that Y became available at a later point and adjust the functionality + it provides. However, other userspace applications could have started using X + with the limited functionality before Y was available and it might not be + possible to transparently transition X or the users of X to full + functionality while X is in use. + + Similarly, when it comes to suspend (resume) ordering, it's unclear which + device in a dependency cycle needs to be suspended/resumed first and trying + arbitrary orders can result in system crashes or instability. + + Explicitly calling out which link in a cycle needs to be broken when + determining the order, simplifies things a lot, improves efficiency, makes + the behavior more deterministic and maximizes the functionality that can be + provided without interruption. + + This property is used to provide this additional information between devices + in a cycle by telling which provider(s) is not needed for initializing the + device that lists this property. + + In the example above, Z would list X as a post-init-providers and the + initialization dependency would become X -> Y -> Z -/-> X. So the best order + to initialize them becomes clear: Z, Y and then X. + +select: true + +properties: + post-init-providers: + # One or more providers can be marked as post initialization provider + description: + List of phandles to providers that are not needed for initializing or + resuming this device. + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + maxItems: 1 + +additionalProperties: true + +examples: + - | + gcc: clock-controller@1000 { + compatible = "vendor,soc4-gcc", "vendor,soc1-gcc"; + reg = <0x1000 0x80>; + clocks = <&dispcc 0x1>; + #clock-cells = <1>; + post-init-providers = <&dispcc>; + }; + dispcc: clock-controller@2000 { + compatible = "vendor,soc4-dispcc", "vendor,soc1-dispcc"; + reg = <0x2000 0x80>; + clocks = <&gcc 0xdd>; + #clock-cells = <1>; + }; From c1cef8b2d62d79f46f55a963640c05322ab4b3e8 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Wed, 20 Mar 2024 22:23:18 +0100 Subject: [PATCH 452/505] README: fix broken link to json-schema.org The link to the documentation is not valid anymore. There are at least two sections that might be used as a replacement ("Specification" and "Getting Started"), but to avoid a broken link in the future, point to the main site. Signed-off-by: Javier Carrasco --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d2f6e8e..6b54c69c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ The dtschema module contains tools and schema data for Devicetree schema validation using the -[json-schema](http://json-schema.org/documentation.html) vocabulary. +[json-schema](https://json-schema.org) vocabulary. The tools validate Devicetree files using DT binding schema files. The tools also validate the DT binding schema files. Schema files are written in a JSON compatible subset of YAML to be both human and machine From 3c46a2137df632ec2c88c08be33a291cfd9bd928 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 7 Mar 2024 18:41:33 -0500 Subject: [PATCH 453/505] schemas: chosen: Remove 'linux,tpm-kexec-buffer' The property linux,tpm-kexec-buffer has not been implemented by Linux and therefore needs to be removed. Signed-off-by: Stefan Berger --- dtschema/schemas/chosen.yaml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/dtschema/schemas/chosen.yaml b/dtschema/schemas/chosen.yaml index 5e73d77e..f14fb17d 100644 --- a/dtschema/schemas/chosen.yaml +++ b/dtschema/schemas/chosen.yaml @@ -202,24 +202,6 @@ properties: carrying the IMA measurement logs. The address and the size are expressed in #address-cells and #size-cells, respectively of the root node. - linux,tpm-kexec-buffer: - $ref: types.yaml#/definitions/address - maxItems: 1 - description: | - This property (currently used by powerpc64) holds the memory range, - "the address and the size", of the TPM's measurement log that is being - carried over to the new kernel. - - / { - chosen { - linux,tpm-kexec-buffer = <0x9 0x82000000 0x0 0x00008000>; - }; - }; - - This property does not represent real hardware, but the memory allocated for - carrying the TPM measurement log. The address and the size are expressed in - #address-cells and #size-cells, respectively of the root node. - linux,uefi-system-table: $ref: types.yaml#/definitions/uint64 description: From ebfb590d7c01330d12a700a135aed51da53569ab Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Mar 2024 16:27:06 -0500 Subject: [PATCH 454/505] validator: Add a version to the processed schemas The contents of the processed schemas can change either from fixes to the fixups or new features. Add a version tag to the schema so we can detect changes and refuse to use old processed schema file. Really, there's enough information (the file paths) in the processed schema that we could just re-run the processing, but that can be a future enhancement. Since we now require a version, there's no need to handle the old list format of the processed schemas and that fixup can be dropped. Signed-off-by: Rob Herring --- dtschema/validator.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index e2c99186..b3b86515 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -359,17 +359,10 @@ def __init__(self, schema_files, filter=None): # Ensure the cache is a processed schema and not just a single schema file if '$id' in schema_cache: schema_cache = None + elif schema_cache.pop('version', None) != dtschema.__version__: + raise Exception(f"Processed schema out of date, delete and retry: {os.path.abspath(schema_files[0])}") if schema_cache: - # Convert old format to new - if isinstance(schema_cache, list): - d = {} - for sch in schema_cache: - if not isinstance(sch, dict): - return None - d[sch['$id']] = sch - schema_cache = d - if 'generated-types' in schema_cache: self.props = schema_cache['generated-types']['properties'] if 'generated-pattern-types' in schema_cache: @@ -385,6 +378,8 @@ def __init__(self, schema_files, filter=None): for k in self.pat_props: self.pat_props[k][0]['regex'] = re.compile(k) + self.schemas['version'] = dtschema.__version__ + def http_handler(self, uri): '''Custom handler for http://devicetree.org references''' try: From db9c05a08709b32013717cd86da01a7f58775a2f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Mar 2024 12:14:32 -0500 Subject: [PATCH 455/505] validator: Rework selecting schemas for validation Validation of devicetrees is slow because every schema is checked whether to apply it or not to every node. With 1000s of schemas and 100s-1000s of nodes in 1000s of DTBs, that makes for long validation times. The reality is there's a few schemas that apply to all nodes (mostly the core schemas) and only 1 schema with a matching compatible string that applies (not counting schemas included by $ref). There's also a few corner cases which have their own 'select'. Rework the validation to take advantage of this by storing up front the list of schemas to always iterate thru, and a map of compatible strings to their respective schema. The result is a 6-7x reduction in the validation time. Signed-off-by: Rob Herring --- dtschema/fixups.py | 27 +-------------------------- dtschema/validator.py | 43 ++++++++++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index e009fdc7..ba065b8d 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -405,37 +405,14 @@ def add_select_schema(schema): '''Get a schema to be used in select tests. If the provided schema has a 'select' property, then use that as the select schema. - If it has a compatible property, then create a select schema from that. If it has a $nodename property, then create a select schema from that. - If it has none of those, then return a match-nothing schema ''' if "select" in schema: return - if 'properties' not in schema: - schema['select'] = False + if 'properties' not in schema or 'compatible' in schema['properties']: return - if 'compatible' in schema['properties']: - compatible_list = dtschema.extract_node_compatibles(schema['properties']['compatible']) - - if len(compatible_list): - try: - compatible_list.remove('syscon') - except: - pass - try: - compatible_list.remove('simple-mfd') - except: - pass - - if len(compatible_list) != 0: - schema['select'] = { - 'required': ['compatible'], - 'properties': {'compatible': {'contains': {'enum': sorted(compatible_list)}}}} - - return - if '$nodename' in schema['properties'] and schema['properties']['$nodename'] is not True: schema['select'] = { 'required': ['$nodename'], @@ -443,8 +420,6 @@ def add_select_schema(schema): return - schema['select'] = False - def fixup_schema(schema): # Remove parts not necessary for validation diff --git a/dtschema/validator.py b/dtschema/validator.py index b3b86515..0ea1e941 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -239,7 +239,7 @@ def make_compatible_schema(schemas): compat_sch[0]['enum'].sort() schemas['generated-compatibles'] = { - '$id': 'http://devicetree.org/schemas/generated-compatibles', + '$id': 'generated-compatibles', '$filename': 'Generated schema of documented compatible strings', 'select': True, 'properties': { @@ -269,9 +269,6 @@ def process_schema(filename): return schema = dtsch.fixup() - if 'select' not in schema: - print(f"{filename}: warning: no 'select' found in schema found", file=sys.stderr) - return schema["type"] = "object" schema["$filename"] = filename @@ -378,6 +375,20 @@ def __init__(self, schema_files, filter=None): for k in self.pat_props: self.pat_props[k][0]['regex'] = re.compile(k) + # Speed up iterating thru schemas in validation by saving a list of schemas + # to always apply and a map of compatible strings to schema. + self.always_schemas = [] + self.compat_map = {} + for sch in self.schemas.values(): + if 'select' in sch: + if sch['select'] is not False: + self.always_schemas += [sch['$id']] + elif 'properties' in sch and 'compatible' in sch['properties']: + compatibles = dtschema.extract_node_compatibles(sch['properties']['compatible']) + compatibles = set(compatibles) - {'syscon', 'simple-mfd'} + for c in compatibles: + self.compat_map[c] = sch['$id'] + self.schemas['version'] = dtschema.__version__ def http_handler(self, uri): @@ -399,16 +410,26 @@ def annotate_error(self, id, error): error.note = None def iter_errors(self, instance, filter=None): - for id, schema in self.schemas.items(): - if 'select' not in schema: - continue - if filter and filter not in id: + if 'compatible' in instance: + inst_compat = instance['compatible'][0] + if inst_compat in self.compat_map: + schema_id = self.compat_map[inst_compat] + if not filter or filter in schema_id: + schema = self.schemas[schema_id] + for error in self.DtValidator(schema, + resolver=self.resolver, + ).iter_errors(instance): + self.annotate_error(schema['$id'], error) + yield error + for schema_id in self.always_schemas: + if filter and filter not in schema_id: continue - sch = {'if': schema['select'], 'then': schema} - for error in self.DtValidator(sch, + schema = {'if': self.schemas[schema_id]['select'], + 'then': self.schemas[schema_id]} + for error in self.DtValidator(schema, resolver=self.resolver, ).iter_errors(instance): - self.annotate_error(id, error) + self.annotate_error(schema_id, error) yield error def validate(self, instance, filter=None): From dc5e8d9b400adcb2e9ab01d3dfbd9ca4e65e7eeb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 10 Apr 2024 20:04:47 +0200 Subject: [PATCH 456/505] schemas: pci: allow additional device properties in pci-pci-bridge Device schemas referencing pci-pci-bridge.yaml might have additional properties. Signed-off-by: Krzysztof Kozlowski --- dtschema/schemas/pci/pci-pci-bridge.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/pci/pci-pci-bridge.yaml b/dtschema/schemas/pci/pci-pci-bridge.yaml index d8de2504..7933e015 100644 --- a/dtschema/schemas/pci/pci-pci-bridge.yaml +++ b/dtschema/schemas/pci/pci-pci-bridge.yaml @@ -34,4 +34,4 @@ properties: to D3 states. type: boolean -unevaluatedProperties: false +additionalProperties: true From 64b72b0a81a843d97f93715fc4cc64290f0f74df Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 1 Apr 2024 13:35:19 -0500 Subject: [PATCH 457/505] dt-validate: Add an 'only matching compatible' schema validation mode Add an 'only matching compatible' schema validation mode which only applies the schema matching nodes' compatible string. Currently, only the most specific (i.e. 1st) compatible string in the instance is used, but that may change in the future. This mode tends to be 4x faster (on top of the recent 6-7x speed up) while still giving 80-90% of the warnings. Mostly the core schemas are skipped. Signed-off-by: Rob Herring --- dtschema/dtb_validate.py | 8 +++++++- dtschema/validator.py | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/dtschema/dtb_validate.py b/dtschema/dtb_validate.py index b8e3e530..6a029466 100755 --- a/dtschema/dtb_validate.py +++ b/dtschema/dtb_validate.py @@ -13,6 +13,7 @@ verbose = False show_unmatched = False match_schema_file = None +compatible_match = False class schema_group(): @@ -30,7 +31,8 @@ def check_node(self, tree, node, disabled, nodename, fullname, filename): node['$nodename'] = [nodename] try: - for error in self.validator.iter_errors(node, filter=match_schema_file): + for error in self.validator.iter_errors(node, filter=match_schema_file, + compatible_match=compatible_match): # Disabled nodes might not have all the required # properties filled in, such as a regulator or a @@ -93,6 +95,7 @@ def main(): global verbose global show_unmatched global match_schema_file + global compatible_match ap = argparse.ArgumentParser(fromfile_prefix_chars='@', epilog='Arguments can also be passed in a file prefixed with a "@" character.') @@ -101,6 +104,8 @@ def main(): ap.add_argument('-s', '--schema', help="preparsed schema file or path to schema files") ap.add_argument('-p', '--preparse', help="preparsed schema file (deprecated, use '-s')") ap.add_argument('-l', '--limit', help="limit validation to schemas with $id matching LIMIT substring") + ap.add_argument('-c', '--compatible-match', action="store_true", + help="limit validation to schema matching nodes' most specific compatible string") ap.add_argument('-m', '--show-unmatched', help="Print out node 'compatible' strings which don't match any schema.", action="store_true") @@ -114,6 +119,7 @@ def main(): verbose = args.verbose show_unmatched = args.show_unmatched match_schema_file = args.limit + compatible_match = args.compatible_match # Maintain prior behaviour which accepted file paths by stripping the file path if args.url_path and args.limit: diff --git a/dtschema/validator.py b/dtschema/validator.py index 0ea1e941..653543b4 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -409,7 +409,7 @@ def annotate_error(self, id, error): error.linecol = -1, -1 error.note = None - def iter_errors(self, instance, filter=None): + def iter_errors(self, instance, filter=None, compatible_match=False): if 'compatible' in instance: inst_compat = instance['compatible'][0] if inst_compat in self.compat_map: @@ -421,6 +421,10 @@ def iter_errors(self, instance, filter=None): ).iter_errors(instance): self.annotate_error(schema['$id'], error) yield error + + if compatible_match: + return + for schema_id in self.always_schemas: if filter and filter not in schema_id: continue From 0f006b1c7dce4334f7db8bef57860a3bf4a5d00b Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 16 Apr 2024 13:58:24 -0500 Subject: [PATCH 458/505] fixups: Convert anyOf/oneOf + const to enum The use anyOf/oneOf + const is common when a description is desired for enum entries. But anyOf/oneOf gives worse error messages, so convert this pattern to an 'enum'. Signed-off-by: Rob Herring (Arm) --- dtschema/fixups.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index ba065b8d..2b3d56e6 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -253,9 +253,41 @@ def fixup_vals(schema, path=[]): fixup_schema_to_201909(schema) +def _fixup_oneOf_to_enum(schema, path=[]): + # Convert oneOf/anyOf lists with just 'const' entries into an enum. + # This pattern is used to add descriptions on each entry which is not + # possible with 'enum', but the error reporting is much worse with + # oneOf/anyOf schemas. + + if 'anyOf' in schema: + sch_list = schema['anyOf'] + elif 'oneOf' in schema: + sch_list = schema['oneOf'] + elif 'items' in schema and isinstance(schema['items'], dict): + # Sometimes 'items' appears first which isn't really handled by the + # fixups, but we can handle it here. + _fixup_oneOf_to_enum(schema['items'], path=path + ['items']) + return + else: + return + + const_list = [] + for l in sch_list: + if 'const' not in l or set(l) > {'const', 'description'}: + return + const_list += [l['const']] + + schema.pop('anyOf', None) + schema.pop('oneOf', None) + schema['enum'] = const_list + + def walk_properties(schema, path=[]): if not isinstance(schema, dict): return + + _fixup_oneOf_to_enum(schema, path=path) + # Recurse until we don't hit a conditional # Note we expect to encounter conditionals first. # For example, a conditional below 'items' is not supported From 1a2c5d8fc436df74a643121ef78702ef1dfa62d7 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 3 May 2024 13:43:19 -0500 Subject: [PATCH 459/505] Improve 'oneOf' error messages 'oneOf' failures are hard because the messages give little indication of which of the oneOf clauses is most likely what needs to be fixed. The jsonschema.best_match() method can help in some cases when the errors have different schema depths. The handling for more than 1 oneOf condition being true is worse than the default for jsonschema as it prints the whole oneOf schema rather than just the true cases. I think jsonschema improved this at some point. With that, we can just remove the custom formatting. Signed-off-by: Rob Herring (Arm) --- dtschema/lib.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 4883ab96..779cfee8 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -4,7 +4,8 @@ # Python library for Devicetree schema validation import os import re -import pprint + +from jsonschema.exceptions import best_match # We use a lot of regex's in schema and exceeding the cache size has noticeable # peformance impact. @@ -128,21 +129,19 @@ def format_error(filename, error, prefix="", nodename=None, verbose=False): elif not error.schema_path: msg = error.message elif error.context: - # An error on a conditional will have context with sub-errors - msg = "'" + error.schema_path[-1] + "' conditional failed, one must be fixed:" - - for suberror in sorted(error.context, key=lambda e: e.path): - if suberror.context: - msg += '\n' + format_error(filename, suberror, prefix=prefix+"\t", nodename=nodename, verbose=verbose) - elif suberror.message not in msg: - msg += '\n' + prefix + '\t' + suberror.message - if hasattr(suberror, 'note') and suberror.note and suberror.note != error.note: - msg += '\n\t\t' + prefix + 'hint: ' + suberror.note - - elif error.schema_path[-1] == 'oneOf': - msg = 'More than one condition true in oneOf schema:\n\t' + \ - '\t'.join(pprint.pformat(error.schema, width=72).splitlines(True)) - + if len(error.context) == 1: + msg = best_match(error.context).message + else: + # An error on a conditional will have context with sub-errors + msg = "\n'" + error.schema_path[-1] + "' conditional failed, one must be fixed:" + + for suberror in sorted(error.context, key=lambda e: e.path): + if suberror.context: + msg += '\n' + format_error(filename, suberror, prefix=prefix+"\t", nodename=nodename, verbose=verbose) + elif suberror.message not in msg: + msg += '\n' + prefix + '\t' + suberror.message + if hasattr(suberror, 'note') and suberror.note and suberror.note != error.note: + msg += '\n\t\t' + prefix + 'hint: ' + suberror.note else: msg = error.message From ed9190d20f146d13e262cc9138506326f7d4da91 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 3 May 2024 13:54:04 -0500 Subject: [PATCH 460/505] schemas: simple-bus: Rework handling of child nodes without unit-address The simple-bus currently will spit out the whole bus subtree when it contains a child node without a unit-address. It also has a false positive when the child node is another bus that has an empty 'ranges' property. Rework the schema to use 'additionalProperties' instead of a pattern and use an if/then schema. Now validation will report "ranges is required" which is a little misleading, but better than the huge dump of the whole subtree. Signed-off-by: Rob Herring (Arm) --- dtschema/schemas/simple-bus.yaml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/dtschema/schemas/simple-bus.yaml b/dtschema/schemas/simple-bus.yaml index 5f3524ea..0d1d37d4 100644 --- a/dtschema/schemas/simple-bus.yaml +++ b/dtschema/schemas/simple-bus.yaml @@ -57,12 +57,19 @@ patternProperties: - required: - ranges - "^[^@]+$": - # Only additional properties should be properties, not nodes. - not: - type: object +additionalProperties: + description: + Anything else must be a property or have empty 'ranges'. An empty 'ranges' + is only appropriate if the child node is another 'simple-bus' or similar. + if: + type: object + then: + properties: + ranges: + type: boolean -additionalProperties: false + required: + - ranges required: - compatible From 8733c90fed776d4c94efa2336c523ae8235b8a2c Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 9 May 2024 10:16:38 -0500 Subject: [PATCH 461/505] format_error: Drop inadvertent newline added to conditional error messages A newline was inadvertently added to the start of the output of conditional error messages. Signed-off-by: Rob Herring (Arm) --- dtschema/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/lib.py b/dtschema/lib.py index 779cfee8..33505a1d 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -133,7 +133,7 @@ def format_error(filename, error, prefix="", nodename=None, verbose=False): msg = best_match(error.context).message else: # An error on a conditional will have context with sub-errors - msg = "\n'" + error.schema_path[-1] + "' conditional failed, one must be fixed:" + msg = "'" + error.schema_path[-1] + "' conditional failed, one must be fixed:" for suberror in sorted(error.context, key=lambda e: e.path): if suberror.context: From a5bbb3e27c67a5fa73887c732de57cf36d706662 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 12 Sep 2023 13:35:24 -0500 Subject: [PATCH 462/505] schema: Another take on checking additionalProperties/unevaluatedProperties Complete schemas need to have additionalProperties or unevaluatedProperties constraint in order to prevent undefined properties. Attempts to check this with meta-schemas resulted in corner cases which couldn't be fixed or required redundant unevaluatedProperties. The problem is we need to know if a referenced schema has the constraint already or not. So let's solve this with code to look into $ref's to see if the ref constrains the properties or not. Signed-off-by: Rob Herring --- dtschema/schema.py | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/dtschema/schema.py b/dtschema/schema.py index 0da09e7d..6d638d78 100644 --- a/dtschema/schema.py +++ b/dtschema/schema.py @@ -45,6 +45,15 @@ def get_line_col(tree, path, obj=None): return obj.lc.key(path[-1]) return -1, -1 +def _is_node_schema(schema): + return isinstance(schema, dict) and \ + (('type' in schema and schema['type'] == 'object') or + schema.keys() & {'properties', 'patternProperties'}) + + +def _schema_allows_no_undefined_props(schema): + return not schema.get("additionalProperties", True) or \ + not schema.get("unevaluatedProperties", True) class DTSchema(dict): DtValidator = jsonschema.validators.extend( @@ -143,15 +152,36 @@ def fixup(self): dtschema.fixups.fixup_schema(processed_schema) return processed_schema - def _check_schema_refs(self, schema): - if isinstance(schema, dict) and '$ref' in schema: - self.resolver.resolve(schema['$ref']) - elif isinstance(schema, dict): + def _check_schema_refs(self, schema, parent=None, is_common=False, has_constraint=False): + if not parent: + is_common = not _schema_allows_no_undefined_props(schema) + if isinstance(schema, dict): + if parent in {'if', 'select', 'definitions', '$defs', 'then', + 'else', 'dependencies', 'dependentSchemas'}: + return + + if _is_node_schema(schema): + has_constraint = _schema_allows_no_undefined_props(schema) + + if not is_common and _is_node_schema(schema) and \ + (schema.keys() & {'properties', 'patternProperties', '$ref'}): + ref_has_constraint = False + if '$ref' in schema: + url, ref_sch = self.resolver.resolve(schema['$ref']) + + ref_has_constraint = _schema_allows_no_undefined_props(ref_sch) + if not ref_has_constraint and \ + not (has_constraint or (schema.keys() & {'additionalProperties', 'unevaluatedProperties'})): + print(f"{self.filename}: {parent}: Missing additionalProperties/unevaluatedProperties constraint\n", + file=sys.stderr) + for k, v in schema.items(): - self._check_schema_refs(v) + self._check_schema_refs(v, parent=k, is_common=is_common, + has_constraint=has_constraint) elif isinstance(schema, (list, tuple)): for i in range(len(schema)): - self._check_schema_refs(schema[i]) + self._check_schema_refs(schema[i], parent=parent, is_common=is_common, + has_constraint=has_constraint) def check_schema_refs(self): id = self['$id'].rstrip('#') From 7c8798f6594a58a0f492519f543a3bb9aa70c21d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 21 Jul 2023 15:56:11 -0600 Subject: [PATCH 463/505] dtschema: Delay ruamel.yaml import When running dt-validate, YAML support isn't needed when using a preprocessed schema JSON file. The import time for ruamel takes about 40ms which around 1/4th of the total startup time. It is mostly due to pkg_resources module import by ruamel. Move the imports to where they are needed. It's not much of a speed-up overall, but every little bit helps. Signed-off-by: Rob Herring --- dtschema/schema.py | 21 +++++++++++++-------- dtschema/validator.py | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/dtschema/schema.py b/dtschema/schema.py index 6d638d78..085757ef 100644 --- a/dtschema/schema.py +++ b/dtschema/schema.py @@ -4,7 +4,6 @@ # Python library for Devicetree schema validation import sys import os -import ruamel.yaml import re import copy import jsonschema @@ -16,13 +15,6 @@ schema_base_url = "http://devicetree.org/" schema_basedir = os.path.dirname(os.path.abspath(__file__)) -rtyaml = ruamel.yaml.YAML(typ='rt') -rtyaml.allow_duplicate_keys = False -rtyaml.preserve_quotes = True - -yaml = ruamel.yaml.YAML(typ='safe') -yaml.allow_duplicate_keys = False - def path_to_obj(tree, path): for pc in path: @@ -31,6 +23,8 @@ def path_to_obj(tree, path): def get_line_col(tree, path, obj=None): + import ruamel.yaml + if isinstance(obj, ruamel.yaml.comments.CommentedBase): return obj.lc.line, obj.lc.col obj = path_to_obj(tree, path) @@ -64,9 +58,17 @@ class DTSchema(dict): def __init__(self, schema_file, line_numbers=False): self.paths = [(schema_base_url, schema_basedir + '/')] with open(schema_file, 'r', encoding='utf-8') as f: + import ruamel.yaml + if line_numbers: + rtyaml = ruamel.yaml.YAML(typ='rt') + rtyaml.allow_duplicate_keys = False + rtyaml.preserve_quotes = True + schema = rtyaml.load(f.read()) else: + yaml = ruamel.yaml.YAML(typ='safe') + yaml.allow_duplicate_keys = False schema = yaml.load(f.read()) self.filename = os.path.abspath(schema_file) @@ -85,6 +87,9 @@ def http_handler(self, uri): if not os.path.isfile(filename): continue with open(filename, 'r', encoding='utf-8') as f: + import ruamel.yaml + yaml = ruamel.yaml.YAML(typ='safe') + yaml.allow_duplicate_keys = False return yaml.load(f.read()) raise RefResolutionError('Error in referenced schema matching $id: ' + uri) diff --git a/dtschema/validator.py b/dtschema/validator.py index 653543b4..5c6bc2c8 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -9,7 +9,6 @@ import glob import json import jsonschema -import ruamel.yaml from jsonschema.exceptions import RefResolutionError @@ -347,6 +346,7 @@ def __init__(self, schema_files, filter=None): except json.decoder.JSONDecodeError: try: f.seek(0) + import ruamel.yaml yaml = ruamel.yaml.YAML(typ='safe') schema_cache = yaml.load(f.read()) except: From 833054f47a07c6717926f47a9140cf0ad7592f0e Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 4 Jun 2024 15:15:07 -0500 Subject: [PATCH 464/505] validator: Add 'test,' compatible prefix for test cases There's not really much need to document test cases which need test bindings, so add 'test,' as an allowed compatible string vendor prefix. Signed-off-by: Rob Herring (Arm) --- dtschema/validator.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/validator.py b/dtschema/validator.py index 5c6bc2c8..2c6c1040 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -225,6 +225,9 @@ def make_compatible_schema(schemas): # Allow 'foo' values for examples compat_sch += [{'pattern': '^foo'}] + # Allow 'test,' vendor prefix for test cases + compat_sch += [{'pattern': '^test,'}] + prog = re.compile(r'.*[\^\[{\(\$].*') for c in compatible_list: if prog.match(c): From 3b69bad1fdc6fbc74a7ac6e1e6c1179c3376e33e Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 26 Jun 2024 11:26:26 -0600 Subject: [PATCH 465/505] validator: Support matching schemas on fallback compatible strings Since commit db9c05a08709 ("validator: Rework selecting schemas for validation") only matching on the most specific compatible (i.e. the 1st one) has been done. This dropped matching on some schemas where the most specific compatible is a pattern in the schema (not a normal occurrence). Reported-by: Krzysztof Kozlowski Signed-off-by: Rob Herring (Arm) --- dtschema/validator.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index 2c6c1040..54f6ffd9 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -414,16 +414,17 @@ def annotate_error(self, id, error): def iter_errors(self, instance, filter=None, compatible_match=False): if 'compatible' in instance: - inst_compat = instance['compatible'][0] - if inst_compat in self.compat_map: - schema_id = self.compat_map[inst_compat] - if not filter or filter in schema_id: - schema = self.schemas[schema_id] - for error in self.DtValidator(schema, - resolver=self.resolver, - ).iter_errors(instance): - self.annotate_error(schema['$id'], error) - yield error + for inst_compat in instance['compatible']: + if inst_compat in self.compat_map: + schema_id = self.compat_map[inst_compat] + if not filter or filter in schema_id: + schema = self.schemas[schema_id] + for error in self.DtValidator(schema, + resolver=self.resolver, + ).iter_errors(instance): + self.annotate_error(schema['$id'], error) + yield error + break if compatible_match: return From 650bf2d3e777e2037464f86e50030d012c56fcab Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 21 Jun 2024 20:11:59 +0800 Subject: [PATCH 466/505] schemas: introduce assigned-clock-rates-u64 To support rates that exceeds UINT32_MAX, introduce assigned-clock-rates-u64 Signed-off-by: Peng Fan --- dtschema/fixups.py | 1 + dtschema/meta-schemas/clocks.yaml | 3 +++ dtschema/schemas/clock/clock.yaml | 3 +++ 3 files changed, 7 insertions(+) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index 2b3d56e6..e8254cf5 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -413,6 +413,7 @@ def fixup_node_props(schema): if "clocks" in keys and "assigned-clocks" not in keys: schema['properties']['assigned-clocks'] = True + schema['properties']['assigned-clock-rates-u64'] = True schema['properties']['assigned-clock-rates'] = True schema['properties']['assigned-clock-parents'] = True diff --git a/dtschema/meta-schemas/clocks.yaml b/dtschema/meta-schemas/clocks.yaml index 3227d60a..50aee9ff 100644 --- a/dtschema/meta-schemas/clocks.yaml +++ b/dtschema/meta-schemas/clocks.yaml @@ -21,6 +21,8 @@ properties: $ref: cell.yaml#/array assigned-clock-rates: $ref: cell.yaml#/array + assigned-clock-rates-u64: + $ref: cell.yaml#/array clock-frequency: $ref: cell.yaml#/single @@ -35,3 +37,4 @@ dependentRequired: assigned-clocks: [clocks] assigned-clock-parents: [assigned-clocks] assigned-clock-rates: [assigned-clocks] + assigned-clock-rates-u64: [assigned-clocks] diff --git a/dtschema/schemas/clock/clock.yaml b/dtschema/schemas/clock/clock.yaml index 9e69bd65..bfdc6b0c 100644 --- a/dtschema/schemas/clock/clock.yaml +++ b/dtschema/schemas/clock/clock.yaml @@ -129,6 +129,8 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array assigned-clock-rates: $ref: /schemas/types.yaml#/definitions/uint32-array + assigned-clock-rates-u64: + $ref: /schemas/types.yaml#/definitions/uint64-array protected-clocks: $ref: /schemas/types.yaml#/definitions/uint32-array @@ -147,6 +149,7 @@ dependentRequired: clock-ranges: [clocks] assigned-clock-parents: [assigned-clocks] assigned-clock-rates: [assigned-clocks] + assigned-clock-rates-u64: [assigned-clocks] protected-clocks: ["#clock-cells"] dependentSchemas: From 23441a412f88245a842f92aaba5377e96b536936 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 8 Nov 2022 16:35:50 -0600 Subject: [PATCH 467/505] Decode DTB properties to native type and drop schema fixups Originally with the YAML encoded DT there was little to no information about a property's type. So all integer properties were decoded into an 2 dimensional matrix even if the property was a scalar. However, in order to keep schemas simple, the schemas were written according to the type and omitted this complexity. So the tools processed the schemas to add this extra encoding. This works okay except in a few places like if/then schemas where the tools don't know the property type in order to do the correct fixup. With the DTB based decoding, we now have the property type for every property and we can just decode the properties to the correct type. This only affects integer types as 'string' and 'string-array' are still both encoded the same way (as an array). And 'phandle' is still encoded as a matrix like 'phandle-array'. Signed-off-by: Rob Herring --- dtschema/dtb.py | 20 +-- dtschema/fixups.py | 113 +++------------ dtschema/schemas/dt-core.yaml | 2 +- dtschema/schemas/types.yaml | 259 ++++++---------------------------- dtschema/validator.py | 2 +- 5 files changed, 81 insertions(+), 315 deletions(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index a11089c7..d22eb1d1 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -178,15 +178,19 @@ def prop_value(validator, nodename, p): for i in type_struct.iter_unpack(data): val_int += [dtschema.sized_int(i[0], size=(type_struct.size * 8))] - if 'matrix' in fmt or 'phandle-array' in fmt: + if 'matrix' in fmt or fmt in {'phandle', 'phandle-array', 'address'}: dim = validator.property_get_type_dim(p.name) - if dim: - stride = get_stride(len(val_int), dim) + if dim: + stride = get_stride(len(val_int), dim) - #print(p.name, dim, stride, len(val_int)) - return [val_int[i:i+stride] for i in range(0, len(val_int), stride)] + #print(p.name, dim, stride, len(val_int)) + return [val_int[i:i+stride] for i in range(0, len(val_int), stride)] + else: + return [val_int] + elif 'array' not in fmt and len(val_int) == 1: + return val_int[0] - return [val_int] + return val_int def node_props(validator, fdt, nodename, offset): @@ -249,7 +253,7 @@ def fdt_scan_node(validator, fdt, nodename, offset): node_dict = node_props(validator, fdt, nodename, offset) if 'phandle' in node_dict: #print('phandle', node_dict['phandle']) - phandles[node_dict['phandle'][0][0]] = node_dict + phandles[node_dict['phandle']] = node_dict offset = fdt.first_subnode(offset, QUIET_NOTFOUND) while offset >= 0: @@ -285,7 +289,7 @@ def _get_cells_size(node, cellname): if isinstance(cellname, int): return cellname elif cellname in node: - return node[cellname][0][0] + return node[cellname] else: return 0 diff --git a/dtschema/fixups.py b/dtschema/fixups.py index e8254cf5..cee6075d 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -58,69 +58,6 @@ def _is_matrix_schema(subschema): return False -int_array_re = re.compile('int(8|16|32|64)-array') -unit_types_re = re.compile('-(bps|kBps|bits|percent|bp|m?hz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|microvolt|picofarads|(milli)?celsius|kelvin|k?pascal)$') - -# Remove this once we remove array to matrix fixups -known_array_props = { - 'assigned-clock-rates', - 'linux,keycodes', - 'max8997,pmic-buck1-dvs-voltage', - 'max8997,pmic-buck2-dvs-voltage', - 'max8997,pmic-buck5-dvs-voltage', -} - - -def is_int_array_schema(subschema, path=[]): - if 'allOf' in subschema: - # Find 'items'. It may be under the 'allOf' or at the same level - for item in subschema['allOf']: - if 'items' in item: - subschema = item - continue - if '$ref' in item: - return int_array_re.search(item['$ref']) - if '$ref' in subschema: - return int_array_re.search(subschema['$ref']) - else: - if [p for p in path if unit_types_re.search(p)] or set(path) & known_array_props: - return True - - return 'items' in subschema and \ - ((isinstance(subschema['items'], list) and _is_int_schema(subschema['items'][0])) or - (isinstance(subschema['items'], dict) and _is_int_schema(subschema['items']))) - - -# Fixup an int array that only defines the number of items. -def _fixup_int_array_min_max_to_matrix(subschema, path=[]): - if not is_int_array_schema(subschema, path=path): - return - - if 'allOf' in subschema: - # Find 'min/maxItems'. It may be under the 'allOf' or at the same level - for item in subschema['allOf']: - if item.keys() & {'minItems', 'maxItems'}: - subschema = item - break - - if 'items' in subschema and isinstance(subschema['items'], list): - return - - if _is_matrix_schema(subschema): - return - - tmpsch = {} - if 'minItems' in subschema: - tmpsch['minItems'] = subschema.pop('minItems') - if 'maxItems' in subschema: - tmpsch['maxItems'] = subschema.pop('maxItems') - if 'items' in subschema: - tmpsch['items'] = subschema.pop('items') - - if tmpsch: - subschema['items'] = tmpsch - subschema['maxItems'] = 1 - def _fixup_remove_empty_items(subschema): if 'items' not in subschema: return @@ -140,33 +77,31 @@ def _fixup_remove_empty_items(subschema): del subschema['items'] -def _fixup_int_array_items_to_matrix(subschema, path=[]): - itemkeys = ('items', 'minItems', 'maxItems', 'uniqueItems', 'default') - if not is_int_array_schema(subschema, path=path): - return - - if 'allOf' in subschema: - # Find 'items'. It may be under the 'allOf' or at the same level - for item in subschema['allOf']: - if 'items' in item: - subschema = item - break - - if 'items' not in subschema or _is_matrix_schema(subschema): - return - - if isinstance(subschema['items'], dict): - subschema['items'] = {k: subschema.pop(k) for k in itemkeys if k in subschema} - - if isinstance(subschema['items'], list): - subschema['items'] = [{k: subschema.pop(k) for k in itemkeys if k in subschema}] - +# Keep in sync with property-units.yaml +unit_types_array_re = re.compile('-(kBps|bits|percent|bp|mhz|sec|ms|us|ns|ps|mm|nanoamp|(micro-)?ohms|micro(amp|watt)(-hours)?|milliwatt|(femto|pico)farads|(milli)?celsius|kelvin|k?pascal)$') +unit_types_matrix_re = re.compile('-(hz|microvolt)$') -def _fixup_scalar_to_array(subschema): - if not _is_int_schema(subschema): +def _fixup_unit_suffix_props(subschema, path=[]): + path.reverse() + for idx, p in enumerate(path): + if p in {'properties', '$defs'}: + propname = path[idx - 1] + break + else: return - subschema['items'] = [{'items': [_extract_single_schemas(subschema)]}] + if unit_types_array_re.search(propname) and _is_int_schema(subschema): + subschema['items'] = [_extract_single_schemas(subschema)] + elif unit_types_matrix_re.search(propname): + if _is_matrix_schema(subschema): + return + if {'items', 'minItems', 'maxItems'} & subschema.keys(): + subschema['items'] = [copy.deepcopy(subschema)] + subschema.pop('minItems', None) + subschema.pop('maxItems', None) + #print(subschema, file=sys.stderr) + elif _is_int_schema(subschema): + subschema['items'] = [{'items': [_extract_single_schemas(subschema)]}] def _fixup_items_size(schema, path=[]): @@ -244,10 +179,8 @@ def fixup_vals(schema, path=[]): _fixup_reg_schema(schema, path=path) _fixup_remove_empty_items(schema) - _fixup_int_array_min_max_to_matrix(schema, path=path) - _fixup_int_array_items_to_matrix(schema, path=path) + _fixup_unit_suffix_props(schema, path=path) _fixup_string_to_array(schema) - _fixup_scalar_to_array(schema) _fixup_items_size(schema, path=path) fixup_schema_to_201909(schema) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index aad85c67..926e2afc 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -75,7 +75,7 @@ patternProperties: # property and node namespace overlaps. Catch both here "^[a-zA-Z0-9][a-zA-Z0-9#,+\\-._]{0,63}$": - type: [object, array, boolean, 'null'] + type: [object, integer, array, boolean, 'null'] # Anything with a '@' is definitely a node "^[a-zA-Z0-9][a-zA-Z0-9,+\\-._]{0,63}@[0-9a-fA-F]+(,[0-9a-fA-F]+)*$": diff --git a/dtschema/schemas/types.yaml b/dtschema/schemas/types.yaml index 568efb33..0e2d5524 100644 --- a/dtschema/schemas/types.yaml +++ b/dtschema/schemas/types.yaml @@ -31,307 +31,137 @@ definitions: allOf: - $ref: "#/definitions/string-array" - maxItems: 1 - uint8-item: + uint8: type: integer + typeSize: 8 minimum: 0 maximum: 0xff - uint8-matrix: - type: array - typeSize: 8 - items: - type: array - items: - $ref: "#/definitions/uint8-item" uint8-array: type: array - typeSize: 8 minItems: 1 - maxItems: 1 items: - type: array - items: - $ref: "#/definitions/uint8-item" - uint8: + $ref: "#/definitions/uint8" + uint8-matrix: type: array - typeSize: 8 minItems: 1 - maxItems: 1 items: - type: array - items: - $ref: "#/definitions/uint8-item" - minItems: 1 - maxItems: 1 + $ref: "#/definitions/uint8-array" - int8-item: + int8: type: integer - minimum: -128 - # maximum: 127 - maximum: 0xff - int8-matrix: - type: array typeSize: 8 - items: - type: array - items: - $ref: "#/definitions/int8-item" + minimum: -128 + maximum: 127 int8-array: type: array - typeSize: 8 minItems: 1 - maxItems: 1 items: - type: array - items: - $ref: "#/definitions/int8-item" - int8: + $ref: "#/definitions/int8" + int8-matrix: type: array - typeSize: 8 minItems: 1 - maxItems: 1 items: - type: array - items: - $ref: "#/definitions/int8-item" - minItems: 1 - maxItems: 1 + $ref: "#/definitions/int8-array" - uint16-item: + uint16: type: integer + typeSize: 16 minimum: 0 maximum: 0xffff - uint16-matrix: - type: array - typeSize: 16 - items: - type: array - items: - $ref: "#/definitions/uint16-item" uint16-array: type: array - typeSize: 16 minItems: 1 - maxItems: 1 items: - type: array - items: - $ref: "#/definitions/uint16-item" - uint16: + $ref: "#/definitions/uint16" + uint16-matrix: type: array - typeSize: 16 minItems: 1 - maxItems: 1 items: - type: array - items: - $ref: "#/definitions/uint16-item" - minItems: 1 - maxItems: 1 + $ref: "#/definitions/uint16-array" - int16-item: + int16: type: integer - minimum: -8192 - # maximum: 8191 - maximum: 0xffff - int16-matrix: - type: array typeSize: 16 - items: - type: array - items: - $ref: "#/definitions/uint16-item" + minimum: -8192 + maximum: 8191 int16-array: type: array - typeSize: 16 minItems: 1 - maxItems: 1 items: - type: array - items: - $ref: "#/definitions/uint16-item" - int16: + $ref: "#/definitions/int16" + int16-matrix: type: array - typeSize: 16 minItems: 1 - maxItems: 1 items: - type: array - items: - $ref: "#/definitions/uint16-item" - minItems: 1 - maxItems: 1 + $ref: "#/definitions/int16-array" - cell: + uint32: type: integer + typeSize: 32 minimum: 0 maximum: 0xffffffff - - uint32-matrix: + uint32-array: type: array - typeSize: 32 minItems: 1 items: - type: array - items: - $ref: "#/definitions/cell" - uint32-array: - # For single cell arrays, we need to support encodings as either: - # prop = <0x1234 0x5678>; - # or - # prop = <0x1234>, <0x5678>; - typeSize: 32 - anyOf: - - type: array - minItems: 1 - maxItems: 1 - items: - type: array - items: - $ref: "#/definitions/cell" - - type: array - items: - type: array - minItems: 1 - maxItems: 1 - items: - $ref: "#/definitions/cell" - uint32: + $ref: "#/definitions/uint32" + uint32-matrix: type: array - typeSize: 32 minItems: 1 - maxItems: 1 items: - type: array - items: - $ref: "#/definitions/cell" - minItems: 1 - maxItems: 1 + $ref: "#/definitions/uint32-array" - int32-item: + int32: type: integer minimum: -2147483648 maximum: 2147483647 - - int32-matrix: + int32-array: type: array - typeSize: 32 minItems: 1 items: - type: array - items: - $ref: "#/definitions/int32-item" - int32-array: - # For single cell arrays, we need to support encodings as either: - # prop = <0x1234 0x5678>; - # or - # prop = <0x1234>, <0x5678>; - typeSize: 32 - anyOf: - - type: array - minItems: 1 - maxItems: 1 - items: - type: array - items: - $ref: "#/definitions/int32-item" - - type: array - items: - type: array - minItems: 1 - maxItems: 1 - items: - $ref: "#/definitions/int32-item" - int32: + $ref: "#/definitions/int32" + int32-matrix: type: array - typeSize: 32 minItems: 1 - maxItems: 1 items: - type: array - items: - $ref: "#/definitions/int32-item" - minItems: 1 - maxItems: 1 + $ref: "#/definitions/int32-array" - int64-item: + int64: type: integer + typeSize: 64 minimum: -9223372036854775808 maximum: 9223372036854775807 - - int64: - type: array - minItems: 1 - maxItems: 1 - typeSize: 64 - items: - type: array - items: - $ref: "#/definitions/int64-item" - minItems: 1 - maxItems: 1 int64-array: type: array minItems: 1 - maxItems: 1 - typeSize: 64 items: - type: array - items: - $ref: "#/definitions/int64-item" + $ref: "#/definitions/int64" int64-matrix: type: array minItems: 1 - typeSize: 64 items: - type: array - items: - $ref: "#/definitions/int64-item" + $ref: "#/definitions/int64-array" - uint64-item: + uint64: type: integer + typeSize: 64 minimum: 0 maximum: 0xffffffffffffffff - - uint64: - type: array - minItems: 1 - maxItems: 1 - typeSize: 64 - items: - type: array - items: - $ref: "#/definitions/uint64-item" - minItems: 1 - maxItems: 1 uint64-array: type: array minItems: 1 - maxItems: 1 - typeSize: 64 items: - type: array - items: - $ref: "#/definitions/uint64-item" + $ref: "#/definitions/uint64" uint64-matrix: type: array minItems: 1 - typeSize: 64 items: - type: array - items: - $ref: "#/definitions/uint64-item" + $ref: "#/definitions/uint64-array" phandle: - type: array - minItems: 1 + $ref: "#/definitions/phandle-array" maxItems: 1 items: - type: array - items: - phandle: true - type: integer - maximum: 0xffffffff - minItems: 1 maxItems: 1 phandle-array: type: array @@ -341,14 +171,13 @@ definitions: minItems: 1 items: - oneOf: - - phandle: true - type: integer + - type: integer minimum: 1 maximum: 0xffffffff - type: integer const: 0 additionalItems: - $ref: "#/definitions/cell" + $ref: "#/definitions/uint32" address: $ref: "#/definitions/uint32-matrix" diff --git a/dtschema/validator.py b/dtschema/validator.py index 54f6ffd9..8d566d36 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -318,7 +318,7 @@ def process_schemas(schema_paths, core_schema=True): def typeSize(validator, typeSize, instance, schema): try: - size = instance[0][0].size + size = instance.size except: size = 32 From 0e44e14b7eb425cf09a5f42ef1e171b4451ef66a Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 26 Jul 2024 09:59:25 -0500 Subject: [PATCH 468/505] schema: Skip additionalProperties check when all properties are false A common sub-schema to disallow some properties in certain conditions is: properties: foo: false bar: false This case causes spurious warnings for missing additionalProperties/ unevaluatedProperties. Detect this case and skip the warning. Signed-off-by: Rob Herring (Arm) --- dtschema/schema.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dtschema/schema.py b/dtschema/schema.py index 085757ef..146d1d2f 100644 --- a/dtschema/schema.py +++ b/dtschema/schema.py @@ -170,7 +170,16 @@ def _check_schema_refs(self, schema, parent=None, is_common=False, has_constrain if not is_common and _is_node_schema(schema) and \ (schema.keys() & {'properties', 'patternProperties', '$ref'}): + ref_has_constraint = False + if 'properties' in schema: + # All false properties are not complete schemas + for prop,val in schema['properties'].items(): + if val is not False: + break + else: + ref_has_constraint = True + if '$ref' in schema: url, ref_sch = self.resolver.resolve(schema['$ref']) From 6eb87ba1cbf28dbdf7b6a8fc276396d4e4863194 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 29 Jul 2024 10:17:32 -0500 Subject: [PATCH 469/505] dtb: Ensure there's only 1 phandle type Dropping the 'phandle-array' when the length is 4 bytes was wrong as having a single phandle can still be valid in that case. Instead, make sure there is only a single phandle type. Otherwise, we'll end up decoding as a 'uint32-array' which is the default when the type can't be determined. Signed-off-by: Rob Herring (Arm) --- dtschema/dtb.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index d22eb1d1..4a4e256a 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -100,7 +100,7 @@ def prop_value(validator, nodename, p): if len(p) > 4: prop_types -= {'int32', 'uint32', 'phandle'} else: - prop_types -= {'int64', 'uint64', 'int64-array', 'uint64-array', 'phandle-array'} + prop_types -= {'int64', 'uint64', 'int64-array', 'uint64-array'} if len(p) > 2: prop_types -= {'int16', 'uint16'} else: @@ -112,6 +112,9 @@ def prop_value(validator, nodename, p): if len(p) > 0: prop_types -= {'flag'} + if prop_types >= {'phandle', 'phandle-array'}: + prop_types -= {'phandle'} + if len(prop_types) > 1: if {'string', 'string-array'} & prop_types: str = bytes_to_string(data) From c00f7475c7c8a8e59ba1b30af03cccd451104722 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 29 Jul 2024 10:23:18 -0500 Subject: [PATCH 470/505] dtb: Handle multiple types for 'dma-masters' The 'dma-masters' property is problematic to decode as it can be either a phandle-array or uint32. This didn't matter until commit 23441a412f88 ("Decode DTB properties to native type and drop schema fixups") which made decoding of these 2 types different. Ideally, we'd get rid of the uint32 user, but for now just look at the value as the uint32 case can only be 1-4 and a phandle is most likely (but still possible) not 1-4. Signed-off-by: Rob Herring (Arm) --- dtschema/dtb.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 4a4e256a..30337999 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -127,7 +127,15 @@ def prop_value(validator, nodename, p): return data else: #print(p.name + ': multiple types found', file=sys.stderr) - fmt = None + # HACK around a type collision. Since 4 bytes could be either type, + # let's hope a value of 1-4 is not a phandle + if p.name == "dma-masters": + if len(p) == 4 and (0 < type_format['uint32'].unpack(data)[0] <= 4): + fmt = 'uint32' + else: + fmt = 'phandle-array' + else: + fmt = None elif len(prop_types) == 1: fmt = prop_types.pop() From f13c18173f9afd35f58bd7aaa6c117b908208bcc Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 31 Jul 2024 08:39:42 -0600 Subject: [PATCH 471/505] dtb: Handle multiple types differing in sign If a property has multiple types differing in sign, drop the unsigned type. This prevents us from falling back to a 'uint32-array' which is now decoded differently. Same thing could happen for arrays or matrices, but ignore those for now. Signed-off-by: Rob Herring (Arm) --- dtschema/dtb.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 30337999..46a0b993 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -115,6 +115,16 @@ def prop_value(validator, nodename, p): if prop_types >= {'phandle', 'phandle-array'}: prop_types -= {'phandle'} + # Drop the unsigned type if both signed and unsigned type exists + if prop_types >= {'int64', 'uint64'}: + prop_types -= {'uint64'} + if prop_types >= {'int32', 'uint32'}: + prop_types -= {'uint32'} + if prop_types >= {'int16', 'uint16'}: + prop_types -= {'uint16'} + if prop_types >= {'int8', 'uint8'}: + prop_types -= {'uint8'} + if len(prop_types) > 1: if {'string', 'string-array'} & prop_types: str = bytes_to_string(data) From 69c4839595eb0523f8a242bcef530887d7b6a277 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 8 Aug 2024 14:44:50 -0600 Subject: [PATCH 472/505] validator: Decend allOf/anyOf/oneOf keywords when extracting properties Properties in a schema like this were not getting parsed: additionalProperties: anyOf: - properties: foo: ... The property walking code was only handling allOf/anyOf/oneOf as part of a property sub-schema. Handle allOf/anyOf/oneOf keywords occurring before a property is encountered. Signed-off-by: Rob Herring (Arm) --- dtschema/validator.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dtschema/validator.py b/dtschema/validator.py index 8d566d36..82234078 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -172,6 +172,10 @@ def _extract_subschema_types(props, schema, subschema): if 'additionalProperties' in subschema: _extract_subschema_types(props, schema, subschema['additionalProperties']) + for k in subschema.keys() & {'allOf', 'oneOf', 'anyOf'}: + for v in subschema[k]: + _extract_subschema_types(props, schema, v) + for k in subschema.keys() & {'properties', 'patternProperties'}: if isinstance(subschema[k], dict): for p, v in subschema[k].items(): From e5d88ac8ab4f4b050a7ecce9f9b63729d7cab406 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 8 Aug 2024 14:25:19 -0600 Subject: [PATCH 473/505] dtb: Fix 'interrupt-map' decoding for single entry In the case where 'interrupt-map' is a single entry and the phandle is unresolved (e.g. examples), doing nothing is wrong because the value was cleared initially. Rework the loop copying the property value to work in the case of a single entry. Signed-off-by: Rob Herring (Arm) --- dtschema/dtb.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 46a0b993..0197b9cb 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -459,11 +459,11 @@ def fixup_interrupts(dt, icells): # Assume uniform sizes (same interrupt provider) try: cells = val.index(0xffffffff, ac + icells + 1) - (ac + icells) - while i < len(val): - dt[k] += [val[i:i + cells]] - i += cells - except: - pass # Only 1 entry, nothing to do + except ValueError: + cells = len(val) + while i < len(val): + dt[k] += [val[i:i + cells]] + i += cells else: while i < len(val): p_icells = _get_cells_size(phandles[phandle], '#interrupt-cells') From 8f5303c6491ba08a654e05e439cf7a7e952701cf Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 14 Aug 2024 15:42:00 -0600 Subject: [PATCH 474/505] meta-schemas: Disable checks on non-conformant unit suffix properties There's a few properties with standard unit suffixes, but are the wrong size. Given there's only 3 known cases, let's just list them explicitly. The schema itself can be simplified slightly by removing the 'allOf'. Signed-off-by: Rob Herring (Arm) --- dtschema/meta-schemas/core.yaml | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/dtschema/meta-schemas/core.yaml b/dtschema/meta-schemas/core.yaml index 51d7f6c8..c8cd0343 100644 --- a/dtschema/meta-schemas/core.yaml +++ b/dtschema/meta-schemas/core.yaml @@ -15,6 +15,14 @@ allOf: - required: [ additionalProperties ] definitions: + unit-suffix-properties: + $ref: cell.yaml#/array + propertyNames: + description: Standard unit suffix properties don't need a type $ref + not: + const: $ref + + all-properties: allOf: - $ref: "#/definitions/core-properties" @@ -58,13 +66,16 @@ definitions: propertyNames: enum: [ description, deprecated ] - '-(bits|bps|kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|nanoamp|microamp(-hours)?|(micro-)?ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kelvin|k?pascal)$': - allOf: - - $ref: cell.yaml#/array - - description: Standard unit suffix properties don't need a type $ref - propertyNames: - not: - const: $ref + '-(bits|bps|kBps|percent|bp|mhz|hz|sec|ms|us|ns|ps|mm|nanoamp|microamp(-hours)?|micro-ohms|microwatt-hours|microvolt|(femto|pico)farads|(milli)?celsius|kelvin|k?pascal)$': + $ref: '#/definitions/unit-suffix-properties' + + # Some special cases which don't match the normal size. + '(? Date: Thu, 15 Aug 2024 09:05:38 -0600 Subject: [PATCH 475/505] schemas: property-units: Exclude some non-conforming properties There's a few properties with standard unit suffixes, but are the wrong size. Given there's only 3 known cases, let's just list them explicitly. Signed-off-by: Rob Herring (Arm) --- dtschema/schemas/property-units.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index 4532d76d..3f70c526 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -59,7 +59,8 @@ patternProperties: "-sec$": $ref: types.yaml#/definitions/uint32-array description: second - "-ms$": + # Really is "marvell,wakeup-gap-ms", but look-behind requires a fixed width pattern + "(? Date: Thu, 15 Aug 2024 14:09:45 -0600 Subject: [PATCH 476/505] dt-validate: Support multiple schema id matches The schema validation in the kernel has supported providing multiple schema substrings to limit validation to matching schemas, but no one has noticed that it didn't work for dt-validate (only validation of schemas themselves). Add the necessary support to support multiple matches in dt-validate. Signed-off-by: Rob Herring (Arm) --- dtschema/dtb_validate.py | 14 +++++++++----- dtschema/validator.py | 12 ++++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/dtschema/dtb_validate.py b/dtschema/dtb_validate.py index 6a029466..e22d5dd4 100755 --- a/dtschema/dtb_validate.py +++ b/dtschema/dtb_validate.py @@ -103,7 +103,8 @@ def main(): help="Filename or directory of devicetree DTB input file(s)") ap.add_argument('-s', '--schema', help="preparsed schema file or path to schema files") ap.add_argument('-p', '--preparse', help="preparsed schema file (deprecated, use '-s')") - ap.add_argument('-l', '--limit', help="limit validation to schemas with $id matching LIMIT substring") + ap.add_argument('-l', '--limit', help="limit validation to schemas with $id matching LIMIT substring. " \ + "Multiple substrings separated by ':' can be listed (e.g. foo:bar:baz).") ap.add_argument('-c', '--compatible-match', action="store_true", help="limit validation to schema matching nodes' most specific compatible string") ap.add_argument('-m', '--show-unmatched', @@ -118,14 +119,17 @@ def main(): verbose = args.verbose show_unmatched = args.show_unmatched - match_schema_file = args.limit + if args.limit: + match_schema_file = args.limit.split(':') compatible_match = args.compatible_match # Maintain prior behaviour which accepted file paths by stripping the file path if args.url_path and args.limit: - for d in args.url_path.split(os.path.sep): - if d and match_schema_file.startswith(d): - match_schema_file = match_schema_file[(len(d) + 1):] + for i,match in enumerate(match_schema_file): + for d in args.url_path.split(os.path.sep): + if d and match.startswith(d): + match = match[(len(d) + 1):] + match_schema_file[i] = match if args.preparse: sg = schema_group(args.preparse) diff --git a/dtschema/validator.py b/dtschema/validator.py index 82234078..4d94d9ea 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -416,12 +416,20 @@ def annotate_error(self, id, error): error.linecol = -1, -1 error.note = None + def _filter_match(self, schema_id, filter): + if not filter: + return True + for f in filter: + if f in schema_id: + return True + return False + def iter_errors(self, instance, filter=None, compatible_match=False): if 'compatible' in instance: for inst_compat in instance['compatible']: if inst_compat in self.compat_map: schema_id = self.compat_map[inst_compat] - if not filter or filter in schema_id: + if self._filter_match(schema_id, filter): schema = self.schemas[schema_id] for error in self.DtValidator(schema, resolver=self.resolver, @@ -434,7 +442,7 @@ def iter_errors(self, instance, filter=None, compatible_match=False): return for schema_id in self.always_schemas: - if filter and filter not in schema_id: + if not self._filter_match(schema_id, filter): continue schema = {'if': self.schemas[schema_id]['select'], 'then': self.schemas[schema_id]} From 74bc7ead3618723280d0d7fd95c2781fedba4656 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 15 Aug 2024 23:40:11 +0200 Subject: [PATCH 477/505] schemas: i2c: reword descriptions for inclusive language Changing bindings is hard, changing descriptions is easy. Let's start with the low-hanging fruits and use the official I2C terminology (as of specs v7) in the descriptions. Drop a superfluous 'a' from the description of 'reg' for targets. Signed-off-by: Wolfram Sang Signed-off-by: Rob Herring (Arm) --- dtschema/schemas/i2c/i2c-controller.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index 96700820..e475ead7 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -99,7 +99,7 @@ properties: multi-master: type: boolean description: - States that there is another master active on this bus. The OS can use + States that there is another controller active on this bus. The OS can use this information to adapt power management to keep the arbitration awake all the time, for example. Can not be combined with 'single-master'. @@ -116,9 +116,9 @@ properties: single-master: type: boolean description: - States that there is no other master active on this bus. The OS can use - this information to detect a stalled bus more reliably, for example. Can - not be combined with 'multi-master'. + States that there is no other controller active on this bus. The OS can + use this information to detect a stalled bus more reliably, for example. + Can not be combined with 'multi-master'. smbus: type: boolean @@ -155,7 +155,7 @@ patternProperties: - minimum: 0xc0000000 maximum: 0xc00003ff description: | - One or many I2C slave addresses. These are usually a 7 bit addresses. + One or many I2C target addresses. These are usually 7 bit addresses. However, flags can be attached to an address. I2C_TEN_BIT_ADDRESS is used to mark a 10 bit address. It is needed to avoid the ambiguity between e.g. a 7 bit address of 0x50 and a 10 bit address of 0x050 @@ -172,7 +172,7 @@ patternProperties: interrupts: description: I2C core will treat "irq" interrupt (or the very first interrupt if - not using interrupt names) as primary interrupt for the slave. + not using interrupt names) as primary interrupt for the target. interrupt-names: anyOf: From 285f99159c8f79103530f53efae425b9e67e4bd0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 15 Aug 2024 23:40:12 +0200 Subject: [PATCH 478/505] schemas: i2c: clean up interrupt descriptions for I2C targets Schemas should be OS agnostic, so don't mention what the "I2C core" will do because this only applies to Linux. Also, drop the generic "smbus_alert" naming because this belongs to controllers not targets, so we don't want to describe it here. Finally, use "contains" instead of "items" because the enum is not exhaustive. Signed-off-by: Wolfram Sang Signed-off-by: Rob Herring (Arm) --- dtschema/schemas/i2c/i2c-controller.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index e475ead7..6dc73f8b 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -171,20 +171,20 @@ patternProperties: interrupts: description: - I2C core will treat "irq" interrupt (or the very first interrupt if - not using interrupt names) as primary interrupt for the target. + If not using interrupt-names, the first interrupt will be treated as + the primary interrupt for the target. interrupt-names: anyOf: - {} # Any name is allowed. - - items: + - contains: enum: - irq - wakeup - - smbus_alert description: - Names which are recognized by I2C core, other names are left to - individual bindings. + Generic names are "irq" for the primary interrupt and "wakeup" + for the wakeup interrupt. Other names are left to individual + bindings. wakeup-source: description: From c51125d571cac9596048e888a856d70650e400e0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 15 Aug 2024 23:40:13 +0200 Subject: [PATCH 479/505] schemas: i2c: add generic interrupt name for I2C controllers "smbus_alert" is a generic interrupt name for controllers, so document it. Signed-off-by: Wolfram Sang Signed-off-by: Rob Herring (Arm) --- dtschema/schemas/i2c/i2c-controller.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index 6dc73f8b..97d0aaa7 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -90,6 +90,21 @@ properties: low-pass analog filter). Typical value should be above the normal i2c bus clock frequency (clock-frequency). Specified in Hz. + interrupts: + description: + If not using interrupt-names, the first interrupt will be treated as the + primary interrupt for the controller. + + interrupt-names: + anyOf: + - {} # Any name is allowed. + - contains: + enum: + - smbus_alert + description: + Generic name is "smbus_alert" for the SMBusAlert signal. Other names + are left to individual bindings. + mctp-controller: type: boolean description: From 52c380eb3562015ac95aff1a7be1f937f452c00d Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 9 Sep 2024 12:57:54 +0800 Subject: [PATCH 480/505] schemas: core: Introduce "fail-needs-probe" status Some components can not be absolutely determined to exist on a given device when the device tree is written or compiled. However such components can either be probed using I2C transfers, or determined to exist based on runtime information, such as GPIO or ADC strappings, or extra information passed over from boot firmware or read from some flash chip. Such an arrangement of components are commonly seen in the consumer electronics world, where the manufacturer will swap out electrically compatible components due to inventory or price constraints. These components are commonly attached to the baseboard with a standardized ribbon cable, and the ribbon cable may contain strapping resistors if necessary. Introduce a new "fail-needs-probe" status string that corresponds to devices or components that "might" exist. (The term "component" shall be used to avoid confusion with the actual "complete device".) This status signals that the implementation needs to do extra probing to determine the exact state of the component. Signed-off-by: Chen-Yu Tsai --- dtschema/schemas/dt-core.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/dt-core.yaml b/dtschema/schemas/dt-core.yaml index 926e2afc..0dd1164d 100644 --- a/dtschema/schemas/dt-core.yaml +++ b/dtschema/schemas/dt-core.yaml @@ -56,7 +56,7 @@ properties: oneOf: - type: object - $ref: types.yaml#/definitions/string - enum: [ okay, disabled, reserved, fail ] + enum: [ okay, disabled, reserved, fail, fail-needs-probe ] phandle: $ref: types.yaml#/definitions/uint32 From 615da72415bf7c1a897caf3a87261132fed6aac8 Mon Sep 17 00:00:00 2001 From: Nick Chan Date: Wed, 11 Sep 2024 22:55:55 +0800 Subject: [PATCH 481/505] schemas: root-node: Add 'television' chassis-type The 'television' chassis-type includes Smart TVs and set-top boxes, or any remote-controlled displays in general. Signed-off-by: Nick Chan --- dtschema/schemas/root-node.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/dtschema/schemas/root-node.yaml b/dtschema/schemas/root-node.yaml index dc06e0c4..b7f4c944 100644 --- a/dtschema/schemas/root-node.yaml +++ b/dtschema/schemas/root-node.yaml @@ -27,6 +27,7 @@ properties: - handset - watch - embedded + - television "#address-cells": enum: [1, 2] "#size-cells": From dc4787b374ecdec84a1ad2e5e682ff3a8593a1f0 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 11 Sep 2024 14:26:10 -0500 Subject: [PATCH 482/505] validator: Warn on multiple schemas with same compatible string Since only 1 schema can map to a compatible, it is undefined which schema will be used. It's also generally a mistake to have the same compatible in multiple schemas, so add a warning when that is detected. Signed-off-by: Rob Herring (Arm) --- dtschema/validator.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index 4d94d9ea..6341712e 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -392,8 +392,12 @@ def __init__(self, schema_files, filter=None): self.always_schemas += [sch['$id']] elif 'properties' in sch and 'compatible' in sch['properties']: compatibles = dtschema.extract_node_compatibles(sch['properties']['compatible']) - compatibles = set(compatibles) - {'syscon', 'simple-mfd'} + if len(compatibles) > 1: + compatibles = set(compatibles) - {'syscon', 'simple-mfd', 'simple-bus'} for c in compatibles: + if not schema_cache and c in self.compat_map: + print(f'Warning: Duplicate compatible "{c}" found in schemas matching "$id":\n' + f'\t{self.compat_map[c]}\n\t{sch["$id"]}', file=sys.stderr) self.compat_map[c] = sch['$id'] self.schemas['version'] = dtschema.__version__ From 577c1abc92fa309cb38cd9a567e8a9854a990cd0 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 11 Sep 2024 16:31:35 -0500 Subject: [PATCH 483/505] github: Update actions versions The current versions generate node.js warnings, so update to the latest versions. Signed-off-by: Rob Herring (Arm) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 817c61cd..23908434 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,9 +11,9 @@ jobs: python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From 0934678abc36614cd3c5165ca49ba78b881ee2fa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 9 Sep 2024 12:58:35 +0200 Subject: [PATCH 484/505] schemas: i2c: add optional GPIO binding for SMBALERT# line Most I2C controllers do not have a dedicated pin for SMBus Alerts. Allow them to define a GPIO as a side-channel. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20240909105835.28531-1-wsa+renesas@sang-engineering.com Signed-off-by: Rob Herring (Arm) --- dtschema/schemas/i2c/i2c-controller.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dtschema/schemas/i2c/i2c-controller.yaml b/dtschema/schemas/i2c/i2c-controller.yaml index 97d0aaa7..487e6693 100644 --- a/dtschema/schemas/i2c/i2c-controller.yaml +++ b/dtschema/schemas/i2c/i2c-controller.yaml @@ -135,6 +135,11 @@ properties: use this information to detect a stalled bus more reliably, for example. Can not be combined with 'multi-master'. + smbalert-gpios: + maxItems: 1 + description: + Specifies the GPIO used for the SMBALERT# line. Optional. + smbus: type: boolean description: From 12c3cd5333ba0003a7c6b1cef4358471c1d60987 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 8 Oct 2024 13:16:31 -0500 Subject: [PATCH 485/505] schemas: Add wakeup-source schema Add schema for "wakeup-source" property. The descriptions and examples are from wakeup-source.txt in the Linux kernel. Sudeep (Arm) was the author for that. Signed-off-by: Rob Herring (Arm) --- dtschema/schemas/wakeup-source.yaml | 72 +++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 dtschema/schemas/wakeup-source.yaml diff --git a/dtschema/schemas/wakeup-source.yaml b/dtschema/schemas/wakeup-source.yaml new file mode 100644 index 00000000..a2ba7d71 --- /dev/null +++ b/dtschema/schemas/wakeup-source.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2015,2024 Arm Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/wakeup-source.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Wakeup sources + +description: > + Nodes that describe devices which have wakeup capability may contain a + "wakeup-source" boolean property. + + If the device is marked as a wakeup-source, interrupt wake capability depends + on the device specific "interrupt-names" property. If no interrupts are labeled + as wake capable, then it is up to the device to determine which interrupts can + wake the system. + + However if a device has a dedicated interrupt as the wakeup source, then it + needs to specify/identify it using a device specific interrupt name. In such + cases only that interrupt can be used as a wakeup interrupt. + + While various legacy interrupt names exist, new devices should use "wakeup" as + the canonical interrupt name. + +maintainers: + - Rob Herring + +select: true + +properties: + wakeup-source: + type: boolean + +additionalProperties: true + +examples: + - | + # With "wakeup" interrupt name + device@10000 { + compatible = "vendor,device-id"; + reg = <0x10000 0x1000>; + interrupts = <0 19 4>, <0 21 4>, <0 22 4>; + interrupt-names = "ack", "err", "wakeup"; + wakeup-source; + }; + + - | + # Without "wakeup" interrupt name + embedded-controller@1e { + compatible = "google,cros-ec-i2c"; + reg = <0x1e>; + interrupts = <6 0>; + wakeup-source; + }; + + - | + # Without interrupts + keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button { + debounce-interval = <50>; + wakeup-source; + linux,code = <116>; + label = "POWER"; + gpios = <&iofpga_gpio0 0 0x4>; + }; + }; +... From 3656244c20e3513fe5964cf0ab786d2a1a26da98 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 1 Nov 2024 13:08:28 -0500 Subject: [PATCH 486/505] meta-schemas: Exclude "adi,channels" from vendor properties "adi,channels" is a node name which is in use. Add it to the exceptions. Signed-off-by: Rob Herring (Arm) --- dtschema/meta-schemas/vendor-props.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dtschema/meta-schemas/vendor-props.yaml b/dtschema/meta-schemas/vendor-props.yaml index fcc37269..39b9ced3 100644 --- a/dtschema/meta-schemas/vendor-props.yaml +++ b/dtschema/meta-schemas/vendor-props.yaml @@ -8,6 +8,10 @@ $schema: https://json-schema.org/draft/2019-09/schema description: Metaschema for vendor specific properties +properties: + adi,channels: + type: object + patternProperties: '[\[\]*{}$\^\\]+': true # exclude regex's '^[^,]*$': true From 09834635dc1ecfb1301b21b5c0fd9bb828708581 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 1 Nov 2024 13:52:10 -0500 Subject: [PATCH 487/505] meta-schemas: Allow "not" in "items" list Sometimes there's a need to document generic/fallback compatibles before any specific compatible can be defined. In order to support that, allow using "not" to do something like this: items: - not: {} description: Needs a specific compatible - const: fallback-compatible Signed-off-by: Rob Herring (Arm) --- dtschema/meta-schemas/string-array.yaml | 26 ++++++++++++------------- test/schemas/good-example.yaml | 4 ++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/dtschema/meta-schemas/string-array.yaml b/dtschema/meta-schemas/string-array.yaml index 8475eba5..f5234c6c 100644 --- a/dtschema/meta-schemas/string-array.yaml +++ b/dtschema/meta-schemas/string-array.yaml @@ -28,20 +28,17 @@ all-properties: maxItems: minimum: 1 items: - oneOf: - - type: object - allOf: - - $ref: '#/all-properties' - - type: array - minItems: 1 - items: - allOf: - - $ref: '#/all-properties' - - properties: - enum: {} - const: {} - pattern: {} - additionalProperties: false + if: + type: object + then: + $ref: '#/all-properties' + else: + type: array + minItems: 1 + items: + $ref: '#/all-properties' + propertyNames: + enum: [ const, description, enum, not, pattern ] enum: type: array items: @@ -54,6 +51,7 @@ all-properties: $ref: '#/all-properties' default: {} deprecated: {} + not: {} pattern: type: string diff --git a/test/schemas/good-example.yaml b/test/schemas/good-example.yaml index 13ed27a1..fd22d8f4 100644 --- a/test/schemas/good-example.yaml +++ b/test/schemas/good-example.yaml @@ -26,6 +26,10 @@ properties: - items: - enum: - vendor,soc1-ip + - items: + - not: {} + description: Needs a specific compatible + - const: vendor,soc1-ip reg: maxItems: 2 From c9b47977c6103fc93a1167057c89e5e9dadfb48c Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 1 Nov 2024 14:10:44 -0500 Subject: [PATCH 488/505] fixups: Allow "items" entries to be boolean Empty schemas are allowed, so a boolean should be as well. Signed-off-by: Rob Herring (Arm) --- dtschema/fixups.py | 2 ++ dtschema/lib.py | 4 ++++ test/schemas/good-example.yaml | 1 + 3 files changed, 7 insertions(+) diff --git a/dtschema/fixups.py b/dtschema/fixups.py index cee6075d..11ca9c80 100644 --- a/dtschema/fixups.py +++ b/dtschema/fixups.py @@ -66,6 +66,8 @@ def _fixup_remove_empty_items(subschema): return for item in subschema['items']: + if not isinstance(item, dict): + continue item.pop('description', None) _fixup_remove_empty_items(item) if item != {}: diff --git a/dtschema/lib.py b/dtschema/lib.py index 33505a1d..b1c19e1f 100644 --- a/dtschema/lib.py +++ b/dtschema/lib.py @@ -33,6 +33,8 @@ def _value_is_type(subschema, key, type): def _is_int_schema(subschema): + if not isinstance(subschema, dict): + return False for match in ['const', 'enum', 'minimum', 'maximum']: if _value_is_type(subschema, match, int): return True @@ -41,6 +43,8 @@ def _is_int_schema(subschema): def _is_string_schema(subschema): + if not isinstance(subschema, dict): + return False for match in ['const', 'enum', 'pattern']: if _value_is_type(subschema, match, str): return True diff --git a/test/schemas/good-example.yaml b/test/schemas/good-example.yaml index fd22d8f4..2005b8f8 100644 --- a/test/schemas/good-example.yaml +++ b/test/schemas/good-example.yaml @@ -27,6 +27,7 @@ properties: - enum: - vendor,soc1-ip - items: + - false - not: {} description: Needs a specific compatible - const: vendor,soc1-ip From 5844e95323c12549d21dc5acac7f3f655b6defa1 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 13 Sep 2024 00:33:40 +0530 Subject: [PATCH 489/505] schemas: gpio: Remove #gpio-cells dependence on gpio-controller Nexus node [0] introduced with devicetree spec v0.3 allow routing GPIO, clock, etc. For a GPIO nexus node, the dependence of #gpio-cells on gpio-controller does not make sense. [0]: https://devicetree-specification.readthedocs.io/en/v0.3/devicetree-basics.html#nexus-nodes-and-specifier-mapping Signed-off-by: Ayush Singh --- dtschema/schemas/gpio/gpio.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dtschema/schemas/gpio/gpio.yaml b/dtschema/schemas/gpio/gpio.yaml index 87c381b2..9e2ad3c9 100644 --- a/dtschema/schemas/gpio/gpio.yaml +++ b/dtschema/schemas/gpio/gpio.yaml @@ -35,10 +35,9 @@ properties: dependencies: gpio-controller: ['#gpio-cells'] - '#gpio-cells': [ gpio-controller ] - gpio-line-names: ['#gpio-cells'] - ngpios: ['#gpio-cells'] - gpio-reserved-ranges: ['#gpio-cells'] - gpio-ranges: ['#gpio-cells'] + gpio-line-names: ['#gpio-cells', gpio-controller] + ngpios: ['#gpio-cells', gpio-controller] + gpio-reserved-ranges: ['#gpio-cells', gpio-controller] + gpio-ranges: ['#gpio-cells', gpio-controller] additionalProperties: true From f333676f9ff789842a40575be981215781cbb0b9 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 13 Sep 2024 00:38:55 +0530 Subject: [PATCH 490/505] schemas: gpio: Add GPIO nexus node GPIO Nexus Node [0] allows routing gpios in devicetree. [0]: https://devicetree-specification.readthedocs.io/en/v0.3/devicetree-basics.html#nexus-nodes-and-specifier-mapping Signed-off-by: Ayush Singh --- dtschema/schemas/gpio/gpio-nexus-node.yaml | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 dtschema/schemas/gpio/gpio-nexus-node.yaml diff --git a/dtschema/schemas/gpio/gpio-nexus-node.yaml b/dtschema/schemas/gpio/gpio-nexus-node.yaml new file mode 100644 index 00000000..12c00064 --- /dev/null +++ b/dtschema/schemas/gpio/gpio-nexus-node.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright Ayush Singh + +$id: http://devicetree.org/schemas/gpio/gpio-nexus-node.yaml# +$schema: http://devicetree.org/meta-schemas/base.yaml# + +title: GPIO Nexus node properties + +description: Schema for nexus node devicetree bindings +maintainers: + - Ayush Singh + +# always select the core schema +select: true + +properties: + "#gpio-cells": true + gpio-map: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + gpio-map-mask: + $ref: types.yaml#/definitions/uint32-array + gpio-map-pass-thru: + $ref: types.yaml#/definitions/uint32-array + +dependentRequired: + gpio-map: ['#gpio-cells'] + 'gpio-map-mask': [ gpio-map ] + 'gpio-map-pass-thru': [ gpio-map ] + +additionalProperties: true From d41cf1ec222feb2c624f95e764934fc3eee5e231 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 10 May 2024 02:03:01 +0200 Subject: [PATCH 491/505] validator: Don't crash if the de-aliaser hack fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This can apparently fall off the bike: SCHEMA Documentation/devicetree/bindings/processed-schema.json Traceback (most recent call last): File "/home/konrad/.local/bin/dt-mk-schema", line 38, in schemas = dtschema.DTValidator(args.schemas).schemas ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/site-packages/dtschema/validator.py", line 373, in __init__ self.make_property_type_cache() File "/usr/lib/python3.12/site-packages/dtschema/validator.py", line 460, in make_property_type_cache self.props, self.pat_props = get_prop_types(self.schemas) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/site-packages/dtschema/validator.py", line 195, in get_prop_types del props[r'^[a-z][a-z0-9\-]*$'] ~~~~~^^^^^^^^^^^^^^^^^^^^^^^ KeyError: '^[a-z][a-z0-9\\-]*$' make[2]: *** [Documentation/devicetree/bindings/Makefile:64: Documentation/devicetree/bindings/processed-schema.json] Błąd 1 Signed-off-by: Konrad Dybcio --- dtschema/validator.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dtschema/validator.py b/dtschema/validator.py index 6341712e..a59a99ab 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -195,7 +195,10 @@ def get_prop_types(schemas): props = extract_types(schemas) # hack to remove aliases and generic patterns - del props[r'^[a-z][a-z0-9\-]*$'] + try: + del props[r'^[a-z][a-z0-9\-]*$'] + except: + pass # Remove all node types for val in props.values(): From 3033f0b3479760db047fd58f38ed777dc7e2a856 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 21 Sep 2024 00:34:45 +0200 Subject: [PATCH 492/505] dt-bindings: u-boot: Add property for LED boot and activity Add property for LED boot and activity and period for blink mode. These property define the phandle to an LED to use for the u-boot boot or activity LED to signal successful boot or activity like flash write or tftp traffic. Signed-off-by: Christian Marangi --- dtschema/schemas/options/u-boot.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dtschema/schemas/options/u-boot.yaml b/dtschema/schemas/options/u-boot.yaml index c9894ff5..4b84eb0c 100644 --- a/dtschema/schemas/options/u-boot.yaml +++ b/dtschema/schemas/options/u-boot.yaml @@ -110,6 +110,26 @@ properties: enabled) 2: console output is suppressed and not recorded + boot-led: + $ref: /schemas/types.yaml#/definitions/phandle + description: | + This is used to specify a phandle to an LED to indicate a successful boot. + + boot-led-period-ms: + default: 250 + description: | + This is used to specify the default period (in ms) for an LED in blink mode. + + activity-led: + $ref: /schemas/types.yaml#/definitions/phandle + description: | + This is used to specify a phandle to an LED to indicate an activity. + + activity-led-period-ms: + default: 250 + description: | + This is used to specify the default period (in ms) for an LED in blink mode. + required: - compatible From 9efa90eacf2d0faf6f5276a01d12e844551b4570 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 9 Nov 2023 16:37:13 -0600 Subject: [PATCH 493/505] Add a tool to compare schemas for ABI changes Add a new tool which compares 2 sets of schemas for possible ABI changes. It's not complete nor 100% accurate, but it's a start. This checks for the following kinds of changes: - New required properties - Minimum number of entries required increased - Removed properties - Deprecated properties Limitations: Restructuring of schemas may result in false positives or missed ABI changes. There's some support if a property moves from a schema to a referenced schema. Schemas underneath logic keywords (allOf, oneOf, anyOf) other than 'required' or if/then/else schemas are not handled. Signed-off-by: Rob Herring --- dtschema/cmp_schema.py | 150 +++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 1 + 2 files changed, 151 insertions(+) create mode 100755 dtschema/cmp_schema.py diff --git a/dtschema/cmp_schema.py b/dtschema/cmp_schema.py new file mode 100755 index 00000000..14437ce1 --- /dev/null +++ b/dtschema/cmp_schema.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2023-2024 Arm Ltd. + +import sys +import argparse +import urllib + +import dtschema + + +def path_list_to_str(path): + return '/' + '/'.join(path) + + +def prop_generator(schema, path=[]): + if not isinstance(schema, dict): + return + for prop_key in ['properties', 'patternProperties']: + if prop_key in schema: + for p, sch in schema[prop_key].items(): + yield path + [prop_key, p], sch + yield from prop_generator(sch, path=path + [prop_key, p]) + + +def _ref_to_id(schema_id, ref): + ref = urllib.parse.urljoin(schema_id, ref) + if '#/' not in ref: + ref += '#' + return ref + + +def _prop_in_schema(prop, schema, schemas): + for p, sch in prop_generator(schema): + if p[1] == prop: + return True + + if 'allOf' in schema: + for e in schema['allOf']: + if '$ref' in e: + ref_id = _ref_to_id(schema['$id'], e['$ref']) + if ref_id in schemas: + if _prop_in_schema(prop, schemas[ref_id], schemas): + return True + + if '$ref' in schema: + ref_id = _ref_to_id(schema['$id'], schema['$ref']) + if ref_id in schemas and _prop_in_schema(prop, schemas[ref_id], schemas): + return True + + return False + + +def check_removed_property(schema_id, base, schemas): + for p, sch in prop_generator(base): + if not _prop_in_schema(p[1], schemas[schema_id], schemas): + print(f'{schema_id}{path_list_to_str(p)}: existing property removed', file=sys.stderr) + + +def check_deprecated_property(schema_id, base, schemas): + for p, sch in prop_generator(base): + if isinstance(sch, dict) and 'deprecated' in sch: + continue + schema = schema_get_from_path(schemas[schema_id], p) + if schema and isinstance(schema, dict) and 'deprecated' in schema: + print(f'{schema_id}{path_list_to_str(p)}: existing property deprecated', file=sys.stderr) + + +def schema_get_from_path(sch, path): + for p in path: + try: + sch = sch[p] + except: + return None + return sch + + +def check_new_items(schema_id, base, new): + for p, sch in prop_generator(new): + if not isinstance(sch, dict) or 'minItems' not in sch: + continue + + new_min = sch['minItems'] + base_min = schema_get_from_path(base, p + ['minItems']) + + if base_min and new_min > base_min: + print(f'{schema_id}{path_list_to_str(p)}: required entries increased from {base_min} to {new_min}', file=sys.stderr) + + +def _get_required(schema): + required = [] + for k in {'allOf', 'oneOf', 'anyOf'} & schema.keys(): + for sch in schema[k]: + if 'required' not in sch: + continue + required += sch['required'] + + if 'required' in schema: + required += schema['required'] + + return set(required) + + +def _check_required(schema_id, base, new, path=[]): + if not isinstance(base, dict) or not isinstance(new, dict): + return + + base_req = _get_required(base) + new_req = _get_required(new) + + if not new_req: + return + + diff = new_req - base_req + if diff: + print(f'{schema_id}{path_list_to_str(path)}: new required properties added: {", ".join(diff)}', file=sys.stderr) + return + + +def check_required(schema_id, base, new): + _check_required(schema_id, base, new) + + for p, sch in prop_generator(new): + _check_required(schema_id, schema_get_from_path(base, p), sch, path=p) + + +def main(): + ap = argparse.ArgumentParser(description="Compare 2 sets of schemas for possible ABI differences") + ap.add_argument("baseline", type=str, + help="Baseline schema directory or preprocessed schema file") + ap.add_argument("new", type=str, + help="New schema directory or preprocessed schema file") + ap.add_argument('-V', '--version', help="Print version number", + action="version", version=dtschema.__version__) + args = ap.parse_args() + + base_schemas = dtschema.DTValidator([args.baseline]).schemas + schemas = dtschema.DTValidator([args.new]).schemas + + if not schemas or not base_schemas: + return -1 + + for schema_id, sch in schemas.items(): + if schema_id not in base_schemas or 'generated' in schema_id: + continue + + check_required(schema_id, base_schemas[schema_id], sch) + check_removed_property(schema_id, base_schemas[schema_id], schemas) + check_deprecated_property(schema_id, base_schemas[schema_id], schemas) + check_new_items(schema_id, base_schemas[schema_id], sch) diff --git a/pyproject.toml b/pyproject.toml index 2192a685..0ad2fa2c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ dependencies = [ [project.scripts] dt-check-compatible = "dtschema.check_compatible:main" +dt-cmp-schema = "dtschema.cmp_schema:main" dt-doc-validate = "dtschema.doc_validate:main" dt-extract-example = "dtschema.extract_example:main" dt-extract-props = "dtschema.extract_props:main" From 4f1b8c113900f8cafff08afd6e2eb70a3aac4dda Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 8 Nov 2024 14:20:53 -0600 Subject: [PATCH 494/505] github: Enable python 3.12 and 3.13 Signed-off-by: Rob Herring (Arm) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23908434..dbfa648a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v4 From cabb5b9507a53d46eb5ccf162281e35abfa6e88e Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 15 Nov 2024 09:13:22 -0600 Subject: [PATCH 495/505] dtb: Fix type collision with "mode-gpios" "mode-gpios" matches on 2 regex's: "^mode-" and "-gpios$". Handle it as another special case. Signed-off-by: Rob Herring (Arm) --- dtschema/dtb.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/dtb.py b/dtschema/dtb.py index 0197b9cb..c166f00b 100644 --- a/dtschema/dtb.py +++ b/dtschema/dtb.py @@ -144,6 +144,9 @@ def prop_value(validator, nodename, p): fmt = 'uint32' else: fmt = 'phandle-array' + elif p.name == "mode-gpios": + # "mode-gpios" also matches "^mode-" pattern, but it is always a GPIO + fmt = 'phandle-array' else: fmt = None elif len(prop_types) == 1: From cc02c1329190f2123b8fe02f48da33a7e3da0593 Mon Sep 17 00:00:00 2001 From: Krishna chaitanya chundru Date: Sat, 26 Oct 2024 05:17:04 +0530 Subject: [PATCH 496/505] schemas: pci: bridge: Document PCIe equalization presets PCIe equalization presets are predefined settings used to optimize signal integrity by compensating for signal loss and distortion in high-speed data transmission. As per PCIe spec 6.0.1 revision section 8.3.3.3 & 4.2.4 for data rates of 8.0 GT/s, 16.0 GT/s, 32.0 GT/s and 64.0 GT/s provides a way to configure lane equalization presets for each lane to enhance the PCIe link reliability. Each preset value represents a different combination of pre-shoot and de-emphasis values. For each data rate it may be required to have a different preset configuration and each lane will have different preset values. Define per data rate equalization preset property with array of 16 representing 16 lanes of the PCIe. Signed-off-by: Krishna chaitanya chundru --- dtschema/schemas/pci/pci-bus-common.yaml | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/dtschema/schemas/pci/pci-bus-common.yaml b/dtschema/schemas/pci/pci-bus-common.yaml index dfd5c32e..94b648f3 100644 --- a/dtschema/schemas/pci/pci-bus-common.yaml +++ b/dtschema/schemas/pci/pci-bus-common.yaml @@ -159,6 +159,46 @@ properties: vpcie3v3aux-supply: description: 3.3v AUX regulator phandle for the slot + eq-presets-8gts: + description: + Contains the equalization preset values for PCIe data rates 8.0 GT/s. + Each preset value is used to adjust the transmitter settings to improve + signal quality and meet the electrical requirements. These preset values + go in Lane Equalization Control registers (PCIe r6.0, sec 7.7.3.4). + $ref: /schemas/types.yaml#/definitions/uint16-array + minItems: 1 + maxItems: 16 + + eq-presets-16gts: + description: + Contains the equalization preset values for PCIe data rates 16.0 GT/s. + Each preset value is used to adjust the transmitter settings to improve + signal quality and meet the electrical requirements. These preset values + go in Lane Equalization Control registers (PCIe r6.0, sec 7.7.5.9). + $ref: /schemas/types.yaml#/definitions/uint8-array + minItems: 1 + maxItems: 16 + + eq-presets-32gts: + description: + Contains the equalization preset values for PCIe data rates 32.0 GT/s. + Each preset value is used to adjust the transmitter settings to improve + signal quality and meet the electrical requirements. These preset values + go in Lane Equalization Control registers (PCIe r6.0, sec 7.7.6.9). + $ref: /schemas/types.yaml#/definitions/uint8-array + minItems: 1 + maxItems: 16 + + eq-presets-64gts: + description: + Contains the equalization preset values for PCIe data rates 64.0 GT/s. + Each preset value is used to adjust the transmitter settings to improve + signal quality and meet the electrical requirements. These preset values + go in Lane Equalization Control registers (PCIe r6.0, sec 7.7.7.5). + $ref: /schemas/types.yaml#/definitions/uint8-array + minItems: 1 + maxItems: 16 + patternProperties: "@1?[0-9a-f](,[0-7])?$": type: object From 93ee8008959e362548168eaa7bdc20c115f3d586 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 20 Nov 2024 17:26:06 -0600 Subject: [PATCH 497/505] dt-bindings: trigger: Add trigger source Add a new binding for trigger source providers and consumers. This is essentially the trigger source bindings from the leds subsystem in the Linux kernel, but with more generic descriptions and no restrictions on #trigger-source-cells. Signed-off-by: David Lechner --- dtschema/schemas/trigger/trigger-source.yaml | 33 ++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 dtschema/schemas/trigger/trigger-source.yaml diff --git a/dtschema/schemas/trigger/trigger-source.yaml b/dtschema/schemas/trigger/trigger-source.yaml new file mode 100644 index 00000000..272c763f --- /dev/null +++ b/dtschema/schemas/trigger/trigger-source.yaml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/trigger/trigger-source.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Trigger source provider + +maintainers: + - David Lechner + +description: + A trigger source providers are an abstraction for anything that provides a + signal to trigger an event. For example, this could be a disk activity signal + that triggers a LED to turn on or off or it could be a data ready signal + that triggers a SPI offload to read data without a software interrupt. Each + trigger source provider should be represented by a device tree node. + +select: true + +properties: + '#trigger-source-cells': + description: + Number of cells required to specify a trigger source. This property is + is applied to the trigger source provider. + + trigger-sources: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + This property is applied to the trigger source consumer to describe the + connection to a trigger source provider. + +additionalProperties: true From b5356dfe9516266ab47bf23c4c7c11757f88dffe Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 27 Nov 2024 09:17:41 -0600 Subject: [PATCH 498/505] meta-schemas: Allow additionalItems to be a schema Allow for a case where the first item entries are fixed followed by a series of optional entries: maxItems: 5 items: - const: ipg additionalItems: pattern: '^source[0-4]$' Signed-off-by: Rob Herring (Arm) --- dtschema/meta-schemas/keywords.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dtschema/meta-schemas/keywords.yaml b/dtschema/meta-schemas/keywords.yaml index f3c60b4a..7609ca19 100644 --- a/dtschema/meta-schemas/keywords.yaml +++ b/dtschema/meta-schemas/keywords.yaml @@ -126,7 +126,11 @@ properties: not: pattern: '^https?://' additionalItems: - type: boolean + oneOf: + - type: object + allOf: + - $ref: "#/definitions/sub-schemas" + - type: boolean additionalProperties: oneOf: - type: object From ea243eb8c15d0f14785b0c95d69a40fc7c51c21e Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 17 Dec 2024 13:10:04 -0600 Subject: [PATCH 499/505] github: Disable python 3.7 Python 3.7 has been dropped as testing moved to ubuntu 24.04. Signed-off-by: Rob Herring (Arm) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dbfa648a..f0c2167b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v4 From c4da38d004ac01b5dc84e91cfbe3c5a7bfcc8fc0 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 23 Dec 2024 11:17:40 +0800 Subject: [PATCH 500/505] schemas: Add access controller consumer Add a new binding access controller consumers. There are bus resource domain controllers, eFuse access controllers, so add the consumer bindings for various nodes to use. Signed-off-by: Peng Fan --- .../access-controller-consumer.yaml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 dtschema/schemas/access-controller/access-controller-consumer.yaml diff --git a/dtschema/schemas/access-controller/access-controller-consumer.yaml b/dtschema/schemas/access-controller/access-controller-consumer.yaml new file mode 100644 index 00000000..a19c3961 --- /dev/null +++ b/dtschema/schemas/access-controller/access-controller-consumer.yaml @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: BSD-2-Clause +# Copyright 2024 NXP +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/access-controller/access-controller-consumer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Access Controller Consumer Properties + +maintainers: + - Peng Fan + +select: true + +properties: + access-controllers: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + This property is applied to the access controller consumer to describe + the connection to an access controller provider. + +additionalProperties: true From 6fa259dc18302c79d32a1a928b127f344061d811 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Wed, 15 Jan 2025 12:20:40 -0600 Subject: [PATCH 501/505] validator: Add warning for properties with incompatible multiple types While generally having multiple types for the same property name is discouraged, there are some cases of this we're stuck with. In many cases the type for a specific instance can be determined based on the property length or the data (ASCII strings). In a few cases, there is no way to tell. These cases have types of scalar, array, or matrix, and the possible property length overlaps. Signed-off-by: Rob Herring (Arm) --- dtschema/validator.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/dtschema/validator.py b/dtschema/validator.py index a59a99ab..21d5e479 100644 --- a/dtschema/validator.py +++ b/dtschema/validator.py @@ -479,10 +479,46 @@ def check_missing_property_types(self): for id in val[0]['$id']: print(f"{self.schemas[id]['$filename']}: {p}: missing type definition", file=sys.stderr) + def check_duplicate_property_types(self): + """ + Check for properties with multiple types consisting of a mixture of + integer scalar, array or matrix. These cannot be decoded reliably. + """ + for p, val in self.props.items(): + # Exclude some known problematic properties + if p in ['dma-masters']: + continue + + has_int = 0 + has_array = 0 + has_matrix = 0 + for v in val: + if v['type'] is None: + break + if re.match(r'u?int(8|16|32|64)$', v['type']): + has_int += 1 + elif re.match(r'u?int.+-array', v['type']): + has_array += 1 + elif re.match(r'u?int.+-matrix', v['type']): + has_matrix += 1 + min_size = v['dim'][0][0] * v['dim'][1][0] + elif v['type'] == 'phandle-array': + has_matrix += 1 + min_size = v['dim'][0][0] * v['dim'][1][0] + + if not ((has_int and (has_array or (has_matrix and min_size == 1))) or + (has_array and has_matrix)): + continue + + for v in val: + for sch_id in v['$id']: + print(f"{self.schemas[sch_id]['$filename']}: {p}: multiple incompatible types: {v['type']}", file=sys.stderr) + def make_property_type_cache(self): self.props, self.pat_props = get_prop_types(self.schemas) self.check_missing_property_types() + self.check_duplicate_property_types() for val in self.props.values(): for t in val: From bd5701e9b02c8189aa9f1feb121440c187320822 Mon Sep 17 00:00:00 2001 From: Mikael Gonella-Bolduc Date: Wed, 22 Jan 2025 10:25:44 -0500 Subject: [PATCH 502/505] schemas: property-units: Add the picoamp type Signed-off-by: Mikael Gonella-Bolduc --- dtschema/schemas/property-units.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dtschema/schemas/property-units.yaml b/dtschema/schemas/property-units.yaml index 3f70c526..a491f9c8 100644 --- a/dtschema/schemas/property-units.yaml +++ b/dtschema/schemas/property-units.yaml @@ -85,6 +85,9 @@ patternProperties: "-nanoamp$": $ref: types.yaml#/definitions/uint32-array description: nanoampere + "-picoamp$": + $ref: types.yaml#/definitions/uint32-array + description: picoampere "-microamp-hours$": $ref: types.yaml#/definitions/uint32-array description: microampere hour From 6f17cbd234a647f1cc9d2a64b5395a397d991a36 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 20 Jan 2025 09:01:01 +0100 Subject: [PATCH 503/505] schemas: gpio: Restrict HOG node name pattern to suffixes Bring some sort of uniformity by allowing only "-hog" suffix, not prefix, for gpio-hog node names. There is only one user of dropped prefix pattern in the Linux kernel DTS, being fixed in patch: https://lore.kernel.org/linux-devicetree/20250115204603.136997-1-krzysztof.kozlowski@linaro.org/ Signed-off-by: Krzysztof Kozlowski --- dtschema/schemas/gpio/gpio-hog.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtschema/schemas/gpio/gpio-hog.yaml b/dtschema/schemas/gpio/gpio-hog.yaml index b2836c30..e0060aca 100644 --- a/dtschema/schemas/gpio/gpio-hog.yaml +++ b/dtschema/schemas/gpio/gpio-hog.yaml @@ -20,7 +20,7 @@ select: properties: $nodename: - pattern: "^(hog-[0-9]+|.+-hog(-[0-9]+)?)$" + pattern: "-hog(-[0-9]+)?$" gpio-hog: $ref: /schemas/types.yaml#/definitions/flag From 644421d4650e2328a1e71f7fcda9453a4ece7da1 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 24 Jan 2025 16:48:56 +0200 Subject: [PATCH 504/505] schemas: root-node: add 'spectacles' chassis-type With the growing interest in the AR/VR/XR devices, it is expected that more and more devices will have the spectacles or eyeglasses-like form factor. Follow the devicetree specification change and add 'spectacles' as to list of possible values for the 'chassis-type' property. Signed-off-by: Dmitry Baryshkov --- dtschema/schemas/root-node.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/dtschema/schemas/root-node.yaml b/dtschema/schemas/root-node.yaml index b7f4c944..e088fd1f 100644 --- a/dtschema/schemas/root-node.yaml +++ b/dtschema/schemas/root-node.yaml @@ -28,6 +28,7 @@ properties: - watch - embedded - television + - spectacles "#address-cells": enum: [1, 2] "#size-cells": From ee08e89b245b43c3663fc26d4f93aba0a4c2e066 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 17 Nov 2022 13:43:18 -0600 Subject: [PATCH 505/505] schemas: gpio: Add descriptions Add descriptions from gpio.txt in the Linux kernel. Signed-off-by: Rob Herring --- dtschema/schemas/gpio/gpio.yaml | 44 ++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/dtschema/schemas/gpio/gpio.yaml b/dtschema/schemas/gpio/gpio.yaml index 9e2ad3c9..0b0ddf06 100644 --- a/dtschema/schemas/gpio/gpio.yaml +++ b/dtschema/schemas/gpio/gpio.yaml @@ -4,7 +4,19 @@ $id: http://devicetree.org/schemas/gpio/gpio.yaml# $schema: http://devicetree.org/meta-schemas/base.yaml# title: GPIO Controller Common Properties -description: Schema for GPIO devicetree bindings + +description: | + Every GPIO controller node must contain both an empty "gpio-controller" + property, and a #gpio-cells integer property, which indicates the number of + cells in a gpio-specifier. + + Some system-on-chips (SoCs) use the concept of GPIO banks. A GPIO bank is an + instance of a hardware IP core on a silicon die, usually exposed to the + programmer as a coherent range of I/O addresses. Usually each such bank is + exposed in the device tree as an individual gpio-controller node, reflecting + the fact that the hardware was synthesized by reusing the same IP block a few + times over. + maintainers: - Rob Herring @@ -17,13 +29,43 @@ properties: $ref: /schemas/types.yaml#/definitions/flag gpio-line-names: $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: > + An array of strings defining the names of the GPIO lines going out of the + GPIO controller. This name should be the most meaningful producer name for + the system, such as a rail name indicating the usage. Package names such + as pin name are discouraged: such lines have opaque names (since they are + by definition generic purpose) and such names are usually not very + helpful. For example "MMC-CD", "Red LED Vdd" and "ethernet reset" are + reasonable line names as they describe what the line is used for. "GPIO0" + is not a good name to give to a GPIO line. Placeholders are discouraged: + rather use the "" (blank string) if the use of the GPIO line is undefined + in your design. The names are assigned starting from line offset 0 from + left to right from the passed array. An incomplete array (where the number + of passed named are less than ngpios) will still be used up until the last + provided valid line index. + ngpios: $ref: /schemas/types.yaml#/definitions/uint32 + description: > + Indicates the number of in-use slots of available slots for GPIOs. The + typical example is something like this: the hardware register is 32 bits + wide, but only 18 of the bits have a physical counterpart. The driver is + generally written so that all 32 bits can be used, but the IP block is + reused in a lot of designs, some using all 32 bits, some using 18 and some + using 12. In this case, setting "ngpios = <18>;" informs the driver that + only the first 18 GPIOs, at local offset 0 .. 17, are in use. If these + GPIOs do not happen to be the first N GPIOs at offset 0...N-1, an + additional set of tuples is needed to specify which GPIOs are unusable, + with the gpio-reserved-ranges binding. + gpio-reserved-ranges: $ref: /schemas/types.yaml#/definitions/uint32-matrix items: minItems: 2 maxItems: 2 + description: + Indicates the start and size of the GPIOs that can't be used. + gpio-ranges: $ref: /schemas/types.yaml#/definitions/phandle-array items: