xref: /openbmc/u-boot/drivers/core/root.c (revision 2f20aa82)
1 /*
2  * Copyright (c) 2013 Google, Inc
3  *
4  * (C) Copyright 2012
5  * Pavel Herrmann <morpheus.ibis@gmail.com>
6  *
7  * SPDX-License-Identifier:	GPL-2.0+
8  */
9 
10 #include <common.h>
11 #include <errno.h>
12 #include <fdtdec.h>
13 #include <malloc.h>
14 #include <libfdt.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/root.h>
20 #include <dm/uclass.h>
21 #include <dm/util.h>
22 #include <linux/list.h>
23 
24 DECLARE_GLOBAL_DATA_PTR;
25 
26 static const struct driver_info root_info = {
27 	.name		= "root_driver",
28 };
29 
30 struct udevice *dm_root(void)
31 {
32 	if (!gd->dm_root) {
33 		dm_warn("Virtual root driver does not exist!\n");
34 		return NULL;
35 	}
36 
37 	return gd->dm_root;
38 }
39 
40 int dm_init(void)
41 {
42 	int ret;
43 
44 	if (gd->dm_root) {
45 		dm_warn("Virtual root driver already exists!\n");
46 		return -EINVAL;
47 	}
48 	INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);
49 
50 	ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
51 	if (ret)
52 		return ret;
53 #ifdef CONFIG_OF_CONTROL
54 	DM_ROOT_NON_CONST->of_offset = 0;
55 #endif
56 	ret = device_probe(DM_ROOT_NON_CONST);
57 	if (ret)
58 		return ret;
59 
60 	return 0;
61 }
62 
63 int dm_uninit(void)
64 {
65 	device_remove(dm_root());
66 	device_unbind(dm_root());
67 
68 	return 0;
69 }
70 
71 int dm_scan_platdata(bool pre_reloc_only)
72 {
73 	int ret;
74 
75 	ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only);
76 	if (ret == -ENOENT) {
77 		dm_warn("Some drivers were not found\n");
78 		ret = 0;
79 	}
80 
81 	return ret;
82 }
83 
84 #ifdef CONFIG_OF_CONTROL
85 int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
86 		     bool pre_reloc_only)
87 {
88 	int ret = 0, err;
89 
90 	for (offset = fdt_first_subnode(blob, offset);
91 	     offset > 0;
92 	     offset = fdt_next_subnode(blob, offset)) {
93 		if (pre_reloc_only &&
94 		    !fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL))
95 			continue;
96 		if (!fdtdec_get_is_enabled(blob, offset)) {
97 			dm_dbg("   - ignoring disabled device\n");
98 			continue;
99 		}
100 		err = lists_bind_fdt(parent, blob, offset, NULL);
101 		if (err && !ret)
102 			ret = err;
103 	}
104 
105 	if (ret)
106 		dm_warn("Some drivers failed to bind\n");
107 
108 	return ret;
109 }
110 
111 int dm_scan_fdt(const void *blob, bool pre_reloc_only)
112 {
113 	return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);
114 }
115 #endif
116 
117 __weak int dm_scan_other(bool pre_reloc_only)
118 {
119 	return 0;
120 }
121 
122 int dm_init_and_scan(bool pre_reloc_only)
123 {
124 	int ret;
125 
126 	ret = dm_init();
127 	if (ret) {
128 		debug("dm_init() failed: %d\n", ret);
129 		return ret;
130 	}
131 	ret = dm_scan_platdata(pre_reloc_only);
132 	if (ret) {
133 		debug("dm_scan_platdata() failed: %d\n", ret);
134 		return ret;
135 	}
136 #ifdef CONFIG_OF_CONTROL
137 	ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
138 	if (ret) {
139 		debug("dm_scan_fdt() failed: %d\n", ret);
140 		return ret;
141 	}
142 #endif
143 	ret = dm_scan_other(pre_reloc_only);
144 	if (ret)
145 		return ret;
146 
147 	return 0;
148 }
149 
150 /* This is the root driver - all drivers are children of this */
151 U_BOOT_DRIVER(root_driver) = {
152 	.name	= "root_driver",
153 	.id	= UCLASS_ROOT,
154 };
155 
156 /* This is the root uclass */
157 UCLASS_DRIVER(root) = {
158 	.name	= "root",
159 	.id	= UCLASS_ROOT,
160 };
161