From 6f3e63b4de851357d81f74211f14fd3b577cae6c Mon Sep 17 00:00:00 2001 From: "Markus Schneider-Pargmann (TI.com)" Date: Tue, 27 Jan 2026 12:03:35 +0100 Subject: [PATCH 1/5] dm: core: lists_bind_fdt: Remove unused variable 'result' is unused in this function, remove it. Reviewed-by: Simon Glass Reviewed-by: Mattijs Korpershoek Signed-off-by: Markus Schneider-Pargmann (TI.com) --- drivers/core/lists.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/core/lists.c b/drivers/core/lists.c index c7be504b6fc..52ba6c7bfa0 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -207,7 +207,6 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, bool found = false; const char *name, *compat_list, *compat; int compat_length, i; - int result = 0; int ret = 0; if (devp) @@ -283,9 +282,9 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, break; } - if (!found && !result && ret != -ENODEV) + if (!found && ret != -ENODEV) log_debug("No match for node '%s'\n", name); - return result; + return 0; } #endif From 41cf66011fc80bd122c3ebbeda4218547c48c297 Mon Sep 17 00:00:00 2001 From: "Markus Schneider-Pargmann (TI.com)" Date: Tue, 27 Jan 2026 12:03:36 +0100 Subject: [PATCH 2/5] dm: core: lists_bind_fdt: Replace found variable 'found' is only used at the end of the function to print a debug message. No need to maintain a variable if we can just return 0 immediately when a driver was bound successfully. Reviewed-by: Simon Glass Reviewed-by: Mattijs Korpershoek Signed-off-by: Markus Schneider-Pargmann (TI.com) --- drivers/core/lists.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 52ba6c7bfa0..9d1ca38212e 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -204,7 +204,6 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, const struct udevice_id *id; struct driver *entry; struct udevice *dev; - bool found = false; const char *name, *compat_list, *compat; int compat_length, i; int ret = 0; @@ -275,14 +274,14 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, ret); return log_msg_ret("bind", ret); } else { - found = true; if (devp) *devp = dev; + return 0; } break; } - if (!found && ret != -ENODEV) + if (ret != -ENODEV) log_debug("No match for node '%s'\n", name); return 0; From 6668b8e7cc68ee287ef87e18aadc97bf88cea4db Mon Sep 17 00:00:00 2001 From: "Markus Schneider-Pargmann (TI.com)" Date: Tue, 27 Jan 2026 12:03:37 +0100 Subject: [PATCH 3/5] dm: core: Support multiple drivers with same compatibles Currently once a driver matched the compatible string of a device, other drivers are ignored. If the first matching driver returns -ENODEV, no other possibly matching drivers are iterated with that compatible of the device. Instead the next compatible in the list of compatibles is selected, assuming only one driver matches one compatible at a time. To be able to use the bind function to return -ENODEV and continue matching other drivers with the same compatible, move the for loop a bit to continue the for loop after -ENODEV was returned. The loop had to be adjusted a bit to still support the 'drv' argument properly. Some simplifications were done as well. The modification will only add additional loop iterations if -ENODEV is returned. Otherwise the exit and continue conditions for the loop stay the same and do not cause any additional iterations and should not impact performance. This is required for ti-musb-host and ti-musb-peripheral which both match on the same device but differ based on the dr_mode DT property. Depending on this property, the driver is either UCLASS_USB or UCLASS_USB_GADGET_GENERIC. By checking the DT property in the bind function and returning -ENODEV the other driver can probe instead. Reviewed-by: Simon Glass Acked-by: Dinesh Maniyam Signed-off-by: Markus Schneider-Pargmann (TI.com) --- drivers/core/lists.c | 65 ++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 9d1ca38212e..813c3de52b2 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -235,50 +235,51 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, log_debug(" - attempt to match compatible string '%s'\n", compat); - id = NULL; for (entry = driver; entry != driver + n_ents; entry++) { + /* Search for drivers with matching drv or existing of_match */ if (drv) { if (drv != entry) continue; - if (!entry->of_match) - break; + } else if (!entry->of_match) { + continue; } - ret = driver_check_compatible(entry->of_match, &id, - compat); - if (!ret) - break; - } - if (entry == driver + n_ents) - continue; - if (pre_reloc_only) { - if (!ofnode_pre_reloc(node) && - !(entry->flags & DM_FLAG_PRE_RELOC)) { - log_debug("Skipping device pre-relocation\n"); - return 0; + id = NULL; + if (entry->of_match) { + ret = driver_check_compatible(entry->of_match, &id, + compat); + if (ret) + continue; + log_debug(" - found match at driver '%s' for '%s'\n", + entry->name, id->compatible); + } + + if (pre_reloc_only) { + if (!ofnode_pre_reloc(node) && + !(entry->flags & DM_FLAG_PRE_RELOC)) { + log_debug("Skipping device pre-relocation\n"); + return 0; + } + } + + ret = device_bind_with_driver_data(parent, entry, name, + id ? id->data : 0, node, + &dev); + if (!drv && ret == -ENODEV) { + log_debug("Driver '%s' refuses to bind\n", entry->name); + continue; + } + if (ret) { + dm_warn("Error binding driver '%s': %d\n", entry->name, + ret); + return log_msg_ret("bind", ret); } - } - if (entry->of_match) - log_debug(" - found match at driver '%s' for '%s'\n", - entry->name, id->compatible); - ret = device_bind_with_driver_data(parent, entry, name, - id ? id->data : 0, node, - &dev); - if (ret == -ENODEV) { - log_debug("Driver '%s' refuses to bind\n", entry->name); - continue; - } - if (ret) { - dm_warn("Error binding driver '%s': %d\n", entry->name, - ret); - return log_msg_ret("bind", ret); - } else { if (devp) *devp = dev; + return 0; } - break; } if (ret != -ENODEV) From 87d7d8190f5cc17abc104f924e0f499fda2fd02e Mon Sep 17 00:00:00 2001 From: "Markus Schneider-Pargmann (TI)" Date: Tue, 27 Jan 2026 12:03:38 +0100 Subject: [PATCH 4/5] dm: core: lists_bind_fdt: Indent continuation debug log message The loop in lists_bind_fdt uses an indented style for log messages within the loop and normal messages for errors that lead to the exit of the function. Due to the change of the previous patch that adds support for continuation on -ENODEV returned by bind, the log message should be indented. Signed-off-by: Markus Schneider-Pargmann (TI) --- drivers/core/lists.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 813c3de52b2..2545dc142f6 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -266,7 +266,7 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, id ? id->data : 0, node, &dev); if (!drv && ret == -ENODEV) { - log_debug("Driver '%s' refuses to bind\n", entry->name); + log_debug(" - Driver '%s' refuses to bind\n", entry->name); continue; } if (ret) { From c7e0e3fd33ca9809605a6de0a58809daf1224bff Mon Sep 17 00:00:00 2001 From: "Markus Schneider-Pargmann (TI.com)" Date: Tue, 27 Jan 2026 12:03:39 +0100 Subject: [PATCH 5/5] test: dm: Add compatible multimatch test Add a test for binding of multiple drivers with the same compatible. If one of the drivers returns -ENODEV the other one needs to be bound. Reviewed-by: Simon Glass Reviewed-by: Mattijs Korpershoek Signed-off-by: Markus Schneider-Pargmann (TI.com) --- arch/sandbox/dts/test.dts | 4 ++++ test/dm/core.c | 15 +++++++++++++++ test/dm/test-driver.c | 26 ++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index cd53c170171..b7402d7042a 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -457,6 +457,10 @@ mux-control-names = "mux0"; }; + multimatch-test { + compatible = "sandbox,multimatch-test"; + }; + phy_provider0: gen_phy@0 { compatible = "sandbox,phy"; #phy-cells = <1>; diff --git a/test/dm/core.c b/test/dm/core.c index 53693f4f7ed..78ee14af228 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -1410,3 +1410,18 @@ static int dm_test_try_first_device(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_try_first_device, 0); + +/* Test that all drivers are iterated when bind returns -ENODEV */ +static int dm_test_multimatch(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_find_device_by_name(UCLASS_TEST, "multimatch-test", + &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("test_multimatch_second", dev->driver->name); + ut_asserteq(2, dm_testdrv_op_count[DM_TEST_OP_BIND]); + + return 0; +} +DM_TEST(dm_test_multimatch, UTF_SCAN_FDT); diff --git a/test/dm/test-driver.c b/test/dm/test-driver.c index 759de3a5f77..d628a6d766f 100644 --- a/test/dm/test-driver.c +++ b/test/dm/test-driver.c @@ -197,3 +197,29 @@ U_BOOT_DRIVER(test_act_dma_vital_clk_drv) = { .unbind = test_manual_unbind, .flags = DM_FLAG_VITAL | DM_FLAG_ACTIVE_DMA, }; + +static int test_multimatch_first_bind(struct udevice *dev) +{ + dm_testdrv_op_count[DM_TEST_OP_BIND]++; + + return -ENODEV; +} + +static const struct udevice_id test_multimatch_ids[] = { + { .compatible = "sandbox,multimatch-test" }, + { } +}; + +U_BOOT_DRIVER(test_multimatch_first) = { + .name = "test_multimatch_first", + .id = UCLASS_TEST, + .of_match = test_multimatch_ids, + .bind = test_multimatch_first_bind, +}; + +U_BOOT_DRIVER(test_multimatch_second) = { + .name = "test_multimatch_second", + .id = UCLASS_TEST, + .of_match = test_multimatch_ids, + .bind = test_manual_bind, +};