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 #include <common.h> 10 #include <errno.h> 11 #include <dm/device.h> 12 #include <dm/device-internal.h> 13 #include <dm/lists.h> 14 #include <dm/platdata.h> 15 #include <dm/uclass.h> 16 #include <dm/util.h> 17 #include <fdtdec.h> 18 #include <linux/compiler.h> 19 20 struct driver *lists_driver_lookup_name(const char *name) 21 { 22 struct driver *drv = 23 ll_entry_start(struct driver, driver); 24 const int n_ents = ll_entry_count(struct driver, driver); 25 struct driver *entry; 26 27 for (entry = drv; entry != drv + n_ents; entry++) { 28 if (!strcmp(name, entry->name)) 29 return entry; 30 } 31 32 /* Not found */ 33 return NULL; 34 } 35 36 struct uclass_driver *lists_uclass_lookup(enum uclass_id id) 37 { 38 struct uclass_driver *uclass = 39 ll_entry_start(struct uclass_driver, uclass); 40 const int n_ents = ll_entry_count(struct uclass_driver, uclass); 41 struct uclass_driver *entry; 42 43 for (entry = uclass; entry != uclass + n_ents; entry++) { 44 if (entry->id == id) 45 return entry; 46 } 47 48 return NULL; 49 } 50 51 int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) 52 { 53 struct driver_info *info = 54 ll_entry_start(struct driver_info, driver_info); 55 const int n_ents = ll_entry_count(struct driver_info, driver_info); 56 struct driver_info *entry; 57 struct udevice *dev; 58 int result = 0; 59 int ret; 60 61 for (entry = info; entry != info + n_ents; entry++) { 62 ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev); 63 if (ret && ret != -EPERM) { 64 dm_warn("No match for driver '%s'\n", entry->name); 65 if (!result || ret != -ENOENT) 66 result = ret; 67 } 68 } 69 70 return result; 71 } 72 73 int device_bind_driver(struct udevice *parent, const char *drv_name, 74 const char *dev_name, struct udevice **devp) 75 { 76 return device_bind_driver_to_node(parent, drv_name, dev_name, 77 ofnode_null(), devp); 78 } 79 80 int device_bind_driver_to_node(struct udevice *parent, const char *drv_name, 81 const char *dev_name, ofnode node, 82 struct udevice **devp) 83 { 84 struct driver *drv; 85 int ret; 86 87 drv = lists_driver_lookup_name(drv_name); 88 if (!drv) { 89 debug("Cannot find driver '%s'\n", drv_name); 90 return -ENOENT; 91 } 92 ret = device_bind_with_driver_data(parent, drv, dev_name, 0 /* data */, 93 node, devp); 94 95 return ret; 96 } 97 98 #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) 99 /** 100 * driver_check_compatible() - Check if a driver matches a compatible string 101 * 102 * @param of_match: List of compatible strings to match 103 * @param of_idp: Returns the match that was found 104 * @param compat: The compatible string to search for 105 * @return 0 if there is a match, -ENOENT if no match 106 */ 107 static int driver_check_compatible(const struct udevice_id *of_match, 108 const struct udevice_id **of_idp, 109 const char *compat) 110 { 111 if (!of_match) 112 return -ENOENT; 113 114 while (of_match->compatible) { 115 if (!strcmp(of_match->compatible, compat)) { 116 *of_idp = of_match; 117 return 0; 118 } 119 of_match++; 120 } 121 122 return -ENOENT; 123 } 124 125 int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, 126 bool pre_reloc_only) 127 { 128 struct driver *driver = ll_entry_start(struct driver, driver); 129 const int n_ents = ll_entry_count(struct driver, driver); 130 const struct udevice_id *id; 131 struct driver *entry; 132 struct udevice *dev; 133 bool found = false; 134 const char *name, *compat_list, *compat; 135 int compat_length, i; 136 int result = 0; 137 int ret = 0; 138 139 if (devp) 140 *devp = NULL; 141 name = ofnode_get_name(node); 142 pr_debug("bind node %s\n", name); 143 144 compat_list = ofnode_get_property(node, "compatible", &compat_length); 145 if (!compat_list) { 146 if (compat_length == -FDT_ERR_NOTFOUND) { 147 pr_debug("Device '%s' has no compatible string\n", 148 name); 149 return 0; 150 } 151 152 dm_warn("Device tree error at node '%s'\n", name); 153 return compat_length; 154 } 155 156 /* 157 * Walk through the compatible string list, attempting to match each 158 * compatible string in order such that we match in order of priority 159 * from the first string to the last. 160 */ 161 for (i = 0; i < compat_length; i += strlen(compat) + 1) { 162 compat = compat_list + i; 163 pr_debug(" - attempt to match compatible string '%s'\n", 164 compat); 165 166 for (entry = driver; entry != driver + n_ents; entry++) { 167 ret = driver_check_compatible(entry->of_match, &id, 168 compat); 169 if (!ret) 170 break; 171 } 172 if (entry == driver + n_ents) 173 continue; 174 175 if (pre_reloc_only) { 176 if (!dm_ofnode_pre_reloc(node) && 177 !(entry->flags & DM_FLAG_PRE_RELOC)) 178 return 0; 179 } 180 181 pr_debug(" - found match at '%s'\n", entry->name); 182 ret = device_bind_with_driver_data(parent, entry, name, 183 id->data, node, &dev); 184 if (ret == -ENODEV) { 185 pr_debug("Driver '%s' refuses to bind\n", entry->name); 186 continue; 187 } 188 if (ret) { 189 dm_warn("Error binding driver '%s': %d\n", entry->name, 190 ret); 191 return ret; 192 } else { 193 found = true; 194 if (devp) 195 *devp = dev; 196 } 197 break; 198 } 199 200 if (!found && !result && ret != -ENODEV) 201 pr_debug("No match for node '%s'\n", name); 202 203 return result; 204 } 205 #endif 206