diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files')
6 files changed, 1301 insertions, 199 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch deleted file mode 100644 index cc1e56fdb..000000000 --- a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0016-Add-support-for-128MB-Macronix-spi-flash-MX66L1G45G.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 8992df8f3a0f5fc16ec41ad6dd7a5a13e6f94d32 Mon Sep 17 00:00:00 2001 -From: Vernon Mauery <vernon.mauery@linux.intel.com> -Date: Wed, 5 Dec 2018 16:13:15 -0800 -Subject: [PATCH] Add support for 128MB Macronix spi flash MX66L1G45G - -This will enable u-boot support for the Macronix MX66L1G45G part. - -Change-Id: I5edc69357a8b1607c5c44e53bed3eddf38fdc0be -Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com> ---- - drivers/mtd/spi/sf_params.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c -index c577d9ed6c..d2a96efe48 100644 ---- a/drivers/mtd/spi/sf_params.c -+++ b/drivers/mtd/spi/sf_params.c -@@ -50,6 +50,7 @@ const struct spi_flash_params spi_flash_params_table[] = { - {"MX25L12805", 0xc22018, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, - {"MX25L25635F", 0xc22019, 0x0, 64 * 1024, 512, RD_FULL, WR_QPP}, - {"MX25L51235F", 0xc2201a, 0x0, 64 * 1024, 1024, RD_FULL, WR_QPP}, -+ {"MX66L1G45G", 0xc2201b, 0x0, 64 * 1024, 2048, RD_FULL, SECT_4K|WR_QPP}, - {"MX25L12855E", 0xc22618, 0x0, 64 * 1024, 256, RD_FULL, WR_QPP}, - #endif - #ifdef CONFIG_SPI_FLASH_SPANSION /* SPANSION */ --- -2.17.1 - diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0017-Enable-Macronix-and-Micron-SPI-support.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0017-Enable-Macronix-and-Micron-SPI-support.patch deleted file mode 100644 index b26803c95..000000000 --- a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0017-Enable-Macronix-and-Micron-SPI-support.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 8415002a2e77a41831b3064dae264f60996ac88a Mon Sep 17 00:00:00 2001 -From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> -Date: Thu, 6 Dec 2018 15:07:09 -0800 -Subject: [PATCH] Enable Macronix and Micron SPI support - -This commit enables Macronix and Micron SPI support. - -Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> ---- - configs/ast_g5_ncsi_2boot_defconfig | 2 ++ - configs/ast_g5_ncsi_defconfig | 2 ++ - configs/ast_g5_phy_defconfig | 2 ++ - 3 files changed, 6 insertions(+) - -diff --git a/configs/ast_g5_ncsi_2boot_defconfig b/configs/ast_g5_ncsi_2boot_defconfig -index d5b7894a9e00..abceed817615 100644 ---- a/configs/ast_g5_ncsi_2boot_defconfig -+++ b/configs/ast_g5_ncsi_2boot_defconfig -@@ -10,6 +10,8 @@ CONFIG_FIT_VERBOSE=y - CONFIG_HUSH_PARSER=y - CONFIG_OF_LIBFDT=y - CONFIG_SPI_FLASH=y -+CONFIG_SPI_FLASH_MACRONIX=y -+CONFIG_SPI_FLASH_STMICRO=y - CONFIG_SYS_NS16550=y - CONFIG_FIRMWARE_2ND_BOOT=y - CONFIG_AUTOBOOT=y -diff --git a/configs/ast_g5_ncsi_defconfig b/configs/ast_g5_ncsi_defconfig -index 9481e5fb6e9d..3f504a325649 100644 ---- a/configs/ast_g5_ncsi_defconfig -+++ b/configs/ast_g5_ncsi_defconfig -@@ -10,5 +10,7 @@ CONFIG_FIT_VERBOSE=y - CONFIG_HUSH_PARSER=y - CONFIG_OF_LIBFDT=y - CONFIG_SPI_FLASH=y -+CONFIG_SPI_FLASH_MACRONIX=y -+CONFIG_SPI_FLASH_STMICRO=y - CONFIG_SYS_NS16550=y - CONFIG_USE_IRQ=y -diff --git a/configs/ast_g5_phy_defconfig b/configs/ast_g5_phy_defconfig -index 4aefcf49e880..8f0919043376 100644 ---- a/configs/ast_g5_phy_defconfig -+++ b/configs/ast_g5_phy_defconfig -@@ -11,5 +11,7 @@ CONFIG_FIT_VERBOSE=y - CONFIG_HUSH_PARSER=y - CONFIG_OF_LIBFDT=y - CONFIG_SPI_FLASH=y -+CONFIG_SPI_FLASH_MACRONIX=y -+CONFIG_SPI_FLASH_STMICRO=y - CONFIG_SYS_NS16550=y - CONFIG_USE_IRQ=y --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch deleted file mode 100644 index 2ed297a96..000000000 --- a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0018-Add-support-for-Macronix-and-Micron-1Gbits-SPI-flash.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 0039c15251a7fcf60154d59933a11d9e17b04d5c Mon Sep 17 00:00:00 2001 -From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> -Date: Thu, 6 Dec 2018 18:49:04 -0800 -Subject: [PATCH] Add support for Macronix and Micron 1Gbits SPI flash - -Quick fix to support Macronix and Micron 1Gbits SPI. - -Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> ---- - arch/arm/mach-aspeed/flash.c | 33 ++++++++++++++++++++++++++++++++- - 1 file changed, 32 insertions(+), 1 deletion(-) - -diff --git a/arch/arm/mach-aspeed/flash.c b/arch/arm/mach-aspeed/flash.c -index dece4315d755..2a31b6503a22 100644 ---- a/arch/arm/mach-aspeed/flash.c -+++ b/arch/arm/mach-aspeed/flash.c -@@ -79,6 +79,7 @@ flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* FLASH chips info */ - #define MX25L12805D 0x1820C2 - #define MX25L25635E 0x1920C2 - #define MX66L51235F 0x1A20C2 -+#define MX66L1G45G 0x1B20C2 - #define SST25VF016B 0x4125bf - #define SST25VF064C 0x4b25bf - #define SST25VF040B 0x8d25bf -@@ -978,6 +979,35 @@ static ulong flash_get_size (ulong base, flash_info_t *info) - #endif - break; - -+ case MX66L1G45G: -+ erase_region_size = 0x10000; -+ info->readcmd = 0x0b; -+ info->dualport = 0; -+ info->dummybyte = 1; -+ info->buffersize = 256; -+ WriteClk = 50; -+ EraseClk = 20; -+ ReadClk = 50; -+#if 1 -+ info->sector_count = 2048; -+ info->size = 0x4000000; -+ info->address32 = 1; -+#if defined(CONFIG_FLASH_SPIx2_Dummy) -+ info->readcmd = 0xbb; -+ info->dummybyte = 1; -+ info->dualport = 1; -+ info->iomode = IOMODEx2_dummy; -+#elif defined(CONFIG_FLASH_SPIx4_Dummy) -+ info->readcmd = 0xeb; -+ info->dummybyte = 3; -+ info->dualport = 0; -+ info->iomode = IOMODEx4_dummy; -+ info->quadport = 1; -+ info->dummydata = 0xaa; -+#endif -+#endif -+ break; -+ - case MX25L12805D: - info->sector_count = 256; - info->size = 0x1000000; -@@ -1093,7 +1123,8 @@ static ulong flash_get_size (ulong base, flash_info_t *info) - info->readcmd = 0x0b; - info->dualport = 0; - info->dummybyte = 1; -- info->buffersize = 1; -+ info->buffersize = 256; -+ info->address32 = 1; - WriteClk = 50; - EraseClk = 25; - ReadClk = 50; --- -2.7.4 - diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-KCS-driver-support-in-uBoot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-KCS-driver-support-in-uBoot.patch index 79028d2a1..c79b2f2dc 100644 --- a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-KCS-driver-support-in-uBoot.patch +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0022-KCS-driver-support-in-uBoot.patch @@ -1,4 +1,4 @@ -From 16209364c27a0cb7e2b7fdd445942f68e9180263 Mon Sep 17 00:00:00 2001 +From b11377c73c85bdee1975402084c3760b70cc99c4 Mon Sep 17 00:00:00 2001 From: AppaRao Puli <apparao.puli@linux.intel.com> Date: Wed, 13 Mar 2019 14:28:05 +0530 Subject: [PATCH] KCS driver support in uBoot @@ -28,9 +28,9 @@ Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> --- board/aspeed/ast-g5/Makefile | 1 + board/aspeed/ast-g5/ast-g5-intel.c | 3 + - board/aspeed/ast-g5/ast-g5-kcs.c | 425 +++++++++++++++++++++++++++++++++++++ - board/aspeed/ast-g5/ast-g5-kcs.h | 114 ++++++++++ - 4 files changed, 543 insertions(+) + board/aspeed/ast-g5/ast-g5-kcs.c | 420 +++++++++++++++++++++++++++++++++++++ + board/aspeed/ast-g5/ast-g5-kcs.h | 112 ++++++++++ + 4 files changed, 536 insertions(+) create mode 100644 board/aspeed/ast-g5/ast-g5-kcs.c create mode 100644 board/aspeed/ast-g5/ast-g5-kcs.h @@ -44,7 +44,7 @@ index 9022433..05972b9 100644 obj-y += ast-g5-timer.o +obj-y += ast-g5-kcs.o diff --git a/board/aspeed/ast-g5/ast-g5-intel.c b/board/aspeed/ast-g5/ast-g5-intel.c -index f810a40..f9955c7 100644 +index 409b1a7..41d41ea 100644 --- a/board/aspeed/ast-g5/ast-g5-intel.c +++ b/board/aspeed/ast-g5/ast-g5-intel.c @@ -437,6 +437,7 @@ static void pwm_init(void) @@ -66,16 +66,15 @@ index f810a40..f9955c7 100644 } diff --git a/board/aspeed/ast-g5/ast-g5-kcs.c b/board/aspeed/ast-g5/ast-g5-kcs.c new file mode 100644 -index 0000000..f983b4a +index 0000000..7bff26f --- /dev/null +++ b/board/aspeed/ast-g5/ast-g5-kcs.c -@@ -0,0 +1,425 @@ +@@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018-2019 Intel Corporation + +#include "ast-g5-kcs.h" + -+#define DEBUG_KCS_ENABLED 0 +#ifdef DEBUG_KCS_ENABLED +#define DBG_KCS printf +#else @@ -139,7 +138,7 @@ index 0000000..f983b4a + } + + /* very unlike code hits here. */ -+ printf("ERROR: %s error. ChannelNo: %d\n", __func__, channel_num); ++ DBG_KCS("ERROR: %s error. ChannelNo: %d\n", __func__, channel_num); + BUG(); +} + @@ -148,7 +147,7 @@ index 0000000..f983b4a + struct kcs_packet *kcs_pkt = NULL; + + kcs_pkt = get_kcs_packet(channel_num); -+ printf("ERROR: KCS communication aborted (Channel:%d, Error:%d)\n", ++ DBG_KCS("ERROR: KCS communication aborted (Channel:%d, Error:%d)\n", + channel_num, kcs_pkt->error); + set_kcs_state(channel_num, KCS_STATE_ERROR); + read_data(channel_num); @@ -176,6 +175,7 @@ index 0000000..f983b4a +static void process_kcs_request(u16 channel_num) +{ + struct kcs_packet *kcs_pkt = NULL; ++ int i; + + kcs_pkt = get_kcs_packet(channel_num); + if (!kcs_pkt->read_req_done) @@ -184,8 +184,6 @@ index 0000000..f983b4a + DBG_KCS("%s:- chan:%d\n", __func__, channel_num); + +#ifdef DEBUG_KCS_ENABLED -+ int i; -+ + DBG_KCS("Request data(Len:%d): ", kcs_pkt->data_in_idx); + for (i = 0; i < kcs_pkt->data_in_idx; i++) + DBG_KCS(" 0x%02x", kcs_pkt->data_in[i]); @@ -240,8 +238,6 @@ index 0000000..f983b4a + struct kcs_packet *kcs_pkt = NULL; + + kcs_pkt = get_kcs_packet(channel_num); -+ DBG_KCS("%s:- chan:%d, kcs_pkt->phase:%d\n", __func__, channel_num, -+ kcs_pkt->phase); + + switch (kcs_pkt->phase) { + case KCS_PHASE_WRITE_START: @@ -326,7 +322,6 @@ index 0000000..f983b4a + write_data(channel_num, ZERO_DATA); + + u16 cmd = read_data(channel_num); -+ DBG_KCS("%s:- chan:%d, cmd:0x%02x\n", __func__, channel_num, cmd); + switch (cmd) { + case KCS_CTRL_CODE_WRITE_START: + init_kcs_packet(channel_num); @@ -497,10 +492,10 @@ index 0000000..f983b4a +} diff --git a/board/aspeed/ast-g5/ast-g5-kcs.h b/board/aspeed/ast-g5/ast-g5-kcs.h new file mode 100644 -index 0000000..52b5097 +index 0000000..bb697c4 --- /dev/null +++ b/board/aspeed/ast-g5/ast-g5-kcs.h -@@ -0,0 +1,114 @@ +@@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2018-2019 Intel Corporation */ + @@ -515,8 +510,8 @@ index 0000000..52b5097 +/* KCS channel addresses */ +#define KCS_CHANNEL1_ADDR 0xCA0 +#define KCS_CHANNEL2_ADDR 0xCA8 -+#define KCS_CHANNEL3_ADDR 0xCA2 -+#define KCS_CHANNEL4_ADDR 0xCB2 ++#define KCS_CHANNEL3_ADDR 0xCA2 /* KCS SMS */ ++#define KCS_CHANNEL4_ADDR 0xCA4 /* KCS SMM */ + +#define ZERO_DATA 0x00 + @@ -539,6 +534,11 @@ index 0000000..52b5097 +#define LPC_STR1 0x3C /* Status Register 1 */ +#define LPC_STR2 0x40 /* Status Register 2 */ +#define LPC_STR3 0x44 /* Status Register 3 */ ++#define LPC_HICRB 0x100 /* Host Interface Control Register B */ ++#define LPC_LADR4 0x110 /* LPC channel #4 Address Register */ ++#define LPC_IDR4 0x114 /* Input Data Register 4 */ ++#define LPC_ODR4 0x118 /* Output Data Register 4 */ ++#define LPC_STR4 0x11C /* Status Data Register 4 */ + +/* LPC Bits */ +#define BIT_LADR12AS BIT(7) /* Channel Address selection */ @@ -549,15 +549,8 @@ index 0000000..52b5097 +#define BIT_LPC2E BIT(6) /* Enable LPC channel #2 */ +#define BIT_LPC3E BIT(7) /* Enable LPC channel #2 */ +#define BIT_KCSENBL BIT(2) /* Enable KCS interface in Channel #3 */ -+ -+/* mapped to lpc-host@80 IO space */ -+#define LPC_HICRB 0x080 +#define BIT_IBFIE4 BIT(1) +#define BIT_LPC4E BIT(0) -+#define LPC_LADR4 0x090 -+#define LPC_IDR4 0x094 /* Input Data Register 4 */ -+#define LPC_ODR4 0x098 /* Output Data Register 4 */ -+#define LPC_STR4 0x09c /* Status Data Register 4 */ + +#define BIT_STATUS_OBF BIT(0) /* Output Data Register full #1/#2/#3 */ +#define BIT_STATUS_IBF BIT(1) /* Input Data Register full #1/#2/#3 */ diff --git a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch index 47cb56062..9096b09b2 100644 --- a/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch +++ b/meta-openbmc-mods/meta-common/recipes-bsp/u-boot/files/0024-IPMI-command-handler-implementation-in-uboot.patch @@ -1,6 +1,6 @@ -From d770ea7a30742339b0692858847838dd2a738aeb Mon Sep 17 00:00:00 2001 +From 50d3a7264fc0ecdd61ae1686839b19091b124e8d Mon Sep 17 00:00:00 2001 From: AppaRao Puli <apparao.puli@linux.intel.com> -Date: Fri, 5 Apr 2019 17:53:21 +0530 +Date: Tue, 21 May 2019 00:19:16 +0530 Subject: [PATCH] IPMI command handler implementation in uboot IPMI command handler implemtation in uBoot. @@ -22,10 +22,10 @@ Change-Id: I18b205bc45c34f7c4ef16adc29fa5bd494624ceb Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> --- board/aspeed/ast-g5/Makefile | 1 + - board/aspeed/ast-g5/ast-g5-kcs.c | 78 +++++++++++++----------- + board/aspeed/ast-g5/ast-g5-kcs.c | 77 +++++++++++++----------- board/aspeed/ast-g5/ipmi-handler.c | 118 +++++++++++++++++++++++++++++++++++++ board/aspeed/ast-g5/ipmi-handler.h | 40 +++++++++++++ - 4 files changed, 202 insertions(+), 35 deletions(-) + 4 files changed, 202 insertions(+), 34 deletions(-) create mode 100644 board/aspeed/ast-g5/ipmi-handler.c create mode 100644 board/aspeed/ast-g5/ipmi-handler.h @@ -39,7 +39,7 @@ index 05972b9..f28fcfe 100644 obj-y += ast-g5-kcs.o +obj-y += ipmi-handler.o diff --git a/board/aspeed/ast-g5/ast-g5-kcs.c b/board/aspeed/ast-g5/ast-g5-kcs.c -index f983b4a..05b1cc2 100644 +index 7bff26f..98bf69b 100644 --- a/board/aspeed/ast-g5/ast-g5-kcs.c +++ b/board/aspeed/ast-g5/ast-g5-kcs.c @@ -1,7 +1,7 @@ @@ -49,9 +49,9 @@ index f983b4a..05b1cc2 100644 -#include "ast-g5-kcs.h" +#include "ipmi-handler.h" - #define DEBUG_KCS_ENABLED 0 #ifdef DEBUG_KCS_ENABLED -@@ -10,11 +10,6 @@ + #define DBG_KCS printf +@@ -9,11 +9,6 @@ #define DBG_KCS(...) #endif @@ -63,22 +63,15 @@ index f983b4a..05b1cc2 100644 #define KCS_CHANNEL_NO_3 3 static const u16 enabled_kcs_channel[] = { KCS_CHANNEL_NO_3 }; -@@ -104,13 +99,13 @@ static void init_kcs_packet(u16 channel_num) +@@ -103,6 +98,7 @@ static void init_kcs_packet(u16 channel_num) static void process_kcs_request(u16 channel_num) { struct kcs_packet *kcs_pkt = NULL; + struct ipmi_cmd_data ipmi_data; - - kcs_pkt = get_kcs_packet(channel_num); - if (!kcs_pkt->read_req_done) - return; - - DBG_KCS("%s:- chan:%d\n", __func__, channel_num); -- - #ifdef DEBUG_KCS_ENABLED int i; -@@ -119,37 +114,49 @@ static void process_kcs_request(u16 channel_num) + kcs_pkt = get_kcs_packet(channel_num); +@@ -117,37 +113,49 @@ static void process_kcs_request(u16 channel_num) DBG_KCS(" 0x%02x", kcs_pkt->data_in[i]); DBG_KCS("\n"); #endif @@ -156,7 +149,7 @@ index f983b4a..05b1cc2 100644 #ifdef DEBUG_KCS_ENABLED DBG_KCS("Response data(Len:%d): ", kcs_pkt->data_out_len); -@@ -158,6 +165,7 @@ static void process_kcs_request(u16 channel_num) +@@ -156,6 +164,7 @@ static void process_kcs_request(u16 channel_num) DBG_KCS("\n"); #endif 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 + |