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