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