/ util / amdtools / update_efs_spi_speed
update_efs_spi_speed
  1  #!/usr/bin/env bash
  2  # SPDX-License-Identifier: BSD-3-Clause
  3  
  4  ROM="$1"
  5  declare -i NEW_SPEED="$2"
  6  
  7  readonly EFS_SIG_DWORD="55aa55aa"
  8  readonly FAST_SPEED_NEW_F15_MOD_60_6F_OFFSET=0x41
  9  readonly SPI_FASTSPEED_F17_MOD_00_2F_OFFSET=0x44
 10  readonly SPI_FASTSPEED_F17_MOD_30_3F_OFFSET=0x48
 11  
 12  # print out the very simple usage
 13  usage() {
 14    echo "Usage: $0 <ROM> <Speed>"
 15    echo "  Speed must be between 0 & 5"
 16    echo "    0: 66.66Mhz"
 17    echo "    1: 33.33MHz"
 18    echo "    2: 22.22MHz"
 19    echo "    3: 16.66MHz"
 20    echo "    4: 100MHz"
 21    echo "    5: 800KHz"
 22  }
 23  
 24  # Validate the input parameters
 25  if [[ $# -ne 2 || ! -f "${ROM}" || "${NEW_SPEED}" -lt 0 || "${NEW_SPEED}" -gt 5 ]]; then
 26    usage
 27    exit 1
 28  fi
 29  
 30  # Read a 32, 16, or 8 bit value from a location in a binary file
 31  getval() {
 32    local location=$1
 33    local length=$2
 34  
 35    if [[ ${length} -eq 1 ]]; then
 36      dd "if=${ROM}" bs=1 "skip=${location}" "count=${length}" 2>/dev/null | hexdump -v -e '1/1 "%02x\n"'
 37    elif [[ ${length} -eq 2 ]]; then
 38      dd "if=${ROM}" bs=1 "skip=${location}" "count=${length}" 2>/dev/null | hexdump -v -e '1/2 "%04x\n"'
 39    elif [[ ${length} -eq 4 ]]; then
 40      dd "if=${ROM}" bs=1 "skip=${location}" "count=${length}" 2>/dev/null | hexdump -v -e '1/4 "%08x\n"'
 41    else
 42      echo "Error: invalid value"
 43      exit 1
 44    fi
 45  }
 46  
 47  # Update a location in a binary
 48  # Note that the passed in value must be formatted correctly:
 49  # Each byte needs to be specified as "\\xXX" where X is a hex digit
 50  setval() {
 51    local location=$1
 52    local length=$2
 53    local hexval=$3
 54  
 55    # shellcheck disable=SC2059
 56    if ! printf "$hexval" | dd "of=${ROM}" bs=1 "seek=${location}" "count=${length}" conv=notrunc status=none; then
 57      echo "Error: Could not write to ${ROM}"
 58      exit 1
 59    fi
 60  }
 61  
 62  # Print the speed associated with the passed-in value
 63  showspeed() {
 64    local speedval=$1
 65    case ${speedval} in
 66    0 | 00) echo "0: 66.66Mhz" ;;
 67    1 | 01) echo "1: 33.33MHz" ;;
 68    2 | 02) echo "2: 22.22MHz" ;;
 69    3 | 03) echo "3: 16.66MHz" ;;
 70    4 | 04) echo "4: 100MHz" ;;
 71    5 | 05) echo "5: 800KHz" ;;
 72    ff) echo "Error: Speed not set" ;;
 73    *) echo "Error: Unknown speed (${speedval})" ;;
 74    esac
 75  }
 76  
 77  # Locate the SPI speed data and update it to the new speed
 78  update_efs() {
 79    local location=$1
 80    local updated_speed=0
 81  
 82    for speed_offset in FAST_SPEED_NEW_F15_MOD_60_6F_OFFSET SPI_FASTSPEED_F17_MOD_00_2F_OFFSET SPI_FASTSPEED_F17_MOD_30_3F_OFFSET; do
 83      local speed_val
 84      local speed_loc=$((location + speed_offset))
 85      speed_val=$(getval "${speed_loc}" "1")
 86  
 87      if [[ "${speed_val}" != "ff" ]]; then
 88        printf "Found speed value of %s at %#06x\n" "$(showspeed "${speed_val}")" "${speed_loc}"
 89        updated_speed=1
 90        setval "${speed_loc}" "1" "\\x0${NEW_SPEED}"
 91        speed_val=$(getval "${speed_loc}" "1")
 92        printf "New speed value: %s\n" "$(showspeed "${speed_val}")"
 93      fi
 94  
 95    done
 96    if [[ ${updated_speed} -eq 0 ]]; then
 97      echo "Error: Could not find speed value to update."
 98      exit 1
 99    fi
100  }
101  
102  # Find the EFS location and update the speed
103  main() {
104    local location
105    local val
106  
107    for i in {0..5}; do
108      location="$((0xffffff - (0x80000 << i) + 0x20000 + 1))"
109      val="$(getval "${location}" 4 )"
110      if [[ "${val}" == "${EFS_SIG_DWORD}" ]]; then
111        printf "EFS found at %#06x\n" "${location}"
112        update_efs "${location}"
113        exit 0
114      fi
115    done
116  
117    echo "Error: EFS not found in ${ROM}."
118    exit 1
119  }
120  
121  main