diff --git a/doc/guides/dts/macros.bnf b/doc/guides/dts/macros.bnf index 828a6cd995171..e26dab1ee4546 100644 --- a/doc/guides/dts/macros.bnf +++ b/doc/guides/dts/macros.bnf @@ -43,6 +43,8 @@ node-macro =/ %s"DT_N" path-id %s"_IRQ_NAME_" dt-name node-macro =/ %s"DT_N" path-id %s"_COMPAT_MATCHES_" dt-name ; The node identifier for the node's parent in the devicetree. node-macro =/ %s"DT_N" path-id %s"_PARENT" +; The node identifier for the node's status +node-macro =/ %s"DT_N" path-id %s"_STATUS_" status ; -------------------------------------------------------------------- ; property-macro: a macro related to a node property diff --git a/include/devicetree.h b/include/devicetree.h index 5f72456afb0d8..68397c2be8b67 100644 --- a/include/devicetree.h +++ b/include/devicetree.h @@ -880,6 +880,38 @@ * @{ */ +/** @internal helper for DT_NODE_HAS_STATUS so we can additional + * macro expansion + */ +#define DT_NODE_HAS_STATUS_(node_id, status) \ + IS_ENABLED(DT_CAT(node_id, _STATUS_##status)) + +/** + * @brief Does a devicetree node match a status? + * + * Example devicetree fragment: + * + * n: node { + * compatible = "generic-device"; + * status = "okay"; + * } + * + * Example usages which evaluate to 1: + * + * DT_NODE_HAS_STATUS(DT_NODELABEL(n), okay) + * + * Example usages which evaluate to 0: + * + * DT_NODE_HAS_STATUS(DT_NODELABEL(n), disabled) + * + * @param node_id node identifier + * @param status status value to check for + * @return 1 if the node's status property matches status, + * 0 otherwise. + */ +#define DT_NODE_HAS_STATUS(node_id, status) \ + DT_NODE_HAS_STATUS_(node_id, status) + /** * @brief Does a node identifier refer to a usable node? * @@ -898,7 +930,7 @@ * @return 1 if the node identifier refers to a usable node, * 0 otherwise. */ -#define DT_HAS_NODE_STATUS_OKAY(node_id) IS_ENABLED(DT_CAT(node_id, _EXISTS)) +#define DT_HAS_NODE_STATUS_OKAY(node_id) DT_NODE_HAS_STATUS(node_id, okay) /** * @brief Does the devicetree have any usable nodes with a compatible? diff --git a/scripts/dts/edtlib.py b/scripts/dts/edtlib.py index 1bfb90127b3c4..513c50a18d546 100644 --- a/scripts/dts/edtlib.py +++ b/scripts/dts/edtlib.py @@ -771,7 +771,7 @@ class Node: A list with the nodes that the node directly depends on enabled: - True unless the node has 'status = "disabled"' + True if 'status = "okay"', 'status = "ok"', or no status property. read_only: True if the node has a 'read-only' property, and False otherwise @@ -914,7 +914,8 @@ def depends_on(self): def enabled(self): "See the class docstring" return "status" not in self._node.props or \ - self._node.props["status"].to_string() != "disabled" + self._node.props["status"].to_string() == "okay" or \ + self._node.props["status"].to_string() == "ok" @property def read_only(self): @@ -1087,15 +1088,43 @@ def _init_props(self): self.props = OrderedDict() - if not self._binding: - return + node = self._node + if self._binding: + binding_props = self._binding.get("properties") + else: + binding_props = None # Initialize self.props - if "properties" in self._binding: - for name, options in self._binding["properties"].items(): + if binding_props: + for name, options in binding_props.items(): self._init_prop(name, options) - - self._check_undeclared_props() + self._check_undeclared_props() + else: + common_prop_types = { + "compatible" : "string-array", + "status" : "string", + "reg" : "array", + "reg-names": "string-array", + "label" : "string", + "interrupt" : "array", + "interrupts-extended": "compound", + "interrupt-names": "string-array", + "interrupt-controller": "boolean", + } + + for name in node.props: + if name in common_prop_types: + prop_type = common_prop_types[name] + val = self._prop_val(name, prop_type, False, None) + prop = Property() + prop.node = self + prop.name = name + prop.description = None + prop.val = val + prop.type = prop_type + # We don't set enum_index for "compatible" + prop.enum_index = None + self.props[name] = prop def _init_prop(self, name, options): # _init_props() helper for initializing a single property diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py index f86c2b9aa4c56..55583a25e4a35 100755 --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -59,9 +59,6 @@ def main(): if not node.enabled: out_comment("No node macros: node is disabled") continue - if not node.matching_compat: - out_comment("No node macros: node has no matching binding") - continue write_idents_and_existence(node) write_bus(node) @@ -244,6 +241,7 @@ def write_special_props(node): write_regs(node) write_interrupts(node) write_compatibles(node) + write_status(node) def write_regs(node): @@ -359,6 +357,21 @@ def write_compatibles(node): f"{node.z_path_id}_COMPAT_MATCHES_{str2ident(compat)}", 1) +def write_status(node): + # Writes a macro that we can utilize to test the "status" of a node + # We normalize status = "ok" to "okay", and if there is no "status" + # property we treat that as "okay" + + if "status" in node.props: + status = node.props["status"].val + if status == "ok": + status = "okay" + else: + status = "okay" + + out_dt_define(f"{node.z_path_id}_STATUS_{status}", 1) + + def write_vanilla_props(node): # Writes macros for any and all properties defined in the # "properties" section of the binding for the node. diff --git a/tests/lib/devicetree/app.overlay b/tests/lib/devicetree/app.overlay index 9293918cf4f7a..54b1dfeffa952 100644 --- a/tests/lib/devicetree/app.overlay +++ b/tests/lib/devicetree/app.overlay @@ -75,6 +75,13 @@ status = "disabled"; }; + test_no_status: intc_no_status@0 { + compatible = "vnd,intc"; + reg = <0x0 0x1000>; + interrupt-controller; + #interrupt-cells = <2>; + }; + test_nodelabel: TEST_NODELABEL_ALLCAPS: test_gpio_1: gpio@deadbeef { compatible = "vnd,gpio"; gpio-controller; diff --git a/tests/lib/devicetree/src/main.c b/tests/lib/devicetree/src/main.c index 18c8e4cd16697..cf5d924f66794 100644 --- a/tests/lib/devicetree/src/main.c +++ b/tests/lib/devicetree/src/main.c @@ -200,6 +200,27 @@ static void test_has_compat(void) zassert_equal(compats, 0x3, "as bit array"); } +static void test_has_status(void) +{ + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(test_gpio_1), okay), + 1, "vnd,gpio okay"); + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(test_gpio_1), disabled), + 0, "vnd,gpio not disabled"); + + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(test_no_status), okay), + 1, "vnd,gpio okay"); + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(test_no_status), disabled), + 0, "vnd,gpio not disabled"); + +/* Disabled for now until we generate something for non-"enabled" nodes */ +#if 0 + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(disabled_gpio), disabled), + 1, "vnd,disabled-compat disabled"); + zassert_equal(DT_NODE_HAS_STATUS(DT_NODELABEL(disabled_gpio), okay), + 0, "vnd,disabled-compat not okay"); +#endif +} + #define TEST_I2C_DEV DT_PATH(test, i2c_11112222, test_i2c_dev_10) #define TEST_I2C_BUS DT_BUS(TEST_I2C_DEV) @@ -1381,6 +1402,7 @@ void test_main(void) ztest_unit_test(test_inst_checks), ztest_unit_test(test_has_nodelabel), ztest_unit_test(test_has_compat), + ztest_unit_test(test_has_status), ztest_unit_test(test_bus), ztest_unit_test(test_reg), ztest_unit_test(test_irq),