Blame view

drivers/core/device.c 15.6 KB
6494d708b   Simon Glass   dm: Add base driv...
1
2
3
4
5
6
7
8
9
10
11
12
  /*
   * Device manager
   *
   * Copyright (c) 2013 Google, Inc
   *
   * (C) Copyright 2012
   * Pavel Herrmann <morpheus.ibis@gmail.com>
   *
   * SPDX-License-Identifier:	GPL-2.0+
   */
  
  #include <common.h>
7c6168625   Vignesh R   dm: core: impleme...
13
  #include <asm/io.h>
f4fcba5c5   Philipp Tomsich   clk: implement cl...
14
  #include <clk.h>
5a66a8ff8   Simon Glass   dm: Introduce dev...
15
  #include <fdtdec.h>
ef5cd3306   Stefan Roese   dm: core: Enable ...
16
  #include <fdt_support.h>
6494d708b   Simon Glass   dm: Add base driv...
17
18
19
20
  #include <malloc.h>
  #include <dm/device.h>
  #include <dm/device-internal.h>
  #include <dm/lists.h>
29d11b883   Mario Six   core: Make device...
21
  #include <dm/of_access.h>
d90a5a30d   Masahiro Yamada   pinctrl: add pin ...
22
  #include <dm/pinctrl.h>
6494d708b   Simon Glass   dm: Add base driv...
23
  #include <dm/platdata.h>
396e343b3   Simon Glass   dm: core: Allow b...
24
  #include <dm/read.h>
6494d708b   Simon Glass   dm: Add base driv...
25
26
27
28
29
  #include <dm/uclass.h>
  #include <dm/uclass-internal.h>
  #include <dm/util.h>
  #include <linux/err.h>
  #include <linux/list.h>
2fde20b3d   Ye Li   MLK-16118-3 core:...
30
31
32
  #ifdef CONFIG_POWER_DOMAIN
  #include <power-domain.h>
  #endif
6494d708b   Simon Glass   dm: Add base driv...
33

5a66a8ff8   Simon Glass   dm: Introduce dev...
34
  DECLARE_GLOBAL_DATA_PTR;
daac3bfee   Stephen Warren   dm: allow setting...
35
36
  static int device_bind_common(struct udevice *parent, const struct driver *drv,
  			      const char *name, void *platdata,
7a61b0b58   Simon Glass   dm: core: Adjust ...
37
  			      ulong driver_data, ofnode node,
9fa281900   Simon Glass   dm: core: Expand ...
38
  			      uint of_platdata_size, struct udevice **devp)
6494d708b   Simon Glass   dm: Add base driv...
39
  {
54c5d08a0   Heiko Schocher   dm: rename device...
40
  	struct udevice *dev;
6494d708b   Simon Glass   dm: Add base driv...
41
  	struct uclass *uc;
5eaed8802   Przemyslaw Marczak   dm: core: Extend ...
42
  	int size, ret = 0;
6494d708b   Simon Glass   dm: Add base driv...
43

e6cabe4a6   Masahiro Yamada   dm: core: allow d...
44
45
  	if (devp)
  		*devp = NULL;
6494d708b   Simon Glass   dm: Add base driv...
46
47
48
49
  	if (!name)
  		return -EINVAL;
  
  	ret = uclass_get(drv->id, &uc);
3346c8762   Simon Glass   dm: Improve handl...
50
51
52
  	if (ret) {
  		debug("Missing uclass for driver %s
  ", drv->name);
6494d708b   Simon Glass   dm: Add base driv...
53
  		return ret;
3346c8762   Simon Glass   dm: Improve handl...
54
  	}
6494d708b   Simon Glass   dm: Add base driv...
55

54c5d08a0   Heiko Schocher   dm: rename device...
56
  	dev = calloc(1, sizeof(struct udevice));
6494d708b   Simon Glass   dm: Add base driv...
57
58
59
60
61
62
  	if (!dev)
  		return -ENOMEM;
  
  	INIT_LIST_HEAD(&dev->sibling_node);
  	INIT_LIST_HEAD(&dev->child_head);
  	INIT_LIST_HEAD(&dev->uclass_node);
e2282d707   Masahiro Yamada   devres: make Devr...
63
  #ifdef CONFIG_DEVRES
608f26c51   Masahiro Yamada   devres: introduce...
64
  	INIT_LIST_HEAD(&dev->devres_head);
e2282d707   Masahiro Yamada   devres: make Devr...
65
  #endif
6494d708b   Simon Glass   dm: Add base driv...
66
  	dev->platdata = platdata;
daac3bfee   Stephen Warren   dm: allow setting...
67
  	dev->driver_data = driver_data;
6494d708b   Simon Glass   dm: Add base driv...
68
  	dev->name = name;
7a61b0b58   Simon Glass   dm: core: Adjust ...
69
  	dev->node = node;
6494d708b   Simon Glass   dm: Add base driv...
70
71
72
  	dev->parent = parent;
  	dev->driver = drv;
  	dev->uclass = uc;
5a66a8ff8   Simon Glass   dm: Introduce dev...
73

5a66a8ff8   Simon Glass   dm: Introduce dev...
74
  	dev->seq = -1;
9cc36a2b8   Simon Glass   dm: core: Add a f...
75
  	dev->req_seq = -1;
4f627c5a5   Nathan Rossi   spl: dm: Add SPL_...
76
  	if (CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DM_SEQ_ALIAS)) {
36fa61dc6   Simon Glass   dm: core: Allow s...
77
  		/*
770eb30ed   Stefan Roese   dm: device.c: Min...
78
79
80
81
82
83
  		 * 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.
  		 */
36fa61dc6   Simon Glass   dm: core: Allow s...
84
  		if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) {
7a61b0b58   Simon Glass   dm: core: Adjust ...
85
  			if (uc->uc_drv->name && ofnode_valid(node)) {
396e343b3   Simon Glass   dm: core: Allow b...
86
  				dev_read_alias_seq(dev, &dev->req_seq);
36fa61dc6   Simon Glass   dm: core: Allow s...
87
  			}
9cc36a2b8   Simon Glass   dm: core: Add a f...
88
  		}
5a66a8ff8   Simon Glass   dm: Introduce dev...
89
  	}
36fa61dc6   Simon Glass   dm: core: Allow s...
90

9fa281900   Simon Glass   dm: core: Expand ...
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  	if (drv->platdata_auto_alloc_size) {
  		bool alloc = !platdata;
  
  		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)
  					alloc = true;
  			}
  		}
  		if (alloc) {
  			dev->flags |= DM_FLAG_ALLOC_PDATA;
  			dev->platdata = calloc(1,
  					       drv->platdata_auto_alloc_size);
  			if (!dev->platdata) {
  				ret = -ENOMEM;
  				goto fail_alloc1;
  			}
  			if (CONFIG_IS_ENABLED(OF_PLATDATA) && platdata) {
  				memcpy(dev->platdata, platdata,
  				       of_platdata_size);
  			}
f8a85449e   Simon Glass   dm: core: Allocat...
114
115
  		}
  	}
cdc133bde   Simon Glass   dm: core: Allow p...
116

5eaed8802   Przemyslaw Marczak   dm: core: Extend ...
117
118
119
120
121
122
123
124
125
126
127
128
  	size = uc->uc_drv->per_device_platdata_auto_alloc_size;
  	if (size) {
  		dev->flags |= DM_FLAG_ALLOC_UCLASS_PDATA;
  		dev->uclass_platdata = calloc(1, size);
  		if (!dev->uclass_platdata) {
  			ret = -ENOMEM;
  			goto fail_alloc2;
  		}
  	}
  
  	if (parent) {
  		size = parent->driver->per_child_platdata_auto_alloc_size;
ba8da9dc4   Simon Glass   dm: core: Allow u...
129
130
131
132
  		if (!size) {
  			size = parent->uclass->uc_drv->
  					per_child_platdata_auto_alloc_size;
  		}
cdc133bde   Simon Glass   dm: core: Allow p...
133
134
135
136
137
  		if (size) {
  			dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA;
  			dev->parent_platdata = calloc(1, size);
  			if (!dev->parent_platdata) {
  				ret = -ENOMEM;
5eaed8802   Przemyslaw Marczak   dm: core: Extend ...
138
  				goto fail_alloc3;
cdc133bde   Simon Glass   dm: core: Allow p...
139
140
141
  			}
  		}
  	}
6494d708b   Simon Glass   dm: Add base driv...
142
143
144
145
146
147
148
  
  	/* put dev into parent's successor list */
  	if (parent)
  		list_add_tail(&dev->sibling_node, &parent->child_head);
  
  	ret = uclass_bind_device(dev);
  	if (ret)
72ebfe86f   Simon Glass   dm: core: Tidy up...
149
  		goto fail_uclass_bind;
6494d708b   Simon Glass   dm: Add base driv...
150
151
152
153
  
  	/* if we fail to bind we remove device from successors and free it */
  	if (drv->bind) {
  		ret = drv->bind(dev);
72ebfe86f   Simon Glass   dm: core: Tidy up...
154
  		if (ret)
6494d708b   Simon Glass   dm: Add base driv...
155
  			goto fail_bind;
6494d708b   Simon Glass   dm: Add base driv...
156
  	}
0118ce795   Simon Glass   dm: core: Add a p...
157
158
159
160
161
  	if (parent && parent->driver->child_post_bind) {
  		ret = parent->driver->child_post_bind(dev);
  		if (ret)
  			goto fail_child_post_bind;
  	}
20af3c0a0   Simon Glass   dm: core: Call uc...
162
163
164
165
166
  	if (uc->uc_drv->post_bind) {
  		ret = uc->uc_drv->post_bind(dev);
  		if (ret)
  			goto fail_uclass_post_bind;
  	}
0118ce795   Simon Glass   dm: core: Add a p...
167

6494d708b   Simon Glass   dm: Add base driv...
168
  	if (parent)
ceb919096   Masahiro Yamada   dm: replace dm_db...
169
170
  		pr_debug("Bound device %s to %s
  ", dev->name, parent->name);
e6cabe4a6   Masahiro Yamada   dm: core: allow d...
171
172
  	if (devp)
  		*devp = dev;
6494d708b   Simon Glass   dm: Add base driv...
173

aed1a4dd8   Masahiro Yamada   dm: add DM_FLAG_B...
174
  	dev->flags |= DM_FLAG_BOUND;
6494d708b   Simon Glass   dm: Add base driv...
175
  	return 0;
20af3c0a0   Simon Glass   dm: core: Call uc...
176
177
  fail_uclass_post_bind:
  	/* There is no child unbind() method, so no clean-up required */
0118ce795   Simon Glass   dm: core: Add a p...
178
  fail_child_post_bind:
0a5804b53   Masahiro Yamada   dm: drop CONFIG_D...
179
  	if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
5a87c4174   Simon Glass   dm: core: Drop de...
180
181
182
183
184
  		if (drv->unbind && drv->unbind(dev)) {
  			dm_warn("unbind() method failed on dev '%s' on error path
  ",
  				dev->name);
  		}
0118ce795   Simon Glass   dm: core: Add a p...
185
  	}
6494d708b   Simon Glass   dm: Add base driv...
186
  fail_bind:
0a5804b53   Masahiro Yamada   dm: drop CONFIG_D...
187
  	if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
5a87c4174   Simon Glass   dm: core: Drop de...
188
189
190
191
192
  		if (uclass_unbind_device(dev)) {
  			dm_warn("Failed to unbind dev '%s' on error path
  ",
  				dev->name);
  		}
72ebfe86f   Simon Glass   dm: core: Tidy up...
193
194
  	}
  fail_uclass_bind:
0a5804b53   Masahiro Yamada   dm: drop CONFIG_D...
195
  	if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
5a87c4174   Simon Glass   dm: core: Drop de...
196
197
198
199
200
  		list_del(&dev->sibling_node);
  		if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
  			free(dev->parent_platdata);
  			dev->parent_platdata = NULL;
  		}
cdc133bde   Simon Glass   dm: core: Allow p...
201
  	}
5eaed8802   Przemyslaw Marczak   dm: core: Extend ...
202
203
204
205
206
  fail_alloc3:
  	if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
  		free(dev->uclass_platdata);
  		dev->uclass_platdata = NULL;
  	}
cdc133bde   Simon Glass   dm: core: Allow p...
207
  fail_alloc2:
f8a85449e   Simon Glass   dm: core: Allocat...
208
209
210
211
212
  	if (dev->flags & DM_FLAG_ALLOC_PDATA) {
  		free(dev->platdata);
  		dev->platdata = NULL;
  	}
  fail_alloc1:
608f26c51   Masahiro Yamada   devres: introduce...
213
  	devres_release_all(dev);
6494d708b   Simon Glass   dm: Add base driv...
214
  	free(dev);
72ebfe86f   Simon Glass   dm: core: Tidy up...
215

6494d708b   Simon Glass   dm: Add base driv...
216
217
  	return ret;
  }
daac3bfee   Stephen Warren   dm: allow setting...
218
219
  int device_bind_with_driver_data(struct udevice *parent,
  				 const struct driver *drv, const char *name,
396e343b3   Simon Glass   dm: core: Allow b...
220
  				 ulong driver_data, ofnode node,
daac3bfee   Stephen Warren   dm: allow setting...
221
222
  				 struct udevice **devp)
  {
396e343b3   Simon Glass   dm: core: Allow b...
223
224
  	return device_bind_common(parent, drv, name, NULL, driver_data, node,
  				  0, devp);
daac3bfee   Stephen Warren   dm: allow setting...
225
226
227
228
229
230
  }
  
  int device_bind(struct udevice *parent, const struct driver *drv,
  		const char *name, void *platdata, int of_offset,
  		struct udevice **devp)
  {
7a61b0b58   Simon Glass   dm: core: Adjust ...
231
232
  	return device_bind_common(parent, drv, name, platdata, 0,
  				  offset_to_ofnode(of_offset), 0, devp);
daac3bfee   Stephen Warren   dm: allow setting...
233
  }
00606d7e3   Simon Glass   dm: Allow drivers...
234
235
  int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
  			const struct driver_info *info, struct udevice **devp)
6494d708b   Simon Glass   dm: Add base driv...
236
237
  {
  	struct driver *drv;
9fa281900   Simon Glass   dm: core: Expand ...
238
  	uint platdata_size = 0;
6494d708b   Simon Glass   dm: Add base driv...
239
240
241
242
  
  	drv = lists_driver_lookup_name(info->name);
  	if (!drv)
  		return -ENOENT;
00606d7e3   Simon Glass   dm: Allow drivers...
243
244
  	if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
  		return -EPERM;
6494d708b   Simon Glass   dm: Add base driv...
245

9fa281900   Simon Glass   dm: core: Expand ...
246
247
248
249
  #if CONFIG_IS_ENABLED(OF_PLATDATA)
  	platdata_size = info->platdata_size;
  #endif
  	return device_bind_common(parent, drv, info->name,
396e343b3   Simon Glass   dm: core: Allow b...
250
251
  			(void *)info->platdata, 0, ofnode_null(), platdata_size,
  			devp);
6494d708b   Simon Glass   dm: Add base driv...
252
  }
2c03c4633   Simon Glass   dm: core: Support...
253
254
255
256
257
  static void *alloc_priv(int size, uint flags)
  {
  	void *priv;
  
  	if (flags & DM_FLAG_ALLOC_PRIV_DMA) {
5924da1df   Faiz Abbas   dm: core: Round u...
258
  		size = ROUND(size, ARCH_DMA_MINALIGN);
2c03c4633   Simon Glass   dm: core: Support...
259
  		priv = memalign(ARCH_DMA_MINALIGN, size);
5a8a8045a   Simon Glass   dm: core: Ensure ...
260
  		if (priv) {
2c03c4633   Simon Glass   dm: core: Support...
261
  			memset(priv, '\0', size);
5a8a8045a   Simon Glass   dm: core: Ensure ...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  
  			/*
  			 * Ensure that the zero bytes are flushed to memory.
  			 * This prevents problems if the driver uses this as
  			 * both an input and an output buffer:
  			 *
  			 * 1. Zeroes written to buffer (here) and sit in the
  			 *	cache
  			 * 2. Driver issues a read command to DMA
  			 * 3. CPU runs out of cache space and evicts some cache
  			 *	data in the buffer, writing zeroes to RAM from
  			 *	the memset() above
  			 * 4. DMA completes
  			 * 5. Buffer now has some DMA data and some zeroes
  			 * 6. Data being read is now incorrect
  			 *
  			 * To prevent this, ensure that the cache is clean
  			 * within this range at the start. The driver can then
  			 * use normal flush-after-write, invalidate-before-read
  			 * procedures.
  			 *
  			 * TODO(sjg@chromium.org): Drop this microblaze
  			 * exception.
  			 */
  #ifndef CONFIG_MICROBLAZE
  			flush_dcache_range((ulong)priv, (ulong)priv + size);
  #endif
  		}
2c03c4633   Simon Glass   dm: core: Support...
290
291
292
293
294
295
  	} else {
  		priv = calloc(1, size);
  	}
  
  	return priv;
  }
c6db965f6   Simon Glass   dm: Remove device...
296
  int device_probe(struct udevice *dev)
6494d708b   Simon Glass   dm: Add base driv...
297
  {
3479253da   Simon Glass   dm: core: Convert...
298
  	const struct driver *drv;
6494d708b   Simon Glass   dm: Add base driv...
299
300
  	int size = 0;
  	int ret;
5a66a8ff8   Simon Glass   dm: Introduce dev...
301
  	int seq;
6494d708b   Simon Glass   dm: Add base driv...
302
303
304
305
306
307
308
309
310
  
  	if (!dev)
  		return -EINVAL;
  
  	if (dev->flags & DM_FLAG_ACTIVATED)
  		return 0;
  
  	drv = dev->driver;
  	assert(drv);
cdeb2ba99   Bin Meng   dm: core: Fix cod...
311
312
  	/* Allocate private data if requested and not reentered */
  	if (drv->priv_auto_alloc_size && !dev->priv) {
2c03c4633   Simon Glass   dm: core: Support...
313
  		dev->priv = alloc_priv(drv->priv_auto_alloc_size, drv->flags);
6494d708b   Simon Glass   dm: Add base driv...
314
315
316
317
318
  		if (!dev->priv) {
  			ret = -ENOMEM;
  			goto fail;
  		}
  	}
cdeb2ba99   Bin Meng   dm: core: Fix cod...
319
  	/* Allocate private data if requested and not reentered */
6494d708b   Simon Glass   dm: Add base driv...
320
  	size = dev->uclass->uc_drv->per_device_auto_alloc_size;
cdeb2ba99   Bin Meng   dm: core: Fix cod...
321
  	if (size && !dev->uclass_priv) {
6494d708b   Simon Glass   dm: Add base driv...
322
323
324
325
326
327
328
329
330
  		dev->uclass_priv = calloc(1, size);
  		if (!dev->uclass_priv) {
  			ret = -ENOMEM;
  			goto fail;
  		}
  	}
  
  	/* Ensure all parents are probed */
  	if (dev->parent) {
e59f458de   Simon Glass   dm: Introduce per...
331
  		size = dev->parent->driver->per_child_auto_alloc_size;
dac8db2ce   Simon Glass   dm: core: Allow u...
332
333
334
335
  		if (!size) {
  			size = dev->parent->uclass->uc_drv->
  					per_child_auto_alloc_size;
  		}
cdeb2ba99   Bin Meng   dm: core: Fix cod...
336
  		if (size && !dev->parent_priv) {
2c03c4633   Simon Glass   dm: core: Support...
337
  			dev->parent_priv = alloc_priv(size, drv->flags);
e59f458de   Simon Glass   dm: Introduce per...
338
339
340
341
342
  			if (!dev->parent_priv) {
  				ret = -ENOMEM;
  				goto fail;
  			}
  		}
6494d708b   Simon Glass   dm: Add base driv...
343
344
345
  		ret = device_probe(dev->parent);
  		if (ret)
  			goto fail;
cdeb2ba99   Bin Meng   dm: core: Fix cod...
346
347
348
349
350
351
352
353
354
  
  		/*
  		 * The device might have already been probed during
  		 * the call to device_probe() on its parent device
  		 * (e.g. PCI bridge devices). Test the flags again
  		 * so that we don't mess up the device.
  		 */
  		if (dev->flags & DM_FLAG_ACTIVATED)
  			return 0;
6494d708b   Simon Glass   dm: Add base driv...
355
  	}
5a66a8ff8   Simon Glass   dm: Introduce dev...
356
357
358
359
360
361
  	seq = uclass_resolve_seq(dev);
  	if (seq < 0) {
  		ret = seq;
  		goto fail;
  	}
  	dev->seq = seq;
206d4d2b4   Simon Glass   dm: core: Mark de...
362
  	dev->flags |= DM_FLAG_ACTIVATED;
84d26e296   Simon Glass   dm: core: Don't u...
363
364
  	/*
  	 * Process pinctrl for everything except the root device, and
0379597e5   Simon Glass   dm: core: Don't s...
365
366
367
  	 * continue regardless of the result of pinctrl. Don't process pinctrl
  	 * settings for pinctrl devices since the device may not yet be
  	 * probed.
84d26e296   Simon Glass   dm: core: Don't u...
368
  	 */
0379597e5   Simon Glass   dm: core: Don't s...
369
  	if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL)
84d26e296   Simon Glass   dm: core: Don't u...
370
  		pinctrl_select_state(dev, "default");
d90a5a30d   Masahiro Yamada   pinctrl: add pin ...
371

2fde20b3d   Ye Li   MLK-16118-3 core:...
372
373
374
375
  #ifdef CONFIG_POWER_DOMAIN
  	if (dev->parent && device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) {
  		struct power_domain pd;
  		if (!power_domain_get(dev, &pd)) {
363214f9f   Ye Li   MLK-20945-2 dm: d...
376
377
378
379
380
381
382
  			if (!(dev->driver->flags & DM_FLAG_IGNORE_POWER_ON)) {
  				ret = power_domain_on(&pd);
  				if (ret) {
  					power_domain_free(&pd);
  					goto fail;
  				}
  			}
2fde20b3d   Ye Li   MLK-16118-3 core:...
383
384
385
  		}
  	}
  #endif
02c07b374   Simon Glass   dm: core: Add a u...
386
  	ret = uclass_pre_probe_device(dev);
83c7e434c   Simon Glass   dm: core: Allow u...
387
388
  	if (ret)
  		goto fail;
a327dee0f   Simon Glass   dm: Add child_pre...
389
390
391
392
393
  	if (dev->parent && dev->parent->driver->child_pre_probe) {
  		ret = dev->parent->driver->child_pre_probe(dev);
  		if (ret)
  			goto fail;
  	}
396e343b3   Simon Glass   dm: core: Allow b...
394
  	if (drv->ofdata_to_platdata && dev_has_of_node(dev)) {
6494d708b   Simon Glass   dm: Add base driv...
395
396
397
398
  		ret = drv->ofdata_to_platdata(dev);
  		if (ret)
  			goto fail;
  	}
f4fcba5c5   Philipp Tomsich   clk: implement cl...
399
400
401
402
  	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
  	ret = clk_set_defaults(dev);
  	if (ret)
  		goto fail;
6494d708b   Simon Glass   dm: Add base driv...
403
404
  	if (drv->probe) {
  		ret = drv->probe(dev);
02eeb1bbb   Simon Glass   dm: core: Mark de...
405
406
  		if (ret) {
  			dev->flags &= ~DM_FLAG_ACTIVATED;
6494d708b   Simon Glass   dm: Add base driv...
407
  			goto fail;
02eeb1bbb   Simon Glass   dm: core: Mark de...
408
  		}
6494d708b   Simon Glass   dm: Add base driv...
409
  	}
6494d708b   Simon Glass   dm: Add base driv...
410
  	ret = uclass_post_probe_device(dev);
206d4d2b4   Simon Glass   dm: core: Mark de...
411
  	if (ret)
6494d708b   Simon Glass   dm: Add base driv...
412
  		goto fail_uclass;
6494d708b   Simon Glass   dm: Add base driv...
413

c3ab98536   Peng Fan   dm: core: device:...
414
415
  	if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL)
  		pinctrl_select_state(dev, "default");
6494d708b   Simon Glass   dm: Add base driv...
416
417
  	return 0;
  fail_uclass:
706865afe   Stefan Roese   dm: core: Add fla...
418
  	if (device_remove(dev, DM_REMOVE_NORMAL)) {
6494d708b   Simon Glass   dm: Add base driv...
419
420
421
422
423
  		dm_warn("%s: Device '%s' failed to remove on error path
  ",
  			__func__, dev->name);
  	}
  fail:
206d4d2b4   Simon Glass   dm: core: Mark de...
424
  	dev->flags &= ~DM_FLAG_ACTIVATED;
5a66a8ff8   Simon Glass   dm: Introduce dev...
425
  	dev->seq = -1;
6494d708b   Simon Glass   dm: Add base driv...
426
427
428
429
  	device_free(dev);
  
  	return ret;
  }
54c5d08a0   Heiko Schocher   dm: rename device...
430
  void *dev_get_platdata(struct udevice *dev)
6494d708b   Simon Glass   dm: Add base driv...
431
432
  {
  	if (!dev) {
964d153c0   Simon Glass   dm: device: Add n...
433
434
  		dm_warn("%s: null device
  ", __func__);
6494d708b   Simon Glass   dm: Add base driv...
435
436
437
438
439
  		return NULL;
  	}
  
  	return dev->platdata;
  }
cdc133bde   Simon Glass   dm: core: Allow p...
440
441
442
  void *dev_get_parent_platdata(struct udevice *dev)
  {
  	if (!dev) {
36d7cc17b   Simon Glass   dm: core: Add \n ...
443
444
  		dm_warn("%s: null device
  ", __func__);
cdc133bde   Simon Glass   dm: core: Allow p...
445
446
447
448
449
  		return NULL;
  	}
  
  	return dev->parent_platdata;
  }
5eaed8802   Przemyslaw Marczak   dm: core: Extend ...
450
451
452
  void *dev_get_uclass_platdata(struct udevice *dev)
  {
  	if (!dev) {
36d7cc17b   Simon Glass   dm: core: Add \n ...
453
454
  		dm_warn("%s: null device
  ", __func__);
5eaed8802   Przemyslaw Marczak   dm: core: Extend ...
455
456
457
458
459
  		return NULL;
  	}
  
  	return dev->uclass_platdata;
  }
54c5d08a0   Heiko Schocher   dm: rename device...
460
  void *dev_get_priv(struct udevice *dev)
6494d708b   Simon Glass   dm: Add base driv...
461
462
  {
  	if (!dev) {
964d153c0   Simon Glass   dm: device: Add n...
463
464
  		dm_warn("%s: null device
  ", __func__);
6494d708b   Simon Glass   dm: Add base driv...
465
466
467
468
469
  		return NULL;
  	}
  
  	return dev->priv;
  }
997c87bb0   Simon Glass   dm: Add functions...
470

e564f054a   Simon Glass   dm: core: Add dev...
471
472
473
474
475
476
477
478
479
480
  void *dev_get_uclass_priv(struct udevice *dev)
  {
  	if (!dev) {
  		dm_warn("%s: null device
  ", __func__);
  		return NULL;
  	}
  
  	return dev->uclass_priv;
  }
bcbe3d157   Simon Glass   dm: Rename dev_ge...
481
  void *dev_get_parent_priv(struct udevice *dev)
e59f458de   Simon Glass   dm: Introduce per...
482
483
  {
  	if (!dev) {
964d153c0   Simon Glass   dm: device: Add n...
484
485
  		dm_warn("%s: null device
  ", __func__);
e59f458de   Simon Glass   dm: Introduce per...
486
487
488
489
490
  		return NULL;
  	}
  
  	return dev->parent_priv;
  }
997c87bb0   Simon Glass   dm: Add functions...
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
  static int device_get_device_tail(struct udevice *dev, int ret,
  				  struct udevice **devp)
  {
  	if (ret)
  		return ret;
  
  	ret = device_probe(dev);
  	if (ret)
  		return ret;
  
  	*devp = dev;
  
  	return 0;
  }
  
  int device_get_child(struct udevice *parent, int index, struct udevice **devp)
  {
  	struct udevice *dev;
  
  	list_for_each_entry(dev, &parent->child_head, sibling_node) {
  		if (!index--)
  			return device_get_device_tail(dev, 0, devp);
  	}
  
  	return -ENODEV;
  }
  
  int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
  			     bool find_req_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) {
  			*devp = dev;
  			return 0;
  		}
  	}
  
  	return -ENODEV;
  }
  
  int device_get_child_by_seq(struct udevice *parent, int seq,
  			    struct udevice **devp)
  {
  	struct udevice *dev;
  	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);
  	}
  	return device_get_device_tail(dev, ret, devp);
  }
  
  int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
  				   struct udevice **devp)
  {
  	struct udevice *dev;
  
  	*devp = NULL;
  
  	list_for_each_entry(dev, &parent->child_head, sibling_node) {
e160f7d43   Simon Glass   dm: core: Replace...
564
  		if (dev_of_offset(dev) == of_offset) {
997c87bb0   Simon Glass   dm: Add functions...
565
566
567
568
569
570
571
  			*devp = dev;
  			return 0;
  		}
  	}
  
  	return -ENODEV;
  }
132f9bfc9   Simon Glass   dm: core: Correct...
572
  int device_get_child_by_of_offset(struct udevice *parent, int node,
997c87bb0   Simon Glass   dm: Add functions...
573
574
575
576
577
578
  				  struct udevice **devp)
  {
  	struct udevice *dev;
  	int ret;
  
  	*devp = NULL;
132f9bfc9   Simon Glass   dm: core: Correct...
579
  	ret = device_find_child_by_of_offset(parent, node, &dev);
997c87bb0   Simon Glass   dm: Add functions...
580
581
  	return device_get_device_tail(dev, ret, devp);
  }
a8981d4f8   Simon Glass   dm: core: Add fun...
582

2693047ac   Simon Glass   dm: core: Add a f...
583
584
585
586
  static struct udevice *_device_find_global_by_of_offset(struct udevice *parent,
  							int of_offset)
  {
  	struct udevice *dev, *found;
e160f7d43   Simon Glass   dm: core: Replace...
587
  	if (dev_of_offset(parent) == of_offset)
2693047ac   Simon Glass   dm: core: Add a f...
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
  		return parent;
  
  	list_for_each_entry(dev, &parent->child_head, sibling_node) {
  		found = _device_find_global_by_of_offset(dev, of_offset);
  		if (found)
  			return found;
  	}
  
  	return NULL;
  }
  
  int device_get_global_by_of_offset(int of_offset, struct udevice **devp)
  {
  	struct udevice *dev;
  
  	dev = _device_find_global_by_of_offset(gd->dm_root, of_offset);
  	return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
  }
a8981d4f8   Simon Glass   dm: core: Add fun...
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
  int device_find_first_child(struct udevice *parent, struct udevice **devp)
  {
  	if (list_empty(&parent->child_head)) {
  		*devp = NULL;
  	} else {
  		*devp = list_first_entry(&parent->child_head, struct udevice,
  					 sibling_node);
  	}
  
  	return 0;
  }
  
  int device_find_next_child(struct udevice **devp)
  {
  	struct udevice *dev = *devp;
  	struct udevice *parent = dev->parent;
  
  	if (list_is_last(&dev->sibling_node, &parent->child_head)) {
  		*devp = NULL;
  	} else {
  		*devp = list_entry(dev->sibling_node.next, struct udevice,
  				   sibling_node);
  	}
  
  	return 0;
  }
2ef249b44   Simon Glass   dm: core: Allow a...
632

479728cb0   Simon Glass   dm: core: Add fun...
633
634
635
636
  struct udevice *dev_get_parent(struct udevice *child)
  {
  	return child->parent;
  }
39de84335   Simon Glass   dm: core: Rename ...
637
  ulong dev_get_driver_data(struct udevice *dev)
2ef249b44   Simon Glass   dm: core: Allow a...
638
  {
39de84335   Simon Glass   dm: core: Rename ...
639
  	return dev->driver_data;
2ef249b44   Simon Glass   dm: core: Allow a...
640
  }
b36705310   Simon Glass   dm: core: Add a f...
641

cc73d37b7   Przemyslaw Marczak   dm: core: device:...
642
643
644
645
646
647
648
  const void *dev_get_driver_ops(struct udevice *dev)
  {
  	if (!dev || !dev->driver->ops)
  		return NULL;
  
  	return dev->driver->ops;
  }
b36705310   Simon Glass   dm: core: Add a f...
649
650
651
652
  enum uclass_id device_get_uclass_id(struct udevice *dev)
  {
  	return dev->uclass->uc_drv->id;
  }
c9cac3f84   Peng Fan   dm: introduce dev...
653

f9c370dcd   Przemyslaw Marczak   dm: core: device:...
654
655
656
657
658
659
660
  const char *dev_get_uclass_name(struct udevice *dev)
  {
  	if (!dev)
  		return NULL;
  
  	return dev->uclass->uc_drv->name;
  }
c5785673b   Simon Glass   dm: core: Add dev...
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
  bool device_has_children(struct udevice *dev)
  {
  	return !list_empty(&dev->child_head);
  }
  
  bool device_has_active_children(struct udevice *dev)
  {
  	struct udevice *child;
  
  	for (device_find_first_child(dev, &child);
  	     child;
  	     device_find_next_child(&child)) {
  		if (device_active(child))
  			return true;
  	}
  
  	return false;
  }
  
  bool device_is_last_sibling(struct udevice *dev)
  {
  	struct udevice *parent = dev->parent;
  
  	if (!parent)
  		return false;
  	return list_is_last(&dev->sibling_node, &parent->child_head);
  }
f5c67ea03   Simon Glass   dm: core: Add a w...
688

a2040facd   Simon Glass   dm: core: Allow d...
689
690
  void device_set_name_alloced(struct udevice *dev)
  {
fd1c2d9b6   Simon Glass   dm: core: Rename ...
691
  	dev->flags |= DM_FLAG_NAME_ALLOCED;
a2040facd   Simon Glass   dm: core: Allow d...
692
  }
f5c67ea03   Simon Glass   dm: core: Add a w...
693
694
695
696
697
698
  int device_set_name(struct udevice *dev, const char *name)
  {
  	name = strdup(name);
  	if (!name)
  		return -ENOMEM;
  	dev->name = name;
a2040facd   Simon Glass   dm: core: Allow d...
699
  	device_set_name_alloced(dev);
f5c67ea03   Simon Glass   dm: core: Add a w...
700
701
702
  
  	return 0;
  }
73443b9e4   Mugunthan V N   drivers: core: de...
703

911f3aef3   Simon Glass   dm: core: Rename ...
704
  bool device_is_compatible(struct udevice *dev, const char *compat)
73443b9e4   Mugunthan V N   drivers: core: de...
705
706
  {
  	const void *fdt = gd->fdt_blob;
29d11b883   Mario Six   core: Make device...
707
  	ofnode node = dev_ofnode(dev);
73443b9e4   Mugunthan V N   drivers: core: de...
708

29d11b883   Mario Six   core: Make device...
709
710
711
712
  	if (ofnode_is_np(node))
  		return of_device_is_compatible(ofnode_to_np(node), compat, NULL, NULL);
  	else
  		return !fdt_node_check_compatible(fdt, ofnode_to_offset(node), compat);
73443b9e4   Mugunthan V N   drivers: core: de...
713
714
715
716
717
718
719
720
  }
  
  bool of_machine_is_compatible(const char *compat)
  {
  	const void *fdt = gd->fdt_blob;
  
  	return !fdt_node_check_compatible(fdt, 0, compat);
  }