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 #if defined(CONFIG_NEEDS_MANUAL_RELOC) 41 void fix_drivers(void) 42 { 43 struct driver *drv = 44 ll_entry_start(struct driver, driver); 45 const int n_ents = ll_entry_count(struct driver, driver); 46 struct driver *entry; 47 48 for (entry = drv; entry != drv + n_ents; entry++) { 49 if (entry->of_match) 50 entry->of_match = (const struct udevice_id *) 51 ((u32)entry->of_match + gd->reloc_off); 52 if (entry->bind) 53 entry->bind += gd->reloc_off; 54 if (entry->probe) 55 entry->probe += gd->reloc_off; 56 if (entry->remove) 57 entry->remove += gd->reloc_off; 58 if (entry->unbind) 59 entry->unbind += gd->reloc_off; 60 if (entry->ofdata_to_platdata) 61 entry->ofdata_to_platdata += gd->reloc_off; 62 if (entry->child_post_bind) 63 entry->child_post_bind += gd->reloc_off; 64 if (entry->child_pre_probe) 65 entry->child_pre_probe += gd->reloc_off; 66 if (entry->child_post_remove) 67 entry->child_post_remove += gd->reloc_off; 68 /* OPS are fixed in every uclass post_probe function */ 69 if (entry->ops) 70 entry->ops += gd->reloc_off; 71 } 72 } 73 74 void fix_uclass(void) 75 { 76 struct uclass_driver *uclass = 77 ll_entry_start(struct uclass_driver, uclass); 78 const int n_ents = ll_entry_count(struct uclass_driver, uclass); 79 struct uclass_driver *entry; 80 81 for (entry = uclass; entry != uclass + n_ents; entry++) { 82 if (entry->post_bind) 83 entry->post_bind += gd->reloc_off; 84 if (entry->pre_unbind) 85 entry->pre_unbind += gd->reloc_off; 86 if (entry->pre_probe) 87 entry->pre_probe += gd->reloc_off; 88 if (entry->post_probe) 89 entry->post_probe += gd->reloc_off; 90 if (entry->pre_remove) 91 entry->pre_remove += gd->reloc_off; 92 if (entry->child_post_bind) 93 entry->child_post_bind += gd->reloc_off; 94 if (entry->child_pre_probe) 95 entry->child_pre_probe += gd->reloc_off; 96 if (entry->init) 97 entry->init += gd->reloc_off; 98 if (entry->destroy) 99 entry->destroy += gd->reloc_off; 100 /* FIXME maybe also need to fix these ops */ 101 if (entry->ops) 102 entry->ops += gd->reloc_off; 103 } 104 } 105 #endif 106 107 int dm_init(void) 108 { 109 int ret; 110 111 if (gd->dm_root) { 112 dm_warn("Virtual root driver already exists!\n"); 113 return -EINVAL; 114 } 115 INIT_LIST_HEAD(&DM_UCLASS_ROOT_NON_CONST); 116 117 #if defined(CONFIG_NEEDS_MANUAL_RELOC) 118 fix_drivers(); 119 fix_uclass(); 120 #endif 121 122 ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST); 123 if (ret) 124 return ret; 125 #if CONFIG_IS_ENABLED(OF_CONTROL) 126 DM_ROOT_NON_CONST->of_offset = 0; 127 #endif 128 ret = device_probe(DM_ROOT_NON_CONST); 129 if (ret) 130 return ret; 131 132 return 0; 133 } 134 135 int dm_uninit(void) 136 { 137 device_remove(dm_root()); 138 device_unbind(dm_root()); 139 140 return 0; 141 } 142 143 int dm_scan_platdata(bool pre_reloc_only) 144 { 145 int ret; 146 147 ret = lists_bind_drivers(DM_ROOT_NON_CONST, pre_reloc_only); 148 if (ret == -ENOENT) { 149 dm_warn("Some drivers were not found\n"); 150 ret = 0; 151 } 152 153 return ret; 154 } 155 156 #if CONFIG_IS_ENABLED(OF_CONTROL) 157 int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset, 158 bool pre_reloc_only) 159 { 160 int ret = 0, err; 161 162 for (offset = fdt_first_subnode(blob, offset); 163 offset > 0; 164 offset = fdt_next_subnode(blob, offset)) { 165 if (pre_reloc_only && 166 !fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL)) 167 continue; 168 if (!fdtdec_get_is_enabled(blob, offset)) { 169 dm_dbg(" - ignoring disabled device\n"); 170 continue; 171 } 172 err = lists_bind_fdt(parent, blob, offset, NULL); 173 if (err && !ret) { 174 ret = err; 175 debug("%s: ret=%d\n", fdt_get_name(blob, offset, NULL), 176 ret); 177 } 178 } 179 180 if (ret) 181 dm_warn("Some drivers failed to bind\n"); 182 183 return ret; 184 } 185 186 int dm_scan_fdt(const void *blob, bool pre_reloc_only) 187 { 188 return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only); 189 } 190 #endif 191 192 __weak int dm_scan_other(bool pre_reloc_only) 193 { 194 return 0; 195 } 196 197 int dm_init_and_scan(bool pre_reloc_only) 198 { 199 int ret; 200 201 ret = dm_init(); 202 if (ret) { 203 debug("dm_init() failed: %d\n", ret); 204 return ret; 205 } 206 ret = dm_scan_platdata(pre_reloc_only); 207 if (ret) { 208 debug("dm_scan_platdata() failed: %d\n", ret); 209 return ret; 210 } 211 212 if (CONFIG_IS_ENABLED(OF_CONTROL)) { 213 ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); 214 if (ret) { 215 debug("dm_scan_fdt() failed: %d\n", ret); 216 return ret; 217 } 218 } 219 220 ret = dm_scan_other(pre_reloc_only); 221 if (ret) 222 return ret; 223 224 return 0; 225 } 226 227 /* This is the root driver - all drivers are children of this */ 228 U_BOOT_DRIVER(root_driver) = { 229 .name = "root_driver", 230 .id = UCLASS_ROOT, 231 }; 232 233 /* This is the root uclass */ 234 UCLASS_DRIVER(root) = { 235 .name = "root", 236 .id = UCLASS_ROOT, 237 }; 238