meta-ampere: Support Ampere power control

Implement the Ampere power control requirements for Altra system.

Tested:
- Check the ipmi commands: ipmi power on/off/soft/reset/cycle
- Check the redfish commands: On, Off, ForceOn, ForceOff,
GracefulShutdown, GracefulRestart, ForceRestart, PowerCycle

Signed-off-by: Tung Nguyen <tungnguyen@os.amperecomputing.com>
Change-Id: Id0c64c1284a6338ce47ca720d0ef75e99d21aa3c
diff --git a/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl.bb b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl.bb
new file mode 100644
index 0000000..e7c3cc1
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl.bb
@@ -0,0 +1,85 @@
+SUMMARY = "Ampere Computing LLC Host Control Implementation"
+DESCRIPTION = "A host control implementation suitable for Ampere Computing LLC's systems"
+PR = "r1"
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
+
+inherit systemd
+inherit obmc-phosphor-systemd
+
+# For now, monitoring shutdown_ack and reboot_ack are the only usecases
+OBMC_HOST_MONITOR_INSTANCES = "shutdown_ack reboot_ack"
+SYSTEMD_ENVIRONMENT_FILE_${PN} +="obmc/gpio/shutdown_ack obmc/gpio/reboot_ack"
+
+S = "${WORKDIR}"
+
+SRC_URI = "file://ampere-host-shutdown.service \
+          file://ampere-host-reset.service \
+          file://ampere_power_util.sh \
+          file://ampere-chassis-poweroff.service \
+          file://ampere-chassis-poweron.service \
+          file://ampere-host-reset-ack.service \
+          file://ampere-host-force-reset.service \
+          file://ampere-host-power-cycle.service \
+          "
+
+DEPENDS = "systemd virtual/obmc-gpio-monitor"
+RDEPENDS_${PN} = "bash virtual/obmc-gpio-monitor"
+
+SYSTEMD_PACKAGES = "${PN}"
+SYSTEMD_SERVICE_${PN} = " \
+        ampere-host-shutdown.service \
+        ampere-host-reset.service \
+        ampere-chassis-poweroff.service \
+        ampere-chassis-poweron.service \
+        ampere-host-reset-ack.service \
+        ampere-host-force-reset.service \
+        ampere-host-power-cycle.service \
+        "
+# host power control
+# overwrite the host shutdown to graceful shutdown
+HOST_SHUTDOWN_TMPL = "ampere-host-shutdown.service"
+HOST_SHUTDOWN_TGTFMT = "obmc-host-shutdown@{0}.target"
+HOST_SHUTDOWN_FMT = "../${HOST_SHUTDOWN_TMPL}:${HOST_SHUTDOWN_TGTFMT}.requires/${HOST_SHUTDOWN_TMPL}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'HOST_SHUTDOWN_FMT', 'OBMC_HOST_INSTANCES')}"
+
+# Force the power cycle target to run the ampere power cycle
+HOST_REBOOT_SVC = "ampere-host-power-cycle.service"
+HOST_REBOOT_SVC_TGTFMT = "obmc-host-reboot@{0}.target"
+HOST_REBOOT_SVC_FMT = "../${HOST_REBOOT_SVC}:${HOST_REBOOT_SVC_TGTFMT}.requires/${HOST_REBOOT_SVC}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'HOST_REBOOT_SVC_FMT', 'OBMC_HOST_INSTANCES')}"
+
+# overwrite the host reset to graceful reset
+HOST_WARM_REBOOT_SOFT_SVC = "ampere-host-reset.service"
+HOST_WARM_REBOOT_TGTFMT = "obmc-host-warm-reboot@{0}.target"
+HOST_WARM_REBOOT_SOFT_SVC_FMT = "../${HOST_WARM_REBOOT_SOFT_SVC}:${HOST_WARM_REBOOT_TGTFMT}.requires/${HOST_WARM_REBOOT_SOFT_SVC}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'HOST_WARM_REBOOT_SOFT_SVC_FMT', 'OBMC_HOST_INSTANCES')}"
+
+# overwrite force reboot
+HOST_WARM_REBOOT_FORCE_TGT = "ampere-host-force-reset.service"
+HOST_WARM_REBOOT_FORCE_TGTFMT = "obmc-host-force-warm-reboot@{0}.target"
+HOST_WARM_REBOOT_FORCE_TARGET_FMT = "../${HOST_WARM_REBOOT_FORCE_TGT}:${HOST_WARM_REBOOT_FORCE_TGTFMT}.requires/${HOST_WARM_REBOOT_FORCE_TGT}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'HOST_WARM_REBOOT_FORCE_TARGET_FMT', 'OBMC_HOST_INSTANCES')}"
+
+# chassis power control
+CHASSIS_POWERON_SVC = "ampere-chassis-poweron.service"
+CHASSIS_POWERON_TGTFMT = "obmc-chassis-poweron@{0}.target"
+CHASSIS_POWERON_FMT = "../${CHASSIS_POWERON_SVC}:${CHASSIS_POWERON_TGTFMT}.requires/${CHASSIS_POWERON_SVC}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'CHASSIS_POWERON_FMT', 'OBMC_CHASSIS_INSTANCES')}"
+
+CHASSIS_POWEROFF_SVC = "ampere-chassis-poweroff.service"
+CHASSIS_POWEROFF_TGTFMT = "obmc-chassis-poweroff@{0}.target"
+CHASSIS_POWEROFF_FMT = "../${CHASSIS_POWEROFF_SVC}:${CHASSIS_POWEROFF_TGTFMT}.requires/${CHASSIS_POWEROFF_SVC}"
+SYSTEMD_LINK_${PN} += "${@compose_list_zip(d, 'CHASSIS_POWEROFF_FMT', 'OBMC_CHASSIS_INSTANCES')}"
+
+TMPL = "phosphor-gpio-monitor@.service"
+INSTFMT = "phosphor-gpio-monitor@{0}.service"
+TGT = "multi-user.target"
+FMT = "../${TMPL}:${TGT}.requires/${INSTFMT}"
+SYSTEMD_LINK_${PN} += "${@compose_list(d, 'FMT', 'OBMC_HOST_MONITOR_INSTANCES')}"
+
+do_install() {
+    install -d ${D}/usr/sbin
+    install -m 0755 ${WORKDIR}/ampere_power_util.sh ${D}/${sbindir}/ampere_power_util.sh
+}
+
diff --git a/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-chassis-poweroff.service b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-chassis-poweroff.service
new file mode 100644
index 0000000..b0a1af7
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-chassis-poweroff.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Ampere Computing LLC Power OFF Chassis
+Requires=op-wait-power-off@%i.service
+Before=op-wait-power-off@%i.service
+Conflicts=obmc-chassis-poweron@0.target
+
+[Service]
+RemainAfterExit=no
+Type=oneshot
+ExecStart=/usr/bin/env ampere_power_util.sh mb off
+SyslogIdentifier=ampere_power_util.sh
diff --git a/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-chassis-poweron.service b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-chassis-poweron.service
new file mode 100644
index 0000000..76ceb88
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-chassis-poweron.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Ampere Computing LLC Power ON Chassis
+Conflicts=obmc-chassis-poweroff@0.target
+
+[Service]
+RemainAfterExit=yes
+Type=oneshot
+ExecStart=/usr/bin/env ampere_power_util.sh mb on
+SyslogIdentifier=ampere_power_util.sh
diff --git a/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-force-reset.service b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-force-reset.service
new file mode 100644
index 0000000..8a40baf
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-force-reset.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Ampere Computing LLC force reset host
+Conflicts=obmc-chassis-poweroff@0.target
+OnFailure=obmc-chassis-powerreset@0.target
+
+[Service]
+RemainAfterExit=no
+Type=oneshot
+ExecStart=/usr/bin/env ampere_power_util.sh mb force_reset
+SyslogIdentifier=ampere_power_util.sh
+
diff --git a/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-power-cycle.service b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-power-cycle.service
new file mode 100644
index 0000000..2fb03ef
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-power-cycle.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Ampere Computing LLC power cycle service
+Conflicts=obmc-host-start@0.target
+OnFailure=obmc-chassis-powerreset@0.target
+
+[Service]
+RemainAfterExit=no
+Type=oneshot
+ExecStart=/usr/bin/env ampere_power_util.sh mb cycle
+SyslogIdentifier=ampere_power_util.sh
diff --git a/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-reset-ack.service b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-reset-ack.service
new file mode 100644
index 0000000..504186e
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-reset-ack.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Ampere Computing LLC triggering reset ACK
+Conflicts=obmc-host-start@0.target
+OnFailure=obmc-chassis-powerreset@0.target
+
+[Service]
+RemainAfterExit=no
+Type=oneshot
+ExecStart=/usr/bin/env ampere_power_util.sh mb force_reset
+SyslogIdentifier=ampere_power_util.sh
diff --git a/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-reset.service b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-reset.service
new file mode 100644
index 0000000..ac7618a
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-reset.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Ampere Computing LLC warm reset host
+Conflicts=obmc-chassis-poweroff@0.target
+
+[Service]
+RemainAfterExit=no
+Type=oneshot
+ExecStart=/usr/bin/env ampere_power_util.sh mb graceful_reset
+SyslogIdentifier=ampere_power_util.sh
diff --git a/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-shutdown.service b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-shutdown.service
new file mode 100644
index 0000000..be4d452
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/host/ampere-hostctrl/ampere-host-shutdown.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Ampere Computing LLC graceful shutdown host
+Conflicts=obmc-host-start@0.target
+OnFailure=obmc-chassis-poweroff@0.target
+
+[Service]
+RemainAfterExit=no
+Type=oneshot
+ExecStart=/usr/bin/env ampere_power_util.sh mb graceful_shutdown
+SyslogIdentifier=ampere_power_util.sh
diff --git a/meta-ampere/meta-common/recipes-ac01/host/files/ampere_power_util.sh b/meta-ampere/meta-common/recipes-ac01/host/files/ampere_power_util.sh
new file mode 100644
index 0000000..8bab9a3
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/host/files/ampere_power_util.sh
@@ -0,0 +1,109 @@
+#!/bin/bash
+# Usage of this utility
+function usage() {
+  echo "usage: power-util mb [on|off|status|cycle|reset|graceful_shutdown|graceful_reset|force_reset]";
+}
+
+power_off() {
+  echo "Shutting down Server $2"
+  busctl set-property xyz.openbmc_project.State.Chassis /xyz/openbmc_project/state/chassis0 xyz.openbmc_project.State.Chassis RequestedPowerTransition s xyz.openbmc_project.State.Chassis.Transition.Off
+}
+
+power_on() {
+  echo "Powering on Server $2"
+  busctl set-property xyz.openbmc_project.State.Chassis /xyz/openbmc_project/state/chassis0 xyz.openbmc_project.State.Chassis RequestedPowerTransition s xyz.openbmc_project.State.Chassis.Transition.On
+}
+
+power_status() {
+  st=$(busctl get-property xyz.openbmc_project.State.Chassis /xyz/openbmc_project/state/chassis0 xyz.openbmc_project.State.Chassis CurrentPowerState | cut -d"." -f6)
+  if [ "$st" == "On\"" ]; then
+  echo "on"
+  else
+  echo "off"
+  fi
+}
+
+power_reset() {
+  echo "Reset on server $2"
+  busctl set-property xyz.openbmc_project.State.Host /xyz/openbmc_project/state/host0 xyz.openbmc_project.State.Host RequestedHostTransition s xyz.openbmc_project.State.Host.Transition.Reboot
+}
+
+graceful_shutdown() {
+  if [ -f "/run/openbmc/host@0-request" ]; then
+    echo "shutdown host immediately"
+    power_off
+  else
+    echo "Triggering graceful shutdown"
+    gpioset -l 0 49=1
+    sleep 1
+    gpioset -l 0 49=0
+    sleep 30s
+  fi
+}
+
+force_reset() {
+  echo "Triggering sysreset pin"
+  gpioset -l 0 91=1
+  sleep 1
+  gpioset -l 0 91=0
+}
+
+if [ $# -lt 2 ]; then
+  echo "Total number of parameter=$#"
+  echo "Insufficient parameter"
+  usage;
+  exit 0;
+fi
+
+if [ $1 != "mb" ]; then
+  echo "Invalid parameter1=$1"
+  usage;
+  exit 0;
+fi
+
+if [ $2 = "on" ]; then
+  if [ $(power_status) == "off" ]; then
+    power_on
+  fi
+elif [ $2 = "off" ]; then
+  if [ $(power_status) == "on" ]; then
+    power_off
+  fi
+  # If any request of graceful reset, need to power on
+  if [ -f "/run/openbmc/host@0-graceful-reset" ]; then
+    sleep 20s
+    power_on
+    rm -f "/run/openbmc/host@0-graceful-reset"
+  fi
+elif [ $2 == "cycle" ]; then
+  if [ $(power_status) == "on" ]; then
+    echo "Powering off server"
+    power_off
+    sleep 20s
+    power_on
+  else
+    echo "Host is already off, do nothing"
+  fi
+elif [ $2 == "reset" ]; then
+  if [ $(power_status) == "on" ]; then
+    power_reset
+  else
+    echo "ERROR: Server not powered on"
+  fi
+elif [[ $2 == "graceful_shutdown" ]]; then
+  graceful_shutdown
+elif [ $2 == "graceful_reset" ]; then
+  mkdir -p "/run/openbmc/"
+  touch "/run/openbmc/host@0-graceful-reset"
+  graceful_shutdown
+  sleep 20s
+elif [ $2 == "status" ]; then
+  power_status
+elif [ $2 == "force_reset" ]; then
+  force_reset
+else
+  echo "Invalid parameter2=$2"
+  usage;
+fi
+
+exit 0;
diff --git a/meta-ampere/meta-common/recipes-ac01/host/files/obmc/gpio/reboot_ack b/meta-ampere/meta-common/recipes-ac01/host/files/obmc/gpio/reboot_ack
new file mode 100644
index 0000000..0436d32
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/host/files/obmc/gpio/reboot_ack
@@ -0,0 +1,4 @@
+DEVPATH=/dev/input/event0
+KEY=75
+POLARITY=1
+TARGET=ampere-host-reset-ack.service
diff --git a/meta-ampere/meta-common/recipes-ac01/host/files/obmc/gpio/shutdown_ack b/meta-ampere/meta-common/recipes-ac01/host/files/obmc/gpio/shutdown_ack
new file mode 100644
index 0000000..a0e857f
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/host/files/obmc/gpio/shutdown_ack
@@ -0,0 +1,4 @@
+DEVPATH=/dev/input/event0
+KEY=50
+POLARITY=1
+TARGET=ampere-chassis-poweroff.service
diff --git a/meta-ampere/meta-common/recipes-ac01/packagegroups/packagegroup-ampere-apps.bb b/meta-ampere/meta-common/recipes-ac01/packagegroups/packagegroup-ampere-apps.bb
new file mode 100644
index 0000000..2990d8e
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-ac01/packagegroups/packagegroup-ampere-apps.bb
@@ -0,0 +1,27 @@
+SUMMARY = "OpenBMC for Ampere - Applications"
+PR = "r1"
+
+inherit packagegroup
+inherit obmc-phosphor-utils
+
+PROVIDES = "${PACKAGES}"
+PACKAGES = " \
+        ${PN}-chassis \
+        ${PN}-system \
+        "
+
+PROVIDES += "virtual/obmc-chassis-mgmt"
+PROVIDES += "virtual/obmc-system-mgmt"
+
+RPROVIDES_${PN}-chassis += "virtual-obmc-chassis-mgmt"
+RPROVIDES_${PN}-system += "virtual-obmc-system-mgmt"
+
+SUMMARY_${PN}-chassis = "Ampere Chassis"
+RDEPENDS_${PN}-chassis = " \
+        obmc-op-control-power \
+        ampere-hostctrl \
+        "
+
+SUMMARY_${PN}-system = "Ampere System"
+RDEPENDS_${PN}-system = " \
+        "
diff --git a/meta-ampere/meta-common/recipes-phosphor/state/phosphor-state-manager/resetreason.conf b/meta-ampere/meta-common/recipes-phosphor/state/phosphor-state-manager/resetreason.conf
new file mode 100644
index 0000000..828d98b
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-phosphor/state/phosphor-state-manager/resetreason.conf
@@ -0,0 +1,2 @@
+[Unit]
+ConditionKernelCommandLine=resetreason=power
diff --git a/meta-ampere/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend b/meta-ampere/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend
new file mode 100644
index 0000000..d54407b
--- /dev/null
+++ b/meta-ampere/meta-common/recipes-phosphor/state/phosphor-state-manager_%.bbappend
@@ -0,0 +1,24 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+DEPS_CFG = "resetreason.conf"
+DEPS_TGT = "phosphor-discover-system-state@.service"
+SYSTEMD_OVERRIDE_${PN}-discover_append = "${DEPS_CFG}:${DEPS_TGT}.d/${DEPS_CFG}"
+
+# We don't want the obmc-host-shutdown (softoff) to require
+# obmc-chassis-poweroff. obmc-chassis-poweroff will be activated once
+# the Shutdown ACK pin is toggled (monitored by phosphor-gpio-monitor)
+HOST_STOP_FMT = ""
+HOST_REBOOT_FMT = ""
+
+pkg_postinst_${PN}-obmc-targets_append() {
+    rm "$D$systemd_system_unitdir/obmc-host-shutdown@0.target.requires/obmc-chassis-poweroff@0.target"
+
+    rm "$D$systemd_system_unitdir/obmc-host-warm-reboot@0.target.requires/xyz.openbmc_project.Ipmi.Internal.SoftPowerOff.service"
+    rm "$D$systemd_system_unitdir/obmc-host-warm-reboot@0.target.requires/obmc-host-force-warm-reboot@0.target"
+
+    rm "$D$systemd_system_unitdir/obmc-host-reboot@0.target.requires/phosphor-reboot-host@0.service"
+    rm "$D$systemd_system_unitdir/obmc-host-reboot@0.target.requires/obmc-host-shutdown@0.target"
+
+    rm "$D$systemd_system_unitdir/obmc-host-force-warm-reboot@0.target.requires/obmc-host-stop@0.target"
+    rm "$D$systemd_system_unitdir/obmc-host-force-warm-reboot@0.target.requires/phosphor-reboot-host@0.service"
+}