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 <malloc.h> 13 #include <dm/device.h> 14 #include <dm/device-internal.h> 15 #include <dm/lists.h> 16 #include <dm/uclass.h> 17 #include <dm/uclass-internal.h> 18 #include <dm/util.h> 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 struct uclass *uclass_find(enum uclass_id key) 23 { 24 struct uclass *uc; 25 26 if (!gd->dm_root) 27 return NULL; 28 /* 29 * TODO(sjg@chromium.org): Optimise this, perhaps moving the found 30 * node to the start of the list, or creating a linear array mapping 31 * id to node. 32 */ 33 list_for_each_entry(uc, &gd->uclass_root, sibling_node) { 34 if (uc->uc_drv->id == key) 35 return uc; 36 } 37 38 return NULL; 39 } 40 41 /** 42 * uclass_add() - Create new uclass in list 43 * @id: Id number to create 44 * @ucp: Returns pointer to uclass, or NULL on error 45 * @return 0 on success, -ve on error 46 * 47 * The new uclass is added to the list. There must be only one uclass for 48 * each id. 49 */ 50 static int uclass_add(enum uclass_id id, struct uclass **ucp) 51 { 52 struct uclass_driver *uc_drv; 53 struct uclass *uc; 54 int ret; 55 56 *ucp = NULL; 57 uc_drv = lists_uclass_lookup(id); 58 if (!uc_drv) { 59 dm_warn("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n", 60 id); 61 return -ENOENT; 62 } 63 if (uc_drv->ops) { 64 dm_warn("No ops for uclass id %d\n", id); 65 return -EINVAL; 66 } 67 uc = calloc(1, sizeof(*uc)); 68 if (!uc) 69 return -ENOMEM; 70 if (uc_drv->priv_auto_alloc_size) { 71 uc->priv = calloc(1, uc_drv->priv_auto_alloc_size); 72 if (!uc->priv) { 73 ret = -ENOMEM; 74 goto fail_mem; 75 } 76 } 77 uc->uc_drv = uc_drv; 78 INIT_LIST_HEAD(&uc->sibling_node); 79 INIT_LIST_HEAD(&uc->dev_head); 80 list_add(&uc->sibling_node, &DM_UCLASS_ROOT_NON_CONST); 81 82 if (uc_drv->init) { 83 ret = uc_drv->init(uc); 84 if (ret) 85 goto fail; 86 } 87 88 *ucp = uc; 89 90 return 0; 91 fail: 92 if (uc_drv->priv_auto_alloc_size) { 93 free(uc->priv); 94 uc->priv = NULL; 95 } 96 list_del(&uc->sibling_node); 97 fail_mem: 98 free(uc); 99 100 return ret; 101 } 102 103 int uclass_destroy(struct uclass *uc) 104 { 105 struct uclass_driver *uc_drv; 106 struct udevice *dev, *tmp; 107 int ret; 108 109 list_for_each_entry_safe(dev, tmp, &uc->dev_head, uclass_node) { 110 ret = device_remove(dev); 111 if (ret) 112 return ret; 113 ret = device_unbind(dev); 114 if (ret) 115 return ret; 116 } 117 118 uc_drv = uc->uc_drv; 119 if (uc_drv->destroy) 120 uc_drv->destroy(uc); 121 list_del(&uc->sibling_node); 122 if (uc_drv->priv_auto_alloc_size) 123 free(uc->priv); 124 free(uc); 125 126 return 0; 127 } 128 129 int uclass_get(enum uclass_id id, struct uclass **ucp) 130 { 131 struct uclass *uc; 132 133 *ucp = NULL; 134 uc = uclass_find(id); 135 if (!uc) 136 return uclass_add(id, ucp); 137 *ucp = uc; 138 139 return 0; 140 } 141 142 int uclass_find_device(enum uclass_id id, int index, struct udevice **devp) 143 { 144 struct uclass *uc; 145 struct udevice *dev; 146 int ret; 147 148 *devp = NULL; 149 ret = uclass_get(id, &uc); 150 if (ret) 151 return ret; 152 153 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 154 if (!index--) { 155 *devp = dev; 156 return 0; 157 } 158 } 159 160 return -ENODEV; 161 } 162 163 int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq, 164 bool find_req_seq, struct udevice **devp) 165 { 166 struct uclass *uc; 167 struct udevice *dev; 168 int ret; 169 170 *devp = NULL; 171 debug("%s: %d %d\n", __func__, find_req_seq, seq_or_req_seq); 172 if (seq_or_req_seq == -1) 173 return -ENODEV; 174 ret = uclass_get(id, &uc); 175 if (ret) 176 return ret; 177 178 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 179 debug(" - %d %d\n", dev->req_seq, dev->seq); 180 if ((find_req_seq ? dev->req_seq : dev->seq) == 181 seq_or_req_seq) { 182 *devp = dev; 183 debug(" - found\n"); 184 return 0; 185 } 186 } 187 debug(" - not found\n"); 188 189 return -ENODEV; 190 } 191 192 static int uclass_find_device_by_of_offset(enum uclass_id id, int node, 193 struct udevice **devp) 194 { 195 struct uclass *uc; 196 struct udevice *dev; 197 int ret; 198 199 *devp = NULL; 200 if (node < 0) 201 return -ENODEV; 202 ret = uclass_get(id, &uc); 203 if (ret) 204 return ret; 205 206 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 207 if (dev->of_offset == node) { 208 *devp = dev; 209 return 0; 210 } 211 } 212 213 return -ENODEV; 214 } 215 216 /** 217 * uclass_get_device_tail() - handle the end of a get_device call 218 * 219 * This handles returning an error or probing a device as needed. 220 * 221 * @dev: Device that needs to be probed 222 * @ret: Error to return. If non-zero then the device is not probed 223 * @devp: Returns the value of 'dev' if there is no error 224 * @return ret, if non-zero, else the result of the device_probe() call 225 */ 226 static int uclass_get_device_tail(struct udevice *dev, int ret, 227 struct udevice **devp) 228 { 229 if (ret) 230 return ret; 231 232 ret = device_probe(dev); 233 if (ret) 234 return ret; 235 236 *devp = dev; 237 238 return 0; 239 } 240 241 int uclass_get_device(enum uclass_id id, int index, struct udevice **devp) 242 { 243 struct udevice *dev; 244 int ret; 245 246 *devp = NULL; 247 ret = uclass_find_device(id, index, &dev); 248 return uclass_get_device_tail(dev, ret, devp); 249 } 250 251 int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp) 252 { 253 struct udevice *dev; 254 int ret; 255 256 *devp = NULL; 257 ret = uclass_find_device_by_seq(id, seq, false, &dev); 258 if (ret == -ENODEV) { 259 /* 260 * We didn't find it in probed devices. See if there is one 261 * that will request this seq if probed. 262 */ 263 ret = uclass_find_device_by_seq(id, seq, true, &dev); 264 } 265 return uclass_get_device_tail(dev, ret, devp); 266 } 267 268 int uclass_get_device_by_of_offset(enum uclass_id id, int node, 269 struct udevice **devp) 270 { 271 struct udevice *dev; 272 int ret; 273 274 *devp = NULL; 275 ret = uclass_find_device_by_of_offset(id, node, &dev); 276 return uclass_get_device_tail(dev, ret, devp); 277 } 278 279 int uclass_first_device(enum uclass_id id, struct udevice **devp) 280 { 281 struct uclass *uc; 282 struct udevice *dev; 283 int ret; 284 285 *devp = NULL; 286 ret = uclass_get(id, &uc); 287 if (ret) 288 return ret; 289 if (list_empty(&uc->dev_head)) 290 return 0; 291 292 dev = list_first_entry(&uc->dev_head, struct udevice, uclass_node); 293 ret = device_probe(dev); 294 if (ret) 295 return ret; 296 *devp = dev; 297 298 return 0; 299 } 300 301 int uclass_next_device(struct udevice **devp) 302 { 303 struct udevice *dev = *devp; 304 int ret; 305 306 *devp = NULL; 307 if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head)) 308 return 0; 309 310 dev = list_entry(dev->uclass_node.next, struct udevice, 311 uclass_node); 312 ret = device_probe(dev); 313 if (ret) 314 return ret; 315 *devp = dev; 316 317 return 0; 318 } 319 320 int uclass_bind_device(struct udevice *dev) 321 { 322 struct uclass *uc; 323 int ret; 324 325 uc = dev->uclass; 326 327 list_add_tail(&dev->uclass_node, &uc->dev_head); 328 329 if (uc->uc_drv->post_bind) { 330 ret = uc->uc_drv->post_bind(dev); 331 if (ret) { 332 list_del(&dev->uclass_node); 333 return ret; 334 } 335 } 336 337 return 0; 338 } 339 340 int uclass_unbind_device(struct udevice *dev) 341 { 342 struct uclass *uc; 343 int ret; 344 345 uc = dev->uclass; 346 if (uc->uc_drv->pre_unbind) { 347 ret = uc->uc_drv->pre_unbind(dev); 348 if (ret) 349 return ret; 350 } 351 352 list_del(&dev->uclass_node); 353 return 0; 354 } 355 356 int uclass_resolve_seq(struct udevice *dev) 357 { 358 struct udevice *dup; 359 int seq; 360 int ret; 361 362 assert(dev->seq == -1); 363 ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, dev->req_seq, 364 false, &dup); 365 if (!ret) { 366 dm_warn("Device '%s': seq %d is in use by '%s'\n", 367 dev->name, dev->req_seq, dup->name); 368 } else if (ret == -ENODEV) { 369 /* Our requested sequence number is available */ 370 if (dev->req_seq != -1) 371 return dev->req_seq; 372 } else { 373 return ret; 374 } 375 376 for (seq = 0; seq < DM_MAX_SEQ; seq++) { 377 ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, seq, 378 false, &dup); 379 if (ret == -ENODEV) 380 break; 381 if (ret) 382 return ret; 383 } 384 return seq; 385 } 386 387 int uclass_post_probe_device(struct udevice *dev) 388 { 389 struct uclass_driver *uc_drv = dev->uclass->uc_drv; 390 391 if (uc_drv->post_probe) 392 return uc_drv->post_probe(dev); 393 394 return 0; 395 } 396 397 int uclass_pre_remove_device(struct udevice *dev) 398 { 399 struct uclass_driver *uc_drv; 400 struct uclass *uc; 401 int ret; 402 403 uc = dev->uclass; 404 uc_drv = uc->uc_drv; 405 if (uc->uc_drv->pre_remove) { 406 ret = uc->uc_drv->pre_remove(dev); 407 if (ret) 408 return ret; 409 } 410 if (uc_drv->per_device_auto_alloc_size) { 411 free(dev->uclass_priv); 412 dev->uclass_priv = NULL; 413 } 414 dev->seq = -1; 415 416 return 0; 417 } 418