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