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