From 247970978d3de3e46537550e83137df586d9dee9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 26 Sep 2023 08:14:37 -0600 Subject: dm: core: Reverse the argument order in ofnode_copy_props() Follow the order used by memcpy() as it may be less confusing. Signed-off-by: Simon Glass --- include/dm/ofnode.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/dm') diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 06c969c61fe..32917f66155 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -1598,7 +1598,7 @@ int ofnode_add_subnode(ofnode parent, const char *name, ofnode *nodep); /** * ofnode_copy_props() - copy all properties from one node to another * - * Makes a copy of all properties from the source note in the destination node. + * Makes a copy of all properties from the source node to the destination node. * Existing properties in the destination node remain unchanged, except that * any with the same name are overwritten, including changing the size of the * property. @@ -1606,9 +1606,9 @@ int ofnode_add_subnode(ofnode parent, const char *name, ofnode *nodep); * For livetree, properties are copied / allocated, so the source tree does not * need to be present afterwards. * + * @dst: Destination node to write properties to * @src: Source node to read properties from - * @dst: Destination node to write properties too */ -int ofnode_copy_props(ofnode src, ofnode dst); +int ofnode_copy_props(ofnode dst, ofnode src); #endif -- cgit v1.3.1 From e0c3c21d8ba1a0abbb7effee6c5a952f3e65a03d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 26 Sep 2023 08:14:40 -0600 Subject: dm: core: Add a function to create an empty tree Provide a function to create a new, empty tree. Signed-off-by: Simon Glass --- drivers/core/ofnode.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++---- include/dm/ofnode.h | 9 +++++++++ include/of_live.h | 8 ++++++++ lib/of_live.c | 19 +++++++++++++++++ test/dm/ofnode.c | 16 +++++++++++++++ 5 files changed, 104 insertions(+), 4 deletions(-) (limited to 'include/dm') diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 515396c62f4..d2bdb8b9af1 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -47,6 +47,17 @@ static int oftree_find(const void *fdt) return -1; } +static int check_tree_count(void) +{ + if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) { + log_warning("Too many registered device trees (max %d)\n", + CONFIG_OFNODE_MULTI_TREE_MAX); + return -E2BIG; + } + + return 0; +} + static oftree oftree_ensure(void *fdt) { oftree tree; @@ -69,11 +80,8 @@ static oftree oftree_ensure(void *fdt) if (gd->flags & GD_FLG_RELOC) { i = oftree_find(fdt); if (i == -1) { - if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) { - log_warning("Too many registered device trees (max %d)\n", - CONFIG_OFNODE_MULTI_TREE_MAX); + if (check_tree_count()) return oftree_null(); - } /* register the new tree */ i = oftree_count++; @@ -92,6 +100,41 @@ static oftree oftree_ensure(void *fdt) return tree; } +int oftree_new(oftree *treep) +{ + oftree tree = oftree_null(); + int ret; + + if (of_live_active()) { + struct device_node *root; + + ret = of_live_create_empty(&root); + if (ret) + return log_msg_ret("liv", ret); + tree = oftree_from_np(root); + } else { + const int size = 1024; + void *fdt; + + ret = check_tree_count(); + if (ret) + return log_msg_ret("fla", ret); + + /* register the new tree with a small size */ + fdt = malloc(size); + if (!fdt) + return log_msg_ret("fla", -ENOMEM); + ret = fdt_create_empty_tree(fdt, size); + if (ret) + return log_msg_ret("fla", -EINVAL); + oftree_list[oftree_count++] = fdt; + tree.fdt = fdt; + } + *treep = tree; + + return 0; +} + void oftree_dispose(oftree tree) { if (of_live_active()) @@ -193,6 +236,11 @@ static inline int oftree_find(const void *fdt) return 0; } +int oftree_new(oftree *treep) +{ + return -ENOSYS; +} + #endif /* OFNODE_MULTI_TREE */ /** diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 32917f66155..0b96ab34ede 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -127,6 +127,15 @@ static inline ofnode noffset_to_ofnode(ofnode other_node, int of_offset) #endif /* OFNODE_MULTI_TREE */ +/** + * oftree_new() - Create a new, empty tree + * + * @treep: Returns a pointer to the tree, on success + * Returns: 0 on success, -ENOMEM if out of memory, -E2BIG if !OF_LIVE and + * there are too many (flattrees) already + */ +int oftree_new(oftree *treep); + /** * ofnode_to_np() - convert an ofnode to a live DT node pointer * diff --git a/include/of_live.h b/include/of_live.h index 05e86ac06b1..81cb9bd13e2 100644 --- a/include/of_live.h +++ b/include/of_live.h @@ -46,4 +46,12 @@ int unflatten_device_tree(const void *blob, struct device_node **mynodes); */ void of_live_free(struct device_node *root); +/** + * of_live_create_empty() - Create a new, empty tree + * + * @rootp: Returns the root node of the created tree + * Return: 0 if OK, -ENOMEM if out of memory + */ +int of_live_create_empty(struct device_node **rootp); + #endif diff --git a/lib/of_live.c b/lib/of_live.c index 25f7af61061..e4eee385547 100644 --- a/lib/of_live.c +++ b/lib/of_live.c @@ -336,3 +336,22 @@ void of_live_free(struct device_node *root) /* the tree is stored as a contiguous block of memory */ free(root); } + +int of_live_create_empty(struct device_node **rootp) +{ + struct device_node *root; + + root = calloc(1, sizeof(struct device_node)); + if (!root) + return -ENOMEM; + root->name = strdup(""); + if (!root->name) { + free(root); + return -ENOMEM; + } + root->type = ""; + root->full_name = ""; + *rootp = root; + + return 0; +} diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index 3bf97761d1e..594116e3c04 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -1346,3 +1346,19 @@ static int dm_test_livetree_ensure(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_livetree_ensure, UT_TESTF_SCAN_FDT); + +static int dm_test_oftree_new(struct unit_test_state *uts) +{ + ofnode node, subnode, check; + oftree tree; + + ut_assertok(oftree_new(&tree)); + node = oftree_root(tree); + ut_assert(ofnode_valid(node)); + ut_assertok(ofnode_add_subnode(node, "edmund", &subnode)); + check = ofnode_find_subnode(node, "edmund"); + ut_asserteq(check.of_offset, subnode.of_offset); + + return 0; +} +DM_TEST(dm_test_oftree_new, UT_TESTF_SCAN_FDT); -- cgit v1.3.1 From c15862ffdd5f7797338808cf7645786109bcddc3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 26 Sep 2023 08:14:41 -0600 Subject: dm: core: Add a way to copy a node Add a function to copy a node to another place under a new name. This is useful at least for testing, since copying a test node with existing properties is easier than writing the code to generate it all afresh. Signed-off-by: Simon Glass --- drivers/core/ofnode.c | 20 ++++++++++++++++ include/dm/ofnode.h | 15 ++++++++++++ test/dm/ofnode.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) (limited to 'include/dm') diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index d2bdb8b9af1..403ee06ad94 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -1802,3 +1802,23 @@ int ofnode_copy_props(ofnode dst, ofnode src) return 0; } + +int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src, + ofnode *nodep) +{ + ofnode node; + int ret; + + ret = ofnode_add_subnode(dst_parent, name, &node); + if (ret) { + if (ret == -EEXIST) + *nodep = node; + return log_msg_ret("add", ret); + } + ret = ofnode_copy_props(node, src); + if (ret) + return log_msg_ret("cpy", ret); + *nodep = node; + + return 0; +} diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 0b96ab34ede..7eb04accd62 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -1620,4 +1620,19 @@ int ofnode_add_subnode(ofnode parent, const char *name, ofnode *nodep); */ int ofnode_copy_props(ofnode dst, ofnode src); +/** + * ofnode_copy_node() - Copy a node to another place + * + * If a node with this name already exists in dst_parent, this returns an + * .error + * + * @dst_parent: Parent of the newly copied node + * @name: Name to give the new node + * @src: Source node to copy + * @nodep: Returns the new node, or the existing node if there is one + * Return: 0 if OK, -EEXIST if dst_parent already has a node with this parent + */ +int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src, + ofnode *nodep); + #endif diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index 594116e3c04..5459a9afbb9 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -1362,3 +1362,66 @@ static int dm_test_oftree_new(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_oftree_new, UT_TESTF_SCAN_FDT); + +static int check_copy_node(struct unit_test_state *uts, ofnode dst, ofnode src, + ofnode *nodep) +{ + u32 reg[2], val; + ofnode node; + + ut_assertok(ofnode_copy_node(dst, "copy-test", src, &node)); + + ut_assertok(ofnode_read_u32(node, "ping-expect", &val)); + ut_asserteq(3, val); + + ut_asserteq_str("denx,u-boot-fdt-test", + ofnode_read_string(node, "compatible")); + + /* check that a property with the same name is overwritten */ + ut_assertok(ofnode_read_u32_array(node, "reg", reg, ARRAY_SIZE(reg))); + ut_asserteq(3, reg[0]); + ut_asserteq(1, reg[1]); + + /* reset the compatible so the live tree does not change */ + ut_assertok(ofnode_write_string(node, "compatible", "nothing")); + *nodep = node; + + return 0; +} + +static int dm_test_ofnode_copy_node(struct unit_test_state *uts) +{ + ofnode src, dst, node, try; + + /* + * These nodes are chosen so that the src node is before the destination + * node in the tree. This doesn't matter with livetree, but with + * flattree any attempt to insert a property earlier in the tree will + * mess up the offsets after it. + */ + src = ofnode_path("/b-test"); + dst = ofnode_path("/some-bus"); + + ut_assertok(check_copy_node(uts, dst, src, &node)); + + /* check trying to copy over an existing node */ + ut_asserteq(-EEXIST, ofnode_copy_node(dst, "copy-test", src, &try)); + ut_asserteq(try.of_offset, node.of_offset); + + return 0; +} +DM_TEST(dm_test_ofnode_copy_node, UT_TESTF_SCAN_FDT); + +/* test ofnode_copy_node() with the 'other' tree */ +static int dm_test_ofnode_copy_node_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + ofnode src, dst, node; + + src = ofnode_path("/b-test"); + dst = oftree_path(otree, "/node/subnode2"); + ut_assertok(check_copy_node(uts, dst, src, &node)); + + return 0; +} +DM_TEST(dm_test_ofnode_copy_node_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); -- cgit v1.3.1 From 67fb2159fb3438359fa0fc3f8cb491ffe8d57c0f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 26 Sep 2023 08:14:42 -0600 Subject: dm: core: Add a way to delete a node Add a function to delete a node in an existing tree. Signed-off-by: Simon Glass --- drivers/core/of_access.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/core/ofnode.c | 23 +++++++++++++++++ include/dm/of_access.h | 18 ++++++++++++++ include/dm/ofnode.h | 13 ++++++++++ test/dm/ofnode.c | 31 +++++++++++++++++++++++ 5 files changed, 150 insertions(+) (limited to 'include/dm') diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index 1bb4d8eab70..c8db743f529 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -1040,3 +1040,68 @@ int of_add_subnode(struct device_node *parent, const char *name, int len, return 0; } + +int __of_remove_property(struct device_node *np, struct property *prop) +{ + struct property **next; + + for (next = &np->properties; *next; next = &(*next)->next) { + if (*next == prop) + break; + } + if (!*next) + return -ENODEV; + + /* found the node */ + *next = prop->next; + + return 0; +} + +int of_remove_property(struct device_node *np, struct property *prop) +{ + int rc; + + mutex_lock(&of_mutex); + + rc = __of_remove_property(np, prop); + + mutex_unlock(&of_mutex); + + return rc; +} + +int of_remove_node(struct device_node *to_remove) +{ + struct device_node *parent = to_remove->parent; + struct device_node *np, *prev; + + if (!parent) + return -EPERM; + prev = NULL; + __for_each_child_of_node(parent, np) { + if (np == to_remove) + break; + prev = np; + } + if (!np) + return -EFAULT; + + /* if there is a previous node, link it to this one's sibling */ + if (prev) + prev->sibling = np->sibling; + else + parent->child = np->sibling; + + /* + * don't free it, since if this is an unflattened tree, all the memory + * was alloced in one block; this pointer will be somewhere in the + * middle of that + * + * TODO(sjg@chromium.org): Consider marking nodes as 'allocated'? + * + * free(np); + */ + + return 0; +} diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 403ee06ad94..a5efedf6af3 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -1779,6 +1779,29 @@ int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep) return ret; /* 0 or -EEXIST */ } +int ofnode_delete(ofnode *nodep) +{ + ofnode node = *nodep; + int ret; + + assert(ofnode_valid(node)); + if (ofnode_is_np(node)) { + ret = of_remove_node(ofnode_to_np(node)); + } else { + void *fdt = ofnode_to_fdt(node); + int offset = ofnode_to_offset(node); + + ret = fdt_del_node(fdt, offset); + if (ret) + ret = -EFAULT; + } + if (ret) + return ret; + *nodep = ofnode_null(); + + return 0; +} + int ofnode_copy_props(ofnode dst, ofnode src) { struct ofprop prop; diff --git a/include/dm/of_access.h b/include/dm/of_access.h index 9361d0a87bf..de740d44674 100644 --- a/include/dm/of_access.h +++ b/include/dm/of_access.h @@ -597,4 +597,22 @@ int of_write_prop(struct device_node *np, const char *propname, int len, int of_add_subnode(struct device_node *node, const char *name, int len, struct device_node **subnodep); +/** + * of_remove_property() - Remove a property from a node + * + * @np: Node to remove from + * @prop: Pointer to property to remove + * Return 0 if OK, -ENODEV if the property could not be found in the node + */ +int of_remove_property(struct device_node *np, struct property *prop); + +/** + * of_remove_node() - Remove a node from the tree + * + * @to_remove: Node to remove + * Return: 0 if OK, -EPERM if it is the root node (wWhich cannot be removed), + * -ENOENT if the tree is broken (to_remove is not a child of its parent) + */ +int of_remove_node(struct device_node *to_remove); + #endif diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 7eb04accd62..f1ee02cd837 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -1635,4 +1635,17 @@ int ofnode_copy_props(ofnode dst, ofnode src); int ofnode_copy_node(ofnode dst_parent, const char *name, ofnode src, ofnode *nodep); +/** + * ofnode_delete() - Delete a node + * + * Delete a node from the tree + * + * @nodep: Pointer to node to delete (set to ofnode_null() on success) + * Return: 0 if OK, -ENOENT if the node does not exist, -EPERM if it is the root + * node (wWhich cannot be removed), -EFAULT if the tree is broken (to_remove is + * not a child of its parent), + * + */ +int ofnode_delete(ofnode *nodep); + #endif diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index 5459a9afbb9..845cded449a 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -1425,3 +1425,34 @@ static int dm_test_ofnode_copy_node_ot(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_ofnode_copy_node_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); + +static int dm_test_ofnode_delete(struct unit_test_state *uts) +{ + ofnode node; + + /* + * At present the livetree is not restored after changes made in tests. + * See test_pre_run() for how this is done with the other FDT and + * dm_test_pre_run() where it sets up the root-tree pointer. So use + * nodes which don't matter to other tests. + * + * We could fix this by detecting livetree changes and regenerating it + * before the next test if needed. + */ + node = ofnode_path("/leds/iracibble"); + ut_assert(ofnode_valid(node)); + ut_assertok(ofnode_delete(&node)); + ut_assert(!ofnode_valid(node)); + ut_assert(!ofnode_valid(ofnode_path("/leds/iracibble"))); + + node = ofnode_path("/leds/default_on"); + ut_assert(ofnode_valid(node)); + ut_assertok(ofnode_delete(&node)); + ut_assert(!ofnode_valid(node)); + ut_assert(!ofnode_valid(ofnode_path("/leds/default_on"))); + + ut_asserteq(2, ofnode_get_child_count(ofnode_path("/leds"))); + + return 0; +} +DM_TEST(dm_test_ofnode_delete, UT_TESTF_SCAN_FDT); -- cgit v1.3.1 From 62b1db33778611a3023d1e3a98e869b495edc9ca Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 26 Sep 2023 08:14:43 -0600 Subject: dm: core: Add a way to convert a devicetree to a dtb Add a way to flatten a devicetree into binary form. For livetree this involves generating the devicetree using fdt_property() and other calls. For flattree it simply involves providing the buffer containing the tree. Signed-off-by: Simon Glass --- drivers/core/ofnode.c | 18 ++++++++ include/dm/ofnode.h | 13 ++++++ include/of_live.h | 10 +++++ lib/of_live.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/dm/ofnode.c | 24 ++++++++++ 5 files changed, 187 insertions(+) (limited to 'include/dm') diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index a5efedf6af3..39ba480c8f8 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -243,6 +243,24 @@ int oftree_new(oftree *treep) #endif /* OFNODE_MULTI_TREE */ +int oftree_to_fdt(oftree tree, struct abuf *buf) +{ + int ret; + + if (of_live_active()) { + ret = of_live_flatten(ofnode_to_np(oftree_root(tree)), buf); + if (ret) + return log_msg_ret("flt", ret); + } else { + void *fdt = oftree_lookup_fdt(tree); + + abuf_init(buf); + abuf_set(buf, fdt, fdt_totalsize(fdt)); + } + + return 0; +} + /** * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree) * diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index f1ee02cd837..a8605fb718b 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -17,6 +17,7 @@ /* Enable checks to protect against invalid calls */ #undef OF_CHECKS +struct abuf; struct resource; #include @@ -136,6 +137,18 @@ static inline ofnode noffset_to_ofnode(ofnode other_node, int of_offset) */ int oftree_new(oftree *treep); +/** + * oftree_to_fdt() - Convert an oftree to a flat FDT + * + * @tree: tree to flatten (if livetree) or copy (if not) + * @buf: Returns inited buffer containing the newly created flat tree. Note + * that for flat tree the buffer is not allocated. In either case the caller + * must call abut_uninit() to free any memory used by @buf + * Return: 0 on success, -ENOMEM if out of memory, other -ve value for any other + * error + */ +int oftree_to_fdt(oftree tree, struct abuf *buf); + /** * ofnode_to_np() - convert an ofnode to a live DT node pointer * diff --git a/include/of_live.h b/include/of_live.h index 81cb9bd13e2..67bd5f02c74 100644 --- a/include/of_live.h +++ b/include/of_live.h @@ -9,6 +9,7 @@ #ifndef _OF_LIVE_H #define _OF_LIVE_H +struct abuf; struct device_node; /** @@ -54,4 +55,13 @@ void of_live_free(struct device_node *root); */ int of_live_create_empty(struct device_node **rootp); +/** + * of_live_flatten() - Create an FDT from a hierarchical tree + * + * @root: Root node of tree to convert + * @buf: Buffer to return the tree (inited by this function) + * Return: 0 if OK, -ENOMEM if out of memory + */ +int of_live_flatten(const struct device_node *root, struct abuf *buf); + #endif diff --git a/lib/of_live.c b/lib/of_live.c index e4eee385547..812c488f606 100644 --- a/lib/of_live.c +++ b/lib/of_live.c @@ -8,13 +8,21 @@ * Copyright (c) 2017 Google, Inc */ +#define LOG_CATEGORY LOGC_DT + #include +#include #include #include #include #include #include #include +#include + +enum { + BUF_STEP = SZ_64K, +}; static void *unflatten_dt_alloc(void **mem, unsigned long size, unsigned long align) @@ -355,3 +363,117 @@ int of_live_create_empty(struct device_node **rootp) return 0; } + +static int check_space(int ret, struct abuf *buf) +{ + if (ret == -FDT_ERR_NOSPACE) { + if (!abuf_realloc_inc(buf, BUF_STEP)) + return log_msg_ret("spc", -ENOMEM); + ret = fdt_resize(abuf_data(buf), abuf_data(buf), + abuf_size(buf)); + if (ret) + return log_msg_ret("res", -EFAULT); + + return -EAGAIN; + } + + return 0; +} + +/** + * flatten_node() - Write out the node and its properties into a flat tree + */ +static int flatten_node(struct abuf *buf, const struct device_node *node) +{ + const struct device_node *np; + const struct property *pp; + int ret; + + ret = fdt_begin_node(abuf_data(buf), node->name); + ret = check_space(ret, buf); + if (ret == -EAGAIN) { + ret = fdt_begin_node(abuf_data(buf), node->name); + if (ret) { + log_debug("Internal error a %d\n", ret); + return -EFAULT; + } + } + if (ret) + return log_msg_ret("beg", ret); + + /* First write out the properties */ + for (pp = node->properties; !ret && pp; pp = pp->next) { + ret = fdt_property(abuf_data(buf), pp->name, pp->value, + pp->length); + ret = check_space(ret, buf); + if (ret == -EAGAIN) { + ret = fdt_property(abuf_data(buf), pp->name, pp->value, + pp->length); + } + } + + /* Next write out the subnodes */ + for (np = node->child; np; np = np->sibling) { + ret = flatten_node(buf, np); + if (ret) + return log_msg_ret("sub", ret); + } + + ret = fdt_end_node(abuf_data(buf)); + ret = check_space(ret, buf); + if (ret == -EAGAIN) { + ret = fdt_end_node(abuf_data(buf)); + if (ret) { + log_debug("Internal error b %d\n", ret); + return -EFAULT; + } + } + if (ret) + return log_msg_ret("end", ret); + + return 0; +} + +int of_live_flatten(const struct device_node *root, struct abuf *buf) +{ + int ret; + + abuf_init(buf); + if (!abuf_realloc(buf, BUF_STEP)) + return log_msg_ret("ini", -ENOMEM); + + ret = fdt_create(abuf_data(buf), abuf_size(buf)); + if (!ret) + ret = fdt_finish_reservemap(abuf_data(buf)); + if (ret) { + log_debug("Failed to start FDT (err=%d)\n", ret); + return log_msg_ret("sta", -EINVAL); + } + + ret = flatten_node(buf, root); + if (ret) + return log_msg_ret("flt", ret); + + ret = fdt_finish(abuf_data(buf)); + ret = check_space(ret, buf); + if (ret == -EAGAIN) { + ret = fdt_finish(abuf_data(buf)); + if (ret) { + log_debug("Internal error c %d\n", ret); + return -EFAULT; + } + } + if (ret) + return log_msg_ret("fin", ret); + + ret = fdt_pack(abuf_data(buf)); + if (ret) { + log_debug("Failed to pack (err=%d)\n", ret); + return log_msg_ret("pac", -EFAULT); + } + + if (!abuf_realloc(buf, fdt_totalsize(abuf_data(buf)))) + return log_msg_ret("abu", -EFAULT); + + return 0; +} diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index 845cded449a..ceeb8e57791 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #include #include @@ -1456,3 +1458,25 @@ static int dm_test_ofnode_delete(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_ofnode_delete, UT_TESTF_SCAN_FDT); + +static int dm_test_oftree_to_fdt(struct unit_test_state *uts) +{ + oftree tree, check; + struct abuf buf, buf2; + + tree = oftree_default(); + ut_assertok(oftree_to_fdt(tree, &buf)); + ut_assert(abuf_size(&buf) > SZ_16K); + + /* convert it back to a tree and see if it looks OK */ + check = oftree_from_fdt(abuf_data(&buf)); + ut_assert(oftree_valid(check)); + + ut_assertok(oftree_to_fdt(check, &buf2)); + ut_assert(abuf_size(&buf2) > SZ_16K); + ut_asserteq(abuf_size(&buf), abuf_size(&buf2)); + ut_asserteq_mem(abuf_data(&buf), abuf_data(&buf2), abuf_size(&buf)); + + return 0; +} +DM_TEST(dm_test_oftree_to_fdt, UT_TESTF_SCAN_FDT); -- cgit v1.3.1 From d9216c8683fced4cbf6d437b4357c9368bf1bf86 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 26 Sep 2023 08:14:44 -0600 Subject: dm: core: Support writing a boolean Add functions to write a boolean property. This involves deleting it if the value is false. Add a new ofnode_has_property() as well. Add a comment about the behaviour of of_read_property() when the property value is empty. Signed-off-by: Simon Glass --- drivers/core/ofnode.c | 36 ++++++++++++++++++++++++++++++++++-- include/dm/ofnode.h | 32 +++++++++++++++++++++++++++++++- test/dm/ofnode.c | 25 +++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 3 deletions(-) (limited to 'include/dm') diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 39ba480c8f8..4dcb3dd1c03 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -491,12 +491,12 @@ u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def) bool ofnode_read_bool(ofnode node, const char *propname) { - const void *prop; + bool prop; assert(ofnode_valid(node)); debug("%s: %s: ", __func__, propname); - prop = ofnode_get_property(node, propname, NULL); + prop = ofnode_has_property(node, propname); debug("%s\n", prop ? "true" : "false"); @@ -1168,6 +1168,14 @@ const void *ofnode_get_property(ofnode node, const char *propname, int *lenp) propname, lenp); } +bool ofnode_has_property(ofnode node, const char *propname) +{ + if (ofnode_is_np(node)) + return of_find_property(ofnode_to_np(node), propname, NULL); + else + return ofnode_get_property(node, propname, NULL); +} + int ofnode_first_property(ofnode node, struct ofprop *prop) { prop->node = node; @@ -1616,6 +1624,30 @@ int ofnode_write_u32(ofnode node, const char *propname, u32 value) return ofnode_write_prop(node, propname, val, sizeof(value), false); } +int ofnode_write_bool(ofnode node, const char *propname, bool value) +{ + if (value) + return ofnode_write_prop(node, propname, NULL, 0, false); + else + return ofnode_delete_prop(node, propname); +} + +int ofnode_delete_prop(ofnode node, const char *propname) +{ + if (ofnode_is_np(node)) { + struct property *prop; + int len; + + prop = of_find_property(ofnode_to_np(node), propname, &len); + if (prop) + return of_remove_property(ofnode_to_np(node), prop); + return 0; + } else { + return fdt_delprop(ofnode_to_fdt(node), ofnode_to_offset(node), + propname); + } +} + int ofnode_set_enabled(ofnode node, bool value) { assert(ofnode_valid(node)); diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index a8605fb718b..ebea29d32af 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -1037,10 +1037,19 @@ int ofnode_decode_panel_timing(ofnode node, * @node: node to read * @propname: property to read * @lenp: place to put length on success - * Return: pointer to property, or NULL if not found + * Return: pointer to property value, or NULL if not found or empty */ const void *ofnode_get_property(ofnode node, const char *propname, int *lenp); +/** + * ofnode_has_property() - check if a node has a named property + * + * @node: node to read + * @propname: property to read + * Return: true if the property exists in the node, false if not + */ +bool ofnode_has_property(ofnode node, const char *propname); + /** * ofnode_first_property()- get the reference of the first property * @@ -1452,6 +1461,27 @@ int ofnode_write_string(ofnode node, const char *propname, const char *value); */ int ofnode_write_u32(ofnode node, const char *propname, u32 value); +/** + * ofnode_write_bool() - Set a boolean property of an ofnode + * + * This either adds or deleted a property with a zero-length value + * + * @node: The node for whose string property should be set + * @propname: The name of the string property to set + * @value: The new value of the boolean property + * Return: 0 if successful, -ve on error + */ +int ofnode_write_bool(ofnode node, const char *propname, bool value); + +/** + * ofnode_delete_prop() - Delete a property + * + * @node: Node containing the property to delete + * @propname: Name of property to delete + * Return: 0 if successful, -ve on error + */ +int ofnode_delete_prop(ofnode node, const char *propname); + /** * ofnode_set_enabled() - Enable or disable a device tree node given by its * ofnode diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index ceeb8e57791..9477f791d64 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -1480,3 +1480,28 @@ static int dm_test_oftree_to_fdt(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_oftree_to_fdt, UT_TESTF_SCAN_FDT); + +/* test ofnode_read_bool() and ofnode_write_bool() */ +static int dm_test_bool(struct unit_test_state *uts) +{ + const char *propname = "missing-bool-value"; + ofnode node; + + node = ofnode_path("/a-test"); + ut_assert(ofnode_read_bool(node, "bool-value")); + ut_assert(!ofnode_read_bool(node, propname)); + ut_assert(!ofnode_has_property(node, propname)); + + ut_assertok(ofnode_write_bool(node, propname, true)); + ut_assert(ofnode_read_bool(node, propname)); + ut_assert(ofnode_has_property(node, propname)); + ut_assert(ofnode_read_bool(node, "bool-value")); + + ut_assertok(ofnode_write_bool(node, propname, false)); + ut_assert(!ofnode_read_bool(node, propname)); + ut_assert(!ofnode_has_property(node, propname)); + ut_assert(ofnode_read_bool(node, "bool-value")); + + return 0; +} +DM_TEST(dm_test_bool, UT_TESTF_SCAN_FDT); -- cgit v1.3.1 From 7071c82bdc55ed5d7955d8e1682b7c80af5659b5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 26 Sep 2023 08:14:45 -0600 Subject: dm: core: Support writing a 64-bit value Add support for writing a single 64-bit value into a property. Repurpose the existing tests to handle this case too. Signed-off-by: Simon Glass --- drivers/core/ofnode.c | 17 ++++++++++++++++- include/dm/ofnode.h | 10 ++++++++++ test/dm/ofnode.c | 15 +++++++++++++-- 3 files changed, 39 insertions(+), 3 deletions(-) (limited to 'include/dm') diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 4dcb3dd1c03..18d2eb0f118 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -1621,7 +1621,22 @@ int ofnode_write_u32(ofnode node, const char *propname, u32 value) return -ENOMEM; *val = cpu_to_fdt32(value); - return ofnode_write_prop(node, propname, val, sizeof(value), false); + return ofnode_write_prop(node, propname, val, sizeof(value), true); +} + +int ofnode_write_u64(ofnode node, const char *propname, u64 value) +{ + fdt64_t *val; + + assert(ofnode_valid(node)); + + log_debug("%s = %llx", propname, (unsigned long long)value); + val = malloc(sizeof(*val)); + if (!val) + return -ENOMEM; + *val = cpu_to_fdt64(value); + + return ofnode_write_prop(node, propname, val, sizeof(value), true); } int ofnode_write_bool(ofnode node, const char *propname, bool value) diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index ebea29d32af..ef1437cc556 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -1461,6 +1461,16 @@ int ofnode_write_string(ofnode node, const char *propname, const char *value); */ int ofnode_write_u32(ofnode node, const char *propname, u32 value); +/** + * ofnode_write_u64() - Set an integer property of an ofnode + * + * @node: The node for whose string property should be set + * @propname: The name of the string property to set + * @value: The new value of the 64-bit integer property + * Return: 0 if successful, -ve on error + */ +int ofnode_write_u64(ofnode node, const char *propname, u64 value); + /** * ofnode_write_bool() - Set a boolean property of an ofnode * diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index 9477f791d64..e078a9755a8 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -1009,7 +1009,8 @@ static int dm_test_ofnode_u32_array(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_u32_array, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); -static int dm_test_ofnode_read_u64(struct unit_test_state *uts) +/* test ofnode_read_u64() and ofnode_write_u64() */ +static int dm_test_ofnode_u64(struct unit_test_state *uts) { ofnode node; u64 val; @@ -1018,6 +1019,10 @@ static int dm_test_ofnode_read_u64(struct unit_test_state *uts) ut_assert(ofnode_valid(node)); ut_assertok(ofnode_read_u64(node, "int64-value", &val)); ut_asserteq_64(0x1111222233334444, val); + ut_assertok(ofnode_write_u64(node, "new-int64-value", 0x9876543210)); + ut_assertok(ofnode_read_u64(node, "new-int64-value", &val)); + ut_asserteq_64(0x9876543210, val); + ut_asserteq(-EINVAL, ofnode_read_u64(node, "missing", &val)); ut_assertok(ofnode_read_u64_index(node, "int64-array", 0, &val)); @@ -1028,9 +1033,15 @@ static int dm_test_ofnode_read_u64(struct unit_test_state *uts) ofnode_read_u64_index(node, "int64-array", 2, &val)); ut_asserteq(-EINVAL, ofnode_read_u64_index(node, "missing", 0, &val)); + ut_assertok(ofnode_write_u64(node, "int64-array", 0x9876543210)); + ut_assertok(ofnode_read_u64_index(node, "int64-array", 0, &val)); + ut_asserteq_64(0x9876543210, val); + ut_asserteq(-EOVERFLOW, + ofnode_read_u64_index(node, "int64-array", 1, &val)); + return 0; } -DM_TEST(dm_test_ofnode_read_u64, UT_TESTF_SCAN_FDT); +DM_TEST(dm_test_ofnode_u64, UT_TESTF_SCAN_FDT); static int dm_test_ofnode_add_subnode(struct unit_test_state *uts) { -- cgit v1.3.1 From 61fc132051740e0378a5e71f3db6cb1581e970fe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 26 Sep 2023 08:14:57 -0600 Subject: dm: core: Tweak device_is_on_pci_bus() for code size This function cannot return true if PCI is not enabled, since no PCI devices will have been bound. Add a check for this to reduce code size where it is used. Signed-off-by: Simon Glass --- include/dm/device.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/dm') diff --git a/include/dm/device.h b/include/dm/device.h index e54cb6bca41..add67f9ec06 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -1005,7 +1005,8 @@ int dev_enable_by_path(const char *path); */ static inline bool device_is_on_pci_bus(const struct udevice *dev) { - return dev->parent && device_get_uclass_id(dev->parent) == UCLASS_PCI; + return CONFIG_IS_ENABLED(PCI) && dev->parent && + device_get_uclass_id(dev->parent) == UCLASS_PCI; } /** -- cgit v1.3.1 From f69d3d6d10b15872a279aeb10b7c522627aff6c2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 26 Sep 2023 08:14:58 -0600 Subject: pci: serial: Support reading PCI-register size with base The PCI helpers read only the base address for a PCI region. In some cases the size is needed as well, e.g. to pass along to a driver which needs to know the size of its register area. Update the functions to allow the size to be returned. For serial, record the information and provided it with the serial_info() call. A limitation still exists in that the size is not available when OF_LIVE is enabled, so take account of that in the tests. Signed-off-by: Simon Glass --- arch/sandbox/dts/test.dts | 6 +++--- drivers/core/fdtaddr.c | 6 +++--- drivers/core/ofnode.c | 11 ++++++++--- drivers/core/read.c | 6 ++++-- drivers/core/util.c | 2 +- drivers/pci/pci-uclass.c | 2 +- drivers/pci/pci_mvebu.c | 3 ++- drivers/pci/pci_tegra.c | 2 +- drivers/pci/pcie_mediatek.c | 4 ++-- drivers/serial/ns16550.c | 16 +++++++++++----- include/dm/fdtaddr.h | 3 ++- include/dm/ofnode.h | 4 +++- include/dm/read.h | 8 +++++--- include/ns16550.h | 4 +++- include/serial.h | 2 ++ test/dm/pci.c | 14 ++++++++++---- 16 files changed, 61 insertions(+), 32 deletions(-) (limited to 'include/dm') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 962b9ebcbf6..6abce9e3963 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -1123,8 +1123,8 @@ pci@1,0 { compatible = "pci-generic"; /* reg 0 is at 0x14, using FDT_PCI_SPACE_MEM32 */ - reg = <0x02000814 0 0 0 0 - 0x01000810 0 0 0 0>; + reg = <0x02000814 0 0 0x80 0 + 0x01000810 0 0 0xc0 0>; sandbox,emul = <&swap_case_emul0_1>; }; p2sb-pci@2,0 { @@ -1151,7 +1151,7 @@ pci@1f,0 { compatible = "pci-generic"; /* reg 0 is at 0x10, using FDT_PCI_SPACE_IO */ - reg = <0x0100f810 0 0 0 0>; + reg = <0x0100f810 0 0 0x100 0>; sandbox,emul = <&swap_case_emul0_1f>; }; }; diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c index 546db675aaf..b79d138c419 100644 --- a/drivers/core/fdtaddr.c +++ b/drivers/core/fdtaddr.c @@ -215,7 +215,7 @@ void *devfdt_map_physmem(const struct udevice *dev, unsigned long size) return map_physmem(addr, size, MAP_NOCACHE); } -fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev) +fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev, fdt_size_t *sizep) { ulong addr; @@ -226,12 +226,12 @@ fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev) int ret; ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32, - "reg", &pci_addr); + "reg", &pci_addr, sizep); if (ret) { /* try if there is any i/o-mapped register */ ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_IO, "reg", - &pci_addr); + &pci_addr, sizep); if (ret) return FDT_ADDR_T_NONE; } diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 18d2eb0f118..29a42945102 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -1270,7 +1270,8 @@ const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname, } int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, - const char *propname, struct fdt_pci_addr *addr) + const char *propname, struct fdt_pci_addr *addr, + fdt_size_t *size) { const fdt32_t *cell; int len; @@ -1298,14 +1299,18 @@ int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, (ulong)fdt32_to_cpu(cell[1]), (ulong)fdt32_to_cpu(cell[2])); if ((fdt32_to_cpu(*cell) & type) == type) { + const unaligned_fdt64_t *ptr; + addr->phys_hi = fdt32_to_cpu(cell[0]); addr->phys_mid = fdt32_to_cpu(cell[1]); addr->phys_lo = fdt32_to_cpu(cell[2]); + ptr = (const unaligned_fdt64_t *)(cell + 3); + if (size) + *size = fdt64_to_cpu(*ptr); break; } - cell += (FDT_PCI_ADDR_CELLS + - FDT_PCI_SIZE_CELLS); + cell += FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS; } if (i == num) { diff --git a/drivers/core/read.c b/drivers/core/read.c index 49066b59cda..419013451f0 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -405,13 +405,15 @@ int dev_read_alias_highest_id(const char *stem) return fdtdec_get_alias_highest_id(gd->fdt_blob, stem); } -fdt_addr_t dev_read_addr_pci(const struct udevice *dev) +fdt_addr_t dev_read_addr_pci(const struct udevice *dev, fdt_size_t *sizep) { ulong addr; addr = dev_read_addr(dev); + if (sizep) + *sizep = 0; if (addr == FDT_ADDR_T_NONE && !of_live_active()) - addr = devfdt_get_addr_pci(dev); + addr = devfdt_get_addr_pci(dev, sizep); return addr; } diff --git a/drivers/core/util.c b/drivers/core/util.c index aa60fdd15bc..81497df85ff 100644 --- a/drivers/core/util.c +++ b/drivers/core/util.c @@ -30,7 +30,7 @@ int pci_get_devfn(struct udevice *dev) /* Extract the devfn from fdt_pci_addr */ ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG, - "reg", &addr); + "reg", &addr, NULL); if (ret) { if (ret != -ENOENT) return -EINVAL; diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index ae7350aaff9..e0d01f6a85d 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -123,7 +123,7 @@ static void pci_dev_find_ofnode(struct udevice *bus, phys_addr_t bdf, dev_for_each_subnode(node, bus) { ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", - &addr); + &addr, NULL); if (ret) continue; diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 3697cd8d652..83559550e6f 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -641,7 +641,8 @@ static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pci pcie->is_x4 = true; /* devfn is in bits [15:8], see PCI_DEV usage */ - ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr); + ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr, + NULL); if (ret < 0) { printf("%s: property \"reg\" is invalid\n", pcie->name); goto err; diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index 131c21b7684..d6374a58e33 100644 --- a/drivers/pci/pci_tegra.c +++ b/drivers/pci/pci_tegra.c @@ -462,7 +462,7 @@ static int tegra_pcie_parse_port_info(ofnode node, uint *index, uint *lanes) *lanes = err; - err = ofnode_read_pci_addr(node, 0, "reg", &addr); + err = ofnode_read_pci_addr(node, 0, "reg", &addr, NULL); if (err < 0) { pr_err("failed to parse \"reg\" property\n"); return err; diff --git a/drivers/pci/pcie_mediatek.c b/drivers/pci/pcie_mediatek.c index ed25a10bcf0..f0f34b5d119 100644 --- a/drivers/pci/pcie_mediatek.c +++ b/drivers/pci/pcie_mediatek.c @@ -661,7 +661,7 @@ static int mtk_pcie_probe(struct udevice *dev) if (!ofnode_is_enabled(subnode)) continue; - err = ofnode_read_pci_addr(subnode, 0, "reg", &addr); + err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL); if (err) return err; @@ -700,7 +700,7 @@ static int mtk_pcie_probe_v2(struct udevice *dev) if (!ofnode_is_enabled(subnode)) continue; - err = ofnode_read_pci_addr(subnode, 0, "reg", &addr); + err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL); if (err) return err; diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 5ca2828ae85..6deb1d8ddc5 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -484,6 +484,7 @@ static int ns16550_serial_getinfo(struct udevice *dev, info->addr_space = SERIAL_ADDRESS_SPACE_MEMORY; #endif info->addr = plat->base; + info->size = plat->size; info->reg_width = plat->reg_width; info->reg_shift = plat->reg_shift; info->reg_offset = plat->reg_offset; @@ -492,7 +493,8 @@ static int ns16550_serial_getinfo(struct udevice *dev, return 0; } -static int ns16550_serial_assign_base(struct ns16550_plat *plat, fdt_addr_t base) +static int ns16550_serial_assign_base(struct ns16550_plat *plat, + fdt_addr_t base, fdt_size_t size) { if (base == FDT_ADDR_T_NONE) return -EINVAL; @@ -502,6 +504,7 @@ static int ns16550_serial_assign_base(struct ns16550_plat *plat, fdt_addr_t base #else plat->base = (unsigned long)map_physmem(base, 0, MAP_NOCACHE); #endif + plat->size = size; return 0; } @@ -512,6 +515,7 @@ int ns16550_serial_probe(struct udevice *dev) struct ns16550 *const com_port = dev_get_priv(dev); struct reset_ctl_bulk reset_bulk; fdt_addr_t addr; + fdt_addr_t size; int ret; /* @@ -519,8 +523,8 @@ int ns16550_serial_probe(struct udevice *dev) * or via a PCI bridge, assign plat->base before probing hardware. */ if (device_is_on_pci_bus(dev)) { - addr = devfdt_get_addr_pci(dev); - ret = ns16550_serial_assign_base(plat, addr); + addr = devfdt_get_addr_pci(dev, &size); + ret = ns16550_serial_assign_base(plat, addr, size); if (ret) return ret; } @@ -547,12 +551,14 @@ int ns16550_serial_of_to_plat(struct udevice *dev) { struct ns16550_plat *plat = dev_get_plat(dev); const u32 port_type = dev_get_driver_data(dev); + fdt_size_t size = 0; fdt_addr_t addr; struct clk clk; int err; - addr = dev_read_addr(dev); - err = ns16550_serial_assign_base(plat, addr); + addr = spl_in_proper() ? dev_read_addr_size(dev, &size) : + dev_read_addr(dev); + err = ns16550_serial_assign_base(plat, addr, size); if (err && !device_is_on_pci_bus(dev)) return err; diff --git a/include/dm/fdtaddr.h b/include/dm/fdtaddr.h index dcdc19137cc..6d2fa8f1044 100644 --- a/include/dm/fdtaddr.h +++ b/include/dm/fdtaddr.h @@ -168,8 +168,9 @@ fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev, * devfdt_get_addr_pci() - Read an address and handle PCI address translation * * @dev: Device to read from + * @sizep: If non-NULL, returns size of address space * Return: address or FDT_ADDR_T_NONE if not found */ -fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev); +fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev, fdt_size_t *sizep); #endif diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index ef1437cc556..19e97a90327 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -1153,13 +1153,15 @@ const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname, * @type: pci address type (FDT_PCI_SPACE_xxx) * @propname: name of property to find * @addr: returns pci address in the form of fdt_pci_addr + * @size: if non-null, returns register-space size * Return: * 0 if ok, -ENOENT if the property did not exist, -EINVAL if the * format of the property was invalid, -ENXIO if the requested * address type was not found */ int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, - const char *propname, struct fdt_pci_addr *addr); + const char *propname, struct fdt_pci_addr *addr, + fdt_size_t *size); /** * ofnode_read_pci_vendev() - look up PCI vendor and device id diff --git a/include/dm/read.h b/include/dm/read.h index c2615f72f40..3c2eea6f0c4 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -346,9 +346,10 @@ void *dev_read_addr_ptr(const struct udevice *dev); * fdtdec_get_addr() and friends. * * @dev: Device to read from + * @sizep: If non-NULL, returns size of address space found * Return: address or FDT_ADDR_T_NONE if not found */ -fdt_addr_t dev_read_addr_pci(const struct udevice *dev); +fdt_addr_t dev_read_addr_pci(const struct udevice *dev, fdt_size_t *sizep); /** * dev_remap_addr() - Get the reg property of a device as a @@ -996,9 +997,10 @@ static inline void *dev_read_addr_ptr(const struct udevice *dev) return devfdt_get_addr_ptr(dev); } -static inline fdt_addr_t dev_read_addr_pci(const struct udevice *dev) +static inline fdt_addr_t dev_read_addr_pci(const struct udevice *dev, + fdt_size_t *sizep) { - return devfdt_get_addr_pci(dev); + return devfdt_get_addr_pci(dev, sizep); } static inline void *dev_remap_addr(const struct udevice *dev) diff --git a/include/ns16550.h b/include/ns16550.h index e7e68663d03..7f481300083 100644 --- a/include/ns16550.h +++ b/include/ns16550.h @@ -58,6 +58,7 @@ enum ns16550_flags { * struct ns16550_plat - information about a NS16550 port * * @base: Base register address + * @size: Size of register area in bytes * @reg_width: IO accesses size of registers (in bytes, 1 or 4) * @reg_shift: Shift size of registers (0=byte, 1=16bit, 2=32bit...) * @reg_offset: Offset to start of registers (normally 0) @@ -67,7 +68,8 @@ enum ns16550_flags { * @bdf: PCI slot/function (pci_dev_t) */ struct ns16550_plat { - unsigned long base; + ulong base; + ulong size; int reg_width; int reg_shift; int reg_offset; diff --git a/include/serial.h b/include/serial.h index 42bdf3759c0..205889d28be 100644 --- a/include/serial.h +++ b/include/serial.h @@ -137,6 +137,7 @@ enum adr_space_type { * @type: type of the UART chip * @addr_space: address space to access the registers * @addr: physical address of the registers + * @size: size of the register area in bytes * @reg_width: size (in bytes) of the IO accesses to the registers * @reg_offset: offset to apply to the @addr from the start of the registers * @reg_shift: quantity to shift the register offsets by @@ -147,6 +148,7 @@ struct serial_device_info { enum serial_chip_type type; enum adr_space_type addr_space; ulong addr; + ulong size; u8 reg_width; u8 reg_offset; u8 reg_shift; diff --git a/test/dm/pci.c b/test/dm/pci.c index 70a736cfdb8..8c5e7da9e62 100644 --- a/test/dm/pci.c +++ b/test/dm/pci.c @@ -301,10 +301,12 @@ static int dm_test_pci_addr_flat(struct unit_test_state *uts) { struct udevice *swap1f, *swap1; ulong io_addr, mem_addr; + fdt_addr_t size; ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f)); io_addr = dm_pci_read_bar32(swap1f, 0); - ut_asserteq(io_addr, dev_read_addr_pci(swap1f)); + ut_asserteq(io_addr, dev_read_addr_pci(swap1f, &size)); + ut_asserteq(0, size); /* * This device has both I/O and MEM spaces but the MEM space appears @@ -312,7 +314,8 @@ static int dm_test_pci_addr_flat(struct unit_test_state *uts) */ ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1)); mem_addr = dm_pci_read_bar32(swap1, 1); - ut_asserteq(mem_addr, dev_read_addr_pci(swap1)); + ut_asserteq(mem_addr, dev_read_addr_pci(swap1, &size)); + ut_asserteq(0, size); return 0; } @@ -329,12 +332,15 @@ DM_TEST(dm_test_pci_addr_flat, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT | static int dm_test_pci_addr_live(struct unit_test_state *uts) { struct udevice *swap1f, *swap1; + fdt_size_t size; ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f)); - ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f)); + ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f, &size)); + ut_asserteq(0, size); ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1)); - ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1)); + ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1, &size)); + ut_asserteq(0, size); return 0; } -- cgit v1.3.1