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