mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
Since the stm32 MCUs are programmed over the UART, we need to make some changes to allow the interpreter to stop listening to the UART PTY when flash_ec needs those PTYs. Otherwise, the EC-3PO interpreter will interfere with the programming and cause the flash to fail every time. BUG=chromium:571170 BRANCH=None TEST=Use flash_ec to program both veyron_jerry and samus_pd with no interruptions. TEST=Use flash_ec to program veyron_jerry without servod changes with no interruptions. CQ-DEPEND=CL:321084 CQ-DEPEND=CL:318900 Change-Id: I350fdb708d30c4ec6f18e5dc4abd621370522381 Signed-off-by: Aseda Aboagye <aaboagye@google.com> Reviewed-on: https://chromium-review.googlesource.com/320629 Commit-Ready: Aseda Aboagye <aaboagye@chromium.org> Tested-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Todd Broch <tbroch@chromium.org>
583 lines
12 KiB
Bash
Executable File
583 lines
12 KiB
Bash
Executable File
#!/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_LM4=(
|
|
auron
|
|
rambi
|
|
samus
|
|
)
|
|
|
|
BOARDS_STM32=(
|
|
big
|
|
blaze
|
|
chell_pd
|
|
discovery
|
|
glados_pd
|
|
honeybuns
|
|
jerry
|
|
kitty
|
|
kunimitsu_pd
|
|
lars_pd
|
|
llama
|
|
lucid
|
|
minimuffin
|
|
oak
|
|
oak_pd
|
|
pit
|
|
plankton
|
|
ryu
|
|
samus_pd
|
|
snoball
|
|
strago_pd
|
|
zinger
|
|
)
|
|
BOARDS_STM32_PROG_EN=(
|
|
plankton
|
|
)
|
|
|
|
BOARDS_STM32_DFU=(
|
|
dingdong
|
|
hoho
|
|
twinkie
|
|
)
|
|
|
|
BOARDS_NPCX_JTAG=(
|
|
npcx_evb
|
|
npcx_evb_arm
|
|
)
|
|
|
|
BOARDS_NPCX_SPI=(
|
|
wheatley
|
|
)
|
|
|
|
BOARDS_NRF51=(
|
|
hadoken
|
|
)
|
|
|
|
BOARDS_MEC1322=(
|
|
chell
|
|
glados
|
|
kunimitsu
|
|
lars
|
|
strago
|
|
)
|
|
|
|
# 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 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_JTAG[@]}" "${BOARD}"); then
|
|
CHIP="npcx_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 [ -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
|
|
}
|
|
|
|
# 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
|
|
}
|
|
|
|
# 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
|
|
|
|
ec_reset
|
|
}
|
|
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|kunimitsu_pd|lars_pd ) 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"
|
|
else
|
|
FLASHROM_PARAM="-p ft2232_spi:type=servo-v2,port=B"
|
|
fi
|
|
|
|
if [ ! -x "$FLASHROM" ]; then
|
|
die "no flashrom util found."
|
|
fi
|
|
|
|
if ! on_servov3; then
|
|
SERIALNAME=$(${DUT_CONTROL_CMD} serialname | cut -d: -f2)
|
|
if [[ "$SERIALNAME" != "" ]] ; then
|
|
FLASHROM_PARAM="${FLASHROM_PARAM},serial=${SERIALNAME}"
|
|
fi
|
|
fi
|
|
|
|
dut_control cold_reset:on
|
|
|
|
# Turn on SPI1 interface on servo for 3.3V SPI Flash Chip
|
|
dut_control spi1_vref:pp3300 spi1_buf_en:on spi1_buf_on_flex_en:on
|
|
|
|
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} -w "${T}"
|
|
|
|
rm $T
|
|
|
|
# Turn off SPI1 interface on servo
|
|
dut_control spi1_vref:off spi1_buf_en:off spi1_buf_on_flex_en:off
|
|
|
|
# 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
|
|
ec_reset
|
|
# 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_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 ${IMG_PATH} ${FLAGS_offset}; shutdown;"
|
|
else
|
|
# Program all EC regions
|
|
OCD_CMDS="init; flash_npcx_all ${IMG_PATH} ${FLAGS_offset}; shutdown;"
|
|
fi
|
|
|
|
# Reset the EC
|
|
ec_reset
|
|
|
|
flash_openocd
|
|
}
|
|
|
|
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 [ "${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."
|