1#!/bin/bash 2# Copyright 2020 Google LLC 3# Copyright 2020 Quanta Computer Inc. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17# shellcheck source=meta-quanta/meta-gbs/recipes-gbs/gbs-sysinit/files/gbs-gpio-common.sh 18source /usr/libexec/gbs-gpio-common.sh 19 20WD1RCR_ADDR=0xf080103c 21CORSTC_ADDR=0xf080105c 22BOARD_VER="" # Set by check_board_ver 23pe_eeprom_addr=( 50 54 ) 24 25SERVICE_NAME="xyz.openbmc_project.Inventory.Manager" 26INTERFACE_NAME="xyz.openbmc_project.Inventory.Item" 27 28PE_PRESENT_OBJPATH=("/xyz/openbmc_project/inventory/system/chassis/entity/pe_slot0_prsnt" 29"/xyz/openbmc_project/inventory/system/chassis/entity/pe_slot1_prsnt") 30SATA0_PRESENT_OBJPATH="/xyz/openbmc_project/inventory/system/chassis/entity/sata0_prsnt" 31 32set_gpio_persistence() { 33 reg_val=$(devmem ${WD1RCR_ADDR} 32) 34 # Clear bit 16-23 to perserve all GPIO states across warm resets 35 reg_val=$(printf "0x%08x" $((reg_val & ~0xff0000))) 36 echo "Setting WD1RCR_ADDR to ${reg_val}" 37 devmem "${WD1RCR_ADDR}" 32 "${reg_val}" 38 39 reg_val=$(devmem ${CORSTC_ADDR} 32) 40 # Clear bit 16-23 of CORSTC 41 reg_val=$(printf "0x%08x" $((reg_val & ~0xff0000))) 42 echo "Setting CORSTC_ADDR to ${reg_val}" 43 devmem "${CORSTC_ADDR}" 32 "${reg_val}" 44} 45 46get_board_rev_id() { 47 echo "$(get_gpio_value 'BMC_BRD_REV_ID7')"\ 48 "$(get_gpio_value 'BMC_BRD_REV_ID6')"\ 49 "$(get_gpio_value 'BMC_BRD_REV_ID5')"\ 50 "$(get_gpio_value 'BMC_BRD_REV_ID4')"\ 51 "$(get_gpio_value 'BMC_BRD_REV_ID3')"\ 52 "$(get_gpio_value 'BMC_BRD_REV_ID2')"\ 53 "$(get_gpio_value 'BMC_BRD_REV_ID1')"\ 54 "$(get_gpio_value 'BMC_BRD_REV_ID0')"\ 55 | sed 's/ //g' > ~/board_rev_id.txt 56} 57 58get_board_sku_id() { 59 echo "$(get_gpio_value 'BMC_BRD_SKU_ID3')"\ 60 "$(get_gpio_value 'BMC_BRD_SKU_ID2')"\ 61 "$(get_gpio_value 'BMC_BRD_SKU_ID1')"\ 62 "$(get_gpio_value 'BMC_BRD_SKU_ID0')"\ 63 | sed 's/ //g' > ~/board_sku_id.txt 64} 65 66get_hsbp_board_rev_id() { 67 echo "$(get_gpio_value 'HSBP_BRD_REV_ID3')"\ 68 "$(get_gpio_value 'HSBP_BRD_REV_ID2')"\ 69 "$(get_gpio_value 'HSBP_BRD_REV_ID1')"\ 70 "$(get_gpio_value 'HSBP_BRD_REV_ID0')"\ 71 | sed 's/ //g' > ~/hsbp_board_rev_id.txt 72} 73 74get_fan_board_rev_id() { 75 echo "$(get_gpio_value 'FAN_BRD_REV_ID1')"\ 76 "$(get_gpio_value 'FAN_BRD_REV_ID0')"\ 77 | sed 's/ //g' > ~/fan_board_rev_id.txt 78} 79 80check_board_ver() { 81 # Sets BOARD_VER to either "PREPVT" or "PVT" 82 # 83 # BOARD_REV_ID[7:6] = 84 # 0x00 - EVT 85 # 0x01 - DVT 86 # 0x10 - PVT 87 # 0x11 - MP 88 89 rev7_val=$(get_gpio_value 'BMC_BRD_REV_ID7') 90 if (( rev7_val == 0 )); then 91 echo "EVT/DVT rev!" 92 BOARD_VER="PREPVT" 93 else 94 echo "PVT/MP rev!" 95 BOARD_VER="PVT" 96 fi 97} 98 99check_board_sku() { 100 sku1_val=$(get_gpio_value 'BMC_BRD_SKU_ID1') 101 if (( sku1_val == 1 )); then 102 echo "GBS SKU!" 103 else 104 echo "Other SKU!" 105 fi 106} 107 108set_uart_en_low() { 109 # GPIO76 UART_EN polarity inverted between DVT/PVT 110 # Pin direction was set high in the kernel. 111 set_gpio_direction 'FM_BMC_CPU_UART_EN' low 112} 113 114set_hdd_prsnt() { 115 # On PVT need to forward SATA0_PRSNT_N to HDD_PRSNT_N 116 # The signal is safe to set on DVT boards so just set universally. 117 mapper wait ${SATA0_PRESENT_OBJPATH} 118 sata_prsnt_n="$(busctl get-property $SERVICE_NAME ${SATA0_PRESENT_OBJPATH} \ 119 $INTERFACE_NAME Present)" 120 121 # sata_prsnt_n is active low => value "true" means low 122 if [[ ${sata_prsnt_n} == "b true" ]]; then 123 set_gpio_direction 'HDD_PRSNT_N' low 124 else 125 set_gpio_direction 'HDD_PRSNT_N' high 126 fi 127} 128 129KERNEL_FIU_ID="c0000000.spi" 130KERNEL_SYSFS_FIU="/sys/bus/platform/drivers/NPCM-FIU" 131 132# the node of FIU is spi for kernel 5.10, but 133# for less than or equal kernel 5.4, the node 134# is fiu 135if ls "$KERNEL_SYSFS_FIU"/*.fiu 1> /dev/null 2>&1; then 136 KERNEL_FIU_ID="c0000000.fiu" 137fi 138 139bind_host_mtd() { 140 set_gpio_direction 'SPI_SW_SELECT' high 141 if [[ -d ${KERNEL_SYSFS_FIU}/${KERNEL_FIU_ID} ]]; then 142 echo "${KERNEL_FIU_ID}" > "${KERNEL_SYSFS_FIU}"/unbind 143 fi 144 echo "${KERNEL_FIU_ID}" > "${KERNEL_SYSFS_FIU}"/bind 145} 146 147unbind_host_mtd() { 148 if [[ -d ${KERNEL_SYSFS_FIU}/${KERNEL_FIU_ID} ]]; then 149 echo "${KERNEL_FIU_ID}" > "${KERNEL_SYSFS_FIU}"/unbind 150 fi 151 set_gpio_direction 'SPI_SW_SELECT' low 152} 153trap unbind_host_mtd EXIT SIGHUP SIGINT SIGTERM 154 155# Taken from /run/initramfs/update 156# Given label name, return mtd node. e.g. `findmtd bmc` returns 'mtd0' 157findmtd() { 158 m=$(grep -xl "$1" /sys/class/mtd/*/name) 159 m=${m%/name} 160 m=${m##*/} 161 echo "$m" 162} 163 164verify_host_bios() { 165 echo "BIOS verification start!" 166 167 # placeholder for verifying host BIOS. For now time BIOS read 168 # with dd 169 bind_host_mtd || { echo "Failed to bind FIU driver for host MTD"; return 1; } 170 171 pnor_mtd=$(findmtd pnor) 172 [[ -z "${pnor_mtd}" ]] && { echo "Failed to find host MTD partition!"; return 1; } 173 174 # Test timing by computing SHA256SUM. 175 sha256sum "/dev/${pnor_mtd}ro" 176 177 echo "BIOS verification complete!" 178 unbind_host_mtd 179} 180 181parse_pe_fru() { 182 pe_fruid=3 183 for i in {1..2}; 184 do 185 mapper wait "${PE_PRESENT_OBJPATH[$((i-1))]}" 186 pe_prsnt_n="$(busctl get-property $SERVICE_NAME "${PE_PRESENT_OBJPATH[$((i-1))]}" \ 187 $INTERFACE_NAME Present)" 188 189 if [[ ${pe_prsnt_n} == "b false" ]]; then 190 pe_fruid=$((pe_fruid+1)) 191 continue 192 fi 193 194 # Output is the i2c bus number for the PCIE cards on PE0/PE1 195 # i2c-0 -> i2c mux (addr: 0x71) -> PE0/PE1 196 # PE0: channel 0 197 # PE1: channel 1 198 # shellcheck disable=SC2010 199 pe_fru_bus="$(ls -al /sys/bus/i2c/drivers/pca954x/0-0071/ | grep channel \ 200 | awk -F "/" '{print $(NF)}' | awk -F "-" '{print $2}' | sed -n "${i}p")" 201 202 # If the PE FRU EEPROM syspath does not exist, create it ("24c02" is the 203 # EEPROM part number) and perform a phosphor-read-eeprom 204 for ((j=0; j < ${#pe_eeprom_addr[@]}; j++)); 205 do 206 if i2cget -f -y "$pe_fru_bus" "0x${pe_eeprom_addr[$j]}" 0x01 > /dev/null 2>&1 ; then 207 if [ ! -f "/sys/bus/i2c/devices/$pe_fru_bus-00${pe_eeprom_addr[$j]}/eeprom" ]; then 208 echo 24c02 "0x${pe_eeprom_addr[$j]}" > "/sys/bus/i2c/devices/i2c-$pe_fru_bus/new_device" 209 fi 210 pe_fru_bus="/sys/bus/i2c/devices/$pe_fru_bus-00${pe_eeprom_addr[$j]}/eeprom" 211 phosphor-read-eeprom --eeprom "$pe_fru_bus" --fruid $pe_fruid 212 break 213 fi 214 done 215 pe_fruid=$((pe_fruid+1)) 216 done 217} 218 219check_power_status() { 220 res0="$(busctl get-property -j xyz.openbmc_project.State.Chassis \ 221 /xyz/openbmc_project/state/chassis0 xyz.openbmc_project.State.Chassis \ 222 CurrentPowerState | jq -r '.["data"]')" 223 echo "$res0" 224} 225 226clk_buf_bus_switch="11-0076" 227clk_buf_driver="/sys/bus/i2c/drivers/pca954x/" 228 229bind_clk_buf_switch() { 230 echo "Re-bind i2c bus 11 clk_buf_switch" 231 echo "${clk_buf_bus_switch}" > "${clk_buf_driver}"/bind 232} 233 234main() { 235 get_board_rev_id 236 get_board_sku_id 237 get_hsbp_board_rev_id 238 get_fan_board_rev_id 239 240 check_board_ver 241 if [[ "${BOARD_VER}" == "PREPVT" ]]; then 242 set_uart_en_low 243 fi 244 245 check_board_sku 246 247 if [[ $(check_power_status) != \ 248 'xyz.openbmc_project.State.Chassis.PowerState.On' ]]; then 249 verify_host_bios 250 251 echo "Release host from reset!" >&2 252 set_gpio_direction 'RST_BMC_RSMRST_N' high 253 set_gpio_direction 'RST_KBRST_BMC_CPLD_N' high 254 # TODO: remove the hack once kernel driver is ready 255 # Set the GPIO states to preserve across reboots 256 set_gpio_persistence 257 258 echo "Starting host power!" >&2 259 busctl set-property xyz.openbmc_project.State.Host \ 260 /xyz/openbmc_project/state/host0 \ 261 xyz.openbmc_project.State.Host \ 262 RequestedHostTransition s \ 263 xyz.openbmc_project.State.Host.Transition.On 264 265 sleep 1 266 bind_clk_buf_switch 267 else 268 echo "Host is already running, doing nothing!" >&2 269 fi 270 271 set_hdd_prsnt 272 parse_pe_fru 273} 274 275# Exit without running main() if sourced 276if ! (return 0 2>/dev/null) ; then 277 main "$@" 278fi 279