summaryrefslogtreecommitdiff
path: root/drivers/core/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/core/device.c')
-rw-r--r--drivers/core/device.c320
1 files changed, 166 insertions, 154 deletions
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 4b3dcb3b37..aeab3836ed 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -34,13 +34,15 @@
DECLARE_GLOBAL_DATA_PTR;
static int device_bind_common(struct udevice *parent, const struct driver *drv,
- const char *name, void *platdata,
+ const char *name, void *plat,
ulong driver_data, ofnode node,
- uint of_platdata_size, struct udevice **devp)
+ uint of_plat_size, struct udevice **devp)
{
struct udevice *dev;
struct uclass *uc;
int size, ret = 0;
+ bool auto_seq = true;
+ void *ptr;
if (devp)
*devp = NULL;
@@ -63,88 +65,79 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
#ifdef CONFIG_DEVRES
INIT_LIST_HEAD(&dev->devres_head);
#endif
- dev->platdata = platdata;
+ dev_set_plat(dev, plat);
dev->driver_data = driver_data;
dev->name = name;
- dev->node = node;
+ dev_set_ofnode(dev, node);
dev->parent = parent;
dev->driver = drv;
dev->uclass = uc;
- dev->seq = -1;
- dev->req_seq = -1;
+ dev->seq_ = -1;
if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) &&
(uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) {
/*
* Some devices, such as a SPI bus, I2C bus and serial ports
* are numbered using aliases.
- *
- * This is just a 'requested' sequence, and will be
- * resolved (and ->seq updated) when the device is probed.
*/
if (CONFIG_IS_ENABLED(OF_CONTROL) &&
!CONFIG_IS_ENABLED(OF_PLATDATA)) {
- if (uc->uc_drv->name && ofnode_valid(node))
- dev_read_alias_seq(dev, &dev->req_seq);
-#if CONFIG_IS_ENABLED(OF_PRIOR_STAGE)
- if (dev->req_seq == -1)
- dev->req_seq =
- uclass_find_next_free_req_seq(drv->id);
-#endif
- } else {
- dev->req_seq = uclass_find_next_free_req_seq(drv->id);
+ if (uc->uc_drv->name && ofnode_valid(node)) {
+ if (!dev_read_alias_seq(dev, &dev->seq_))
+ auto_seq = false;
+ }
}
}
+ if (auto_seq && !(uc->uc_drv->flags & DM_UC_FLAG_NO_AUTO_SEQ))
+ dev->seq_ = uclass_find_next_free_seq(uc);
- if (drv->platdata_auto_alloc_size) {
- bool alloc = !platdata;
+ if (drv->plat_auto) {
+ bool alloc = !plat;
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
- if (of_platdata_size) {
- dev->flags |= DM_FLAG_OF_PLATDATA;
- if (of_platdata_size <
- drv->platdata_auto_alloc_size)
+ if (of_plat_size) {
+ dev_or_flags(dev, DM_FLAG_OF_PLATDATA);
+ if (of_plat_size < drv->plat_auto)
alloc = true;
}
}
if (alloc) {
- dev->flags |= DM_FLAG_ALLOC_PDATA;
- dev->platdata = calloc(1,
- drv->platdata_auto_alloc_size);
- if (!dev->platdata) {
+ dev_or_flags(dev, DM_FLAG_ALLOC_PDATA);
+ ptr = calloc(1, drv->plat_auto);
+ if (!ptr) {
ret = -ENOMEM;
goto fail_alloc1;
}
- if (CONFIG_IS_ENABLED(OF_PLATDATA) && platdata) {
- memcpy(dev->platdata, platdata,
- of_platdata_size);
- }
+ if (CONFIG_IS_ENABLED(OF_PLATDATA) && plat)
+ memcpy(ptr, plat, of_plat_size);
+ dev_set_plat(dev, ptr);
}
}
- size = uc->uc_drv->per_device_platdata_auto_alloc_size;
+ size = uc->uc_drv->per_device_plat_auto;
if (size) {
- dev->flags |= DM_FLAG_ALLOC_UCLASS_PDATA;
- dev->uclass_platdata = calloc(1, size);
- if (!dev->uclass_platdata) {
+ dev_or_flags(dev, DM_FLAG_ALLOC_UCLASS_PDATA);
+ ptr = calloc(1, size);
+ if (!ptr) {
ret = -ENOMEM;
goto fail_alloc2;
}
+ dev_set_uclass_plat(dev, ptr);
}
if (parent) {
- size = parent->driver->per_child_platdata_auto_alloc_size;
+ size = parent->driver->per_child_plat_auto;
if (!size) {
- size = parent->uclass->uc_drv->
- per_child_platdata_auto_alloc_size;
+ size = parent->uclass->uc_drv->per_child_plat_auto;
}
if (size) {
- dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA;
- dev->parent_platdata = calloc(1, size);
- if (!dev->parent_platdata) {
+ dev_or_flags(dev, DM_FLAG_ALLOC_PARENT_PDATA);
+ ptr = calloc(1, size);
+ if (!ptr) {
ret = -ENOMEM;
goto fail_alloc3;
}
+ dev_set_parent_plat(dev, ptr);
}
/* put dev into parent's successor list */
list_add_tail(&dev->sibling_node, &parent->child_head);
@@ -176,7 +169,7 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
if (devp)
*devp = dev;
- dev->flags |= DM_FLAG_BOUND;
+ dev_or_flags(dev, DM_FLAG_BOUND);
return 0;
@@ -200,20 +193,20 @@ fail_bind:
fail_uclass_bind:
if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
list_del(&dev->sibling_node);
- if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
- free(dev->parent_platdata);
- dev->parent_platdata = NULL;
+ if (dev_get_flags(dev) & DM_FLAG_ALLOC_PARENT_PDATA) {
+ free(dev_get_parent_plat(dev));
+ dev_set_parent_plat(dev, NULL);
}
}
fail_alloc3:
- if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
- free(dev->uclass_platdata);
- dev->uclass_platdata = NULL;
+ if (dev_get_flags(dev) & DM_FLAG_ALLOC_UCLASS_PDATA) {
+ free(dev_get_uclass_plat(dev));
+ dev_set_uclass_plat(dev, NULL);
}
fail_alloc2:
- if (dev->flags & DM_FLAG_ALLOC_PDATA) {
- free(dev->platdata);
- dev->platdata = NULL;
+ if (dev_get_flags(dev) & DM_FLAG_ALLOC_PDATA) {
+ free(dev_get_plat(dev));
+ dev_set_plat(dev, NULL);
}
fail_alloc1:
devres_release_all(dev);
@@ -233,18 +226,10 @@ int device_bind_with_driver_data(struct udevice *parent,
}
int device_bind(struct udevice *parent, const struct driver *drv,
- const char *name, void *platdata, int of_offset,
+ const char *name, void *plat, ofnode node,
struct udevice **devp)
{
- return device_bind_common(parent, drv, name, platdata, 0,
- offset_to_ofnode(of_offset), 0, devp);
-}
-
-int device_bind_ofnode(struct udevice *parent, const struct driver *drv,
- const char *name, void *platdata, ofnode node,
- struct udevice **devp)
-{
- return device_bind_common(parent, drv, name, platdata, 0, node, 0,
+ return device_bind_common(parent, drv, name, plat, 0, node, 0,
devp);
}
@@ -252,7 +237,7 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
const struct driver_info *info, struct udevice **devp)
{
struct driver *drv;
- uint platdata_size = 0;
+ uint plat_size = 0;
int ret;
drv = lists_driver_lookup_name(info->name);
@@ -262,11 +247,10 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
return -EPERM;
#if CONFIG_IS_ENABLED(OF_PLATDATA)
- platdata_size = info->platdata_size;
+ plat_size = info->plat_size;
#endif
- ret = device_bind_common(parent, drv, info->name,
- (void *)info->platdata, 0, ofnode_null(),
- platdata_size, devp);
+ ret = device_bind_common(parent, drv, info->name, (void *)info->plat, 0,
+ ofnode_null(), plat_size, devp);
if (ret)
return ret;
@@ -339,21 +323,68 @@ static void *alloc_priv(int size, uint flags)
return priv;
}
-int device_ofdata_to_platdata(struct udevice *dev)
+/**
+ * device_alloc_priv() - Allocate priv/plat data required by the device
+ *
+ * @dev: Device to process
+ * @return 0 if OK, -ENOMEM if out of memory
+ */
+static int device_alloc_priv(struct udevice *dev)
+{
+ const struct driver *drv;
+ void *ptr;
+ int size;
+
+ drv = dev->driver;
+ assert(drv);
+
+ /* Allocate private data if requested and not reentered */
+ if (drv->priv_auto && !dev_get_priv(dev)) {
+ ptr = alloc_priv(drv->priv_auto, drv->flags);
+ if (!ptr)
+ return -ENOMEM;
+ dev_set_priv(dev, ptr);
+ }
+
+ /* Allocate private data if requested and not reentered */
+ size = dev->uclass->uc_drv->per_device_auto;
+ if (size && !dev_get_uclass_priv(dev)) {
+ ptr = alloc_priv(size, dev->uclass->uc_drv->flags);
+ if (!ptr)
+ return -ENOMEM;
+ dev_set_uclass_priv(dev, ptr);
+ }
+
+ /* Allocate parent data for this child */
+ if (dev->parent) {
+ size = dev->parent->driver->per_child_auto;
+ if (!size)
+ size = dev->parent->uclass->uc_drv->per_child_auto;
+ if (size && !dev_get_parent_priv(dev)) {
+ ptr = alloc_priv(size, drv->flags);
+ if (!ptr)
+ return -ENOMEM;
+ dev_set_parent_priv(dev, ptr);
+ }
+ }
+
+ return 0;
+}
+
+int device_of_to_plat(struct udevice *dev)
{
const struct driver *drv;
- int size = 0;
int ret;
if (!dev)
return -EINVAL;
- if (dev->flags & DM_FLAG_PLATDATA_VALID)
+ if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
return 0;
/* Ensure all parents have ofdata */
if (dev->parent) {
- ret = device_ofdata_to_platdata(dev->parent);
+ ret = device_of_to_plat(dev->parent);
if (ret)
goto fail;
@@ -363,56 +394,25 @@ int device_ofdata_to_platdata(struct udevice *dev)
* (e.g. PCI bridge devices). Test the flags again
* so that we don't mess up the device.
*/
- if (dev->flags & DM_FLAG_PLATDATA_VALID)
+ if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
return 0;
}
+ ret = device_alloc_priv(dev);
+ if (ret)
+ goto fail;
+
drv = dev->driver;
assert(drv);
- /* Allocate private data if requested and not reentered */
- if (drv->priv_auto_alloc_size && !dev->priv) {
- dev->priv = alloc_priv(drv->priv_auto_alloc_size, drv->flags);
- if (!dev->priv) {
- ret = -ENOMEM;
- goto fail;
- }
- }
- /* Allocate private data if requested and not reentered */
- size = dev->uclass->uc_drv->per_device_auto_alloc_size;
- if (size && !dev->uclass_priv) {
- dev->uclass_priv = alloc_priv(size,
- dev->uclass->uc_drv->flags);
- if (!dev->uclass_priv) {
- ret = -ENOMEM;
- goto fail;
- }
- }
-
- /* Allocate parent data for this child */
- if (dev->parent) {
- size = dev->parent->driver->per_child_auto_alloc_size;
- if (!size) {
- size = dev->parent->uclass->uc_drv->
- per_child_auto_alloc_size;
- }
- if (size && !dev->parent_priv) {
- dev->parent_priv = alloc_priv(size, drv->flags);
- if (!dev->parent_priv) {
- ret = -ENOMEM;
- goto fail;
- }
- }
- }
-
- if (drv->ofdata_to_platdata &&
- (CONFIG_IS_ENABLED(OF_PLATDATA) || dev_has_of_node(dev))) {
- ret = drv->ofdata_to_platdata(dev);
+ if (drv->of_to_plat &&
+ (CONFIG_IS_ENABLED(OF_PLATDATA) || dev_has_ofnode(dev))) {
+ ret = drv->of_to_plat(dev);
if (ret)
goto fail;
}
- dev->flags |= DM_FLAG_PLATDATA_VALID;
+ dev_or_flags(dev, DM_FLAG_PLATDATA_VALID);
return 0;
fail:
@@ -425,18 +425,17 @@ int device_probe(struct udevice *dev)
{
const struct driver *drv;
int ret;
- int seq;
if (!dev)
return -EINVAL;
- if (dev->flags & DM_FLAG_ACTIVATED)
+ if (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
return 0;
drv = dev->driver;
assert(drv);
- ret = device_ofdata_to_platdata(dev);
+ ret = device_of_to_plat(dev);
if (ret)
goto fail;
@@ -452,18 +451,11 @@ int device_probe(struct udevice *dev)
* (e.g. PCI bridge devices). Test the flags again
* so that we don't mess up the device.
*/
- if (dev->flags & DM_FLAG_ACTIVATED)
+ if (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
return 0;
}
- seq = uclass_resolve_seq(dev);
- if (seq < 0) {
- ret = seq;
- goto fail;
- }
- dev->seq = seq;
-
- dev->flags |= DM_FLAG_ACTIVATED;
+ dev_or_flags(dev, DM_FLAG_ACTIVATED);
/*
* Process pinctrl for everything except the root device, and
@@ -493,7 +485,7 @@ int device_probe(struct udevice *dev)
}
/* Only handle devices that have a valid ofnode */
- if (dev_of_valid(dev)) {
+ if (dev_has_ofnode(dev)) {
/*
* Process 'assigned-{clocks/clock-parents/clock-rates}'
* properties
@@ -523,42 +515,41 @@ fail_uclass:
__func__, dev->name);
}
fail:
- dev->flags &= ~DM_FLAG_ACTIVATED;
+ dev_bic_flags(dev, DM_FLAG_ACTIVATED);
- dev->seq = -1;
device_free(dev);
return ret;
}
-void *dev_get_platdata(const struct udevice *dev)
+void *dev_get_plat(const struct udevice *dev)
{
if (!dev) {
dm_warn("%s: null device\n", __func__);
return NULL;
}
- return dev->platdata;
+ return dev->plat_;
}
-void *dev_get_parent_platdata(const struct udevice *dev)
+void *dev_get_parent_plat(const struct udevice *dev)
{
if (!dev) {
dm_warn("%s: null device\n", __func__);
return NULL;
}
- return dev->parent_platdata;
+ return dev->parent_plat_;
}
-void *dev_get_uclass_platdata(const struct udevice *dev)
+void *dev_get_uclass_plat(const struct udevice *dev)
{
if (!dev) {
dm_warn("%s: null device\n", __func__);
return NULL;
}
- return dev->uclass_platdata;
+ return dev->uclass_plat_;
}
void *dev_get_priv(const struct udevice *dev)
@@ -568,7 +559,7 @@ void *dev_get_priv(const struct udevice *dev)
return NULL;
}
- return dev->priv;
+ return dev->priv_;
}
void *dev_get_uclass_priv(const struct udevice *dev)
@@ -578,7 +569,7 @@ void *dev_get_uclass_priv(const struct udevice *dev)
return NULL;
}
- return dev->uclass_priv;
+ return dev->uclass_priv_;
}
void *dev_get_parent_priv(const struct udevice *dev)
@@ -588,7 +579,7 @@ void *dev_get_parent_priv(const struct udevice *dev)
return NULL;
}
- return dev->parent_priv;
+ return dev->parent_priv_;
}
static int device_get_device_tail(struct udevice *dev, int ret,
@@ -622,7 +613,7 @@ static int device_find_by_ofnode(ofnode node, struct udevice **devp)
struct udevice *dev;
int ret;
- list_for_each_entry(uc, &gd->uclass_root, sibling_node) {
+ list_for_each_entry(uc, gd->uclass_root, sibling_node) {
ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node,
&dev);
if (!ret || dev) {
@@ -659,18 +650,15 @@ int device_get_child_count(const struct udevice *parent)
return count;
}
-int device_find_child_by_seq(const struct udevice *parent, int seq_or_req_seq,
- bool find_req_seq, struct udevice **devp)
+int device_find_child_by_seq(const struct udevice *parent, int seq,
+ struct udevice **devp)
{
struct udevice *dev;
*devp = NULL;
- if (seq_or_req_seq == -1)
- return -ENODEV;
list_for_each_entry(dev, &parent->child_head, sibling_node) {
- if ((find_req_seq ? dev->req_seq : dev->seq) ==
- seq_or_req_seq) {
+ if (dev->seq_ == seq) {
*devp = dev;
return 0;
}
@@ -686,14 +674,8 @@ int device_get_child_by_seq(const struct udevice *parent, int seq,
int ret;
*devp = NULL;
- ret = device_find_child_by_seq(parent, seq, false, &dev);
- if (ret == -ENODEV) {
- /*
- * We didn't find it in probed devices. See if there is one
- * that will request this seq if probed.
- */
- ret = device_find_child_by_seq(parent, seq, true, &dev);
- }
+ ret = device_find_child_by_seq(parent, seq, &dev);
+
return device_get_device_tail(dev, ret, devp);
}
@@ -895,7 +877,7 @@ int device_first_child_ofdata_err(struct udevice *parent, struct udevice **devp)
if (!dev)
return -ENODEV;
- ret = device_ofdata_to_platdata(dev);
+ ret = device_of_to_plat(dev);
if (ret)
return ret;
@@ -913,7 +895,7 @@ int device_next_child_ofdata_err(struct udevice **devp)
if (!dev)
return -ENODEV;
- ret = device_ofdata_to_platdata(dev);
+ ret = device_of_to_plat(dev);
if (ret)
return ret;
@@ -983,7 +965,7 @@ bool device_is_last_sibling(const struct udevice *dev)
void device_set_name_alloced(struct udevice *dev)
{
- dev->flags |= DM_FLAG_NAME_ALLOCED;
+ dev_or_flags(dev, DM_FLAG_NAME_ALLOCED);
}
int device_set_name(struct udevice *dev, const char *name)
@@ -997,6 +979,36 @@ int device_set_name(struct udevice *dev, const char *name)
return 0;
}
+void dev_set_priv(struct udevice *dev, void *priv)
+{
+ dev->priv_ = priv;
+}
+
+void dev_set_parent_priv(struct udevice *dev, void *parent_priv)
+{
+ dev->parent_priv_ = parent_priv;
+}
+
+void dev_set_uclass_priv(struct udevice *dev, void *uclass_priv)
+{
+ dev->uclass_priv_ = uclass_priv;
+}
+
+void dev_set_plat(struct udevice *dev, void *plat)
+{
+ dev->plat_ = plat;
+}
+
+void dev_set_parent_plat(struct udevice *dev, void *parent_plat)
+{
+ dev->parent_plat_ = parent_plat;
+}
+
+void dev_set_uclass_plat(struct udevice *dev, void *uclass_plat)
+{
+ dev->uclass_plat_ = uclass_plat;
+}
+
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
bool device_is_compatible(const struct udevice *dev, const char *compat)
{
@@ -1020,7 +1032,7 @@ int dev_disable_by_path(const char *path)
if (!of_live_active())
return -ENOSYS;
- list_for_each_entry(uc, &gd->uclass_root, sibling_node) {
+ list_for_each_entry(uc, gd->uclass_root, sibling_node) {
ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node, &dev);
if (!ret)
break;