xref: /rk3399_rockchip-uboot/drivers/core/device-remove.c (revision 608f26c51bebc68db7f2edc7590ee513d2bc5465)
13ac435d3SSimon Glass /*
23ac435d3SSimon Glass  * Device manager
33ac435d3SSimon Glass  *
43ac435d3SSimon Glass  * Copyright (c) 2014 Google, Inc
53ac435d3SSimon Glass  *
63ac435d3SSimon Glass  * (C) Copyright 2012
73ac435d3SSimon Glass  * Pavel Herrmann <morpheus.ibis@gmail.com>
83ac435d3SSimon Glass  *
93ac435d3SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
103ac435d3SSimon Glass  */
113ac435d3SSimon Glass 
123ac435d3SSimon Glass #include <common.h>
133ac435d3SSimon Glass #include <errno.h>
143ac435d3SSimon Glass #include <malloc.h>
153ac435d3SSimon Glass #include <dm/device.h>
163ac435d3SSimon Glass #include <dm/device-internal.h>
173ac435d3SSimon Glass #include <dm/uclass.h>
183ac435d3SSimon Glass #include <dm/uclass-internal.h>
193ac435d3SSimon Glass #include <dm/util.h>
203ac435d3SSimon Glass 
21bb52b367SHans de Goede int device_unbind_children(struct udevice *dev)
223ac435d3SSimon Glass {
233ac435d3SSimon Glass 	struct udevice *pos, *n;
243ac435d3SSimon Glass 	int ret, saved_ret = 0;
253ac435d3SSimon Glass 
263ac435d3SSimon Glass 	assert(dev);
273ac435d3SSimon Glass 
283ac435d3SSimon Glass 	list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
293ac435d3SSimon Glass 		ret = device_unbind(pos);
303ac435d3SSimon Glass 		if (ret && !saved_ret)
313ac435d3SSimon Glass 			saved_ret = ret;
323ac435d3SSimon Glass 	}
333ac435d3SSimon Glass 
343ac435d3SSimon Glass 	return saved_ret;
353ac435d3SSimon Glass }
363ac435d3SSimon Glass 
37bb52b367SHans de Goede int device_remove_children(struct udevice *dev)
383ac435d3SSimon Glass {
393ac435d3SSimon Glass 	struct udevice *pos, *n;
403ac435d3SSimon Glass 	int ret;
413ac435d3SSimon Glass 
423ac435d3SSimon Glass 	assert(dev);
433ac435d3SSimon Glass 
443ac435d3SSimon Glass 	list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
453ac435d3SSimon Glass 		ret = device_remove(pos);
463ac435d3SSimon Glass 		if (ret)
473ac435d3SSimon Glass 			return ret;
483ac435d3SSimon Glass 	}
493ac435d3SSimon Glass 
503ac435d3SSimon Glass 	return 0;
513ac435d3SSimon Glass }
523ac435d3SSimon Glass 
533ac435d3SSimon Glass int device_unbind(struct udevice *dev)
543ac435d3SSimon Glass {
553479253dSSimon Glass 	const struct driver *drv;
563ac435d3SSimon Glass 	int ret;
573ac435d3SSimon Glass 
583ac435d3SSimon Glass 	if (!dev)
593ac435d3SSimon Glass 		return -EINVAL;
603ac435d3SSimon Glass 
613ac435d3SSimon Glass 	if (dev->flags & DM_FLAG_ACTIVATED)
623ac435d3SSimon Glass 		return -EINVAL;
633ac435d3SSimon Glass 
64aed1a4ddSMasahiro Yamada 	if (!(dev->flags & DM_FLAG_BOUND))
65aed1a4ddSMasahiro Yamada 		return -EINVAL;
66aed1a4ddSMasahiro Yamada 
673ac435d3SSimon Glass 	drv = dev->driver;
683ac435d3SSimon Glass 	assert(drv);
693ac435d3SSimon Glass 
703ac435d3SSimon Glass 	if (drv->unbind) {
713ac435d3SSimon Glass 		ret = drv->unbind(dev);
723ac435d3SSimon Glass 		if (ret)
733ac435d3SSimon Glass 			return ret;
743ac435d3SSimon Glass 	}
753ac435d3SSimon Glass 
76bb52b367SHans de Goede 	ret = device_unbind_children(dev);
773ac435d3SSimon Glass 	if (ret)
783ac435d3SSimon Glass 		return ret;
793ac435d3SSimon Glass 
80f8a85449SSimon Glass 	if (dev->flags & DM_FLAG_ALLOC_PDATA) {
81f8a85449SSimon Glass 		free(dev->platdata);
82f8a85449SSimon Glass 		dev->platdata = NULL;
83f8a85449SSimon Glass 	}
845eaed880SPrzemyslaw Marczak 	if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
855eaed880SPrzemyslaw Marczak 		free(dev->uclass_platdata);
865eaed880SPrzemyslaw Marczak 		dev->uclass_platdata = NULL;
875eaed880SPrzemyslaw Marczak 	}
88cdc133bdSSimon Glass 	if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
89cdc133bdSSimon Glass 		free(dev->parent_platdata);
90cdc133bdSSimon Glass 		dev->parent_platdata = NULL;
91cdc133bdSSimon Glass 	}
923ac435d3SSimon Glass 	ret = uclass_unbind_device(dev);
933ac435d3SSimon Glass 	if (ret)
943ac435d3SSimon Glass 		return ret;
953ac435d3SSimon Glass 
963ac435d3SSimon Glass 	if (dev->parent)
973ac435d3SSimon Glass 		list_del(&dev->sibling_node);
98*608f26c5SMasahiro Yamada 
99*608f26c5SMasahiro Yamada 	devres_release_all(dev);
100*608f26c5SMasahiro Yamada 
1013ac435d3SSimon Glass 	free(dev);
1023ac435d3SSimon Glass 
1033ac435d3SSimon Glass 	return 0;
1043ac435d3SSimon Glass }
1053ac435d3SSimon Glass 
1063ac435d3SSimon Glass /**
1073ac435d3SSimon Glass  * device_free() - Free memory buffers allocated by a device
1083ac435d3SSimon Glass  * @dev:	Device that is to be started
1093ac435d3SSimon Glass  */
1103ac435d3SSimon Glass void device_free(struct udevice *dev)
1113ac435d3SSimon Glass {
1123ac435d3SSimon Glass 	int size;
1133ac435d3SSimon Glass 
1143ac435d3SSimon Glass 	if (dev->driver->priv_auto_alloc_size) {
1153ac435d3SSimon Glass 		free(dev->priv);
1163ac435d3SSimon Glass 		dev->priv = NULL;
1173ac435d3SSimon Glass 	}
1183ac435d3SSimon Glass 	size = dev->uclass->uc_drv->per_device_auto_alloc_size;
1193ac435d3SSimon Glass 	if (size) {
1203ac435d3SSimon Glass 		free(dev->uclass_priv);
1213ac435d3SSimon Glass 		dev->uclass_priv = NULL;
1223ac435d3SSimon Glass 	}
1233ac435d3SSimon Glass 	if (dev->parent) {
1243ac435d3SSimon Glass 		size = dev->parent->driver->per_child_auto_alloc_size;
125dac8db2cSSimon Glass 		if (!size) {
126dac8db2cSSimon Glass 			size = dev->parent->uclass->uc_drv->
127dac8db2cSSimon Glass 					per_child_auto_alloc_size;
128dac8db2cSSimon Glass 		}
1293ac435d3SSimon Glass 		if (size) {
1303ac435d3SSimon Glass 			free(dev->parent_priv);
1313ac435d3SSimon Glass 			dev->parent_priv = NULL;
1323ac435d3SSimon Glass 		}
1333ac435d3SSimon Glass 	}
134*608f26c5SMasahiro Yamada 
135*608f26c5SMasahiro Yamada 	devres_release_probe(dev);
1363ac435d3SSimon Glass }
1373ac435d3SSimon Glass 
1383ac435d3SSimon Glass int device_remove(struct udevice *dev)
1393ac435d3SSimon Glass {
1403479253dSSimon Glass 	const struct driver *drv;
1413ac435d3SSimon Glass 	int ret;
1423ac435d3SSimon Glass 
1433ac435d3SSimon Glass 	if (!dev)
1443ac435d3SSimon Glass 		return -EINVAL;
1453ac435d3SSimon Glass 
1463ac435d3SSimon Glass 	if (!(dev->flags & DM_FLAG_ACTIVATED))
1473ac435d3SSimon Glass 		return 0;
1483ac435d3SSimon Glass 
1493ac435d3SSimon Glass 	drv = dev->driver;
1503ac435d3SSimon Glass 	assert(drv);
1513ac435d3SSimon Glass 
1523ac435d3SSimon Glass 	ret = uclass_pre_remove_device(dev);
1533ac435d3SSimon Glass 	if (ret)
1543ac435d3SSimon Glass 		return ret;
1553ac435d3SSimon Glass 
156bb52b367SHans de Goede 	ret = device_remove_children(dev);
1573ac435d3SSimon Glass 	if (ret)
1583ac435d3SSimon Glass 		goto err;
1593ac435d3SSimon Glass 
1603ac435d3SSimon Glass 	if (drv->remove) {
1613ac435d3SSimon Glass 		ret = drv->remove(dev);
1623ac435d3SSimon Glass 		if (ret)
1633ac435d3SSimon Glass 			goto err_remove;
1643ac435d3SSimon Glass 	}
1653ac435d3SSimon Glass 
1663ac435d3SSimon Glass 	if (dev->parent && dev->parent->driver->child_post_remove) {
1673ac435d3SSimon Glass 		ret = dev->parent->driver->child_post_remove(dev);
1683ac435d3SSimon Glass 		if (ret) {
1693ac435d3SSimon Glass 			dm_warn("%s: Device '%s' failed child_post_remove()",
1703ac435d3SSimon Glass 				__func__, dev->name);
1713ac435d3SSimon Glass 		}
1723ac435d3SSimon Glass 	}
1733ac435d3SSimon Glass 
1743ac435d3SSimon Glass 	device_free(dev);
1753ac435d3SSimon Glass 
1763ac435d3SSimon Glass 	dev->seq = -1;
1773ac435d3SSimon Glass 	dev->flags &= ~DM_FLAG_ACTIVATED;
1783ac435d3SSimon Glass 
1793ac435d3SSimon Glass 	return ret;
1803ac435d3SSimon Glass 
1813ac435d3SSimon Glass err_remove:
1823ac435d3SSimon Glass 	/* We can't put the children back */
1833ac435d3SSimon Glass 	dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
1843ac435d3SSimon Glass 		__func__, dev->name);
1853ac435d3SSimon Glass err:
1863ac435d3SSimon Glass 	ret = uclass_post_probe_device(dev);
1873ac435d3SSimon Glass 	if (ret) {
1883ac435d3SSimon Glass 		dm_warn("%s: Device '%s' failed to post_probe on error path\n",
1893ac435d3SSimon Glass 			__func__, dev->name);
1903ac435d3SSimon Glass 	}
1913ac435d3SSimon Glass 
1923ac435d3SSimon Glass 	return ret;
1933ac435d3SSimon Glass }
194