// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* * Copyright (C) 2020, STMicroelectronics - All Rights Reserved */ #include #include #include #include #include #include #include "stm32prog.h" struct stm32prog_data *stm32prog_data; static void enable_vidconsole(void) { char *stdname; char buf[64]; stdname = env_get("stdout"); if (!stdname || !strstr(stdname, "vidconsole")) { if (!stdname) snprintf(buf, sizeof(buf), "serial,vidconsole"); else snprintf(buf, sizeof(buf), "%s,vidconsole", stdname); env_set("stdout", buf); } stdname = env_get("stderr"); if (!stdname || !strstr(stdname, "vidconsole")) { if (!stdname) snprintf(buf, sizeof(buf), "serial,vidconsole"); else snprintf(buf, sizeof(buf), "%s,vidconsole", stdname); env_set("stderr", buf); } } static int do_stm32prog(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) { ulong addr, size; int dev, ret; enum stm32prog_link_t link = LINK_UNDEFINED; bool reset = false; struct image_header_s header; struct stm32prog_data *data; if (argc < 3 || argc > 5) return CMD_RET_USAGE; if (IS_ENABLED(CONFIG_CMD_STM32PROG_USB) && !strcmp(argv[1], "usb")) link = LINK_USB; else if (IS_ENABLED(CONFIG_CMD_STM32PROG_SERIAL) && !strcmp(argv[1], "serial")) link = LINK_SERIAL; if (link == LINK_UNDEFINED) { log_err("not supported link=%s\n", argv[1]); return CMD_RET_USAGE; } dev = (int)dectoul(argv[2], NULL); addr = CONFIG_SYS_LOAD_ADDR; size = 0; if (argc > 3) { addr = hextoul(argv[3], NULL); if (!addr) return CMD_RET_FAILURE; } if (argc > 4) size = hextoul(argv[4], NULL); /* check STM32IMAGE presence */ if (size == 0) { stm32prog_header_check(addr, &header); if (header.type == HEADER_STM32IMAGE) { size = header.image_length + header.length; } } if (IS_ENABLED(CONFIG_VIDEO)) enable_vidconsole(); data = (struct stm32prog_data *)malloc(sizeof(*data)); if (!data) { log_err("Alloc failed."); return CMD_RET_FAILURE; } stm32prog_data = data; ret = stm32prog_init(data, addr, size); if (ret) log_debug("Invalid or missing layout file at 0x%lx.\n", addr); /* prepare DFU for device read/write */ ret = stm32prog_dfu_init(data); if (ret) goto cleanup; switch (link) { case LINK_SERIAL: ret = stm32prog_serial_init(data, dev); if (ret) goto cleanup; reset = stm32prog_serial_loop(data); break; case LINK_USB: reset = stm32prog_usb_loop(data, dev); break; default: goto cleanup; } stm32prog_clean(data); free(stm32prog_data); stm32prog_data = NULL; puts("Download done\n"); if (data->uimage) { char boot_addr_start[20]; char dtb_addr[20]; char initrd_addr[40]; char *bootm_argv[5] = { "bootm", boot_addr_start, "-", dtb_addr, NULL }; const void *uimage = (void *)data->uimage; const void *dtb = (void *)data->dtb; const void *initrd = (void *)data->initrd; if (!dtb) bootm_argv[3] = env_get("fdtcontroladdr"); else snprintf(dtb_addr, sizeof(dtb_addr) - 1, "0x%p", dtb); snprintf(boot_addr_start, sizeof(boot_addr_start) - 1, "0x%p", uimage); if (initrd) { snprintf(initrd_addr, sizeof(initrd_addr) - 1, "0x%p:0x%zx", initrd, data->initrd_size); bootm_argv[2] = initrd_addr; } printf("Booting kernel at %s %s %s...\n\n\n", boot_addr_start, bootm_argv[2], bootm_argv[3]); /* Try bootm for legacy and FIT format image */ if (genimg_get_format(uimage) != IMAGE_FORMAT_INVALID) do_bootm(cmdtp, 0, 4, bootm_argv); else if (IS_ENABLED(CONFIG_CMD_BOOTZ)) do_bootz(cmdtp, 0, 4, bootm_argv); } if (data->script) cmd_source_script(data->script, NULL, NULL); if (reset) { puts("Reset...\n"); run_command("reset", 0); } return CMD_RET_SUCCESS; cleanup: stm32prog_clean(data); free(stm32prog_data); stm32prog_data = NULL; return CMD_RET_FAILURE; } U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog, "start communication with tools STM32Cubeprogrammer", " [] []\n" " = serial|usb\n" " = device instance\n" " = address of flashlayout\n" " = size of flashlayout (optional for image with STM32 header)\n" ); bool stm32prog_get_fsbl_nor(void) { if (stm32prog_data) return stm32prog_data->fsbl_nor_detected; return false; }