xref: /rk3399_rockchip-uboot/drivers/core/root.c (revision 19c8205e6887d5e47c7dac6cd85d0376411b5444)
16494d708SSimon Glass /*
26494d708SSimon Glass  * Copyright (c) 2013 Google, Inc
36494d708SSimon Glass  *
46494d708SSimon Glass  * (C) Copyright 2012
56494d708SSimon Glass  * Pavel Herrmann <morpheus.ibis@gmail.com>
66494d708SSimon Glass  *
76494d708SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
86494d708SSimon Glass  */
96494d708SSimon Glass 
106494d708SSimon Glass #include <common.h>
116494d708SSimon Glass #include <errno.h>
1294f7afdfSSimon Glass #include <fdtdec.h>
136494d708SSimon Glass #include <malloc.h>
146a6d8fbeSSimon Glass #include <libfdt.h>
156494d708SSimon Glass #include <dm/device.h>
166494d708SSimon Glass #include <dm/device-internal.h>
176494d708SSimon Glass #include <dm/lists.h>
18*19c8205eSSimon Glass #include <dm/of.h>
19*19c8205eSSimon Glass #include <dm/of_access.h>
206494d708SSimon Glass #include <dm/platdata.h>
21*19c8205eSSimon Glass #include <dm/read.h>
22fd536d81SJeroen Hofstee #include <dm/root.h>
236494d708SSimon Glass #include <dm/uclass.h>
246494d708SSimon Glass #include <dm/util.h>
256494d708SSimon Glass #include <linux/list.h>
266494d708SSimon Glass 
276494d708SSimon Glass DECLARE_GLOBAL_DATA_PTR;
286494d708SSimon Glass 
2966eaea6cSStefan Roese struct root_priv {
3066eaea6cSStefan Roese 	fdt_addr_t translation_offset;	/* optional translation offset */
3166eaea6cSStefan Roese };
3266eaea6cSStefan Roese 
336494d708SSimon Glass static const struct driver_info root_info = {
346494d708SSimon Glass 	.name		= "root_driver",
356494d708SSimon Glass };
366494d708SSimon Glass 
3754c5d08aSHeiko Schocher struct udevice *dm_root(void)
386494d708SSimon Glass {
396494d708SSimon Glass 	if (!gd->dm_root) {
406494d708SSimon Glass 		dm_warn("Virtual root driver does not exist!\n");
416494d708SSimon Glass 		return NULL;
426494d708SSimon Glass 	}
436494d708SSimon Glass 
446494d708SSimon Glass 	return gd->dm_root;
456494d708SSimon Glass }
466494d708SSimon Glass 
472f11cd91SSimon Glass void dm_fixup_for_gd_move(struct global_data *new_gd)
482f11cd91SSimon Glass {
492f11cd91SSimon Glass 	/* The sentinel node has moved, so update things that point to it */
50b0d9512aSLokesh Vutla 	if (gd->dm_root) {
512f11cd91SSimon Glass 		new_gd->uclass_root.next->prev = &new_gd->uclass_root;
522f11cd91SSimon Glass 		new_gd->uclass_root.prev->next = &new_gd->uclass_root;
532f11cd91SSimon Glass 	}
54b0d9512aSLokesh Vutla }
552f11cd91SSimon Glass 
5666eaea6cSStefan Roese fdt_addr_t dm_get_translation_offset(void)
5766eaea6cSStefan Roese {
5866eaea6cSStefan Roese 	struct udevice *root = dm_root();
5966eaea6cSStefan Roese 	struct root_priv *priv = dev_get_priv(root);
6066eaea6cSStefan Roese 
6166eaea6cSStefan Roese 	return priv->translation_offset;
6266eaea6cSStefan Roese }
6366eaea6cSStefan Roese 
6466eaea6cSStefan Roese void dm_set_translation_offset(fdt_addr_t offs)
6566eaea6cSStefan Roese {
6666eaea6cSStefan Roese 	struct udevice *root = dm_root();
6766eaea6cSStefan Roese 	struct root_priv *priv = dev_get_priv(root);
6866eaea6cSStefan Roese 
6966eaea6cSStefan Roese 	priv->translation_offset = offs;
7066eaea6cSStefan Roese }
7166eaea6cSStefan Roese 
72484fdf5bSMichal Simek #if defined(CONFIG_NEEDS_MANUAL_RELOC)
73484fdf5bSMichal Simek void fix_drivers(void)
74484fdf5bSMichal Simek {
75484fdf5bSMichal Simek 	struct driver *drv =
76484fdf5bSMichal Simek 		ll_entry_start(struct driver, driver);
77484fdf5bSMichal Simek 	const int n_ents = ll_entry_count(struct driver, driver);
78484fdf5bSMichal Simek 	struct driver *entry;
79484fdf5bSMichal Simek 
80484fdf5bSMichal Simek 	for (entry = drv; entry != drv + n_ents; entry++) {
81484fdf5bSMichal Simek 		if (entry->of_match)
82484fdf5bSMichal Simek 			entry->of_match = (const struct udevice_id *)
83484fdf5bSMichal Simek 				((u32)entry->of_match + gd->reloc_off);
84484fdf5bSMichal Simek 		if (entry->bind)
85484fdf5bSMichal Simek 			entry->bind += gd->reloc_off;
86484fdf5bSMichal Simek 		if (entry->probe)
87484fdf5bSMichal Simek 			entry->probe += gd->reloc_off;
88484fdf5bSMichal Simek 		if (entry->remove)
89484fdf5bSMichal Simek 			entry->remove += gd->reloc_off;
90484fdf5bSMichal Simek 		if (entry->unbind)
91484fdf5bSMichal Simek 			entry->unbind += gd->reloc_off;
92484fdf5bSMichal Simek 		if (entry->ofdata_to_platdata)
93484fdf5bSMichal Simek 			entry->ofdata_to_platdata += gd->reloc_off;
9431e1029aSMichal Simek 		if (entry->child_post_bind)
9531e1029aSMichal Simek 			entry->child_post_bind += gd->reloc_off;
96484fdf5bSMichal Simek 		if (entry->child_pre_probe)
97484fdf5bSMichal Simek 			entry->child_pre_probe += gd->reloc_off;
98484fdf5bSMichal Simek 		if (entry->child_post_remove)
99484fdf5bSMichal Simek 			entry->child_post_remove += gd->reloc_off;
100484fdf5bSMichal Simek 		/* OPS are fixed in every uclass post_probe function */
101484fdf5bSMichal Simek 		if (entry->ops)
102484fdf5bSMichal Simek 			entry->ops += gd->reloc_off;
103484fdf5bSMichal Simek 	}
104484fdf5bSMichal Simek }
105484fdf5bSMichal Simek 
106484fdf5bSMichal Simek void fix_uclass(void)
107484fdf5bSMichal Simek {
108484fdf5bSMichal Simek 	struct uclass_driver *uclass =
109484fdf5bSMichal Simek 		ll_entry_start(struct uclass_driver, uclass);
110484fdf5bSMichal Simek 	const int n_ents = ll_entry_count(struct uclass_driver, uclass);
111484fdf5bSMichal Simek 	struct uclass_driver *entry;
112484fdf5bSMichal Simek 
113484fdf5bSMichal Simek 	for (entry = uclass; entry != uclass + n_ents; entry++) {
114484fdf5bSMichal Simek 		if (entry->post_bind)
115484fdf5bSMichal Simek 			entry->post_bind += gd->reloc_off;
116484fdf5bSMichal Simek 		if (entry->pre_unbind)
117484fdf5bSMichal Simek 			entry->pre_unbind += gd->reloc_off;
11831e1029aSMichal Simek 		if (entry->pre_probe)
11931e1029aSMichal Simek 			entry->pre_probe += gd->reloc_off;
120484fdf5bSMichal Simek 		if (entry->post_probe)
121484fdf5bSMichal Simek 			entry->post_probe += gd->reloc_off;
122484fdf5bSMichal Simek 		if (entry->pre_remove)
123484fdf5bSMichal Simek 			entry->pre_remove += gd->reloc_off;
12431e1029aSMichal Simek 		if (entry->child_post_bind)
12531e1029aSMichal Simek 			entry->child_post_bind += gd->reloc_off;
12631e1029aSMichal Simek 		if (entry->child_pre_probe)
12731e1029aSMichal Simek 			entry->child_pre_probe += gd->reloc_off;
128484fdf5bSMichal Simek 		if (entry->init)
129484fdf5bSMichal Simek 			entry->init += gd->reloc_off;
130484fdf5bSMichal Simek 		if (entry->destroy)
131484fdf5bSMichal Simek 			entry->destroy += gd->reloc_off;
132484fdf5bSMichal Simek 		/* FIXME maybe also need to fix these ops */
133484fdf5bSMichal Simek 		if (entry->ops)
134484fdf5bSMichal Simek 			entry->ops += gd->reloc_off;
135484fdf5bSMichal Simek 	}
136484fdf5bSMichal Simek }
1375aeedebcSAngelo Dureghello 
1385aeedebcSAngelo Dureghello void fix_devices(void)
1395aeedebcSAngelo Dureghello {
1405aeedebcSAngelo Dureghello 	struct driver_info *dev =
1415aeedebcSAngelo Dureghello 		ll_entry_start(struct driver_info, driver_info);
1425aeedebcSAngelo Dureghello 	const int n_ents = ll_entry_count(struct driver_info, driver_info);
1435aeedebcSAngelo Dureghello 	struct driver_info *entry;
1445aeedebcSAngelo Dureghello 
1455aeedebcSAngelo Dureghello 	for (entry = dev; entry != dev + n_ents; entry++) {
1465aeedebcSAngelo Dureghello 		if (entry->platdata)
1475aeedebcSAngelo Dureghello 			entry->platdata += gd->reloc_off;
1485aeedebcSAngelo Dureghello 	}
1495aeedebcSAngelo Dureghello }
1505aeedebcSAngelo Dureghello 
151484fdf5bSMichal Simek #endif
152484fdf5bSMichal Simek 
153*19c8205eSSimon Glass int dm_init(bool of_live)
1546494d708SSimon Glass {
1556494d708SSimon Glass 	int ret;
1566494d708SSimon Glass 
1576494d708SSimon Glass 	if (gd->dm_root) {
1586494d708SSimon Glass 		dm_warn("Virtual root driver already exists!\n");
1596494d708SSimon Glass 		return -EINVAL;
1606494d708SSimon Glass 	}
16189876a55SSimon Glass 	INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);
1626494d708SSimon Glass 
163484fdf5bSMichal Simek #if defined(CONFIG_NEEDS_MANUAL_RELOC)
164484fdf5bSMichal Simek 	fix_drivers();
165484fdf5bSMichal Simek 	fix_uclass();
1665aeedebcSAngelo Dureghello 	fix_devices();
167484fdf5bSMichal Simek #endif
168484fdf5bSMichal Simek 
16900606d7eSSimon Glass 	ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
1706494d708SSimon Glass 	if (ret)
1716494d708SSimon Glass 		return ret;
1720f925822SMasahiro Yamada #if CONFIG_IS_ENABLED(OF_CONTROL)
173*19c8205eSSimon Glass # if CONFIG_IS_ENABLED(OF_LIVE)
174*19c8205eSSimon Glass 	if (of_live)
175*19c8205eSSimon Glass 		DM_ROOT_NON_CONST->node = np_to_ofnode(gd->of_root);
176*19c8205eSSimon Glass 	else
177*19c8205eSSimon Glass #endif
1784984de2bSSimon Glass 		DM_ROOT_NON_CONST->node = offset_to_ofnode(0);
1792f3b95dbSSimon Glass #endif
1807497812dSSimon Glass 	ret = device_probe(DM_ROOT_NON_CONST);
1817497812dSSimon Glass 	if (ret)
1827497812dSSimon Glass 		return ret;
1836494d708SSimon Glass 
1846494d708SSimon Glass 	return 0;
1856494d708SSimon Glass }
1866494d708SSimon Glass 
1879adbd7a1SSimon Glass int dm_uninit(void)
1889adbd7a1SSimon Glass {
189706865afSStefan Roese 	device_remove(dm_root(), DM_REMOVE_NORMAL);
1909adbd7a1SSimon Glass 	device_unbind(dm_root());
1919adbd7a1SSimon Glass 
1929adbd7a1SSimon Glass 	return 0;
1939adbd7a1SSimon Glass }
1949adbd7a1SSimon Glass 
195bc85aa40SStefan Roese #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
196bc85aa40SStefan Roese int dm_remove_devices_flags(uint flags)
197bc85aa40SStefan Roese {
198bc85aa40SStefan Roese 	device_remove(dm_root(), flags);
199bc85aa40SStefan Roese 
200bc85aa40SStefan Roese 	return 0;
201bc85aa40SStefan Roese }
202bc85aa40SStefan Roese #endif
203bc85aa40SStefan Roese 
20400606d7eSSimon Glass int dm_scan_platdata(bool pre_reloc_only)
2056494d708SSimon Glass {
2066494d708SSimon Glass 	int ret;
2076494d708SSimon Glass 
20800606d7eSSimon Glass 	ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only);
2096494d708SSimon Glass 	if (ret == -ENOENT) {
2106494d708SSimon Glass 		dm_warn("Some drivers were not found\n");
2116494d708SSimon Glass 		ret = 0;
2126494d708SSimon Glass 	}
2136494d708SSimon Glass 
214cbf86d71SMasahiro Yamada 	return ret;
2156494d708SSimon Glass }
2166494d708SSimon Glass 
217*19c8205eSSimon Glass #if CONFIG_IS_ENABLED(OF_LIVE)
218*19c8205eSSimon Glass static int dm_scan_fdt_live(struct udevice *parent,
219*19c8205eSSimon Glass 			    const struct device_node *node_parent,
220*19c8205eSSimon Glass 			    bool pre_reloc_only)
221*19c8205eSSimon Glass {
222*19c8205eSSimon Glass 	struct device_node *np;
223*19c8205eSSimon Glass 	int ret = 0, err;
224*19c8205eSSimon Glass 
225*19c8205eSSimon Glass 	for (np = node_parent->child; np; np = np->sibling) {
226*19c8205eSSimon Glass 		if (pre_reloc_only &&
227*19c8205eSSimon Glass 		    !of_find_property(np, "u-boot,dm-pre-reloc", NULL))
228*19c8205eSSimon Glass 			continue;
229*19c8205eSSimon Glass 		if (!of_device_is_available(np)) {
230*19c8205eSSimon Glass 			dm_dbg("   - ignoring disabled device\n");
231*19c8205eSSimon Glass 			continue;
232*19c8205eSSimon Glass 		}
233*19c8205eSSimon Glass 		err = lists_bind_fdt(parent, np_to_ofnode(np), NULL);
234*19c8205eSSimon Glass 		if (err && !ret) {
235*19c8205eSSimon Glass 			ret = err;
236*19c8205eSSimon Glass 			debug("%s: ret=%d\n", np->name, ret);
237*19c8205eSSimon Glass 		}
238*19c8205eSSimon Glass 	}
239*19c8205eSSimon Glass 
240*19c8205eSSimon Glass 	if (ret)
241*19c8205eSSimon Glass 		dm_warn("Some drivers failed to bind\n");
242*19c8205eSSimon Glass 
243*19c8205eSSimon Glass 	return ret;
244*19c8205eSSimon Glass }
245*19c8205eSSimon Glass #endif /* CONFIG_IS_ENABLED(OF_LIVE) */
246*19c8205eSSimon Glass 
24729629eb8SSimon Glass #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
248a771a04fSSimon Glass /**
249a771a04fSSimon Glass  * dm_scan_fdt_node() - Scan the device tree and bind drivers for a node
250a771a04fSSimon Glass  *
251a771a04fSSimon Glass  * This scans the subnodes of a device tree node and and creates a driver
252a771a04fSSimon Glass  * for each one.
253a771a04fSSimon Glass  *
254a771a04fSSimon Glass  * @parent: Parent device for the devices that will be created
255a771a04fSSimon Glass  * @blob: Pointer to device tree blob
256a771a04fSSimon Glass  * @offset: Offset of node to scan
257a771a04fSSimon Glass  * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
258a771a04fSSimon Glass  * flag. If false bind all drivers.
259a771a04fSSimon Glass  * @return 0 if OK, -ve on error
260a771a04fSSimon Glass  */
261a771a04fSSimon Glass static int dm_scan_fdt_node(struct udevice *parent, const void *blob,
262a771a04fSSimon Glass 			    int offset, bool pre_reloc_only)
2636494d708SSimon Glass {
2646494d708SSimon Glass 	int ret = 0, err;
2656494d708SSimon Glass 
2661ca7e206SSimon Glass 	for (offset = fdt_first_subnode(blob, offset);
2671ca7e206SSimon Glass 	     offset > 0;
2681ca7e206SSimon Glass 	     offset = fdt_next_subnode(blob, offset)) {
26900606d7eSSimon Glass 		if (pre_reloc_only &&
27027326c7eSHeiko Stübner 		    !dm_fdt_pre_reloc(blob, offset))
27100606d7eSSimon Glass 			continue;
27294f7afdfSSimon Glass 		if (!fdtdec_get_is_enabled(blob, offset)) {
27394f7afdfSSimon Glass 			dm_dbg("   - ignoring disabled device\n");
27494f7afdfSSimon Glass 			continue;
27594f7afdfSSimon Glass 		}
276f5b5719cSSimon Glass 		err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL);
277bc7b2f43SSimon Glass 		if (err && !ret) {
2786494d708SSimon Glass 			ret = err;
279bc7b2f43SSimon Glass 			debug("%s: ret=%d\n", fdt_get_name(blob, offset, NULL),
280bc7b2f43SSimon Glass 			      ret);
281bc7b2f43SSimon Glass 		}
2826494d708SSimon Glass 	}
2836494d708SSimon Glass 
2846494d708SSimon Glass 	if (ret)
2856494d708SSimon Glass 		dm_warn("Some drivers failed to bind\n");
2866494d708SSimon Glass 
2876494d708SSimon Glass 	return ret;
2886494d708SSimon Glass }
2891ca7e206SSimon Glass 
290cc7f66f7SSimon Glass int dm_scan_fdt_dev(struct udevice *dev)
291cc7f66f7SSimon Glass {
292*19c8205eSSimon Glass 	if (!dev_of_valid(dev))
293cc7f66f7SSimon Glass 		return 0;
294cc7f66f7SSimon Glass 
295*19c8205eSSimon Glass #if CONFIG_IS_ENABLED(OF_LIVE)
296*19c8205eSSimon Glass 	if (of_live_active())
297*19c8205eSSimon Glass 		return dm_scan_fdt_live(dev, dev_np(dev),
298*19c8205eSSimon Glass 				gd->flags & GD_FLG_RELOC ? false : true);
299*19c8205eSSimon Glass 	else
300*19c8205eSSimon Glass #endif
301e160f7d4SSimon Glass 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev_of_offset(dev),
302cc7f66f7SSimon Glass 				gd->flags & GD_FLG_RELOC ? false : true);
303cc7f66f7SSimon Glass }
304cc7f66f7SSimon Glass 
3051ca7e206SSimon Glass int dm_scan_fdt(const void *blob, bool pre_reloc_only)
3061ca7e206SSimon Glass {
307*19c8205eSSimon Glass #if CONFIG_IS_ENABLED(OF_LIVE)
308*19c8205eSSimon Glass 	if (of_live_active())
309*19c8205eSSimon Glass 		return dm_scan_fdt_live(gd->dm_root, gd->of_root,
310*19c8205eSSimon Glass 					pre_reloc_only);
311*19c8205eSSimon Glass 	else
312*19c8205eSSimon Glass #endif
3131ca7e206SSimon Glass 	return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);
3141ca7e206SSimon Glass }
3156494d708SSimon Glass #endif
3166494d708SSimon Glass 
317bb58503dSSimon Glass __weak int dm_scan_other(bool pre_reloc_only)
318bb58503dSSimon Glass {
319bb58503dSSimon Glass 	return 0;
320bb58503dSSimon Glass }
321bb58503dSSimon Glass 
322ab7cd627SSimon Glass int dm_init_and_scan(bool pre_reloc_only)
323ab7cd627SSimon Glass {
324ab7cd627SSimon Glass 	int ret;
325ab7cd627SSimon Glass 
326*19c8205eSSimon Glass 	ret = dm_init(IS_ENABLED(CONFIG_OF_LIVE));
327ab7cd627SSimon Glass 	if (ret) {
328ab7cd627SSimon Glass 		debug("dm_init() failed: %d\n", ret);
329ab7cd627SSimon Glass 		return ret;
330ab7cd627SSimon Glass 	}
331ab7cd627SSimon Glass 	ret = dm_scan_platdata(pre_reloc_only);
332ab7cd627SSimon Glass 	if (ret) {
333ab7cd627SSimon Glass 		debug("dm_scan_platdata() failed: %d\n", ret);
334ab7cd627SSimon Glass 		return ret;
335ab7cd627SSimon Glass 	}
336b2b0d3e7SSimon Glass 
33729629eb8SSimon Glass 	if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
338ab7cd627SSimon Glass 		ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
339ab7cd627SSimon Glass 		if (ret) {
340ab7cd627SSimon Glass 			debug("dm_scan_fdt() failed: %d\n", ret);
341ab7cd627SSimon Glass 			return ret;
342ab7cd627SSimon Glass 		}
343b2b0d3e7SSimon Glass 	}
344b2b0d3e7SSimon Glass 
345bb58503dSSimon Glass 	ret = dm_scan_other(pre_reloc_only);
346bb58503dSSimon Glass 	if (ret)
347bb58503dSSimon Glass 		return ret;
348ab7cd627SSimon Glass 
349ab7cd627SSimon Glass 	return 0;
350ab7cd627SSimon Glass }
351ab7cd627SSimon Glass 
3526494d708SSimon Glass /* This is the root driver - all drivers are children of this */
3536494d708SSimon Glass U_BOOT_DRIVER(root_driver) = {
3546494d708SSimon Glass 	.name	= "root_driver",
3556494d708SSimon Glass 	.id	= UCLASS_ROOT,
35666eaea6cSStefan Roese 	.priv_auto_alloc_size = sizeof(struct root_priv),
3576494d708SSimon Glass };
3586494d708SSimon Glass 
3596494d708SSimon Glass /* This is the root uclass */
3606494d708SSimon Glass UCLASS_DRIVER(root) = {
3616494d708SSimon Glass 	.name	= "root",
3626494d708SSimon Glass 	.id	= UCLASS_ROOT,
3636494d708SSimon Glass };
364