mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-08 19:11:53 +00:00
dm: core: add support for device re-parenting
In common clock framework the relation b/w parent and child clocks is determined based on the udevice parent/child information. A clock parent could be changed based on devices needs. In case this is happen the functionalities for clock who's parent is changed are broken. Add a function that reparent a device. This will be used in clk-uclass.c to reparent a clock device. Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
b04da9fcf7
commit
cfecbaf4e7
3 changed files with 191 additions and 0 deletions
|
@ -276,6 +276,28 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int device_reparent(struct udevice *dev, struct udevice *new_parent)
|
||||||
|
{
|
||||||
|
struct udevice *pos, *n;
|
||||||
|
|
||||||
|
assert(dev);
|
||||||
|
assert(new_parent);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(pos, n, &dev->parent->child_head,
|
||||||
|
sibling_node) {
|
||||||
|
if (pos->driver != dev->driver)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
list_del(&dev->sibling_node);
|
||||||
|
list_add_tail(&dev->sibling_node, &new_parent->child_head);
|
||||||
|
dev->parent = new_parent;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void *alloc_priv(int size, uint flags)
|
static void *alloc_priv(int size, uint flags)
|
||||||
{
|
{
|
||||||
void *priv;
|
void *priv;
|
||||||
|
|
|
@ -83,6 +83,15 @@ int device_bind_with_driver_data(struct udevice *parent,
|
||||||
int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
|
int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
|
||||||
struct driver_info *info, struct udevice **devp);
|
struct driver_info *info, struct udevice **devp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* device_reparent: reparent the device to a new parent
|
||||||
|
*
|
||||||
|
* @dev: pointer to device to be reparented
|
||||||
|
* @new_parent: pointer to new parent device
|
||||||
|
* @return 0 if OK, -ve on error
|
||||||
|
*/
|
||||||
|
int device_reparent(struct udevice *dev, struct udevice *new_parent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* device_ofdata_to_platdata() - Read platform data for a device
|
* device_ofdata_to_platdata() - Read platform data for a device
|
||||||
*
|
*
|
||||||
|
|
160
test/dm/core.c
160
test/dm/core.c
|
@ -643,6 +643,166 @@ static int dm_test_children(struct unit_test_state *uts)
|
||||||
}
|
}
|
||||||
DM_TEST(dm_test_children, 0);
|
DM_TEST(dm_test_children, 0);
|
||||||
|
|
||||||
|
static int dm_test_device_reparent(struct unit_test_state *uts)
|
||||||
|
{
|
||||||
|
struct dm_test_state *dms = uts->priv;
|
||||||
|
struct udevice *top[NODE_COUNT];
|
||||||
|
struct udevice *child[NODE_COUNT];
|
||||||
|
struct udevice *grandchild[NODE_COUNT];
|
||||||
|
struct udevice *dev;
|
||||||
|
int total;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* We don't care about the numbering for this test */
|
||||||
|
dms->skip_post_probe = 1;
|
||||||
|
|
||||||
|
ut_assert(NODE_COUNT > 5);
|
||||||
|
|
||||||
|
/* First create 10 top-level children */
|
||||||
|
ut_assertok(create_children(uts, dms->root, NODE_COUNT, 0, top));
|
||||||
|
|
||||||
|
/* Now a few have their own children */
|
||||||
|
ut_assertok(create_children(uts, top[2], NODE_COUNT, 2, NULL));
|
||||||
|
ut_assertok(create_children(uts, top[5], NODE_COUNT, 5, child));
|
||||||
|
|
||||||
|
/* And grandchildren */
|
||||||
|
for (i = 0; i < NODE_COUNT; i++)
|
||||||
|
ut_assertok(create_children(uts, child[i], NODE_COUNT, 50 * i,
|
||||||
|
i == 2 ? grandchild : NULL));
|
||||||
|
|
||||||
|
/* Check total number of devices */
|
||||||
|
total = NODE_COUNT * (3 + NODE_COUNT);
|
||||||
|
ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_BIND]);
|
||||||
|
|
||||||
|
/* Probe everything */
|
||||||
|
for (i = 0; i < total; i++)
|
||||||
|
ut_assertok(uclass_get_device(UCLASS_TEST, i, &dev));
|
||||||
|
|
||||||
|
/* Re-parent top-level children with no grandchildren. */
|
||||||
|
ut_assertok(device_reparent(top[3], top[0]));
|
||||||
|
/* try to get devices */
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_assertok(device_reparent(top[4], top[0]));
|
||||||
|
/* try to get devices */
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-parent top-level children with grandchildren. */
|
||||||
|
ut_assertok(device_reparent(top[2], top[0]));
|
||||||
|
/* try to get devices */
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_assertok(device_reparent(top[5], top[2]));
|
||||||
|
/* try to get devices */
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-parent grandchildren. */
|
||||||
|
ut_assertok(device_reparent(grandchild[0], top[1]));
|
||||||
|
/* try to get devices */
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_assertok(device_reparent(grandchild[1], top[1]));
|
||||||
|
/* try to get devices */
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove re-pareneted devices. */
|
||||||
|
ut_assertok(device_remove(top[3], DM_REMOVE_NORMAL));
|
||||||
|
/* try to get devices */
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_assertok(device_remove(top[4], DM_REMOVE_NORMAL));
|
||||||
|
/* try to get devices */
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_assertok(device_remove(top[5], DM_REMOVE_NORMAL));
|
||||||
|
/* try to get devices */
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_assertok(device_remove(top[2], DM_REMOVE_NORMAL));
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_assertok(device_remove(grandchild[0], DM_REMOVE_NORMAL));
|
||||||
|
/* try to get devices */
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_assertok(device_remove(grandchild[1], DM_REMOVE_NORMAL));
|
||||||
|
/* try to get devices */
|
||||||
|
for (ret = uclass_find_first_device(UCLASS_TEST, &dev);
|
||||||
|
dev;
|
||||||
|
ret = uclass_find_next_device(&dev)) {
|
||||||
|
ut_assert(!ret);
|
||||||
|
ut_assertnonnull(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try the same with unbind */
|
||||||
|
ut_assertok(device_unbind(top[3]));
|
||||||
|
ut_assertok(device_unbind(top[4]));
|
||||||
|
ut_assertok(device_unbind(top[5]));
|
||||||
|
ut_assertok(device_unbind(top[2]));
|
||||||
|
|
||||||
|
ut_assertok(device_unbind(grandchild[0]));
|
||||||
|
ut_assertok(device_unbind(grandchild[1]));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
DM_TEST(dm_test_device_reparent, 0);
|
||||||
|
|
||||||
/* Test that pre-relocation devices work as expected */
|
/* Test that pre-relocation devices work as expected */
|
||||||
static int dm_test_pre_reloc(struct unit_test_state *uts)
|
static int dm_test_pre_reloc(struct unit_test_state *uts)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue