coreboot-libre-fam15h-rdimm/3rdparty/chromeec/util/flash_ec

1409 lines
34 KiB
Bash
Executable File

#!/bin/bash
# Copyright 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
SCRIPT="$(readlink -f "$0")"
SCRIPT_DIR="$(dirname "$SCRIPT")"
EC_DIR="$(readlink -f "${SCRIPT_DIR}/..")"
if [[ "$(basename "${EC_DIR}")" != "ec" ]]; then
EC_DIR=
fi
# Loads script libraries.
. "/usr/share/misc/shflags" || exit 1
# Redirects tput to stderr, and drop any error messages.
tput2() {
tput "$@" 1>&2 2>/dev/null || true
}
error() {
tput2 bold && tput2 setaf 1
echo "ERROR: $*" >&2
tput2 sgr0
}
info() {
tput2 bold && tput2 setaf 2
echo "INFO: $*" >&2
tput2 sgr0
}
warn() {
tput2 bold && tput2 setaf 3
echo "WARNING: $*" >&2
tput2 sgr0
}
die() {
[ -z "$*" ] || error "$@"
exit 1
}
# Include a board name to the BOARDS_${EC_CHIP} array below ONLY IF servod is
# not aware of its 'ec_chip'. If servod becomes able to answer 'ec_chip'
# for the board, remove it from BOARDS_XXXX array below.
BOARDS_IT83XX=(
glkrvp_ite
it83xx_evb
reef_it8320
tglrvpu_ite
tglrvpy_ite
)
BOARDS_STM32=(
bloonchipper
chell_pd
coffeecake
chocodile_bec
chocodile_vpdmcu
dartmonkey
glados_pd
hatch_fp
jerry
magnemite
masterball
minimuffin
nami_fp
nocturne_fp
oak_pd
pit
plankton
rainier
samus_pd
staff
strago_pd
wand
whiskers
zinger
)
BOARDS_STM32_PROG_EN=(
plankton
)
BOARDS_STM32_DFU=(
dingdong
hoho
twinkie
discovery
servo_v4
servo_micro
sweetberry
polyberry
stm32f446e-eval
tigertail
fluffy
)
BOARDS_NPCX_5M5G_JTAG=(
npcx_evb
npcx_evb_arm
)
BOARDS_NPCX_5M6G_JTAG=(
)
BOARDS_NPCX_7M6X_JTAG=(
)
BOARDS_NPCX_7M7X_JTAG=(
npcx7_evb
)
BOARDS_NPCX_SPI=(
glkrvp
)
BOARDS_SPI_1800MV=(
coral
reef
)
BOARDS_RAIDEN=(
coral
eve
fizz
flapjack
kukui
nami
nautilus
poppy
rammus
reef
scarlet
soraka
)
DEFAULT_PORT="${SERVOD_PORT:-9999}"
BITBANG_RATE="57600" # Could be overwritten by a command line option.
# Flags
DEFINE_integer bitbang_rate "${BITBANG_RATE}" \
"UART baud rate to use when bit bang programming, "\
"standard UART rates from 9600 to 57600 are supported."
DEFINE_string board "${DEFAULT_BOARD}" \
"The board to run debugger on."
DEFINE_string chip "" \
"The chip to run debugger on."
DEFINE_string image "" \
"Full pathname of the EC firmware image to flash."
DEFINE_string logfile "" \
"Stm32 only: pathname of the file to store communications log."
DEFINE_string offset "0" \
"Offset where to program the image from."
DEFINE_integer port "${DEFAULT_PORT}" \
"Port to communicate to servo on."
DEFINE_boolean raiden "${FLAGS_FALSE}" \
"Use raiden_debug_spi programmer"
DEFINE_string read "" "Pathname of the file to store EC firmware image."
DEFINE_boolean ro "${FLAGS_FALSE}" \
"Write only the read-only partition"
DEFINE_integer timeout 600 \
"Timeout for flashing the EC, measured in seconds."
DEFINE_boolean verbose "${FLAGS_FALSE}" \
"Verbose hw control logging"
DEFINE_boolean verify "${FLAGS_FALSE}" \
"Verify EC firmware image after programming."
# Parse command line
FLAGS_HELP="usage: $0 [flags]"
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
if [[ $# -gt 0 ]]; then
die "invalid arguments: \"$*\""
fi
# Error messages
MSG_PROGRAM_FAIL="Failed to flash EC firmware image"
MSG_READ_FAIL="Failed to read EC firmware image"
MSG_VERIFY_FAIL="Failed to verify EC firmware image."
set -e
DUT_CONTROL_CMD=( "dut-control" "--port=${FLAGS_port}" )
DUT_CTRL_PREFIX=""
function dut_control() {
local DUT_CTRL_CML=( "${DUT_CONTROL_CMD[@]}" )
for p in $@ ; do
# Only add the prefix if the arg is a control name.
if [[ ${p} != -* ]] ; then
p="${DUT_CTRL_PREFIX}${p}"
fi
DUT_CTRL_CML+=( "$p" )
done
if [ "${FLAGS_verbose}" = ${FLAGS_TRUE} ]; then
echo "${DUT_CTRL_CML[*]}" 1>&2
fi
"${DUT_CTRL_CML[@]}" >/dev/null
}
function dut_control_or_die {
dut_control "$@" || die "dut-control $* exited $? (non-zero)"
}
function dut_control_get() {
if [ $# -gt 1 ]; then
error "${FUNCNAME[0]} failed: more than one argument: $@"
return 1
fi
local ARGS DUT_GETVAL RETVAL
ARGS=( "${DUT_CONTROL_CMD[@]}" "-o" "${DUT_CTRL_PREFIX}$1" )
RETVAL=0
# || statement is attached to avoid an exit if error exit is enabled.
DUT_GETVAL=$( "${ARGS[@]}" ) || RETVAL="$?"
if (( "${RETVAL}" )) ; then
warn "${FUNCNAME[0]} failed: ${ARGS[*]} returned ${RETVAL}."
return "${RETVAL}"
fi
echo "${DUT_GETVAL}"
}
BOARD=${FLAGS_board}
in_array() {
local n=$#
local value=${!n}
for (( i=1; i<$#; i++ )) do
if [ "${!i}" == "${value}" ]; then
return 0
fi
done
return 1
}
declare -a SUPPORTED_CHIPS
if $(in_array "${BOARDS_STM32[@]}" "${BOARD}"); then
SUPPORTED_CHIPS+=("stm32")
fi
if $(in_array "${BOARDS_STM32_DFU[@]}" "${BOARD}"); then
SUPPORTED_CHIPS+=("stm32_dfu")
fi
if $(in_array "${BOARDS_NPCX_5M5G_JTAG[@]}" "${BOARD}"); then
SUPPORTED_CHIPS+=("npcx_5m5g_jtag")
fi
if $(in_array "${BOARDS_NPCX_5M6G_JTAG[@]}" "${BOARD}"); then
SUPPORTED_CHIPS+=("npcx_5m6g_jtag")
fi
if $(in_array "${BOARDS_NPCX_7M6X_JTAG[@]}" "${BOARD}"); then
SUPPORTED_CHIPS+=("npcx_7m6x_jtag")
fi
if $(in_array "${BOARDS_NPCX_7M7X_JTAG[@]}" "${BOARD}"); then
SUPPORTED_CHIPS+=("npcx_7m7x_jtag")
fi
if $(in_array "${BOARDS_NPCX_SPI[@]}" "${BOARD}"); then
SUPPORTED_CHIPS+=("npcx_spi")
fi
if $(in_array "${BOARDS_IT83XX[@]}" "${BOARD}"); then
SUPPORTED_CHIPS+=("it83xx")
fi
if [[ ${#SUPPORTED_CHIPS[@]} -eq 0 && -n "${FLAGS_chip}" ]]; then
SUPPORTED_CHIPS+="${FLAGS_chip}"
fi
if [[ ${#SUPPORTED_CHIPS[@]} -eq 0 ]]; then
SERVO_EC_CHIP="$(dut_control_get ec_chip)"
SERVO_EC_CHIP="${SERVO_EC_CHIP,,}"
if [[ "${SERVO_EC_CHIP}" =~ "unknown" || -z "${SERVO_EC_CHIP}" ]]; then
die "Please check that servod is running or," \
"manually specify either --board or --chip."
fi
SUPPORTED_CHIPS+=("${SERVO_EC_CHIP}")
fi
if [[ ${#SUPPORTED_CHIPS[@]} -eq 0 ]]; then
# This happens if ${FLAGS_board} is not known in this flash_ec yet,
# ${FLAGS_chip} is not given, and servod doesn't know ec_chip.
# In this case, '--chip' should be specified in the command line.
die "board '${BOARD}' not supported." \
"Please check that servod is running, or manually specify --chip."
elif [[ ${#SUPPORTED_CHIPS[@]} -eq 1 ]]; then
CHIP="${SUPPORTED_CHIPS[0]}"
elif [ -n "${FLAGS_chip}" ]; then
if $(in_array "${SUPPORTED_CHIPS[@]}" "${FLAGS_chip}"); then
CHIP="${FLAGS_chip}"
else
die "board ${BOARD} only supports (${SUPPORTED_CHIPS[@]})," \
"not ${FLAGS_chip}."
fi
else
# Ideally, ec_chip per servo_type should be specified in servo overlay
# file, instead of having multiple board-to-chip mapping info in this
# script. Please refer to crrev.com/c/1496460 for example.
die "board ${BOARD} supports multiple chips" \
"(${FILTERED_CHIPS[@]}). Use --chip= to choose one."
fi
if [ -n "${FLAGS_chip}" -a "${CHIP}" != "${FLAGS_chip}" ]; then
die "board ${BOARD} doesn't use chip ${FLAGS_chip}"
fi
if [[ "${CHIP}" = "stm32_dfu" ]]; then
NEED_SERVO="no"
fi
# Servo variables management
case "${BOARD}" in
chocodile_bec ) MCU="usbpd" ;;
oak_pd|samus_pd|strago_pd ) MCU="usbpd" ;;
chell_pd|glados_pd ) MCU="usbpd" ;;
bloonchipper|dartmonkey|hatch_fp|nami_fp|nocturne_fp ) MCU="usbpd" ;;
dingdong|hoho|twinkie ) DUT_CONTROL_CMD=( "true" ); MCU="ec" ;;
*) MCU="ec" ;;
esac
case "${CHIP}" in
"stm32"|"npcx_spi"|"npcx_int_spi"|"it83xx"|"npcx_uut") ;;
*)
if [[ -n "${FLAGS_read}" ]]; then
die "The flag is not yet supported on ${CHIP}."
fi
# If verification is not supported, then show a warning message.
# Keep it running however.
if [[ "${FLAGS_verify}" == ${FLAGS_TRUE} ]]; then
warn "Ignoring '--verify'" \
"since read is not supported on ${CHIP}."
fi
;;
esac
SERVO_TYPE="$(dut_control_get servo_type || :)"
if [[ ${SERVO_TYPE} =~ servo_v4_with_.*_and_.* ]] ; then
# If there are two devices, servo v4 type will show both devices. The
# default device is first. The other device is second.
# servo_type:servo_v4_with_servo_micro_and_ccd_cr50
SECOND_DEVICE="${SERVO_TYPE#*_and_}"
ACTIVE_DEVICE="$(dut_control_get active_v4_device || :)"
SERVO_TYPE="servo_v4_with_${ACTIVE_DEVICE}"
# Controls sent through the default device don't have a prefix. The
# second device controls do. If the default device isn't active, we
# need to use the second device controls to send commands. Use the
# prefix for all dut control commands.
if [[ "${SECOND_DEVICE}" = "${ACTIVE_DEVICE}" ]] ; then
DUT_CTRL_PREFIX="${ACTIVE_DEVICE}."
fi
fi
servo_has_warm_reset() {
dut_control -i warm_reset >/dev/null 2>&1
}
servo_has_cold_reset() {
dut_control -i cold_reset >/dev/null 2>&1
}
servo_has_dut_i2c_mux() {
dut_control -i dut_i2c_mux >/dev/null 2>&1
}
# reset the EC
toad_ec_hard_reset() {
if dut_control cold_reset 2>/dev/null ; then
dut_control cold_reset:on
dut_control cold_reset:off
else
info "you probably need to hard-reset your EC manually"
fi
}
servo_ec_hard_reset_or_die() {
dut_control_or_die cold_reset:on
dut_control_or_die cold_reset:off
}
servo_ec_hard_reset() {
dut_control cold_reset:on
dut_control cold_reset:off
}
servo_usbpd_hard_reset() {
dut_control usbpd_reset:on sleep:0.5 usbpd_reset:off
}
servo_sh_hard_reset() {
dut_control sh_reset:on
dut_control sh_reset:off
}
ccd_cr50_ec_hard_reset() {
servo_ec_hard_reset
}
ec_reset() {
stype=${SERVO_TYPE}
if [[ "${SERVO_TYPE}" =~ "servo" ]] ; then
stype=servo
fi
if [[ -n "${stype}" ]]; then
eval ${stype}_${MCU}_hard_reset
fi
}
# force the EC to boot in serial monitor mode
toad_ec_boot0() {
dut_control boot_mode:$1
}
ccd_ec_boot0() {
info "Using CCD $2."
dut_control ccd_ec_boot_mode_$2:$1
}
servo_ec_boot0() {
dut_control ec_boot_mode:$1
}
servo_usbpd_boot0() {
dut_control usbpd_boot_mode:$1
}
servo_sh_boot0() {
dut_control sh_boot_mode:$1
}
ec_switch_boot0() {
on_value=$1
# Enable programming GPIOs
if $(in_array "${BOARDS_STM32_PROG_EN[@]}" "${BOARD}"); then
servo_save_add "prog_en"
dut_control prog_en:yes
fi
if [[ "${SERVO_TYPE}" =~ "ccd_cr50" ]] ; then
stype=ccd
elif [[ "${SERVO_TYPE}" =~ "servo" ]] ; then
stype=servo
else
stype=${SERVO_TYPE}
if [[ "${SERVO_TYPE}" =~ "toad" ]] ; then
if [[ "${on_value}" == "on" ]] ; then
on_value="yes"
else
on_value="no"
fi
fi
fi
eval ${stype}_${MCU}_boot0 "${on_value}" $2
}
ec_enable_boot0() {
ec_switch_boot0 "on" $1
}
ec_disable_boot0() {
ec_switch_boot0 "off" $1
}
# Returns 0 on success (if on beaglebone)
on_servov3() {
grep -qs '^CHROMEOS_RELEASE_BOARD=beaglebone_servo' /etc/lsb-release
}
# Returns 0 on success (if raiden should be used instead of servo)
error_reported= # Avoid double printing the error message.
on_raiden() {
if [[ "${SERVO_TYPE}" =~ "servo_v4" ]] || \
[[ "${SERVO_TYPE}" =~ "ccd_cr50" ]] || \
[[ "${SERVO_TYPE}" =~ "servo_micro" ]]; then
return 0
fi
if [ -z "${BOARD}" ]; then
[ "${FLAGS_raiden}" = ${FLAGS_TRUE} ] && return 0 || return 1
fi
if [ "${FLAGS_raiden}" = ${FLAGS_TRUE} ]; then
if in_array "${BOARDS_RAIDEN[@]}" "${BOARD}"; then
return 0
fi
if [ -z "${error_reported}" ]; then
error_reported="y"
die "raiden mode not supported on ${BOARD}" >&2
fi
fi
return 1
}
declare -a DELETE_LIST # Array of file/dir names to delete at exit
# Put back the servo and the system in a clean state at exit
FROZEN_PIDS=""
cleanup() {
for pid in ${FROZEN_PIDS}; do
info "Sending SIGCONT to process ${pid}!"
kill -CONT "${pid}"
done
# Delete all files or directories in DELETE_LIST.
for item in "${DELETE_LIST[@]}"; do
if [[ -e "${item}" ]]; then
rm -rf "${item}" &> /dev/null
fi
done
if [ "${CHIP}" = "it83xx" ]; then
if [ "${SERVO_TYPE}" = "servo_v2" ]; then
info "Reinitializing ftdi_i2c interface"
# Ask servod to close its FTDI I2C interface because it
# could be open or closed at this point. Using
# ftdii2c_cmd:close when it's already closed is okay,
# however ftdii2c_cmd:open when it's already open
# triggers an error.
#
# If there is a simple, reliable way to detect whether
# servod FTDI I2C interface is open or closed, it would
# be preferable to check and only re-initialize if it's
# closed. Patches welcome.
dut_control ftdii2c_cmd:close
dut_control ftdii2c_cmd:init
dut_control ftdii2c_cmd:open
dut_control ftdii2c_cmd:setclock
fi
# Let the AP boot back up.
if servo_has_warm_reset; then
dut_control warm_reset:off
fi
fi
servo_restore
if [ "${CHIP}" = "stm32" -o "${CHIP}" = "npcx_uut" ]; then
dut_control "${MCU}"_boot_mode:off
fi
if [[ "${SERVO_TYPE}" =~ "ccd_cr50" ]]; then
dut_control ccd_ec_boot_mode_uut:off
dut_control ccd_ec_boot_mode_bitbang:off
fi
if ! on_raiden || servo_has_cold_reset; then
ec_reset
fi
}
trap cleanup EXIT
# Possible default EC images
if [ "${FLAGS_ro}" = ${FLAGS_TRUE} ] ; then
EC_FILE=ec.RO.flat
else
EC_FILE=ec.bin
fi
LOCAL_BUILD=
if [[ -n "${EC_DIR}" ]]; then
if [ "${FLAGS_ro}" = ${FLAGS_TRUE} ] ; then
LOCAL_BUILD="${EC_DIR}/build/${BOARD}/RO/${EC_FILE}"
else
LOCAL_BUILD="${EC_DIR}/build/${BOARD}/${EC_FILE}"
fi
fi
# Get baseboard from build system if present
BASEBOARD=
# We do not want to exit script if make call fails; we turn -e back on after
# setting BASEBOARD
set +e
if [[ -n "${EC_DIR}" ]]; then
BASEBOARD=$(make --quiet -C ${EC_DIR} BOARD=${BOARD} print-baseboard \
2>/dev/null)
elif [[ -d "${HOME}/trunk/src/platform/ec" ]]; then
BASEBOARD=$(make --quiet -C ${HOME}/trunk/src/platform/ec \
BOARD=${BOARD} print-baseboard 2>/dev/null)
else
info "Could not find ec build folder to calculate baseboard."
fi
if [ $? -ne 0 ]; then
info "EC build system didn't recognize ${BOARD}. Assuming no baseboard."
fi
set -e
if [[ -n "${BASEBOARD}" ]]; then
EMERGE_BUILD=/build/${BASEBOARD}/firmware/${BOARD}/${EC_FILE}
else
EMERGE_BUILD=/build/${BOARD}/firmware/${EC_FILE}
fi
# Find the EC image to use
function ec_image() {
# No image specified on the command line, try default ones
if [[ -n "${FLAGS_image}" ]] ; then
if [ -f "${FLAGS_image}" ] || \
[ "${FLAGS_image}" == "-" ]; then
echo "${FLAGS_image}"
return
fi
die "Invalid image path : ${FLAGS_image}"
else
if [ -f "${LOCAL_BUILD}" ]; then
echo "${LOCAL_BUILD}"
return
fi
if [ -f "${EMERGE_BUILD}" ]; then
echo "${EMERGE_BUILD}"
return
fi
fi
die "no EC image found : build one or specify one."
}
# Find the EC UART provided by servo.
function servo_ec_uart() {
SERVOD_FAIL="Cannot communicate with servod. Is servod running?"
PTY=$(dut_control_get raw_${MCU}_uart_pty ||
dut_control_get ${MCU}_uart_pty)
if [[ -z "${PTY}" ]]; then
die "${SERVOD_FAIL}"
fi
echo $PTY
}
# Not every control is supported on every servo type. Therefore, define which
# controls are supported by each servo type.
servo_v2_VARS=( "cold_reset" )
servo_micro_VARS=( "cold_reset" )
servo_v4_with_ccd_cr50_VARS=( "cold_reset" )
# Some servo boards use the same controls.
servo_v3_VARS=( "${servo_v2_VARS[@]}" )
servo_v4_with_servo_micro_VARS=( "${servo_micro_VARS[@]}" )
toad_VARS=( "boot_mode" )
declare -a save
#######################################
# Store DUT control value to restore.
# Arguments:
# $1: Control name
# $2: (optional) Value to restore for the name at exit.
#######################################
function servo_save_add() {
local CTRL_RESULT=
case $# in
1) CTRL_RESULT="$( "${DUT_CONTROL_CMD[@]}" \
"${DUT_CTRL_PREFIX}$@" )"
if [[ -n "${CTRL_RESULT}" ]]; then
# Don't save the control with the prefix, because
# dut_control will add the prefix again when we restore
# the settings.
save+=( "${CTRL_RESULT#$DUT_CTRL_PREFIX}" )
fi
;;
2) save+=( "$1:$2" )
;;
*) die "${FUNCNAME[0]} failed: arguments error"
;;
esac
}
function servo_save() {
local SERVO_VARS_NAME="${SERVO_TYPE}_VARS[@]"
for ctrl in "${!SERVO_VARS_NAME}"; do
servo_save_add "${ctrl}"
done
if [[ "${SERVO_TYPE}" == "servo_v2" ]]; then
servo_save_add "i2c_mux_en"
servo_save_add "i2c_mux"
dut_control i2c_mux_en:on
dut_control i2c_mux:remote_adc
fi
}
function servo_restore() {
info "Restoring servo settings..."
for ctrl in "${save[@]}"; do
if [[ -n "${ctrl}" ]]; then
dut_control "${ctrl}"
fi
done
}
function claim_pty() {
if grep -q cros_sdk /proc/1/cmdline; then
die "You must run this tool in a chroot that was entered with" \
"'cros_sdk --no-ns-pid' (see crbug.com/444931 for details)"
fi
if [[ -z "$1" ]]; then
warn "No parameter passed to claim_pty()"
return
fi
# Disconnect the EC-3PO interpreter from the UART since it will
# interfere with flashing.
servo_save_add "${MCU}_ec3po_interp_connect"
dut_control ${MCU}_ec3po_interp_connect:off || \
warn "hdctools cannot disconnect the EC-3PO interpreter from" \
"the UART."
pids=$(lsof -FR 2>/dev/null -- $1 | tr -d 'pR')
FROZEN_PIDS=""
# reverse order to SIGSTOP parents before children
for pid in $(echo ${pids} | tac -s " "); do
if ps -o cmd= "${pid}" | grep -qE "(servod|/sbin/init)"; then
info "Skip stopping servod or init: process ${pid}."
else
info "Sending SIGSTOP to process ${pid}!"
FROZEN_PIDS+=" ${pid}"
sleep 0.02
kill -STOP ${pid}
fi
done
}
function get_serial() {
if [[ "${SERVO_TYPE}" =~ "servo_v4_with_servo_micro" ]]; then
if [[ -z "${BOARD}" ]]; then
sn_ctl="servo_micro_"
else
sn_ctl="servo_micro_for_${BOARD}_"
fi
elif [[ "${SERVO_TYPE}" =~ "_with_ccd" ]] ; then
sn_ctl="ccd_"
else
# If it's none of the above, the main serialname will do.
sn_ctl=""
fi
dut_control_get "${sn_ctl}serialname"
}
# Board specific flashing scripts
# helper function for using servo v2/3 with openocd
function flash_openocd() {
OCD_CFG="servo.cfg"
if [[ -z "${EC_DIR}" ]]; then
# check if we're on beaglebone
if [[ -e "/usr/share/ec-devutils" ]]; then
OCD_PATH="/usr/share/ec-devutils"
else
die "Cannot locate openocd configs"
fi
else
OCD_PATH="${EC_DIR}/util/openocd"
fi
servo_save_add "jtag_buf_on_flex_en"
servo_save_add "jtag_buf_en"
dut_control jtag_buf_on_flex_en:on
dut_control jtag_buf_en:on
sudo timeout -k 10 -s 9 "${FLAGS_timeout}" \
openocd -s "${OCD_PATH}" -f "${OCD_CFG}" -f "${OCD_CHIP_CFG}" \
-c "${OCD_CMDS}" || \
die "Failed to program ${IMG}"
}
# helper function for using servo with flashrom
function flash_flashrom() {
TOOL_PATH="${EC_DIR}/build/${BOARD}/util:/usr/sbin/:$PATH"
FLASHROM=$(PATH="${TOOL_PATH}" which flashrom)
if on_servov3; then
FLASHROM_ARGS="-p linux_spi"
elif on_raiden; then
if [[ "${SERVO_TYPE}" =~ "servo_micro" ]]; then
# Servo micro doesn't use the "target" parameter.
FLASHROM_ARGS="-p raiden_debug_spi:"
else
FLASHROM_ARGS="-p raiden_debug_spi:target=EC,"
fi
else
FLASHROM_ARGS="-p ft2232_spi:type=servo-v2,port=B,"
fi
if [ ! -x "$FLASHROM" ]; then
die "no flashrom util found."
fi
if ! on_servov3; then
SERIALNAME=$(get_serial)
if [[ "$SERIALNAME" != "" ]] ; then
FLASHROM_ARGS+="serial=${SERIALNAME}"
fi
fi
if ! on_raiden || [[ "${SERVO_TYPE}" =~ "servo_micro" ]] ; then
if $(in_array "${BOARDS_SPI_1800MV[@]}" "${BOARD}"); then
SPI_VOLTAGE="pp1800"
else
SPI_VOLTAGE="pp3300"
fi
dut_control cold_reset:on
# If spi flash is in npcx's ec, enable gang programer mode
if [[ "${CHIP}" == "npcx_int_spi" ]]; then
servo_save_add "fw_up" "off"
# Set GP_SEL# as low then start ec
dut_control fw_up:on
sleep 0.1
dut_control cold_reset:off
fi
servo_save_add "spi1_vref" "off"
servo_save_add "spi1_buf_en" "off"
# Turn on SPI1 interface on servo for SPI Flash Chip
dut_control spi1_vref:${SPI_VOLTAGE} spi1_buf_en:on
if [[ ! "${SERVO_TYPE}" =~ "servo_micro" ]]; then
# Servo micro doesn't support this control.
servo_save_add "spi1_buf_on_flex_en" "off"
dut_control spi1_buf_on_flex_en:on
fi
else
if [[ "${CHIP}" == "npcx_int_spi" ]]; then
servo_save_add "fw_up" "off"
# Set GP_SEL# as low then start ec
dut_control cold_reset:on
dut_control fw_up:on
# sleep 0.1
dut_control cold_reset:off
else
# Assert EC reset.
dut_control cold_reset:on
fi
# Temp layout
L=/tmp/flash_spi_layout_$$
DELETE_LIST+=( "${L}" )
[[ -z "${FLAGS_read}" ]] && dump_fmap -F "${IMG}" > "${L}"
FLASHROM_OPTIONS="-i EC_RW -i WP_RO -l "${L}" --ignore-fmap"
FLASHROM_OPTIONS+=" --fast-verify"
fi
# Generate the correct flashrom command base.
FLASHROM_CMDLINE="${FLASHROM} ${FLASHROM_ARGS}"
if [[ -z "${FLAGS_read}" ]]; then
# Program EC image.
# flashrom should report the image size at the end of the output.
local FLASHROM_GETSIZE="sudo ${FLASHROM_CMDLINE} --get-size"
if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then
info "Running flashrom:" 1>&2
echo " ${FLASHROM_GETSIZE}" 1>&2
fi
SPI_SIZE=$(${FLASHROM_GETSIZE} 2>/dev/null |\
grep -oe '[0-9]\+$') || \
die "Failed to determine chip size!"
[[ ${SPI_SIZE} -eq 0 ]] && die "Chip size is 0!"
PATCH_SIZE=$((${SPI_SIZE} - ${IMG_SIZE}))
# Temp image
T=/tmp/flash_spi_$$
DELETE_LIST+=( "${T}" )
if [[ "${CHIP}" =~ ^npcx(|_int)_spi$ ]] ; then
{ # Patch temp image up to SPI_SIZE
cat $IMG
if [[ ${IMG_SIZE} -lt ${SPI_SIZE} ]] ; then
dd if=/dev/zero bs=${PATCH_SIZE} count=1 | \
tr '\0' '\377'
fi
} > $T
else
{ # Patch temp image up to SPI_SIZE
if [[ ${IMG_SIZE} -lt ${SPI_SIZE} ]] ; then
dd if=/dev/zero bs=${PATCH_SIZE} count=1 | \
tr '\0' '\377'
fi
cat $IMG
} > $T
fi
info "Programming EC firmware image."
local FLASHROM_WRITE="${FLASHROM_CMDLINE} ${FLASHROM_OPTIONS}"
if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then
info "Running flashrom:" 1>&2
echo " ${FLASHROM_WRITE} -w ${T}" 1>&2
fi
sudo timeout -k 10 -s 9 "${FLAGS_timeout}" \
${FLASHROM_WRITE} -w "${T}" \
|| die "${MSG_PROGRAM_FAIL}"
else
# Read EC image.
info "Reading EC firmware image."
if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then
info "Running flashrom:" 1>&2
echo " ${FLASHROM_CMDLINE} -r ${FLAGS_read}" 1>&2
fi
sudo timeout -k 10 -s 9 "${FLAGS_timeout}" \
${FLASHROM_CMDLINE} -r "${FLAGS_read}" \
|| die "${MSG_READ_FAIL}"
fi
if [[ -z "${FLAGS_read}" && "${FLAGS_verify}" == ${FLAGS_TRUE} ]]; then
# Verify EC image.
info "Verifying EC firmware image."
if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then
info "Running flashrom:" 1>&2
echo " ${FLASHROM_CMDLINE} -v ${T}" 1>&2
fi
sudo timeout -k 10 -s 9 "${FLAGS_timeout}" \
${FLASHROM_CMDLINE} -v "${T}" \
|| die "${MSG_VERIFY_FAIL}"
fi
}
function flash_stm32() {
local STM32MON
local STM32MON_OPT
if ! servo_has_cold_reset; then
die "Cold reset must be available for STM32 programming"
fi
TOOL_PATH="${EC_DIR}/build/${BOARD}/util:$PATH"
STM32MON=$(PATH="${TOOL_PATH}" which stm32mon)
EC_UART="$(servo_ec_uart)"
if [ ! -x "$STM32MON" ]; then
die "no stm32mon util found."
fi
info "Using serial flasher : ${STM32MON}"
info "${MCU} UART pty : ${EC_UART}"
claim_pty ${EC_UART}
STM32MON_OPT="-d ${EC_UART}"
# Make sure EC reboots in serial monitor mode.
ec_enable_boot0 "bitbang"
# Pulse EC reset.
ec_reset
if ! on_raiden && [[ "${SERVO_TYPE}" =~ "servo" ]] ; then
servo_save_add "${MCU}_uart_en"
dut_control ${MCU}_uart_en:on
fi
servo_save_add "${MCU}_uart_parity"
dut_control ${MCU}_uart_parity:even
if [[ "${SERVO_TYPE}" =~ "ccd_cr50" ]] ; then
case "${FLAGS_bitbang_rate}" in
(9600|19200|38400|57600) : ;;
(*)
die "${FLAGS_bitbang_rate} is not a valid" \
"bit bang rate"
;;
esac
info "Programming at ${FLAGS_bitbang_rate} baud"
servo_save_add "${MCU}_uart_baudrate"
servo_save_add "${MCU}_uart_bitbang_en"
dut_control ${MCU}_uart_baudrate:"${FLAGS_bitbang_rate}"
dut_control ${MCU}_uart_bitbang_en:on
else
servo_save_add "${MCU}_uart_baudrate"
dut_control ${MCU}_uart_baudrate:115200
fi
# Add a delay long enough for cr50 to update the ccdstate. Cr50 updates
# ccdstate once a second, so a 2 second delay should be safe.
if [[ "${SERVO_TYPE}" =~ "ccd_cr50" ]] ; then
sleep 2
STM32MON_OPT+=" -c"
fi
if [ -n "${FLAGS_logfile}" ]; then
info "Saving log in ${FLAGS_logfile}"
STM32MON_OPT+=" -L ${FLAGS_logfile}"
fi
local IMG_READ="${FLAGS_read}"
# Program EC image.
if [[ -z "${IMG_READ}" ]]; then
info "Programming EC firmware image."
# Unprotect flash, erase, and write
local STM32MON_COMMAND="${STM32MON} ${STM32MON_OPT} -u -e -w"
if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then
echo "${STM32MON_COMMAND} ${IMG}"
fi
timeout -k 10 -s 9 "${FLAGS_timeout}" \
${STM32MON_COMMAND} "${IMG}" \
|| die "${MSG_PROGRAM_FAIL}"
# If it is a program-verify request, then make a temporary
# directory to store the image
if [[ "${FLAGS_verify}" == ${FLAGS_TRUE} ]]; then
local TEMP_SUFFIX=".$(basename ${SCRIPT}).${CHIP}"
local TEMP_DIR="$(mktemp -d --suffix="${TEMP_SUFFIX}")"
IMG_READ="${TEMP_DIR}/ec.read.bin"
DELETE_LIST+=( "${TEMP_DIR}" )
fi
fi
# Read EC image.
if [[ -n "${IMG_READ}" ]]; then
info "Reading EC firmware image."
local STM32MON_READ_CMD="${STM32MON} ${STM32MON_OPT} -U -r"
if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then
echo "${STM32MON_READ_CMD} ${IMG_READ}"
fi
timeout -k 10 -s 9 "${FLAGS_timeout}" \
${STM32MON_READ_CMD} "${IMG_READ}" \
|| die "${MSG_READ_FAIL}"
fi
# Verify the flash by comparing the source image to the read image,
# only if it was a flash write request.
if [[ -z "${FLAGS_read}" && "${FLAGS_verify}" == ${FLAGS_TRUE} ]]; then
info "Verifying EC firmware image."
if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then
echo "cmp -n ${IMG_SIZE} ${IMG} ${IMG_READ}"
fi
cmp -s -n "${IMG_SIZE}" "${IMG}" "${IMG_READ}" \
|| die "${MSG_VERIFY_FAIL}"
fi
# Remove the Application processor reset
# TODO(crosbug.com/p/30738): we cannot rely on servo_VARS to restore it
if servo_has_warm_reset; then
dut_control warm_reset:off
fi
}
function flash_stm32_dfu() {
DFU_DEVICE=0483:df11
ADDR=0x08000000
DFU_UTIL='dfu-util'
which $DFU_UTIL &> /dev/null || die \
"no dfu-util util found. Did you 'sudo emerge dfu-util'"
info "Using dfu flasher : ${DFU_UTIL}"
dev_cnt=$(lsusb -d $DFU_DEVICE | wc -l)
if [ $dev_cnt -eq 0 ] ; then
die "unable to locate dfu device at $DFU_DEVICE"
elif [ $dev_cnt -ne 1 ] ; then
die "too many dfu devices (${dev_cnt}). Disconnect all but one."
fi
SIZE=$(wc -c ${IMG} | cut -d' ' -f1)
# Remove read protection
sudo timeout -k 10 -s 9 "${FLAGS_timeout}" $DFU_UTIL -a 0 -d "${DFU_DEVICE}" \
-s ${ADDR}:${SIZE}:force:unprotect -D "${IMG}"
# Wait for mass-erase and reboot after unprotection
sleep 1
# Actual image flashing
sudo timeout -k 10 -s 9 "${FLAGS_timeout}" $DFU_UTIL -a 0 -d "${DFU_DEVICE}" \
-s ${ADDR}:${SIZE} -D "${IMG}"
}
# TODO(b/130165933): Implement a dut-control command to look up the correct
# I2C adapter number, and use that here in place of the hack of looking at
# I2C adapter names.
function dut_i2c_dev() {
if [ -n "$DUT_I2C_DEV" ]; then
[ -e "$DUT_I2C_DEV" ] ||
die "\$DUT_I2C_DEV is a non-existent path: $DUT_I2C_DEV"
echo "$DUT_I2C_DEV"
return
fi
if ! (
set -e
cd /sys/class/i2c-dev
# Sorting in reverse numerical order generally picks the correct
# servod I2C bus when there are multiple servos in line to the
# DUT, e.g. servo_v4->servo_micro, or servo_v4->CR50 (CCD).
for dev in $(ls | grep ^i2c- | sort -s -t- -n -k2,2 -r); do
if grep -q servod "$dev"/name; then
echo /dev/"$dev"
exit
fi
done
false
); then
die "Could not find servo I2C adapter. This could be because "\
"the i2c-pseudo module was not loaded when servod was started."
fi
}
function flash_it83xx() {
local TOOL_PATH="${EC_DIR}/build/${BOARD}/util:$PATH"
local ITEFLASH_BIN=$(PATH="${TOOL_PATH}" which iteflash)
if [[ ! -x "$ITEFLASH_BIN" ]]; then
die "no iteflash util found."
fi
# Now the we have enabled the I2C mux on the servo to talk to the dut,
# we need to switch the I2C mux on the dut to allow ec programing (if
# there is a mux on the dut)
if servo_has_dut_i2c_mux; then
info "Switching DUT I2C Mux to ${CHIP}"
servo_save_add "dut_i2c_mux"
dut_control dut_i2c_mux:ec_prog
fi
# Ensure that the AP is off while we are flashing the EC via:
# - warm_reset:on
# - cold_reset:on
# - cold_reset:off
# ...reflash EC...
# - warm_reset:off
if servo_has_warm_reset; then
dut_control_or_die warm_reset:on
fi
if servo_has_cold_reset; then
servo_ec_hard_reset_or_die
fi
# Send the special waveform to the ITE EC.
if [[ "${SERVO_TYPE}" =~ "servo_micro" ]]; then
info "Asking Servo Micro to send the dbgr special waveform to "\
"${CHIP}"
dut_control_or_die enable_ite_dfu
elif [[ "${SERVO_TYPE}" =~ "ccd_cr50" ]]; then
local CCD_I2C_CAP="$(dut_control_get ccd_i2c_en)"
if [[ "${CCD_I2C_CAP,,}" != "always" ]]; then
die "CCD I2C capability is not set as 'Always'" \
": ${CCD_I2C_CAP}"
fi
info "Asking CR50 to send the dbgr special waveform to ${CHIP}"
sleep 2
dut_control_or_die cr50_i2c_ctrl:ite_debugger_mode
sleep 3
elif [[ "${SERVO_TYPE}" == "servo_v2" ]]; then
info "Closing servod connection to ftdi_i2c interface"
dut_control_or_die ftdii2c_cmd:close
else
die "This servo type is not yet supported: ${SERVO_TYPE}"
fi
# Build the iteflash command line.
local ITEFLASH_ARGS=( "${ITEFLASH_BIN}" )
if [[ "${SERVO_TYPE}" == "servo_v2" ]]; then
ITEFLASH_ARGS+=( "--send-waveform=1" "--i2c-interface=ftdi" )
else
ITEFLASH_ARGS=( "sudo" "--" "${ITEFLASH_ARGS[@]}" \
"--send-waveform=0" "--i2c-interface=linux" \
"--i2c-dev-path=$(dut_i2c_dev)" )
if [[ "${SERVO_TYPE}" =~ "ccd_cr50" ]]; then
ITEFLASH_ARGS+=( "--block-write-size=256" )
fi
fi
local ERROR_MSG
if [[ -n "${FLAGS_read}" ]]; then
ITEFLASH_ARGS+=( "--read=${FLAGS_read}" )
info "Reading EC firmware image using iteflash..."
ERROR_MSG="${MSG_READ_FAIL}"
else
ITEFLASH_ARGS+=( "--erase" "--write=${IMG}" )
info "Programming EC firmware image using iteflash..."
ERROR_MSG="${MSG_PROGRAM_FAIL}"
fi
if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then
ITEFLASH_ARGS+=( "--debug" )
echo "${ITEFLASH_ARGS[@]}"
fi
"${ITEFLASH_ARGS[@]}" || die "${ERROR_MSG}"
}
function flash_lm4() {
OCD_CHIP_CFG="lm4_chip.cfg"
OCD_CMDS="init; flash_lm4 ${IMG} ${FLAGS_offset}; shutdown;"
flash_openocd
}
function flash_nrf51() {
OCD_CHIP_CFG="nrf51_chip.cfg"
OCD_CMDS="init; flash_nrf51 ${IMG} ${FLAGS_offset}; exit_debug_mode_nrf51; shutdown;"
flash_openocd
# waiting 100us for the reset pulse is not necessary, it takes ~2.5ms
dut_control swd_reset:on swd_reset:off
}
function flash_npcx_jtag() {
IMG_PATH="${EC_DIR}/build/${BOARD}"
OCD_CHIP_CFG="npcx_chip.cfg"
if [ "${FLAGS_ro}" = ${FLAGS_TRUE} ] ; then
# Program RO region only
OCD_CMDS="init; flash_npcx_ro ${CHIP} ${IMG_PATH} ${FLAGS_offset}; shutdown;"
else
# Program all EC regions
OCD_CMDS="init; flash_npcx_all ${CHIP} ${IMG_PATH} ${FLAGS_offset}; shutdown;"
fi
# Reset the EC
ec_reset
flash_openocd
}
function flash_npcx_uut() {
local TOOL_PATH="${EC_DIR}/build/${BOARD}/util:$PATH"
local NPCX_UUT=$(PATH="${TOOL_PATH}" which uartupdatetool)
local EC_UART="$(servo_ec_uart)"
# Look for npcx_monitor.bin in multiple directories, starting with
# the same path as the EC binary.
local MON=""
for dir in \
"$(dirname "$IMG")" \
"${EC_DIR}/build/${BOARD}/chip/npcx/spiflashfw" \
"$(dirname "$LOCAL_BUILD")" \
"$(dirname "$EMERGE_BUILD")" ;
do
if [ -f "$dir/npcx_monitor.bin" ] ; then
MON="$dir/npcx_monitor.bin"
break
fi
done
if [ -z "${MON}" ] ; then
echo "Failed to find npcx_monitor.bin"
exit 1
fi
info "Using NPCX image : ${MON}"
# The start address to restore monitor firmware binary
local MON_ADDR="0x200C3020"
if [ ! -x "$NPCX_UUT" ]; then
die "no NPCX UART Update Tool found."
fi
info "Using: NPCX UART Update Tool"
info "${MCU} UART pty : ${EC_UART}"
claim_pty ${EC_UART}
if [[ "${SERVO_TYPE}" =~ "ccd_cr50" ]] ; then
servo_save_add ccd_keepalive_en
dut_control ccd_keepalive_en:on
fi
# Force the EC to boot in UART update mode
ec_enable_boot0 "uut"
ec_reset
# Have to wait a bit for EC boot-up
sleep 0.1
# For CCD, disable the trigger pin for normal UART operation
ec_disable_boot0 "uut"
sleep 0.1
# Remove the prefix "/dev/" because uartupdatetool will add it.
local UUT_ARGS=( "--port=${EC_UART#/dev/}" " --baudrate=115200" )
local IMG_READ="${FLAGS_read}"
# Program EC image.
if [[ -z "${IMG_READ}" ]]; then
info "Loading monitor binary."
local UUT_MON=( "${NPCX_UUT}" "${UUT_ARGS[@]}" \
"--opr=wr" "--addr=${MON_ADDR}" \
"--file=${MON}" )
# Load monitor binary to address 0x200C3020
if [[ "${FLAGS_verbose}" = ${FLAGS_TRUE} ]]; then
echo "${UUT_MON[*]}"
fi
timeout -k 10 -s 9 "${FLAGS_timeout}" \
"${UUT_MON[@]}" || die "Failed to load monitor binary."
info "Programming EC firmware image."
local UUT_WR=( "${NPCX_UUT}" "${UUT_ARGS[@]}" \
"--auto" "--offset=${FLAGS_offset}" \
"--file=${IMG}" )
if [[ "${FLAGS_verbose}" = ${FLAGS_TRUE} ]]; then
echo "${UUT_WR[*]}"
fi
timeout -k 10 -s 9 "${FLAGS_timeout}" \
"${UUT_WR[@]}" || die "${MSG_PROGRAM_FAIL}"
# If it is a program-verify request, then make a temporary
# directory to store the image.
if [[ "${FLAGS_verify}" == ${FLAGS_TRUE} ]]; then
local TEMP_SUFFIX=".$(basename ${SCRIPT}).${CHIP}.$$"
local TEMP_DIR="$(mktemp -d --suffix="${TEMP_SUFFIX}")"
IMG_READ="${TEMP_DIR}/ec.read.bin"
DELETE_LIST+=( "${TEMP_DIR}" )
fi
fi
# Read EC image.
if [[ -n "${IMG_READ}" ]]; then
info "Reading EC firmware image."
local UUT_RD=( "${NPCX_UUT}" "${UUT_ARGS[@]}" \
"--read-flash" "--file=${IMG_READ}" )
if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then
echo "${UUT_RD[*]}"
fi
timeout -k 10 -s 9 "${FLAGS_timeout}" \
"${UUT_RD[@]}" || die "${MSG_READ_FAIL}"
fi
# Verify the flash by comparing the source image to the read image,
# only if it was a flash write request.
if [[ -z "${FLAGS_read}" && "${FLAGS_verify}" == ${FLAGS_TRUE} ]]; then
info "Verifying EC firmware image."
if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then
echo "cmp -n ${IMG_SIZE} ${IMG} ${IMG_READ}"
fi
cmp -s -n "${IMG_SIZE}" "${IMG}" "${IMG_READ}" \
|| die "${MSG_VERIFY_FAIL}"
fi
}
function flash_npcx_5m5g_jtag() {
flash_npcx_jtag
}
function flash_npcx_5m6g_jtag() {
flash_npcx_jtag
}
function flash_npcx_7m6x_jtag() {
flash_npcx_jtag
}
function flash_npcx_7m7x_jtag() {
flash_npcx_jtag
}
function flash_npcx_spi() {
flash_flashrom
}
function flash_npcx_int_spi() {
flash_flashrom
}
function flash_mec1322() {
flash_flashrom
}
if dut_control boot_mode 2>/dev/null ; then
if [[ "${MCU}" != "ec" ]] ; then
die "Toad cable can't support non-ec UARTs"
fi
SERVO_TYPE=toad
info "Using a dedicated debug cable"
fi
info "Using ${SERVO_TYPE}."
# Only if it is a flash program request, call ec_image.
if [[ -z "${FLAGS_read}" ]]; then
IMG="$(ec_image)"
info "Using ${MCU} image : ${IMG}"
IMG_SIZE=$(stat -c%s "${IMG}")
fi
if [ "${NEED_SERVO}" != "no" ] ; then
servo_save
fi
info "Flashing chip ${CHIP}."
flash_${CHIP}
info "Flashing done."