meta-ampere: mtmitchell: add some helper utils

Add some help scripts to help users easier to debug systems from BMC
console.

Tested:
1. New helper scripts are available from BMC console.
2. Manually check script execution

Signed-off-by: Thang Q. Nguyen <thang@os.amperecomputing.com>
Change-Id: Ibe93547d1299768ae8d67440f161c86c29dbb61e
diff --git a/meta-ampere/meta-common/recipes-ampere/platform/ampere-utils.bb b/meta-ampere/meta-common/recipes-ampere/platform/ampere-utils.bb
index c0ae7bd..7c71b95 100644
--- a/meta-ampere/meta-common/recipes-ampere/platform/ampere-utils.bb
+++ b/meta-ampere/meta-common/recipes-ampere/platform/ampere-utils.bb
@@ -7,6 +7,8 @@
 SRC_URI = " \
            file://ampere_add_redfishevent.sh \
            file://ampere_update_mac.sh \
+           file://ampere_spi_util.sh \
+           file://ampere_power_control_lock.sh \
           "
 
 RDEPENDS:${PN} = "bash"
@@ -15,4 +17,6 @@
     install -d ${D}/usr/sbin
     install -m 0755 ${WORKDIR}/ampere_add_redfishevent.sh ${D}/${sbindir}/
     install -m 0755 ${WORKDIR}/ampere_update_mac.sh ${D}/${sbindir}/
+    install -m 0755 ${WORKDIR}/ampere_spi_util.sh ${D}/${sbindir}/
+    install -m 0755 ${WORKDIR}/ampere_power_control_lock.sh ${D}/${sbindir}/
 }
diff --git a/meta-ampere/meta-common/recipes-ampere/platform/ampere-utils/ampere_power_control_lock.sh b/meta-ampere/meta-common/recipes-ampere/platform/ampere-utils/ampere_power_control_lock.sh
new file mode 100644
index 0000000..db78c43
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ampere/platform/ampere-utils/ampere_power_control_lock.sh
@@ -0,0 +1,99 @@
+#!/bin/bash
+
+declare -a power_reboot_targets=(
+				 obmc-host-reboot@0.target
+				 obmc-host-warm-reboot@0.target
+				 obmc-host-force-warm-reboot@0.target
+				)
+
+declare -a power_off_targets=(
+			      obmc-chassis-hard-poweroff@0.target
+			     )
+
+declare -a power_on_targets=(
+			     obmc-host-start@0.target
+			    )
+
+systemd1_service="org.freedesktop.systemd1"
+systemd1_object_path="/org/freedesktop/systemd1"
+systemd1_manager_interface="org.freedesktop.systemd1.Manager"
+mask_method="MaskUnitFiles"
+unmask_method="UnmaskUnitFiles"
+
+function mask_reboot_targets()
+{
+	# To prevent reboot actions, this function will mask all reboot targets
+	for target in "${power_reboot_targets[@]}"
+	do
+		busctl call $systemd1_service $systemd1_object_path $systemd1_manager_interface \
+			$mask_method asbb 1 "$target" true true
+	done
+}
+
+function unmask_reboot_targets()
+{
+	# Allow reboot targets work normal
+	for target in "${power_reboot_targets[@]}"
+	do
+		busctl call $systemd1_service $systemd1_object_path $systemd1_manager_interface \
+			$unmask_method asb 1 "$target" true
+	done
+}
+
+function mask_off_targets()
+{
+	# To prevent off actions,this function will mask all off targets
+	for target in "${power_off_targets[@]}"
+	do
+		busctl call $systemd1_service $systemd1_object_path $systemd1_manager_interface \
+			$mask_method asbb 1 "$target" true true
+	done
+}
+
+function unmask_off_targets()
+{
+	# Allow off targets work normal
+	for target in "${power_off_targets[@]}"
+	do
+		busctl call $systemd1_service $systemd1_object_path $systemd1_manager_interface \
+			$unmask_method asb 1 "$target" true
+	done
+}
+
+function mask_on_targets()
+{
+	# To prevent on actions, this function will mask all on targets
+	systemctl mask "${power_on_targets[@]}" --runtime
+}
+
+function unmask_on_targets()
+{
+	# Allow on targets work normal
+	systemctl unmask "${power_on_targets[@]}" --runtime
+}
+
+purpose=$1
+allow=$2
+
+if [ "$purpose" == "reboot" ]; then
+	if [ "$allow" == "false" ]
+	then
+		mask_reboot_targets
+	else
+		unmask_reboot_targets
+	fi
+elif [ "$purpose" == "off" ]; then
+	if [ "$allow" == "false" ]
+	then
+		mask_off_targets
+	else
+		unmask_off_targets
+	fi
+elif [ "$purpose" == "on" ]; then
+	if [ "$allow" == "false" ]
+	then
+		mask_on_targets
+	else
+		unmask_on_targets
+	fi
+fi
diff --git a/meta-ampere/meta-common/recipes-ampere/platform/ampere-utils/ampere_spi_util.sh b/meta-ampere/meta-common/recipes-ampere/platform/ampere-utils/ampere_spi_util.sh
new file mode 100755
index 0000000..ad3df4e
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ampere/platform/ampere-utils/ampere_spi_util.sh
@@ -0,0 +1,242 @@
+#!/bin/bash
+
+# shellcheck disable=SC2046
+# shellcheck source=meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-platform-init/gpio-lib.sh
+source /usr/sbin/gpio-lib.sh
+
+spi_address="1e630000.spi"
+spi_bind="/sys/bus/platform/drivers/spi-aspeed-smc/bind"
+spi_unbind="/sys/bus/platform/drivers/spi-aspeed-smc/unbind"
+spi_lock="/run/platform/spi.lock"
+spi_lock_dir="/run/platform"
+
+bind_aspeed_smc_driver() {
+	if [ -f "${spi_lock}" ]; then
+		pid=$1
+		pid_lock=$(cat "${spi_lock}")
+		if [[ "${pid}" != "${pid_lock}" ]]; then
+			echo "SPI-NOR resoure is lock by process $pid_lock"
+			return 1
+		fi
+	fi
+
+	# BMC access SPI-NOR resource
+	gpio_name_set spi0-program-sel 1
+	sleep 0.1
+	echo "Bind the ASpeed SMC driver"
+	echo "${spi_address}" > "${spi_bind}"  2>/dev/null
+	# Check the HNOR partition available
+	HOST_MTD=$(< /proc/mtd grep "pnor" | sed -n 's/^\(.*\):.*/\1/p')
+	if [ -z "$HOST_MTD" ]; then
+		echo "${spi_address}" > "${spi_unbind}"
+		sleep 0.1
+		echo "${spi_address}" > "${spi_bind}"
+	fi
+	# BMC release SPI-NOR resource
+	gpio_name_set spi0-program-sel 0
+	return 0
+}
+
+unbind_aspeed_smc_driver() {
+	if [ -f "${spi_lock}" ]; then
+		pid=$1
+		pid_lock=$(cat "${spi_lock}")
+		if [[ "${pid}" != "${pid_lock}" ]]; then
+			echo "SPI-NOR resoure is lock by process $pid_lock . Wait 10s"
+			# Wait maximum 10 seconds for unlock SPI-NOR
+			cnt=10
+			while [ $cnt -gt 0 ]
+			do
+				if [ -f "${spi_lock}" ]; then
+					sleep 1
+					cnt=$((cnt - 1))
+				else
+					break
+				fi
+			done
+			if [ "$cnt" -eq "0" ]; then
+				echo "Timeout 10 seconds, SPI-NOR still busy. Force unlock to access SPI"
+				rm -f "${spi_lock}"
+			fi
+		fi
+	fi
+
+	HOST_MTD=$(< /proc/mtd grep "pnor" | sed -n 's/^\(.*\):.*/\1/p')
+	if [ -n "$HOST_MTD" ]; then
+		# If the HNOR partition is available, then unbind driver
+		# BMC access SPI-NOR resource
+		gpio_name_set spi0-program-sel 1
+		sleep 0.1
+		echo "Unbind the ASpeed SMC driver"
+		echo "${spi_address}" > "${spi_unbind}"
+	fi
+	# BMC release SPI-NOR resource
+	gpio_name_set spi0-program-sel 0
+	# Deassert BMC access SPI-NOR pin
+	gpio_name_set spi-nor-access 0
+	sleep 0.5
+	return 0
+}
+
+lock_spi_resource() {
+	# Wait maximum 10 seconds to lock SPI-NOR
+	cnt=10
+	while [ $cnt -gt 0 ]
+	do
+		if [ -f "${spi_lock}" ]; then
+			sleep 1
+			cnt=$((cnt - 1))
+		else
+			echo "$1" > "${spi_lock}"
+			break
+		fi
+	done
+
+	if [ "$cnt" -eq "0" ]; then
+		echo "Timeout 10 seconds, SPI-NOR is still locked by another process"
+		return 1
+	fi
+	return 0
+}
+
+unlock_spi_resource() {
+	if [ ! -f "${spi_lock}" ]; then
+		echo "SPI-NOR is already unlocked"
+		return 0
+	fi
+
+	pid=$1
+	pid_lock=$(cat "${spi_lock}")
+	if [[ "${pid}" == "${pid_lock}" ]]; then
+		rm -f "${spi_lock}"
+	else
+		echo "Cannot unlock, SPI-NOR is locked by another process"
+		return 1
+	fi
+	return 0
+}
+
+start_handshake_spi() {
+	if [ -f "${spi_lock}" ]; then
+		pid=$1
+		pid_lock=$(cat "${spi_lock}")
+		if [[ "${pid}" != "${pid_lock}" ]]; then
+			echo "SPI-NOR resoure is lock by process $pid_lock"
+			return 1
+		fi
+	fi
+
+	# Wait maximum 10 seconds to grant access SPI
+	cnt=10
+	while [ $cnt -gt 0 ]
+	do
+		spinor_access=$(gpio_name_get soc-spi-nor-access)
+		if [ "$spinor_access" == "1" ]; then
+			sleep 1
+			cnt=$((cnt - 1))
+		else
+			break
+		fi
+	done
+
+	if [ "$cnt" -eq "0" ]; then
+		echo "Timeout 10 seconds, host is still hold SPI-NOR."
+		return 1
+	fi
+	echo "Start handshake SPI-NOR"
+	# Grant BMC access SPI-NOR. The process call the scripts should only
+	# claim the bus for only maximum period 500ms.
+	gpio_name_set spi-nor-access 1
+	# Switch the Host SPI-NOR to BMC
+	gpio_name_set spi0-program-sel 1
+}
+
+stop_handshake_spi() {
+	if [ -f "${spi_lock}" ]; then
+		pid=$1
+		pid_lock=$(cat "${spi_lock}")
+		if [[ "${pid}" != "${pid_lock}" ]]; then
+			echo "SPI-NOR resoure is lock by process $pid_lock"
+			return 1
+		fi
+	fi
+	echo "Stop handshake SPI-NOR"
+	# Switch the Host SPI-NOR to HOST
+	gpio_name_set spi0-program-sel 0
+	# Deassert BMC access SPI-NOR pin
+	gpio_name_set spi-nor-access 0
+}
+
+
+if [ $# -eq 0 ]; then
+	echo "Usage:"
+	echo "  - Handshake access SPI-NOR "
+	echo "     $(basename "$0") cmd pid"
+	echo "    <cmd>:"
+	echo "        lock   - lock the SPI-NOR resource"
+	echo "        unlock - unlock the SPI-NOR resource"
+	echo "        bind   - bind the SPI-NOR resource"
+	echo "        unbind - unbind the SPI-NOR resource"
+	echo "        start_handshake - start handshake between BMC and Host"
+	echo "        stop_handshake - release handshake between BMC and Host"
+	echo "    <pid>: Optional - PID of the process call script"
+	exit 0
+fi
+
+CMD=$1
+
+if [ ! -d "${spi_lock_dir}" ]; then
+	mkdir -p "${spi_lock_dir}"
+fi
+
+if [ -z "$2" ]; then
+	PID=$$
+else
+	PID=$2
+fi
+
+if [[ "${CMD}" == "lock" ]]; then
+	lock_spi_resource "${PID}"
+	ret=$?
+	if [[ "${ret}" == "1" ]]; then
+		echo "Cannot lock SPI-NOR, the resource is busy"
+		exit 1
+	fi
+elif [[ "${CMD}" == "unlock" ]]; then
+	unlock_spi_resource "${PID}"
+	ret=$?
+	if [[ "${ret}" == "1" ]]; then
+		echo "Cannot unlock SPI-NOR, the resource is busy"
+		exit 1
+	fi
+elif [[ "${CMD}" == "bind" ]]; then
+	bind_aspeed_smc_driver "${PID}"
+	ret=$?
+	if [[ "${ret}" == "1" ]]; then
+		echo "Cannot bind SPI-NOR, the resource is busy"
+		exit 1
+	fi
+elif [[ "${CMD}" == "unbind" ]]; then
+	unbind_aspeed_smc_driver "${PID}"
+	ret=$?
+	if [[ "${ret}" == "1" ]]; then
+		echo "Cannot unbind SPI-NOR, the resource is busy"
+		exit 1
+	fi
+elif [[ "${CMD}" == "start_handshake" ]]; then
+	start_handshake_spi "${PID}"
+	ret=$?
+	if [[ "${ret}" == "1" ]]; then
+		echo "Cannot start handshake SPI-NOR"
+		exit 1
+	fi
+elif [[ "${CMD}" == "stop_handshake" ]]; then
+	stop_handshake_spi "${PID}"
+	ret=$?
+	if [[ "${ret}" == "1" ]]; then
+		echo "Cannot stop handshake SPI-NOR"
+		exit 1
+	fi
+fi
+
+exit 0
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 341ca13..778ca98 100644
--- a/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils.bbappend
+++ b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils.bbappend
@@ -8,6 +8,8 @@
            file://ampere_flash_bios.sh \
            file://ampere_power_on_driver_binder.sh \
            file://ampere_firmware_version.sh \
+           file://ampere_fanctrl.sh \
+           file://ampere_scandump_mode.sh \
           "
 
 do_install:append() {
@@ -17,4 +19,6 @@
     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}/
+    install -m 0755 ${WORKDIR}/ampere_fanctrl.sh ${D}/${sbindir}/
+    install -m 0755 ${WORKDIR}/ampere_scandump_mode.sh ${D}/${sbindir}/
 }
diff --git a/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_fanctrl.sh b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_fanctrl.sh
new file mode 100644
index 0000000..9dcc6d8
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_fanctrl.sh
@@ -0,0 +1,168 @@
+#!/bin/bash
+
+fanSensorService="xyz.openbmc_project.FanSensor"
+
+sensorPath="/xyz/openbmc_project/sensors/fan_tach/"
+pwmTargetPath="/xyz/openbmc_project/control/fanpwm/"
+
+sensorValueInterfaceName="xyz.openbmc_project.Sensor.Value"
+sensorValuePropertyName="Value"
+
+pwmTargetInterfaceName="xyz.openbmc_project.Control.FanPwm"
+pwmTargetPropertyName="Target"
+
+function stop_phosphor_fan_services() {
+    systemctl stop phosphor-fan-control@0.service
+    systemctl stop phosphor-fan-monitor@0.service
+    systemctl stop phosphor-fan-presence-tach@0.service
+}
+
+function start_phosphor_fan_services() {
+    systemctl start phosphor-fan-control@0.service
+    systemctl start phosphor-fan-monitor@0.service
+    systemctl start phosphor-fan-presence-tach@0.service
+}
+
+function read_speed() {
+    fan_val=$(busctl get-property "$fanSensorService" "${sensorPath}$1" "$sensorValueInterfaceName" "$sensorValuePropertyName")
+    busctl_error=$?
+    if (( busctl_error != 0 )); then
+      echo "Error: get-property $sensorValuePropertyName failed! "
+      exit 1
+    fi
+
+    pwm_target=$(busctl get-property "$fanSensorService" "${pwmTargetPath}$2" "$pwmTargetInterfaceName" "$pwmTargetPropertyName")
+    busctl_error=$?
+    if (( busctl_error != 0 )); then
+      echo "Error: get-property $pwmTargetPropertyName failed! "
+      exit 1
+    fi
+
+    fan_val=$(echo "$fan_val" | cut -d " " -f 2)
+    pwm_target=$(echo "$pwm_target" | cut -d " " -f 2)
+
+    # Convert fan PWM to Duty cycle, adding 127 for rounding.
+    pwm_duty_cyle=$(((("$pwm_target" * 100) + 127) / 255))
+
+    echo "$1, PWM: $pwm_target, Duty cycle: $pwm_duty_cyle%, Speed(RPM): $fan_val"
+}
+
+function set_pwm() {
+
+    # Convert Fan Duty cycle to PWM, adding 50 for rounding.
+    fan_pwm=$(((($2 * 255) + 50) / 100))
+
+    busctl set-property "$fanSensorService" "${pwmTargetPath}$1" "$pwmTargetInterfaceName" "$pwmTargetPropertyName" t "$fan_pwm"
+    busctl_error=$?
+    if (( busctl_error != 0 )); then
+      echo "Error: set-property $pwmTargetPropertyName failed! "
+      exit 255
+    fi
+}
+
+function getstatus() {
+    fan_ctl_stt=$(systemctl is-active phosphor-fan-control@0.service | grep inactive)
+    fan_monitor_stt=$(systemctl is-active phosphor-fan-monitor@0.service | grep inactive)
+    if [[ -z "$fan_ctl_stt" && -z "$fan_monitor_stt" ]]; then
+        echo "Thermal Control operational status: Enabled"
+        exit 0
+    else
+        echo "Thermal Control operational status: Disabled"
+        exit 1
+    fi
+}
+
+function setstatus() {
+    if [ "$1" == 0 ]; then
+        # Enable fan services
+        start_phosphor_fan_services
+    else
+        # Disable fan services
+        stop_phosphor_fan_services
+    fi
+}
+
+function setspeed() {
+    # Get fan_pwm value of the fan
+    case "$1" in
+    0) fan_pwm=PWM7
+    ;;
+    1) fan_pwm=PWM5
+    ;;
+    2) fan_pwm=PWM4
+    ;;
+    3) fan_pwm=PWM3
+    ;;
+    4) fan_pwm=PWM1
+    ;;
+    5) fan_pwm=PWM0
+    ;;
+    *) echo "fan $1 doesn't exit"
+        exit 1
+    ;;
+    esac
+
+    set_pwm "$fan_pwm" "$2"
+    exit 0
+}
+
+function getspeed() {
+
+    # Mapping fan number to fan_input and fan_pwm index
+    case "$1" in
+    0) fan_input_f=FAN0_F
+       fan_input_r=FAN0_R
+       fan_pwm=PWM7
+    ;;
+    1) fan_input_f=FAN1_F
+       fan_input_r=FAN1_R
+       fan_pwm=PWM5
+    ;;
+    2) fan_input_f=FAN2_F
+       fan_input_r=FAN2_R
+       fan_pwm=PWM4
+    ;;
+    3) fan_input_f=FAN3_F
+       fan_input_r=FAN3_R
+       fan_pwm=PWM3
+    ;;
+    4) fan_input_f=FAN4_F
+       fan_input_r=FAN4_R
+       fan_pwm=PWM1
+    ;;
+    5) fan_input_f=FAN5_F
+       fan_input_r=FAN5_F
+       fan_pwm=PWM0
+    ;;
+    *) echo "fan $1 doesn't exit"
+        exit 1
+    ;;
+    esac
+
+    # Get fan speed, each fan number has two values is front and rear
+    read_speed "$fan_input_f" "$fan_pwm"
+    read_speed "$fan_input_r" "$fan_pwm"
+
+    exit 0
+}
+
+# Usage of this utility
+function usage() {
+    echo "Usage:"
+    echo "  ampere_fanctrl.sh [getstatus] [setstatus <0|1>] [setspeed <fan> <duty>] [getspeed <fan>]"
+    echo "  fan: 0-5"
+    echo "  duty: 1-100"
+}
+
+if [ "$1" == "getstatus" ]; then
+    getstatus
+elif [ "$1" == "setstatus" ]; then
+    setstatus "$2"
+elif [ "$1" == "setspeed" ]; then
+    stop_phosphor_fan_services
+    setspeed "$2" "$3"
+elif [ "$1" == "getspeed" ]; then
+    getspeed "$2"
+else
+    usage
+fi
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
index dce6e6c..9c187b1 100755
--- 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
@@ -134,19 +134,19 @@
 	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"
+		ampere_cpldupdate_i2c -b 101 -s 0x40 -t 3 -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"
+		ampere_cpldupdate_i2c -b 102 -s 0x40 -t 3 -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"
+		ampere_cpldupdate_i2c -b 100 -s 0x40 -t 3 -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"
+		ampere_cpldupdate_i2c -b 103 -s 0x40 -t 3 -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"
+		ampere_cpldupdate_i2c -b 104 -s 0x40 -t 3 -p "$BP_CPLD_IMAGE"
 	fi
 
 	echo "Done"
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
index 081e303..adb9869 100755
--- 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
@@ -40,24 +40,24 @@
 	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
+		ampere_cpldupdate_i2c -b 101 -s 0x40 -t 3 -v
+		ampere_cpldupdate_i2c -b 101 -s 0x40 -t 3 -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
+		ampere_cpldupdate_i2c -b 102 -s 0x40 -t 3 -v
+		ampere_cpldupdate_i2c -b 102 -s 0x40 -t 3 -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
+		ampere_cpldupdate_i2c -b 100 -s 0x40 -t 3 -v
+		ampere_cpldupdate_i2c -b 100 -s 0x40 -t 3 -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
+		ampere_cpldupdate_i2c -b 103 -s 0x40 -t 3 -v
+		ampere_cpldupdate_i2c -b 103 -s 0x40 -t 3 -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
+		ampere_cpldupdate_i2c -b 104 -s 0x40 -t 3 -v
+		ampere_cpldupdate_i2c -b 104 -s 0x40 -t 3 -i
 	fi
 }
 
diff --git a/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_scandump_mode.sh b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_scandump_mode.sh
new file mode 100755
index 0000000..f08c968
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-ampere/platform/ampere-utils/ampere_scandump_mode.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+
+# Helper script to support enable/disable Scandump Mode
+# Author : Hieu Huynh (hieu.huynh@amperecomputing.com)
+#
+# To enable Scandump mode:
+#    ampere_scandump_mode.sh enable
+#
+# To disable Scandump mode:
+#    ampere_scandump_mode.sh disable
+#
+# To get Scandump mode status:
+#    ampere_scandump_mode.sh getstatus
+
+enable_scandump_mode() {
+	echo "Enable Scandump mode"
+	# Disable Mpro hang detection
+	systemctl stop ampere-sysfw-hang-handler.service
+
+	# Disable PLDM service
+	systemctl stop pldmd.service
+
+	# Enable scandump mode in CPLD
+	# Get Port0 value
+	p0_val=$(i2cget -f -y 15 0x22 0x02)
+	p0_val=$(("$p0_val" | (1 << 4)))
+	# Set Port0[4] value to "1" to mask all CPU’s GPIOs, set Port0[4].
+	i2cset -f -y 15 0x22 0x02 $p0_val
+
+	p0_IOexp_val=$(i2cget -f -y 15 0x22 0x06)
+	p0_IOexp_val=$(("$p0_IOexp_val" & ~(1 << 4)))
+	# Config CPLD's IOepx Port0[4] from input to output, clear IOepx Port0[4].
+	i2cset -f -y 15 0x22 0x06 $p0_IOexp_val
+}
+
+diable_scandump_mode() {
+	echo "Disable Scandump mode"
+
+	# Disable scandump mode in CPLD
+	# Get Port0 value
+	p0_val=$(i2cget -f -y 15 0x22 0x02)
+	p0_val=$(("$p0_val" & ~(1 << 4)))
+	# Set Port0[4] value to "0" to unmask all CPU’s GPIOs, clear Port0[4].
+	i2cset -f -y 15 0x22 0x02 $p0_val
+
+	p0_IOexp_val=$(i2cget -f -y 15 0x22 0x06)
+	p0_IOexp_val=$(("$p0_IOexp_val" | (1 << 4)))
+	# Config CPLD's IOepx Port0[4] from output to input, set IOepx Port0[4].
+	i2cset -f -y 15 0x22 0x06 $p0_IOexp_val
+
+	# Enable Mpro hang detection
+	systemctl start ampere-sysfw-hang-handler.service
+
+	# Enable PLDM service
+	systemctl start pldmd.service
+}
+
+getstatus() {
+	# Get CPLD's IOepx Port0[4], if this bit is "0" scandump mode is enabled.
+	p0_IOexp_val=$(i2cget -f -y 15 0x22 0x06)
+	p0_IOexp_val=$(("$p0_IOexp_val" & (1 << 4)))
+	if [[ "$p0_IOexp_val" == "0" ]]; then
+		echo "Scandump mode is enabled"
+		exit 1
+	else
+		echo "Scandump mode is disabled"
+		exit 0
+	fi
+}
+
+# Usage of this utility
+usage() {
+	echo "Usage:"
+	echo "  - To enable Scandump mode"
+	echo "     $(basename "$0") enable"
+	echo "  - To disable Scandump mode"
+	echo "     $(basename "$0") disable"
+	echo "  - To get Scandump mode status"
+	echo "     $(basename "$0") getstatus"
+	exit 0
+}
+
+if [[ $1 == "enable" ]]; then
+	enable_scandump_mode
+elif [[ $1 == "disable" ]]; then
+	diable_scandump_mode
+elif [[ $1 == "getstatus" ]]; then
+	getstatus
+else
+	echo "Invalid mode"
+	usage
+fi
+
+exit 0