aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/lib/bdinfo.c16
-rw-r--r--arch/arm/lib/bootm.c3
-rw-r--r--arch/arm/mach-rockchip/sdram.c2
-rw-r--r--arch/m68k/lib/bdinfo.c2
-rw-r--r--arch/powerpc/lib/bdinfo.c4
-rw-r--r--arch/riscv/cpu/fu540/dram.c7
-rw-r--r--arch/riscv/cpu/generic/dram.c7
-rw-r--r--arch/riscv/include/asm/types.h4
-rw-r--r--board/AndesTech/ax25-ae350/ax25-ae350.c2
-rw-r--r--cmd/bdinfo.c52
-rw-r--r--doc/driver-model/design.rst20
-rw-r--r--drivers/core/device-remove.c96
-rw-r--r--drivers/core/root.c2
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_devices.c3
-rw-r--r--drivers/mtd/nand/raw/brcmnand/brcmnand.c5
-rw-r--r--drivers/net/ftmac100.c10
-rw-r--r--drivers/pci/pcie_iproc.c2
-rw-r--r--drivers/serial/serial_sifive.c2
-rw-r--r--drivers/smem/msm_smem.c6
-rw-r--r--drivers/video/meson/meson_vpu.c2
-rw-r--r--drivers/watchdog/rti_wdt.c2
-rw-r--r--include/asm-generic/global_data.h2
-rw-r--r--include/dm/device-internal.h15
-rw-r--r--include/dm/device.h15
-rw-r--r--include/init.h3
-rw-r--r--include/os.h2
-rw-r--r--lib/fdtdec.c2
-rw-r--r--test/dm/core.c94
-rw-r--r--test/dm/test-driver.c22
-rw-r--r--test/dm/virtio.c4
30 files changed, 305 insertions, 103 deletions
diff --git a/arch/arm/lib/bdinfo.c b/arch/arm/lib/bdinfo.c
index 25bc6e80f47..c905783bdc8 100644
--- a/arch/arm/lib/bdinfo.c
+++ b/arch/arm/lib/bdinfo.c
@@ -15,23 +15,23 @@ void arch_print_bdinfo(void)
{
struct bd_info *bd = gd->bd;
- bdinfo_print_num("arch_number", bd->bi_arch_number);
+ bdinfo_print_num_l("arch_number", bd->bi_arch_number);
#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
if (gd->arch.secure_ram & MEM_RESERVE_SECURE_SECURED) {
- bdinfo_print_num("Secure ram",
- gd->arch.secure_ram &
- MEM_RESERVE_SECURE_ADDR_MASK);
+ bdinfo_print_num_ll("Secure ram",
+ gd->arch.secure_ram &
+ MEM_RESERVE_SECURE_ADDR_MASK);
}
#endif
#ifdef CONFIG_RESV_RAM
if (gd->arch.resv_ram)
- bdinfo_print_num("Reserved ram", gd->arch.resv_ram);
+ bdinfo_print_num_ll("Reserved ram", gd->arch.resv_ram);
#endif
#if !(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
- bdinfo_print_num("TLB addr", gd->arch.tlb_addr);
+ bdinfo_print_num_l("TLB addr", gd->arch.tlb_addr);
#endif
- bdinfo_print_num("irq_sp", gd->irq_sp); /* irq stack pointer */
- bdinfo_print_num("sp start ", gd->start_addr_sp);
+ bdinfo_print_num_l("irq_sp", gd->irq_sp); /* irq stack pointer */
+ bdinfo_print_num_l("sp start ", gd->start_addr_sp);
/*
* TODO: Currently only support for davinci SOC's is added.
* Remove this check once all the board implement this.
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index 1206e306db6..f46d51d6553 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -119,6 +119,9 @@ static void announce_and_cleanup(int fake)
* This may be useful for last-stage operations, like cancelling
* of DMA operation or releasing device internal buffers.
*/
+ dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL | DM_REMOVE_NON_VITAL);
+
+ /* Remove all active vital devices next */
dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
cleanup_before_linux();
diff --git a/arch/arm/mach-rockchip/sdram.c b/arch/arm/mach-rockchip/sdram.c
index 4c637b77673..c3d5fed7db3 100644
--- a/arch/arm/mach-rockchip/sdram.c
+++ b/arch/arm/mach-rockchip/sdram.c
@@ -37,7 +37,7 @@ struct tos_parameter_t {
int dram_init_banksize(void)
{
size_t top = min((unsigned long)(gd->ram_size + CONFIG_SYS_SDRAM_BASE),
- gd->ram_top);
+ (unsigned long)(gd->ram_top));
#ifdef CONFIG_ARM64
/* Reserve 0x200000 for ATF bl31 */
diff --git a/arch/m68k/lib/bdinfo.c b/arch/m68k/lib/bdinfo.c
index 404e5f19ed8..92ea1752023 100644
--- a/arch/m68k/lib/bdinfo.c
+++ b/arch/m68k/lib/bdinfo.c
@@ -38,7 +38,7 @@ void arch_print_bdinfo(void)
bdinfo_print_mhz("busfreq", bd->bi_busfreq);
#if defined(CONFIG_SYS_MBAR)
- bdinfo_print_num("mbar", bd->bi_mbar_base);
+ bdinfo_print_num_l("mbar", bd->bi_mbar_base);
#endif
bdinfo_print_mhz("cpufreq", bd->bi_intfreq);
if (IS_ENABLED(CONFIG_PCI))
diff --git a/arch/powerpc/lib/bdinfo.c b/arch/powerpc/lib/bdinfo.c
index 36c9c99ee6f..b14e75b68ab 100644
--- a/arch/powerpc/lib/bdinfo.c
+++ b/arch/powerpc/lib/bdinfo.c
@@ -47,9 +47,9 @@ void arch_print_bdinfo(void)
bdinfo_print_mhz("busfreq", bd->bi_busfreq);
#if defined(CONFIG_MPC8xx) || defined(CONFIG_E500)
- bdinfo_print_num("immr_base", bd->bi_immr_base);
+ bdinfo_print_num_l("immr_base", bd->bi_immr_base);
#endif
- bdinfo_print_num("bootflags", bd->bi_bootflags);
+ bdinfo_print_num_l("bootflags", bd->bi_bootflags);
bdinfo_print_mhz("intfreq", bd->bi_intfreq);
#ifdef CONFIG_ENABLE_36BIT_PHYS
if (IS_ENABLED(CONFIG_PHYS_64BIT))
diff --git a/arch/riscv/cpu/fu540/dram.c b/arch/riscv/cpu/fu540/dram.c
index 1dc77efeca5..259da65a545 100644
--- a/arch/riscv/cpu/fu540/dram.c
+++ b/arch/riscv/cpu/fu540/dram.c
@@ -22,7 +22,6 @@ int dram_init_banksize(void)
ulong board_get_usable_ram_top(ulong total_size)
{
-#ifdef CONFIG_64BIT
/*
* Ensure that we run from first 4GB so that all
* addresses used by U-Boot are 32bit addresses.
@@ -31,8 +30,8 @@ ulong board_get_usable_ram_top(ulong total_size)
* devices work fine because DMA mapping APIs will
* provide 32bit DMA addresses only.
*/
- if (gd->ram_top > SZ_4G)
- return SZ_4G;
-#endif
+ if (gd->ram_top >= SZ_4G)
+ return SZ_4G - 1;
+
return gd->ram_top;
}
diff --git a/arch/riscv/cpu/generic/dram.c b/arch/riscv/cpu/generic/dram.c
index 1dc77efeca5..259da65a545 100644
--- a/arch/riscv/cpu/generic/dram.c
+++ b/arch/riscv/cpu/generic/dram.c
@@ -22,7 +22,6 @@ int dram_init_banksize(void)
ulong board_get_usable_ram_top(ulong total_size)
{
-#ifdef CONFIG_64BIT
/*
* Ensure that we run from first 4GB so that all
* addresses used by U-Boot are 32bit addresses.
@@ -31,8 +30,8 @@ ulong board_get_usable_ram_top(ulong total_size)
* devices work fine because DMA mapping APIs will
* provide 32bit DMA addresses only.
*/
- if (gd->ram_top > SZ_4G)
- return SZ_4G;
-#endif
+ if (gd->ram_top >= SZ_4G)
+ return SZ_4G - 1;
+
return gd->ram_top;
}
diff --git a/arch/riscv/include/asm/types.h b/arch/riscv/include/asm/types.h
index b800b2d221b..49f7a5d6b3a 100644
--- a/arch/riscv/include/asm/types.h
+++ b/arch/riscv/include/asm/types.h
@@ -35,8 +35,8 @@ typedef u64 dma_addr_t;
typedef u32 dma_addr_t;
#endif
-typedef unsigned long phys_addr_t;
-typedef unsigned long phys_size_t;
+typedef unsigned long long phys_addr_t;
+typedef unsigned long long phys_size_t;
#endif /* __KERNEL__ */
diff --git a/board/AndesTech/ax25-ae350/ax25-ae350.c b/board/AndesTech/ax25-ae350/ax25-ae350.c
index 59a43e4dcc4..3125233488f 100644
--- a/board/AndesTech/ax25-ae350/ax25-ae350.c
+++ b/board/AndesTech/ax25-ae350/ax25-ae350.c
@@ -77,7 +77,7 @@ int smc_init(void)
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- regs = (struct ftsmc020_bank *)addr;
+ regs = (struct ftsmc020_bank *)(uintptr_t)addr;
regs->cr &= ~FTSMC020_BANK_WPROT;
return 0;
diff --git a/cmd/bdinfo.c b/cmd/bdinfo.c
index 8d8daa6336a..dfd50ae8491 100644
--- a/cmd/bdinfo.c
+++ b/cmd/bdinfo.c
@@ -18,11 +18,16 @@
DECLARE_GLOBAL_DATA_PTR;
-void bdinfo_print_num(const char *name, ulong value)
+void bdinfo_print_num_l(const char *name, ulong value)
{
printf("%-12s= 0x%0*lx\n", name, 2 * (int)sizeof(value), value);
}
+void bdinfo_print_num_ll(const char *name, unsigned long long value)
+{
+ printf("%-12s= 0x%.*llx\n", name, 2 * (int)sizeof(ulong), value);
+}
+
static void print_eth(int idx)
{
char name[10], *val;
@@ -36,12 +41,6 @@ static void print_eth(int idx)
printf("%-12s= %s\n", name, val);
}
-static void print_phys_addr(const char *name, phys_addr_t value)
-{
- printf("%-12s= 0x%.*llx\n", name, 2 * (int)sizeof(ulong),
- (unsigned long long)value);
-}
-
void bdinfo_print_mhz(const char *name, unsigned long hz)
{
char buf[32];
@@ -55,9 +54,9 @@ static void print_bi_dram(const struct bd_info *bd)
for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) {
if (bd->bi_dram[i].size) {
- bdinfo_print_num("DRAM bank", i);
- bdinfo_print_num("-> start", bd->bi_dram[i].start);
- bdinfo_print_num("-> size", bd->bi_dram[i].size);
+ bdinfo_print_num_l("DRAM bank", i);
+ bdinfo_print_num_ll("-> start", bd->bi_dram[i].start);
+ bdinfo_print_num_ll("-> size", bd->bi_dram[i].size);
}
}
}
@@ -77,9 +76,10 @@ static void show_video_info(void)
if (device_active(dev)) {
struct video_priv *upriv = dev_get_uclass_priv(dev);
- print_phys_addr("FB base", (ulong)upriv->fb);
+ bdinfo_print_num_ll("FB base", (ulong)upriv->fb);
if (upriv->copy_fb)
- print_phys_addr("FB copy", (ulong)upriv->copy_fb);
+ bdinfo_print_num_ll("FB copy",
+ (ulong)upriv->copy_fb);
printf("%-12s= %dx%dx%d\n", "FB size", upriv->xsize,
upriv->ysize, 1 << upriv->bpix);
}
@@ -91,36 +91,36 @@ int do_bdinfo(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
struct bd_info *bd = gd->bd;
#ifdef DEBUG
- bdinfo_print_num("bd address", (ulong)bd);
+ bdinfo_print_num_l("bd address", (ulong)bd);
#endif
- bdinfo_print_num("boot_params", (ulong)bd->bi_boot_params);
+ bdinfo_print_num_l("boot_params", (ulong)bd->bi_boot_params);
print_bi_dram(bd);
if (IS_ENABLED(CONFIG_SYS_HAS_SRAM)) {
- bdinfo_print_num("sramstart", (ulong)bd->bi_sramstart);
- bdinfo_print_num("sramsize", (ulong)bd->bi_sramsize);
+ bdinfo_print_num_l("sramstart", (ulong)bd->bi_sramstart);
+ bdinfo_print_num_l("sramsize", (ulong)bd->bi_sramsize);
}
- bdinfo_print_num("flashstart", (ulong)bd->bi_flashstart);
- bdinfo_print_num("flashsize", (ulong)bd->bi_flashsize);
- bdinfo_print_num("flashoffset", (ulong)bd->bi_flashoffset);
+ bdinfo_print_num_l("flashstart", (ulong)bd->bi_flashstart);
+ bdinfo_print_num_l("flashsize", (ulong)bd->bi_flashsize);
+ bdinfo_print_num_l("flashoffset", (ulong)bd->bi_flashoffset);
printf("baudrate = %u bps\n", gd->baudrate);
- bdinfo_print_num("relocaddr", gd->relocaddr);
- bdinfo_print_num("reloc off", gd->reloc_off);
+ bdinfo_print_num_l("relocaddr", gd->relocaddr);
+ bdinfo_print_num_l("reloc off", gd->reloc_off);
printf("%-12s= %u-bit\n", "Build", (uint)sizeof(void *) * 8);
if (IS_ENABLED(CONFIG_CMD_NET)) {
printf("current eth = %s\n", eth_get_name());
print_eth(0);
printf("IP addr = %s\n", env_get("ipaddr"));
}
- bdinfo_print_num("fdt_blob", (ulong)gd->fdt_blob);
- bdinfo_print_num("new_fdt", (ulong)gd->new_fdt);
- bdinfo_print_num("fdt_size", (ulong)gd->fdt_size);
+ bdinfo_print_num_l("fdt_blob", (ulong)gd->fdt_blob);
+ bdinfo_print_num_l("new_fdt", (ulong)gd->new_fdt);
+ bdinfo_print_num_l("fdt_size", (ulong)gd->fdt_size);
if (IS_ENABLED(CONFIG_DM_VIDEO))
show_video_info();
#if defined(CONFIG_LCD) || defined(CONFIG_VIDEO)
- bdinfo_print_num("FB base ", gd->fb_base);
+ bdinfo_print_num_l("FB base ", gd->fb_base);
#endif
#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
- bdinfo_print_num("multi_dtb_fit", (ulong)gd->multi_dtb_fit);
+ bdinfo_print_num_l("multi_dtb_fit", (ulong)gd->multi_dtb_fit);
#endif
if (gd->fdt_blob) {
struct lmb lmb;
diff --git a/doc/driver-model/design.rst b/doc/driver-model/design.rst
index ffed7d5f79a..2417976ab74 100644
--- a/doc/driver-model/design.rst
+++ b/doc/driver-model/design.rst
@@ -880,6 +880,26 @@ If a parent has children these will be destroyed first. After this point
the device does not exist and its memory has be deallocated.
+Special cases for removal
+-------------------------
+
+Some devices need to do clean-up before the OS is called. For example, a USB
+driver may want to stop the bus. This can be done in the remove() method.
+Some special flags are used to determine whether to remove the device:
+
+ DM_FLAG_OS_PREPARE - indicates that the device needs to get ready for OS
+ boot. The device will be removed just before the OS is booted
+ DM_REMOVE_ACTIVE_DMA - indicates that the device uses DMA. This is
+ effectively the same as DM_FLAG_OS_PREPARE, so the device is removed
+ before the OS is booted
+ DM_FLAG_VITAL - indicates that the device is 'vital' to the operation of
+ other devices. It is possible to remove this device after all regular
+ devices are removed. This is useful e.g. for a clock, which need to
+ be active during the device-removal phase.
+
+The dm_remove_devices_flags() function can be used to remove devices based on
+their driver flags.
+
Data Structures
---------------
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 7e8f3afb2d6..616dcf07859 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -8,6 +8,8 @@
* Pavel Herrmann <morpheus.ibis@gmail.com>
*/
+#define LOG_CATEGORY LOGC_DM
+
#include <common.h>
#include <errno.h>
#include <log.h>
@@ -45,20 +47,24 @@ int device_chld_remove(struct udevice *dev, struct driver *drv,
uint flags)
{
struct udevice *pos, *n;
- int ret;
+ int result = 0;
assert(dev);
list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
+ int ret;
+
if (drv && (pos->driver != drv))
continue;
ret = device_remove(pos, flags);
- if (ret)
+ if (ret == -EPROBE_DEFER)
+ result = ret;
+ else if (ret && ret != -EKEYREJECTED)
return ret;
}
- return 0;
+ return result;
}
int device_unbind(struct udevice *dev)
@@ -149,13 +155,43 @@ void device_free(struct udevice *dev)
devres_release_probe(dev);
}
-static bool flags_remove(uint flags, uint drv_flags)
+/**
+ * flags_remove() - Figure out whether to remove a device
+ *
+ * If this is called with @flags == DM_REMOVE_NON_VITAL | DM_REMOVE_ACTIVE_DMA,
+ * then it returns 0 (=go head and remove) if the device is not matked vital
+ * but is marked DM_REMOVE_ACTIVE_DMA.
+ *
+ * If this is called with @flags == DM_REMOVE_ACTIVE_DMA,
+ * then it returns 0 (=go head and remove) if the device is marked
+ * DM_REMOVE_ACTIVE_DMA, regardless of whether it is marked vital.
+ *
+ * @flags: Flags passed to device_remove()
+ * @drv_flags: Driver flags
+ * @return 0 if the device should be removed,
+ * -EKEYREJECTED if @flags includes a flag in DM_REMOVE_ACTIVE_ALL but
+ * @drv_flags does not (indicates that this device has nothing to do for
+ * DMA shutdown or OS prepare)
+ * -EPROBE_DEFER if @flags is DM_REMOVE_NON_VITAL but @drv_flags contains
+ * DM_FLAG_VITAL (indicates the device is vital and should not be removed)
+ */
+static int flags_remove(uint flags, uint drv_flags)
{
- if ((flags & DM_REMOVE_NORMAL) ||
- (flags && (drv_flags & (DM_FLAG_ACTIVE_DMA | DM_FLAG_OS_PREPARE))))
- return true;
+ if (!(flags & DM_REMOVE_NORMAL)) {
+ bool vital_match;
+ bool active_match;
+
+ active_match = !(flags & DM_REMOVE_ACTIVE_ALL) ||
+ (drv_flags & flags);
+ vital_match = !(flags & DM_REMOVE_NON_VITAL) ||
+ !(drv_flags & DM_FLAG_VITAL);
+ if (!vital_match)
+ return -EPROBE_DEFER;
+ if (!active_match)
+ return -EKEYREJECTED;
+ }
- return false;
+ return 0;
}
int device_remove(struct udevice *dev, uint flags)
@@ -169,22 +205,32 @@ int device_remove(struct udevice *dev, uint flags)
if (!(dev_get_flags(dev) & DM_FLAG_ACTIVATED))
return 0;
+ /*
+ * If the child returns EKEYREJECTED, continue. It just means that it
+ * didn't match the flags.
+ */
+ ret = device_chld_remove(dev, NULL, flags);
+ if (ret && ret != -EKEYREJECTED)
+ return ret;
+
+ /*
+ * Remove the device if called with the "normal" remove flag set,
+ * or if the remove flag matches any of the drivers remove flags
+ */
drv = dev->driver;
assert(drv);
+ ret = flags_remove(flags, drv->flags);
+ if (ret) {
+ log_debug("%s: When removing: flags=%x, drv->flags=%x, err=%d\n",
+ dev->name, flags, drv->flags, ret);
+ return ret;
+ }
ret = uclass_pre_remove_device(dev);
if (ret)
return ret;
- ret = device_chld_remove(dev, NULL, flags);
- if (ret)
- goto err;
-
- /*
- * Remove the device if called with the "normal" remove flag set,
- * or if the remove flag matches any of the drivers remove flags
- */
- if (drv->remove && flags_remove(flags, drv->flags)) {
+ if (drv->remove) {
ret = drv->remove(dev);
if (ret)
goto err_remove;
@@ -200,28 +246,20 @@ int device_remove(struct udevice *dev, uint flags)
if (!(flags & DM_REMOVE_NO_PD) &&
!(drv->flags &
- (DM_FLAG_DEFAULT_PD_CTRL_OFF | DM_FLAG_REMOVE_WITH_PD_ON)) &&
+ (DM_FLAG_DEFAULT_PD_CTRL_OFF | DM_FLAG_LEAVE_PD_ON)) &&
dev != gd->cur_serial_dev)
dev_power_domain_off(dev);
- if (flags_remove(flags, drv->flags)) {
- device_free(dev);
+ device_free(dev);
- dev_bic_flags(dev, DM_FLAG_ACTIVATED);
- }
+ dev_bic_flags(dev, DM_FLAG_ACTIVATED);
- return ret;
+ return 0;
err_remove:
/* We can't put the children back */
dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
__func__, dev->name);
-err:
- ret = uclass_post_probe_device(dev);
- if (ret) {
- dm_warn("%s: Device '%s' failed to post_probe on error path\n",
- __func__, dev->name);
- }
return ret;
}
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 2bfa75b4725..7ef2ec2da27 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -162,6 +162,8 @@ int dm_init(bool of_live)
int dm_uninit(void)
{
+ /* Remove non-vital devices first */
+ device_remove(dm_root(), DM_REMOVE_NON_VITAL);
device_remove(dm_root(), DM_REMOVE_NORMAL);
device_unbind(dm_root());
gd->dm_root = NULL;
diff --git a/drivers/firmware/scmi/sandbox-scmi_devices.c b/drivers/firmware/scmi/sandbox-scmi_devices.c
index 414da6f4df1..1a6fafbf531 100644
--- a/drivers/firmware/scmi/sandbox-scmi_devices.c
+++ b/drivers/firmware/scmi/sandbox-scmi_devices.c
@@ -50,6 +50,9 @@ static int sandbox_scmi_devices_remove(struct udevice *dev)
int ret = 0;
size_t n;
+ if (!devices)
+ return 0;
+
for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
int ret2 = reset_free(devices->reset + n);
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index 7349a9bc99e..99a1c2e6e2e 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -2526,10 +2526,7 @@ int brcmnand_probe(struct udevice *dev, struct brcmnand_soc *soc)
if (ret)
return ret;
} else {
- ret = PTR_ERR(ctrl->clk);
- if (ret == -EPROBE_DEFER)
- return ret;
-
+ /* Ignore PTR_ERR(ctrl->clk) */
ctrl->clk = NULL;
}
diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c
index 0d672374fda..fc578b03752 100644
--- a/drivers/net/ftmac100.c
+++ b/drivers/net/ftmac100.c
@@ -35,7 +35,7 @@ struct ftmac100_data {
*/
static void ftmac100_reset(struct ftmac100_data *priv)
{
- struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase;
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)(uintptr_t)priv->iobase;
debug ("%s()\n", __func__);
@@ -56,7 +56,7 @@ static void ftmac100_reset(struct ftmac100_data *priv)
static void ftmac100_set_mac(struct ftmac100_data *priv ,
const unsigned char *mac)
{
- struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase;
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)(uintptr_t)priv->iobase;
unsigned int maddr = mac[0] << 8 | mac[1];
unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
@@ -71,7 +71,7 @@ static void ftmac100_set_mac(struct ftmac100_data *priv ,
*/
static void _ftmac100_halt(struct ftmac100_data *priv)
{
- struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase;
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)(uintptr_t)priv->iobase;
debug ("%s()\n", __func__);
writel (0, &ftmac100->maccr);
}
@@ -81,7 +81,7 @@ static void _ftmac100_halt(struct ftmac100_data *priv)
*/
static int _ftmac100_init(struct ftmac100_data *priv, unsigned char enetaddr[6])
{
- struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase;
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)(uintptr_t)priv->iobase;
struct ftmac100_txdes *txdes = priv->txdes;
struct ftmac100_rxdes *rxdes = priv->rxdes;
unsigned int maccr;
@@ -186,7 +186,7 @@ static int __ftmac100_recv(struct ftmac100_data *priv)
*/
static int _ftmac100_send(struct ftmac100_data *priv, void *packet, int length)
{
- struct ftmac100 *ftmac100 = (struct ftmac100 *)priv->iobase;
+ struct ftmac100 *ftmac100 = (struct ftmac100 *)(uintptr_t)priv->iobase;
struct ftmac100_txdes *curr_des = priv->txdes;
ulong start;
diff --git a/drivers/pci/pcie_iproc.c b/drivers/pci/pcie_iproc.c
index 6725ff64372..12ce9d525ca 100644
--- a/drivers/pci/pcie_iproc.c
+++ b/drivers/pci/pcie_iproc.c
@@ -1283,5 +1283,5 @@ U_BOOT_DRIVER(pci_iproc) = {
.probe = iproc_pcie_probe,
.remove = iproc_pcie_remove,
.priv_auto = sizeof(struct iproc_pcie),
- .flags = DM_REMOVE_OS_PREPARE,
+ .flags = DM_FLAG_OS_PREPARE,
};
diff --git a/drivers/serial/serial_sifive.c b/drivers/serial/serial_sifive.c
index d26fe7e7704..97bf20c967a 100644
--- a/drivers/serial/serial_sifive.c
+++ b/drivers/serial/serial_sifive.c
@@ -178,7 +178,7 @@ static int sifive_serial_of_to_plat(struct udevice *dev)
{
struct sifive_uart_plat *plat = dev_get_plat(dev);
- plat->regs = (struct uart_sifive *)dev_read_addr(dev);
+ plat->regs = (struct uart_sifive *)(uintptr_t)dev_read_addr(dev);
if (IS_ERR(plat->regs))
return PTR_ERR(plat->regs);
diff --git a/drivers/smem/msm_smem.c b/drivers/smem/msm_smem.c
index 597d425d11f..26462151b3a 100644
--- a/drivers/smem/msm_smem.c
+++ b/drivers/smem/msm_smem.c
@@ -437,7 +437,7 @@ static int qcom_smem_alloc(unsigned int host, unsigned int item, size_t size)
int ret;
if (!__smem)
- return -EPROBE_DEFER;
+ return -ENOMEM;
if (item < SMEM_ITEM_LAST_FIXED) {
dev_err(__smem->dev,
@@ -559,7 +559,7 @@ static void *qcom_smem_get(unsigned int host, unsigned int item, size_t *size)
{
struct smem_partition_header *phdr;
size_t cacheln;
- void *ptr = ERR_PTR(-EPROBE_DEFER);
+ void *ptr = ERR_PTR(-ENOMEM);
if (!__smem)
return ptr;
@@ -597,7 +597,7 @@ static int qcom_smem_get_free_space(unsigned int host)
unsigned int ret;
if (!__smem)
- return -EPROBE_DEFER;
+ return -ENOMEM;
if (host < SMEM_HOST_COUNT && __smem->partitions[host]) {
phdr = __smem->partitions[host];
diff --git a/drivers/video/meson/meson_vpu.c b/drivers/video/meson/meson_vpu.c
index ca6933a6c54..558f9ba766c 100644
--- a/drivers/video/meson/meson_vpu.c
+++ b/drivers/video/meson/meson_vpu.c
@@ -212,5 +212,5 @@ U_BOOT_DRIVER(meson_vpu) = {
.probe = meson_vpu_probe,
.bind = meson_vpu_bind,
.priv_auto = sizeof(struct meson_vpu_priv),
- .flags = DM_FLAG_PRE_RELOC | DM_FLAG_REMOVE_WITH_PD_ON,
+ .flags = DM_FLAG_PRE_RELOC | DM_FLAG_LEAVE_PD_ON,
};
diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c
index f64a39f6579..8335b20ae84 100644
--- a/drivers/watchdog/rti_wdt.c
+++ b/drivers/watchdog/rti_wdt.c
@@ -119,5 +119,5 @@ U_BOOT_DRIVER(rti_wdt) = {
.ops = &rti_wdt_ops,
.probe = rti_wdt_probe,
.priv_auto = sizeof(struct rti_wdt_priv),
- .flags = DM_FLAG_REMOVE_WITH_PD_ON,
+ .flags = DM_FLAG_LEAVE_PD_ON,
};
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index b6f707e97e5..998beb01760 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -147,7 +147,7 @@ struct global_data {
/**
* @ram_top: top address of RAM used by U-Boot
*/
- unsigned long ram_top;
+ phys_addr_t ram_top;
/**
* @relocaddr: start address of U-Boot in RAM
*
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 639bbd293d9..39406c3f352 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -123,7 +123,9 @@ int device_probe(struct udevice *dev);
*
* @dev: Pointer to device to remove
* @flags: Flags for selective device removal (DM_REMOVE_...)
- * @return 0 if OK, -ve on error (an error here is normally a very bad thing)
+ * @return 0 if OK, -EKEYREJECTED if not removed due to flags, -EPROBE_DEFER if
+ * this is a vital device and flags is DM_REMOVE_NON_VITAL, other -ve on
+ * error (such an error here is normally a very bad thing)
*/
#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
int device_remove(struct udevice *dev, uint flags);
@@ -173,10 +175,19 @@ static inline int device_chld_unbind(struct udevice *dev, struct driver *drv)
/**
* device_chld_remove() - Stop all device's children
+ *
+ * This continues through all children recursively stopping part-way through if
+ * an error occurs. Return values of -EKEYREJECTED are ignored and processing
+ * continues, since they just indicate that the child did not elect to be
+ * removed based on the value of @flags. Return values of -EPROBE_DEFER cause
+ * processing of other children to continue, but the function will return
+ * -EPROBE_DEFER.
+ *
* @dev: The device whose children are to be removed
* @drv: The targeted driver
* @flags: Flag, if this functions is called in the pre-OS stage
- * @return 0 on success, -ve on error
+ * @return 0 on success, -EPROBE_DEFER if any child failed to remove, other
+ * -ve on error
*/
#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
int device_chld_remove(struct udevice *dev, struct driver *drv,
diff --git a/include/dm/device.h b/include/dm/device.h
index e665558444b..28533ce0b6d 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -71,12 +71,22 @@ struct driver_info;
* Device is removed without switching off its power domain. This might
* be required, i. e. for serial console (debug) output when booting OS.
*/
-#define DM_FLAG_REMOVE_WITH_PD_ON (1 << 13)
+#define DM_FLAG_LEAVE_PD_ON (1 << 13)
+
+/*
+ * Device is vital to the operation of other devices. It is possible to remove
+ * removed this device after all regular devices are removed. This is useful
+ * e.g. for clock, which need to be active during the device-removal phase.
+ */
+#define DM_FLAG_VITAL (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
* driver flags can be done.
+ *
+ * DO NOT use these flags in your driver's @flags value...
+ * use the above DM_FLAG_... values instead
*/
enum {
/* Normal remove, remove all devices */
@@ -88,7 +98,8 @@ enum {
/* Remove devices which need some final OS preparation steps */
DM_REMOVE_OS_PREPARE = DM_FLAG_OS_PREPARE,
- /* Add more use cases here */
+ /* Remove only devices that are not marked vital */
+ DM_REMOVE_NON_VITAL = DM_FLAG_VITAL,
/* Remove devices with any active flag */
DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA | DM_REMOVE_OS_PREPARE,
diff --git a/include/init.h b/include/init.h
index 980be279936..88f84599e9e 100644
--- a/include/init.h
+++ b/include/init.h
@@ -326,7 +326,8 @@ void relocate_code(ulong start_addr_sp, struct global_data *new_gd,
#endif
/* Print a numeric value (for use in arch_print_bdinfo()) */
-void bdinfo_print_num(const char *name, ulong value);
+void bdinfo_print_num_l(const char *name, ulong value);
+void bdinfo_print_num_ll(const char *name, unsigned long long value);
/* Print a clock speed in MHz */
void bdinfo_print_mhz(const char *name, unsigned long hz);
diff --git a/include/os.h b/include/os.h
index e192e32d592..65bcb232cab 100644
--- a/include/os.h
+++ b/include/os.h
@@ -341,7 +341,7 @@ void os_localtime(struct rtc_time *rt);
/**
* os_abort() - raise SIGABRT to exit sandbox (e.g. to debugger)
*/
-void os_abort(void);
+void os_abort(void) __attribute__((noreturn));
/**
* os_mprotect_allow() - Remove write-protection on a region of memory
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index a2d2fb4e1fe..e048f7777d6 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -1572,7 +1572,7 @@ int fdtdec_setup(void)
return -1;
}
# elif defined(CONFIG_OF_PRIOR_STAGE)
- gd->fdt_blob = (void *)prior_stage_fdt_address;
+ gd->fdt_blob = (void *)(uintptr_t)prior_stage_fdt_address;
# endif
# ifndef CONFIG_SPL_BUILD
/* Allow the early environment to override the fdt address */
diff --git a/test/dm/core.c b/test/dm/core.c
index 1f5ca570dc7..bfd6565d952 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -72,6 +72,14 @@ static struct driver_info driver_info_act_dma = {
.name = "test_act_dma_drv",
};
+static struct driver_info driver_info_vital_clk = {
+ .name = "test_vital_clk_drv",
+};
+
+static struct driver_info driver_info_act_dma_vital_clk = {
+ .name = "test_act_dma_vital_clk_drv",
+};
+
void dm_leak_check_start(struct unit_test_state *uts)
{
uts->start = mallinfo();
@@ -883,6 +891,92 @@ static int dm_test_remove_active_dma(struct unit_test_state *uts)
}
DM_TEST(dm_test_remove_active_dma, 0);
+/* Test removal of 'vital' devices */
+static int dm_test_remove_vital(struct unit_test_state *uts)
+{
+ struct dm_test_state *dms = uts->priv;
+ struct udevice *normal, *dma, *vital, *dma_vital;
+
+ /* Skip the behaviour in test_post_probe() */
+ dms->skip_post_probe = 1;
+
+ ut_assertok(device_bind_by_name(dms->root, false, &driver_info_manual,
+ &normal));
+ ut_assertnonnull(normal);
+
+ ut_assertok(device_bind_by_name(dms->root, false, &driver_info_act_dma,
+ &dma));
+ ut_assertnonnull(dma);
+
+ ut_assertok(device_bind_by_name(dms->root, false,
+ &driver_info_vital_clk, &vital));
+ ut_assertnonnull(vital);
+
+ ut_assertok(device_bind_by_name(dms->root, false,
+ &driver_info_act_dma_vital_clk,
+ &dma_vital));
+ ut_assertnonnull(dma_vital);
+
+ /* Probe the devices */
+ ut_assertok(device_probe(normal));
+ ut_assertok(device_probe(dma));
+ ut_assertok(device_probe(vital));
+ ut_assertok(device_probe(dma_vital));
+
+ /* Check that devices are active right now */
+ ut_asserteq(true, device_active(normal));
+ ut_asserteq(true, device_active(dma));
+ ut_asserteq(true, device_active(vital));
+ ut_asserteq(true, device_active(dma_vital));
+
+ /* Remove active devices via selective remove flag */
+ dm_remove_devices_flags(DM_REMOVE_NON_VITAL | DM_REMOVE_ACTIVE_ALL);
+
+ /*
+ * Check that this only has an effect on the dma device, since two
+ * devices are vital and the third does not have active DMA
+ */
+ ut_asserteq(true, device_active(normal));
+ ut_asserteq(false, device_active(dma));
+ ut_asserteq(true, device_active(vital));
+ ut_asserteq(true, device_active(dma_vital));
+
+ /* Remove active devices via selective remove flag */
+ ut_assertok(device_probe(dma));
+ dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
+
+ /* This should have affected both active-dma devices */
+ ut_asserteq(true, device_active(normal));
+ ut_asserteq(false, device_active(dma));
+ ut_asserteq(true, device_active(vital));
+ ut_asserteq(false, device_active(dma_vital));
+
+ /* Remove non-vital devices */
+ ut_assertok(device_probe(dma));
+ ut_assertok(device_probe(dma_vital));
+ dm_remove_devices_flags(DM_REMOVE_NON_VITAL);
+
+ /* This should have affected only non-vital devices */
+ ut_asserteq(false, device_active(normal));
+ ut_asserteq(false, device_active(dma));
+ ut_asserteq(true, device_active(vital));
+ ut_asserteq(true, device_active(dma_vital));
+
+ /* Remove vital devices via normal remove flag */
+ ut_assertok(device_probe(normal));
+ ut_assertok(device_probe(dma));
+ dm_remove_devices_flags(DM_REMOVE_NORMAL);
+
+ /* Check that all devices are inactive right now */
+ ut_asserteq(false, device_active(normal));
+ ut_asserteq(false, device_active(dma));
+ ut_asserteq(false, device_active(vital));
+ ut_asserteq(false, device_active(dma_vital));
+
+ return 0;
+}
+DM_TEST(dm_test_remove_vital, 0);
+
static int dm_test_uclass_before_ready(struct unit_test_state *uts)
{
struct uclass *uc;
diff --git a/test/dm/test-driver.c b/test/dm/test-driver.c
index a67f5d3f982..ca7626a0668 100644
--- a/test/dm/test-driver.c
+++ b/test/dm/test-driver.c
@@ -170,3 +170,25 @@ U_BOOT_DRIVER(test_act_dma_drv) = {
.unbind = test_manual_unbind,
.flags = DM_FLAG_ACTIVE_DMA,
};
+
+U_BOOT_DRIVER(test_vital_clk_drv) = {
+ .name = "test_vital_clk_drv",
+ .id = UCLASS_TEST,
+ .ops = &test_manual_ops,
+ .bind = test_manual_bind,
+ .probe = test_manual_probe,
+ .remove = test_manual_remove,
+ .unbind = test_manual_unbind,
+ .flags = DM_FLAG_VITAL,
+};
+
+U_BOOT_DRIVER(test_act_dma_vital_clk_drv) = {
+ .name = "test_act_dma_vital_clk_drv",
+ .id = UCLASS_TEST,
+ .ops = &test_manual_ops,
+ .bind = test_manual_bind,
+ .probe = test_manual_probe,
+ .remove = test_manual_remove,
+ .unbind = test_manual_unbind,
+ .flags = DM_FLAG_VITAL | DM_FLAG_ACTIVE_DMA,
+};
diff --git a/test/dm/virtio.c b/test/dm/virtio.c
index ad355981cf4..9a7e658cceb 100644
--- a/test/dm/virtio.c
+++ b/test/dm/virtio.c
@@ -123,7 +123,9 @@ static int dm_test_virtio_remove(struct unit_test_state *uts)
/* check the device can be successfully removed */
dev_or_flags(dev, DM_FLAG_ACTIVATED);
- ut_assertok(device_remove(bus, DM_REMOVE_ACTIVE_ALL));
+ ut_asserteq(-EKEYREJECTED, device_remove(bus, DM_REMOVE_ACTIVE_ALL));
+
+ ut_asserteq(false, device_active(dev));
return 0;
}