xref: /aosp_15_r20/external/coreboot/util/amdtools/update_efs_spi_speed (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1#!/usr/bin/env bash
2# SPDX-License-Identifier: BSD-3-Clause
3
4ROM="$1"
5declare -i NEW_SPEED="$2"
6
7readonly EFS_SIG_DWORD="55aa55aa"
8readonly FAST_SPEED_NEW_F15_MOD_60_6F_OFFSET=0x41
9readonly SPI_FASTSPEED_F17_MOD_00_2F_OFFSET=0x44
10readonly SPI_FASTSPEED_F17_MOD_30_3F_OFFSET=0x48
11
12# print out the very simple usage
13usage() {
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
25if [[ $# -ne 2 || ! -f "${ROM}" || "${NEW_SPEED}" -lt 0 || "${NEW_SPEED}" -gt 5 ]]; then
26  usage
27  exit 1
28fi
29
30# Read a 32, 16, or 8 bit value from a location in a binary file
31getval() {
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
50setval() {
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
63showspeed() {
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
78update_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
103main() {
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
121main
122