| #!/bin/bash |
| |
| # Copyright 2014 The ChromiumOS Authors |
| # 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. |
| # shellcheck source=../../../scripts/lib/shflags/shflags |
| . "${SHFLAGS:-/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 |
| reef_it8320 |
| ) |
| |
| 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 |
| strago_pd |
| zinger |
| ) |
| BOARDS_STM32_PROG_EN=( |
| ) |
| |
| 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=( |
| buccaneer |
| helipilot |
| ) |
| |
| BOARDS_NPCX_INT_SPI=( |
| adlrvpp_npcx |
| mtlrvpp_npcx |
| mtlrvpp_pd |
| ) |
| |
| BOARDS_SPI_1800MV=( |
| coral |
| reef |
| ) |
| |
| # hold cold_reset:on when using debug header (e.g. servo header) |
| BOARDS_HOLD_COLD_RESET_DBG_HDR=( |
| reef |
| ) |
| |
| BOARDS_RAIDEN=( |
| coral |
| eve |
| fizz |
| kukui |
| nami |
| nautilus |
| poppy |
| rammus |
| reef |
| soraka |
| ) |
| |
| BOARDS_MCHP_INT_SPI=( |
| mtlrvpp_mchp |
| ) |
| 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 "" \ |
| "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 mchp_loader "" \ |
| "Full pathname of the Microchip loader firmware image to SRAM." |
| 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" |
| DEFINE_boolean no_preserve "${FLAGS_FALSE}" \ |
| "Avoid preserving the sections of firmware image with preserve property" |
| DEFINE_boolean try_apshutdown "${FLAGS_FALSE}" \ |
| "Shutdown the AP immediately after flashing. It does not guarantee a " \ |
| "successful AP shutdown for all devices or in all situations. You need" \ |
| " to understand the limitations when you build a solution on it. " |
| DEFINE_integer try_apshutdown_count 16 \ |
| "Number of attempts to shutdown the AP immediately after flashing." |
| DEFINE_string dut_ip "" \ |
| "DUT IP address" |
| DEFINE_string token_db "${EC_DIR}/build/tokens.bin" \ |
| "Full pathname of the EC tokenized database to copy to DUT." |
| # shellcheck disable=SC2034 # Remove someday when autorepair doesn't use it. |
| DEFINE_boolean use_i2c_pseudo "${FLAGS_FALSE}" \ |
| "Ignored." |
| |
| # 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." |
| MSG_CHIP_READ_INVALID="Invalid chip type passed to be read" |
| |
| set -e |
| |
| if [[ -n "${BAZEL_DUT_CONTROL}" ]]; then |
| DUT_CONTROL_CMD=( "${BAZEL_DUT_CONTROL}" ) |
| else |
| DUT_CONTROL_CMD=( "dut-control" ) |
| fi |
| DUT_CONTROL_CMD+=( "--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 |
| if [[ "${FLAGS_verbose}" == "${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 |
| |
| echo "${quoted_args[@]}" >&2 |
| fi |
| "$@" |
| fi |
| } |
| |
| # Helper routine to test if specific control is available. |
| # This always executes, even with --dry_run so that the control flow |
| # of the script continues normally. |
| function dut_has_control() { |
| local CONTROL=$1 |
| |
| "${DUT_CONTROL_CMD[@]}" -i "${CONTROL}" >/dev/null 2>&1 |
| } |
| |
| 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 |
| |
| 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}}" |
| |
| 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 in_array "${BOARDS_MCHP_INT_SPI[@]}" "${BOARD}"; then |
| SUPPORTED_CHIPS+=("mchp_int_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" \ |
| "(${SUPPORTED_CHIPS[*]}). Use --chip= to choose one." |
| fi |
| |
| if [ -n "${FLAGS_chip}" ] && [ "${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|buccaneer|dartmonkey|hatch_fp|helipilot|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"|"ite_i2c"|"npcx_uut"|"ite_spi"| \ |
| "ite_spi_ccd_i2c"|"it8xxx2"|"mchp_int_spi") |
| ;; |
| *) |
| 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)" |
| if [[ ${ACTIVE_DEVICE} == neither ]]; then |
| die "Could not determine servo V4 active device" |
| fi |
| 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" ]] |
| } |
| |
| servo_has_warm_reset() { |
| dut_has_control warm_reset |
| } |
| |
| servo_has_cold_reset() { |
| dut_has_control cold_reset |
| } |
| |
| servo_has_dut_i2c_mux() { |
| dut_has_control dut_i2c_mux |
| } |
| |
| servo_has_dut_i2c_en() { |
| dut_has_control dut_i2c_en |
| } |
| |
| servo_ec_hard_reset_or_die() { |
| # Cold reset on C2D2 is H1 reset, which will double reset the EC |
| if [[ "${SERVO_TYPE}" =~ "c2d2" ]]; then |
| dut_control_or_die gsc_ec_reset:on |
| dut_control_or_die gsc_ec_reset:off |
| elif servo_has_cold_reset; then |
| dut_control_or_die cold_reset:on |
| dut_control_or_die cold_reset:off |
| else |
| info "Skipping cold reset" |
| 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 |
| |
| # b/177331210: Workaround for an outstanding issue that prevents |
| # flashing dartmonkey with a servo_micro. The exact root cause is still |
| # unknown, but it's been observed that repeating the FPMCU reset |
| # sequence twice makes the operation succeed. |
| if [[ "${BOARD}" =~ "dartmonkey" ]] ; then |
| warn "Workaround for dartmonkey + servo_micro: repeat FPMCU reset sequence" |
| dut_control fpmcu_reset:on sleep:0.5 fpmcu_reset:off |
| fi |
| } |
| |
| 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" ] || [ "${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 |
| |
| if [[ "${FLAGS_try_apshutdown}" == "${FLAGS_TRUE}" ]]; then |
| info "Attempting to shut down the AP..." |
| dut_control ec_uart_regexp:None |
| for (( i = 0; i < "${FLAGS_try_apshutdown_count}"; i++ )); do |
| dut_control ec_uart_cmd:apshutdown |
| sleep 1 |
| done |
| 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 |
| 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/${BOARD}/output/${EC_FILE}" |
| else |
| LOCAL_BUILD="${EC_DIR}/build/${BOARD}/${EC_FILE}" |
| fi |
| fi |
| |
| LOCAL_TOKEN_DB= |
| if [[ -n "${EC_DIR}" ]]; then |
| if [ -f "${EC_DIR}/build/tokens.bin" ] ; then |
| LOCAL_TOKEN_DB="${EC_DIR}/build/tokens.bin" |
| 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) |
| elif [ -z "${FLAGS_image}" ] ; then |
| info "Could not find ec build folder to calculate baseboard." |
| fi |
| # shellcheck disable=SC2181 |
| if [ $? -ne 0 ] && [ -z "${FLAGS_image}" ]; 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 [ -e "${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." |
| } |
| |
| function ec_token_database() { |
| # No token database specified on command line, try default location |
| if [[ -n "${FLAGS_token_db}" ]] ; then |
| if [ -e "${FLAGS_token_db}" ] || \ |
| [ "${FLAGS_token_db}" == "-" ]; then |
| echo "${FLAGS_token_db}" |
| return |
| fi |
| die "Invalid image path : ${FLAGS_token_db}" |
| else |
| if [ -f "${LOCAL_TOKEN_DB}" ]; then |
| echo "${LOCAL_TOKEN_DB}" |
| return |
| fi |
| fi |
| die "no token database found : specify one." |
| } |
| |
| function load_token_db() { |
| local TOKEN_DB |
| local DUT_IP |
| |
| TOKEN_DB="$(ec_token_database)" |
| DUT_IP="${FLAGS_dut_ip}" |
| |
| info "TOKEN_DB=${TOKEN_DB}" |
| info "DUT_IP=${DUT_IP}" |
| |
| ssh root@"${DUT_IP}" 'mkdir -p /usr/local/cros_ec/' |
| scp "${TOKEN_DB}" root@"${DUT_IP}":/usr/local/cros_ec/tokens.bin |
| |
| return |
| } |
| |
| # Find the Loader image to use |
| function mchp_loader_image() { |
| # Use the image specified on the command line |
| if [[ -n "${FLAGS_mchp_loader}" ]] ; then |
| if [ -e "${FLAGS_mchp_loader}" ] || \ |
| [ "${FLAGS_mchp_loader}" == "-" ]; then |
| LOADER=${FLAGS_mchp_loader} |
| fi |
| # Try default one |
| else |
| for dir in \ |
| "$(dirname "${IMG}")" \ |
| "${EC_DIR}/build/${BOARD}/output" \ |
| "${EC_DIR}/build/zephyr/${BOARD}/output" \ |
| "$(dirname "${LOCAL_BUILD}")" \ |
| "$(dirname "${EMERGE_BUILD}")" ; |
| do |
| if [ -f "${dir}/second_loader_fw.bin" ] ; then |
| LOADER="${dir}/second_loader_fw.bin" |
| break |
| fi |
| done |
| fi |
| |
| if [ -z "${LOADER}" ] ; then |
| die "No loader image found: build one or specify correct one" |
| fi |
| |
| info "using MCHP loader: ${LOADER}" |
| echo "${LOADER}" |
| } |
| |
| # 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}" |
| } |
| |
| 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() { |
| servo_save_add "cold_reset" |
| |
| 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 |
| warn "You might want to 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 |
| # shellcheck disable=SC2009 |
| 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 if get_serial used CCD. |
| function get_serial_is_ccd() { |
| if [[ "${SERVO_TYPE}" =~ ^servo_v4(p1)?_with_servo_micro ]]; then |
| false |
| elif [[ "${SERVO_TYPE}" =~ ^servo_v4(p1)?_with_c2d2 ]]; then |
| false |
| elif [[ "${SERVO_TYPE}" =~ "_with_ccd" ]] ; then |
| true |
| else |
| false |
| fi |
| } |
| |
| # 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}" =~ ^servo_v4(p1)?_with_c2d2 ]]; then |
| if [[ -z "${BOARD}" ]]; then |
| sn_ctl="c2d2_" |
| elif [[ "$(dut_control_get "c2d2_for_${BOARD}_serialname")" =~ \ |
| "unknown" ]] ; then |
| # Fall back to c2d2_ if S/N is uknown. |
| sn_ctl="c2d2_" |
| else |
| sn_ctl="c2d2_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 |
| (( 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) |
| local TEMP_DIR |
| TEMP_DIR="$(mktemp -d --suffix="${TEMP_SUFFIX}")" |
| DELETE_LIST+=("${TEMP_DIR}") |
| |
| if on_servov3; then |
| FLASHROM_ARGS="--programmer=linux_spi" |
| elif on_raiden; then |
| if [[ "${SERVO_TYPE}" =~ "servo_micro" ]]; then |
| # Servo micro doesn't use the "target" parameter. |
| FLASHROM_ARGS="--programmer=raiden_debug_spi:" |
| else |
| FLASHROM_ARGS="--programmer=raiden_debug_spi:target=EC," |
| fi |
| else |
| FLASHROM_ARGS="--programmer=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 |
| |
| # Eventually remove ite_spi_ccd_i2c once all references are removed |
| 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" || |
| "${CHIP}" == "it8xxx2" ]]; 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.2 |
| if ! in_array "${BOARDS_HOLD_COLD_RESET_DBG_HDR[@]}" "${BOARD}"; then |
| dut_control cold_reset:off |
| fi |
| # Gang programmer mode for npcx_spi requires using dev_mode |
| # rather than fw_up |
| elif [[ "${CHIP}" == "npcx_spi" ]]; then |
| servo_save_add "dev_mode" "off" |
| |
| dut_control dev_mode:on |
| sleep 0.2 |
| if ! in_array "${BOARDS_HOLD_COLD_RESET_DBG_HDR[@]}" "${BOARD}"; then |
| dut_control cold_reset:off |
| fi |
| fi |
| |
| # Enable SPI programming mode. |
| if [[ "${CHIP}" == "ite_spi" || |
| "${CHIP}" == "ite_spi_ccd_i2c" || |
| "${CHIP}" == "it8xxx2" ]]; 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.2 |
| # 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.2 |
| 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. |
| # shellcheck disable=SC2206 |
| 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}" =~ "it8xxx2" ]] || |
| [[ "${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 |
| |
| if [[ "${FLAGS_no_preserve}" == "${FLAGS_FALSE}" ]]; then |
| local IMG_CPY |
| |
| IMG_CPY="${TEMP_DIR}/ec.new.cpy.bin" |
| cat "${T}" > "${IMG_CPY}" |
| T="${IMG_CPY}" |
| preserve_sections "spi" "${T}" "${TEMP_DIR}" \ |
| "${FLASHROM}" "${FLASHROM_ARGS}" || die "${MSG_PROGRAM_FAIL}" |
| fi |
| |
| info "Programming EC firmware image." |
| local FLASHROM_WRITE=("${FLASHROM_CMDLINE[@]}" "${FLASHROM_OPTIONS[@]}") |
| if [[ "${FLAGS_verbose}" == "${FLAGS_TRUE}" ]]; then |
| info "Running flashrom:" 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 |
| 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) |
| 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 |
| local TEMP_DIR |
| TEMP_SUFFIX=".$(basename "${SCRIPT}").${CHIP}" |
| 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) |
| 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 ite_dfu_mode() { |
| # 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}" |
| sleep 3 |
| dut_control_or_die enable_ite_dfu |
| elif servo_is_ccd; then |
| local CCD_I2C_CAP |
| 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 |
| } |
| |
| function flash_it83xx() { |
| local TOOL_PATH="${EC_DIR}/build/host/util:${PATH}" |
| local ITEFLASH_BIN |
| local TEMP_DIR |
| ITEFLASH_BIN=$(PATH="${TOOL_PATH}" which iteflash) |
| TEMP_DIR="$(mktemp -d --suffix="${TEMP_SUFFIX}")" |
| DELETE_LIST+=("${TEMP_DIR}") |
| |
| 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 gsc_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 of the |
| # GSC. Also make sure that the setting is restored after |
| # completion. |
| servo_save_add "ec_flash_select" "off" |
| 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 |
| |
| # The board overlay defines "dut_i2c_en" if there is a signal that |
| # must be asserted to access the I2C programming pins on the dut. |
| if servo_has_dut_i2c_en; then |
| info "Enabling I2C programming to ${CHIP}" |
| servo_save_add "dut_i2c_en" |
| dut_control dut_i2c_en:on |
| 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 gsc_ec_reset:off |
| else |
| servo_ec_hard_reset_or_die |
| fi |
| |
| ite_dfu_mode |
| |
| # 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+=( "--send-waveform=0" "--i2c-interface=usb" \ |
| "-s" "$(get_serial)" ) |
| if get_serial_is_ccd; then |
| ITEFLASH_ARGS+=( "--block-write-size=256" ) |
| fi |
| fi |
| |
| if [[ "${FLAGS_no_preserve}" == "${FLAGS_FALSE}" && \ |
| -z "${FLAGS_read}" ]]; then |
| local IMG_CPY |
| |
| IMG_CPY="${TEMP_DIR}/ec.new.cpy.bin" |
| cat "${IMG}" > "${IMG_CPY}" |
| IMG="${IMG_CPY}" |
| preserve_sections "ite_i2c" "${IMG}" "${TEMP_DIR}" \ |
| "${ITEFLASH_ARGS[@]}" || die "${MSG_PROGRAM_FAIL}" |
| 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" ) |
| 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}" |
| } |
| |
| # Alias for flashing ITE chips over I2C from all servo types. |
| function flash_ite_i2c() { |
| flash_it83xx |
| } |
| |
| # Alias for flashing ITE chips over SPI from all servo types. |
| function flash_ite_spi() { |
| flash_flashrom |
| } |
| |
| # Flash ITE chips over SPI when using the servod debug connector |
| # and over I2C whn using CCD. |
| function flash_ite_spi_ccd_i2c() { |
| if [[ "${SERVO_TYPE}" =~ "servo_micro" || \ |
| "${SERVO_TYPE}" =~ "servo_v2" ]] ; then |
| flash_flashrom |
| else |
| flash_it83xx |
| fi |
| } |
| |
| # Flash ITE chips over SPI when using the servod debug connector |
| # and over I2C whn using CCD. |
| function flash_it8xxx2() { |
| flash_ite_spi_ccd_i2c |
| } |
| |
| 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 NPCX_UUT |
| local EC_UART |
| local TEMP_SUFFIX |
| local TEMP_DIR |
| local TOOL_PATH="${EC_DIR}/build/${BOARD}/util:${PATH}" |
| set +e |
| NPCX_UUT=$(PATH="${TOOL_PATH}" which uartupdatetool) |
| set -e |
| EC_UART="$(servo_ec_uart)" |
| TEMP_SUFFIX=".$(basename "${SCRIPT}").${CHIP}.$$" |
| TEMP_DIR="$(mktemp -d --suffix="${TEMP_SUFFIX}")" |
| DELETE_LIST+=("${TEMP_DIR}") |
| |
| # 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/${BOARD}/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 gsc_ec_reset:on |
| |
| # Force the EC to boot in UART update mode coming out of reset |
| ec_enable_boot0 "uut" |
| dut_control gsc_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 |
| local monitor_res=0 |
| print_or_run timeout -k 10 -s 9 "${FLAGS_timeout}" \ |
| "${UUT_MON[@]}" || monitor_res=$? |
| |
| if [[ ${monitor_res} != 0 ]]; then |
| # Try to determine if WP is enabled |
| local dut_res=0 |
| local wp_state |
| wp_state=$(dut-control fw_wp_state) || dut_res=$? |
| |
| if [[ ${dut_res} = 0 ]]; then |
| if echo "${wp_state}" | grep "on"; then |
| die "Failed to load monitor binary, WP is enabled" |
| fi |
| fi |
| |
| die "Failed to load monitor binary." |
| fi |
| |
| if [[ "${FLAGS_no_preserve}" == "${FLAGS_FALSE}" ]]; then |
| local IMG_CPY |
| |
| IMG_CPY="${TEMP_DIR}/ec.new.cpy.bin" |
| cat "${IMG}" > "${IMG_CPY}" |
| IMG="${IMG_CPY}" |
| preserve_sections "${CHIP}" "${IMG}" "${TEMP_DIR}" \ |
| "${NPCX_UUT}" "${UUT_ARGS[@]}" || die "${MSG_PROGRAM_FAIL}" |
| fi |
| |
| info "Programming EC firmware image." |
| local UUT_WR=( "${NPCX_UUT}" "${UUT_ARGS[@]}" \ |
| "--auto" "--offset=${FLAGS_offset}" \ |
| "--file=${IMG}" ) |
| 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 |
| IMG_READ="${TEMP_DIR}/ec.read.bin" |
| 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}" ) |
| |
| 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." |
| |
| 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_mchp_int_spi() { |
| EC_UART="$(servo_ec_uart)" |
| EC_UART_PREFIX="$(servo_ec_uart_prefix)" |
| MCHP_DIR="${EC_DIR}/util/mchp" |
| |
| # Gather the image information before changing the UART settings |
| MCHP_LOADER=$(mchp_loader_image) |
| EC_IMAGE=$(ec_image) |
| |
| # Store the EC UART interpreter status |
| ec_ec3po_interp="$(dut_control_get ec_ec3po_interp_connect)" |
| servo_save_add "ec_ec3po_interp_connect" "${ec_ec3po_interp}" |
| |
| # Disable the EC UART interpreter |
| dut_control ec_ec3po_interp_connect:off |
| |
| # Use of --value_only argument helps to get only baudrate value. |
| current_baudrate="$(dut_control_get "${EC_UART_PREFIX}"_baudrate)" |
| |
| # On script exit, serial port will be configured back with saved |
| # baudrate by servo_restore thru cleanup method |
| servo_save_add "${EC_UART_PREFIX}_baudrate" "${current_baudrate}" |
| |
| # Reset chip in firmware update mode |
| dut_control cold_reset:on fw_up:on cold_reset:off |
| |
| # Set 9600 baudrate to program Second loader image |
| sec_load_baudrate=9600 |
| if [ "${current_baudrate}" != "${sec_load_baudrate}" ] ; then |
| dut_control "${EC_UART_PREFIX}"_baudrate:"${sec_load_baudrate}" |
| fi |
| # Load Second loader image into SRAM |
| "${MCHP_DIR}"/crisis_rcvry_util.py -s "${MCHP_LOADER}" -p "${EC_UART}" |
| |
| # Set 57600 baudrate to program EC image |
| image_load_baudrate=57600 |
| dut_control "${EC_UART_PREFIX}"_baudrate:"${image_load_baudrate}" |
| |
| # Flash EC image into the internal flash |
| "${MCHP_DIR}"/crisis_rcvry_util.py -e "${EC_IMAGE}" -p "${EC_UART}" |
| |
| # Reset chip in firmware execution mode |
| dut_control cold_reset:on fw_up:off cold_reset:off |
| |
| # Restore the EC UART interpreter back |
| dut_control ec_ec3po_interp_connect:"${ec_ec3po_interp}" |
| } |
| |
| 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 |
| |
| function preserve_sections() { |
| local CHIP_TYPE |
| local NEW_IMG |
| local TEMP_DIR |
| local CHIP_CMD_PREFIX |
| |
| CHIP_TYPE=${1:?"missing arg 1: Chip type"} |
| shift |
| NEW_IMG=${1:?"missing arg 2: New EC image path"} |
| NEW_IMG=$(readlink -f "${NEW_IMG}") |
| shift |
| TEMP_DIR=${1:?"missing arg 3: Temp directory path"} |
| shift |
| CHIP_CMD_PREFIX=("$@") |
| ( |
| cd "${TEMP_DIR}" |
| local NEW_FMAP |
| local NEW_FMAP_OFFSET |
| local NEW_FMAP_SIZE |
| local CUR_FMAP_IMG |
| local CUR_IMG |
| local CUR_FMAP_HEADER |
| |
| NEW_FMAP=$(dump_fmap "${NEW_IMG}" -e FMAP) |
| NEW_FMAP_NFIELD=$(echo "${NEW_FMAP}" | awk '{print NF}') |
| if [ "${NEW_FMAP_NFIELD}" -ne 4 ]; then |
| die "The output of dump_fmap is not expected; try update_chroot" |
| fi |
| |
| NEW_FMAP_OFFSET=$(echo "${NEW_FMAP}" | awk '{print $2}') |
| NEW_FMAP_SIZE=$(echo "${NEW_FMAP}" | awk '{print $3}') |
| CUR_FMAP_IMG="${TEMP_DIR}/ec.cur.fmap.bin" |
| CUR_IMG="${TEMP_DIR}/ec.cur.bin" |
| info "Reading FMAP section from EC chip" |
| read_chip_partially "${CHIP_TYPE}" "${NEW_FMAP_OFFSET}" \ |
| "${NEW_FMAP_SIZE}" "${CUR_FMAP_IMG}" "FMAP" \ |
| "${CHIP_CMD_PREFIX[@]}" |
| # Verify the partial file starts with the correct FMAP header. |
| # If the FMAP has moved between the current image and new |
| # image, this should catch this. |
| # bash can't store NUL characters into variables so strip |
| # any read from the file. |
| CUR_FMAP_HEADER=$(head -c 8 "${CUR_FMAP_IMG}" | tr -d '\0') |
| if [[ "${CUR_FMAP_HEADER}" != "__FMAP__" ]]; then |
| info "FMAP section read failed, reading complete image" |
| read_chip "${CHIP_TYPE}" "${CUR_IMG}" "${CHIP_CMD_PREFIX[@]}" |
| check_preserve_sections_not_present "${CUR_IMG}" \ |
| "${NEW_IMG}" "${TEMP_DIR}" || die |
| preserve_sections_with_cur_image "${CUR_IMG}" "${NEW_IMG}" "${TEMP_DIR}" |
| else |
| info "FMAP read is successful from EC flash" |
| check_preserve_sections_not_present "${CUR_FMAP_IMG}" \ |
| "${NEW_IMG}" "${TEMP_DIR}" || die |
| preserve_sections_with_fmap_image "${CUR_FMAP_IMG}" \ |
| "${NEW_IMG}" "${TEMP_DIR}" "${CHIP_TYPE}" \ |
| "${CHIP_CMD_PREFIX[@]}" |
| fi |
| ) |
| } |
| |
| function check_preserve_sections_not_present() { |
| local CUR_IMG |
| local NEW_IMG |
| local TEMP_DIR |
| |
| CUR_IMG=${1:?"missing arg 1: Cur EC image path"} |
| NEW_IMG=${2:?"missing arg 2: New EC image path"} |
| TEMP_DIR=${3:?"missing arg 3: Temp directory path"} |
| |
| if ! dump_fmap "${CUR_IMG}" -e | grep -q ' preserve'; then |
| info "No sections are being preserved" |
| else |
| check_preserve_sections_presence "${CUR_IMG}" "${NEW_IMG}" "${TEMP_DIR}" |
| fi |
| } |
| |
| function preserve_sections_with_fmap_image() { |
| local CUR_FMAP_IMG |
| local NEW_IMG |
| local TEMP_DIR |
| local CHIP_TYPE |
| local CHIP_CMD_PREFIX |
| |
| CUR_FMAP_IMG=${1:?"missing arg 1: Cur EC FMAP image path"} |
| shift |
| NEW_IMG=${1:?"missing arg 2: New EC image path"} |
| shift |
| TEMP_DIR=${1:?"missing arg 3: Temp directory path"} |
| shift |
| CHIP_TYPE=${1:?"missing arg 4: Chip type"} |
| shift |
| CHIP_CMD_PREFIX=("$@") |
| ( |
| cd "${TEMP_DIR}" |
| dump_fmap "${CUR_FMAP_IMG}" -e | grep ' preserve' | cut \ |
| -f1 -d' ' | |
| while read -r line |
| do |
| local SEC_IMG |
| local SEC_FMAP_DUMP |
| local SEC_OFFSET |
| local SEC_SIZE |
| |
| SEC_IMG="${TEMP_DIR}/ec.cur.${line}.bin" |
| SEC_FMAP_DUMP=$(dump_fmap "${CUR_FMAP_IMG}" -e "${line}") |
| SEC_OFFSET=$(echo "${SEC_FMAP_DUMP}" | awk '{print $2}') |
| SEC_SIZE=$(echo "${SEC_FMAP_DUMP}" | awk '{print $3}') |
| info "Reading ${line} section from EC chip" |
| read_chip_partially "${CHIP_TYPE}" \ |
| "${SEC_OFFSET}" "${SEC_SIZE}" "${SEC_IMG}" "${line}" "${CHIP_CMD_PREFIX[@]}" |
| info "Preserving ${line} section in new image" |
| futility load_fmap "${NEW_IMG}" "${line}:${SEC_IMG}" |
| done |
| ) |
| } |
| |
| function preserve_sections_with_cur_image() { |
| local CUR_IMG |
| local NEW_IMG |
| local TEMP_DIR |
| |
| CUR_IMG=${1:?"missing arg 1: Cur EC image path"} |
| NEW_IMG=${2:?"missing arg 2: New EC image path"} |
| TEMP_DIR=${3:?"missing arg 3: Temp directory path"} |
| ( |
| cd "${TEMP_DIR}" |
| dump_fmap "${CUR_IMG}" -e | grep ' preserve' | cut \ |
| -f1 -d' ' | |
| while read -r line |
| do |
| local SEC_IMG |
| |
| info "Preserving ${line} section on EC chip" |
| SEC_IMG="${TEMP_DIR}/ec.cur.${line}.bin" |
| futility dump_fmap -x "${CUR_IMG}" "${line}" |
| mv "${line}" "${SEC_IMG}" |
| futility load_fmap "${NEW_IMG}" "${line}:${SEC_IMG}" |
| done |
| ) |
| } |
| |
| function read_chip_partially() { |
| local CHIP_TYPE |
| local OFFSET |
| local SIZE |
| local FILE_PATH |
| local SECTION |
| local CHIP_CMD_PREFIX |
| |
| CHIP_TYPE=${1:?"missing arg 1: Chip type"} |
| shift |
| OFFSET=${1:?"missing arg 2: Offset"} |
| shift |
| SIZE=${1:?"missing arg 3: Size"} |
| shift |
| FILE_PATH=${1:?"missing arg 4: Image storage path"} |
| shift |
| SECTION=${1:?"missing arg 5: Section name"} |
| shift |
| CHIP_CMD_PREFIX=("$@") |
| |
| if [ "${CHIP_TYPE}" = "npcx_uut" ]; then |
| local NPCX_BASE_ADDR |
| |
| NPCX_BASE_ADDR=0x64000000 |
| OFFSET=$(("${NPCX_BASE_ADDR}" + "${OFFSET}")) |
| UUT_CUR_FMAP_RD=( "${CHIP_CMD_PREFIX[@]}" "--opr=rd" \ |
| "--addr=${OFFSET}" "--size=${SIZE}" \ |
| "--file=${FILE_PATH}" ) |
| print_or_run timeout -k 10 -s 9 "${FLAGS_timeout}" \ |
| "${UUT_CUR_FMAP_RD[@]}" || die "${MSG_READ_FAIL}" |
| elif [ "${CHIP_TYPE}" == "ite_i2c" ]; then |
| local UUT_CUR_FMAP_RD |
| local ALIGNED_START SKIP_BYTES ALIGNED_SIZE RANGE ALIGNED_FILE |
| |
| # ITE flash tool can start reads on a 256 byte page boundary |
| info "ITE partial read: offset ${OFFSET} size ${SIZE}" |
| |
| ALIGNED_START=$((OFFSET & 0xFFFFFF00)) |
| SKIP_BYTES=$((OFFSET - ALIGNED_START)) |
| ALIGNED_SIZE=$((SIZE + SKIP_BYTES)) |
| ALIGNED_FILE="${FILE_PATH}.aligned" |
| |
| # --range requires hex representation |
| RANGE=$(printf '0x%x:0x%x' "${ALIGNED_START}" "${ALIGNED_SIZE}" ) |
| info "ITE partial read range ${RANGE}" |
| |
| UUT_CUR_FMAP_RD=( "${CHIP_CMD_PREFIX[@]}" \ |
| "--read=${ALIGNED_FILE}" "--range=${RANGE}") |
| print_or_run timeout -k 10 -s 9 "${FLAGS_timeout}" \ |
| "${UUT_CUR_FMAP_RD[@]}" || die "${MSG_READ_FAIL}" |
| |
| if [[ "${ALIGNED_START}" != "${OFFSET}" ]]; then |
| local DD_CMD |
| # We had to read extra data from the DUT. Use dd |
| # to extract just the portion needed. |
| info "Extract ${SIZE} bytes from temp file" |
| DD_CMD=( "dd" "if=${ALIGNED_FILE}" "of=${FILE_PATH}" \ |
| "skip=${SKIP_BYTES}" "count=${SIZE}" "bs=1" ) |
| print_or_run "${DD_CMD[@]}" |
| else |
| # Extracted file has what we need |
| print_or_run mv "${ALIGNED_FILE}" "${FILE_PATH}" |
| fi |
| |
| # Reset EC before setting DFU mode |
| servo_ec_hard_reset_or_die |
| # ITE DFU mode must be re-enabled after each operation |
| ite_dfu_mode |
| elif [ "${CHIP_TYPE}" == "spi" ]; then |
| local FLASHROM_FMAP_RD |
| |
| FLASHROM_FMAP_RD=( "sudo" "${CHIP_CMD_PREFIX[@]}" \ |
| "--extract" "--include=${SECTION}:${FILE_PATH}") |
| print_or_run timeout -k 10 -s 9 "${FLAGS_timeout}" \ |
| "${FLASHROM_FMAP_RD[@]}" || die "${MSG_READ_FAIL}" |
| else |
| die "${MSG_CHIP_READ_INVALID}" |
| fi |
| } |
| |
| function read_chip() { |
| local CHIP_TYPE |
| local FILE_PATH |
| local UUT_CUR_RD |
| local FLASHROM_RD |
| local CHIP_CMD_PREFIX |
| |
| CHIP_TYPE=${1:?"missing arg 1: Chip type"} |
| shift |
| FILE_PATH=${1:?"missing arg 2: Image storage path"} |
| shift |
| CHIP_CMD_PREFIX=("$@") |
| |
| if [ "${CHIP_TYPE}" = "npcx_uut" ]; then |
| UUT_CUR_RD=( "${CHIP_CMD_PREFIX[@]}" "--read-flash" "--file=${FILE_PATH}" ) |
| print_or_run timeout -k 10 -s 9 "${FLAGS_timeout}" \ |
| "${UUT_CUR_RD[@]}" || die "${MSG_READ_FAIL}" |
| elif [ "${CHIP_TYPE}" == "ite_i2c" ]; then |
| UUT_CUR_RD=( "${CHIP_CMD_PREFIX[@]}" "--read=${FILE_PATH}" ) |
| print_or_run timeout -k 10 -s 9 "${FLAGS_timeout}" \ |
| "${UUT_CUR_RD[@]}" || die "${MSG_READ_FAIL}" |
| |
| # Reset EC before setting DFU mode |
| servo_ec_hard_reset_or_die |
| # ITE DFU mode must be re-enabled after each operation |
| ite_dfu_mode |
| elif [ "${CHIP_TYPE}" == "spi" ]; then |
| FLASHROM_RD=( "sudo" "${CHIP_CMD_PREFIX[@]}" "--read=${FILE_PATH}" ) |
| print_or_run timeout -k 10 -s 9 "${FLAGS_timeout}" \ |
| "${FLASHROM_RD[@]}" || die "${MSG_READ_FAIL}" |
| else |
| die "${MSG_CHIP_READ_INVALID}" |
| fi |
| } |
| |
| function check_preserve_sections_presence() { |
| local CUR_IMG |
| local NEW_IMG |
| local TEMP_DIR |
| |
| CUR_IMG=${1:?"missing arg 1: Cur EC image path"} |
| NEW_IMG=${2:?"missing arg 2: New EC image path"} |
| TEMP_DIR=${3:?"missing arg 3: Temp directory path"} |
| ( |
| cd "${TEMP_DIR}" |
| dump_fmap "${CUR_IMG}" -e | grep ' preserve' | cut \ |
| -f1 -d' ' | |
| while read -r line |
| do |
| if [[ -z "$(dump_fmap "${NEW_IMG}" -e "${line}")" ]]; then |
| die "New image don't contain the ${line} section" |
| fi |
| done |
| ) |
| } |
| |
| if [[ -n "${FLAGS_dut_ip}" ]] ; then |
| info "Updating token database" |
| load_token_db |
| fi |
| |
| info "Flashing chip ${CHIP}." |
| flash_"${CHIP}" |
| info "Flashing done." |