// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2021 * Köry Maincent, Bootlin, */ #include #include #include #include #include #include #include static LIST_HEAD(extension_list); static int extension_apply(struct extension *extension) { char *overlay_cmd; ulong extrasize, overlay_addr; struct fdt_header *blob; if (!working_fdt) { printf("No FDT memory address configured. Please configure\n" "the FDT address via \"fdt addr
\" command.\n"); return CMD_RET_FAILURE; } overlay_cmd = env_get("extension_overlay_cmd"); if (!overlay_cmd) { printf("Environment extension_overlay_cmd is missing\n"); return CMD_RET_FAILURE; } overlay_addr = env_get_hex("extension_overlay_addr", 0); if (!overlay_addr) { printf("Environment extension_overlay_addr is missing\n"); return CMD_RET_FAILURE; } env_set("extension_overlay_name", extension->overlay); if (run_command(overlay_cmd, 0) != 0) return CMD_RET_FAILURE; extrasize = env_get_hex("filesize", 0); if (!extrasize) return CMD_RET_FAILURE; fdt_shrink_to_minimum(working_fdt, extrasize); blob = map_sysmem(overlay_addr, 0); if (!fdt_valid(&blob)) return CMD_RET_FAILURE; /* apply method prints messages on error */ if (fdt_overlay_apply_verbose(working_fdt, blob)) return CMD_RET_FAILURE; return CMD_RET_SUCCESS; } static int do_extension_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { int i = 0; struct extension *extension; if (list_empty(&extension_list)) { printf("No extension registered - Please run \"extension scan\"\n"); return CMD_RET_SUCCESS; } list_for_each_entry(extension, &extension_list, list) { printf("Extension %d: %s\n", i++, extension->name); printf("\tManufacturer: \t\t%s\n", extension->owner); printf("\tVersion: \t\t%s\n", extension->version); printf("\tDevicetree overlay: \t%s\n", extension->overlay); printf("\tOther information: \t%s\n", extension->other); } return CMD_RET_SUCCESS; } static int do_extension_scan(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct extension *extension, *next; int extension_num; list_for_each_entry_safe(extension, next, &extension_list, list) { list_del(&extension->list); free(extension); } extension_num = extension_board_scan(&extension_list); if (extension_num < 0) return CMD_RET_FAILURE; printf("Found %d extension board(s).\n", extension_num); return CMD_RET_SUCCESS; } static int do_extension_apply(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct extension *extension = NULL; struct list_head *entry; int i = 0, extension_id, ret; if (argc < 2) return CMD_RET_USAGE; if (strcmp(argv[1], "all") == 0) { list_for_each_entry(extension, &extension_list, list) { ret = extension_apply(extension); if (ret != CMD_RET_SUCCESS) break; } } else { extension_id = simple_strtol(argv[1], NULL, 10); list_for_each(entry, &extension_list) { if (i == extension_id) { extension = list_entry(entry, struct extension, list); break; } i++; } if (!extension) { printf("Wrong extension number\n"); return CMD_RET_FAILURE; } ret = extension_apply(extension); } return ret; } static struct cmd_tbl cmd_extension[] = { U_BOOT_CMD_MKENT(scan, 1, 1, do_extension_scan, "", ""), U_BOOT_CMD_MKENT(list, 1, 0, do_extension_list, "", ""), U_BOOT_CMD_MKENT(apply, 2, 0, do_extension_apply, "", ""), }; static int do_extensionops(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct cmd_tbl *cp; /* Drop the extension command */ argc--; argv++; cp = find_cmd_tbl(argv[0], cmd_extension, ARRAY_SIZE(cmd_extension)); if (cp) return cp->cmd(cmdtp, flag, argc, argv); return CMD_RET_USAGE; } U_BOOT_CMD(extension, 3, 1, do_extensionops, "Extension board management sub system", "scan - scan plugged extension(s) board(s)\n" "extension list - lists available extension(s) board(s)\n" "extension apply - applies DT overlays corresponding to extension boards\n" );