| #!/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." |