| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Commands for UPL handoff generation |
| * |
| * Copyright 2024 Google LLC |
| * Written by Simon Glass <sjg@chromium.org> |
| */ |
| |
| #define LOG_CATEGORY UCLASS_BOOTSTD |
| |
| #include <abuf.h> |
| #include <alist.h> |
| #include <command.h> |
| #include <display_options.h> |
| #include <mapmem.h> |
| #include <string.h> |
| #include <upl.h> |
| #include <dm/ofnode.h> |
| #include <test/ut.h> |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| static int do_upl_info(struct cmd_tbl *cmdtp, int flag, int argc, |
| char *const argv[]) |
| { |
| const struct upl *upl = gd_upl(); |
| |
| printf("UPL state: %sactive\n", upl ? "" : "in"); |
| if (!upl) |
| return 0; |
| if (argc > 1 && !strcmp("-v", argv[1])) { |
| int i; |
| |
| printf("fit %lx\n", upl->fit); |
| printf("conf_offset %x\n", upl->conf_offset); |
| for (i = 0; i < upl->image.count; i++) { |
| const struct upl_image *img = |
| alist_get(&upl->image, i, struct upl_image); |
| |
| printf("image %d: load %lx size %lx offset %x: %s\n", i, |
| img->load, img->size, img->offset, |
| img->description); |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int do_upl_write(struct cmd_tbl *cmdtp, int flag, int argc, |
| char *const argv[]) |
| { |
| struct upl s_upl, *upl = &s_upl; |
| struct unit_test_state uts = { 0 }; |
| struct abuf buf; |
| oftree tree; |
| ulong addr; |
| int ret; |
| |
| upl_get_test_data(&uts, upl); |
| |
| log_debug("Writing UPL\n"); |
| ret = upl_create_handoff_tree(upl, &tree); |
| if (ret) { |
| log_err("Failed to write (err=%dE)\n", ret); |
| return CMD_RET_FAILURE; |
| } |
| |
| log_debug("Flattening\n"); |
| ret = oftree_to_fdt(tree, &buf); |
| if (ret) { |
| log_err("Failed to write (err=%dE)\n", ret); |
| return CMD_RET_FAILURE; |
| } |
| addr = map_to_sysmem(abuf_data(&buf)); |
| printf("UPL handoff written to %lx size %zx\n", addr, abuf_size(&buf)); |
| if (env_set_hex("upladdr", addr) || |
| env_set_hex("uplsize", abuf_size(&buf))) { |
| printf("Cannot set env var\n"); |
| return CMD_RET_FAILURE; |
| } |
| |
| log_debug("done\n"); |
| |
| return 0; |
| } |
| |
| static int do_upl_read(struct cmd_tbl *cmdtp, int flag, int argc, |
| char *const argv[]) |
| { |
| struct upl s_upl, *upl = &s_upl; |
| oftree tree; |
| ulong addr; |
| int ret; |
| |
| if (argc < 1) |
| return CMD_RET_USAGE; |
| addr = hextoul(argv[1], NULL); |
| |
| printf("Reading UPL at %lx\n", addr); |
| tree = oftree_from_fdt(map_sysmem(addr, 0)); |
| ret = upl_read_handoff(upl, tree); |
| if (ret) { |
| log_err("Failed to read (err=%dE)\n", ret); |
| return CMD_RET_FAILURE; |
| } |
| |
| return 0; |
| } |
| |
| U_BOOT_LONGHELP(upl, |
| "info [-v] - Check UPL status\n" |
| "upl read <addr> - Read handoff information\n" |
| "upl write - Write handoff information"); |
| |
| U_BOOT_CMD_WITH_SUBCMDS(upl, "Universal Payload support", upl_help_text, |
| U_BOOT_SUBCMD_MKENT(info, 2, 1, do_upl_info), |
| U_BOOT_SUBCMD_MKENT(read, 2, 1, do_upl_read), |
| U_BOOT_SUBCMD_MKENT(write, 1, 1, do_upl_write)); |