diff mbox series

[RFC] dt-bindings: add a jsonschema binding example

Message ID 20180418222905.10414-1-robh@kernel.org
State RFC, archived
Headers show
Series [RFC] dt-bindings: add a jsonschema binding example | expand

Commit Message

Rob Herring April 18, 2018, 10:29 p.m. UTC
The current DT binding documentation format of freeform text is painful
to write, review, validate and maintain.

This is just an example of what a binding in the schema format looks
like. It's using jsonschema vocabulary in a YAML encoded document. Using
jsonschema gives us access to existing tooling. A YAML encoding gives us
something easy to edit.

This example is just the tip of the iceberg, but it the part most
developers writing bindings will interact with. Backing all this up
are meta-schema (to validate the binding schemas), some DT core schema,
YAML encoded DT output with dtc, and a small number of python scripts to
run validation. The gory details including how to run end-to-end
validation can be found here:

https://www.spinics.net/lists/devicetree-spec/msg00649.html

Signed-off-by: Rob Herring <robh@kernel.org>
---
Cc list,
You all review and/or write lots of binding documents. I'd like some feedback
on the format.

Thanks,
Rob

 .../devicetree/bindings/example-schema.yaml        | 149 +++++++++++++++++++++
 1 file changed, 149 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/example-schema.yaml

--
2.14.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Stephen Boyd April 20, 2018, 4:47 p.m. UTC | #1
Quoting Rob Herring (2018-04-18 15:29:05)
> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
> new file mode 100644
> index 000000000000..fe0a3bd1668e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/example-schema.yaml
> @@ -0,0 +1,149 @@
> +# SPDX-License-Identifier: BSD-2-Clause
> +# Copyright 2018 Linaro Ltd.
> +%YAML 1.2
> +---
> +# All the top-level keys are standard json-schema keywords except for
> +# '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#"
> +
> +# Only 1 version supported for now
> +version: 1
> +
> +title: An example schema annotated with jsonschema details
> +
> +maintainers:
> +  - Rob Herring <robh@kernel.org>
> +
> +description: |
> +  A more detailed multi-line description of the binding.
> +
> +  Details about the hardware device and any links to datasheets can go here.
> +
> +  The end of the description is marked by indentation less than the first line
> +  in the description.
> +
> +select: false
> +  # 'select' is a schema applied to a DT node to determine if this binding
> +  # schema should be applied to the node. It is optional and by default the
> +  # possible compatible strings are extracted and used to match.

Can we get a concrete example here?

> +
> +properties:
[...]
> +
> +  interrupts:
> +    # Either 1 or 2 interrupts can be present
> +    minItems: 1
> +    maxItems: 2
> +    items:
> +      - description: tx or combined interrupt
> +      - description: rx interrupt
> +
> +    description: |

The '|' is needed to make yaml happy?

> +      A variable number of interrupts warrants a description of what conditions
> +      affect the number of interrupts. Otherwise, descriptions on standard
> +      properties are not necessary.
> +
> +  interrupt-names:
> +    # minItems must be specified here because the default would be 2
> +    minItems: 1
> +    items:
> +      - const: "tx irq"
> +      - const: "rx irq"
> +
> +  # Property names starting with '#' must be quoted
> +  '#interrupt-cells':
> +    # A simple case where the value must always be '2'.
> +    # The core schema handles that this must be a single integer.
> +    const: 2
> +
> +  interrupt-controller: {}

Does '{}' mean nothing to see here?

> +    # The core checks this is a boolean, so just have to list it here to be
> +    # valid for this binding.
> +
> +  clock-frequency:
> +    # The type is set in the core schema. Per device schema only need to set
> +    # constraints on the possible values.
> +    minimum: 100
> +    maximum: 400000
> +    # The value that should be used if the property is not present
> +    default: 200
> +

The 'default' field is neat. I look forward to the compiler using the
schema to insert defaults into the dtb if the properties aren't present
in the input file.

> +  foo-gpios:
> +    maxItems: 1
> +    description: A connection of the 'foo' gpio line.
> +
> +  vendor,int-property:
> +    description: Vendor specific properties must have a description
> +    type: integer # A type is also required
> +    enum: [2, 4, 6, 8, 10]
> +
> +  vendor,bool-property:
> +    description: Vendor specific properties must have a description
> +    type: boolean
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - interrupt-controller

Can the required or optional parts go under each property instead of
having a different section? Or does that make the schema parser
difficult to implement? It may also make sense to negate this and
specify only the optional properties, or to require both optional and
required lists to make things more explicit at the cost of some
verbosity.

> +
> +examples:
> +  - |
> +    /{

Is the first slash required here?

> +          compatible = "vendor,soc4-ip", "vendor,soc1-ip";
> +          reg = <0x1000 0x80>,
> +                <0x3000 0x80>;
> +          reg-names = "core", "aux";
> +          interrupts = <10>;
> +          interrupt-controller;
> +    };
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown April 20, 2018, 4:59 p.m. UTC | #2
On Wed, Apr 18, 2018 at 05:29:05PM -0500, Rob Herring wrote:
> The current DT binding documentation format of freeform text is painful
> to write, review, validate and maintain.
> 
> This is just an example of what a binding in the schema format looks
> like. It's using jsonschema vocabulary in a YAML encoded document. Using
> jsonschema gives us access to existing tooling. A YAML encoding gives us
> something easy to edit.

It'd be useful to see some examples of how things like including by
reference other schema work.  It feels like something we should be able
to use more in a schema based thing but perhaps that's not viable with
realistic tooling.  In general this looks OK, especially with all the
meta comments about the language stripped out.

> +    description: |
> +      A variable number of interrupts warrants a description of what conditions

Like Stephen said the | looks odd.

> +  interrupt-names:
> +    # minItems must be specified here because the default would be 2
> +    minItems: 1
> +    items:
> +      - const: "tx irq"
> +      - const: "rx irq"

Any way to relate this to the interrupts property in the schema
language (eg, must have the less or equal number of elements)?

> +  # Property names starting with '#' must be quoted

That's awkward :/  Perhaps just by convention quote all property names
for simplicity?
Rob Herring April 20, 2018, 6:15 p.m. UTC | #3
On Fri, Apr 20, 2018 at 11:47 AM, Stephen Boyd <sboyd@kernel.org> wrote:
> Quoting Rob Herring (2018-04-18 15:29:05)
>> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
>> new file mode 100644
>> index 000000000000..fe0a3bd1668e
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/example-schema.yaml
>> @@ -0,0 +1,149 @@
>> +# SPDX-License-Identifier: BSD-2-Clause
>> +# Copyright 2018 Linaro Ltd.
>> +%YAML 1.2
>> +---
>> +# All the top-level keys are standard json-schema keywords except for
>> +# '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#"
>> +
>> +# Only 1 version supported for now
>> +version: 1
>> +
>> +title: An example schema annotated with jsonschema details
>> +
>> +maintainers:
>> +  - Rob Herring <robh@kernel.org>
>> +
>> +description: |
>> +  A more detailed multi-line description of the binding.
>> +
>> +  Details about the hardware device and any links to datasheets can go here.
>> +
>> +  The end of the description is marked by indentation less than the first line
>> +  in the description.
>> +
>> +select: false
>> +  # 'select' is a schema applied to a DT node to determine if this binding
>> +  # schema should be applied to the node. It is optional and by default the
>> +  # possible compatible strings are extracted and used to match.
>
> Can we get a concrete example here?

select: true

:) Which is apply to every node.

A better one is from the memory node schema ('$nodename' gets added :

select:
  required: ["$nodename"]
  properties:
    $nodename:
      oneOf:
        - pattern: "^memory@[0-9a-f]*"
        - const: "memory" # 'memory' only allowed for selecting


I expect the vast majority of device bindings will not use select at
all and rely on compatible string matching.

>> +
>> +properties:
> [...]
>> +
>> +  interrupts:
>> +    # Either 1 or 2 interrupts can be present
>> +    minItems: 1
>> +    maxItems: 2
>> +    items:
>> +      - description: tx or combined interrupt
>> +      - description: rx interrupt
>> +
>> +    description: |
>
> The '|' is needed to make yaml happy?

Yes, this is simply how you do literal text blocks in yaml.

We don't really need for this one really, but for the top-level
'description' we do. The long term intent is 'description' would be
written in sphinx/rst and can be extracted into the DT spec (for
common bindings). Grant has experimented with that some.

>> +      A variable number of interrupts warrants a description of what conditions
>> +      affect the number of interrupts. Otherwise, descriptions on standard
>> +      properties are not necessary.
>> +
>> +  interrupt-names:
>> +    # minItems must be specified here because the default would be 2
>> +    minItems: 1
>> +    items:
>> +      - const: "tx irq"
>> +      - const: "rx irq"
>> +
>> +  # Property names starting with '#' must be quoted
>> +  '#interrupt-cells':
>> +    # A simple case where the value must always be '2'.
>> +    # The core schema handles that this must be a single integer.
>> +    const: 2
>> +
>> +  interrupt-controller: {}
>
> Does '{}' mean nothing to see here?

Yes. It's just an empty schema that's always valid.

>> +    # The core checks this is a boolean, so just have to list it here to be
>> +    # valid for this binding.
>> +
>> +  clock-frequency:
>> +    # The type is set in the core schema. Per device schema only need to set
>> +    # constraints on the possible values.
>> +    minimum: 100
>> +    maximum: 400000
>> +    # The value that should be used if the property is not present
>> +    default: 200
>> +
>
> The 'default' field is neat. I look forward to the compiler using the
> schema to insert defaults into the dtb if the properties aren't present
> in the input file.

That wasn't really my intention, but it's what the OS should use if
property is not present. But at least for required properties, we
could certainly do as you suggest.

>> +  foo-gpios:
>> +    maxItems: 1
>> +    description: A connection of the 'foo' gpio line.
>> +
>> +  vendor,int-property:
>> +    description: Vendor specific properties must have a description
>> +    type: integer # A type is also required
>> +    enum: [2, 4, 6, 8, 10]
>> +
>> +  vendor,bool-property:
>> +    description: Vendor specific properties must have a description
>> +    type: boolean
>> +
>> +required:
>> +  - compatible
>> +  - reg
>> +  - interrupts
>> +  - interrupt-controller
>
> Can the required or optional parts go under each property instead of
> having a different section?

No, because then it is not json-schema language.

> Or does that make the schema parser
> difficult to implement?

Yes, because then we have to implement a schema parser.

> It may also make sense to negate this and
> specify only the optional properties, or to require both optional and
> required lists to make things more explicit at the cost of some
> verbosity.
>
>> +
>> +examples:
>> +  - |
>> +    /{
>
> Is the first slash required here?

No, just leftover from being the root node in the example.


Thanks for taking a look.

>> +          compatible = "vendor,soc4-ip", "vendor,soc1-ip";
>> +          reg = <0x1000 0x80>,
>> +                <0x3000 0x80>;
>> +          reg-names = "core", "aux";
>> +          interrupts = <10>;
>> +          interrupt-controller;
>> +    };
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rob Herring April 20, 2018, 6:47 p.m. UTC | #4
On Fri, Apr 20, 2018 at 11:59 AM, Mark Brown <broonie@kernel.org> wrote:
> On Wed, Apr 18, 2018 at 05:29:05PM -0500, Rob Herring wrote:
>> The current DT binding documentation format of freeform text is painful
>> to write, review, validate and maintain.
>>
>> This is just an example of what a binding in the schema format looks
>> like. It's using jsonschema vocabulary in a YAML encoded document. Using
>> jsonschema gives us access to existing tooling. A YAML encoding gives us
>> something easy to edit.
>
> It'd be useful to see some examples of how things like including by
> reference other schema work.  It feels like something we should be able
> to use more in a schema based thing but perhaps that's not viable with
> realistic tooling.  In general this looks OK, especially with all the
> meta comments about the language stripped out.

There are several examples in the meta-schema and some of the core
schema as references are used there quite a bit. It gets quite fun to
follow with recursion. :)

I think the need for references in device bindings should be pretty
minimal. We'd probably mainly need references for some vendor specific
properties which will need to reference some of our compound types. So
we'd have something like this:

vendor,a-string-array-prop:
  $ref: "dt-core.yaml#/definitions/proptypes/stringarray"

For common bindings, we don't have to reference them in device
bindings (which should save lots of boilerplate). We can select and
apply them based on presence of properties and that happens
independent of the device binding. The device binding only needs
define what the common binding cannot which is typically how many
elements and what are they.

>
>> +    description: |
>> +      A variable number of interrupts warrants a description of what conditions
>
> Like Stephen said the | looks odd.

That's just how literal blocks in yaml are done.

>> +  interrupt-names:
>> +    # minItems must be specified here because the default would be 2
>> +    minItems: 1
>> +    items:
>> +      - const: "tx irq"
>> +      - const: "rx irq"
>
> Any way to relate this to the interrupts property in the schema
> language (eg, must have the less or equal number of elements)?

I've wanted something like that, but there isn't any way that I've
come up with. Generally, the "jsonschema way" is each schema is
supposed to be independent of each other. There's some discussion
about adding data dependent schema which might help in this case.

>
>> +  # Property names starting with '#' must be quoted
>
> That's awkward :/  Perhaps just by convention quote all property names
> for simplicity?

Yes, perhaps we should. I have a formatting tool, I'll look into
whether i can make it do that.

Thanks for taking a look.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Frank Rowand April 20, 2018, 7:53 p.m. UTC | #5
On 04/20/18 11:15, Rob Herring wrote:
> On Fri, Apr 20, 2018 at 11:47 AM, Stephen Boyd <sboyd@kernel.org> wrote:
>> Quoting Rob Herring (2018-04-18 15:29:05)
>>> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
>>> new file mode 100644
>>> index 000000000000..fe0a3bd1668e
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/example-schema.yaml
>>> @@ -0,0 +1,149 @@
>>> +# SPDX-License-Identifier: BSD-2-Clause
>>> +# Copyright 2018 Linaro Ltd.
>>> +%YAML 1.2
>>> +---
>>> +# All the top-level keys are standard json-schema keywords except for
>>> +# '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#"
>>> +
>>> +# Only 1 version supported for now
>>> +version: 1
>>> +
>>> +title: An example schema annotated with jsonschema details
>>> +
>>> +maintainers:
>>> +  - Rob Herring <robh@kernel.org>
>>> +
>>> +description: |
>>> +  A more detailed multi-line description of the binding.
>>> +
>>> +  Details about the hardware device and any links to datasheets can go here.
>>> +
>>> +  The end of the description is marked by indentation less than the first line
>>> +  in the description.
>>> +
>>> +select: false
>>> +  # 'select' is a schema applied to a DT node to determine if this binding
>>> +  # schema should be applied to the node. It is optional and by default the
>>> +  # possible compatible strings are extracted and used to match.
>>
>> Can we get a concrete example here?
> 
> select: true
> 
> :) Which is apply to every node.
> 
> A better one is from the memory node schema ('$nodename' gets added :
> 
> select:
>   required: ["$nodename"]
>   properties:
>     $nodename:
>       oneOf:
>         - pattern: "^memory@[0-9a-f]*"
>         - const: "memory" # 'memory' only allowed for selecting
> 
> 
> I expect the vast majority of device bindings will not use select at
> all and rely on compatible string matching.
> 
>>> +
>>> +properties:
>> [...]
>>> +
>>> +  interrupts:
>>> +    # Either 1 or 2 interrupts can be present
>>> +    minItems: 1
>>> +    maxItems: 2
>>> +    items:
>>> +      - description: tx or combined interrupt
>>> +      - description: rx interrupt
>>> +
>>> +    description: |
>>
>> The '|' is needed to make yaml happy?
> 
> Yes, this is simply how you do literal text blocks in yaml.
> 
> We don't really need for this one really, but for the top-level
> 'description' we do. The long term intent is 'description' would be
> written in sphinx/rst and can be extracted into the DT spec (for
> common bindings). Grant has experimented with that some.
> 
>>> +      A variable number of interrupts warrants a description of what conditions
>>> +      affect the number of interrupts. Otherwise, descriptions on standard
>>> +      properties are not necessary.
>>> +
>>> +  interrupt-names:
>>> +    # minItems must be specified here because the default would be 2
>>> +    minItems: 1
>>> +    items:
>>> +      - const: "tx irq"
>>> +      - const: "rx irq"
>>> +
>>> +  # Property names starting with '#' must be quoted
>>> +  '#interrupt-cells':
>>> +    # A simple case where the value must always be '2'.
>>> +    # The core schema handles that this must be a single integer.
>>> +    const: 2
>>> +
>>> +  interrupt-controller: {}
>>
>> Does '{}' mean nothing to see here?
> 
> Yes. It's just an empty schema that's always valid.
> 
>>> +    # The core checks this is a boolean, so just have to list it here to be
>>> +    # valid for this binding.
>>> +
>>> +  clock-frequency:
>>> +    # The type is set in the core schema. Per device schema only need to set
>>> +    # constraints on the possible values.
>>> +    minimum: 100
>>> +    maximum: 400000
>>> +    # The value that should be used if the property is not present
>>> +    default: 200
>>> +
>>
>> The 'default' field is neat. I look forward to the compiler using the
>> schema to insert defaults into the dtb if the properties aren't present
>> in the input file.
> 
> That wasn't really my intention, but it's what the OS should use if
> property is not present. But at least for required properties, we
> could certainly do as you suggest.

I understand the thought of 'neat', but it would also add yet one more
layer to the "how did this property get into my dtb?" stew.

But more importantly, if this becomes a required part of the kernel
build process, is it adding a new required tool (python)?  (Or is
python already required?)  There is resistance to adding new tools.

-Frank


>>> +  foo-gpios:
>>> +    maxItems: 1
>>> +    description: A connection of the 'foo' gpio line.
>>> +
>>> +  vendor,int-property:
>>> +    description: Vendor specific properties must have a description
>>> +    type: integer # A type is also required
>>> +    enum: [2, 4, 6, 8, 10]
>>> +
>>> +  vendor,bool-property:
>>> +    description: Vendor specific properties must have a description
>>> +    type: boolean
>>> +
>>> +required:
>>> +  - compatible
>>> +  - reg
>>> +  - interrupts
>>> +  - interrupt-controller
>>
>> Can the required or optional parts go under each property instead of
>> having a different section?
> 
> No, because then it is not json-schema language.
> 
>> Or does that make the schema parser
>> difficult to implement?
> 
> Yes, because then we have to implement a schema parser.
> 
>> It may also make sense to negate this and
>> specify only the optional properties, or to require both optional and
>> required lists to make things more explicit at the cost of some
>> verbosity.
>>
>>> +
>>> +examples:
>>> +  - |
>>> +    /{
>>
>> Is the first slash required here?
> 
> No, just leftover from being the root node in the example.
> 
> 
> Thanks for taking a look.
> 
>>> +          compatible = "vendor,soc4-ip", "vendor,soc1-ip";
>>> +          reg = <0x1000 0x80>,
>>> +                <0x3000 0x80>;
>>> +          reg-names = "core", "aux";
>>> +          interrupts = <10>;
>>> +          interrupt-controller;
>>> +    };
> 

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Frank Rowand April 20, 2018, 9 p.m. UTC | #6
Hi Rob,

Thanks for the example.  It was a good starting tutorial of sorts for me
to understand the format a bit.


On 04/18/18 15:29, Rob Herring wrote:
> The current DT binding documentation format of freeform text is painful
> to write, review, validate and maintain.
> 
> This is just an example of what a binding in the schema format looks
> like. It's using jsonschema vocabulary in a YAML encoded document. Using
> jsonschema gives us access to existing tooling. A YAML encoding gives us
> something easy to edit.
> 
> This example is just the tip of the iceberg, but it the part most
> developers writing bindings will interact with. Backing all this up
> are meta-schema (to validate the binding schemas), some DT core schema,
> YAML encoded DT output with dtc, and a small number of python scripts to
> run validation. The gory details including how to run end-to-end
> validation can be found here:
> 
> https://www.spinics.net/lists/devicetree-spec/msg00649.html
> 
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
> Cc list,
> You all review and/or write lots of binding documents. I'd like some feedback
> on the format.
> 
> Thanks,
> Rob
> 
>  .../devicetree/bindings/example-schema.yaml        | 149 +++++++++++++++++++++
>  1 file changed, 149 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/example-schema.yaml
> 
> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
> new file mode 100644
> index 000000000000..fe0a3bd1668e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/example-schema.yaml

I'm guessing by the path name that this is in the Linux kernel source tree.


> @@ -0,0 +1,149 @@
> +# SPDX-License-Identifier: BSD-2-Clause

If in the Linux kernel source tree, then allow gpl-v2 as a possible license.


> +# Copyright 2018 Linaro Ltd.
> +%YAML 1.2
> +---
> +# All the top-level keys are standard json-schema keywords except for
> +# 'maintainers' and 'select'
> +
> +# $id is a unique idenifier based on the filename

                     ^^^^^^^^^  identifier

> +$id: "http://devicetree.org/schemas/example-schema.yaml#"

Does this imply that all schemas will be at devicetree.org instead
of in the Linux kernel source tree?  This would be counter to my
earlier guess about where this patch is applied.


> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"

How is $schema used?  Is it accessed across the network?

> +
> +# Only 1 version supported for now
> +version: 1
> +
> +title: An example schema annotated with jsonschema details
> +
> +maintainers:
> +  - Rob Herring <robh@kernel.org>
> +
> +description: |
> +  A more detailed multi-line description of the binding.
> +
> +  Details about the hardware device and any links to datasheets can go here.
> +
> +  The end of the description is marked by indentation less than the first line
> +  in the description.
> +
> +select: false
> +  # 'select' is a schema applied to a DT node to determine if this binding
> +  # schema should be applied to the node. It is optional and by default the
> +  # possible compatible strings are extracted and used to match.

My first reaction was that 'node' should somehow be included in the name
of 'select'.  But my second thought was that maybe 'node' is implied,
because every schema file describes a single node???  This is where my
lack of knowledge kicks in - I'll go read stuff in your yaml-bindings
repo to get a better background...


> +
> +properties:
> +  # A dictionary of DT properties for this binding schema
> +  compatible:
> +    # More complicated schema can use oneOf (XOR), anyOf (OR), or allOf (AND)
> +    # to handle different conditions.
> +    # In this case, it's needed to handle a variable number of values as there
> +    # isn't another way to express a constraint of the last string value.
> +    # The boolean schema must be a list of schemas.
> +    oneOf:
> +      - items:
> +          # items is a list of possible values for the property. The number of
> +          # values is determined by the number of elements in the list.
> +          # Order in lists is significant, order in dicts is not
> +          # Must be one of the 1st enums followed by the 2nd enum
> +          #
> +          # Each element in items should be 'enum' or 'const'
> +          - enum:
> +              - vendor,soc4-ip
> +              - vendor,soc3-ip
> +              - vendor,soc2-ip
> +          - enum:
> +              - vendor,soc1-ip
> +        # additionalItems being false is implied
> +        # minItems/maxItems equal to 2 is implied
> +      - items:
> +          # 'const' is just a special case of an enum with a single possible value
> +          - const: vendor,soc1-ip

I'm using this as an example of a concept, not to pick on this one specific
instance.

One of my concerns with YAML has been the rich, flexible syntax available.  To
a YAML expert, this is a very useful feature.  To someone who does not use YAML
and will not use it for anything other than binding schemas, this adds more
complexity.

What I have heard some people say in the validation discussions is that the
allowed YAML syntax for binding schemas would be limited to one (or a very
small number) of the possible YAML alternative syntaxes for use in the
bindings.  Will there be a document describing such a limitation on
alternate syntaxes?

(This example file provides a good example of a single syntax style, but does
not preclude other equivalent syntax.)

Getting back to the specific example of 'const', it is a less verbose way of
specifying a single value enum, and I think it looks cleaner and more
readable.  But it is also a case of adding more complexity for someone who
does not otherwise use YAML.  I would using the more verbose syntax of
enum even for a single possible value.


> +
> +  reg:
> +    # The description of each element defines the order and implicitly defines
> +    # the number of reg entries
> +    items:
> +      - description: core registers
> +      - description: aux registers
> +    # minItems/maxItems equal to 2 is implied
> +
> +  reg-names:
> +    # The core schema enforces this is a string array
> +    items:
> +      - const: core
> +      - const: aux
> +
> +  clocks:
> +    # Only a single entry, so just need to set the max number of items.

       # More restrictions are provided in meta-schemas/clocks.yaml


> +    maxItems: 1
> +
> +  clock-names:
> +    items:
> +      - const: bus
> +
> +  interrupts:
> +    # Either 1 or 2 interrupts can be present
> +    minItems: 1
> +    maxItems: 2
> +    items:
> +      - description: tx or combined interrupt
> +      - description: rx interrupt
> +
> +    description: |
> +      A variable number of interrupts warrants a description of what conditions
> +      affect the number of interrupts. Otherwise, descriptions on standard
> +      properties are not necessary.
> +
> +  interrupt-names:
> +    # minItems must be specified here because the default would be 2
> +    minItems: 1

Why the difference between the interrupts property and the interrupt-names
property (specifying maxItems for interrupt, but not interrupt-names)?

Others have already commented on a desire to have a way to specify that
number of interrupts should match number of interrupt-names.


> +    items:
> +      - const: "tx irq"
> +      - const: "rx irq"
> +
> +  # Property names starting with '#' must be quoted
> +  '#interrupt-cells':
> +    # A simple case where the value must always be '2'.
> +    # The core schema handles that this must be a single integer.
> +    const: 2
> +
> +  interrupt-controller: {}
> +    # The core checks this is a boolean, so just have to list it here to be
> +    # valid for this binding.
> +
> +  clock-frequency:
> +    # The type is set in the core schema. Per device schema only need to set
> +    # constraints on the possible values.
> +    minimum: 100
> +    maximum: 400000
> +    # The value that should be used if the property is not present
> +    default: 200

This is confusing to me.  (Beyond the discussion of this in Stephen Boyd's
reply...)  My naive reading of this is that the default is the value that
the driver should implement if the property is missing, which is unrelated
to the concept of validating a dts file.


> +
> +  foo-gpios:
> +    maxItems: 1
> +    description: A connection of the 'foo' gpio line.
> +
> +  vendor,int-property:
> +    description: Vendor specific properties must have a description
> +    type: integer # A type is also required
> +    enum: [2, 4, 6, 8, 10]
> +
> +  vendor,bool-property:
> +    description: Vendor specific properties must have a description
> +    type: boolean
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - interrupt-controller
> +
> +examples:
> +  - |
> +    /{
> +          compatible = "vendor,soc4-ip", "vendor,soc1-ip";
> +          reg = <0x1000 0x80>,
> +                <0x3000 0x80>;
> +          reg-names = "core", "aux";
> +          interrupts = <10>;
> +          interrupt-controller;
> +    };
> --
> 2.14.1
> 

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bjorn Andersson April 20, 2018, 9:47 p.m. UTC | #7
On Wed 18 Apr 15:29 PDT 2018, Rob Herring wrote:

> The current DT binding documentation format of freeform text is painful
> to write, review, validate and maintain.
> 
> This is just an example of what a binding in the schema format looks
> like. It's using jsonschema vocabulary in a YAML encoded document. Using
> jsonschema gives us access to existing tooling. A YAML encoding gives us
> something easy to edit.
> 
> This example is just the tip of the iceberg, but it the part most
> developers writing bindings will interact with. Backing all this up
> are meta-schema (to validate the binding schemas), some DT core schema,
> YAML encoded DT output with dtc, and a small number of python scripts to
> run validation. The gory details including how to run end-to-end
> validation can be found here:
> 
> https://www.spinics.net/lists/devicetree-spec/msg00649.html
> 
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
> Cc list,
> You all review and/or write lots of binding documents. I'd like some feedback
> on the format.
> 

I really like the idea of formalizing the binding document format and
the ability of validating a dtb is really nice.

> Thanks,
> Rob
> 
>  .../devicetree/bindings/example-schema.yaml        | 149 +++++++++++++++++++++
>  1 file changed, 149 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/example-schema.yaml
> 
> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
[..]
> +  reg:
> +    # The description of each element defines the order and implicitly defines
> +    # the number of reg entries
> +    items:
> +      - description: core registers
> +      - description: aux registers
> +    # minItems/maxItems equal to 2 is implied

I assume that a reg with variable number of entries would have
"description" for all of them and then a minItems that matches the
required ones and maxItems matching all of them?

> +
> +  reg-names:
> +    # The core schema enforces this is a string array
> +    items:
> +      - const: core
> +      - const: aux

I presume validation based on this should check that there's equal
number of entries in reg-names as there where in reg. Should this
relationship be described in the schema?

[..]
> +  interrupts:
> +    # Either 1 or 2 interrupts can be present
> +    minItems: 1
> +    maxItems: 2
> +    items:
> +      - description: tx or combined interrupt
> +      - description: rx interrupt
> +
> +    description: |
> +      A variable number of interrupts warrants a description of what conditions
> +      affect the number of interrupts. Otherwise, descriptions on standard
> +      properties are not necessary.

For validation purposes this could be interrupts with interrupt-parents
or a interrupts-extend, a fact that we probably don't want to duplicate
in every definition?

Perhaps we should just do like you did here and define the "interrupts"
and then in the validation tool - where we need to encode the logic
behind this anyways - we support the different variants.

> +
> +  interrupt-names:
> +    # minItems must be specified here because the default would be 2
> +    minItems: 1

As with reg-names, it would be good to have the validator warn if this
is not the same number of items as entries in "interrupts".

> +    items:
> +      - const: "tx irq"
> +      - const: "rx irq"
> +
> +  # Property names starting with '#' must be quoted
> +  '#interrupt-cells':
> +    # A simple case where the value must always be '2'.
> +    # The core schema handles that this must be a single integer.
> +    const: 2

If this is specified then interrupt-controller should also be given, or
vise versa. How would we describe that?

> +
> +  interrupt-controller: {}
> +    # The core checks this is a boolean, so just have to list it here to be
> +    # valid for this binding.
> +

Regards,
Bjorn
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Boyd April 20, 2018, 11:41 p.m. UTC | #8
Quoting Rob Herring (2018-04-20 11:15:04)
> On Fri, Apr 20, 2018 at 11:47 AM, Stephen Boyd <sboyd@kernel.org> wrote:
> > Quoting Rob Herring (2018-04-18 15:29:05)
> >> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
> >> new file mode 100644
> >> index 000000000000..fe0a3bd1668e
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/example-schema.yaml
> >> @@ -0,0 +1,149 @@
> >> +
> >> +  The end of the description is marked by indentation less than the first line
> >> +  in the description.
> >> +
> >> +select: false
> >> +  # 'select' is a schema applied to a DT node to determine if this binding
> >> +  # schema should be applied to the node. It is optional and by default the
> >> +  # possible compatible strings are extracted and used to match.
> >
> > Can we get a concrete example here?
> 
> select: true
> 
> :) Which is apply to every node.
> 
> A better one is from the memory node schema ('$nodename' gets added :
> 
> select:
>   required: ["$nodename"]
>   properties:
>     $nodename:
>       oneOf:
>         - pattern: "^memory@[0-9a-f]*"
>         - const: "memory" # 'memory' only allowed for selecting
> 
> 
> I expect the vast majority of device bindings will not use select at
> all and rely on compatible string matching.

Thanks! I was looking to see how the select syntax would work and this
shows one example nicely. I suppose another way would be to show how a
compatible string would be matched through select, even though it's
redundant.

Is there a way we can enforce node names through the schema too? For
example to enforce that a clock controller is called 'clock-controller'
or a spi master is called 'spi'.

> 
> >> +
> >> +properties:
> > [...]
> >> +
> >> +  interrupts:
> >> +    # Either 1 or 2 interrupts can be present
> >> +    minItems: 1
> >> +    maxItems: 2
> >> +    items:
> >> +      - description: tx or combined interrupt
> >> +      - description: rx interrupt
> >> +
> >> +    description: |
> >
> > The '|' is needed to make yaml happy?
> 
> Yes, this is simply how you do literal text blocks in yaml.
> 
> We don't really need for this one really, but for the top-level
> 'description' we do. The long term intent is 'description' would be
> written in sphinx/rst and can be extracted into the DT spec (for
> common bindings). Grant has experimented with that some.

Ok. That sounds cool. Then we could embed links to datasheets and SVGs
too.

> 
> >> +      A variable number of interrupts warrants a description of what conditions
> >> +      affect the number of interrupts. Otherwise, descriptions on standard
> >> +      properties are not necessary.
> >> +
> >> +  interrupt-names:
> >> +    # minItems must be specified here because the default would be 2
> >> +    minItems: 1
> >> +    items:
> >> +      - const: "tx irq"
> >> +      - const: "rx irq"
> >> +
> >> +  # Property names starting with '#' must be quoted
> >> +  '#interrupt-cells':
> >> +    # A simple case where the value must always be '2'.
> >> +    # The core schema handles that this must be a single integer.
> >> +    const: 2
> >> +
> >> +  interrupt-controller: {}
> >
> > Does '{}' mean nothing to see here?
> 
> Yes. It's just an empty schema that's always valid.

Could we include another schema to indicate that this is an interrupt
controller? I'm sort of asking for multi-schema inheritance.

> 
> >> +  foo-gpios:
> >> +    maxItems: 1
> >> +    description: A connection of the 'foo' gpio line.
> >> +
> >> +  vendor,int-property:
> >> +    description: Vendor specific properties must have a description
> >> +    type: integer # A type is also required
> >> +    enum: [2, 4, 6, 8, 10]
> >> +
> >> +  vendor,bool-property:
> >> +    description: Vendor specific properties must have a description
> >> +    type: boolean
> >> +
> >> +required:
> >> +  - compatible
> >> +  - reg
> >> +  - interrupts
> >> +  - interrupt-controller
> >
> > Can the required or optional parts go under each property instead of
> > having a different section?
> 
> No, because then it is not json-schema language.
> 
> > Or does that make the schema parser
> > difficult to implement?
> 
> Yes, because then we have to implement a schema parser.

:/
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rob Herring April 21, 2018, 1:28 a.m. UTC | #9
On Fri, Apr 20, 2018 at 4:00 PM, Frank Rowand <frowand.list@gmail.com> wrote:
> Hi Rob,
>
> Thanks for the example.  It was a good starting tutorial of sorts for me
> to understand the format a bit.
>
>
> On 04/18/18 15:29, Rob Herring wrote:
>> The current DT binding documentation format of freeform text is painful
>> to write, review, validate and maintain.
>>
>> This is just an example of what a binding in the schema format looks
>> like. It's using jsonschema vocabulary in a YAML encoded document. Using
>> jsonschema gives us access to existing tooling. A YAML encoding gives us
>> something easy to edit.
>>
>> This example is just the tip of the iceberg, but it the part most
>> developers writing bindings will interact with. Backing all this up
>> are meta-schema (to validate the binding schemas), some DT core schema,
>> YAML encoded DT output with dtc, and a small number of python scripts to
>> run validation. The gory details including how to run end-to-end
>> validation can be found here:
>>
>> https://www.spinics.net/lists/devicetree-spec/msg00649.html
>>
>> Signed-off-by: Rob Herring <robh@kernel.org>
>> ---
>> Cc list,
>> You all review and/or write lots of binding documents. I'd like some feedback
>> on the format.
>>
>> Thanks,
>> Rob
>>
>>  .../devicetree/bindings/example-schema.yaml        | 149 +++++++++++++++++++++
>>  1 file changed, 149 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/example-schema.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
>> new file mode 100644
>> index 000000000000..fe0a3bd1668e
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/example-schema.yaml
>
> I'm guessing by the path name that this is in the Linux kernel source tree.

Yes, well, my kernel tree. Most of the work still lives here:

https://github.com/robherring/yaml-bindings/

>> @@ -0,0 +1,149 @@
>> +# SPDX-License-Identifier: BSD-2-Clause
>
> If in the Linux kernel source tree, then allow gpl-v2 as a possible license.

Why? BSD is compatible. The license of the above repo is all BSD.

Of course there's all the existing docs which default to GPLv2 and
we'll probably have to maintain that.

>> +# Copyright 2018 Linaro Ltd.
>> +%YAML 1.2
>> +---
>> +# All the top-level keys are standard json-schema keywords except for
>> +# 'maintainers' and 'select'
>> +
>> +# $id is a unique idenifier based on the filename
>
>                      ^^^^^^^^^  identifier
>
>> +$id: "http://devicetree.org/schemas/example-schema.yaml#"
>
> Does this imply that all schemas will be at devicetree.org instead
> of in the Linux kernel source tree?  This would be counter to my
> earlier guess about where this patch is applied.

They could be, but not necessarily. This is just convention in
jsonschema is the best I understand it.

I don't think you'd want validation to require an internet connection.
For the base meta-schema, for example, it does exist at
http://json-schema.org/draft-06/schema, but that's also distributed
with implementations of jsonschema validators.

A large part (not that any part is large) of the tools Grant and I
have written is doing the cross reference resolution of files which
uses the $id field.


>> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
>
> How is $schema used?

Tells the validator what meta-schema this schema follows. Typically
you see draft04 or draft06 here if you haven't written a meta-schema.

> Is it accessed across the network?

Could be, but generally no.


>> +
>> +# Only 1 version supported for now
>> +version: 1
>> +
>> +title: An example schema annotated with jsonschema details
>> +
>> +maintainers:
>> +  - Rob Herring <robh@kernel.org>
>> +
>> +description: |
>> +  A more detailed multi-line description of the binding.
>> +
>> +  Details about the hardware device and any links to datasheets can go here.
>> +
>> +  The end of the description is marked by indentation less than the first line
>> +  in the description.
>> +
>> +select: false
>> +  # 'select' is a schema applied to a DT node to determine if this binding
>> +  # schema should be applied to the node. It is optional and by default the
>> +  # possible compatible strings are extracted and used to match.
>
> My first reaction was that 'node' should somehow be included in the name
> of 'select'.  But my second thought was that maybe 'node' is implied,
> because every schema file describes a single node???  This is where my
> lack of knowledge kicks in - I'll go read stuff in your yaml-bindings
> repo to get a better background...

Yes, schema are applied to nodes and most of the current uses of
select are based on node name. We walk the DT and apply all the schema
for a node that select (either in the doc or generated from
compatible) is valid.


>> +
>> +properties:
>> +  # A dictionary of DT properties for this binding schema
>> +  compatible:
>> +    # More complicated schema can use oneOf (XOR), anyOf (OR), or allOf (AND)
>> +    # to handle different conditions.
>> +    # In this case, it's needed to handle a variable number of values as there
>> +    # isn't another way to express a constraint of the last string value.
>> +    # The boolean schema must be a list of schemas.
>> +    oneOf:
>> +      - items:
>> +          # items is a list of possible values for the property. The number of
>> +          # values is determined by the number of elements in the list.
>> +          # Order in lists is significant, order in dicts is not
>> +          # Must be one of the 1st enums followed by the 2nd enum
>> +          #
>> +          # Each element in items should be 'enum' or 'const'
>> +          - enum:
>> +              - vendor,soc4-ip
>> +              - vendor,soc3-ip
>> +              - vendor,soc2-ip
>> +          - enum:
>> +              - vendor,soc1-ip
>> +        # additionalItems being false is implied
>> +        # minItems/maxItems equal to 2 is implied
>> +      - items:
>> +          # 'const' is just a special case of an enum with a single possible value
>> +          - const: vendor,soc1-ip
>
> I'm using this as an example of a concept, not to pick on this one specific
> instance.
>
> One of my concerns with YAML has been the rich, flexible syntax available.  To
> a YAML expert, this is a very useful feature.  To someone who does not use YAML
> and will not use it for anything other than binding schemas, this adds more
> complexity.

I think you need to replace YAML with jsonschema. Our YAML use is
restricted to the subset of which JSON supports (plus the literal
block support which I think can't be done in JSON). And then the
vocabulary we are using is jsonschema.

I share the concern as I doubt most kernel developers don't know
jsonschema. But then the alternative is us defining and writing our
own thing which is C like 'cause that's what kernel developers
understand. My hope is to simplify and restrict things enough that it
writing a binding doc is straightforward without being jsonschema
experts. That was the intent of this patch without going into all the
details behind it.

> What I have heard some people say in the validation discussions is that the
> allowed YAML syntax for binding schemas would be limited to one (or a very
> small number) of the possible YAML alternative syntaxes for use in the
> bindings.  Will there be a document describing such a limitation on
> alternate syntaxes?

The syntax is jsonschema. That's what defines the top-level fields for
the most part. For common properties, the syntax is pretty locked down
by what the meta-schema allows. So for example the following will fail
on the meta-schema even though something like this is valid
jsonschema:

compatible:
  allOf:
    - items:
        - enum: [ foo ]
    - items:
        - enum: [ bar ]

Jsonschema has the "feature" that if the validator doesn't recognize a
keyword, it is supposed to silently ignore the keyword. So a typo in a
keyword would just be ignored. The meta-schema


>
> (This example file provides a good example of a single syntax style, but does
> not preclude other equivalent syntax.)

There's also a question of formatting. For example, we can have:

enum: [1,2,3]

or

enum:
  - 1
  - 2
  - 3

IMO, we should lock that down too.

> Getting back to the specific example of 'const', it is a less verbose way of
> specifying a single value enum, and I think it looks cleaner and more
> readable.  But it is also a case of adding more complexity for someone who
> does not otherwise use YAML.  I would using the more verbose syntax of
> enum even for a single possible value.

That's fine. There's certainly cases where we might start with 1 value
and plan to add more over time and would want to use enum.

>> +
>> +  reg:
>> +    # The description of each element defines the order and implicitly defines
>> +    # the number of reg entries
>> +    items:
>> +      - description: core registers
>> +      - description: aux registers
>> +    # minItems/maxItems equal to 2 is implied
>> +
>> +  reg-names:
>> +    # The core schema enforces this is a string array
>> +    items:
>> +      - const: core
>> +      - const: aux
>> +
>> +  clocks:
>> +    # Only a single entry, so just need to set the max number of items.
>
>        # More restrictions are provided in meta-schemas/clocks.yaml
>
>
>> +    maxItems: 1
>> +
>> +  clock-names:
>> +    items:
>> +      - const: bus
>> +
>> +  interrupts:
>> +    # Either 1 or 2 interrupts can be present
>> +    minItems: 1
>> +    maxItems: 2
>> +    items:
>> +      - description: tx or combined interrupt
>> +      - description: rx interrupt
>> +
>> +    description: |
>> +      A variable number of interrupts warrants a description of what conditions
>> +      affect the number of interrupts. Otherwise, descriptions on standard
>> +      properties are not necessary.
>> +
>> +  interrupt-names:
>> +    # minItems must be specified here because the default would be 2
>> +    minItems: 1
>
> Why the difference between the interrupts property and the interrupt-names
> property (specifying maxItems for interrupt, but not interrupt-names)?

I should probably have maxItems here too.

> Others have already commented on a desire to have a way to specify that
> number of interrupts should match number of interrupt-names.

Yeah, but I don't see a way to do that. You could stick the array size
constraints in a common definition and have a $ref to that definition
from both, but that doesn't really save you too much.

>> +    items:
>> +      - const: "tx irq"
>> +      - const: "rx irq"
>> +
>> +  # Property names starting with '#' must be quoted
>> +  '#interrupt-cells':
>> +    # A simple case where the value must always be '2'.
>> +    # The core schema handles that this must be a single integer.
>> +    const: 2
>> +
>> +  interrupt-controller: {}
>> +    # The core checks this is a boolean, so just have to list it here to be
>> +    # valid for this binding.
>> +
>> +  clock-frequency:
>> +    # The type is set in the core schema. Per device schema only need to set
>> +    # constraints on the possible values.
>> +    minimum: 100
>> +    maximum: 400000
>> +    # The value that should be used if the property is not present
>> +    default: 200
>
> This is confusing to me.  (Beyond the discussion of this in Stephen Boyd's
> reply...)  My naive reading of this is that the default is the value that
> the driver should implement if the property is missing, which is unrelated
> to the concept of validating a dts file.

Your reading was my intent and what we currently document. Stephen's
suggestion is probably more inline with typical jsonschema use of
default (i.e. to fill in missing data).

The schema doc is for more than just dts validation.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rob Herring April 21, 2018, 1:34 a.m. UTC | #10
On Fri, Apr 20, 2018 at 6:41 PM, Stephen Boyd <sboyd@kernel.org> wrote:
> Quoting Rob Herring (2018-04-20 11:15:04)
>> On Fri, Apr 20, 2018 at 11:47 AM, Stephen Boyd <sboyd@kernel.org> wrote:
>> > Quoting Rob Herring (2018-04-18 15:29:05)
>> >> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
>> >> new file mode 100644
>> >> index 000000000000..fe0a3bd1668e
>> >> --- /dev/null
>> >> +++ b/Documentation/devicetree/bindings/example-schema.yaml
>> >> @@ -0,0 +1,149 @@
>> >> +
>> >> +  The end of the description is marked by indentation less than the first line
>> >> +  in the description.
>> >> +
>> >> +select: false
>> >> +  # 'select' is a schema applied to a DT node to determine if this binding
>> >> +  # schema should be applied to the node. It is optional and by default the
>> >> +  # possible compatible strings are extracted and used to match.
>> >
>> > Can we get a concrete example here?
>>
>> select: true
>>
>> :) Which is apply to every node.
>>
>> A better one is from the memory node schema ('$nodename' gets added :
>>
>> select:
>>   required: ["$nodename"]
>>   properties:
>>     $nodename:
>>       oneOf:
>>         - pattern: "^memory@[0-9a-f]*"
>>         - const: "memory" # 'memory' only allowed for selecting
>>
>>
>> I expect the vast majority of device bindings will not use select at
>> all and rely on compatible string matching.
>
> Thanks! I was looking to see how the select syntax would work and this
> shows one example nicely. I suppose another way would be to show how a
> compatible string would be matched through select, even though it's
> redundant.
>
> Is there a way we can enforce node names through the schema too? For
> example to enforce that a clock controller is called 'clock-controller'
> or a spi master is called 'spi'.

Yes, that's something I'd like to do. I think the easiest is to just
treat node name as a property. We already generate a $nodename
property when parsing the yaml format DT.

>>
>> >> +
>> >> +properties:
>> > [...]
>> >> +
>> >> +  interrupts:
>> >> +    # Either 1 or 2 interrupts can be present
>> >> +    minItems: 1
>> >> +    maxItems: 2
>> >> +    items:
>> >> +      - description: tx or combined interrupt
>> >> +      - description: rx interrupt
>> >> +
>> >> +    description: |
>> >
>> > The '|' is needed to make yaml happy?
>>
>> Yes, this is simply how you do literal text blocks in yaml.
>>
>> We don't really need for this one really, but for the top-level
>> 'description' we do. The long term intent is 'description' would be
>> written in sphinx/rst and can be extracted into the DT spec (for
>> common bindings). Grant has experimented with that some.
>
> Ok. That sounds cool. Then we could embed links to datasheets and SVGs
> too.
>
>>
>> >> +      A variable number of interrupts warrants a description of what conditions
>> >> +      affect the number of interrupts. Otherwise, descriptions on standard
>> >> +      properties are not necessary.
>> >> +
>> >> +  interrupt-names:
>> >> +    # minItems must be specified here because the default would be 2
>> >> +    minItems: 1
>> >> +    items:
>> >> +      - const: "tx irq"
>> >> +      - const: "rx irq"
>> >> +
>> >> +  # Property names starting with '#' must be quoted
>> >> +  '#interrupt-cells':
>> >> +    # A simple case where the value must always be '2'.
>> >> +    # The core schema handles that this must be a single integer.
>> >> +    const: 2
>> >> +
>> >> +  interrupt-controller: {}
>> >
>> > Does '{}' mean nothing to see here?
>>
>> Yes. It's just an empty schema that's always valid.
>
> Could we include another schema to indicate that this is an interrupt
> controller? I'm sort of asking for multi-schema inheritance.

Yes, but there's no need to do that here. Another schema can select on
"interrupt-controller" property and be applied independently. There's
already an example of that for the root node in my yaml-bindings repo.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Geert Uytterhoeven April 23, 2018, 7:25 a.m. UTC | #11
Hi Rob,

On Sat, Apr 21, 2018 at 3:28 AM, Rob Herring <robh@kernel.org> wrote:
> On Fri, Apr 20, 2018 at 4:00 PM, Frank Rowand <frowand.list@gmail.com> wrote:
>> Others have already commented on a desire to have a way to specify that
>> number of interrupts should match number of interrupt-names.
>
> Yeah, but I don't see a way to do that. You could stick the array size
> constraints in a common definition and have a $ref to that definition
> from both, but that doesn't really save you too much.

As Bjorn said, this could be handled in the validation tool, for the myriad of
standard list properties that have an accompanying names property.

That avoids having to specify the relation in each and every binding document.

Gr{oetje,eeting}s,

                        Geert
Grant Likely April 23, 2018, 2:01 p.m. UTC | #12
On 21/04/2018 00:41, Stephen Boyd wrote:
> Quoting Rob Herring (2018-04-20 11:15:04)
>> On Fri, Apr 20, 2018 at 11:47 AM, Stephen Boyd <sboyd@kernel.org> wrote:
>>> Quoting Rob Herring (2018-04-18 15:29:05)
>>>> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
>>>> new file mode 100644
>>>> index 000000000000..fe0a3bd1668e
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/example-schema.yaml
[...]
>>>> +  interrupts:
>>>> +    # Either 1 or 2 interrupts can be present
>>>> +    minItems: 1
>>>> +    maxItems: 2
>>>> +    items:
>>>> +      - description: tx or combined interrupt
>>>> +      - description: rx interrupt
>>>> +
>>>> +    description: |
>>>
>>> The '|' is needed to make yaml happy?
>>
>> Yes, this is simply how you do literal text blocks in yaml.
>>
>> We don't really need for this one really, but for the top-level
>> 'description' we do. The long term intent is 'description' would be
>> written in sphinx/rst and can be extracted into the DT spec (for
>> common bindings). Grant has experimented with that some.
>
> Ok. That sounds cool. Then we could embed links to datasheets and SVGs
> too.

I'd like it if we can define the description text blocks to be
reStructeredText markup. That makes it even easier to integrate with the
specification documentation.

[...]
>>>> +  # Property names starting with '#' must be quoted
>>>> +  '#interrupt-cells':
>>>> +    # A simple case where the value must always be '2'.
>>>> +    # The core schema handles that this must be a single integer.
>>>> +    const: 2
>>>> +
>>>> +  interrupt-controller: {}
>>>
>>> Does '{}' mean nothing to see here?
>>
>> Yes. It's just an empty schema that's always valid.

IIRC, in the current jsonschema draft-6 spec, the following also has the
same behaviour, which I like slightly better:
     interrupt-controller: true

g.
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rob Herring April 23, 2018, 2:38 p.m. UTC | #13
On Mon, Apr 23, 2018 at 9:01 AM, Grant Likely <grant.likely@arm.com> wrote:
> On 21/04/2018 00:41, Stephen Boyd wrote:
>>
>> Quoting Rob Herring (2018-04-20 11:15:04)
>>>
>>> On Fri, Apr 20, 2018 at 11:47 AM, Stephen Boyd <sboyd@kernel.org> wrote:
>>>>
>>>> Quoting Rob Herring (2018-04-18 15:29:05)
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/example-schema.yaml
>>>>> b/Documentation/devicetree/bindings/example-schema.yaml
>>>>> new file mode 100644
>>>>> index 000000000000..fe0a3bd1668e
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/example-schema.yaml
>
> [...]
>>>>>
>>>>> +  interrupts:
>>>>> +    # Either 1 or 2 interrupts can be present
>>>>> +    minItems: 1
>>>>> +    maxItems: 2
>>>>> +    items:
>>>>> +      - description: tx or combined interrupt
>>>>> +      - description: rx interrupt
>>>>> +
>>>>> +    description: |
>>>>
>>>>
>>>> The '|' is needed to make yaml happy?
>>>
>>>
>>> Yes, this is simply how you do literal text blocks in yaml.
>>>
>>> We don't really need for this one really, but for the top-level
>>> 'description' we do. The long term intent is 'description' would be
>>> written in sphinx/rst and can be extracted into the DT spec (for
>>> common bindings). Grant has experimented with that some.
>>
>>
>> Ok. That sounds cool. Then we could embed links to datasheets and SVGs
>> too.
>
>
> I'd like it if we can define the description text blocks to be
> reStructeredText markup. That makes it even easier to integrate with the
> specification documentation.

I think that's going to require thinking about how each binding is
integrated into the spec. We're only talking about common bindings I
presume, but still we have no model defined. For example, with
properties, I'd assume we'd want to generate a table of properties and
we wouldn't want the property descriptions in rST because the
description becomes just a cell in the table. So we need some sort of
template.

Also, how do we validate that description contains valid rST? No point
requiring it until we can validate it.

> [...]
>>>>>
>>>>> +  # Property names starting with '#' must be quoted
>>>>> +  '#interrupt-cells':
>>>>> +    # A simple case where the value must always be '2'.
>>>>> +    # The core schema handles that this must be a single integer.
>>>>> +    const: 2
>>>>> +
>>>>> +  interrupt-controller: {}
>>>>
>>>>
>>>> Does '{}' mean nothing to see here?
>>>
>>>
>>> Yes. It's just an empty schema that's always valid.
>
>
> IIRC, in the current jsonschema draft-6 spec, the following also has the
> same behaviour, which I like slightly better:
>     interrupt-controller: true

They are not exactly the same. '{}' is a schema object and 'true' is
just a boolean. But yes, it can work. We need to drop "type: object"
from meta-schemas/boolean.yaml and it will work.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Grant Likely April 23, 2018, 2:47 p.m. UTC | #14
On 21/04/2018 02:28, Rob Herring wrote:
> On Fri, Apr 20, 2018 at 4:00 PM, Frank Rowand <frowand.list@gmail.com> wrote:
>> Hi Rob,
>>
>> Thanks for the example.  It was a good starting tutorial of sorts for me
>> to understand the format a bit.
>>
>>
>> On 04/18/18 15:29, Rob Herring wrote:
>>> The current DT binding documentation format of freeform text is painful
>>> to write, review, validate and maintain.
>>>
>>> This is just an example of what a binding in the schema format looks
>>> like. It's using jsonschema vocabulary in a YAML encoded document. Using
>>> jsonschema gives us access to existing tooling. A YAML encoding gives us
>>> something easy to edit.
>>>
>>> This example is just the tip of the iceberg, but it the part most
>>> developers writing bindings will interact with. Backing all this up
>>> are meta-schema (to validate the binding schemas), some DT core schema,
>>> YAML encoded DT output with dtc, and a small number of python scripts to
>>> run validation. The gory details including how to run end-to-end
>>> validation can be found here:
>>>
>>> https://www.spinics.net/lists/devicetree-spec/msg00649.html
>>>
>>> Signed-off-by: Rob Herring <robh@kernel.org>
>>> ---
>>> Cc list,
>>> You all review and/or write lots of binding documents. I'd like some feedback
>>> on the format.
>>>
>>> Thanks,
>>> Rob
>>>
>>>   .../devicetree/bindings/example-schema.yaml        | 149 +++++++++++++++++++++
>>>   1 file changed, 149 insertions(+)
>>>   create mode 100644 Documentation/devicetree/bindings/example-schema.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
>>> new file mode 100644
>>> index 000000000000..fe0a3bd1668e
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/example-schema.yaml
>>
>> I'm guessing by the path name that this is in the Linux kernel source tree.
>
> Yes, well, my kernel tree. Most of the work still lives here:
>
> https://github.com/robherring/yaml-bindings/
>
>>> @@ -0,0 +1,149 @@
>>> +# SPDX-License-Identifier: BSD-2-Clause
>>
>> If in the Linux kernel source tree, then allow gpl-v2 as a possible license.
>
> Why? BSD is compatible. The license of the above repo is all BSD.
>
> Of course there's all the existing docs which default to GPLv2 and
> we'll probably have to maintain that.
>
>>> +# Copyright 2018 Linaro Ltd.
>>> +%YAML 1.2
>>> +---
>>> +# All the top-level keys are standard json-schema keywords except for
>>> +# 'maintainers' and 'select'
>>> +
>>> +# $id is a unique idenifier based on the filename
>>
>>                       ^^^^^^^^^  identifier
>>
>>> +$id: "http://devicetree.org/schemas/example-schema.yaml#"
>>
>> Does this imply that all schemas will be at devicetree.org instead
>> of in the Linux kernel source tree?  This would be counter to my
>> earlier guess about where this patch is applied.
>
> They could be, but not necessarily. This is just convention in
> jsonschema is the best I understand it.
>
> I don't think you'd want validation to require an internet connection.
> For the base meta-schema, for example, it does exist at
> http://json-schema.org/draft-06/schema, but that's also distributed
> with implementations of jsonschema validators.
>
> A large part (not that any part is large) of the tools Grant and I
> have written is doing the cross reference resolution of files which
> uses the $id field.
>
>
>>> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
>>
>> How is $schema used?
>
> Tells the validator what meta-schema this schema follows. Typically
> you see draft04 or draft06 here if you haven't written a meta-schema.

On this topic, we should probably do the same thing for the dt
metaschemas. I didn't worry about it initially because there was a lot
of working out what it should look like, but we should include a
revision number in the DT metaschema $id URLs.

>> Is it accessed across the network?
>
> Could be, but generally no.

The $schema and $id values are used as unique identifiers. The parser is
setup to look locally for both devicetree.org and json-schema.org URLs,
so network access is not used. The parser /can/ fetch a URL over the
network, but that isn't a feature we want to use.

Using the http://devicetree.org/ prefix makes sense for the metaschema,
and for all the schema files because I think the desire is to have a
common database for all users. For practical reasons it makes sense to
start with putting them in the Linux kernel tree, but only because
that's where all the binding documents currently are. However, we also
have the DT rebasing tree that is tracking mainline and has a good
structure. We can start encouraging non-Linux users to base off the
-rebasing tree, and work on transition plans to allow patches against
-rebasing, and to eventually make it the master tree instead of the kernel.

It is also possible to have other prefixes for schemas that don't belong
in the common repo (but I cannot think of many good reasons for doing that).


>>
>> (This example file provides a good example of a single syntax style, but does
>> not preclude other equivalent syntax.)
>
> There's also a question of formatting. For example, we can have:
>
> enum: [1,2,3]
>
> or
>
> enum:
>    - 1
>    - 2
>    - 3
>
> IMO, we should lock that down too.

I don't think this level of variance needs to be locked down. That is a
very basic example of standard YAML encoding of lists. There are times
when one will look better than the other, and it isn't a lot different
from the kinds of things we do in C. For example:

    int a;
    int b;

vs.

    int a, b;

On Jsonschema vocabulary? Yes, start with it restricted because there
may be unintended consequences. But for YAML syntax, I would rely on the
metaschema to make sure the structure of the data is correct, but not
get worried about the encoding.

[...]
>>> +  interrupts:
>>> +    # Either 1 or 2 interrupts can be present
>>> +    minItems: 1
>>> +    maxItems: 2
>>> +    items:
>>> +      - description: tx or combined interrupt
>>> +      - description: rx interrupt
>>> +
>>> +    description: |
>>> +      A variable number of interrupts warrants a description of what conditions
>>> +      affect the number of interrupts. Otherwise, descriptions on standard
>>> +      properties are not necessary.
>>> +
>>> +  interrupt-names:
>>> +    # minItems must be specified here because the default would be 2
>>> +    minItems: 1
>>
>> Why the difference between the interrupts property and the interrupt-names
>> property (specifying maxItems for interrupt, but not interrupt-names)?
>
> I should probably have maxItems here too.
>
>> Others have already commented on a desire to have a way to specify that
>> number of interrupts should match number of interrupt-names.
>
> Yeah, but I don't see a way to do that. You could stick the array size
> constraints in a common definition and have a $ref to that definition
> from both, but that doesn't really save you too much.

There has been discussions in the jsonschema community regarding
referencing data in the document when applying the schema.

https://github.com/json-schema-org/json-schema-spec/issues/549

However, those discussions are ongoing and have been pushed back to
after draft-8 (the current release is draft-7). We can instead define
DT-specific keywords and extend the validator to make it do what we
want. We need to do something very similar to validate that the length
of tuples in 'reg', 'interrupts', and '*gpios' match the '#*-cells' values.

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Grant Likely April 23, 2018, 2:49 p.m. UTC | #15
On 23/04/2018 15:38, Rob Herring wrote:
> On Mon, Apr 23, 2018 at 9:01 AM, Grant Likely <grant.likely@arm.com> wrote:
>> On 21/04/2018 00:41, Stephen Boyd wrote:
>>>
>>> Quoting Rob Herring (2018-04-20 11:15:04)
>>>>
>>>> On Fri, Apr 20, 2018 at 11:47 AM, Stephen Boyd <sboyd@kernel.org> wrote:
>>>>>
>>>>> Quoting Rob Herring (2018-04-18 15:29:05)
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/example-schema.yaml
>>>>>> b/Documentation/devicetree/bindings/example-schema.yaml
>>>>>> new file mode 100644
>>>>>> index 000000000000..fe0a3bd1668e
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/example-schema.yaml
>>
>> [...]
>>>>>>
>>>>>> +  interrupts:
>>>>>> +    # Either 1 or 2 interrupts can be present
>>>>>> +    minItems: 1
>>>>>> +    maxItems: 2
>>>>>> +    items:
>>>>>> +      - description: tx or combined interrupt
>>>>>> +      - description: rx interrupt
>>>>>> +
>>>>>> +    description: |
>>>>>
>>>>>
>>>>> The '|' is needed to make yaml happy?
>>>>
>>>>
>>>> Yes, this is simply how you do literal text blocks in yaml.
>>>>
>>>> We don't really need for this one really, but for the top-level
>>>> 'description' we do. The long term intent is 'description' would be
>>>> written in sphinx/rst and can be extracted into the DT spec (for
>>>> common bindings). Grant has experimented with that some.
>>>
>>>
>>> Ok. That sounds cool. Then we could embed links to datasheets and SVGs
>>> too.
>>
>>
>> I'd like it if we can define the description text blocks to be
>> reStructeredText markup. That makes it even easier to integrate with the
>> specification documentation.
>
> I think that's going to require thinking about how each binding is
> integrated into the spec. We're only talking about common bindings I
> presume, but still we have no model defined. For example, with
> properties, I'd assume we'd want to generate a table of properties and
> we wouldn't want the property descriptions in rST because the
> description becomes just a cell in the table. So we need some sort of
> template.
>
> Also, how do we validate that description contains valid rST? No point
> requiring it until we can validate it.

Indeed. Part of that was me thinking outloud. Need to actually get it
working before adding constraints.

g.
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Geert Uytterhoeven April 23, 2018, 4:49 p.m. UTC | #16
Hi Grant,

On Mon, Apr 23, 2018 at 4:47 PM, Grant Likely <grant.likely@arm.com> wrote:
> On 21/04/2018 02:28, Rob Herring wrote:
>> On Fri, Apr 20, 2018 at 4:00 PM, Frank Rowand <frowand.list@gmail.com>
>> wrote:
>>>> +  interrupts:
>>>> +    # Either 1 or 2 interrupts can be present
>>>> +    minItems: 1
>>>> +    maxItems: 2
>>>> +    items:
>>>> +      - description: tx or combined interrupt
>>>> +      - description: rx interrupt
>>>> +
>>>> +    description: |
>>>> +      A variable number of interrupts warrants a description of what
>>>> conditions
>>>> +      affect the number of interrupts. Otherwise, descriptions on
>>>> standard
>>>> +      properties are not necessary.
>>>> +
>>>> +  interrupt-names:
>>>> +    # minItems must be specified here because the default would be 2
>>>> +    minItems: 1
>>>
>>> Why the difference between the interrupts property and the
>>> interrupt-names
>>> property (specifying maxItems for interrupt, but not interrupt-names)?
>>
>> I should probably have maxItems here too.
>>
>>> Others have already commented on a desire to have a way to specify that
>>> number of interrupts should match number of interrupt-names.
>>
>> Yeah, but I don't see a way to do that. You could stick the array size
>> constraints in a common definition and have a $ref to that definition
>> from both, but that doesn't really save you too much.
>
>
> There has been discussions in the jsonschema community regarding
> referencing data in the document when applying the schema.
>
> https://github.com/json-schema-org/json-schema-spec/issues/549
>
> However, those discussions are ongoing and have been pushed back to
> after draft-8 (the current release is draft-7). We can instead define
> DT-specific keywords and extend the validator to make it do what we
> want. We need to do something very similar to validate that the length
> of tuples in 'reg', 'interrupts', and '*gpios' match the '#*-cells' values.

Checking that property lengths match the corresponding #*-cells cannot
be done for a schema, but only for the final DTS, as #*-cells is a property
of the target node, right?

Gr{oetje,eeting}s,

                        Geert
Rob Herring April 23, 2018, 4:51 p.m. UTC | #17
On Fri, Apr 20, 2018 at 4:47 PM, Bjorn Andersson
<bjorn.andersson@linaro.org> wrote:
> On Wed 18 Apr 15:29 PDT 2018, Rob Herring wrote:
>
>> The current DT binding documentation format of freeform text is painful
>> to write, review, validate and maintain.
>>
>> This is just an example of what a binding in the schema format looks
>> like. It's using jsonschema vocabulary in a YAML encoded document. Using
>> jsonschema gives us access to existing tooling. A YAML encoding gives us
>> something easy to edit.
>>
>> This example is just the tip of the iceberg, but it the part most
>> developers writing bindings will interact with. Backing all this up
>> are meta-schema (to validate the binding schemas), some DT core schema,
>> YAML encoded DT output with dtc, and a small number of python scripts to
>> run validation. The gory details including how to run end-to-end
>> validation can be found here:
>>
>> https://www.spinics.net/lists/devicetree-spec/msg00649.html
>>
>> Signed-off-by: Rob Herring <robh@kernel.org>
>> ---
>> Cc list,
>> You all review and/or write lots of binding documents. I'd like some feedback
>> on the format.
>>
>
> I really like the idea of formalizing the binding document format and
> the ability of validating a dtb is really nice.
>
>> Thanks,
>> Rob
>>
>>  .../devicetree/bindings/example-schema.yaml        | 149 +++++++++++++++++++++
>>  1 file changed, 149 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/example-schema.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
> [..]
>> +  reg:
>> +    # The description of each element defines the order and implicitly defines
>> +    # the number of reg entries
>> +    items:
>> +      - description: core registers
>> +      - description: aux registers
>> +    # minItems/maxItems equal to 2 is implied
>
> I assume that a reg with variable number of entries would have
> "description" for all of them and then a minItems that matches the
> required ones and maxItems matching all of them?

You could do that, but it doesn't really enforce which compatible(s)
each size of reg is valid for. It would work okay when just the last N
entries are variable, but it will break down if you have cases where
essentially any subset is valid. For bindings with lots of conditional
sizes for reg, clocks, resets, etc. based on compatible strings, I
think we will need to split the binding into a schema per compatible.

IMO, things like this are probably not going to be addressed at the
start and may remain in the description (as we have today). I think we
need to start with a base schema and can improve them over time.

>> +
>> +  reg-names:
>> +    # The core schema enforces this is a string array
>> +    items:
>> +      - const: core
>> +      - const: aux
>
> I presume validation based on this should check that there's equal
> number of entries in reg-names as there where in reg. Should this
> relationship be described in the schema?

Yes, if we can figure out how. But I don't think it belongs in per
device schema as it is a core requirement.

>
> [..]
>> +  interrupts:
>> +    # Either 1 or 2 interrupts can be present
>> +    minItems: 1
>> +    maxItems: 2
>> +    items:
>> +      - description: tx or combined interrupt
>> +      - description: rx interrupt
>> +
>> +    description: |
>> +      A variable number of interrupts warrants a description of what conditions
>> +      affect the number of interrupts. Otherwise, descriptions on standard
>> +      properties are not necessary.
>
> For validation purposes this could be interrupts with interrupt-parents
> or a interrupts-extend, a fact that we probably don't want to duplicate
> in every definition?
>
> Perhaps we should just do like you did here and define the "interrupts"
> and then in the validation tool - where we need to encode the logic
> behind this anyways - we support the different variants.

Yes, essentially as we do now where the binding just describes
'interrupts' and 'interrupts-extended' is implicitly supported.

>> +
>> +  interrupt-names:
>> +    # minItems must be specified here because the default would be 2
>> +    minItems: 1
>
> As with reg-names, it would be good to have the validator warn if this
> is not the same number of items as entries in "interrupts".
>
>> +    items:
>> +      - const: "tx irq"
>> +      - const: "rx irq"
>> +
>> +  # Property names starting with '#' must be quoted
>> +  '#interrupt-cells':
>> +    # A simple case where the value must always be '2'.
>> +    # The core schema handles that this must be a single integer.
>> +    const: 2
>
> If this is specified then interrupt-controller should also be given, or
> vise versa. How would we describe that?

The core meta-schema can check that with 'dependencies'. Here's gpio
meta-schema for example:

dependencies:
  gpio-controller: ['#gpio-cells']
  '#gpio-cells': [gpio-controller]
  gpio-ranges: [gpio-controller]
  ngpios: [gpio-controller]


Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Frank Rowand April 25, 2018, 12:33 a.m. UTC | #18
On 04/20/18 18:28, Rob Herring wrote:
> On Fri, Apr 20, 2018 at 4:00 PM, Frank Rowand <frowand.list@gmail.com> wrote:
>> Hi Rob,
>>
>> Thanks for the example.  It was a good starting tutorial of sorts for me
>> to understand the format a bit.
>>
>>
>> On 04/18/18 15:29, Rob Herring wrote:
>>> The current DT binding documentation format of freeform text is painful
>>> to write, review, validate and maintain.
>>>
>>> This is just an example of what a binding in the schema format looks
>>> like. It's using jsonschema vocabulary in a YAML encoded document. Using
>>> jsonschema gives us access to existing tooling. A YAML encoding gives us
>>> something easy to edit.
>>>
>>> This example is just the tip of the iceberg, but it the part most
>>> developers writing bindings will interact with. Backing all this up
>>> are meta-schema (to validate the binding schemas), some DT core schema,
>>> YAML encoded DT output with dtc, and a small number of python scripts to
>>> run validation. The gory details including how to run end-to-end
>>> validation can be found here:
>>>
>>> https://www.spinics.net/lists/devicetree-spec/msg00649.html
>>>
>>> Signed-off-by: Rob Herring <robh@kernel.org>
>>> ---
>>> Cc list,
>>> You all review and/or write lots of binding documents. I'd like some feedback
>>> on the format.
>>>
>>> Thanks,
>>> Rob
>>>
>>>  .../devicetree/bindings/example-schema.yaml        | 149 +++++++++++++++++++++
>>>  1 file changed, 149 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/example-schema.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
>>> new file mode 100644
>>> index 000000000000..fe0a3bd1668e
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/example-schema.yaml
>>
>> I'm guessing by the path name that this is in the Linux kernel source tree.
> 
> Yes, well, my kernel tree. Most of the work still lives here:
> 
> https://github.com/robherring/yaml-bindings/
> 
>>> @@ -0,0 +1,149 @@
>>> +# SPDX-License-Identifier: BSD-2-Clause
>>
>> If in the Linux kernel source tree, then allow gpl-v2 as a possible license.
> 
> Why? BSD is compatible. The license of the above repo is all BSD.

I said __if__ in the Linux kernel source tree.  As my other comments
indicated, I wasn't sure if this was intended to end up in the Linux
kernel source tree.  __If__ in the Linux kernel source tree then it
would be dual licensed, correct?  And thus the tag would reflect that?


> Of course there's all the existing docs which default to GPLv2 and
> we'll probably have to maintain that.
> 

< snip >
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Grant Likely April 25, 2018, 10:15 a.m. UTC | #19
On 23/04/2018 17:49, Geert Uytterhoeven wrote:
> Hi Grant,
>
> On Mon, Apr 23, 2018 at 4:47 PM, Grant Likely <grant.likely@arm.com> wrote:
>> On 21/04/2018 02:28, Rob Herring wrote:
>>> On Fri, Apr 20, 2018 at 4:00 PM, Frank Rowand <frowand.list@gmail.com>
>>> wrote:
>>>>> +  interrupts:
>>>>> +    # Either 1 or 2 interrupts can be present
>>>>> +    minItems: 1
>>>>> +    maxItems: 2
>>>>> +    items:
>>>>> +      - description: tx or combined interrupt
>>>>> +      - description: rx interrupt
>>>>> +
>>>>> +    description: |
>>>>> +      A variable number of interrupts warrants a description of what
>>>>> conditions
>>>>> +      affect the number of interrupts. Otherwise, descriptions on
>>>>> standard
>>>>> +      properties are not necessary.
>>>>> +
>>>>> +  interrupt-names:
>>>>> +    # minItems must be specified here because the default would be 2
>>>>> +    minItems: 1
>>>>
>>>> Why the difference between the interrupts property and the
>>>> interrupt-names
>>>> property (specifying maxItems for interrupt, but not interrupt-names)?
>>>
>>> I should probably have maxItems here too.
>>>
>>>> Others have already commented on a desire to have a way to specify that
>>>> number of interrupts should match number of interrupt-names.
>>>
>>> Yeah, but I don't see a way to do that. You could stick the array size
>>> constraints in a common definition and have a $ref to that definition
>>> from both, but that doesn't really save you too much.
>>
>>
>> There has been discussions in the jsonschema community regarding
>> referencing data in the document when applying the schema.
>>
>> https://github.com/json-schema-org/json-schema-spec/issues/549
>>
>> However, those discussions are ongoing and have been pushed back to
>> after draft-8 (the current release is draft-7). We can instead define
>> DT-specific keywords and extend the validator to make it do what we
>> want. We need to do something very similar to validate that the length
>> of tuples in 'reg', 'interrupts', and '*gpios' match the '#*-cells' values.
>
> Checking that property lengths match the corresponding #*-cells cannot
> be done for a schema, but only for the final DTS, as #*-cells is a property
> of the target node, right?

It can be done in the schema checking of the target node. For example,
given a GPIO specifier of:

gpios = <&gpio1 0> <&gpio2 4 1> <&gpio2 3 0>;

The validation engine could validate that the &gpio1 and &gpio2 targets
have the same length as the associated gpio descriptor tuples. (ex.
gpio1 needs #gpio-cells=<1>; and gpio2 needs #gpio-cells=<2>; If the
tuples are the wrong size, then validation should fail.

g.
>
> Gr{oetje,eeting}s,
>
>                          Geert
>

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
jonsmirl@gmail.com Nov. 14, 2018, 7:39 p.m. UTC | #20
On Fri, Apr 20, 2018 at 9:36 PM Rob Herring <robh@kernel.org> wrote:
> I share the concern as I doubt most kernel developers don't know
> jsonschema. But then the alternative is us defining and writing our
> own thing which is C like 'cause that's what kernel developers
> understand. My hope is to simplify and restrict things enough that it
> writing a binding doc is straightforward without being jsonschema
> experts. That was the intent of this patch without going into all the
> details behind it.

When schemas were first discussed long, long ago the idea was to have
a n arbitrator who controls the schema (like Grant/Rob) so there is no
need for general schema design knowledge in random kernel developers.

First a developer should try and build their device tree using the
existing schema. Then only if they find that impossible to do so
should they propose schema changes. The schema arbitrator would then
look at those changes and work them into the existing schemas as
needed. Doing this via an arbitrator will ensure consistency in the
overall schema design while eliminating redundancy with slight
variations (like we have now).

Another side effect of schemas is that as they evolve and enforce
commonality among driver implementation it will become possible to
turn those in-common pieces into driver libraries.
Rob Herring Nov. 15, 2018, 11:42 p.m. UTC | #21
On Wed, Nov 14, 2018 at 1:39 PM jonsmirl@gmail.com <jonsmirl@gmail.com> wrote:
>
> On Fri, Apr 20, 2018 at 9:36 PM Rob Herring <robh@kernel.org> wrote:
> > I share the concern as I doubt most kernel developers don't know
> > jsonschema. But then the alternative is us defining and writing our
> > own thing which is C like 'cause that's what kernel developers
> > understand. My hope is to simplify and restrict things enough that it
> > writing a binding doc is straightforward without being jsonschema
> > experts. That was the intent of this patch without going into all the
> > details behind it.
>
> When schemas were first discussed long, long ago the idea was to have
> a n arbitrator who controls the schema (like Grant/Rob) so there is no
> need for general schema design knowledge in random kernel developers.
>
> First a developer should try and build their device tree using the
> existing schema. Then only if they find that impossible to do so
> should they propose schema changes. The schema arbitrator would then
> look at those changes and work them into the existing schemas as
> needed. Doing this via an arbitrator will ensure consistency in the
> overall schema design while eliminating redundancy with slight
> variations (like we have now).
>
> Another side effect of schemas is that as they evolve and enforce
> commonality among driver implementation it will become possible to
> turn those in-common pieces into driver libraries.

If we replace 'schemas' everywhere above with 'bindings', then this
pretty much describes the status quo today. Most device specific
bindings are a collection of standard bindings. Occasionally, we have
new common bindings. All the bindings get reviewed by me. The only
real change here is submitters have to have some level of
understanding of json-schema instead of just English (for writing free
form text). I think it will continue to largely be following existing
examples of other bindings.

Rob
jonsmirl@gmail.com Nov. 16, 2018, 1:34 a.m. UTC | #22
On Thu, Nov 15, 2018 at 6:42 PM Rob Herring <robh@kernel.org> wrote:
>
> On Wed, Nov 14, 2018 at 1:39 PM jonsmirl@gmail.com <jonsmirl@gmail.com> wrote:
> >
> > On Fri, Apr 20, 2018 at 9:36 PM Rob Herring <robh@kernel.org> wrote:
> > > I share the concern as I doubt most kernel developers don't know
> > > jsonschema. But then the alternative is us defining and writing our
> > > own thing which is C like 'cause that's what kernel developers
> > > understand. My hope is to simplify and restrict things enough that it
> > > writing a binding doc is straightforward without being jsonschema
> > > experts. That was the intent of this patch without going into all the
> > > details behind it.
> >
> > When schemas were first discussed long, long ago the idea was to have
> > a n arbitrator who controls the schema (like Grant/Rob) so there is no
> > need for general schema design knowledge in random kernel developers.
> >
> > First a developer should try and build their device tree using the
> > existing schema. Then only if they find that impossible to do so
> > should they propose schema changes. The schema arbitrator would then
> > look at those changes and work them into the existing schemas as
> > needed. Doing this via an arbitrator will ensure consistency in the
> > overall schema design while eliminating redundancy with slight
> > variations (like we have now).
> >
> > Another side effect of schemas is that as they evolve and enforce
> > commonality among driver implementation it will become possible to
> > turn those in-common pieces into driver libraries.
>
> If we replace 'schemas' everywhere above with 'bindings', then this
> pretty much describes the status quo today. Most device specific
> bindings are a collection of standard bindings. Occasionally, we have
> new common bindings. All the bindings get reviewed by me. The only
> real change here is submitters have to have some level of
> understanding of json-schema instead of just English (for writing free
> form text). I think it will continue to largely be following existing
> examples of other bindings.

What used to happen is that drivers would be written out of tree
without review of their bindings until mainline submission (if they
submit them at all).  With schema a driver writer who is working out
of tree can use the schema to validate their new device tree entries
before submitting them. That way they will know ahead of time if they
are making up something non-standard. It will also give them the heads
up that they can't just make up anything they want in the device tree
and that they are going to have to defend their design when asking for
the schema to be changed to support it. An example of where schema
would have been initially valuable is in the i2c bindings which
contain significant variation but the function is the same.

Maybe we are thinking about schema differently. I had envisioned
starting from a base generic schema that is capable of validating all
possible legal Linux device trees. This schema is more strict that
YAML syntax, but it obviously can't validate in detail.  Someone
working out of tree would always be able to validate against this
schema.

As this generic schema validates the device tree it will discover that
it can utilize more strict schema fragments. So by providing these
fragments you can validate to any desired level of conformance. The
end of that process is the json-schema bindings file. But if those
fragments are missing you can still validate, just not at a detailed
level.

A large set of schemas that work like this are used in ONVIF (security
cameras). A flavor of SOAP.
https://www.onvif.org/profiles/specifications/
These schemas are using XML stylesheets to make them pretty, use view
source to see the actual schemas.

The ONVIF schemas define points where vendors are allowed to insert
arbitrary items (ANY elements) and then they will use a vendor
supplied schema to validate the fragment if one is available. If not
the generic schema is used to validate the basic structure of the
vendor fragments.

>
> Rob
diff mbox series

Patch

diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml
new file mode 100644
index 000000000000..fe0a3bd1668e
--- /dev/null
+++ b/Documentation/devicetree/bindings/example-schema.yaml
@@ -0,0 +1,149 @@ 
+# SPDX-License-Identifier: BSD-2-Clause
+# Copyright 2018 Linaro Ltd.
+%YAML 1.2
+---
+# All the top-level keys are standard json-schema keywords except for
+# '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#"
+
+# Only 1 version supported for now
+version: 1
+
+title: An example schema annotated with jsonschema details
+
+maintainers:
+  - Rob Herring <robh@kernel.org>
+
+description: |
+  A more detailed multi-line description of the binding.
+
+  Details about the hardware device and any links to datasheets can go here.
+
+  The end of the description is marked by indentation less than the first line
+  in the description.
+
+select: false
+  # 'select' is a schema applied to a DT node to determine if this binding
+  # schema should be applied to the node. It is optional and by default the
+  # possible compatible strings are extracted and used to match.
+
+properties:
+  # A dictionary of DT properties for this binding schema
+  compatible:
+    # More complicated schema can use oneOf (XOR), anyOf (OR), or allOf (AND)
+    # to handle different conditions.
+    # In this case, it's needed to handle a variable number of values as there
+    # isn't another way to express a constraint of the last string value.
+    # The boolean schema must be a list of schemas.
+    oneOf:
+      - items:
+          # items is a list of possible values for the property. The number of
+          # values is determined by the number of elements in the list.
+          # Order in lists is significant, order in dicts is not
+          # Must be one of the 1st enums followed by the 2nd enum
+          #
+          # Each element in items should be 'enum' or 'const'
+          - enum:
+              - vendor,soc4-ip
+              - vendor,soc3-ip
+              - vendor,soc2-ip
+          - enum:
+              - vendor,soc1-ip
+        # additionalItems being false is implied
+        # minItems/maxItems equal to 2 is implied
+      - items:
+          # 'const' is just a special case of an enum with a single possible value
+          - const: vendor,soc1-ip
+
+  reg:
+    # The description of each element defines the order and implicitly defines
+    # the number of reg entries
+    items:
+      - description: core registers
+      - description: aux registers
+    # minItems/maxItems equal to 2 is implied
+
+  reg-names:
+    # The core schema enforces this is a string array
+    items:
+      - const: core
+      - const: aux
+
+  clocks:
+    # Only a single entry, so just need to set the max number of items.
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: bus
+
+  interrupts:
+    # Either 1 or 2 interrupts can be present
+    minItems: 1
+    maxItems: 2
+    items:
+      - description: tx or combined interrupt
+      - description: rx interrupt
+
+    description: |
+      A variable number of interrupts warrants a description of what conditions
+      affect the number of interrupts. Otherwise, descriptions on standard
+      properties are not necessary.
+
+  interrupt-names:
+    # minItems must be specified here because the default would be 2
+    minItems: 1
+    items:
+      - const: "tx irq"
+      - const: "rx irq"
+
+  # Property names starting with '#' must be quoted
+  '#interrupt-cells':
+    # A simple case where the value must always be '2'.
+    # The core schema handles that this must be a single integer.
+    const: 2
+
+  interrupt-controller: {}
+    # The core checks this is a boolean, so just have to list it here to be
+    # valid for this binding.
+
+  clock-frequency:
+    # The type is set in the core schema. Per device schema only need to set
+    # constraints on the possible values.
+    minimum: 100
+    maximum: 400000
+    # The value that should be used if the property is not present
+    default: 200
+
+  foo-gpios:
+    maxItems: 1
+    description: A connection of the 'foo' gpio line.
+
+  vendor,int-property:
+    description: Vendor specific properties must have a description
+    type: integer # A type is also required
+    enum: [2, 4, 6, 8, 10]
+
+  vendor,bool-property:
+    description: Vendor specific properties must have a description
+    type: boolean
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+
+examples:
+  - |
+    /{
+          compatible = "vendor,soc4-ip", "vendor,soc1-ip";
+          reg = <0x1000 0x80>,
+                <0x3000 0x80>;
+          reg-names = "core", "aux";
+          interrupts = <10>;
+          interrupt-controller;
+    };