blob: 4a75ba0db60d35aa42b19f9748c769db4656bac5 [file] [log] [blame]
#!/bin/bash
# Copyright (c) 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
}
BOARDS_IT83XX=(
it83xx_evb
reef_it8320
)
BOARDS_LM4=(
samus
)
BOARDS_STM32=(
big
blaze
chell_pd
elm
eve_fp
glados_pd
hammer
honeybuns
jerry
kitty
llama
lucid
minimuffin
oak
oak_pd
pit
plankton
ryu
samus_pd
snoball
staff
strago_pd
zinger
)
BOARDS_STM32_PROG_EN=(
plankton
)
BOARDS_STM32_DFU=(
dingdong
hoho
twinkie
discovery
servo_v4
servo_micro
sweetberry
polyberry
stm32f446e-eval
tigertail
)
BOARDS_NPCX_5M5G_JTAG=(
npcx_evb
npcx_evb_arm
)
BOARDS_NPCX_5M6G_JTAG=(
)
BOARDS_NPCX_7M6X_JTAG=(
npcx7_evb
)
BOARDS_NPCX_SPI=(
coral
eve
fizz
gru
kevin
poppy
reef
soraka
wheatley
kahlee
)
BOARDS_NRF51=(
hadoken
)
BOARDS_MEC1322=(
chell
glados
strago
)
BOARDS_SPI_1800MV=(
coral
gru
kevin
reef
)
BOARDS_RAIDEN=(
coral
eve
fizz
gru
kevin
poppy
reef
soraka
)
# Flags
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_integer timeout 600 \
"Timeout for flashing the EC, measured in seconds."
DEFINE_string offset "0" \
"Offset where to program the image from."
DEFINE_integer port 9999 \
"Port to communicate to servo on."
DEFINE_boolean raiden "${FLAGS_FALSE}" \
"Use raiden_debug_spi programmer"
DEFINE_boolean ro "${FLAGS_FALSE}" \
"Write only the read-only partition"
# Parse command line
FLAGS_HELP="usage: $0 [flags]"
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
if [[ $# -gt 0 ]]; then
die "invalid arguments: \"$*\""
fi
set -e
if [ -z "${FLAGS_board}" -a -z "${FLAGS_chip}" ]; then
die "should specify a board or a chip."
fi
SERVO_TYPE=servo
BOARD=${FLAGS_board}
BOARD_ROOT=/build/${BOARD}
in_array() {
local n=$#
local value=${!n}
for (( i=1; i<$#; i++ )) do
if [ "${!i}" == "${value}" ]; then
return 0
fi
done
return 1
}
if $(in_array "${BOARDS_LM4[@]}" "${BOARD}"); then
CHIP="lm4"
elif $(in_array "${BOARDS_STM32[@]}" "${BOARD}"); then
CHIP="stm32"
elif $(in_array "${BOARDS_STM32_DFU[@]}" "${BOARD}"); then
CHIP="stm32_dfu"
NEED_SERVO="no"
elif $(in_array "${BOARDS_NPCX_5M5G_JTAG[@]}" "${BOARD}"); then
CHIP="npcx_5m5g_jtag"
elif $(in_array "${BOARDS_NPCX_5M6G_JTAG[@]}" "${BOARD}"); then
CHIP="npcx_5m6g_jtag"
elif $(in_array "${BOARDS_NPCX_7M6X_JTAG[@]}" "${BOARD}"); then
CHIP="npcx_7m6x_jtag"
elif $(in_array "${BOARDS_NPCX_SPI[@]}" "${BOARD}"); then
CHIP="npcx_spi"
elif $(in_array "${BOARDS_NRF51[@]}" "${BOARD}"); then
CHIP="nrf51"
elif $(in_array "${BOARDS_MEC1322[@]}" "${BOARD}"); then
CHIP="mec1322"
elif $(in_array "${BOARDS_IT83XX[@]}" "${BOARD}"); then
CHIP="it83xx"
NEED_SERVO="no"
elif [ -n "${FLAGS_chip}" ]; then
CHIP="${FLAGS_chip}"
else
die "board ${BOARD} not supported"
fi
if [ -n "${FLAGS_chip}" -a "${CHIP}" != "${FLAGS_chip}" ]; then
die "board ${BOARD} doesn't use chip ${FLAGS_chip}"
fi
servo_has_warm_reset() {
dut_control warm_reset >/dev/null 2>&1
}
servo_has_cold_reset() {
dut_control cold_reset >/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() {
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
}
ec_reset() {
eval ${SERVO_TYPE}_${MCU}_hard_reset
}
# force the EC to boot in serial monitor mode
toad_ec_boot0() {
dut_control boot_mode:yes
}
servo_ec_boot0() {
dut_control ec_boot_mode:on
}
servo_usbpd_boot0() {
dut_control usbpd_boot_mode:on
}
servo_sh_boot0() {
dut_control sh_boot_mode:on
}
ec_enable_boot0() {
# Enable programming GPIOs
if $(in_array "${BOARDS_STM32_PROG_EN[@]}" "${BOARD}"); then
dut_control prog_en:yes
fi
eval ${SERVO_TYPE}_${MCU}_boot0
}
# 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 [ -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
}
# Put back the servo and the system in a clean state at exit
FROZEN_PIDS=""
cleanup() {
if [ -n "${save}" ]; then
info "Restoring servo settings..."
servo_restore "$save"
fi
for pid in ${FROZEN_PIDS}; do
info "Sending SIGCONT to process ${pid}!"
kill -CONT ${pid}
done
if ! on_raiden; 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
EMERGE_BUILD=${BOARD_ROOT}/firmware/${EC_FILE}
LOCAL_BUILD=
if [[ -n "${EC_DIR}" ]]; then
LOCAL_BUILD="${EC_DIR}/build/${BOARD}/${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."
}
DUT_CONTROL_CMD="dut-control --port=${FLAGS_port}"
function dut_control() {
$DUT_CONTROL_CMD "$@" >/dev/null
}
# Find the EC UART on the servo v2
function ec_uart() {
SERVOD_FAIL="Cannot communicate with servo. is servod running ?"
($DUT_CONTROL_CMD raw_${MCU}_uart_pty || \
$DUT_CONTROL_CMD ${MCU}_uart_pty || \
die "${SERVOD_FAIL}") | cut -d: -f2
}
# Servo variables management
case "${BOARD}" in
oak_pd|samus_pd|strago_pd ) MCU="usbpd" ;;
chell_pd|glados_pd ) MCU="usbpd" ;;
eve_fp ) MCU="usbpd" ;;
dingdong|hoho|twinkie ) DUT_CONTROL_CMD="true" ; MCU="ec" ;;
*) MCU="ec" ;;
esac
servo_VARS="${MCU}_uart_en ${MCU}_uart_parity \
${MCU}_uart_baudrate jtag_buf_on_flex_en jtag_buf_en dev_mode"
if [ "${CHIP}" = "stm32" ] ; then
servo_VARS+=" ${MCU}_boot_mode"
fi
if $(in_array "${BOARDS_STM32_PROG_EN[@]}" "${BOARD}"); then
servo_VARS+=" prog_en"
fi
toad_VARS="${MCU}_uart_parity \
${MCU}_uart_baudrate boot_mode"
function servo_save() {
SERVO_VARS_NAME=${SERVO_TYPE}_VARS
$DUT_CONTROL_CMD ${!SERVO_VARS_NAME}
}
function servo_restore() {
echo "$1" | while read line
do
dut_control "$line"
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
# Disconnect the EC-3PO interpreter from the UART since it will
# interfere with flashing.
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
}
# 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/bin/lib" ]]; then
OCD_PATH="/usr/bin/lib"
else
die "Cannot locate openocd configs"
fi
else
OCD_PATH="${EC_DIR}/util/openocd"
fi
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 v2/3 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_PARAM="-p linux_spi"
elif on_raiden; then
info "Using raiden debug cable."
FLASHROM_PARAM="-p raiden_debug_spi:target=EC"
else
FLASHROM_PARAM="-p ft2232_spi:type=servo-v2,port=B"
fi
if [ ! -x "$FLASHROM" ]; then
die "no flashrom util found."
fi
if ! on_raiden; then
if ! on_servov3; then
SERIALNAME=$(${DUT_CONTROL_CMD} serialname | \
cut -d: -f2)
if [[ "$SERIALNAME" != "" ]] ; then
FLASHROM_PARAM+=",serial=${SERIALNAME}"
fi
fi
if $(in_array "${BOARDS_SPI_1800MV[@]}" "${BOARD}"); then
SPI_VOLTAGE="pp1800"
else
SPI_VOLTAGE="pp3300"
fi
dut_control cold_reset:on
# Turn on SPI1 interface on servo for SPI Flash Chip
dut_control spi1_vref:${SPI_VOLTAGE} spi1_buf_en:on \
spi1_buf_on_flex_en:on
else
# Temp layout
L=/tmp/flash_spi_layout_$$
dump_fmap -F "${IMG}" > "${L}"
FLASHROM_OPTIONS="-i EC_RW -i WP_RO -l "${L}" --ignore-fmap \
--fast-verify"
fi
SPI_SIZE=$(sudo ${FLASHROM} ${FLASHROM_PARAM} --get-size 2>/dev/null | \
tail -n 1)
IMG_SIZE=$(stat -c%s "$IMG")
PATCH_SIZE=$((${SPI_SIZE} - ${IMG_SIZE}))
# Temp image
T=/tmp/flash_spi_$$
if $(in_array "${BOARDS_NPCX_SPI[@]}" "${BOARD}"); 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
sudo timeout -k 10 -s 9 "${FLAGS_timeout}" \
${FLASHROM} ${FLASHROM_PARAM} ${FLASHROM_OPTIONS} -w "${T}"
rm $T
if ! on_raiden; then
# Turn off SPI1 interface on servo
dut_control spi1_vref:off spi1_buf_en:off \
spi1_buf_on_flex_en:off
else
rm $L
fi
# Do not save/restore servo settings
save=
}
function flash_stm32() {
TOOL_PATH="${EC_DIR}/build/${BOARD}/util:$PATH"
STM32MON=$(PATH="${TOOL_PATH}" which stm32mon)
if [ ! -x "$STM32MON" ]; then
die "no stm32mon util found."
fi
info "Using serial flasher : ${STM32MON}"
claim_pty ${EC_UART}
if [ "${SERVO_TYPE}" = "servo" ] ; then
dut_control ${MCU}_uart_en:on
fi
dut_control ${MCU}_uart_parity:even
dut_control ${MCU}_uart_baudrate:115200
if $(servo_has_warm_reset); then
dut_control warm_reset:on
fi
# Force the EC to boot in serial monitor mode
ec_enable_boot0
# Reset the EC
if $(servo_has_cold_reset); then
ec_reset
fi
# Unprotect flash, erase, and write
timeout -k 10 -s 9 "${FLAGS_timeout}" \
${STM32MON} -d ${EC_UART} -U -u -e -w "${IMG}"
# 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
# Reconnect the EC-3PO interpreter to the UART.
dut_control ${MCU}_ec3po_interp_connect:on || \
warn "hdctools cannot reconnect the EC-3PO interpreter to" \
"the UART."
}
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 -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 -s ${ADDR}:${SIZE} -D "${IMG}"
}
function flash_it83xx() {
TOOL_PATH="${EC_DIR}/build/${BOARD}/util:$PATH"
ITEFLASH=$(PATH="${TOOL_PATH}" which iteflash)
if [ ! -x "$ITEFLASH" ]; then
die "no iteflash util found."
fi
sudo ${ITEFLASH} -w ${IMG}
}
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_5m5g_jtag() {
flash_npcx_jtag
}
function flash_npcx_5m6g_jtag() {
flash_npcx_jtag
}
function flash_npcx_7m6x_jtag() {
flash_npcx_jtag
}
function flash_npcx_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
IMG="$(ec_image)"
info "Using ${MCU} image : ${IMG}"
if ! on_raiden && [ "${NEED_SERVO}" != "no" ] ; then
EC_UART="$(ec_uart)"
info "${MCU} UART pty : ${EC_UART}"
save="$(servo_save)"
fi
info "Flashing chip ${CHIP}."
flash_${CHIP}
info "Flashing done."