meta-ampere: mtmitchell: support Host firmware update

Support Host firmware update for HostFW, EEPROM and FRU via BMC
console and Redfish.

Tested:
1. Flash firmwares via BMC console.
2. Flash firmware via Redfish
3. Get MB CPLD firmware revision
   $ ampere_firmware_version.sh mb_cpld
     MB CPLD
     CPLD Version: 22060268
     CPLD DeviceID: 612BE043

Signed-off-by: Chanh Nguyen <chanh@os.amperecomputing.com>
Change-Id: I1cfbe4832b7d57168e2ea1df0059e23ada1b3b6d
diff --git a/meta-ampere/meta-common/recipes-phosphor/flash/phosphor-software-manager/firmware_update.sh b/meta-ampere/meta-common/recipes-phosphor/flash/phosphor-software-manager/firmware_update.sh
index cc39f30f..c23f250 100755
--- a/meta-ampere/meta-common/recipes-phosphor/flash/phosphor-software-manager/firmware_update.sh
+++ b/meta-ampere/meta-common/recipes-phosphor/flash/phosphor-software-manager/firmware_update.sh
@@ -1,23 +1,4 @@
 #!/bin/bash
-#
-# Copyright (c) 2021 Ampere Computing LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#	http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This script updates the EDKII / SCP firmware.
-# Author : Chanh Nguyen (chnguyen@amperecomputing.com)
-# Date : Sep 7, 2021
-# Modified:
 
 usage () {
 	echo "Usage:"
@@ -73,9 +54,34 @@
 		CMD="/usr/sbin/ampere_firmware_upgrade.sh smpmpro $IMAGE 2"
 		;;
 
-	"fru")
+	"eeprom" | "eeprom-primary")
+		IMAGE=$(find "${IMG_PATH}" -type f \( -name "*.img" -o -name "*.slim" -o -name "*.rom" -o -name "*.bin" \))
+		CMD="/usr/sbin/ampere_firmware_upgrade.sh eeprom $IMAGE 1"
+		;;
+
+	"eeprom-secondary")
+		IMAGE=$(find "${IMG_PATH}" -type f \( -name "*.img" -o -name "*.slim" -o -name "*.rom" -o -name "*.bin" \))
+		CMD="/usr/sbin/ampere_firmware_upgrade.sh eeprom $IMAGE 2"
+		;;
+
+	"fru" | "mbfru")
 		IMAGE=$(find "${IMG_PATH}" -type f \( -name "*.bin" \))
-		CMD="/usr/sbin/ampere_firmware_upgrade.sh fru $IMAGE"
+		CMD="/usr/sbin/ampere_firmware_upgrade.sh fru $IMAGE 1"
+		;;
+
+
+	"bmcfru")
+		IMAGE=$(find "${IMG_PATH}" -type f \( -name "*.bin" \))
+		CMD="/usr/sbin/ampere_firmware_upgrade.sh fru $IMAGE 2"
+		;;
+
+	"mbcpld")
+		IMAGE=$(find "${IMG_PATH}" -type f \( -name "*.jed" \))
+		CMD="/usr/bin/ampere_firmware_upgrade.sh mb_cpld $IMAGE"
+		;;
+	"bmccpld")
+		IMAGE=$(find "${IMG_PATH}" -type f \( -name "*.jed" \))
+		CMD="/usr/bin/ampere_firmware_upgrade.sh bmc_cpld $IMAGE"
 		;;
 
 	*)
diff --git a/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils.bbappend b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils.bbappend
index f325395..341ca13 100644
--- a/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils.bbappend
+++ b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils.bbappend
@@ -4,11 +4,17 @@
 
 SRC_URI:append = " \
            file://ampere_power_util.sh \
+           file://ampere_firmware_upgrade.sh \
+           file://ampere_flash_bios.sh \
            file://ampere_power_on_driver_binder.sh \
+           file://ampere_firmware_version.sh \
           "
 
 do_install:append() {
     install -d ${D}/usr/sbin
     install -m 0755 ${WORKDIR}/ampere_power_util.sh ${D}/${sbindir}/
+    install -m 0755 ${WORKDIR}/ampere_firmware_upgrade.sh ${D}/${sbindir}/
+    install -m 0755 ${WORKDIR}/ampere_flash_bios.sh ${D}/${sbindir}/
     install -m 0755 ${WORKDIR}/ampere_power_on_driver_binder.sh ${D}/${sbindir}/
+    install -m 0755 ${WORKDIR}/ampere_firmware_version.sh ${D}/${sbindir}/
 }
diff --git a/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_firmware_upgrade.sh b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_firmware_upgrade.sh
new file mode 100755
index 0000000..dce6e6c
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_firmware_upgrade.sh
@@ -0,0 +1,201 @@
+#!/bin/bash
+
+# Helper script to flash FRU and Boot EEPROM devices.
+#
+# Syntax for FRU:
+#    ampere_firmware_upgrade.sh fru <image> [<dev>]
+#      dev: 1 for MB FRU (default), 2 for BMC FRU.
+#
+# Syntax for EEPROM:
+#    ampere_firmware_upgrade.sh eeprom <image> [<dev>]
+#      dev: 1 for main Boot EEPROM (default), 2 for secondary Boot EEPROM (if supported)
+#
+# Syntax for Mainboard CPLD:
+#    ampere_firmware_upgrade.sh main_cpld <image>
+#
+# Syntax for BMC CPLD:
+#    ampere_firmware_upgrade.sh bmc_cpld <image>
+#
+# Syntax for Backplane CPLD:
+#    ampere_firmware_upgrade.sh bp_cpld <image> [<target>]
+#      target: 1 for Front Backplane 1
+#              2 for Front Backplane 2
+#              3 for Front Backplane 3
+#              4 for Rear Backplane 1
+#              5 for Rear Backplane 2
+#
+
+# shellcheck disable=SC2046
+
+do_eeprom_flash() {
+	FIRMWARE_IMAGE=$IMAGE
+	BACKUP_SEL=$2
+
+	# Turn off the Host if it is currently ON
+	chassisstate=$(obmcutil chassisstate | awk -F. '{print $NF}')
+	echo "Current Chassis State: $chassisstate"
+	if [ "$chassisstate" == 'On' ];
+	then
+		echo "Turning the Chassis off"
+		obmcutil chassisoff
+		sleep 15
+		# Check if HOST was OFF
+		chassisstate_off=$(obmcutil chassisstate | awk -F. '{print $NF}')
+		if [ "$chassisstate_off" == 'On' ];
+		then
+			echo "Error : Failed turning the Chassis off"
+			exit 1
+		fi
+	fi
+
+	# Switch EEPROM control to BMC AST2600 I2C
+	# BMC_GPIOW6_SPI0_PROGRAM_SEL
+	gpioset $(gpiofind spi0-program-sel)=1
+
+	# BMC_GPIOX0_I2C_BACKUP_SEL (GPIO 184)
+	if [[ $BACKUP_SEL == 1 ]]; then
+		echo "Run update Primary EEPROM"
+		gpioset $(gpiofind i2c-backup-sel)=0
+	elif [[ $BACKUP_SEL == 2 ]]; then
+		echo "Run update Failover EEPROM"
+		gpioset $(gpiofind i2c-backup-sel)=1
+	else
+		echo "Please choose Primary EEPROM (1) or Failover EEPROM (2)"
+		exit 0
+	fi
+
+	# The EEPROM (AT24C64WI) with address 0x50 at BMC_I2C11 bus
+	# Write Firmware to EEPROM and read back for validation
+	ampere_eeprom_prog -b 10 -s 0x50 -p -f "$FIRMWARE_IMAGE"
+
+	# Switch to primary EEPROM
+	gpioset $(gpiofind i2c-backup-sel)=0
+
+	# Switch EEPROM control to CPU HOST
+	gpioset $(gpiofind spi0-program-sel)=0
+
+	if [ "$chassisstate" == 'On' ];
+	then
+		sleep 5
+		echo "Turn on the Host"
+		obmcutil poweron
+	fi
+}
+
+do_fru_flash() {
+	FRU_IMAGE=$1
+	FRU_DEV=$2
+
+	if [[ $FRU_DEV == 1 ]]; then
+		if [ -f /sys/bus/i2c/devices/4-0050/eeprom ]; then
+			FRU_DEVICE="/sys/bus/i2c/devices/4-0050/eeprom"
+		else
+			FRU_DEVICE="/sys/bus/i2c/devices/3-0050/eeprom"
+		fi
+		echo "Flash MB FRU with image $IMAGE at $FRU_DEVICE"
+	elif [[ $FRU_DEV == 2 ]]; then
+		FRU_DEVICE="/sys/bus/i2c/devices/14-0050/eeprom"
+		echo "Flash BMC FRU with image $IMAGE at $FRU_DEVICE"
+	else
+		echo "Please select MB FRU (1) or BMC FRU (2)"
+		exit 0
+	fi
+
+	ampere_fru_upgrade -d "$FRU_DEVICE" -f "$FRU_IMAGE"
+
+	systemctl restart xyz.openbmc_project.FruDevice.service
+	systemctl restart phosphor-ipmi-host.service
+
+	echo "Done"
+}
+
+do_mb_cpld_flash() {
+	MB_CPLD_IMAGE=$1
+	echo "Flashing MB CPLD"
+	gpioset $(gpiofind hpm-fw-recovery)=1
+	gpioset $(gpiofind jtag-program-sel)=1
+	sleep 2
+	ampere_cpldupdate_jtag -t 1 -p "$MB_CPLD_IMAGE"
+	gpioset $(gpiofind hpm-fw-recovery)=0
+	echo "Done"
+}
+
+do_bmc_cpld_flash() {
+	BMC_CPLD_IMAGE=$1
+	echo "Flashing BMC CPLD"
+	gpioset $(gpiofind jtag-program-sel)=0
+	sleep 2
+	ampere_cpldupdate_jtag -t 1 -p "$BMC_CPLD_IMAGE"
+	echo "Done"
+}
+
+do_bp_cpld_flash() {
+	BP_CPLD_IMAGE=$1
+	BP_TARGET=$2
+	if [[ $BP_TARGET == 1 ]]; then
+		echo "Flashing Front Backplane 1 CPLD"
+		ampere_cpldupdate_i2c -b 101 -s 0x40 -t 2 -p "$BP_CPLD_IMAGE"
+	elif [[ $BP_TARGET == 2 ]]; then
+		echo "Flashing Front Backplane 2 CPLD"
+		ampere_cpldupdate_i2c -b 102 -s 0x40 -t 2 -p "$BP_CPLD_IMAGE"
+	elif [[ $BP_TARGET == 3 ]]; then
+		echo "Flashing Front Backplane 3 CPLD"
+		ampere_cpldupdate_i2c -b 100 -s 0x40 -t 2 -p "$BP_CPLD_IMAGE"
+		elif [[ $BP_TARGET == 4 ]]; then
+		echo "Flashing Rear Backplane 1 CPLD"
+		ampere_cpldupdate_i2c -b 103 -s 0x40 -t 2 -p "$BP_CPLD_IMAGE"
+		elif [[ $BP_TARGET == 5 ]]; then
+		echo "Flashing Rear Backplane 2 CPLD"
+		ampere_cpldupdate_i2c -b 104 -s 0x40 -t 2 -p "$BP_CPLD_IMAGE"
+	fi
+
+	echo "Done"
+}
+
+if [ $# -eq 0 ]; then
+	echo "Usage:"
+	echo "  - Flash Boot EEPROM"
+	echo "     $(basename "$0") eeprom <Image file>"
+	echo "  - Flash FRU"
+	echo "     $(basename "$0") fru <Image file> [dev]"
+	echo "    Where:"
+	echo "      dev: 1 - MB FRU, 2 - BMC FRU"
+	echo "  - Flash Mainboard CPLD"
+	echo "     $(basename "$0") mb_cpld <Image file>"
+	echo "  - Flash BMC CPLD (only for DC-SCM BMC board)"
+	echo "     $(basename "$0") bmc_cpld <Image file>"
+	echo "  - Flash Backplane CPLD"
+	echo "     $(basename "$0") bp_cpld <Image file> <Target> "
+	echo "    Where:"
+	echo "      Target: 1 - FrontBP1, 2 - FrontBP2, 3 - FrontBP3"
+	echo "              4 - RearBP1, 5 - RearBP2"
+	exit 0
+fi
+
+TYPE=$1
+IMAGE=$2
+TARGET=$3
+if [ -z "$3" ]; then
+	BACKUP_SEL=1
+else
+	BACKUP_SEL=$3
+fi
+
+if [[ $TYPE == "eeprom" ]]; then
+	# Run EEPROM update: write/read/validation with CRC32 checksum
+	do_eeprom_flash "$IMAGE" "$BACKUP_SEL"
+elif [[ $TYPE == "fru" ]]; then
+	# Run FRU update
+	do_fru_flash "$IMAGE" "$BACKUP_SEL"
+elif [[ $TYPE == "mb_cpld" ]]; then
+	# Run Mainboard CPLD update
+	do_mb_cpld_flash "$IMAGE"
+elif [[ $TYPE == "bmc_cpld" ]]; then
+	# Run CPLD BMC update
+	do_bmc_cpld_flash "$IMAGE"
+elif [[ $TYPE == "bp_cpld" ]]; then
+	# Run Backplane CPLD update
+	do_bp_cpld_flash "$IMAGE" "$TARGET"
+fi
+
+exit 0
diff --git a/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_firmware_version.sh b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_firmware_version.sh
new file mode 100755
index 0000000..081e303
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_firmware_version.sh
@@ -0,0 +1,99 @@
+#!/bin/bash
+
+# Helper script to report firmware version for components on the system (MB CPLD, Backplane CPLD, …)
+# Author : Hieu Huynh (hieu.huynh@amperecomputing.com)
+#
+# Get MB CPLD firmware revision:
+#    ampere_firmware_version.sh mb_cpld
+#
+# Get BMC CPLD firmware revision:
+#    ampere_firmware_version.sh bmc_cpld
+#
+# Get Backplane CPLD firmware revision:
+#    ampere_firmware_version.sh bp_cpld <id>
+#    <id>: 1 for Front Backplane 1
+#          2 for Front Backplane 2
+#          3 for Front Backplane 3
+#          4 for Rear Backplane 1
+#          5 for Rear Backplane 2
+
+# shellcheck disable=SC2046
+
+do_mb_cpld_firmware_report() {
+	echo "MB CPLD"
+	gpioset $(gpiofind hpm-fw-recovery)=1
+	gpioset $(gpiofind jtag-program-sel)=1
+	sleep 1
+	ampere_cpldupdate_jtag -v
+	ampere_cpldupdate_jtag -i
+}
+
+do_bmc_cpld_firmware_report() {
+	echo "BMC CPLD (Only for DC-SCM board)"
+	gpioset $(gpiofind jtag-program-sel)=0
+	sleep 1
+	ampere_cpldupdate_jtag -v
+	ampere_cpldupdate_jtag -i
+}
+
+do_bp_cpld_firmware_report() {
+	BP_ID=$1
+	if [[ $BP_ID == 1 ]]; then
+		echo "Front Backplane 1 CPLD"
+		ampere_cpldupdate_i2c -b 101 -s 0x40 -t 2 -v
+		ampere_cpldupdate_i2c -b 101 -s 0x40 -t 2 -i
+	elif [[ $BP_ID == 2 ]]; then
+		echo "Front Backplane 2 CPLD"
+		ampere_cpldupdate_i2c -b 102 -s 0x40 -t 2 -v
+		ampere_cpldupdate_i2c -b 102 -s 0x40 -t 2 -i
+	elif [[ $BP_ID == 3 ]]; then
+		echo "Front Backplane 3 CPLD"
+		ampere_cpldupdate_i2c -b 100 -s 0x40 -t 2 -v
+		ampere_cpldupdate_i2c -b 100 -s 0x40 -t 2 -i
+	elif [[ $BP_ID == 4 ]]; then
+		echo "Rear Backplane 1 CPLD"
+		ampere_cpldupdate_i2c -b 103 -s 0x40 -t 2 -v
+		ampere_cpldupdate_i2c -b 103 -s 0x40 -t 2 -i
+	elif [[ $BP_ID == 5 ]]; then
+		echo "Rear Backplane 2 CPLD"
+		ampere_cpldupdate_i2c -b 104 -s 0x40 -t 2 -v
+		ampere_cpldupdate_i2c -b 104 -s 0x40 -t 2 -i
+	fi
+}
+
+if [ $# -eq 0 ]; then
+	echo "Usage:"
+	echo "  - Get MB CPLD firmware revision"
+	echo "     $(basename "$0") mb_cpld"
+	echo "  - Get BMC CPLD firmware revision"
+	echo "     $(basename "$0") bmc_cpld"
+	echo "  - Get Backplane CPLD firmware revision"
+	echo "     $(basename "$0") bp_cpld <id>"
+	echo "    <id>:"
+	echo "        1 - FrontBP1"
+	echo "        2 - FrontBP2"
+	echo "        3 - FrontBP3"
+	echo "        4 - RearBP1"
+	echo "        5 - RearBP2"
+	exit 0
+fi
+
+TYPE=$1
+ID=$2
+
+if [[ $TYPE == "mb_cpld" ]]; then
+	do_mb_cpld_firmware_report
+elif [[ $TYPE == "bmc_cpld" ]]; then
+	do_bmc_cpld_firmware_report
+elif [[ $TYPE == "bp_cpld" ]]; then
+	if [ -z "$ID" ]; then
+		echo "Please choose backplanes id: 1 - FrontBP1, 2 - FrontBP2, 3 - FrontBP3, 4 - FrontBP4, 5 - FrontBP5"
+		exit 0
+	elif [[ "$ID" -ge "1" ]] && [[ "$ID" -le "5" ]]; then
+		do_bp_cpld_firmware_report "$ID"
+	else
+		echo "Backplanes id invalid"
+	fi
+fi
+
+exit 0
diff --git a/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_flash_bios.sh b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_flash_bios.sh
new file mode 100755
index 0000000..0e0c18c
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_flash_bios.sh
@@ -0,0 +1,126 @@
+#!/bin/bash
+
+# This script is used to flash the UEFI/EDKII
+
+# Syntax: ampere_flash_bios.sh $image_file $device_sellect
+# Where:
+#       $image_file : the image binary file
+#       $device_sellect : 1 - Host Main SPI Nor
+#                         2 - Host Second SPI Nor
+
+# Author : Chanh Nguyen (chnguyen@amperecomputing.com)
+
+# Note:
+#      BMC_GPIOW6_SPI0_PROGRAM_SEL (GPIO 182): 1 => BMC owns SPI bus for upgrading
+#                                              0 => HOST owns SPI bus for upgrading
+
+#      BMC_GPIOW7_SPI0_BACKUP_SEL (GPIO 183) :  1 => to switch SPI_CS0_L to primary SPI Nor device
+#                                               0 => to switch SPI_CS0_L to second SPI Nor device
+
+# shellcheck disable=SC2046
+
+do_flash () {
+	# Check the HNOR partition available
+	HOST_MTD=$(< /proc/mtd grep "pnor" | sed -n 's/^\(.*\):.*/\1/p')
+	if [ -z "$HOST_MTD" ];
+	then
+		# Check the ASpeed SMC driver binded before
+		HOST_SPI=/sys/bus/platform/drivers/spi-aspeed-smc/1e630000.spi
+		if [ -d "$HOST_SPI" ]; then
+			echo "Unbind the ASpeed SMC driver"
+			echo 1e630000.spi > /sys/bus/platform/drivers/spi-aspeed-smc/unbind
+			sleep 2
+		fi
+
+		# If the HNOR partition is not available, then bind again driver
+		echo "--- Bind the ASpeed SMC driver"
+		echo 1e630000.spi > /sys/bus/platform/drivers/spi-aspeed-smc/bind
+		sleep 2
+
+		HOST_MTD=$(< /proc/mtd grep "pnor" | sed -n 's/^\(.*\):.*/\1/p')
+		if [ -z "$HOST_MTD" ];
+		then
+			echo "Fail to probe Host SPI-NOR device"
+			exit 1
+		fi
+	fi
+
+	echo "--- Flashing firmware image $IMAGE to @/dev/$HOST_MTD"
+	flashcp -v "$IMAGE" /dev/"$HOST_MTD"
+}
+
+
+if [ $# -eq 0 ]; then
+	echo "Usage: $(basename "$0") <UEFI/EDKII image file>"
+	exit 0
+fi
+
+IMAGE="$1"
+if [ ! -f "$IMAGE" ]; then
+	echo "The image file $IMAGE does not exist"
+	exit 1
+fi
+
+if [ -z "$2" ]; then
+       DEV_SEL="1"    # by default, select primary device
+else
+       DEV_SEL="$2"
+fi
+
+# Turn off the Host if it is currently ON
+chassisstate=$(obmcutil chassisstate | awk -F. '{print $NF}')
+echo "--- Current Chassis State: $chassisstate"
+if [ "$chassisstate" == 'On' ];
+then
+	echo "--- Turning the Chassis off"
+	obmcutil chassisoff
+	sleep 10
+	# Check if HOST was OFF
+	chassisstate_off=$(obmcutil chassisstate | awk -F. '{print $NF}')
+	if [ "$chassisstate_off" == 'On' ];
+	then
+		echo "--- Error : Failed turning the Chassis off"
+		exit 1
+	fi
+fi
+
+# Switch the host SPI bus to BMC"
+echo "--- Switch the host SPI bus to BMC."
+if ! gpioset $(gpiofind spi0-program-sel)=1; then
+	echo "ERROR: Switch the host SPI bus to BMC. Please check gpio state"
+	exit 1
+fi
+
+# Switch the host SPI bus (between primary and secondary)
+# 183 is BMC_GPIOW7_SPI0_BACKUP_SEL
+if [[ $DEV_SEL == 1 ]]; then
+	echo "Run update Primary Host SPI-NOR"
+	gpioset $(gpiofind spi0-backup-sel)=1       # Primary SPI
+elif [[ $DEV_SEL == 2 ]]; then
+	echo "Run update Second Host SPI-NOR"
+	gpioset $(gpiofind spi0-backup-sel)=0       # Second SPI
+else
+	echo "Please choose primary SPI (1) or second SPI (2)"
+	exit 0
+fi
+
+# Flash the firmware
+do_flash
+
+# Switch the SPI bus to the primary spi device
+echo "Switch to the Primary Host SPI-NOR"
+gpioset $(gpiofind spi0-backup-sel)=1       # Primary SPI
+
+# Switch the host SPI bus to HOST."
+echo "--- Switch the host SPI bus to HOST."
+if ! gpioset $(gpiofind spi0-program-sel)=0; then
+	echo "ERROR: Switch the host SPI bus to HOST. Please check gpio state"
+	exit 1
+fi
+
+if [ "$chassisstate" == 'On' ];
+then
+	sleep 5
+	echo "Turn on the Host"
+	obmcutil poweron
+fi