From patchwork Sun Apr 26 10:51:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 238487 List-Id: U-Boot discussion From: marek.vasut at gmail.com (Marek Vasut) Date: Sun, 26 Apr 2020 12:51:55 +0200 Subject: [PATCH 1/3] [RFC] dm: core: Add late driver remove option Message-ID: <20200426105157.24791-1-marek.vasut+renesas@gmail.com> 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 Cc: Simon Glass Cc: Tom Rini --- 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, }; /**