xref: /openbmc/u-boot/drivers/core/device.c (revision 5a66a8ff)
1 /*
2  * Device manager
3  *
4  * Copyright (c) 2013 Google, Inc
5  *
6  * (C) Copyright 2012
7  * Pavel Herrmann <morpheus.ibis@gmail.com>
8  *
9  * SPDX-License-Identifier:	GPL-2.0+
10  */
11 
12 #include <common.h>
13 #include <fdtdec.h>
14 #include <malloc.h>
15 #include <dm/device.h>
16 #include <dm/device-internal.h>
17 #include <dm/lists.h>
18 #include <dm/platdata.h>
19 #include <dm/uclass.h>
20 #include <dm/uclass-internal.h>
21 #include <dm/util.h>
22 #include <linux/err.h>
23 #include <linux/list.h>
24 
25 DECLARE_GLOBAL_DATA_PTR;
26 
27 /**
28  * device_chld_unbind() - Unbind all device's children from the device
29  *
30  * On error, the function continues to unbind all children, and reports the
31  * first error.
32  *
33  * @dev:	The device that is to be stripped of its children
34  * @return 0 on success, -ve on error
35  */
36 static int device_chld_unbind(struct udevice *dev)
37 {
38 	struct udevice *pos, *n;
39 	int ret, saved_ret = 0;
40 
41 	assert(dev);
42 
43 	list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
44 		ret = device_unbind(pos);
45 		if (ret && !saved_ret)
46 			saved_ret = ret;
47 	}
48 
49 	return saved_ret;
50 }
51 
52 /**
53  * device_chld_remove() - Stop all device's children
54  * @dev:	The device whose children are to be removed
55  * @return 0 on success, -ve on error
56  */
57 static int device_chld_remove(struct udevice *dev)
58 {
59 	struct udevice *pos, *n;
60 	int ret;
61 
62 	assert(dev);
63 
64 	list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
65 		ret = device_remove(pos);
66 		if (ret)
67 			return ret;
68 	}
69 
70 	return 0;
71 }
72 
73 int device_bind(struct udevice *parent, struct driver *drv, const char *name,
74 		void *platdata, int of_offset, struct udevice **devp)
75 {
76 	struct udevice *dev;
77 	struct uclass *uc;
78 	int ret = 0;
79 
80 	*devp = NULL;
81 	if (!name)
82 		return -EINVAL;
83 
84 	ret = uclass_get(drv->id, &uc);
85 	if (ret)
86 		return ret;
87 
88 	dev = calloc(1, sizeof(struct udevice));
89 	if (!dev)
90 		return -ENOMEM;
91 
92 	INIT_LIST_HEAD(&dev->sibling_node);
93 	INIT_LIST_HEAD(&dev->child_head);
94 	INIT_LIST_HEAD(&dev->uclass_node);
95 	dev->platdata = platdata;
96 	dev->name = name;
97 	dev->of_offset = of_offset;
98 	dev->parent = parent;
99 	dev->driver = drv;
100 	dev->uclass = uc;
101 
102 	/*
103 	 * For some devices, such as a SPI or I2C bus, the 'reg' property
104 	 * is a reasonable indicator of the sequence number. But if there is
105 	 * an alias, we use that in preference. In any case, this is just
106 	 * a 'requested' sequence, and will be resolved (and ->seq updated)
107 	 * when the device is probed.
108 	 */
109 	dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
110 	dev->seq = -1;
111 	if (uc->uc_drv->name && of_offset != -1) {
112 		fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset,
113 				     &dev->req_seq);
114 	}
115 
116 	if (!dev->platdata && drv->platdata_auto_alloc_size)
117 		dev->flags |= DM_FLAG_ALLOC_PDATA;
118 
119 	/* put dev into parent's successor list */
120 	if (parent)
121 		list_add_tail(&dev->sibling_node, &parent->child_head);
122 
123 	ret = uclass_bind_device(dev);
124 	if (ret)
125 		goto fail_bind;
126 
127 	/* if we fail to bind we remove device from successors and free it */
128 	if (drv->bind) {
129 		ret = drv->bind(dev);
130 		if (ret) {
131 			if (uclass_unbind_device(dev)) {
132 				dm_warn("Failed to unbind dev '%s' on error path\n",
133 					dev->name);
134 			}
135 			goto fail_bind;
136 		}
137 	}
138 	if (parent)
139 		dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
140 	*devp = dev;
141 
142 	return 0;
143 
144 fail_bind:
145 	list_del(&dev->sibling_node);
146 	free(dev);
147 	return ret;
148 }
149 
150 int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
151 			const struct driver_info *info, struct udevice **devp)
152 {
153 	struct driver *drv;
154 
155 	drv = lists_driver_lookup_name(info->name);
156 	if (!drv)
157 		return -ENOENT;
158 	if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
159 		return -EPERM;
160 
161 	return device_bind(parent, drv, info->name, (void *)info->platdata,
162 			   -1, devp);
163 }
164 
165 int device_unbind(struct udevice *dev)
166 {
167 	struct driver *drv;
168 	int ret;
169 
170 	if (!dev)
171 		return -EINVAL;
172 
173 	if (dev->flags & DM_FLAG_ACTIVATED)
174 		return -EINVAL;
175 
176 	drv = dev->driver;
177 	assert(drv);
178 
179 	if (drv->unbind) {
180 		ret = drv->unbind(dev);
181 		if (ret)
182 			return ret;
183 	}
184 
185 	ret = device_chld_unbind(dev);
186 	if (ret)
187 		return ret;
188 
189 	ret = uclass_unbind_device(dev);
190 	if (ret)
191 		return ret;
192 
193 	if (dev->parent)
194 		list_del(&dev->sibling_node);
195 	free(dev);
196 
197 	return 0;
198 }
199 
200 /**
201  * device_free() - Free memory buffers allocated by a device
202  * @dev:	Device that is to be started
203  */
204 static void device_free(struct udevice *dev)
205 {
206 	int size;
207 
208 	if (dev->driver->priv_auto_alloc_size) {
209 		free(dev->priv);
210 		dev->priv = NULL;
211 	}
212 	if (dev->flags & DM_FLAG_ALLOC_PDATA) {
213 		free(dev->platdata);
214 		dev->platdata = NULL;
215 	}
216 	size = dev->uclass->uc_drv->per_device_auto_alloc_size;
217 	if (size) {
218 		free(dev->uclass_priv);
219 		dev->uclass_priv = NULL;
220 	}
221 }
222 
223 int device_probe(struct udevice *dev)
224 {
225 	struct driver *drv;
226 	int size = 0;
227 	int ret;
228 	int seq;
229 
230 	if (!dev)
231 		return -EINVAL;
232 
233 	if (dev->flags & DM_FLAG_ACTIVATED)
234 		return 0;
235 
236 	drv = dev->driver;
237 	assert(drv);
238 
239 	/* Allocate private data and platdata if requested */
240 	if (drv->priv_auto_alloc_size) {
241 		dev->priv = calloc(1, drv->priv_auto_alloc_size);
242 		if (!dev->priv) {
243 			ret = -ENOMEM;
244 			goto fail;
245 		}
246 	}
247 	/* Allocate private data if requested */
248 	if (dev->flags & DM_FLAG_ALLOC_PDATA) {
249 		dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
250 		if (!dev->platdata) {
251 			ret = -ENOMEM;
252 			goto fail;
253 		}
254 	}
255 	size = dev->uclass->uc_drv->per_device_auto_alloc_size;
256 	if (size) {
257 		dev->uclass_priv = calloc(1, size);
258 		if (!dev->uclass_priv) {
259 			ret = -ENOMEM;
260 			goto fail;
261 		}
262 	}
263 
264 	/* Ensure all parents are probed */
265 	if (dev->parent) {
266 		ret = device_probe(dev->parent);
267 		if (ret)
268 			goto fail;
269 	}
270 
271 	seq = uclass_resolve_seq(dev);
272 	if (seq < 0) {
273 		ret = seq;
274 		goto fail;
275 	}
276 	dev->seq = seq;
277 
278 	if (drv->ofdata_to_platdata && dev->of_offset >= 0) {
279 		ret = drv->ofdata_to_platdata(dev);
280 		if (ret)
281 			goto fail;
282 	}
283 
284 	if (drv->probe) {
285 		ret = drv->probe(dev);
286 		if (ret)
287 			goto fail;
288 	}
289 
290 	dev->flags |= DM_FLAG_ACTIVATED;
291 
292 	ret = uclass_post_probe_device(dev);
293 	if (ret) {
294 		dev->flags &= ~DM_FLAG_ACTIVATED;
295 		goto fail_uclass;
296 	}
297 
298 	return 0;
299 fail_uclass:
300 	if (device_remove(dev)) {
301 		dm_warn("%s: Device '%s' failed to remove on error path\n",
302 			__func__, dev->name);
303 	}
304 fail:
305 	dev->seq = -1;
306 	device_free(dev);
307 
308 	return ret;
309 }
310 
311 int device_remove(struct udevice *dev)
312 {
313 	struct driver *drv;
314 	int ret;
315 
316 	if (!dev)
317 		return -EINVAL;
318 
319 	if (!(dev->flags & DM_FLAG_ACTIVATED))
320 		return 0;
321 
322 	drv = dev->driver;
323 	assert(drv);
324 
325 	ret = uclass_pre_remove_device(dev);
326 	if (ret)
327 		return ret;
328 
329 	ret = device_chld_remove(dev);
330 	if (ret)
331 		goto err;
332 
333 	if (drv->remove) {
334 		ret = drv->remove(dev);
335 		if (ret)
336 			goto err_remove;
337 	}
338 
339 	device_free(dev);
340 
341 	dev->seq = -1;
342 	dev->flags &= ~DM_FLAG_ACTIVATED;
343 
344 	return 0;
345 
346 err_remove:
347 	/* We can't put the children back */
348 	dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
349 		__func__, dev->name);
350 err:
351 	ret = uclass_post_probe_device(dev);
352 	if (ret) {
353 		dm_warn("%s: Device '%s' failed to post_probe on error path\n",
354 			__func__, dev->name);
355 	}
356 
357 	return ret;
358 }
359 
360 void *dev_get_platdata(struct udevice *dev)
361 {
362 	if (!dev) {
363 		dm_warn("%s: null device", __func__);
364 		return NULL;
365 	}
366 
367 	return dev->platdata;
368 }
369 
370 void *dev_get_priv(struct udevice *dev)
371 {
372 	if (!dev) {
373 		dm_warn("%s: null device", __func__);
374 		return NULL;
375 	}
376 
377 	return dev->priv;
378 }
379