summaryrefslogtreecommitdiff
path: root/meta-quanta/meta-gbs/recipes-gbs/gbs-sysinit/files/gbs-sysinit.sh
blob: 17074ddaff9954cc35068b3d8542427f2d6c8cf5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#!/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.Chassis0 \
        /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.Host0 \
        /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 "$@"