xref: /openbmc/u-boot/drivers/core/root.c (revision fc47cf9d)
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 struct root_priv {
27 	fdt_addr_t translation_offset;	/* optional translation offset */
28 };
29 
30 static const struct driver_info root_info = {
31 	.name		= "root_driver",
32 };
33 
34 struct udevice *dm_root(void)
35 {
36 	if (!gd->dm_root) {
37 		dm_warn("Virtual root driver does not exist!\n");
38 		return NULL;
39 	}
40 
41 	return gd->dm_root;
42 }
43 
44 void dm_fixup_for_gd_move(struct global_data *new_gd)
45 {
46 	/* The sentinel node has moved, so update things that point to it */
47 	new_gd->uclass_root.next->prev = &new_gd->uclass_root;
48 	new_gd->uclass_root.prev->next = &new_gd->uclass_root;
49 }
50 
51 fdt_addr_t dm_get_translation_offset(void)
52 {
53 	struct udevice *root = dm_root();
54 	struct root_priv *priv = dev_get_priv(root);
55 
56 	return priv->translation_offset;
57 }
58 
59 void dm_set_translation_offset(fdt_addr_t offs)
60 {
61 	struct udevice *root = dm_root();
62 	struct root_priv *priv = dev_get_priv(root);
63 
64 	priv->translation_offset = offs;
65 }
66 
67 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
68 void fix_drivers(void)
69 {
70 	struct driver *drv =
71 		ll_entry_start(struct driver, driver);
72 	const int n_ents = ll_entry_count(struct driver, driver);
73 	struct driver *entry;
74 
75 	for (entry = drv; entry != drv + n_ents; entry++) {
76 		if (entry->of_match)
77 			entry->of_match = (const struct udevice_id *)
78 				((u32)entry->of_match + gd->reloc_off);
79 		if (entry->bind)
80 			entry->bind += gd->reloc_off;
81 		if (entry->probe)
82 			entry->probe += gd->reloc_off;
83 		if (entry->remove)
84 			entry->remove += gd->reloc_off;
85 		if (entry->unbind)
86 			entry->unbind += gd->reloc_off;
87 		if (entry->ofdata_to_platdata)
88 			entry->ofdata_to_platdata += gd->reloc_off;
89 		if (entry->child_post_bind)
90 			entry->child_post_bind += gd->reloc_off;
91 		if (entry->child_pre_probe)
92 			entry->child_pre_probe += gd->reloc_off;
93 		if (entry->child_post_remove)
94 			entry->child_post_remove += gd->reloc_off;
95 		/* OPS are fixed in every uclass post_probe function */
96 		if (entry->ops)
97 			entry->ops += gd->reloc_off;
98 	}
99 }
100 
101 void fix_uclass(void)
102 {
103 	struct uclass_driver *uclass =
104 		ll_entry_start(struct uclass_driver, uclass);
105 	const int n_ents = ll_entry_count(struct uclass_driver, uclass);
106 	struct uclass_driver *entry;
107 
108 	for (entry = uclass; entry != uclass + n_ents; entry++) {
109 		if (entry->post_bind)
110 			entry->post_bind += gd->reloc_off;
111 		if (entry->pre_unbind)
112 			entry->pre_unbind += gd->reloc_off;
113 		if (entry->pre_probe)
114 			entry->pre_probe += gd->reloc_off;
115 		if (entry->post_probe)
116 			entry->post_probe += gd->reloc_off;
117 		if (entry->pre_remove)
118 			entry->pre_remove += gd->reloc_off;
119 		if (entry->child_post_bind)
120 			entry->child_post_bind += gd->reloc_off;
121 		if (entry->child_pre_probe)
122 			entry->child_pre_probe += gd->reloc_off;
123 		if (entry->init)
124 			entry->init += gd->reloc_off;
125 		if (entry->destroy)
126 			entry->destroy += gd->reloc_off;
127 		/* FIXME maybe also need to fix these ops */
128 		if (entry->ops)
129 			entry->ops += gd->reloc_off;
130 	}
131 }
132 
133 void fix_devices(void)
134 {
135 	struct driver_info *dev =
136 		ll_entry_start(struct driver_info, driver_info);
137 	const int n_ents = ll_entry_count(struct driver_info, driver_info);
138 	struct driver_info *entry;
139 
140 	for (entry = dev; entry != dev + n_ents; entry++) {
141 		if (entry->platdata)
142 			entry->platdata += gd->reloc_off;
143 	}
144 }
145 
146 #endif
147 
148 int dm_init(void)
149 {
150 	int ret;
151 
152 	if (gd->dm_root) {
153 		dm_warn("Virtual root driver already exists!\n");
154 		return -EINVAL;
155 	}
156 	INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST);
157 
158 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
159 	fix_drivers();
160 	fix_uclass();
161 	fix_devices();
162 #endif
163 
164 	ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
165 	if (ret)
166 		return ret;
167 #if CONFIG_IS_ENABLED(OF_CONTROL)
168 	DM_ROOT_NON_CONST->of_offset = 0;
169 #endif
170 	ret = device_probe(DM_ROOT_NON_CONST);
171 	if (ret)
172 		return ret;
173 
174 	return 0;
175 }
176 
177 int dm_uninit(void)
178 {
179 	device_remove(dm_root());
180 	device_unbind(dm_root());
181 
182 	return 0;
183 }
184 
185 int dm_scan_platdata(bool pre_reloc_only)
186 {
187 	int ret;
188 
189 	ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only);
190 	if (ret == -ENOENT) {
191 		dm_warn("Some drivers were not found\n");
192 		ret = 0;
193 	}
194 
195 	return ret;
196 }
197 
198 #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
199 int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
200 		     bool pre_reloc_only)
201 {
202 	int ret = 0, err;
203 
204 	for (offset = fdt_first_subnode(blob, offset);
205 	     offset > 0;
206 	     offset = fdt_next_subnode(blob, offset)) {
207 		if (pre_reloc_only &&
208 		    !fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL))
209 			continue;
210 		if (!fdtdec_get_is_enabled(blob, offset)) {
211 			dm_dbg("   - ignoring disabled device\n");
212 			continue;
213 		}
214 		err = lists_bind_fdt(parent, blob, offset, NULL);
215 		if (err && !ret) {
216 			ret = err;
217 			debug("%s: ret=%d\n", fdt_get_name(blob, offset, NULL),
218 			      ret);
219 		}
220 	}
221 
222 	if (ret)
223 		dm_warn("Some drivers failed to bind\n");
224 
225 	return ret;
226 }
227 
228 int dm_scan_fdt_dev(struct udevice *dev)
229 {
230 	if (dev->of_offset == -1)
231 		return 0;
232 
233 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset,
234 				gd->flags & GD_FLG_RELOC ? false : true);
235 }
236 
237 int dm_scan_fdt(const void *blob, bool pre_reloc_only)
238 {
239 	return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);
240 }
241 #endif
242 
243 __weak int dm_scan_other(bool pre_reloc_only)
244 {
245 	return 0;
246 }
247 
248 int dm_init_and_scan(bool pre_reloc_only)
249 {
250 	int ret;
251 
252 	ret = dm_init();
253 	if (ret) {
254 		debug("dm_init() failed: %d\n", ret);
255 		return ret;
256 	}
257 	ret = dm_scan_platdata(pre_reloc_only);
258 	if (ret) {
259 		debug("dm_scan_platdata() failed: %d\n", ret);
260 		return ret;
261 	}
262 
263 	if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
264 		ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
265 		if (ret) {
266 			debug("dm_scan_fdt() failed: %d\n", ret);
267 			return ret;
268 		}
269 	}
270 
271 	ret = dm_scan_other(pre_reloc_only);
272 	if (ret)
273 		return ret;
274 
275 	return 0;
276 }
277 
278 /* This is the root driver - all drivers are children of this */
279 U_BOOT_DRIVER(root_driver) = {
280 	.name	= "root_driver",
281 	.id	= UCLASS_ROOT,
282 	.priv_auto_alloc_size = sizeof(struct root_priv),
283 };
284 
285 /* This is the root uclass */
286 UCLASS_DRIVER(root) = {
287 	.name	= "root",
288 	.id	= UCLASS_ROOT,
289 };
290