summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch')
-rw-r--r--meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch1271
1 files changed, 1271 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch b/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch
new file mode 100644
index 000000000..238630af6
--- /dev/null
+++ b/meta-openbmc-mods/meta-ast2500/recipes-bsp/u-boot/files/0029-FFUJ-FW-IPMI-commands-and-flash-support-in-u-boot.patch
@@ -0,0 +1,1271 @@
+From 61587868bf9979dd8308f12157310949f0e5c430 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:
+ - Tested the individual commands implementation and negative
+ cases.
+ - Used debug tool for validating Firmware image transfer via
+ KCS and flashing.
+
+Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
+
+---
+ .../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 | 13 +
+ configs/ast_g5_phy_defconfig | 1 +
+ 10 files changed, 1093 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 cd9a0994fa..a88521a1b3 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 f28fcfe61c..0b2d936c23 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 0000000000..99239938b5
+--- /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 0000000000..ed033adfed
+--- /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 0000000000..3eba056e7f
+--- /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 0000000000..e490f6b527
+--- /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 9cccee9f2f..5e78546e70 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 9d46d9bd9a..8eea93063a 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 d66c0fa63a..3647d5fb21 100644
+--- a/common/autoboot.c
++++ b/common/autoboot.c
+@@ -349,6 +349,19 @@ 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()) {
++ printf("#### Force firmware update mode is enabled, "
++ "Serial console is disabled. ####\n");
++ 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 1b96ab7f3b..5965a9b04f 100644
+--- a/configs/ast_g5_phy_defconfig
++++ b/configs/ast_g5_phy_defconfig
+@@ -15,3 +15,4 @@ CONFIG_SYS_NS16550=y
+ CONFIG_USE_IRQ=y
+ CONFIG_CMD_I2C=y
+ CONFIG_SYS_I2C_AST=y
++CONFIG_LIB_RAND=y