[PATCH 1/3] [RFC] dm: core: Add late driver remove option

Marek Vasut marek.vasut at gmail.com
Sun Apr 26 12:51:55 CEST 2020


Add another flag to the DM core which could be assigned to drivers and
which makes those drivers call their remove callbacks last, just before
booting OS and after all the other drivers finished with their remove
callbacks. This is necessary for things like clock drivers, where the
other drivers might depend on the clock driver in their remove callbacks.
Prime example is the mmc subsystem, which can reconfigure a card from HS
mode to slower modes in the remove callback and for that it needs to
reconfigure the controller clock.

Signed-off-by: Marek Vasut <marek.vasut+renesas at gmail.com>
Cc: Simon Glass <sjg at chromium.org>
Cc: Tom Rini <trini at konsulko.com>
---
 arch/arm/lib/bootm.c         |  1 +
 drivers/core/device-remove.c | 11 ++++++++---
 drivers/core/root.c          |  2 ++
 include/dm/device.h          |  4 ++++
 4 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index f4b5ca6de0..1d247128b7 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -116,6 +116,7 @@ static void announce_and_cleanup(int fake)
 	 * of DMA operation or releasing device internal buffers.
 	 */
 	dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
+	dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL | DM_REMOVE_LATE);
 
 	cleanup_before_linux();
 }
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index efdb0f2905..07b241b6bb 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -172,14 +172,19 @@ int device_remove(struct udevice *dev, uint flags)
 	drv = dev->driver;
 	assert(drv);
 
-	ret = uclass_pre_remove_device(dev);
-	if (ret)
-		return ret;
+	if (!(flags & DM_REMOVE_LATE)) {
+		ret = uclass_pre_remove_device(dev);
+		if (ret)
+			return ret;
+	}
 
 	ret = device_chld_remove(dev, NULL, flags);
 	if (ret)
 		goto err;
 
+	if (!(flags & DM_REMOVE_LATE) && (drv->flags & DM_FLAG_REMOVE_LATE))
+		return 0;
+
 	/*
 	 * Remove the device if called with the "normal" remove flag set,
 	 * or if the remove flag matches any of the drivers remove flags
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 14df16c280..fcb1dfddf5 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -166,6 +166,7 @@ int dm_init(bool of_live)
 int dm_uninit(void)
 {
 	device_remove(dm_root(), DM_REMOVE_NORMAL);
+	device_remove(dm_root(), DM_REMOVE_LATE);
 	device_unbind(dm_root());
 	gd->dm_root = NULL;
 
@@ -376,6 +377,7 @@ int dm_init_and_scan(bool pre_reloc_only)
 U_BOOT_DRIVER(root_driver) = {
 	.name	= "root_driver",
 	.id	= UCLASS_ROOT,
+	.flags	= DM_FLAG_REMOVE_LATE,
 };
 
 /* This is the root uclass */
diff --git a/include/dm/device.h b/include/dm/device.h
index 975eec5d0e..e7c1c343fe 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -73,6 +73,8 @@ struct driver_info;
  */
 #define DM_FLAG_REMOVE_WITH_PD_ON	(1 << 13)
 
+#define DM_FLAG_REMOVE_LATE		(1 << 14)
+
 /*
  * One or multiple of these flags are passed to device_remove() so that
  * a selective device removal as specified by the remove-stage and the
@@ -95,6 +97,8 @@ enum {
 
 	/* Don't power down any attached power domains */
 	DM_REMOVE_NO_PD		= 1 << 1,
+
+	DM_REMOVE_LATE		= 1 << 2,
 };
 
 /**
-- 
2.25.1



More information about the U-Boot mailing list