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 #ifdef CONFIG_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 #ifdef CONFIG_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 } 168 169 if (ret) 170 dm_warn("Some drivers failed to bind\n"); 171 172 return ret; 173 } 174 175 int dm_scan_fdt(const void *blob, bool pre_reloc_only) 176 { 177 return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only); 178 } 179 #endif 180 181 __weak int dm_scan_other(bool pre_reloc_only) 182 { 183 return 0; 184 } 185 186 int dm_init_and_scan(bool pre_reloc_only) 187 { 188 int ret; 189 190 ret = dm_init(); 191 if (ret) { 192 debug("dm_init() failed: %d\n", ret); 193 return ret; 194 } 195 ret = dm_scan_platdata(pre_reloc_only); 196 if (ret) { 197 debug("dm_scan_platdata() failed: %d\n", ret); 198 return ret; 199 } 200 #ifdef CONFIG_OF_CONTROL 201 ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only); 202 if (ret) { 203 debug("dm_scan_fdt() failed: %d\n", ret); 204 return ret; 205 } 206 #endif 207 ret = dm_scan_other(pre_reloc_only); 208 if (ret) 209 return ret; 210 211 return 0; 212 } 213 214 /* This is the root driver - all drivers are children of this */ 215 U_BOOT_DRIVER(root_driver) = { 216 .name = "root_driver", 217 .id = UCLASS_ROOT, 218 }; 219 220 /* This is the root uclass */ 221 UCLASS_DRIVER(root) = { 222 .name = "root", 223 .id = UCLASS_ROOT, 224 }; 225