blob: 8b660c2dca1a84137cbc932d9737dc20dde4b3fc [file] [log] [blame]
#!/bin/bash
# Copyright 2020 Google LLC
# Copyright 2020 Quanta Computer Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
source /usr/libexec/gbs-gpio-common.sh
WD1RCR_ADDR=0xf080103c
CORSTC_ADDR=0xf080105c
BOARD_VER="" # Set by check_board_ver
pe_eeprom_addr=( 50 54 )
SERVICE_NAME="xyz.openbmc_project.Inventory.Manager"
INTERFACE_NAME="xyz.openbmc_project.Inventory.Item"
PE_PRESENT_OBJPATH=("/xyz/openbmc_project/inventory/system/chassis/entity/pe_slot0_prsnt"
"/xyz/openbmc_project/inventory/system/chassis/entity/pe_slot1_prsnt")
SATA0_PRESENT_OBJPATH="/xyz/openbmc_project/inventory/system/chassis/entity/sata0_prsnt"
set_gpio_persistence() {
reg_val=$(devmem ${WD1RCR_ADDR} 32)
# Clear bit 16-23 to perserve all GPIO states across warm resets
reg_val=$(printf "0x%08x" $((reg_val & ~0xff0000)))
echo "Setting WD1RCR_ADDR to ${reg_val}"
devmem "${WD1RCR_ADDR}" 32 "${reg_val}"
reg_val=$(devmem ${CORSTC_ADDR} 32)
# Clear bit 16-23 of CORSTC
reg_val=$(printf "0x%08x" $((reg_val & ~0xff0000)))
echo "Setting CORSTC_ADDR to ${reg_val}"
devmem "${CORSTC_ADDR}" 32 "${reg_val}"
}
get_board_rev_id() {
echo $(get_gpio_value 'BMC_BRD_REV_ID7')\
$(get_gpio_value 'BMC_BRD_REV_ID6')\
$(get_gpio_value 'BMC_BRD_REV_ID5')\
$(get_gpio_value 'BMC_BRD_REV_ID4')\
$(get_gpio_value 'BMC_BRD_REV_ID3')\
$(get_gpio_value 'BMC_BRD_REV_ID2')\
$(get_gpio_value 'BMC_BRD_REV_ID1')\
$(get_gpio_value 'BMC_BRD_REV_ID0')\
| sed 's/ //g' > ~/board_rev_id.txt
}
get_board_sku_id() {
echo $(get_gpio_value 'BMC_BRD_SKU_ID3')\
$(get_gpio_value 'BMC_BRD_SKU_ID2')\
$(get_gpio_value 'BMC_BRD_SKU_ID1')\
$(get_gpio_value 'BMC_BRD_SKU_ID0')\
| sed 's/ //g' > ~/board_sku_id.txt
}
get_hsbp_board_rev_id() {
echo $(get_gpio_value 'HSBP_BRD_REV_ID3')\
$(get_gpio_value 'HSBP_BRD_REV_ID2')\
$(get_gpio_value 'HSBP_BRD_REV_ID1')\
$(get_gpio_value 'HSBP_BRD_REV_ID0')\
| sed 's/ //g' > ~/hsbp_board_rev_id.txt
}
get_fan_board_rev_id() {
echo $(get_gpio_value 'FAN_BRD_REV_ID1')\
$(get_gpio_value 'FAN_BRD_REV_ID0')\
| sed 's/ //g' > ~/fan_board_rev_id.txt
}
check_board_ver() {
# Sets BOARD_VER to either "PREPVT" or "PVT"
#
# BOARD_REV_ID[7:6] =
# 0x00 - EVT
# 0x01 - DVT
# 0x10 - PVT
# 0x11 - MP
rev7_val=$(get_gpio_value 'BMC_BRD_REV_ID7')
if (( rev7_val == 0 )); then
echo "EVT/DVT rev!"
BOARD_VER="PREPVT"
else
echo "PVT/MP rev!"
BOARD_VER="PVT"
fi
}
check_board_sku() {
sku1_val=$(get_gpio_value 'BMC_BRD_SKU_ID1')
if (( sku1_val == 1 )); then
echo "GBS SKU!"
BOARD_SKU="GBS"
else
echo "Other SKU!"
BOARD_SKU="TBD"
fi
}
set_uart_en_low() {
# GPIO76 UART_EN polarity inverted between DVT/PVT
# Pin direction was set high in the kernel.
set_gpio_direction 'FM_BMC_CPU_UART_EN' low
}
set_hdd_prsnt() {
# On PVT need to forward SATA0_PRSNT_N to HDD_PRSNT_N
# The signal is safe to set on DVT boards so just set universally.
mapper wait ${SATA0_PRESENT_OBJPATH}
sata_prsnt_n="$(busctl get-property $SERVICE_NAME ${SATA0_PRESENT_OBJPATH} \
$INTERFACE_NAME Present)"
# sata_prsnt_n is active low => value "true" means low
if [[ ${sata_prsnt_n} == "b true" ]]; then
set_gpio_direction 'HDD_PRSNT_N' low
else
set_gpio_direction 'HDD_PRSNT_N' high
fi
}
KERNEL_FIU_ID="c0000000.spi"
KERNEL_SYSFS_FIU="/sys/bus/platform/drivers/NPCM-FIU"
# the node of FIU is spi for kernel 5.10, but
# for less than or equal kernel 5.4, the node
# is fiu
shopt -s nullglob
for fiu in "$KERNEL_SYSFS_FIU"/*.fiu; do
KERNEL_FIU_ID="c0000000.fiu"
break
done
bind_host_mtd() {
set_gpio_direction 'SPI_SW_SELECT' high
if [[ -d ${KERNEL_SYSFS_FIU}/${KERNEL_FIU_ID} ]]; then
echo "${KERNEL_FIU_ID}" > "${KERNEL_SYSFS_FIU}"/unbind
fi
echo "${KERNEL_FIU_ID}" > "${KERNEL_SYSFS_FIU}"/bind
}
unbind_host_mtd() {
if [[ -d ${KERNEL_SYSFS_FIU}/${KERNEL_FIU_ID} ]]; then
echo "${KERNEL_FIU_ID}" > "${KERNEL_SYSFS_FIU}"/unbind
fi
set_gpio_direction 'SPI_SW_SELECT' low
}
trap unbind_host_mtd EXIT SIGHUP SIGINT SIGTERM
# Taken from /run/initramfs/update
# Given label name, return mtd node. e.g. `findmtd bmc` returns 'mtd0'
findmtd() {
m=$(grep -xl "$1" /sys/class/mtd/*/name)
m=${m%/name}
m=${m##*/}
echo $m
}
verify_host_bios() {
echo "BIOS verification start!"
# placeholder for verifying host BIOS. For now time BIOS read
# with dd
bind_host_mtd || { echo "Failed to bind FIU driver for host MTD"; return 1; }
pnor_mtd=$(findmtd pnor)
[[ -z "${pnor_mtd}" ]] && { echo "Failed to find host MTD partition!"; return 1; }
# Test timing by computing SHA256SUM.
sha256sum /dev/${pnor_mtd}ro
echo "BIOS verification complete!"
unbind_host_mtd
}
parse_pe_fru() {
pe_fruid=3
for i in {1..2};
do
mapper wait ${PE_PRESENT_OBJPATH[$(($i-1))]}
pe_prsnt_n="$(busctl get-property $SERVICE_NAME ${PE_PRESENT_OBJPATH[$(($i-1))]} \
$INTERFACE_NAME Present)"
if [[ ${pe_prsnt_n} == "b false" ]]; then
pe_fruid=$(($pe_fruid+1))
continue
fi
# Output is the i2c bus number for the PCIE cards on PE0/PE1
# i2c-0 -> i2c mux (addr: 0x71) -> PE0/PE1
# PE0: channel 0
# PE1: channel 1
pe_fru_bus="$(ls -al /sys/bus/i2c/drivers/pca954x/0-0071/ | grep channel \
| awk -F "/" '{print $(NF)}' | awk -F "-" '{print $2}' | sed -n "${i}p")"
# If the PE FRU EEPROM syspath does not exist, create it ("24c02" is the
# EEPROM part number) and perform a phosphor-read-eeprom
for ((j=0; j < ${#pe_eeprom_addr[@]}; j++));
do
i2cget -f -y $pe_fru_bus "0x${pe_eeprom_addr[$j]}" 0x01 > /dev/null 2>&1
if [ $? -eq 0 ]; then
if [ ! -f "/sys/bus/i2c/devices/$pe_fru_bus-00${pe_eeprom_addr[$j]}/eeprom" ]; then
echo 24c02 "0x${pe_eeprom_addr[$j]}" > "/sys/bus/i2c/devices/i2c-$pe_fru_bus/new_device"
fi
pe_fru_bus="/sys/bus/i2c/devices/$pe_fru_bus-00${pe_eeprom_addr[$j]}/eeprom"
phosphor-read-eeprom --eeprom $pe_fru_bus --fruid $pe_fruid
break
fi
done
pe_fruid=$(($pe_fruid+1))
done
}
check_power_status() {
res0="$(busctl get-property -j xyz.openbmc_project.State.Chassis \
/xyz/openbmc_project/state/chassis0 xyz.openbmc_project.State.Chassis \
CurrentPowerState | jq -r '.["data"]')"
echo $res0
}
clk_buf_bus_switch="11-0076"
clk_buf_driver="/sys/bus/i2c/drivers/pca954x/"
bind_clk_buf_switch() {
echo "Re-bind i2c bus 11 clk_buf_switch"
echo "${clk_buf_bus_switch}" > "${clk_buf_driver}"/bind
}
main() {
get_board_rev_id
get_board_sku_id
get_hsbp_board_rev_id
get_fan_board_rev_id
check_board_ver
if [[ "${BOARD_VER}" == "PREPVT" ]]; then
set_uart_en_low
fi
check_board_sku
if [[ $(check_power_status) != \
'xyz.openbmc_project.State.Chassis.PowerState.On' ]]; then
verify_host_bios
echo "Release host from reset!" >&2
set_gpio_direction 'RST_BMC_RSMRST_N' high
set_gpio_direction 'RST_KBRST_BMC_CPLD_N' high
# TODO: remove the hack once kernel driver is ready
# Set the GPIO states to preserve across reboots
set_gpio_persistence
echo "Starting host power!" >&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.On
sleep 1
bind_clk_buf_switch
else
echo "Host is already running, doing nothing!" >&2
fi
set_hdd_prsnt
parse_pe_fru
}
# Exit without running main() if sourced
return 0 2>/dev/null
main "$@"