1#!/bin/bash
2
3set -e
4
5# Check if PCH is on standby to proceed with the
6# host firmware update
7#
8# Find the GPIO pin associated with "pch-ready"
9# and read the value
10PCH_READY_GPIO_PIN=$(gpiofind "pch-ready")
11
12if [ -z "${PCH_READY_GPIO_PIN}" ]; then
13    echo "gpio 'pch-ready' not found in device tree. Exiting."
14    exit 0
15fi
16
17read -r PCH_READY_GPIO_CHIP PCH_READY_GPIO_LINE <<< "$PCH_READY_GPIO_PIN"
18GPIO_VALUE=$(gpioget "$PCH_READY_GPIO_CHIP" "$PCH_READY_GPIO_LINE")
19
20if [ "${GPIO_VALUE}" != "0" ]; then
21    echo "PCH is not on standby. Exiting host firmware version read."
22    exit 0
23fi
24
25IMAGE_FILE=$(find "$1" -name "*.rom")
26
27IPMB_OBJ="xyz.openbmc_project.Ipmi.Channel.Ipmb"
28IPMB_PATH="/xyz/openbmc_project/Ipmi/Channel/Ipmb"
29IPMB_INTF="org.openbmc.Ipmb"
30
31# me address, 0x2e oen, 0x00 - lun, 0xdf - force recovery
32ME_CMD_RECOVER=(1 0x2e 0 0xdf 4 0x57 0x01 0x00 0x01)
33# me address, 0x6 App Fn, 0x00 - lun, 0x2 - cold reset
34ME_CMD_RESET=(1 6 0 0x2 0)
35# me address, 0x6 App Fn, 0x00 - lun, 0x1 - get device id
36ME_GET_DEVICE_ID=(1 6 0 0x1 0)
37
38echo "Bios firmware upgrade started at $(date)"
39
40me_wait_poweron() {
41    echo "Wait for ME firmware to start"
42    for _ in {1..10}; do
43        busctl call --timeout=1 "$IPMB_OBJ" "$IPMB_PATH" "$IPMB_INTF" sendRequest yyyyay "${ME_GET_DEVICE_ID[@]}" 2>/dev/null
44        exit_code=$?
45
46        if [ "$exit_code" -eq 0 ]; then
47            break
48        fi
49
50        sleep 1
51    done
52
53    if [ "$exit_code" -ne 0 ]; then
54        echo "Failed to communicate with SPS firmware after 10 attempts."
55        exit 1
56    fi
57}
58
59me_force_recovery_mode() {
60    # Set ME to recovery mode
61    echo "Set ME to recovery mode"
62    busctl call "$IPMB_OBJ" "$IPMB_PATH" "$IPMB_INTF" sendRequest yyyyay "${ME_CMD_RECOVER[@]}"
63}
64
65me_reset() {
66    #Reset ME to boot from new bios
67    echo "Reset ME to boot from new firmware"
68    busctl call "$IPMB_OBJ" "$IPMB_PATH" "$IPMB_INTF" sendRequest yyyyay "${ME_CMD_RESET[@]}"
69}
70
71configure_flash_env() {
72    # 1. Assert PCH RESET
73    # 2. Enable/Disable FM_FLASH_SEC_OVRD
74    # 3. De-assert PCH RESET
75    local action="$1"
76    if [ "$action" == "enable" ]; then
77        echo "Asserting PCH RESET and enabling flash write override"
78        gpioset "${PCH_RESET_GPIO_CHIP}" "${PCH_RESET_GPIO_LINE}=0"
79        gpioset "${FLASH_OVERRIDE_GPIO_CHIP}" "${FLASH_OVERRIDE_GPIO_LINE}=1"
80        gpioset "${PCH_RESET_GPIO_CHIP}" "${PCH_RESET_GPIO_LINE}=1"
81        sleep 2
82    elif [ "$action" == "disable" ]; then
83        echo "Disabling flash write override and resetting PCH RESET"
84        gpioset "${PCH_RESET_GPIO_CHIP}" "${PCH_RESET_GPIO_LINE}=0"
85        gpioset "${FLASH_OVERRIDE_GPIO_CHIP}" "${FLASH_OVERRIDE_GPIO_LINE}=0"
86        gpioset "${PCH_RESET_GPIO_CHIP}" "${PCH_RESET_GPIO_LINE}=1"
87    else
88        echo "Invalid action specified for configure_flash_env. Use 'enable' or 'disable'."
89        exit 1
90    fi
91}
92
93cleanup_env() {
94    # Disable flash protection and clean up
95    configure_flash_env "disable"
96}
97
98reset_and_cleanup_env() {
99    echo "Reset ME and disable flash-write-override GPIO"
100    me_reset
101    sleep 5
102    cleanup_env
103}
104
105
106PCH_RESET_GPIO_PIN=$(gpiofind "pch-reset")
107if [ -z "${PCH_RESET_GPIO_PIN}" ]; then
108    echo "gpio 'pch-ready' not found in device tree. Exiting."
109    exit 0
110fi
111read -r PCH_RESET_GPIO_CHIP PCH_RESET_GPIO_LINE <<< "$PCH_RESET_GPIO_PIN"
112
113FLASH_OVERRIDE_GPIO_PIN="$(gpiofind flash-write-override)"
114if [ -z "${FLASH_OVERRIDE_GPIO_PIN}" ]; then
115    echo "gpio 'flash-write-override' not found in device tree. Exiting."
116    exit 0
117fi
118read -r FLASH_OVERRIDE_GPIO_CHIP FLASH_OVERRIDE_GPIO_LINE <<< "$FLASH_OVERRIDE_GPIO_PIN"
119
120configure_flash_env "enable"
121sleep 2
122
123me_wait_poweron
124
125me_force_recovery_mode
126
127# Fetch the MTD device number for the specified espi flash device
128DEVICE_NAME="espi-flash-mafs"
129MTD_DEVICE_NUMBER=$(grep "$DEVICE_NAME" /proc/mtd | awk -F: '{print $1}' | awk -F'mtd' '{print $2}')
130
131if [ -n "$MTD_DEVICE_NUMBER" ]; then
132    echo "Found MTD device number: $MTD_DEVICE_NUMBER"
133else
134    echo "Error: MTD device with name '$DEVICE_NAME' not found!"
135    reset_and_cleanup_env
136    exit 1
137fi
138
139#Flashcp image to device.
140if [ -e "$IMAGE_FILE" ];
141then
142    echo "Bios image is $IMAGE_FILE"
143    flashrom -p linux_mtd:dev="${MTD_DEVICE_NUMBER}" -w "$IMAGE_FILE"
144else
145    echo "Bios image $IMAGE_FILE doesn't exist"
146fi
147
148reset_and_cleanup_env
149