extension_board.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * (C) Copyright 2021
  4. * Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
  5. */
  6. #include <common.h>
  7. #include <bootdev.h>
  8. #include <command.h>
  9. #include <dm.h>
  10. #include <malloc.h>
  11. #include <extension_board.h>
  12. #include <mapmem.h>
  13. #include <linux/libfdt.h>
  14. #include <fdt_support.h>
  15. static LIST_HEAD(extension_list);
  16. static int extension_apply(struct extension *extension)
  17. {
  18. char *overlay_cmd;
  19. ulong extrasize, overlay_addr;
  20. struct fdt_header *blob;
  21. if (!working_fdt) {
  22. printf("No FDT memory address configured. Please configure\n"
  23. "the FDT address via \"fdt addr <address>\" command.\n");
  24. return CMD_RET_FAILURE;
  25. }
  26. overlay_cmd = env_get("extension_overlay_cmd");
  27. if (!overlay_cmd) {
  28. printf("Environment extension_overlay_cmd is missing\n");
  29. return CMD_RET_FAILURE;
  30. }
  31. overlay_addr = env_get_hex("extension_overlay_addr", 0);
  32. if (!overlay_addr) {
  33. printf("Environment extension_overlay_addr is missing\n");
  34. return CMD_RET_FAILURE;
  35. }
  36. env_set("extension_overlay_name", extension->overlay);
  37. if (run_command(overlay_cmd, 0) != 0)
  38. return CMD_RET_FAILURE;
  39. extrasize = env_get_hex("filesize", 0);
  40. if (!extrasize)
  41. return CMD_RET_FAILURE;
  42. fdt_shrink_to_minimum(working_fdt, extrasize);
  43. blob = map_sysmem(overlay_addr, 0);
  44. if (!fdt_valid(&blob))
  45. return CMD_RET_FAILURE;
  46. /* apply method prints messages on error */
  47. if (fdt_overlay_apply_verbose(working_fdt, blob))
  48. return CMD_RET_FAILURE;
  49. return CMD_RET_SUCCESS;
  50. }
  51. static int do_extension_list(struct cmd_tbl *cmdtp, int flag,
  52. int argc, char *const argv[])
  53. {
  54. int i = 0;
  55. struct extension *extension;
  56. if (list_empty(&extension_list)) {
  57. printf("No extension registered - Please run \"extension scan\"\n");
  58. return CMD_RET_SUCCESS;
  59. }
  60. list_for_each_entry(extension, &extension_list, list) {
  61. printf("Extension %d: %s\n", i++, extension->name);
  62. printf("\tManufacturer: \t\t%s\n", extension->owner);
  63. printf("\tVersion: \t\t%s\n", extension->version);
  64. printf("\tDevicetree overlay: \t%s\n", extension->overlay);
  65. printf("\tOther information: \t%s\n", extension->other);
  66. }
  67. return CMD_RET_SUCCESS;
  68. }
  69. static int extension_scan(bool show)
  70. {
  71. struct extension *extension, *next;
  72. int extension_num;
  73. list_for_each_entry_safe(extension, next, &extension_list, list) {
  74. list_del(&extension->list);
  75. free(extension);
  76. }
  77. extension_num = extension_board_scan(&extension_list);
  78. if (show && extension_num >= 0)
  79. printf("Found %d extension board(s).\n", extension_num);
  80. /* either the number of extensions, or -ve for error */
  81. return extension_num;
  82. }
  83. static int do_extension_scan(struct cmd_tbl *cmdtp, int flag,
  84. int argc, char *const argv[])
  85. {
  86. int extension_num;
  87. extension_num = extension_scan(true);
  88. if (extension_num < 0)
  89. return CMD_RET_FAILURE;
  90. return CMD_RET_SUCCESS;
  91. }
  92. static int do_extension_apply(struct cmd_tbl *cmdtp, int flag,
  93. int argc, char *const argv[])
  94. {
  95. struct extension *extension = NULL;
  96. struct list_head *entry;
  97. int i = 0, extension_id, ret;
  98. if (argc < 2)
  99. return CMD_RET_USAGE;
  100. if (strcmp(argv[1], "all") == 0) {
  101. ret = CMD_RET_FAILURE;
  102. list_for_each_entry(extension, &extension_list, list) {
  103. ret = extension_apply(extension);
  104. if (ret != CMD_RET_SUCCESS)
  105. break;
  106. }
  107. } else {
  108. extension_id = simple_strtol(argv[1], NULL, 10);
  109. list_for_each(entry, &extension_list) {
  110. if (i == extension_id) {
  111. extension = list_entry(entry, struct extension, list);
  112. break;
  113. }
  114. i++;
  115. }
  116. if (!extension) {
  117. printf("Wrong extension number\n");
  118. return CMD_RET_FAILURE;
  119. }
  120. ret = extension_apply(extension);
  121. }
  122. return ret;
  123. }
  124. static struct cmd_tbl cmd_extension[] = {
  125. U_BOOT_CMD_MKENT(scan, 1, 1, do_extension_scan, "", ""),
  126. U_BOOT_CMD_MKENT(list, 1, 0, do_extension_list, "", ""),
  127. U_BOOT_CMD_MKENT(apply, 2, 0, do_extension_apply, "", ""),
  128. };
  129. static int do_extensionops(struct cmd_tbl *cmdtp, int flag, int argc,
  130. char *const argv[])
  131. {
  132. struct cmd_tbl *cp;
  133. /* Drop the extension command */
  134. argc--;
  135. argv++;
  136. cp = find_cmd_tbl(argv[0], cmd_extension, ARRAY_SIZE(cmd_extension));
  137. if (cp)
  138. return cp->cmd(cmdtp, flag, argc, argv);
  139. return CMD_RET_USAGE;
  140. }
  141. U_BOOT_CMD(extension, 3, 1, do_extensionops,
  142. "Extension board management sub system",
  143. "scan - scan plugged extension(s) board(s)\n"
  144. "extension list - lists available extension(s) board(s)\n"
  145. "extension apply <extension number|all> - applies DT overlays corresponding to extension boards\n"
  146. );
  147. static int extension_bootdev_hunt(struct bootdev_hunter *info, bool show)
  148. {
  149. int ret;
  150. ret = env_set_hex("extension_overlay_addr",
  151. env_get_hex("fdtoverlay_addr_r", 0));
  152. if (ret)
  153. return log_msg_ret("env", ret);
  154. ret = extension_scan(show);
  155. if (ret < 0)
  156. return log_msg_ret("ext", ret);
  157. return 0;
  158. }
  159. /* extensions should have a uclass - for now we use UCLASS_SIMPLE_BUS uclass */
  160. BOOTDEV_HUNTER(extension_bootdev_hunter) = {
  161. .prio = BOOTDEVP_1_PRE_SCAN,
  162. .uclass = UCLASS_SIMPLE_BUS,
  163. .hunt = extension_bootdev_hunt,
  164. };