summaryrefslogtreecommitdiff
path: root/test/dm
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2026-02-02 13:40:50 -0600
committerTom Rini <trini@konsulko.com>2026-02-02 13:40:50 -0600
commitfd070b0e71862c0e7f0fa42b7f19e49dfa7037e7 (patch)
tree852df5d4d70737729c50840d6e4226baa87f89bf /test/dm
parent4b287e0a3ae4ab3159584cb5ae12c9b470716be8 (diff)
parent90cd316b5a0fce702525ff7980d30e2bd233078d (diff)
Merge patch series "clk: support arbitrary clk_register() sequence"DBG/clk-support-arbitrary-clk_register-sequence
Yang Xiwen <forbidden405@outlook.com> says: Currently, the U-Boot clk framework mandates that clock registration begins at the root and proceeds to children. This creates an additional requirement that does not exist in the Linux kernel, making the porting of clk drivers more difficult. This series handles the dependency entirely within the clk framework, allowing drivers the freedom to register clocks in any order. This is achieved by assigning the parent "lazily". The framework caches the parent name in the core clk struct and attempts to resolve the actual parent when clk consumers call clk_get_parent(). The process is transparent to clk consumers as long as they use standard clk framework APIs. I've run `ut dm clk*` and verified these commits do not break any existing test cases. It also passes the new test case. This feature is disabled for xPLs by default. I have not found a clean way to enable this separately for xPLs without introducing a repetitive Kconfig entry (e.g., xPL_CLK_LAZY_REPARENT), which looks very ugly. Link: https://lore.kernel.org/r/20260120-clk-reparent-v3-0-0d43d4b362ac@outlook.com
Diffstat (limited to 'test/dm')
-rw-r--r--test/dm/clk_ccf.c40
-rw-r--r--test/dm/core.c34
2 files changed, 72 insertions, 2 deletions
diff --git a/test/dm/clk_ccf.c b/test/dm/clk_ccf.c
index 9c06aadb7ed..8bbb79bec2a 100644
--- a/test/dm/clk_ccf.c
+++ b/test/dm/clk_ccf.c
@@ -35,12 +35,14 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_ECSPI_ROOT), &clk);
ut_assertok(ret);
ut_asserteq_str("ecspi_root", clk->dev->name);
+ ut_assertnull(clk->parent_name);
ut_asserteq(CLK_SET_RATE_PARENT, clk->flags);
/* Test for clk_get_parent_rate() */
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_ECSPI1), &clk);
ut_assertok(ret);
ut_asserteq_str("ecspi1", clk->dev->name);
+ ut_assertnull(clk->parent_name);
ut_asserteq(CLK_SET_RATE_PARENT, clk->flags);
rate = clk_get_parent_rate(clk);
@@ -50,6 +52,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_ECSPI0), &clk);
ut_assertok(ret);
ut_asserteq_str("ecspi0", clk->dev->name);
+ ut_assertnull(clk->parent_name);
ut_asserteq(CLK_SET_RATE_PARENT, clk->flags);
rate = clk_get_parent_rate(clk);
@@ -59,6 +62,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_USDHC1_SEL), &clk);
ut_assertok(ret);
ut_asserteq_str("usdhc1_sel", clk->dev->name);
+ ut_assertnull(clk->parent_name);
ut_asserteq(CLK_SET_RATE_NO_REPARENT, clk->flags);
rate = clk_get_parent_rate(clk);
@@ -71,6 +75,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ut_asserteq_64(60000000, rate);
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_PLL3_80M), &pclk);
+ ut_assertnull(clk->parent_name);
ut_assertok(ret);
ret = clk_set_parent(clk, pclk);
@@ -82,6 +87,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_USDHC2_SEL), &clk);
ut_assertok(ret);
ut_asserteq_str("usdhc2_sel", clk->dev->name);
+ ut_assertnull(clk->parent_name);
ut_asserteq(CLK_SET_RATE_NO_REPARENT, clk->flags);
rate = clk_get_parent_rate(clk);
@@ -98,6 +104,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ut_asserteq_64(80000000, rate);
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_PLL3_60M), &pclk);
+ ut_assertnull(clk->parent_name);
ut_assertok(ret);
ret = clk_set_parent(clk, pclk);
@@ -110,6 +117,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_I2C), &clk);
ut_assertok(ret);
ut_asserteq_str("i2c", clk->dev->name);
+ ut_assertnull(clk->parent_name);
ut_asserteq(CLK_SET_RATE_UNGATE, clk->flags);
rate = clk_get_rate(clk);
@@ -124,11 +132,13 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ret = clk_get_by_index(test_dev, SANDBOX_CLK_TEST_ID_I2C_ROOT, &clk_ccf);
ut_assertok(ret);
ut_asserteq_str("clk-ccf", clk_ccf.dev->name);
+ ut_assertnull(clk->parent_name);
ut_asserteq(CLK_ID(clk_ccf.dev, SANDBOX_CLK_I2C_ROOT), clk_ccf.id);
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_I2C_ROOT), &clk);
ut_assertok(ret);
ut_asserteq_str("i2c_root", clk->dev->name);
+ ut_assertnull(clk->parent_name);
ut_asserteq(SANDBOX_CLK_I2C_ROOT, clk_get_id(clk));
ret = clk_enable(&clk_ccf);
@@ -138,6 +148,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ut_asserteq(1, ret);
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_I2C), &pclk);
+ ut_assertnull(clk->parent_name);
ut_assertok(ret);
ret = sandbox_clk_enable_count(pclk);
@@ -156,6 +167,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_USDHC1_SEL), &clk);
ut_assertok(ret);
ut_asserteq_str("usdhc1_sel", clk->dev->name);
+ ut_assertnull(clk->parent_name);
pclk = clk_get_parent(clk);
ut_assertok_ptr(pclk);
@@ -169,6 +181,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ret = clk_get_by_id(CLK_ID(dev, clkid), &pclk);
ut_assertok(ret);
+ ut_assertnull(clk->parent_name);
ret = clk_set_parent(clk, pclk);
ut_assertok(ret);
pclk = clk_get_parent(clk);
@@ -179,6 +192,7 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
ret = clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_I2C_ROOT), &clk);
ut_assertok(ret);
ut_asserteq_str("i2c_root", clk->dev->name);
+ ut_assertnull(clk->parent_name);
/* Disable it, if any. */
ret = sandbox_clk_enable_count(clk);
@@ -209,3 +223,29 @@ static int dm_test_clk_ccf(struct unit_test_state *uts)
return 1;
}
DM_TEST(dm_test_clk_ccf, UTF_SCAN_FDT);
+
+#if CONFIG_IS_ENABLED(CLK_LAZY_REPARENT)
+/* Test CLK_LAZY_REPARENT feature */
+static int dm_test_clk_lazy_reparent(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ struct clk *clk_i2s, *clk_i2s_root;
+
+ /* Get the device using the clk device */
+ ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-ccf", &dev));
+
+ ut_assertok(clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_I2S_ROOT), &clk_i2s_root));
+ ut_assertok(clk_get_by_id(CLK_ID(dev, SANDBOX_CLK_I2S), &clk_i2s));
+
+ ut_asserteq_str(clk_i2s_root->parent_name, "i2s");
+ ut_assertnull(clk_i2s_root->dev->parent);
+
+ ut_assertok(clk_enable(clk_i2s_root));
+
+ ut_assertnull(clk_i2s_root->parent_name);
+ ut_asserteq_ptr(clk_i2s_root->dev->parent, clk_i2s->dev);
+
+ return 0;
+}
+DM_TEST(dm_test_clk_lazy_reparent, UTF_SCAN_FDT);
+#endif
diff --git a/test/dm/core.c b/test/dm/core.c
index 78ee14af228..d5a7954be95 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -696,9 +696,10 @@ DM_TEST(dm_test_children, 0);
static int dm_test_device_reparent(struct unit_test_state *uts)
{
struct udevice *top[NODE_COUNT];
- struct udevice *child[NODE_COUNT];
+ struct udevice *child[NODE_COUNT], *temp_child = NULL;
struct udevice *grandchild[NODE_COUNT];
struct udevice *dev;
+ struct udevice *orphan;
int total;
int ret;
int i;
@@ -720,8 +721,11 @@ static int dm_test_device_reparent(struct unit_test_state *uts)
ut_assertok(create_children(uts, child[i], NODE_COUNT, 50 * i,
i == 2 ? grandchild : NULL));
+ /* Create an orphan device */
+ ut_assertok(create_children(uts, NULL, 1, 49, &orphan));
+
/* Check total number of devices */
- total = NODE_COUNT * (3 + NODE_COUNT);
+ total = NODE_COUNT * (3 + NODE_COUNT) + 1;
ut_asserteq(total, dm_testdrv_op_count[DM_TEST_OP_BIND]);
/* Probe everything */
@@ -738,6 +742,14 @@ static int dm_test_device_reparent(struct unit_test_state *uts)
ut_assertok(device_reparent(top[4], top[0]));
+ /* Ensure it's reparented */
+ ut_asserteq_ptr(top[4]->parent, top[0]);
+ device_foreach_child(temp_child, top[0]) {
+ if (temp_child == top[4])
+ break;
+ }
+ ut_asserteq_ptr(temp_child, top[4]);
+
/* try to get devices */
ret = uclass_find_first_device(UCLASS_TEST, &dev);
ut_assert(!ret);
@@ -773,6 +785,24 @@ static int dm_test_device_reparent(struct unit_test_state *uts)
ut_assert(!ret);
ut_assertnonnull(dev);
+ /* Re-parent orphant device */
+ ut_assertok(device_reparent(orphan, top[0]));
+
+ /* try to get the device */
+ ret = uclass_find_first_device(UCLASS_TEST, &dev);
+ ut_assert(!ret);
+ ut_assertnonnull(dev);
+
+ /* ensure it's reparented */
+ ut_asserteq_ptr(orphan->parent, top[0]);
+
+ temp_child = NULL;
+ device_foreach_child(temp_child, top[0]) {
+ if (temp_child == orphan)
+ break;
+ }
+ ut_asserteq_ptr(temp_child, orphan);
+
/* Remove re-pareneted devices. */
ut_assertok(device_remove(top[3], DM_REMOVE_NORMAL));