From ce891fcada6638c39a0de28f821cfa2b9406440c Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Mon, 13 Jan 2020 11:34:56 +0100 Subject: [PATCH] dm: core: add ofnode and dev function to iterate on node property Add functions to iterate on all property with livetree - dev_read_first_prop - dev_read_next_prop - dev_read_prop_by_prop and - ofnode_get_first_property - ofnode_get_next_property - ofnode_get_property_by_prop And helper: dev_for_each_property For example: struct ofprop property; dev_for_each_property(property, config) { value = dev_read_prop_by_prop(&property, &propname, &len); or: for (res = ofnode_get_first_property(node, &property); !res; res = ofnode_get_next_property(&property)) { value = ofnode_get_property_by_prop(&property, &propname, &len); .... } Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- drivers/core/of_access.c | 32 +++++++++++++++++++ drivers/core/ofnode.c | 48 ++++++++++++++++++++++++++++ drivers/core/read.c | 16 ++++++++++ include/dm/of_access.h | 40 ++++++++++++++++++++++++ include/dm/ofnode.h | 63 ++++++++++++++++++++++++++++++++++++- include/dm/read.h | 67 ++++++++++++++++++++++++++++++++++++++++ test/dm/Makefile | 3 +- test/dm/ofread.c | 50 ++++++++++++++++++++++++++++++ 8 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 test/dm/ofread.c diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index c54baa140a..ea3ee8bd63 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -171,6 +171,38 @@ const void *of_get_property(const struct device_node *np, const char *name, return pp ? pp->value : NULL; } +const struct property *of_get_first_property(const struct device_node *np) +{ + if (!np) + return NULL; + + return np->properties; +} + +const struct property *of_get_next_property(const struct device_node *np, + const struct property *property) +{ + if (!np) + return NULL; + + return property->next; +} + +const void *of_get_property_by_prop(const struct device_node *np, + const struct property *property, + const char **name, + int *lenp) +{ + if (!np || !property) + return NULL; + if (name) + *name = property->name; + if (lenp) + *lenp = property->length; + + return property->value; +} + static const char *of_prop_next_string(struct property *prop, const char *cur) { const void *curv = cur; diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index b0be7cbe19..20871a6815 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -571,6 +571,54 @@ const void *ofnode_get_property(ofnode node, const char *propname, int *lenp) propname, lenp); } +int ofnode_get_first_property(ofnode node, struct ofprop *prop) +{ + prop->node = node; + + if (ofnode_is_np(node)) { + prop->prop = of_get_first_property(ofnode_to_np(prop->node)); + if (!prop->prop) + return -FDT_ERR_NOTFOUND; + } else { + prop->offset = + fdt_first_property_offset(gd->fdt_blob, + ofnode_to_offset(prop->node)); + if (prop->offset < 0) + return prop->offset; + } + + return 0; +} + +int ofnode_get_next_property(struct ofprop *prop) +{ + if (ofnode_is_np(prop->node)) { + prop->prop = of_get_next_property(ofnode_to_np(prop->node), + prop->prop); + if (!prop->prop) + return -FDT_ERR_NOTFOUND; + } else { + prop->offset = fdt_next_property_offset(gd->fdt_blob, + prop->offset); + if (prop->offset < 0) + return prop->offset; + } + + return 0; +} + +const void *ofnode_get_property_by_prop(const struct ofprop *prop, + const char **propname, int *lenp) +{ + if (ofnode_is_np(prop->node)) + return of_get_property_by_prop(ofnode_to_np(prop->node), + prop->prop, propname, lenp); + else + return fdt_getprop_by_offset(gd->fdt_blob, + prop->offset, + propname, lenp); +} + bool ofnode_is_available(ofnode node) { if (ofnode_is_np(node)) diff --git a/drivers/core/read.c b/drivers/core/read.c index ce78f09d28..47b8e03446 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -255,6 +255,22 @@ const void *dev_read_prop(const struct udevice *dev, const char *propname, return ofnode_get_property(dev_ofnode(dev), propname, lenp); } +int dev_read_first_prop(const struct udevice *dev, struct ofprop *prop) +{ + return ofnode_get_first_property(dev_ofnode(dev), prop); +} + +int dev_read_next_prop(struct ofprop *prop) +{ + return ofnode_get_next_property(prop); +} + +const void *dev_read_prop_by_prop(struct ofprop *prop, + const char **propname, int *lenp) +{ + return ofnode_get_property_by_prop(prop, propname, lenp); +} + int dev_read_alias_seq(const struct udevice *dev, int *devnump) { ofnode node = dev_ofnode(dev); diff --git a/include/dm/of_access.h b/include/dm/of_access.h index 92876b3ecb..f95a00d065 100644 --- a/include/dm/of_access.h +++ b/include/dm/of_access.h @@ -103,6 +103,46 @@ struct property *of_find_property(const struct device_node *np, const void *of_get_property(const struct device_node *np, const char *name, int *lenp); +/** + * of_get_first_property()- get to the pointer of the first property + * + * Get pointer to the first property of the node, it is used to iterate + * and read all the property with of_get_next_property_by_prop(). + * + * @np: Pointer to device node + * @return pointer to property or NULL if not found + */ +const struct property *of_get_first_property(const struct device_node *np); + +/** + * of_get_next_property() - get to the pointer of the next property + * + * Get pointer to the next property of the node, it is used to iterate + * and read all the property with of_get_property_by_prop(). + * + * @np: Pointer to device node + * @property: pointer of the current property + * @return pointer to next property or NULL if not found + */ +const struct property *of_get_next_property(const struct device_node *np, + const struct property *property); + +/** + * of_get_property_by_prop() - get a property value of a node property + * + * Get value for the property identified by node and property pointer. + * + * @node: node to read + * @property: pointer of the property to read + * @propname: place to property name on success + * @lenp: place to put length on success + * @return pointer to property value or NULL if error + */ +const void *of_get_property_by_prop(const struct device_node *np, + const struct property *property, + const char **name, + int *lenp); + /** * of_device_is_compatible() - Check if the node matches given constraints * @device: pointer to node diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index ce5e366c06..618fc10390 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -58,6 +58,31 @@ struct ofnode_phandle_args { uint32_t args[OF_MAX_PHANDLE_ARGS]; }; +/** + * ofprop - reference to a property of a device tree node + * + * This struct hold the reference on one property of one node, + * using struct ofnode and an offset within the flat device tree or either + * a pointer to a struct property in the live device tree. + * + * Thus we can reference arguments in both the live tree and the flat tree. + * + * The property reference can also hold a null reference. This corresponds to + * a struct property NULL pointer or an offset of -1. + * + * @node: Pointer to device node + * @offset: Pointer into flat device tree, used for flat tree. + * @prop: Pointer to property, used for live treee. + */ + +struct ofprop { + ofnode node; + union { + int offset; + const struct property *prop; + }; +}; + /** * _ofnode_to_np() - convert an ofnode to a live DT node pointer * @@ -595,7 +620,7 @@ int ofnode_decode_display_timing(ofnode node, int index, struct display_timing *config); /** - * ofnode_get_property()- - get a pointer to the value of a node property + * ofnode_get_property() - get a pointer to the value of a node property * * @node: node to read * @propname: property to read @@ -604,6 +629,42 @@ int ofnode_decode_display_timing(ofnode node, int index, */ const void *ofnode_get_property(ofnode node, const char *propname, int *lenp); +/** + * ofnode_get_first_property()- get the reference of the first property + * + * Get reference to the first property of the node, it is used to iterate + * and read all the property with ofnode_get_property_by_prop(). + * + * @node: node to read + * @prop: place to put argument reference + * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found + */ +int ofnode_get_first_property(ofnode node, struct ofprop *prop); + +/** + * ofnode_get_next_property() - get the reference of the next property + * + * Get reference to the next property of the node, it is used to iterate + * and read all the property with ofnode_get_property_by_prop(). + * + * @prop: reference of current argument and place to put reference of next one + * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found + */ +int ofnode_get_next_property(struct ofprop *prop); + +/** + * ofnode_get_property_by_prop() - get a pointer to the value of a property + * + * Get value for the property identified by the provided reference. + * + * @prop: reference on property + * @propname: If non-NULL, place to property name on success, + * @lenp: If non-NULL, place to put length on success + * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found + */ +const void *ofnode_get_property_by_prop(const struct ofprop *prop, + const char **propname, int *lenp); + /** * ofnode_is_available() - check if a node is marked available * diff --git a/include/dm/read.h b/include/dm/read.h index 77d3bc8db5..03c15b8550 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -494,6 +494,42 @@ int dev_read_phandle(const struct udevice *dev); const void *dev_read_prop(const struct udevice *dev, const char *propname, int *lenp); +/** + * dev_read_first_prop()- get the reference of the first property + * + * Get reference to the first property of the node, it is used to iterate + * and read all the property with dev_read_prop_by_prop(). + * + * @dev: device to check + * @prop: place to put argument reference + * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found + */ +int dev_read_first_prop(const struct udevice *dev, struct ofprop *prop); + +/** + * ofnode_get_next_property() - get the reference of the next property + * + * Get reference to the next property of the node, it is used to iterate + * and read all the property with dev_read_prop_by_prop(). + * + * @prop: reference of current argument and place to put reference of next one + * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found + */ +int dev_read_next_prop(struct ofprop *prop); + +/** + * dev_read_prop_by_prop() - get a pointer to the value of a property + * + * Get value for the property identified by the provided reference. + * + * @prop: reference on property + * @propname: If non-NULL, place to property name on success, + * @lenp: If non-NULL, place to put length on success + * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found + */ +const void *dev_read_prop_by_prop(struct ofprop *prop, + const char **propname, int *lenp); + /** * dev_read_alias_seq() - Get the alias sequence number of a node * @@ -860,6 +896,23 @@ static inline const void *dev_read_prop(const struct udevice *dev, return ofnode_get_property(dev_ofnode(dev), propname, lenp); } +static inline int dev_read_first_prop(const struct udevice *dev, struct ofprop *prop) +{ + return ofnode_get_first_property(dev_ofnode(dev), prop); +} + +static inline int dev_read_next_prop(struct ofprop *prop) +{ + return ofnode_get_next_property(prop); +} + +static inline const void *dev_read_prop_by_prop(struct ofprop *prop, + const char **propname, + int *lenp) +{ + return ofnode_get_property_by_prop(prop, propname, lenp); +} + static inline int dev_read_alias_seq(const struct udevice *dev, int *devnump) { return fdtdec_get_alias_seq(gd->fdt_blob, dev->uclass->uc_drv->name, @@ -941,4 +994,18 @@ static inline int dev_read_alias_highest_id(const char *stem) ofnode_valid(subnode); \ subnode = ofnode_next_subnode(subnode)) +/** + * dev_for_each_property() - Helper function to iterate through property + * + * This creates a for() loop which works through the property in a device's + * device-tree node. + * + * @prop: struct ofprop holding the current property + * @dev: device to use for interation (struct udevice *) + */ +#define dev_for_each_property(prop, dev) \ + for (int ret_prop = dev_read_first_prop(dev, &prop); \ + !ret_prop; \ + ret_prop = dev_read_next_prop(&prop)) + #endif diff --git a/test/dm/Makefile b/test/dm/Makefile index f55874c0f2..6c18fd04ce 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -31,8 +31,9 @@ obj-y += irq.o obj-$(CONFIG_LED) += led.o obj-$(CONFIG_DM_MAILBOX) += mailbox.o obj-$(CONFIG_DM_MMC) += mmc.o -obj-y += ofnode.o obj-y += fdtdec.o +obj-y += ofnode.o +obj-y += ofread.o obj-$(CONFIG_OSD) += osd.o obj-$(CONFIG_DM_VIDEO) += panel.o obj-$(CONFIG_DM_PCI) += pci.o diff --git a/test/dm/ofread.c b/test/dm/ofread.c new file mode 100644 index 0000000000..f2a1382259 --- /dev/null +++ b/test/dm/ofread.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include + +static int dm_test_ofnode_get_property_by_prop(struct unit_test_state *uts) +{ + ofnode node; + struct ofprop prop; + const void *value; + const char *propname; + int res, len, count = 0; + + node = ofnode_path("/cros-ec/flash"); + for (res = ofnode_get_first_property(node, &prop); + !res; + res = ofnode_get_next_property(&prop)) { + value = ofnode_get_property_by_prop(&prop, &propname, &len); + ut_assertnonnull(value); + switch (count) { + case 0: + ut_asserteq_str("image-pos", propname); + ut_asserteq(4, len); + break; + case 1: + ut_asserteq_str("size", propname); + ut_asserteq(4, len); + break; + case 2: + ut_asserteq_str("erase-value", propname); + ut_asserteq(4, len); + break; + case 3: + /* only for platdata */ + ut_asserteq_str("name", propname); + ut_asserteq(6, len); + ut_asserteq_str("flash", value); + break; + default: + break; + } + count++; + } + + return 0; +} +DM_TEST(dm_test_ofnode_get_property_by_prop, + DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); -- 2.25.1