#!/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=( adlrvpm_ite adlrvpp_ite it83xx_evb jslrvp_ite reef_it8320 tglrvpu_ite tglrvpu_ite_tcpmv1 tglrvpy_ite tglrvpy_ite_tcpmv1 ) BOARDS_IT83XX_SPI_PROGRAMMING=( it8xxx2_evb it8xxx2_pdevb ) BOARDS_STM32=( bloonchipper chell_pd coffeecake chocodile_bec chocodile_vpdmcu dartmonkey glados_pd hatch_fp jerry minimuffin nami_fp nocturne_fp oak_pd pit plankton rainier strago_pd zinger ) BOARDS_STM32_PROG_EN=( plankton ) BOARDS_STM32_DFU=( c2d2 dingdong hoho twinkie discovery servo_v4 servo_v4p1 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=( ) BOARDS_NPCX_INT_SPI=( adlrvpp_npcx ) BOARDS_SPI_1800MV=( coral reef ) BOARDS_RAIDEN=( coral eve fizz 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_boolean dry_run "${FLAGS_FALSE}" \ "Print the commands to be run instead of actually running them." 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_boolean servo_micro_uart_rx_rework "${FLAGS_FALSE}" \ "The servo micro for flashing has b/143163043#comment3 rework" 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." DEFINE_boolean zephyr "${FLAGS_FALSE}" \ "Program a Zephyr EC image instead of a CrOS EC image" # 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="" # Run a command which mutates the state of an attached device. # This is used by the --dry_run flag, when enabled, the command will # only print. When disabled, the command will run without printing # any message. function print_or_run() { if [ "${FLAGS_dry_run}" = "${FLAGS_TRUE}" ]; then local arg local -a quoted_args # Quote each of the arguments so it can easily be # copy-pasted into a shell. for arg in "$@"; do quoted_args+=("$(printf "%q" "${arg}")") done tput2 bold && tput2 setaf 4 echo "DRY RUN:" "${quoted_args[@]}" >&2 tput2 sgr0 else "$@" fi } 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 print_or_run "${DUT_CTRL_CML[@]}" >/dev/null } function dut_control_or_die { dut_control "$@" || die "command exited $? (non-zero): dut-control $*" } 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[@]}" "--value_only" "${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}" } function dut_control_get_or_die { dut_control_get "$@" || \ die "command exited $? (non-zero): dut-control --value_only $*" } : ${BOARD:=${FLAGS_board}} # Find the Zephyr project directory for the specified board. Zephyr projects # organized under ./zephyr/projects as / directory. : ${ZEPHYR_DIR:=$(find zephyr/projects -mindepth 2 -maxdepth 2 \ -type d -name "${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_NPCX_INT_SPI[@]}" "${BOARD}"); then SUPPORTED_CHIPS+=("npcx_int_spi") fi if $(in_array "${BOARDS_IT83XX[@]}" "${BOARD}"); then SUPPORTED_CHIPS+=("it83xx") fi if $(in_array "${BOARDS_IT83XX_SPI_PROGRAMMING[@]}" "${BOARD}"); then SUPPORTED_CHIPS+=("ite_spi") 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|strago_pd ) MCU="usbpd" ;; chell_pd|glados_pd ) MCU="usbpd" ;; bloonchipper|dartmonkey|hatch_fp|nami_fp|nocturne_fp ) MCU="fpmcu" ;; dingdong|hoho|twinkie ) DUT_CONTROL_CMD=( "true" ); MCU="ec" ;; *) MCU="ec" ;; esac case "${CHIP}" in "stm32"|"npcx_spi"|"npcx_int_spi"|"it83xx"|"npcx_uut"|"ite_spi"| \ "ite_spi_ccd_i2c") ;; *) 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(p1)?_with_.*$ ]]; then ACTIVE_DEVICE="$(dut_control_get active_dut_controller)" else ACTIVE_DEVICE="${SERVO_TYPE}" fi if [[ "${SERVO_TYPE}" =~ ^servo_v4(p1)?_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{p1}_with_servo_micro_and_ccd_cr50 SECOND_DEVICE="${SERVO_TYPE#*_and_}" # servo_v4p1 can shared the same type with servo_v4, since there's no # difference handling the flash. 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_is_ccd() { [[ "${SERVO_TYPE}" =~ "ccd_cr50" ]] || \ [[ "${SERVO_TYPE}" =~ "ccd_ti50" ]] } 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 } servo_ec_hard_reset_or_die() { dut_control_or_die cold_reset:on dut_control_or_die cold_reset:off # Cold reset on C2D2 is H1 reset, which will double reset the EC # We need to wait a little bit to ensure we catch final EC reset if [[ "${SERVO_TYPE}" =~ "c2d2" ]]; then print_or_run sleep 0.2 fi } servo_ec_hard_reset() { dut_control cold_reset:on dut_control cold_reset:off } c2d2_ec_hard_reset() { # This is an H1-level reset (instead of just an EC-level 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_fpmcu_hard_reset() { dut_control fpmcu_reset:on sleep:0.5 fpmcu_reset:off } servo_sh_hard_reset() { dut_control sh_reset:on dut_control sh_reset:off } ec_reset() { local stype if [[ "${SERVO_TYPE}" =~ "servo" ]] || servo_is_ccd; then stype="servo" else stype=${SERVO_TYPE} fi if [[ -n "${stype}" ]]; then eval ${stype}_${MCU}_hard_reset fi } ccd_ec_boot0() { local on_value="${1}" local boot_mode="${2}" info "Using CCD ${boot_mode}." if [[ "${on_value}" == "on" ]] && [[ "${boot_mode}" == "uut" ]] ; then # Ti50 requires EC reset to be asserted before UUT mode can be # enabled, Cr50 should not mind. dut_control cold_reset:on fi dut_control "ccd_ec_boot_mode_${boot_mode}":"${on_value}" } servo_micro_ec_boot0() { # Some devices (e.g. hatch) control the RX UART pin via an on-board # circuit that is controlled by the EC_FLASH_ODL pin. For those boards, # we want to continue to drive the EC_FLASH_ODL if they do not have the # servo micro rework listed below. if [[ "${FLAGS_servo_micro_uart_rx_rework}" == ${FLAGS_TRUE} ]]; then info "Servo micro $2 mode: $1 (using rx_rework)" # Setting the test point allows the EC_TX_SERVO_RX line # to be driven by the servo for 'on' value. 'off' value # lets the EC drive the EC_TX_SERVO_RX net. # # HW Rework (b/143163043#comment3): # - Disconnect U45.1 from ground # - Connected U45.1 to TP1 pad dut_control tp1:$1 dut_control servo_micro_ec_boot_mode_$2:$1 else info "Servo micro $2 mode: $1 (using FW_UP_L)" dut_control ec_boot_mode:$1 fi } servo_ec_boot0() { dut_control ec_boot_mode:$1 } c2d2_ec_boot0() { dut_control ec_boot_mode_uut:$1 } servo_usbpd_boot0() { dut_control usbpd_boot_mode:$1 } servo_fpmcu_boot0() { dut_control fpmcu_boot_mode:"$1" } servo_micro_fpmcu_boot0() { servo_fpmcu_boot0 "$@" } servo_micro_usbpd_boot0() { servo_usbpd_boot0 "$@" } servo_sh_boot0() { dut_control sh_boot_mode:$1 } ec_switch_boot0() { local 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_is_ccd ; then stype=ccd elif [[ "${SERVO_TYPE}" =~ "servo_micro" ]] ; then stype=servo_micro elif [[ "${SERVO_TYPE}" =~ "servo" ]] ; then stype=servo else stype=${SERVO_TYPE} 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_is_ccd || \ [[ "${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 print_or_run 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 fi servo_restore if [ "${CHIP}" = "stm32" -o "${CHIP}" = "npcx_uut" ]; then dut_control "${MCU}"_boot_mode:off fi if servo_is_ccd; 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 # TODO: the name of the RO images created for zephyr vary based on whether # the RO image includes a header. # NPCX images use "build-ro/zephyr/zephyr.npcx.bin" # ITE images use "build-ro/zephyr/zephyr.bin" if [ "${FLAGS_ro}" = ${FLAGS_TRUE} ] && [ "${FLAGS_zephyr}" = ${FLAGS_TRUE} ] then die "The --ro flag is not supported with the --zephyr flag" fi # Possible default EC images if [ "${FLAGS_ro}" = ${FLAGS_TRUE} ] ; then EC_FILE=ec.RO.flat elif [ "${FLAGS_zephyr}" = ${FLAGS_TRUE} ] ; then EC_FILE=zephyr.bin 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}" elif [ "${FLAGS_zephyr}" = ${FLAGS_TRUE} ] ; then LOCAL_BUILD="${EC_DIR}/build/${ZEPHYR_DIR}/output/${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." } # Get the correct UART for flashing. The resulting string is concatenated with # the various UART control suffixes, such as "_pty", "_en", "_parity", etc. function servo_ec_uart_prefix() { if [[ "${MCU}" == "fpmcu" ]]; then # The FPMCU has multiple UARTs. Use the platform UART since it's a # bootloader capable UART on all devices. See # http://go/cros-fingerprint-reference-designs#uart-console. echo "fpmcu_platform_uart" return fi echo "${MCU}_uart" } # Find the EC UART provided by servo. function servo_ec_uart() { SERVOD_FAIL="Cannot communicate with servod. Is servod running?" local EC_UART_PREFIX EC_UART_PREFIX="$(servo_ec_uart_prefix)" PTY=$(dut_control_get "raw_${EC_UART_PREFIX}_pty" || dut_control_get "${EC_UART_PREFIX}_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" ) c2d2_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[@]}" ) declare -a save ####################################### # Store DUT control value to restore in LIFO order. # 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}" "${save[@]}" ) fi ;; 2) save=( "$1:$2" "${save[@]}" ) ;; *) 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 | grep -v '^f' | 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 } # Returns the serialnumber of the specified servo. function get_serial() { if [[ "${SERVO_TYPE}" =~ ^servo_v4(p1)?_with_servo_micro ]]; then if [[ -z "${BOARD}" ]]; then sn_ctl="servo_micro_" elif [[ "$(dut_control_get "servo_micro_for_${BOARD}_serialname")" =~ \ "unknown" ]] ; then # Fall back to servo_micro_ if S/N is uknown. 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" } function c2d2_wait_for_h1_power_on_or_reset() { # Ensure we have the latest c2d2 fw and hdctools. This could # be removed eventually (estimate removal 2020/06/01) dut_control h1_vref_present || die "Need to kill servod and run: repo sync && sudo emerge hdctools servo-firmware && sudo servo_updater -b c2d2" # Handle the case when flash_ec starts before DUT power is # applied. Otherwise just use h1-level reset. if [[ "$(dut_control_get h1_vref_present)" = "off" ]] ; then info "Please attach C2D2 to DUT and power DUT now!" # Waits ~40 seconds for Vref presence before timeout local LOOP_COUNTER=100 while [[ "$(dut_control_get h1_vref_present)" = "off" \ && "${LOOP_COUNTER}" -gt 1 ]] ; do sleep 0.1 let LOOP_COUNTER=LOOP_COUNTER-1 done # If we ran out of time, then just die now if [[ "${LOOP_COUNTER}" -eq 1 ]] ; then die "H1 Vref not present after waiting" fi else # Ensure DUT is in clean state with H1 Reset dut_control cold_reset:on dut_control cold_reset:off fi } # 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 print_or_run 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:$PATH:/usr/sbin" 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=google-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" elif [[ "${CHIP}" == "ite_spi" || "${CHIP}" == "ite_spi_ccd_i2c" ]]; 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 # Enable SPI programming mode. if [[ "${CHIP}" == "ite_spi" || "${CHIP}" == "ite_spi_ccd_i2c" ]]; then # Set hardware strap pin (GPG6) of SPI programming as low then start ec dut_control fw_up:on sleep 0.1 dut_control cold_reset:off sleep 0.1 # We have to release the HW strap pin because it also SPI clock pin. dut_control fw_up: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}" --noverify-all" 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} --flash-size" if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then info "Running flashrom:" 1>&2 echo " ${FLASHROM_GETSIZE}" 1>&2 fi SPI_SIZE=$(${FLASHROM_GETSIZE} | grep -oe '[0-9]\+$' | tail -n1) || 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$ ]] || \ [[ "${CHIP}" =~ "ite_spi_ccd_i2c" ]] || [[ "${CHIP}" =~ "ite_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 print_or_run 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 print_or_run sudo timeout -k 10 -s 9 "${FLAGS_timeout}" \ ${FLASHROM_CMDLINE} -r "${FLAGS_read}" \ || die "${MSG_READ_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)" EC_UART_PREFIX="$(servo_ec_uart_prefix)" 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 "${EC_UART_PREFIX}_en" dut_control "${EC_UART_PREFIX}_en:on" fi servo_save_add "${EC_UART_PREFIX}_parity" dut_control "${EC_UART_PREFIX}_parity:even" if servo_is_ccd ; 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 "${EC_UART_PREFIX}_baudrate" servo_save_add "${EC_UART_PREFIX}_bitbang_en" dut_control "${EC_UART_PREFIX}_baudrate:${FLAGS_bitbang_rate}" dut_control "${EC_UART_PREFIX}_bitbang_en:on" else servo_save_add "${EC_UART_PREFIX}_baudrate" dut_control "${EC_UART_PREFIX}_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_is_ccd ; 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 -u -e -w" if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then echo "${STM32MON_COMMAND} ${IMG}" fi print_or_run 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 print_or_run 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 print_or_run 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 print_or_run sleep 1 # Actual image flashing print_or_run sudo timeout -k 10 -s 9 "${FLAGS_timeout}" $DFU_UTIL -a 0 \ -d "${DFU_DEVICE}" -s ${ADDR}:${SIZE} -D "${IMG}" } 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 local adap_num= adap_num="$(dut_control_get_or_die \ "${ACTIVE_DEVICE}_i2c_pseudo_adapter_num")" echo /dev/i2c-"$adap_num" } 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 # We need to ensure that c2d2 and dut-side path are set up for i2c if [[ "${SERVO_TYPE}" =~ "c2d2" ]]; then c2d2_wait_for_h1_power_on_or_reset # Don't let the EC come out of reset after H1 reset dut_control ec_reset:on # Enable i2c bus on C2D2 at 400kbps servo_save_add "i2c_ec_bus_speed" dut_control_or_die i2c_ec_bus_speed:400 # We need to swing the DUT-side muxes to I2C instead of UART. # This is done by convention with EC_FLASH_SELECT pin from H1 dut_control_or_die ec_flash_select:on 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 # We need to send the special waveform very soon after the EC powers on if [[ "${SERVO_TYPE}" =~ "c2d2" ]]; then # The EC was held in reset above dut_control ec_reset:off elif 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" || \ "${SERVO_TYPE}" =~ "c2d2" ]] ; then info "Asking servo to send the dbgr special waveform to ${CHIP}" dut_control_or_die enable_ite_dfu elif servo_is_ccd; 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_is_ccd; 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_verify}" == "${FLAGS_FALSE}" ]]; then ITEFLASH_ARGS+=( "--noverify" ) fi if [[ "${FLAGS_verbose}" == ${FLAGS_TRUE} ]]; then ITEFLASH_ARGS+=( "--debug" ) echo "${ITEFLASH_ARGS[@]}" fi # Ensure the CR50 doesn't go into low power while flashing # otherwise the DUT side muxes will get cut. Note this also needs to # happen once the CR50 hooks have settled and H1 realizes that the # "AP [is] Off", since that over writes the idle action with sleep. if [[ "${SERVO_TYPE}" =~ "c2d2" ]]; then dut_control cr50_idle_level:active fi print_or_run "${ITEFLASH_ARGS[@]}" || die "${ERROR_MSG}" } function flash_ite_spi() { flash_flashrom } function flash_ite_spi_ccd_i2c() { if [[ "${SERVO_TYPE}" =~ "servo_micro" || \ "${SERVO_TYPE}" =~ "servo_v2" ]] ; then flash_flashrom else flash_it83xx fi } 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")/chip/npcx/spiflashfw" \ "$(dirname "$IMG")" \ "${EC_DIR}/build/${BOARD}/chip/npcx/spiflashfw" \ "${EC_DIR}/build/${ZEPHYR_DIR}/output" \ "$(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 # Ti50 does not yet support ccd_keepalive option which # requires ccdstate command on the GSC console. # TODO(b/161483597) remove the check when Ti50 CCD is on par. servo_save_add ccd_keepalive_en dut_control ccd_keepalive_en:on fi # C2D2 does not use waits and has to ensure that the EC does not come # out of reset after using a H1-level reset if [[ "${SERVO_TYPE}" =~ "c2d2" ]] ; then c2d2_wait_for_h1_power_on_or_reset # Don't let the EC come out of reset after H1 reset dut_control ec_reset:on # Force the EC to boot in UART update mode coming out of reset ec_enable_boot0 "uut" dut_control ec_reset:off # Ensure normal UART operation ec_disable_boot0 "uut" else # Force the EC to boot in UART update mode ec_enable_boot0 "uut" ec_reset # Have to wait a bit for EC boot-up print_or_run sleep 0.1 # Ensure normal UART operation ec_disable_boot0 "uut" print_or_run sleep 0.1 fi # 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 print_or_run 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 print_or_run 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 print_or_run 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 print_or_run 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 } 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."