meta-bletchley: Add services to control step motor
For Bletchley platform, we can only power on system by step motor to press power key.
Add tools and service to initialize step motor and control system power
by motor.
Signed-off-by: Allen.Wang <Allen_Wang@quantatw.com>
Change-Id: Ic75352a037566d701b2e362743c527c370b0c2e5
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/meta-facebook/meta-bletchley/conf/machine/bletchley.conf b/meta-facebook/meta-bletchley/conf/machine/bletchley.conf
index d69357b..6b7711a 100644
--- a/meta-facebook/meta-bletchley/conf/machine/bletchley.conf
+++ b/meta-facebook/meta-bletchley/conf/machine/bletchley.conf
@@ -13,3 +13,6 @@
FLASH_SIZE = "131072"
PREFERRED_PROVIDER_virtual/phosphor-led-manager-config-native = "bletchley-led-manager-config-native"
+
+OBMC_HOST_INSTANCES = "0 1 2 3 4 5 "
+
diff --git a/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/host-poweroff@.service b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/host-poweroff@.service
new file mode 100644
index 0000000..50cd532
--- /dev/null
+++ b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/host-poweroff@.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Power off System in Sled%i by Step Motor
+Requires=motor-init-calibration@%i.service
+After=motor-init-calibration@%i.service
+
+[Service]
+Type=oneshot
+ExecStart=/usr/sbin/power-ctrl sled%i off
+SyslogIdentifier=power-ctrl
+
diff --git a/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/host-poweron@.service b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/host-poweron@.service
new file mode 100644
index 0000000..6ff1120
--- /dev/null
+++ b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/host-poweron@.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Power on System in Sled%i by Step Motor
+Requires=motor-init-calibration@%i.service
+After=motor-init-calibration@%i.service
+
+[Service]
+Type=oneshot
+ExecStart=/usr/sbin/power-ctrl sled%i on
+SyslogIdentifier=power-ctrl
+
diff --git a/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/motor-ctrl b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/motor-ctrl
new file mode 100755
index 0000000..3f8f2ca
--- /dev/null
+++ b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/motor-ctrl
@@ -0,0 +1,101 @@
+#!/bin/bash -e
+#
+# Control step motor rotate of sled
+
+function set_gpio()
+{
+ NET_NAME=$1
+ OUT_VAL=$2
+ mapfile -t -d " " GPIO_INFO < <(gpiofind "$NET_NAME")
+ if [ "${#GPIO_INFO[@]}" -ne 2 ]; then
+ echo "set_gpio: can not find gpio, $NET_NAME"
+ return 1
+ fi
+ echo -n "set_gpio: set $NET_NAME = $OUT_VAL"
+ if ! gpioset "${GPIO_INFO[0]}" "${GPIO_INFO[1]%$'\n'}"="$OUT_VAL"; then
+ echo " failed"
+ return 1
+ fi
+ echo " success"
+ return 0
+}
+
+#Get i2c bus number for sledN
+function get_bus_num() {
+ SLED_NUM=$1
+ local bus=0
+
+ if [[ "$SLED_NUM" = [0-5] ]]; then
+ bus="$SLED_NUM"
+ fi
+ echo "$bus"
+}
+
+#Enable sledN Motor VRef
+function open_vref() {
+ i2cset -f -y "${1}" 0x67 0x06 0x95
+}
+
+#Disable sledN Motor VRef
+function close_vref() {
+ i2cset -f -y "${1}" 0x67 0x06 0x55
+}
+
+#######################################
+# Setting step motor control pins to start/stop motor
+# Arguments:
+# 1. SLED NUMBER
+# 2. Value of STBY RESET PIN
+# 3. Value of ENABLE PIN
+# 4. Value of DIRECTION PIN
+#######################################
+function set_motor() {
+ STBY_PIN="SLED${1}_MD_STBY_RESET"
+ EN_PIN="SLED${1}_MD_IOEXP_EN_FAULT"
+ DIR_PIN="SLED${1}_MD_DIR"
+ set_gpio "$STBY_PIN" "$2"
+ set_gpio "$EN_PIN" "$3"
+ set_gpio "$DIR_PIN" "$4"
+}
+
+function show_usage(){
+ echo "Usage: motor-ctrl [sled0 | sled1 | sled2 | sled3 | sled4 | sled5] [f r s]"
+ echo " f : Step Motor go forward"
+ echo " r : Step Motor go reverse"
+ echo " s : Step Motor stop "
+}
+
+if [ $# -ne 2 ]; then
+ show_usage
+ exit 1;
+fi
+
+if [[ "$1" =~ ^(slot[0-5]{1})$ ]] || [[ "$1" =~ ^(sled[0-5]{1})$ ]]; then
+ SLED=$1
+ SLED_NUM=${SLED:4}
+ I2C_NUM=$(get_bus_num "$SLED_NUM")
+ ACTION=$2
+else
+ echo "invalid sled name: $1"
+ exit 1;
+fi
+
+if [[ "$ACTION" == "s" ]]; then
+ echo "stop motor"
+ set_motor "$SLED_NUM" 1 0 0
+ close_vref "$I2C_NUM"
+elif [[ "$ACTION" == "f" ]];then
+ echo "start motor, direction:forward"
+ set_motor "$SLED_NUM" 1 1 0
+ open_vref "$I2C_NUM"
+elif [[ "$ACTION" == "r" ]];then
+ echo "start motor, direction:reverse"
+ set_motor "$SLED_NUM" 1 1 1
+ open_vref "$I2C_NUM"
+else
+ echo "Error: Unknown action!"
+ exit 1
+fi
+
+exit 0
+
diff --git a/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/motor-init b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/motor-init
new file mode 100755
index 0000000..cecb996
--- /dev/null
+++ b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/motor-init
@@ -0,0 +1,185 @@
+#!/bin/bash -e
+
+# Initialize for step motor of sled:
+# Enable pwm and setup pwm duty
+# Setup gpio pins for step motor control
+# Moving step motor back to initial position
+
+export PATH=$PATH:/usr/libexec
+
+PWM_BASE_ADDR="0x1e61"
+DEV_FILE="/dev/mem"
+CALIBRATE_TIMEOUT=120
+
+#Get pwm register address for sledN
+function get_pwm_offset() {
+ local offset=0
+ case $1 in
+ 0)
+ offset="0080"
+ ;;
+ 1)
+ offset="0090"
+ ;;
+ 2)
+ offset="00a0"
+ ;;
+ 3)
+ offset="00b0"
+ ;;
+ 4)
+ offset="00c0"
+ ;;
+ 5)
+ offset="00d0"
+ ;;
+ esac
+
+ echo ${PWM_BASE_ADDR}${offset}
+}
+
+#Get pwm duty register address for sledN
+function get_duty_offset() {
+ local offset=0
+ case $1 in
+ 0)
+ offset="0084"
+ ;;
+ 1)
+ offset="0094"
+ ;;
+ 2)
+ offset="00a4"
+ ;;
+ 3)
+ offset="00b4"
+ ;;
+ 4)
+ offset="00c4"
+ ;;
+ 5)
+ offset="00d4"
+ ;;
+ esac
+
+ echo ${PWM_BASE_ADDR}${offset}
+}
+
+#Enable pwm for sledN
+function open_pwm() {
+ local SLED_NUM="$1"
+ echo "Open pwm of sled$SLED_NUM"
+ #enable BMC PWM
+ if [ ! -c "$DEV_FILE" ]; then
+ mknod /dev/mem c 1 1
+ fi
+
+ PWM_OFFSET=$(get_pwm_offset "$SLED_NUM")
+ DUTY_OFFSET=$(get_duty_offset "$SLED_NUM")
+ echo "setting ${PWM_OFFSET} to 0x000113F3"
+ echo "setting ${DUTY_OFFSET} to 0xFF006400"
+ devmem "$PWM_OFFSET" 32 0x000113F3
+ devmem "$DUTY_OFFSET" 32 0xFF006400
+}
+
+function set_gpio()
+{
+ NET_NAME=$1
+ OUT_VAL=$2
+ mapfile -t -d " " GPIO_INFO < <(gpiofind "$NET_NAME")
+ if [ "${#GPIO_INFO[@]}" -ne 2 ]; then
+ echo "set_gpio: can not find gpio, $NET_NAME"
+ return 1
+ fi
+ echo -n "set_gpio: set $NET_NAME = $OUT_VAL"
+ if ! gpioset "${GPIO_INFO[0]}" "${GPIO_INFO[1]%$'\n'}"="$OUT_VAL"; then
+ echo " failed"
+ return 1
+ fi
+ echo " success"
+ return 0
+}
+
+function get_gpio()
+{
+ NET_NAME=$1
+ RET_VAL=2
+
+ mapfile -t -d " " GPIO_INFO < <(gpiofind "$NET_NAME")
+ if [ "${#GPIO_INFO[@]}" -ne 2 ]; then
+ echo "get_gpio: can not find gpio, $NET_NAME" >&2
+ return 1
+ fi
+ if ! RET_VAL=$(gpioget "${GPIO_INFO[0]}" "${GPIO_INFO[1]%$'\n'}") ; then
+ echo "get_gpio: get ${NET_NAME} failed" >&2
+ return 1
+ fi
+ echo "${RET_VAL}"
+ return 0
+}
+
+#Init gpio pins for step motor control
+function init_gpios() {
+ echo "Init GPIOs:"
+ motor_ctrl_gpio_pins_names=( "SLED${1}_MD_STBY_RESET"
+ "SLED${1}_MD_IOEXP_EN_FAULT"
+ "SLED${1}_MD_DIR"
+ "SLED${1}_MD_DECAY"
+ "SLED${1}_MD_MODE1"
+ "SLED${1}_MD_MODE2"
+ "SLED${1}_MD_MODE3" )
+
+ for gpio_name in "${motor_ctrl_gpio_pins_names[@]}"; do
+ set_gpio "$gpio_name" 0
+ done
+}
+
+if [[ "$1" =~ ^(slot[0-5]{1})$ ]] || [[ "$1" =~ ^(sled[0-5]{1})$ ]]; then
+ SLED=$1
+ SLED_NUM=${SLED:4}
+else
+ #show_usage
+ echo "invalid sled name: ${1}"
+ exit 1;
+fi
+
+#Check if sled is present
+SLED_PRESENT=$(get_gpio "presence-sled${SLED_NUM}")
+if [ "$SLED_PRESENT" != 0 ];then
+ echo "${SLED} is not present, skip motor initialize"
+ exit 1
+fi
+
+#Init gpios
+init_gpios "$SLED_NUM"
+
+#enable pwm
+open_pwm "$SLED_NUM"
+
+#SLED{N}_MS_DETECT1 (initial position)
+DETECT_PIN1="SLED${SLED_NUM}_MS_DETECT1"
+INIT_POS=$(get_gpio "$DETECT_PIN1")
+
+if [ "$INIT_POS" -eq 1 ];then
+ time_count=0
+ echo "Making motor back to initial position..."
+ motor-ctrl "$SLED" r >/dev/null
+ while [ "$INIT_POS" -eq 1 ] ;do
+ INIT_POS=$(get_gpio "$DETECT_PIN1")
+ sleep 0.1
+ time_count=$(( time_count + 1 ))
+ if [ $time_count -gt $CALIBRATE_TIMEOUT ];then
+ echo "Error: Step motor run over 1 cycle but switch never triggered"
+ break
+ fi
+ done
+ motor-ctrl "$SLED" s >/dev/null
+fi
+
+if [ "$INIT_POS" -eq 0 ];then
+ echo "Motor calibrated to initial position."
+ exit 0
+else
+ echo "Find motor initial position failed"
+ exit 1
+fi
diff --git a/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/motor-init-calibration@.service b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/motor-init-calibration@.service
new file mode 100644
index 0000000..aab61b7
--- /dev/null
+++ b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/motor-init-calibration@.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Motor Initialize for sled%i
+
+[Service]
+ExecStart=/usr/libexec/motor-init sled%i
+SyslogIdentifier=Motor Initialize sled%i
+Type=oneshot
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target
diff --git a/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/power-ctrl b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/power-ctrl
new file mode 100755
index 0000000..111ce8b
--- /dev/null
+++ b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/files/power-ctrl
@@ -0,0 +1,178 @@
+#!/bin/bash
+#
+# Power Control tool
+# Enable/disable AC relay
+# On/off System by step moter to press power key
+
+export PATH=$PATH:/usr/sbin:/usr/libexec
+
+DELAY_POWER_ON="0.5"
+DELAY_POWER_OFF="5"
+POWER_BTN_TIMEOUT_CNT=60
+
+#Switch pull low while it be touched
+function wait_for_switch() {
+ TARGET_PIN=$1
+ TARGET_SWITCH=1
+ TIME_CNT=0
+ while [ "$TARGET_SWITCH" -eq 1 ] ;do
+ TARGET_SWITCH=$(get_gpio "$TARGET_PIN")
+ sleep 0.1
+ TIME_CNT=$(( TIME_CNT +1))
+ if [ $TIME_CNT -gt $POWER_BTN_TIMEOUT_CNT ];then
+ echo "Error: Too long to get target switch, force exit" >&2
+ break
+ fi
+ done
+}
+
+function trigger_power_button() {
+ local sled_num=$1
+ local delay_time=$2
+
+ #SLED{N}_MS_DETECT1 (initial position)
+ GPIO_DETECT_PIN1="SLED${sled_num}_MS_DETECT1"
+ #SLED{N}_MS_DETECT0 (MAC position)
+ GPIO_DETECT_PIN0="SLED${sled_num}_MS_DETECT0"
+
+ echo "Motor go forward to press Power key"
+ motor-ctrl "sled${sled_num}" f >/dev/null
+ wait_for_switch "${GPIO_DETECT_PIN0}"
+ motor-ctrl "sled${sled_num}" s >/dev/null
+
+ if [ "$(get_gpio "$GPIO_DETECT_PIN0")" -eq 0 ];then
+ echo "Power key switch triggered"
+ echo "Press power key for Sled${1} ${delay_time} seconds..."
+ sleep "$delay_time"
+ else
+ echo "Power key switch not trigger, back motor to initail position"
+ fi
+
+ motor-ctrl "sled${sled_num}" r >/dev/null
+ wait_for_switch "${GPIO_DETECT_PIN1}"
+ motor-ctrl "sled${sled_num}" s >/dev/null
+ if [ "$(get_gpio "$GPIO_DETECT_PIN1")" -eq 0 ];then
+ echo "Motor reverse to initial position successful"
+ else
+ echo "Initail position switch not trigger, force stop motor"
+ fi
+}
+
+#Get i2c bus number for sledN
+function get_bus_num() {
+ SLED_NUM=$1
+ local bus=0
+
+ if [[ "$SLED_NUM" = [0-5] ]]; then
+ bus="$SLED_NUM"
+ fi
+ echo "$bus"
+}
+
+function set_gpio()
+{
+ NET_NAME=$1
+ OUT_VAL=$2
+ mapfile -t -d " " GPIO_INFO < <(gpiofind "$NET_NAME")
+ if [ "${#GPIO_INFO[@]}" -ne 2 ]; then
+ echo "set_gpio: can not find gpio, $NET_NAME"
+ return 1
+ fi
+ echo -n "set_gpio: set $NET_NAME = $OUT_VAL"
+ if ! gpioset "${GPIO_INFO[0]}" "${GPIO_INFO[1]%$'\n'}"="$OUT_VAL"; then
+ echo " failed"
+ return 1
+ fi
+ echo " success"
+ return 0
+}
+
+function get_gpio()
+{
+ NET_NAME=$1
+ RET_VAL=2
+
+ mapfile -t -d " " GPIO_INFO < <(gpiofind "$NET_NAME")
+ if [ "${#GPIO_INFO[@]}" -ne 2 ]; then
+ echo "get_gpio: can not find gpio, $NET_NAME" >&2
+ return 1
+ fi
+ if ! RET_VAL=$(gpioget "${GPIO_INFO[0]}" "${GPIO_INFO[1]%$'\n'}") ; then
+ echo "get_gpio: get ${NET_NAME} failed" >&2
+ return 1
+ fi
+ echo "${RET_VAL}"
+ return 0
+}
+
+function get_ac_status(){
+ i2c_bus=$(get_bus_num "$1")
+ p1_output_reg=$(i2cget -f -y "$i2c_bus" 0x76 0x03)
+ p1_config_reg=$(i2cget -f -y "$i2c_bus" 0x76 0x07)
+ host_pwr="$(( (p1_output_reg & 0x80)>>7 ))"
+ is_output="$(( (~p1_config_reg & 0x80)>>7 ))"
+
+ if [ "$(( host_pwr & is_output ))" -eq 1 ];then
+ echo "AC on"
+ else
+ echo "AC off"
+ fi
+}
+
+function show_usage(){
+ echo "Usage: power-ctrl [sled0 | sled1 | sled2 | sled3 | sled4 | sled5] [on off ac-on ac-off status]"
+ echo " power-ctrl chassis-cycle"
+}
+
+if [ $# -eq 1 ]; then
+ if [ "$1" = "chassis-cycle" ];then
+ echo "chassis cycle...."
+ i2cset -y -f 12 0x11 0xd9 c
+ exit 0
+ else
+ echo "Invalid argument: [ $1 ]"
+ show_usage
+ exit 1;
+ fi
+fi
+
+if [ $# -gt 2 ]; then
+ echo "Too many arguments"
+ show_usage
+ exit 1;
+fi
+
+if [[ "$1" =~ ^(slot[0-5]{1})$ ]] || [[ "$1" =~ ^(sled[0-5]{1})$ ]]; then
+ SLED=$1
+ ACTION=$2
+ SLED_NUM=${SLED:4}
+else
+ echo "invalid sled name: ${1}"
+ show_usage
+ exit 1;
+fi
+
+#Check if sled is present
+SLED_PRESENT=$(get_gpio "presence-sled${SLED_NUM}")
+if [ "$SLED_PRESENT" != 0 ];then
+ echo "${SLED} is not present!"
+ exit 1
+fi
+
+if [[ "$ACTION" == "on" ]]; then
+ echo "Power on ${SLED}"
+ trigger_power_button "$SLED_NUM" "$DELAY_POWER_ON"
+elif [[ "$ACTION" == "off" ]];then
+ echo "Power off ${SLED}"
+ trigger_power_button "$SLED_NUM" "$DELAY_POWER_OFF"
+elif [[ "$ACTION" == "status" ]];then
+ get_ac_status "$SLED_NUM"
+ #TODO : check or record Host(DC) power status
+elif [[ "$ACTION" == "ac-on" ]];then
+ set_gpio "power-host${SLED_NUM}" 1
+elif [[ "$ACTION" == "ac-off" ]];then
+ set_gpio "power-host${SLED_NUM}" 0
+else
+ echo "Unknown action: [ ${ACTION} ]"
+ show_usage
+fi
diff --git a/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/motor-ctrl_0.1.bb b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/motor-ctrl_0.1.bb
new file mode 100644
index 0000000..2705eb8
--- /dev/null
+++ b/meta-facebook/meta-bletchley/recipes-bletchley/motor-ctrl/motor-ctrl_0.1.bb
@@ -0,0 +1,37 @@
+SUMMARY = "Bletchley Motor control"
+PR = "r1"
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
+
+inherit obmc-phosphor-systemd
+
+RDEPENDS:${PN} += "bash"
+RDEPENDS:${PN} += "libgpiod-tools"
+RDEPENDS:${PN} += "i2c-tools"
+
+S = "${WORKDIR}"
+SRC_URI += "file://motor-init \
+ file://motor-ctrl \
+ file://power-ctrl "
+
+do_install() {
+ install -d ${D}${sbindir}
+ install -m 0755 ${WORKDIR}/power-ctrl ${D}${sbindir}
+
+ install -d ${D}${libexecdir}
+ install -m 0755 ${WORKDIR}/motor-init ${D}${libexecdir}
+ install -m 0755 ${WORKDIR}/motor-ctrl ${D}${libexecdir}
+}
+
+MOTOR_INIT_INSTFMT= "motor-init-calibration@{0}.service"
+PWR_ON_INSTFMT="host-poweron@.service:host-poweron@{0}.service"
+PWR_OFF_INSTFMT="host-poweroff@.service:host-poweroff@{0}.service"
+
+SYSTEMD_SERVICE:${PN} ="${@compose_list(d, 'MOTOR_INIT_INSTFMT', 'OBMC_HOST_INSTANCES')}"
+FILES:${PN} += "${systemd_system_unitdir}/motor-init-calibration@.service"
+
+SYSTEMD_SERVICE:${PN} +="host-poweron@.service"
+SYSTEMD_LINK:${PN} += "${@compose_list(d, 'PWR_ON_INSTFMT', 'OBMC_HOST_INSTANCES')}"
+
+SYSTEMD_SERVICE:${PN} +="host-poweroff@.service"
+SYSTEMD_LINK:${PN} += "${@compose_list(d, 'PWR_OFF_INSTFMT', 'OBMC_HOST_INSTANCES')}"
diff --git a/meta-facebook/meta-bletchley/recipes-phosphor/images/fb-bletchley-phosphor-image.inc b/meta-facebook/meta-bletchley/recipes-phosphor/images/fb-bletchley-phosphor-image.inc
index 8fa7252..6636f50 100644
--- a/meta-facebook/meta-bletchley/recipes-phosphor/images/fb-bletchley-phosphor-image.inc
+++ b/meta-facebook/meta-bletchley/recipes-phosphor/images/fb-bletchley-phosphor-image.inc
@@ -1,4 +1,5 @@
OBMC_IMAGE_EXTRA_INSTALL:append = " \
phosphor-nvme \
plat-svc \
- "
+ motor-ctrl \
+"