diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch')
-rw-r--r-- | meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch | 1271 |
1 files changed, 1271 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch new file mode 100644 index 000000000..00dbd68da --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch @@ -0,0 +1,1271 @@ +From bd4a64d7ea394d0b418d491699853112229f098e Mon Sep 17 00:00:00 2001 +From: AppaRao Puli <apparao.puli@linux.intel.com> +Date: Tue, 21 May 2019 00:53:04 +0530 +Subject: [PATCH] FFUJ: FW IPMI commands and flash support in u-boot + +Firmware update and OEM ipmi commands implementation +for supporting Force Firmware Update Jumper(FFUJ) +mode. Also added support to update the fit images +in FFUJ mode. + +Firmware update commands: +1) Get BMC Execution Context(0x23) +2) Get Firmware Update Random Number(0x26) +3) Set Firmware Update Mode(0x27) +4) Exit Firmware Update Mode(0x28) +5) Set/Get Firmware Update Control(0x29) +6) Get Firmware Update status(0x2A) +7) Set Firmware Update Options(0x2B) +8) Firmware Image Write(0x2C) + +OEM Commands: +1) Get Buffer Size(0x66) + +Tested: + - Used cmdtool.efi to test the individual commands + implementation and negative cases. + - Used debug fwpiaupd.efi tool for validating Firmware + image transfer via KCS and flashing. + +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +--- + arch/arm/include/asm/arch-aspeed/ast-g5-intel.h | 1 + + board/aspeed/ast-g5/Makefile | 2 + + board/aspeed/ast-g5/fw-update.c | 486 ++++++++++++++++++++++++ + board/aspeed/ast-g5/fw-update.h | 50 +++ + board/aspeed/ast-g5/ipmi-fwupd.c | 402 ++++++++++++++++++++ + board/aspeed/ast-g5/ipmi-fwupd.h | 81 ++++ + board/aspeed/ast-g5/ipmi-handler.c | 66 +++- + board/aspeed/ast-g5/ipmi-handler.h | 3 +- + common/autoboot.c | 11 + + configs/ast_g5_phy_defconfig | 1 + + 10 files changed, 1091 insertions(+), 12 deletions(-) + create mode 100644 board/aspeed/ast-g5/fw-update.c + create mode 100644 board/aspeed/ast-g5/fw-update.h + create mode 100644 board/aspeed/ast-g5/ipmi-fwupd.c + create mode 100644 board/aspeed/ast-g5/ipmi-fwupd.h + +diff --git a/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h +index cd9a099..a88521a 100644 +--- a/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h ++++ b/arch/arm/include/asm/arch-aspeed/ast-g5-intel.h +@@ -14,6 +14,7 @@ + + #ifndef __ASSEMBLY__ + int intel_force_firmware_jumper_enabled(void); ++void start_fw_update_loop(void); + #endif + + #endif /* __AST_INTEL_G5_H__ */ +diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile +index f28fcfe..0b2d936 100644 +--- a/board/aspeed/ast-g5/Makefile ++++ b/board/aspeed/ast-g5/Makefile +@@ -6,3 +6,5 @@ obj-y += ast-g5-gpio.o + obj-y += ast-g5-timer.o + obj-y += ast-g5-kcs.o + obj-y += ipmi-handler.o ++obj-y += ipmi-fwupd.o ++obj-y += fw-update.o +diff --git a/board/aspeed/ast-g5/fw-update.c b/board/aspeed/ast-g5/fw-update.c +new file mode 100644 +index 0000000..9923993 +--- /dev/null ++++ b/board/aspeed/ast-g5/fw-update.c +@@ -0,0 +1,486 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include <common.h> ++#include <cli.h> ++#include <flash.h> ++ ++#include "fw-update.h" ++ ++#define BOOTCMD_BOOTM_STR "bootm " ++#define RANDOM_NUM_TIMEOUT 30 /* in seconds */ ++#define WAIT_STATE_TIMEOUT 10000 /* 10 seconds */ ++ ++#define PROTECT_OFF 0 ++#define PROTECT_ON 1 ++ ++extern struct fwupd_global_setting g_fwupd_settings; ++extern u32 g_write_addr; ++ ++bool g_fwupd_settings_lock = false; ++unsigned long long etime; ++ ++bool fwupd_settings_trylock(void) ++{ ++ if (g_fwupd_settings_lock) ++ return false; ++ ++ g_fwupd_settings_lock = true; ++ return g_fwupd_settings_lock; ++} ++ ++void fwupd_settings_unlock(void) ++{ ++ g_fwupd_settings_lock = false; ++} ++ ++u8 get_active_boot_image(void) ++{ ++ char *bootcmd = getenv("bootcmd"); ++ char *start = strstr(bootcmd, BOOTCMD_BOOTM_STR); ++ u8 boot_image = PRIMARY_IMAGE; ++ ++ if (start) { ++ ulong boot_addr = simple_strtoul( ++ (start + strlen(BOOTCMD_BOOTM_STR)), NULL, 16); ++ if (boot_addr == SECONDARY_FITIMAGE_START_ADDR) ++ return SECONDARY_IMAGE; ++ } ++ return boot_image; ++} ++ ++static ulong get_flash_image_address(void) ++{ ++ char *bootcmd = getenv("bootcmd"); ++ char *start = strstr(bootcmd, BOOTCMD_BOOTM_STR); ++ ulong boot_addr = PRIMARY_FITIMAGE_START_ADDR; ++ ++ if (start) { ++ boot_addr = simple_strtoul((start + strlen(BOOTCMD_BOOTM_STR)), ++ NULL, 16); ++ /* We update in backup region and set the bootcmd accordingly */ ++ if (boot_addr == PRIMARY_FITIMAGE_START_ADDR) ++ boot_addr = SECONDARY_FITIMAGE_START_ADDR; ++ else ++ boot_addr = PRIMARY_FITIMAGE_START_ADDR; ++ } ++ ++ return boot_addr; ++} ++ ++static void update_processing_status(u8 status, u8 percent) ++{ ++ if (!fwupd_settings_trylock()) ++ return; ++ ++ g_fwupd_settings.processing_status = status; ++ g_fwupd_settings.percentage_completion = percent; ++ ++ fwupd_settings_unlock(); ++ return; ++} ++ ++static void reset_all_settings(void) ++{ ++ if (!fwupd_settings_trylock()) ++ return; ++ ++ memset(&g_fwupd_settings, 0, sizeof(g_fwupd_settings)); ++ g_fwupd_settings.fwupd_mode_active = false; ++ g_fwupd_settings.start_update = false; ++ ++ fwupd_settings_unlock(); ++} ++ ++unsigned int get_seed(void) ++{ ++ char seed_str[] = { "INTEL" }; ++ unsigned int seed; ++ ++ for (int i = 0; i < strlen(seed_str); i++) ++ seed += (seed_str[i] << (i * 8)); ++ ++ return seed; ++} ++ ++int generate_random_number(void) ++{ ++ srand(get_seed()); ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ return -1; ++ } ++ for (int i = 0; i < RAND_NUMBER_SIZE; i++) ++ g_fwupd_settings.rand_num[i] = (u8)(rand() & 0xFF); ++ ++ g_fwupd_settings.random_number_valid = true; ++ ++ fwupd_settings_unlock(); ++ ++ /* Random number should be cleared after 30sec timeout */ ++ etime = endtick(RANDOM_NUM_TIMEOUT); ++ ++ return 0; ++} ++ ++static int sect_roundb(ulong *addr) ++{ ++ flash_info_t *info; ++ ulong bank, sector_end_addr; ++ char found; ++ int i; ++ ++ /* find the end addr of the sector where the *addr is */ ++ found = 0; ++ for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS && !found; ++bank) { ++ info = &flash_info[bank]; ++ for (i = 0; i < info->sector_count && !found; ++i) { ++ /* get the end address of the sector */ ++ if (i == info->sector_count - 1) { ++ sector_end_addr = ++ info->start[0] + info->size - 1; ++ } else { ++ sector_end_addr = info->start[i + 1] - 1; ++ } ++ ++ if (*addr <= sector_end_addr && ++ *addr >= info->start[i]) { ++ found = 1; ++ /* adjust *addr if necessary */ ++ if (*addr < sector_end_addr) ++ *addr = sector_end_addr; ++ } /* sector */ ++ } /* bank */ ++ } ++ if (!found) { ++ /* error, address not in flash */ ++ printf("Error: end address (0x%08lx) not in flash!\n", *addr); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int fill_flash_sect_ranges(ulong addr_first, ulong addr_last, ++ int *s_first, int *s_last, int *s_count) ++{ ++ flash_info_t *info; ++ ulong bank; ++ int rcode = 0; ++ ++ *s_count = 0; ++ ++ for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) { ++ s_first[bank] = -1; /* first sector to erase */ ++ s_last[bank] = -1; /* last sector to erase */ ++ } ++ ++ for (bank = 0, info = &flash_info[0]; ++ (bank < CONFIG_SYS_MAX_FLASH_BANKS) && (addr_first <= addr_last); ++ ++bank, ++info) { ++ ulong b_end; ++ int sect; ++ short s_end; ++ ++ if (info->flash_id == FLASH_UNKNOWN) ++ continue; ++ ++ b_end = info->start[0] + info->size - 1; /* bank end addr */ ++ s_end = info->sector_count - 1; /* last sector */ ++ ++ for (sect = 0; sect < info->sector_count; ++sect) { ++ ulong end; /* last address in current sect */ ++ ++ end = (sect == s_end) ? b_end : ++ info->start[sect + 1] - 1; ++ ++ if (addr_first > end) ++ continue; ++ if (addr_last < info->start[sect]) ++ continue; ++ ++ if (addr_first == info->start[sect]) ++ s_first[bank] = sect; ++ if (addr_last == end) ++ s_last[bank] = sect; ++ } ++ if (s_first[bank] >= 0) { ++ if (s_last[bank] < 0) { ++ if (addr_last > b_end) { ++ s_last[bank] = s_end; ++ } else { ++ printf("Error: end address not on sector boundary\n"); ++ rcode = 1; ++ break; ++ } ++ } ++ if (s_last[bank] < s_first[bank]) { ++ printf("Error: end sector precedes start sector\n"); ++ rcode = 1; ++ break; ++ } ++ sect = s_last[bank]; ++ addr_first = (sect == s_end) ? b_end + 1 : ++ info->start[sect + 1]; ++ (*s_count) += s_last[bank] - s_first[bank] + 1; ++ } else if (addr_first >= info->start[0] && addr_first < b_end) { ++ printf("Error: start address not on sector boundary\n"); ++ rcode = 1; ++ break; ++ } else if (s_last[bank] >= 0) { ++ printf("Error: cannot span across banks when they are mapped in reverse order\n"); ++ rcode = 1; ++ break; ++ } ++ } ++ ++ return rcode; ++} ++ ++static int protect_flash_sector(int state, ulong addr_first, ulong addr_last) ++{ ++ flash_info_t *info; ++ ulong bank; ++ int s_first[CONFIG_SYS_MAX_FLASH_BANKS], ++ s_last[CONFIG_SYS_MAX_FLASH_BANKS]; ++ int protected = 0; ++ int planned; ++ int rcode, i; ++ ++ rcode = fill_flash_sect_ranges(addr_first, addr_last, s_first, s_last, ++ &planned); ++ ++ if (planned && (rcode == 0)) { ++ for (bank = 0, info = &flash_info[0]; ++ bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank, ++info) { ++ if (info->flash_id == FLASH_UNKNOWN) ++ continue; ++ ++ if (s_first[bank] >= 0 && ++ s_first[bank] <= s_last[bank]) { ++ debug("%sProtecting sectors %d..%d in bank %ld\n", ++ state ? "" : "Un-", s_first[bank], ++ s_last[bank], bank + 1); ++ protected ++ += s_last[bank] - s_first[bank] + 1; ++ for (i = s_first[bank]; i <= s_last[bank]; ++i) ++ info->protect[i] = state; ++ } ++ } ++ printf("%sProtected %d sectors\n", state ? "" : "Un-", ++ protected); ++ } else if (rcode == 0) { ++ printf("Error: start and/or end address not on sector boundary\n"); ++ rcode = 1; ++ } ++ ++ return rcode; ++} ++ ++static int erase_flash_sector(ulong addr_first, ulong addr_last) ++{ ++ flash_info_t *info; ++ ulong bank; ++ int s_first[CONFIG_SYS_MAX_FLASH_BANKS]; ++ int s_last[CONFIG_SYS_MAX_FLASH_BANKS]; ++ int erased = 0; ++ int planned; ++ int rcode = 0; ++ ++ rcode = fill_flash_sect_ranges(addr_first, addr_last, s_first, s_last, ++ &planned); ++ ++ if (planned && (rcode == 0)) { ++ for (bank = 0, info = &flash_info[0]; ++ (bank < CONFIG_SYS_MAX_FLASH_BANKS) && (rcode == 0); ++ ++bank, ++info) { ++ if (s_first[bank] >= 0) { ++ erased += s_last[bank] - s_first[bank] + 1; ++ debug("Erase Flash from 0x%08lx to 0x%08lx " ++ "in Bank # %ld ", ++ info->start[s_first[bank]], ++ (s_last[bank] == info->sector_count) ? ++ info->start[0] + info->size - 1 : ++ info->start[s_last[bank] + 1] - 1, ++ bank + 1); ++ rcode = flash_erase(info, s_first[bank], ++ s_last[bank]); ++ } ++ } ++ if (rcode == 0) ++ printf("Erased %d sectors\n", erased); ++ } else if (rcode == 0) { ++ printf("Error: start and/or end address not on sector boundary\n"); ++ rcode = 1; ++ } ++ ++ return rcode; ++} ++ ++static int verify_image(void) ++{ ++ ulong src_addr = IMAGE_LOAD_RAM_ADDR; ++ void *hdr = (void *)src_addr; ++ ++ printf("\n## Checking Image at 0x%08lx ...\n", src_addr); ++ /* AT the moment, we only support FIT image flash */ ++ switch (genimg_get_format(hdr)) { ++ case IMAGE_FORMAT_FIT: ++ printf(" FIT image found\n"); ++ if (!fit_check_format(hdr)) { ++ printf("Bad FIT image format!\n"); ++ return -1; ++ } ++ ++ if (!fit_all_image_verify(hdr)) { ++ printf("Bad hash in FIT image!\n"); ++ return -1; ++ } ++ break; ++ default: ++ printf("Unknown image format!\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int flash_image(void) ++{ ++ int rcode; ++ ulong max_size = MAX_FITIMAGE_SIZE; ++ ulong src_addr = IMAGE_LOAD_RAM_ADDR; ++ ulong addr_first = get_flash_image_address(); ++ ulong addr_last = addr_first + max_size - 1; ++ ++ if ((g_write_addr > max_size) || (g_write_addr == 0)) { ++ printf("ERROR: %s(): Invalid file uploaded. filesize(0x%08x)\n", ++ __func__, g_write_addr); ++ return -1; ++ } ++ ++ if (sect_roundb(&addr_last) > 0) { ++ printf("ERROR: %s(): sect_roundb failed\n", __func__); ++ return -1; ++ } ++ ++ if (addr_first >= addr_last) { ++ printf("ERROR: %s(): addr_first(0x%08lx) >= addr_last(0x%08lx)\n", ++ __func__, addr_first, addr_last); ++ return -1; ++ } ++ ++ /* Hack: To update the percentage update, ++ * treat logical division as below. ++ * Image verify - 10% ++ * Unprotecting flash sectors - 10% ++ * Erase flash sectors - 40% ++ * Copy to flash - 40% */ ++ ++ /* Unprotect the flash sectors */ ++ rcode = protect_flash_sector(PROTECT_OFF, addr_first, addr_last); ++ if (rcode != 0) { ++ printf("%s(): Protecting flash sector failed(%d).\n", __func__, ++ rcode); ++ return -1; ++ } ++ update_processing_status(IMG_PROGRAMMING, 20); ++ ++ /* erase flash sectors */ ++ rcode = erase_flash_sector(addr_first, addr_last); ++ if (rcode != 0) { ++ printf("%s(): Erasing flash sector failed(%d).\n", __func__, ++ rcode); ++ return -1; ++ } ++ update_processing_status(IMG_PROGRAMMING, 60); ++ ++ /* write to flash area */ ++ printf("Copy to Flash... "); ++ rcode = flash_write((char *)src_addr, addr_first, g_write_addr * 1); ++ if (rcode != 0) { ++ printf("%s(): Flash copy failed(%d).\n", __func__, rcode); ++ flash_perror(rcode); ++ return -1; ++ } ++ printf("done\n"); ++ return 0; ++} ++ ++void start_fw_update_loop(void) ++{ ++ int rc; ++ ulong boot_addr; ++ char boot_cmd[20]; ++ ++ while (1) { ++ if (g_fwupd_settings.random_number_valid) { ++ /* Random number should be cleared after 30seconds */ ++ if (get_ticks() >= etime) { ++ printf("Clearing random number\n"); ++ ++ if (!fwupd_settings_trylock()) ++ continue; ++ memcpy(g_fwupd_settings.rand_num, 0, ++ RAND_NUMBER_SIZE); ++ g_fwupd_settings.random_number_valid = false; ++ fwupd_settings_unlock(); ++ } ++ } ++ ++ if (g_fwupd_settings.start_update) { ++ update_processing_status(IMG_VALIDATING, 0); ++ ++ rc = verify_image(); ++ if (rc != 0) { ++ update_processing_status(UPDATE_ERROR, 100); ++ /* Adding delay to make consumer gets status */ ++ mdelay(WAIT_STATE_TIMEOUT); ++ ++ reset_all_settings(); ++ continue; ++ } ++ ++ update_processing_status(IMG_PROGRAMMING, 10); ++ ++ rc = flash_image(); ++ if (rc == 0) { ++ /* Update successful, change the boot command */ ++ boot_addr = get_flash_image_address(); ++ snprintf(boot_cmd, sizeof(boot_cmd), ++ "bootm %08x", boot_addr); ++ setenv("bootcmd", boot_cmd); ++ saveenv(); ++ ++ update_processing_status(UPDATE_SUCCESSFUL, ++ 100); ++ } else { ++ update_processing_status(UPDATE_ERROR, 100); ++ } ++ ++ /* Adding delay to make sure consumer gets status */ ++ mdelay(WAIT_STATE_TIMEOUT); ++ ++ reset_all_settings(); ++ ++ /* Reset BMC */ ++ do_reset(NULL, 0, 0, NULL); ++ } ++ mdelay(WAIT_STATE_TIMEOUT); ++ } ++ ++ return; ++} ++ ++#if 1 /* Debug purpose */ ++int do_fwupd(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) ++{ ++ if (argc != 1) ++ return 1; ++ ++ start_fw_update_loop(); ++ return 0; ++} ++U_BOOT_CMD(fwupd, 1, 0, do_fwupd, "Start Firmware update process", ""); ++#endif +diff --git a/board/aspeed/ast-g5/fw-update.h b/board/aspeed/ast-g5/fw-update.h +new file mode 100644 +index 0000000..ed033ad +--- /dev/null ++++ b/board/aspeed/ast-g5/fw-update.h +@@ -0,0 +1,50 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include <common.h> ++ ++/* SPI flash map */ ++#define MAX_FITIMAGE_SIZE 0x1B80000 ++#define PRIMARY_FITIMAGE_START_ADDR 0x20080000 ++#define SECONDARY_FITIMAGE_START_ADDR 0x22480000 ++#define IMAGE_LOAD_RAM_ADDR 0x83000000 ++ ++#define MAX_FILENAME_LENGTH 256 ++#define RAND_NUMBER_SIZE 8 ++ ++enum boot_image { ++ PRIMARY_IMAGE = 0x01, ++ SECONDARY_IMAGE = 0x02 ++}; ++ ++enum update_status { ++ INITIALIZING = 0, ++ IDLE, ++ IMG_DOWNLOADING, ++ IMG_VALIDATING, ++ IMG_PROGRAMMING, ++ UPDATE_SUCCESSFUL, ++ UPDATE_ERROR = 0x0F, ++ UPDATE_FORBIDDEN = 0x80, ++ AC_CYCLE_REQUIRED = 0x83 ++}; ++ ++struct fwupd_global_setting { ++ bool fwupd_mode_active; ++ bool start_update; ++ bool random_number_valid; ++ u8 ctrl_state; ++ u8 options_mask; ++ u8 options_value; ++ u8 processing_status; ++ u8 percentage_completion; ++ u8 integrity_check_status; ++ u8 filename_len; ++ u8 filename[MAX_FILENAME_LENGTH]; ++ u8 rand_num[RAND_NUMBER_SIZE]; ++}; ++ ++bool fwupd_settings_trylock(void); ++void fwupd_settings_unlock(void); ++u8 get_active_boot_image(void); ++int generate_random_number(void); +diff --git a/board/aspeed/ast-g5/ipmi-fwupd.c b/board/aspeed/ast-g5/ipmi-fwupd.c +new file mode 100644 +index 0000000..3eba056 +--- /dev/null ++++ b/board/aspeed/ast-g5/ipmi-fwupd.c +@@ -0,0 +1,402 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include "ipmi-fwupd.h" ++ ++struct fwupd_global_setting g_fwupd_settings; ++u32 g_write_addr = 0; ++ ++u16 fwupd_get_execution_ctx(u8 *req, u16 req_len, u8 *res) ++{ ++ int booting_image = 0x01; ++ struct fwupd_get_exe_ctx_res *result = ++ (struct fwupd_get_exe_ctx_res *)res; ++ ++ /* Get active image location(primary/secondary) */ ++ booting_image = get_active_boot_image(); ++ result->patition_ptr = booting_image; ++ result->exection_ctx = 0x11; /* Forced Firmware Update mode */ ++ ++ result->completion_code = IPMI_CC_OK; ++ return sizeof(struct fwupd_get_exe_ctx_res); ++} ++u16 fwupd_get_rand_number(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_rand_num_res *result = (struct fwupd_rand_num_res *)res; ++ ++ if (req_len != 0) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is critical operation is going on */ ++ if (g_fwupd_settings.start_update) { ++ printf("%s(): Update in progress.\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is it already in fwupdate mode */ ++ if (g_fwupd_settings.fwupd_mode_active) { ++ printf("%s(): Already in firmware update mode\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ if (generate_random_number() != 0) { ++ printf("%s(): Random number generation failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ result->completion_code = IPMI_CC_OK; ++ memcpy(result->rand_num, g_fwupd_settings.rand_num, RAND_NUMBER_SIZE); ++ ++ return sizeof(struct fwupd_rand_num_res); ++} ++ ++u16 fwupd_enter_update_mode(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_set_update_mode_res *result = ++ (struct fwupd_set_update_mode_res *)res; ++ ++ if (req_len != RAND_NUMBER_SIZE) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is critical operation is going on */ ++ if (g_fwupd_settings.start_update) { ++ printf("%s(): Update in progress.\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is it already in fwupdate mode */ ++ if (g_fwupd_settings.fwupd_mode_active) { ++ printf("%s(): Already in firmware update mode\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ /* This command should excute within 30 seconds ++ * after random number generation. */ ++ if (!g_fwupd_settings.random_number_valid) { ++ printf("%s(): No valid random number exist.\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_CODE; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Validate the key to enter this mode */ ++ for (int i = 0; i < RAND_NUMBER_SIZE; i++) { ++ if (req[i] != g_fwupd_settings.rand_num[i]) { ++ printf("%s(): Invalid key entered\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_CODE; ++ return sizeof(result->completion_code); ++ } ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ /* Reset all the settings */ ++ memset(&g_fwupd_settings, 0, sizeof(g_fwupd_settings)); ++ g_fwupd_settings.fwupd_mode_active = true; ++ fwupd_settings_unlock(); ++ ++ result->completion_code = IPMI_CC_OK; ++ ++ return sizeof(struct fwupd_set_update_mode_res); ++} ++ ++u16 fwupd_exit_update_mode(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_exit_update_mode_res *result = ++ (struct fwupd_exit_update_mode_res *)res; ++ ++ if (req_len != 0) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!g_fwupd_settings.fwupd_mode_active) { ++ printf("%s(): Invalid command entered\n", __func__); ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.fwupd_mode_active = false; ++ fwupd_settings_unlock(); ++ ++ result->completion_code = IPMI_CC_OK; ++ ++ return sizeof(struct fwupd_exit_update_mode_res); ++} ++u16 fwupd_set_options(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_options_req *options_req = (struct fwupd_options_req *)req; ++ struct fwupd_options_res *result = (struct fwupd_options_res *)res; ++ ++ if (req_len < 2) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is critical operation is going on */ ++ if (g_fwupd_settings.start_update) { ++ printf("%s(): Update in progress.\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Setting any reserved bits will result the command being rejected */ ++ if (((options_req->options_mask & 0xF0) != 0) || ++ ((options_req->options_value & 0xF0) != 0)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_FIELD; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.options_mask = options_req->options_mask; ++ g_fwupd_settings.options_value = options_req->options_value; ++ fwupd_settings_unlock(); ++ ++ result->completion_code = IPMI_CC_OK; ++ result->options_value = (g_fwupd_settings.options_mask & ++ g_fwupd_settings.options_value); ++ ++ return sizeof(struct fwupd_options_res); ++} ++ ++u16 fwupd_set_get_control(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_control_req *ctrl_req = (struct fwupd_control_req *)req; ++ struct fwupd_control_res *result = (struct fwupd_control_res *)res; ++ ++ if (req_len < 1) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is critical operation is going on */ ++ if (g_fwupd_settings.start_update) { ++ printf("%s(): Update in progress.\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ if ((ctrl_req->ctrl_state == SET_FW_FILENAME) && (req_len < 3)) { ++ printf("%s(): Invalid request data\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } else if ((ctrl_req->ctrl_state != SET_FW_FILENAME) && ++ (req_len != 1)) { ++ printf("%s(): Invalid request data\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ if ((!g_fwupd_settings.fwupd_mode_active) && ++ (ctrl_req->ctrl_state != GET_CTRL_STATE)) { ++ printf("%s(): Invalid request. Control State: %d.\n", __func__, ++ ctrl_req->ctrl_state); ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ switch (ctrl_req->ctrl_state) { ++ case GET_CTRL_STATE: ++ break; ++ case IMG_TRANSFER_START: ++ if ((g_fwupd_settings.ctrl_state & ++ IMG_TRANSFER_CTRL_BIT_START)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = ++ IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.processing_status = IMG_DOWNLOADING; ++ /* Reset control state during start */ ++ g_fwupd_settings.ctrl_state = 0x00; ++ g_fwupd_settings.ctrl_state |= IMG_TRANSFER_CTRL_BIT_START; ++ /* Set current write address to ZERO */ ++ g_write_addr = 0x00; ++ fwupd_settings_unlock(); ++ break; ++ case IMG_TRANSFER_END: ++ if (!(g_fwupd_settings.ctrl_state & ++ IMG_TRANSFER_CTRL_BIT_START)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = ++ IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.start_update = true; ++ g_fwupd_settings.ctrl_state |= IMG_TRANSFER_CTRL_BIT_END; ++ ++ g_fwupd_settings.ctrl_state &= ~(IMG_TRANSFER_CTRL_BIT_START | ++ IMG_TRANSFER_CTRL_BIT_ABORT); ++ fwupd_settings_unlock(); ++ break; ++ case IMG_TRANSFER_ABORT: ++ if (!(g_fwupd_settings.ctrl_state & ++ IMG_TRANSFER_CTRL_BIT_START)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = ++ IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.processing_status = UPDATE_ERROR; ++ g_fwupd_settings.ctrl_state |= IMG_TRANSFER_CTRL_BIT_ABORT; ++ g_fwupd_settings.ctrl_state &= ~(IMG_TRANSFER_CTRL_BIT_START | ++ IMG_TRANSFER_CTRL_BIT_END); ++ fwupd_settings_unlock(); ++ break; ++ case SET_FW_FILENAME: ++ /* Not supporting now */ ++ if (ctrl_req->filename_len > sizeof(ctrl_req->filename)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_FIELD; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!(g_fwupd_settings.ctrl_state & ++ IMG_TRANSFER_CTRL_BIT_START)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = ++ IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!fwupd_settings_trylock()) { ++ printf("%s(): Lock failed\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ g_fwupd_settings.filename_len = ctrl_req->filename_len; ++ strncpy(g_fwupd_settings.filename, ctrl_req->filename, ++ ctrl_req->filename_len); ++ fwupd_settings_unlock(); ++ /* TODO: Used for TFTP update but not implemented yet. */ ++ /* TODO: Verify image and write to flash */ ++ break; ++ case USB_DEV_ATTACH: ++ /* Not supporting now */ ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ case USB_DEV_DETACH: ++ /* Not supporting now */ ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ break; ++ default: ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_FIELD; ++ return sizeof(result->completion_code); ++ } ++ ++ result->completion_code = IPMI_CC_OK; ++ result->curr_state = g_fwupd_settings.ctrl_state; ++ return sizeof(struct fwupd_control_res); ++} ++u16 fwupd_get_update_status(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_get_update_status_res *result = ++ (struct fwupd_get_update_status_res *)res; ++ ++ if (req_len != 0) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ result->processing_status = g_fwupd_settings.processing_status; ++ result->percent_completion = g_fwupd_settings.percentage_completion; ++ result->check_status = 0; ++ /* We don't support error code messages cmd(0x0EH) in uboot.*/ ++ result->error_code = 0; ++ ++ result->completion_code = IPMI_CC_OK; ++ ++ return sizeof(struct fwupd_get_update_status_res); ++} ++ ++u16 fwupd_image_write(u8 *req, u16 req_len, u8 *res) ++{ ++ struct fwupd_image_write_res *result = ++ (struct fwupd_image_write_res *)res; ++ ++ if (req_len < 1) { ++ printf("%s(): Invalid request length\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Check is critical operation is going on */ ++ if (g_fwupd_settings.start_update) { ++ printf("%s(): Update in progress.\n", __func__); ++ result->completion_code = IPMI_CC_NODE_BUSY; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!g_fwupd_settings.fwupd_mode_active) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if (!(g_fwupd_settings.ctrl_state & IMG_TRANSFER_CTRL_BIT_START)) { ++ printf("%s(): Invalid request\n", __func__); ++ result->completion_code = IPMI_CC_NOT_SUPPORTED_IN_STATE; ++ return sizeof(result->completion_code); ++ } ++ ++ if ((g_write_addr + req_len) > MAX_FITIMAGE_SIZE) { ++ printf("%s(): Request length exceeded max size\n", __func__); ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ u8 *mem_addr = (u8 *)((u32)IMAGE_LOAD_RAM_ADDR + g_write_addr); ++ ++ memcpy(mem_addr, req, req_len); ++ g_write_addr += req_len; ++ ++ result->completion_code = IPMI_CC_OK; ++ result->no_of_bytes_written = (u8)req_len; ++ ++ return sizeof(struct fwupd_image_write_res); ++} +diff --git a/board/aspeed/ast-g5/ipmi-fwupd.h b/board/aspeed/ast-g5/ipmi-fwupd.h +new file mode 100644 +index 0000000..e490f6b +--- /dev/null ++++ b/board/aspeed/ast-g5/ipmi-fwupd.h +@@ -0,0 +1,81 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 Intel Corporation ++ ++#include "ipmi-handler.h" ++#include "fw-update.h" ++ ++enum control_state { ++ GET_CTRL_STATE = 0, ++ IMG_TRANSFER_START, ++ IMG_TRANSFER_END, ++ IMG_TRANSFER_ABORT, ++ SET_FW_FILENAME, ++ USB_DEV_ATTACH, ++ USB_DEV_DETACH ++}; ++enum control_state_bit { ++ IMG_TRANSFER_CTRL_BIT_START = (0x01 << 0), ++ IMG_TRANSFER_CTRL_BIT_END = (0x01 << 1), ++ IMG_TRANSFER_CTRL_BIT_ABORT = (0x01 << 2), ++ USB_CTRL_BIT_ATTACH = (0x01 << 3) ++}; ++enum update_options_bit { ++ NO_DOWN_REVISION = 0, ++ DEFER_BMC_RESET = 1, ++ SHA32_INTEGRITY_CHECK = 2, ++ CRC32_INTEGRITY_CHECK = 3 ++}; ++ ++struct fwupd_get_exe_ctx_res { ++ u8 completion_code; ++ u8 exection_ctx; ++ u8 patition_ptr; ++}; ++struct fwupd_rand_num_res { ++ u8 completion_code; ++ u8 rand_num[RAND_NUMBER_SIZE]; ++}; ++struct fwupd_set_update_mode_res { ++ u8 completion_code; ++}; ++struct fwupd_exit_update_mode_res { ++ u8 completion_code; ++}; ++struct fwupd_options_req { ++ u8 options_mask; ++ u8 options_value; ++ u8 integrity_check_value[32]; ++}; ++struct fwupd_options_res { ++ u8 completion_code; ++ u8 options_value; ++}; ++struct fwupd_control_req { ++ u8 ctrl_state; ++ u8 filename_len; ++ u8 filename[MAX_FILENAME_LENGTH]; ++}; ++struct fwupd_control_res { ++ u8 completion_code; ++ u8 curr_state; ++}; ++struct fwupd_get_update_status_res { ++ u8 completion_code; ++ u8 processing_status; ++ u8 percent_completion; ++ u8 check_status; ++ u8 error_code; ++}; ++struct fwupd_image_write_res { ++ u8 completion_code; ++ u8 no_of_bytes_written; ++}; ++ ++u16 fwupd_get_execution_ctx(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_get_rand_number(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_enter_update_mode(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_exit_update_mode(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_set_options(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_set_get_control(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_get_update_status(u8 *req, u16 req_len, u8 *res); ++u16 fwupd_image_write(u8 *req, u16 req_len, u8 *res); +diff --git a/board/aspeed/ast-g5/ipmi-handler.c b/board/aspeed/ast-g5/ipmi-handler.c +index 9cccee9..5e78546 100644 +--- a/board/aspeed/ast-g5/ipmi-handler.c ++++ b/board/aspeed/ast-g5/ipmi-handler.c +@@ -1,18 +1,37 @@ +- + // SPDX-License-Identifier: GPL-2.0 + // Copyright (c) 2018-2019 Intel Corporation + +-#include "ipmi-handler.h" ++#include "ipmi-fwupd.h" + + /* IPMI network function codes */ + #define NETFN_APP 0x06 ++#define NETFN_FIRMWARE 0x08 ++#define NETFN_INTEL_OEM 0x30 + + /* IPMI command codes */ +-#define CMD_GET_DEV_ID 0x01 +-#define CMD_GET_SELF_TEST_RESULTS 0x04 ++#define CMD_APP_GET_DEV_ID 0x01 ++#define CMD_APP_GET_SELF_TEST_RESULTS 0x04 ++#define CMD_FWUPD_GET_EXECUTION_CTX 0x23 ++#define CMD_FWUPD_GET_RANDOM_NUMBER 0x26 ++#define CMD_FWUPD_SET_UPDATE_MODE 0x27 ++#define CMD_FWUPD_EXIT_UPDATE_MODE 0x28 ++#define CMD_FWUPD_CONTROL_GET_SET 0x29 ++#define CMD_FWUPD_GET_UPDATE_STATUS 0x2A ++#define CMD_FWUPD_SET_OPTIONS 0x2B ++#define CMD_FWUPD_IMAGE_WRITE 0x2C ++#define CMD_INTL_OEM_GET_BUFFER_SIZE 0x66 ++ ++#define MAX_KCS_BUF_SIZE 1020 /* (0xFF * 4) */ ++#define MAX_IPMB_BUF_SIZE 1020 /* (0xFF * 4) */ + + typedef u16 (*fun_handler)(u8 *req, u16 req_len, u8 *res); + ++struct ipmi_cmd_table { ++ u8 net_fun; ++ u8 cmd; ++ fun_handler process_cmd; ++}; ++ + struct get_dev_id { + u8 completion_code; + u8 dev_id; +@@ -29,11 +48,10 @@ struct self_test_res { + u8 completion_code; + u8 res_byte[2]; + }; +- +-struct ipmi_cmd_table { +- u8 net_fun; +- u8 cmd; +- fun_handler process_cmd; ++struct intc_get_buf_size_res { ++ u8 completion_code; ++ u8 kcs_size; ++ u8 ipmb_size; + }; + + static u16 get_device_id(u8 *req, u16 req_len, u8 *res) +@@ -84,10 +102,36 @@ static u16 get_self_test_result(u8 *req, u16 req_len, u8 *res) + + return sizeof(struct self_test_res); + } ++static u16 intel_get_buffer_size(u8 *req, u16 req_len, u8 *res) ++{ ++ struct intc_get_buf_size_res *result = ++ (struct intc_get_buf_size_res *)res; ++ ++ if (req_len != 0) { ++ result->completion_code = IPMI_CC_INVALID_DATA_LENGTH; ++ return sizeof(result->completion_code); ++ } ++ ++ /* Size is multiples of four bytes */ ++ result->completion_code = IPMI_CC_OK; ++ result->kcs_size = MAX_KCS_BUF_SIZE / 4; ++ result->ipmb_size = MAX_IPMB_BUF_SIZE / 4; ++ ++ return sizeof(struct intc_get_buf_size_res); ++} + + const struct ipmi_cmd_table cmd_info[] = { +- { NETFN_APP, CMD_GET_DEV_ID, get_device_id }, +- { NETFN_APP, CMD_GET_SELF_TEST_RESULTS, get_self_test_result } ++ { NETFN_APP, CMD_APP_GET_DEV_ID, get_device_id }, ++ { NETFN_APP, CMD_APP_GET_SELF_TEST_RESULTS, get_self_test_result }, ++ { NETFN_FIRMWARE, CMD_FWUPD_GET_EXECUTION_CTX, fwupd_get_execution_ctx }, ++ { NETFN_FIRMWARE, CMD_FWUPD_GET_RANDOM_NUMBER, fwupd_get_rand_number }, ++ { NETFN_FIRMWARE, CMD_FWUPD_SET_UPDATE_MODE, fwupd_enter_update_mode }, ++ { NETFN_FIRMWARE, CMD_FWUPD_EXIT_UPDATE_MODE, fwupd_exit_update_mode }, ++ { NETFN_FIRMWARE, CMD_FWUPD_CONTROL_GET_SET, fwupd_set_get_control }, ++ { NETFN_FIRMWARE, CMD_FWUPD_GET_UPDATE_STATUS, fwupd_get_update_status }, ++ { NETFN_FIRMWARE, CMD_FWUPD_SET_OPTIONS, fwupd_set_options }, ++ { NETFN_FIRMWARE, CMD_FWUPD_IMAGE_WRITE, fwupd_image_write }, ++ { NETFN_INTEL_OEM, CMD_INTL_OEM_GET_BUFFER_SIZE, intel_get_buffer_size } + }; + + #define CMD_TABLE_SIZE ARRAY_SIZE(cmd_info) +diff --git a/board/aspeed/ast-g5/ipmi-handler.h b/board/aspeed/ast-g5/ipmi-handler.h +index 9d46d9b..8eea930 100644 +--- a/board/aspeed/ast-g5/ipmi-handler.h ++++ b/board/aspeed/ast-g5/ipmi-handler.h +@@ -1,4 +1,3 @@ +- + /* SPDX-License-Identifier: GPL-2.0 */ + /* Copyright (c) 2018-2019 Intel Corporation */ + +@@ -6,12 +5,14 @@ + + /* IPMI completion codes */ + #define IPMI_CC_OK 0x00 ++#define IPMI_CC_INVALID_CODE 0x80 + #define IPMI_CC_NODE_BUSY 0xC0 + #define IPMI_CC_INVALID_CMD 0xC1 + #define IPMI_CC_INVALID_CMD_LUN 0xC2 + #define IPMI_CC_OUT_OF_SPACE 0xC4 + #define IPMI_CC_INVALID_DATA_LENGTH 0xC7 + #define IPMI_CC_INVALID_DATA_FIELD 0xCC ++#define IPMI_CC_NOT_SUPPORTED_IN_STATE 0xD5 + #define IPMI_CC_UNSPECIFIED 0xFF + + /* BMC IPMB LUNs */ +diff --git a/common/autoboot.c b/common/autoboot.c +index d66c0fa..45a600e 100644 +--- a/common/autoboot.c ++++ b/common/autoboot.c +@@ -349,6 +349,17 @@ void autoboot_command(const char *s) + { + debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); + ++#ifdef AST_G5_INTEL ++ /* TODO: Make run_command_list as non-blocking(blocked by getc()) ++ * and make main u-boot loop to check both keyboard inputs as well ++ * as start_update firmware flags during FFUJ. ++ * This will make sure debug mode intact during FFUJ. ++ */ ++ if (intel_force_firmware_jumper_enabled()) { ++ start_fw_update_loop(); ++ } ++#endif ++ + if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) { + #if defined(CONFIG_AUTOBOOT_KEYED) && !defined(CONFIG_AUTOBOOT_KEYED_CTRLC) + int prev = disable_ctrlc(1); /* disable Control C checking */ +diff --git a/configs/ast_g5_phy_defconfig b/configs/ast_g5_phy_defconfig +index 47d9563..f070494 100644 +--- a/configs/ast_g5_phy_defconfig ++++ b/configs/ast_g5_phy_defconfig +@@ -17,3 +17,4 @@ CONFIG_SYS_NS16550=y + CONFIG_USE_IRQ=y + CONFIG_CMD_I2C=y + CONFIG_SYS_I2C_AST=y ++CONFIG_LIB_RAND=y +-- +2.7.4 + |