lists.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * Copyright (c) 2013 Google, Inc
  3. *
  4. * (C) Copyright 2012
  5. * Marek Vasut <marex@denx.de>
  6. *
  7. * SPDX-License-Identifier: GPL-2.0+
  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. struct driver *lists_driver_lookup_name(const char *name)
  20. {
  21. struct driver *drv =
  22. ll_entry_start(struct driver, driver);
  23. const int n_ents = ll_entry_count(struct driver, driver);
  24. struct driver *entry;
  25. int len;
  26. if (!drv || !n_ents)
  27. return NULL;
  28. len = strlen(name);
  29. for (entry = drv; entry != drv + n_ents; entry++) {
  30. if (strncmp(name, entry->name, len))
  31. continue;
  32. /* Full match */
  33. if (len == strlen(entry->name))
  34. return entry;
  35. }
  36. /* Not found */
  37. return NULL;
  38. }
  39. struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
  40. {
  41. struct uclass_driver *uclass =
  42. ll_entry_start(struct uclass_driver, uclass);
  43. const int n_ents = ll_entry_count(struct uclass_driver, uclass);
  44. struct uclass_driver *entry;
  45. if ((id == UCLASS_INVALID) || !uclass)
  46. return NULL;
  47. for (entry = uclass; entry != uclass + n_ents; entry++) {
  48. if (entry->id == id)
  49. return entry;
  50. }
  51. return NULL;
  52. }
  53. int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)
  54. {
  55. struct driver_info *info =
  56. ll_entry_start(struct driver_info, driver_info);
  57. const int n_ents = ll_entry_count(struct driver_info, driver_info);
  58. struct driver_info *entry;
  59. struct udevice *dev;
  60. int result = 0;
  61. int ret;
  62. for (entry = info; entry != info + n_ents; entry++) {
  63. ret = device_bind_by_name(parent, pre_reloc_only, entry, &dev);
  64. if (ret && ret != -EPERM) {
  65. dm_warn("No match for driver '%s'\n", entry->name);
  66. if (!result || ret != -ENOENT)
  67. result = ret;
  68. }
  69. }
  70. return result;
  71. }
  72. #ifdef CONFIG_OF_CONTROL
  73. /**
  74. * driver_check_compatible() - Check if a driver is compatible with this node
  75. *
  76. * @param blob: Device tree pointer
  77. * @param offset: Offset of node in device tree
  78. * @param of_matchL List of compatible strings to match
  79. * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node
  80. * does not have a compatible string, other error <0 if there is a device
  81. * tree error
  82. */
  83. static int driver_check_compatible(const void *blob, int offset,
  84. const struct udevice_id *of_match)
  85. {
  86. int ret;
  87. if (!of_match)
  88. return -ENOENT;
  89. while (of_match->compatible) {
  90. ret = fdt_node_check_compatible(blob, offset,
  91. of_match->compatible);
  92. if (!ret)
  93. return 0;
  94. else if (ret == -FDT_ERR_NOTFOUND)
  95. return -ENODEV;
  96. else if (ret < 0)
  97. return -EINVAL;
  98. of_match++;
  99. }
  100. return -ENOENT;
  101. }
  102. int lists_bind_fdt(struct udevice *parent, const void *blob, int offset)
  103. {
  104. struct driver *driver = ll_entry_start(struct driver, driver);
  105. const int n_ents = ll_entry_count(struct driver, driver);
  106. struct driver *entry;
  107. struct udevice *dev;
  108. const char *name;
  109. int result = 0;
  110. int ret;
  111. dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL));
  112. for (entry = driver; entry != driver + n_ents; entry++) {
  113. ret = driver_check_compatible(blob, offset, entry->of_match);
  114. if (ret == -ENOENT) {
  115. continue;
  116. } else if (ret == -ENODEV) {
  117. break;
  118. } else if (ret) {
  119. dm_warn("Device tree error at offset %d\n", offset);
  120. if (!result || ret != -ENOENT)
  121. result = ret;
  122. break;
  123. }
  124. name = fdt_get_name(blob, offset, NULL);
  125. dm_dbg(" - found match at '%s'\n", entry->name);
  126. ret = device_bind(parent, entry, name, NULL, offset, &dev);
  127. if (ret) {
  128. dm_warn("No match for driver '%s'\n", entry->name);
  129. if (!result || ret != -ENOENT)
  130. result = ret;
  131. }
  132. }
  133. return result;
  134. }
  135. #endif