diff options
Diffstat (limited to 'util/flash_fp_mcu')
-rw-r--r-- | util/flash_fp_mcu | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/util/flash_fp_mcu b/util/flash_fp_mcu new file mode 100644 index 0000000000..6a23aa691c --- /dev/null +++ b/util/flash_fp_mcu @@ -0,0 +1,265 @@ +#!/bin/bash +# Copyright 2019 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. + +. /usr/share/misc/shflags + +DEFINE_boolean 'read' "${FLAGS_FALSE}" 'Read instead of write' 'r' +FLAGS_HELP="Usage: ${0} [flags] ec.bin" + +# Process commandline flags +FLAGS "${@}" || exit 1 +eval set -- "${FLAGS_ARGV}" + +if [[ "$#" -eq 0 ]]; then + echo "Missing filename" + flags_help + exit 1 +fi + +# print out canonical path to differentiate between /usr/local/bin and +# /usr/bin installs +echo "$(readlink -f "$0")" + +readonly CROS_EC_SPI_MODALIAS_STR="of:NcrfpTCgoogle,cros-ec-spi" + +check_hardware_write_protect_disabled() { + local hardware_write_protect_state="$(crossystem wpsw_cur)" + if [[ "${hardware_write_protect_state}" != "0" ]]; then + echo "Please make sure hardware write protect is disabled." + echo "See https://www.chromium.org/chromium-os/firmware-porting-guide/firmware-ec-write-protection" + exit 1 + fi +} + +# Get the spiid for the fingerprint sensor based on the modalias +# string: https://crbug.com/955117 +get_spiid() { + for dev in /sys/bus/spi/devices/*; do + if [[ "$(cat "${dev}/modalias")" == "${CROS_EC_SPI_MODALIAS_STR}" ]]; then + echo "$(basename "${dev}")" + exit 0 + fi + done + + exit 1 +} + +# Taken verbatim from +# https://chromium.googlesource.com/chromiumos/docs/+/master/lsb-release.md#shell +# This should not be used by anything except get_platform_name. +# See https://crbug.com/98462. +lsbval() { + local key="$1" + local lsbfile="${2:-/etc/lsb-release}" + + if ! echo "${key}" | grep -Eq '^[a-zA-Z0-9_]+$'; then + return 1 + fi + + sed -E -n -e \ + "/^[[:space:]]*${key}[[:space:]]*=/{ + s:^[^=]+=[[:space:]]*:: + s:[[:space:]]+$:: + p + }" "${lsbfile}" +} + +# Get the underlying board (reference design) that we're running on (not the +# FPMCU or sensor). +get_platform_name() { + # "-l" converts to lowercase + local -l platform_name="$(cros_config /identity platform-name)" + + # If we don't get any result from cros_config, then we have to possible cases: + # + # 1) We're running on a non-unibuild device (the only one with FP is nocturne) + # 2) We're running on a proto device during bringup and the cros_config + # settings haven't yet been setup. + # + # In either case we can fall back to /etc/lsb-release. It's not recommended + # to do this, but we don't have any other options in this case. + # + # TODO(https://crbug.com/984629): cros_config should handle reading + # /etc/lsb-release as backup for us. + if [[ -z "${platform_name}" ]]; then + echo "Getting platform name from cros_config failed." \ + "Falling back to /etc/lsb-release." 1>&2 + platform_name="$(lsbval "CHROMEOS_RELEASE_BOARD")" + if [[ -z "${platform_name}" ]]; then + exit 1 + fi + fi + + echo "${platform_name}" +} + +check_gpio_chip_exists() { + local gpiochip="$1" + if [[ ! -e "/sys/class/gpio/${gpiochip}" ]]; then + echo "Cannot find GPIO chip: ${gpiochip}" + exit 1 + fi +} + +flash_fp_mcu_stm32() { + local spidev="${1}" + local gpio_nrst="${2}" + local gpio_boot0="${3}" + local gpio_pwren="${4}" + local file="${5}" + local spiid + + local STM32MON_READ_FLAGS=" -U -u -p -s ${spidev} -r" + local STM32MON_WRITE_FLAGS="-U -u -p -s ${spidev} -e -w" + local stm32mon_flags="" + + if [[ "${FLAGS_read}" -eq "${FLAGS_TRUE}" ]]; then + if [[ -e "${file}" ]]; then + echo "Output file already exists: ${file}" + exit 1 + fi + stm32mon_flags="${STM32MON_READ_FLAGS}" + else + if [[ ! -f "${file}" ]]; then + echo "Invalid image file: ${file}" + exit 1 + fi + stm32mon_flags="${STM32MON_WRITE_FLAGS}" + fi + + check_hardware_write_protect_disabled + + spiid="$(get_spiid)" + if [[ $? -ne 0 ]]; then + echo "Unable to find FP sensor SPI device: ${CROS_EC_SPI_MODALIAS_STR}" + exit 1 + fi + + echo "Flashing SPI device ID: ${spiid}" + + # Ensure the ACPI is not cutting power when unloading cros-ec-spi + if [[ -n "${gpio_pwren}" ]]; then + echo "${gpio_pwren}" > /sys/class/gpio/export + echo "out" > "/sys/class/gpio/gpio${gpio_pwren}/direction" + echo 1 > "/sys/class/gpio/gpio${gpio_pwren}/value" + fi + + # Remove cros_fp if present + echo "${spiid}" > /sys/bus/spi/drivers/cros-ec-spi/unbind + + # Configure the MCU Boot0 and NRST GPIOs + echo "${gpio_boot0}" > /sys/class/gpio/export + echo "out" > "/sys/class/gpio/gpio${gpio_boot0}/direction" + echo "${gpio_nrst}" > /sys/class/gpio/export + echo "out" > "/sys/class/gpio/gpio${gpio_nrst}/direction" + + # Reset sequence to enter bootloader mode + echo 1 > "/sys/class/gpio/gpio${gpio_boot0}/value" + echo 0 > "/sys/class/gpio/gpio${gpio_nrst}/value" + sleep 0.001 + + # load spidev (fail on cros-ec-spi first to change modalias) + echo "${spiid}" > /sys/bus/spi/drivers/cros-ec-spi/bind 2>/dev/null + echo "${spiid}" > /sys/bus/spi/drivers/spidev/bind + + # Release reset as the SPI bus is now ready + echo 1 > "/sys/class/gpio/gpio${gpio_nrst}/value" + echo "in" > "/sys/class/gpio/gpio${gpio_nrst}/direction" + + stm32mon ${stm32mon_flags} "${file}" + + # unload spidev + echo "${spiid}" > /sys/bus/spi/drivers/spidev/unbind + + # Go back to normal mode + echo "out" > "/sys/class/gpio/gpio${gpio_nrst}/direction" + echo 0 > "/sys/class/gpio/gpio${gpio_boot0}/value" + echo 0 > "/sys/class/gpio/gpio${gpio_nrst}/value" + echo 1 > "/sys/class/gpio/gpio${gpio_nrst}/value" + + # Give up GPIO control + echo "in" > "/sys/class/gpio/gpio${gpio_boot0}/direction" + echo "in" > "/sys/class/gpio/gpio${gpio_nrst}/direction" + echo "${gpio_boot0}" > /sys/class/gpio/unexport + echo "${gpio_nrst}" > /sys/class/gpio/unexport + + # wait for FP MCU to come back up (including RWSIG delay) + sleep 2 + # Put back cros_fp driver + echo "${spiid}" > /sys/bus/spi/drivers/cros-ec-spi/bind + # Kernel driver is back, we are no longer controlling power + if [[ -n "${gpio_pwren}" ]]; then + echo "${gpio_pwren}" > /sys/class/gpio/unexport + fi + # Test it + ectool --name=cros_fp version +} + +config_hatch() { + check_gpio_chip_exists "gpiochip200" + + readonly SPIDEV="/dev/spidev1.1" + # FPMCU RST_ODL is on GPP_A12 = 200 + 12 = 212 + readonly GPIO_NRST=212 + # FPMCU BOOT0 is on GPP_A22 = 200 + 22 = 222 + readonly GPIO_BOOT0=222 + # No PWREN GPIO on Hatch, FPMCU is always on + readonly GPIO_PWREN="" +} + +config_nami() { + check_gpio_chip_exists "gpiochip360" + + readonly SPIDEV="/dev/spidev32765.0" + # FPMCU RST_ODL is on GPP_C9 = 360 + 57 = 417 + readonly GPIO_NRST=417 + # FPMCU BOOT0 is on GPP_D5 = 360 + 77 = 437 + readonly GPIO_BOOT0=437 + # FP_PWR_EN is on GPP_B11 = 360 + 35 = 395 + readonly GPIO_PWREN=395 +} + +config_nocturne() { + check_gpio_chip_exists "gpiochip360" + + readonly SPIDEV="/dev/spidev32765.0" + # FPMCU RST_ODL is on GPP_C10 = 360 + 58 = 418 + readonly GPIO_NRST=418 + # FPMCU BOOT0 is on GPP_C8 = 360 + 56 = 416 + readonly GPIO_BOOT0=416 + # FP_PWR_EN is on GPP_A11 = 360 + 11 = 371 + readonly GPIO_PWREN=371 +} + +# The "platform name" corresponds to the underlying board (reference design) +# that we're running on (not the FPMCU or sensor). At the moment all of the +# reference designs use the same GPIOs. If for some reason a design differs in +# the future, we will want to add a nested check in the config_<platform_name> +# function. Doing it in this manner allows us to reduce the number of +# configurations that we have to maintain (and reduces the amount of testing +# if we're only updating a specific config_<platform_name>). +readonly PLATFORM_NAME="$(get_platform_name)" + +echo "Using config for ${PLATFORM_NAME}" + +# Check that the config function exists +if [[ "$(type -t "config_${PLATFORM_NAME}")" != "function" ]]; then + echo "No config for platform ${PLATFORM_NAME}" + exit 1 +fi + +config_${PLATFORM_NAME} + +if [[ $? -ne 0 ]]; then + echo "Configuration failed for platform ${PLATFORM_NAME}" + exit 1 +fi + +flash_fp_mcu_stm32 \ + "${SPIDEV}" \ + "${GPIO_NRST}" \ + "${GPIO_BOOT0}" \ + "${GPIO_PWREN}" \ + "${1}" |