"Das U-Boot" Source Tree
at master 291 lines 7.4 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2013 Google, Inc 4 * 5 * (C) Copyright 2012 6 * Marek Vasut <marex@denx.de> 7 */ 8 9#define LOG_CATEGORY LOGC_DM 10 11#include <debug_uart.h> 12#include <errno.h> 13#include <log.h> 14#include <dm/device.h> 15#include <dm/device-internal.h> 16#include <dm/lists.h> 17#include <dm/platdata.h> 18#include <dm/uclass.h> 19#include <dm/util.h> 20#include <fdtdec.h> 21#include <linux/compiler.h> 22 23struct driver *lists_driver_lookup_name(const char *name) 24{ 25 struct driver *drv = 26 ll_entry_start(struct driver, driver); 27 const int n_ents = ll_entry_count(struct driver, driver); 28 struct driver *entry; 29 30 for (entry = drv; entry != drv + n_ents; entry++) { 31 if (!strcmp(name, entry->name)) 32 return entry; 33 } 34 35 /* Not found */ 36 return NULL; 37} 38 39struct uclass_driver *lists_uclass_lookup(enum uclass_id id) 40{ 41 struct uclass_driver *uclass = 42 ll_entry_start(struct uclass_driver, uclass_driver); 43 const int n_ents = ll_entry_count(struct uclass_driver, uclass_driver); 44 struct uclass_driver *entry; 45 46 for (entry = uclass; entry != uclass + n_ents; entry++) { 47 if (entry->id == id) 48 return entry; 49 } 50 51 return NULL; 52} 53 54/** 55 * bind_drivers_pass() - Perform a pass of driver binding 56 * 57 * Work through the driver_info records binding a driver for each one. If the 58 * binding fails, continue binding others, but return the error. 59 * 60 * For OF_PLATDATA we must bind parent devices before their children. So only 61 * children of bound parents are bound on each call to this function. When a 62 * child is left unbound, -EAGAIN is returned, indicating that this function 63 * should be called again 64 * 65 * @parent: Parent device to use when binding each child device 66 * Return: 0 if OK, -EAGAIN if unbound children exist, -ENOENT if there is no 67 * driver for one of the devices, other -ve on other error 68 */ 69static int bind_drivers_pass(struct udevice *parent, bool pre_reloc_only) 70{ 71 struct driver_info *info = 72 ll_entry_start(struct driver_info, driver_info); 73 const int n_ents = ll_entry_count(struct driver_info, driver_info); 74 bool missing_parent = false; 75 int result = 0; 76 int idx; 77 78 /* 79 * Do one iteration through the driver_info records. For of-platdata, 80 * bind only devices whose parent is already bound. If we find any 81 * device we can't bind, set missing_parent to true, which will cause 82 * this function to be called again. 83 */ 84 for (idx = 0; idx < n_ents; idx++) { 85 struct udevice *par = parent; 86 const struct driver_info *entry = info + idx; 87 struct driver_rt *drt = gd_dm_driver_rt() + idx; 88 struct udevice *dev; 89 int ret; 90 91 if (CONFIG_IS_ENABLED(OF_PLATDATA)) { 92 int parent_idx = driver_info_parent_id(entry); 93 94 if (drt->dev) 95 continue; 96 97 if (CONFIG_IS_ENABLED(OF_PLATDATA_PARENT) && 98 parent_idx != -1) { 99 struct driver_rt *parent_drt; 100 101 parent_drt = gd_dm_driver_rt() + parent_idx; 102 if (!parent_drt->dev) { 103 missing_parent = true; 104 continue; 105 } 106 107 par = parent_drt->dev; 108 } 109 } 110 ret = device_bind_by_name(par, pre_reloc_only, entry, &dev); 111 if (!ret) { 112 if (CONFIG_IS_ENABLED(OF_PLATDATA)) 113 drt->dev = dev; 114 } else if (ret != -EPERM) { 115 dm_warn("No match for driver '%s'\n", entry->name); 116 if (!result || ret != -ENOENT) 117 result = ret; 118 } 119 } 120 121 return result ? result : missing_parent ? -EAGAIN : 0; 122} 123 124int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) 125{ 126 int result = 0; 127 int pass; 128 129 /* 130 * 10 passes is 10 levels deep in the devicetree, which is plenty. If 131 * OF_PLATDATA_PARENT is not enabled, then bind_drivers_pass() will 132 * always succeed on the first pass. 133 */ 134 for (pass = 0; pass < 10; pass++) { 135 int ret; 136 137 ret = bind_drivers_pass(parent, pre_reloc_only); 138 if (!result || result == -EAGAIN) 139 result = ret; 140 if (ret != -EAGAIN) 141 break; 142 } 143 144 return result; 145} 146 147int device_bind_driver(struct udevice *parent, const char *drv_name, 148 const char *dev_name, struct udevice **devp) 149{ 150 return device_bind_driver_to_node(parent, drv_name, dev_name, 151 ofnode_null(), devp); 152} 153 154int device_bind_driver_to_node(struct udevice *parent, const char *drv_name, 155 const char *dev_name, ofnode node, 156 struct udevice **devp) 157{ 158 struct driver *drv; 159 int ret; 160 161 drv = lists_driver_lookup_name(drv_name); 162 if (!drv) { 163 dm_warn("Cannot find driver '%s'\n", drv_name); 164 return -ENOENT; 165 } 166 ret = device_bind_with_driver_data(parent, drv, dev_name, 0 /* data */, 167 node, devp); 168 169 return ret; 170} 171 172#if CONFIG_IS_ENABLED(OF_REAL) 173/** 174 * driver_check_compatible() - Check if a driver matches a compatible string 175 * 176 * @param of_match: List of compatible strings to match 177 * @param of_idp: Returns the match that was found 178 * @param compat: The compatible string to search for 179 * Return: 0 if there is a match, -ENOENT if no match 180 */ 181static int driver_check_compatible(const struct udevice_id *of_match, 182 const struct udevice_id **of_idp, 183 const char *compat) 184{ 185 if (!of_match) 186 return -ENOENT; 187 188 while (of_match->compatible) { 189 if (!strcmp(of_match->compatible, compat)) { 190 *of_idp = of_match; 191 return 0; 192 } 193 of_match++; 194 } 195 196 return -ENOENT; 197} 198 199int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, 200 struct driver *drv, bool pre_reloc_only) 201{ 202 struct driver *driver = ll_entry_start(struct driver, driver); 203 const int n_ents = ll_entry_count(struct driver, driver); 204 const struct udevice_id *id; 205 struct driver *entry; 206 struct udevice *dev; 207 bool found = false; 208 const char *name, *compat_list, *compat; 209 int compat_length, i; 210 int result = 0; 211 int ret = 0; 212 213 if (devp) 214 *devp = NULL; 215 name = ofnode_get_name(node); 216 log_debug("bind node %s\n", name); 217 218 compat_list = ofnode_get_property(node, "compatible", &compat_length); 219 if (!compat_list) { 220 if (compat_length == -FDT_ERR_NOTFOUND) { 221 log_debug("Device '%s' has no compatible string\n", 222 name); 223 return 0; 224 } 225 226 dm_warn("Device tree error at node '%s'\n", name); 227 return compat_length; 228 } 229 230 /* 231 * Walk through the compatible string list, attempting to match each 232 * compatible string in order such that we match in order of priority 233 * from the first string to the last. 234 */ 235 for (i = 0; i < compat_length; i += strlen(compat) + 1) { 236 compat = compat_list + i; 237 log_debug(" - attempt to match compatible string '%s'\n", 238 compat); 239 240 id = NULL; 241 for (entry = driver; entry != driver + n_ents; entry++) { 242 if (drv) { 243 if (drv != entry) 244 continue; 245 if (!entry->of_match) 246 break; 247 } 248 ret = driver_check_compatible(entry->of_match, &id, 249 compat); 250 if (!ret) 251 break; 252 } 253 if (entry == driver + n_ents) 254 continue; 255 256 if (pre_reloc_only) { 257 if (!ofnode_pre_reloc(node) && 258 !(entry->flags & DM_FLAG_PRE_RELOC)) { 259 log_debug("Skipping device pre-relocation\n"); 260 return 0; 261 } 262 } 263 264 if (entry->of_match) 265 log_debug(" - found match at driver '%s' for '%s'\n", 266 entry->name, id->compatible); 267 ret = device_bind_with_driver_data(parent, entry, name, 268 id ? id->data : 0, node, 269 &dev); 270 if (ret == -ENODEV) { 271 log_debug("Driver '%s' refuses to bind\n", entry->name); 272 continue; 273 } 274 if (ret) { 275 dm_warn("Error binding driver '%s': %d\n", entry->name, 276 ret); 277 return log_msg_ret("bind", ret); 278 } else { 279 found = true; 280 if (devp) 281 *devp = dev; 282 } 283 break; 284 } 285 286 if (!found && !result && ret != -ENODEV) 287 log_debug("No match for node '%s'\n", name); 288 289 return result; 290} 291#endif