summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJett Rink <jettrink@chromium.org>2020-02-10 16:05:20 -0700
committerCommit Bot <commit-bot@chromium.org>2020-02-25 02:28:19 +0000
commit6331dd76feaa4dfeb5f66635f8b570b884380cb7 (patch)
tree9056a777a62ffb14e3dacd6e4551dfed3ca4387a
parentb7de2bf7b2879d582f0c9878034e6f2bba55cbe5 (diff)
downloadchrome-ec-6331dd76feaa4dfeb5f66635f8b570b884380cb7.tar.gz
servo_micro: move ite flashing code
In preparation for servo_micro and c2d2 to sharing the ite, i2c flashing code, move it to a stm specify common file. It is STM specific because it explicitly uses STM registers to accomplish the non-compliant i2c waveforms needed to put the ITE EC into flash mode. BRANCH=servo BUG=b:148610186,b:79684405 TEST=flash ampton with servo_micro using this code Change-Id: Ia0f3f944df2f8a8ad47ea5a62c5f0edae2c71943 Signed-off-by: Jett Rink <jettrink@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2064592 Reviewed-by: Diana Z <dzigterman@chromium.org>
-rw-r--r--board/servo_micro/board.c304
-rw-r--r--board/servo_micro/board.h33
-rw-r--r--chip/stm32/build.mk1
-rw-r--r--chip/stm32/i2c_ite_flash_support.c335
-rw-r--r--include/config.h6
-rw-r--r--include/i2c_ite_flash_support.h27
6 files changed, 380 insertions, 326 deletions
diff --git a/board/servo_micro/board.c b/board/servo_micro/board.c
index d8611fd493..f7a21a6d95 100644
--- a/board/servo_micro/board.c
+++ b/board/servo_micro/board.c
@@ -10,6 +10,7 @@
#include "gpio.h"
#include "hooks.h"
#include "i2c.h"
+#include "i2c_ite_flash_support.h"
#include "queue_policies.h"
#include "registers.h"
#include "spi.h"
@@ -305,302 +306,6 @@ DECLARE_CONSOLE_COMMAND(hold_usart_low, command_hold_usart_low,
"Get/set the hold-low state for usart port");
/******************************************************************************
- * Commands for sending the magic non-I2C handshake over I2C bus wires to an
- * ITE IT8320 EC chip to enable direct firmware update (DFU) over I2C mode.
- */
-
-#define KHz 1000
-#define MHz (1000 * KHz)
-
-/*
- * These constants are values that one might want to try changing if
- * enable_ite_dfu stops working, or does not work on a new ITE EC chip revision.
- */
-
-#define ITE_DFU_I2C_CMD_ADDR_FLAGS 0x5A
-#define ITE_DFU_I2C_DATA_ADDR_FLAGS 0x35
-
-#define SMCLK_WAVEFORM_PERIOD_HZ (100 * KHz)
-#define SMDAT_WAVEFORM_PERIOD_HZ (200 * KHz)
-
-#define START_DELAY_MS 5
-#define SPECIAL_WAVEFORM_MS 50
-#define PLL_STABLE_MS 10
-
-/*
- * Digital line levels to hold before (PRE_) or after (POST_) sending the
- * special waveforms. 0 for low, 1 for high.
- */
-#define SMCLK_PRE_LEVEL 0
-#define SMDAT_PRE_LEVEL 0
-#define SMCLK_POST_LEVEL 0
-#define SMDAT_POST_LEVEL 0
-
-/* The caller should hold the i2c_lock() for I2C_PORT_MASTER. */
-static int ite_i2c_read_register(uint8_t register_offset, uint8_t *output)
-{
- /*
- * Ideally the write and read would be done in one I2C transaction, as
- * is normally done when reading from the same I2C address that the
- * write was sent to. The ITE EC is abnormal in that regard, with its
- * different addresses for writes vs reads.
- *
- * i2c_xfer() does not support that. Its I2C_XFER_START and
- * I2C_XFER_STOP flag bits do not cleanly support that scenario, they
- * are for continuing transfers without either of STOP or START
- * in-between.
- *
- * For what it's worth, the iteflash.c FTDI-based implementation of this
- * does the same thing, issuing a STOP between the write and read. This
- * works, even if perhaps it should not.
- */
- int ret;
- /* Tell the ITE EC which register we want to read. */
- ret = i2c_xfer_unlocked(I2C_PORT_MASTER,
- ITE_DFU_I2C_CMD_ADDR_FLAGS,
- &register_offset, sizeof(register_offset),
- NULL, 0, I2C_XFER_SINGLE);
- if (ret != EC_SUCCESS)
- return ret;
- /* Read in the 1 byte register value. */
- ret = i2c_xfer_unlocked(I2C_PORT_MASTER,
- ITE_DFU_I2C_DATA_ADDR_FLAGS,
- NULL, 0,
- output, sizeof(*output), I2C_XFER_SINGLE);
- return ret;
-}
-
-/* Helper function to read ITE chip ID, for verifying ITE DFU mode. */
-static int cprint_ite_chip_id(void)
-{
- /*
- * Per i2c_read8() implementation, use an array even for single byte
- * reads to ensure alignment for DMA on STM32.
- */
- uint8_t chipid1[1];
- uint8_t chipid2[1];
- uint8_t chipver[1];
-
- int ret;
- int chip_version;
- int flash_kb;
-
- i2c_lock(I2C_PORT_MASTER, 1);
-
- /* Read the CHIPID1 register. */
- ret = ite_i2c_read_register(0x00, chipid1);
- if (ret != EC_SUCCESS)
- goto unlock;
-
- /* Read the CHIPID2 register. */
- ret = ite_i2c_read_register(0x01, chipid2);
- if (ret != EC_SUCCESS)
- goto unlock;
-
- /* Read the CHIPVER register. */
- ret = ite_i2c_read_register(0x02, chipver);
-
-unlock:
- i2c_lock(I2C_PORT_MASTER, 0);
- if (ret != EC_SUCCESS)
- return ret;
-
- /*
- * Compute chip version and embedded flash size from the CHIPVER value.
- *
- * Chip version is mapping from bit 3-0
- * Flash size is mapping from bit 7-4
- *
- * Chip Version (bits 3-0)
- * 0: AX
- * 1: BX
- * 2: CX
- * 3: DX
- *
- * CX or prior flash size (bits 7-4)
- * 0:128KB
- * 4:192KB
- * 8:256KB
- *
- * DX flash size (bits 7-4)
- * 0:128KB
- * 2:192KB
- * 4:256KB
- * 6:384KB
- * 8:512KB
- */
- chip_version = chipver[0] & 0x07;
- if (chip_version < 0x3) {
- /* Chip version is CX or earlier. */
- switch (chipver[0] >> 4) {
- case 0:
- flash_kb = 128;
- break;
- case 4:
- flash_kb = 192;
- break;
- case 8:
- flash_kb = 256;
- break;
- default:
- flash_kb = -2;
- }
- } else if (chip_version == 0x3) {
- /* Chip version is DX. */
- switch (chipver[0] >> 4) {
- case 0:
- flash_kb = 128;
- break;
- case 2:
- flash_kb = 192;
- break;
- case 4:
- flash_kb = 256;
- break;
- case 6:
- flash_kb = 384;
- break;
- case 8:
- flash_kb = 512;
- break;
- default:
- flash_kb = -3;
- }
- } else {
- /* Unrecognized chip version. */
- flash_kb = -1;
- }
-
- ccprintf("ITE EC info: CHIPID1=0x%02X CHIPID2=0x%02X CHIPVER=0x%02X ",
- chipid1[0], chipid2[0], chipver[0]);
- ccprintf("version=%d flash_bytes=%d\n", chip_version, flash_kb << 10);
-
- /*
- * IT8320_eflash_SMBus_Programming_Guide.pdf says it is an error if
- * CHIPID1 != 0x83.
- */
- if (chipid1[0] != 0x83)
- ret = EC_ERROR_HW_INTERNAL;
-
- return ret;
-}
-
-/* Enable ITE direct firmware update (DFU) mode. */
-static int command_enable_ite_dfu(int argc, char **argv)
-{
- if (argc > 1)
- return EC_ERROR_PARAM_COUNT;
-
- /* Enable peripheral clocks. */
- STM32_RCC_APB2ENR |=
- STM32_RCC_APB2ENR_TIM16EN | STM32_RCC_APB2ENR_TIM17EN;
-
- /* Reset timer registers which are not otherwise set below. */
- STM32_TIM_CR2(16) = 0x0000;
- STM32_TIM_CR2(17) = 0x0000;
- STM32_TIM_DIER(16) = 0x0000;
- STM32_TIM_DIER(17) = 0x0000;
- STM32_TIM_SR(16) = 0x0000;
- STM32_TIM_SR(17) = 0x0000;
- STM32_TIM_CNT(16) = 0x0000;
- STM32_TIM_CNT(17) = 0x0000;
- STM32_TIM_RCR(16) = 0x0000;
- STM32_TIM_RCR(17) = 0x0000;
- STM32_TIM_DCR(16) = 0x0000;
- STM32_TIM_DCR(17) = 0x0000;
- STM32_TIM_DMAR(16) = 0x0000;
- STM32_TIM_DMAR(17) = 0x0000;
-
- /* Prescale to 1 MHz and use ARR to achieve NNN KHz periods. */
- /* This approach is seen in STM's documentation. */
- STM32_TIM_PSC(16) = (CPU_CLOCK / MHz) - 1;
- STM32_TIM_PSC(17) = (CPU_CLOCK / MHz) - 1;
-
- /* Set the waveform periods based on 1 MHz prescale. */
- STM32_TIM_ARR(16) = (MHz / SMCLK_WAVEFORM_PERIOD_HZ) - 1;
- STM32_TIM_ARR(17) = (MHz / SMDAT_WAVEFORM_PERIOD_HZ) - 1;
-
- /* Set output compare 1 mode to PWM mode 1 and enable preload. */
- STM32_TIM_CCMR1(16) =
- STM32_TIM_CCMR1_OC1M_PWM_MODE_1 | STM32_TIM_CCMR1_OC1PE;
- STM32_TIM_CCMR1(17) =
- STM32_TIM_CCMR1_OC1M_PWM_MODE_1 | STM32_TIM_CCMR1_OC1PE;
-
- /* Enable output compare 1. */
- STM32_TIM_CCER(16) = STM32_TIM_CCER_CC1E;
- STM32_TIM_CCER(17) = STM32_TIM_CCER_CC1E;
-
- /* Enable main output. */
- STM32_TIM_BDTR(16) = STM32_TIM_BDTR_MOE;
- STM32_TIM_BDTR(17) = STM32_TIM_BDTR_MOE;
-
- /* Update generation (reinitialize counters). */
- STM32_TIM_EGR(16) = STM32_TIM_EGR_UG;
- STM32_TIM_EGR(17) = STM32_TIM_EGR_UG;
-
- /* Set duty cycle to 0% or 100%, pinning each channel low or high. */
- STM32_TIM_CCR1(16) = SMCLK_PRE_LEVEL ? 0xFFFF : 0x0000;
- STM32_TIM_CCR1(17) = SMDAT_PRE_LEVEL ? 0xFFFF : 0x0000;
-
- /* Enable timer counters. */
- STM32_TIM_CR1(16) = STM32_TIM_CR1_CEN;
- STM32_TIM_CR1(17) = STM32_TIM_CR1_CEN;
-
- /* Set PB8 GPIO to alternate mode TIM16_CH1. */
- /* Set PB9 GPIO to alternate mode TIM17_CH1. */
- gpio_config_module(MODULE_I2C_TIMERS, 1);
-
- msleep(START_DELAY_MS);
-
- /* Set pulse width to half of waveform period. */
- STM32_TIM_CCR1(16) = (MHz / SMCLK_WAVEFORM_PERIOD_HZ) / 2;
- STM32_TIM_CCR1(17) = (MHz / SMDAT_WAVEFORM_PERIOD_HZ) / 2;
-
- msleep(SPECIAL_WAVEFORM_MS);
-
- /* Set duty cycle to 0% or 100%, pinning each channel low or high. */
- STM32_TIM_CCR1(16) = SMCLK_POST_LEVEL ? 0xFFFF : 0x0000;
- STM32_TIM_CCR1(17) = SMDAT_POST_LEVEL ? 0xFFFF : 0x0000;
-
- msleep(PLL_STABLE_MS);
-
- /* Set PB8 GPIO to alternate mode I2C1_SCL. */
- /* Set PB9 GPIO to alternate mode I2C1_DAT. */
- gpio_config_module(MODULE_I2C, 1);
-
- /* Disable timer counters. */
- STM32_TIM_CR1(16) = 0x0000;
- STM32_TIM_CR1(17) = 0x0000;
-
- /* Disable peripheral clocks. */
- STM32_RCC_APB2ENR &=
- ~(STM32_RCC_APB2ENR_TIM16EN | STM32_RCC_APB2ENR_TIM17EN);
-
- return cprint_ite_chip_id();
-}
-DECLARE_CONSOLE_COMMAND(
- enable_ite_dfu, command_enable_ite_dfu, "",
- "Enable ITE Direct Firmware Update (DFU) mode");
-
-/* Read ITE chip ID. Can be used to verify ITE DFU mode. */
-/*
- * TODO(b/79684405): There is nothing specific about Servo Micro in the
- * implementation of the "get_ite_chipid" command. Move the implementation to a
- * common place so that it need not be reimplemented for every Servo version
- * that "enable_ite_dfu" is implemented for.
- */
-static int command_get_ite_chipid(int argc, char **argv)
-{
- if (argc > 1)
- return EC_ERROR_PARAM_COUNT;
-
- return cprint_ite_chip_id();
-}
-DECLARE_CONSOLE_COMMAND(
- get_ite_chipid, command_get_ite_chipid, "",
- "Read ITE EC chip ID, version, flash size (must be in DFU mode)");
-
-/******************************************************************************
* Define the strings used in our USB descriptors.
*/
const void *const usb_strings[] = {
@@ -674,6 +379,13 @@ const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
int usb_i2c_board_is_enabled(void) { return 1; }
+/* Configure ITE flash support module */
+const struct ite_dfu_config_t ite_dfu_config = {
+ .i2c_port = I2C_PORT_MASTER,
+ .scl = GPIO_MASTER_I2C_SCL,
+ .sda = GPIO_MASTER_I2C_SDA,
+};
+
void pvd_interrupt(void) {
/* Clear Pending Register */
STM32_EXTI_PR = EXTI_PVD_EVENT;
diff --git a/board/servo_micro/board.h b/board/servo_micro/board.h
index 9a0ca5824d..50e6910811 100644
--- a/board/servo_micro/board.h
+++ b/board/servo_micro/board.h
@@ -86,38 +86,11 @@
#define CONFIG_USB_I2C
#define CONFIG_I2C
#define CONFIG_I2C_MASTER
-/*
- * iteflash requires 256 byte reads for verifying ITE EC firmware. Without this
- * the limit is CONFIG_I2C_CHIP_MAX_READ_SIZE which is 255 for STM32F0 due to an
- * 8 bit field, per src/platform/ec/include/config.h comment.
- */
-#define CONFIG_I2C_XFER_LARGE_READ
#define I2C_PORT_MASTER 0
-/*
- * As of 2018-11-27 the default for both is 60 bytes. These larger values allow
- * for reflashing of ITE EC chips over I2C
- * (https://issuetracker.google.com/79684405) in reasonably speedy fashion. If
- * the EC firmware defaults are ever raised significantly, consider removing
- * these overrides.
- *
- * As of 2018-11-27 the actual maximum write size supported by the I2C-over-USB
- * protocol is (1<<12)-1, and the maximum read size supported is
- * (1<<15)-1. However compile time assertions require that these values be
- * powers of 2 after overheads are included. Thus, the write limit set here
- * /should/ be (1<<12)-4 and the read limit should be (1<<15)-6, however those
- * ideal limits are not actually possible because servo_micro lacks sufficient
- * spare memory for them. With symmetrical limits, the maximum that currently
- * fits is (1<<11)-4 write limit and (1<<11)-6 read limit, leaving 1404 bytes of
- * RAM available.
- *
- * However even with a sufficiently large write value here, the maximum that
- * actually works as of 2018-12-03 is 255 bytes. Additionally, ITE EC firmware
- * image verification requires exactly 256 byte reads. Thus the only useful
- * powers-of-2-minus-overhead limits to set here are (1<<9)-4 writes and
- * (1<<9)-6 reads, leaving 6012 bytes of RAM available, down from 7356 bytes of
- * RAM available with the default 60 byte limits.
- */
+/* See i2c_ite_flash_support.c for more information about these values */
+#define CONFIG_ITE_FLASH_SUPPORT
+#define CONFIG_I2C_XFER_LARGE_READ
#undef CONFIG_USB_I2C_MAX_WRITE_COUNT
#undef CONFIG_USB_I2C_MAX_READ_COUNT
#define CONFIG_USB_I2C_MAX_WRITE_COUNT ((1<<9) - 4)
diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk
index 6ffe44f88e..8949349aed 100644
--- a/chip/stm32/build.mk
+++ b/chip/stm32/build.mk
@@ -48,6 +48,7 @@ chip-$(CONFIG_SPI_MASTER)+=spi_master$(SPI_TYPE).o
chip-$(CONFIG_COMMON_GPIO)+=gpio.o gpio-$(CHIP_FAMILY).o
chip-$(CONFIG_COMMON_TIMER)+=hwtimer$(TIMER_TYPE).o
chip-$(CONFIG_I2C)+=i2c-$(CHIP_FAMILY).o
+chip-$(CONFIG_ITE_FLASH_SUPPORT)+=i2c_ite_flash_support.o
chip-$(CONFIG_STREAM_USART)+=usart.o usart-$(CHIP_FAMILY).o
chip-$(CONFIG_STREAM_USART)+=usart_rx_interrupt-$(CHIP_FAMILY).o
chip-$(CONFIG_STREAM_USART)+=usart_tx_interrupt.o
diff --git a/chip/stm32/i2c_ite_flash_support.c b/chip/stm32/i2c_ite_flash_support.c
new file mode 100644
index 0000000000..6d1631a5bb
--- /dev/null
+++ b/chip/stm32/i2c_ite_flash_support.c
@@ -0,0 +1,335 @@
+/* Copyright 2020 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.
+ */
+/* STM implementation for flashing ITE-based ECs over i2c */
+
+#include "i2c_ite_flash_support.h"
+#include "i2c.h"
+#include "registers.h"
+#include "time.h"
+
+/*
+ * As of 2018-11-27 the default for both is 60 bytes. These larger values allow
+ * for reflashing of ITE EC chips over I2C
+ * (https://issuetracker.google.com/79684405) in reasonably speedy fashion. If
+ * the EC firmware defaults are ever raised significantly, consider removing
+ * these overrides.
+ *
+ * As of 2018-11-27 the actual maximum write size supported by the I2C-over-USB
+ * protocol is (1<<12)-1, and the maximum read size supported is
+ * (1<<15)-1. However compile time assertions require that these values be
+ * powers of 2 after overheads are included. Thus, the write limit set here
+ * /should/ be (1<<12)-4 and the read limit should be (1<<15)-6, however those
+ * ideal limits are not actually possible because stm32 lacks sufficient
+ * spare memory for them. With symmetrical limits, the maximum that currently
+ * fits is (1<<11)-4 write limit and (1<<11)-6 read limit, leaving 1404 bytes of
+ * RAM available.
+ *
+ * However even with a sufficiently large write value here, the maximum that
+ * actually works as of 2018-12-03 is 255 bytes. Additionally, ITE EC firmware
+ * image verification requires exactly 256 byte reads. Thus the only useful
+ * powers-of-2-minus-overhead limits to set here are (1<<9)-4 writes and
+ * (1<<9)-6 reads, leaving 6012 bytes of RAM available, down from 7356 bytes of
+ * RAM available with the default 60 byte limits.
+ */
+#if CONFIG_USB_I2C_MAX_WRITE_COUNT != ((1<<9) - 4)
+#error Must set CONFIG_USB_I2C_MAX_WRITE_COUNT to ((1<<9) - 4)
+#endif
+#if CONFIG_USB_I2C_MAX_READ_COUNT != ((1<<9) - 6)
+#error Must set CONFIG_USB_I2C_MAX_WRITE_COUNT to ((1<<9) - 6)
+#endif
+
+/*
+ * iteflash requires 256 byte reads for verifying ITE EC firmware. Without this
+ * the limit is CONFIG_I2C_CHIP_MAX_READ_SIZE which is 255 for STM32F0 due to an
+ * 8 bit field, per src/platform/ec/include/config.h comment.
+ */
+#ifndef CONFIG_I2C_XFER_LARGE_READ
+#error Must define CONFIG_I2C_XFER_LARGE_READ
+#endif
+
+#define KHz 1000
+#define MHz (1000 * KHz)
+
+/*
+ * These constants are values that one might want to try changing if
+ * enable_ite_dfu stops working, or does not work on a new ITE EC chip revision.
+ */
+
+#define ITE_DFU_I2C_CMD_ADDR_FLAGS 0x5A
+#define ITE_DFU_I2C_DATA_ADDR_FLAGS 0x35
+
+#define SMCLK_WAVEFORM_PERIOD_HZ (100 * KHz)
+#define SMDAT_WAVEFORM_PERIOD_HZ (200 * KHz)
+
+#define START_DELAY_MS 5
+#define SPECIAL_WAVEFORM_MS 50
+#define PLL_STABLE_MS 10
+
+/*
+ * Digital line levels to hold before (PRE_) or after (POST_) sending the
+ * special waveforms. 0 for low, 1 for high.
+ */
+#define SMCLK_PRE_LEVEL 0
+#define SMDAT_PRE_LEVEL 0
+#define SMCLK_POST_LEVEL 0
+#define SMDAT_POST_LEVEL 0
+
+/* The caller should hold the i2c_lock() for ite_dfu_config.i2c_port. */
+static int ite_i2c_read_register(uint8_t register_offset, uint8_t *output)
+{
+ /*
+ * Ideally the write and read would be done in one I2C transaction, as
+ * is normally done when reading from the same I2C address that the
+ * write was sent to. The ITE EC is abnormal in that regard, with its
+ * different 7-bit addresses for writes vs reads.
+ *
+ * i2c_xfer() does not support that. Its I2C_XFER_START and
+ * I2C_XFER_STOP flag bits do not cleanly support that scenario, they
+ * are for continuing transfers without either of STOP or START
+ * in-between.
+ *
+ * For what it's worth, the iteflash.c FTDI-based implementation of this
+ * does the same thing, issuing a STOP between the write and read. This
+ * works, even if perhaps it should not.
+ */
+ int ret;
+ /* Tell the ITE EC which register we want to read. */
+ ret = i2c_xfer_unlocked(ite_dfu_config.i2c_port,
+ ITE_DFU_I2C_CMD_ADDR_FLAGS,
+ &register_offset, sizeof(register_offset),
+ NULL, 0, I2C_XFER_SINGLE);
+ if (ret != EC_SUCCESS)
+ return ret;
+ /* Read in the 1 byte register value. */
+ ret = i2c_xfer_unlocked(ite_dfu_config.i2c_port,
+ ITE_DFU_I2C_DATA_ADDR_FLAGS,
+ NULL, 0,
+ output, sizeof(*output), I2C_XFER_SINGLE);
+ return ret;
+}
+
+/* Helper function to read ITE chip ID, for verifying ITE DFU mode. */
+static int cprint_ite_chip_id(void)
+{
+ /*
+ * Per i2c_read8() implementation, use an array even for single byte
+ * reads to ensure alignment for DMA on STM32.
+ */
+ uint8_t chipid1[1];
+ uint8_t chipid2[1];
+ uint8_t chipver[1];
+
+ int ret;
+ int chip_version;
+ int flash_kb;
+
+ i2c_lock(ite_dfu_config.i2c_port, 1);
+
+ /* Read the CHIPID1 register. */
+ ret = ite_i2c_read_register(0x00, chipid1);
+ if (ret != EC_SUCCESS)
+ goto unlock;
+
+ /* Read the CHIPID2 register. */
+ ret = ite_i2c_read_register(0x01, chipid2);
+ if (ret != EC_SUCCESS)
+ goto unlock;
+
+ /* Read the CHIPVER register. */
+ ret = ite_i2c_read_register(0x02, chipver);
+
+unlock:
+ i2c_lock(ite_dfu_config.i2c_port, 0);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /*
+ * Compute chip version and embedded flash size from the CHIPVER value.
+ *
+ * Chip version is mapping from bit 3-0
+ * Flash size is mapping from bit 7-4
+ *
+ * Chip Version (bits 3-0)
+ * 0: AX
+ * 1: BX
+ * 2: CX
+ * 3: DX
+ *
+ * CX or prior flash size (bits 7-4)
+ * 0:128KB
+ * 4:192KB
+ * 8:256KB
+ *
+ * DX flash size (bits 7-4)
+ * 0:128KB
+ * 2:192KB
+ * 4:256KB
+ * 6:384KB
+ * 8:512KB
+ */
+ chip_version = chipver[0] & 0x07;
+ if (chip_version < 0x3) {
+ /* Chip version is CX or earlier. */
+ switch (chipver[0] >> 4) {
+ case 0:
+ flash_kb = 128;
+ break;
+ case 4:
+ flash_kb = 192;
+ break;
+ case 8:
+ flash_kb = 256;
+ break;
+ default:
+ flash_kb = -2;
+ }
+ } else if (chip_version == 0x3) {
+ /* Chip version is DX. */
+ switch (chipver[0] >> 4) {
+ case 0:
+ flash_kb = 128;
+ break;
+ case 2:
+ flash_kb = 192;
+ break;
+ case 4:
+ flash_kb = 256;
+ break;
+ case 6:
+ flash_kb = 384;
+ break;
+ case 8:
+ flash_kb = 512;
+ break;
+ default:
+ flash_kb = -3;
+ }
+ } else {
+ /* Unrecognized chip version. */
+ flash_kb = -1;
+ }
+
+ ccprintf("ITE EC info: CHIPID1=0x%02X CHIPID2=0x%02X CHIPVER=0x%02X ",
+ chipid1[0], chipid2[0], chipver[0]);
+ ccprintf("version=%d flash_bytes=%d\n", chip_version, flash_kb << 10);
+
+ /*
+ * IT8320_eflash_SMBus_Programming_Guide.pdf says it is an error if
+ * CHIPID1 != 0x83.
+ */
+ if (chipid1[0] != 0x83)
+ ret = EC_ERROR_HW_INTERNAL;
+
+ return ret;
+}
+
+/* Enable ITE direct firmware update (DFU) mode. */
+static int command_enable_ite_dfu(int argc, char **argv)
+{
+ if (argc > 1)
+ return EC_ERROR_PARAM_COUNT;
+
+ /* Enable peripheral clocks. */
+ STM32_RCC_APB2ENR |=
+ STM32_RCC_APB2ENR_TIM16EN | STM32_RCC_APB2ENR_TIM17EN;
+
+ /* Reset timer registers which are not otherwise set below. */
+ STM32_TIM_CR2(16) = 0x0000;
+ STM32_TIM_CR2(17) = 0x0000;
+ STM32_TIM_DIER(16) = 0x0000;
+ STM32_TIM_DIER(17) = 0x0000;
+ STM32_TIM_SR(16) = 0x0000;
+ STM32_TIM_SR(17) = 0x0000;
+ STM32_TIM_CNT(16) = 0x0000;
+ STM32_TIM_CNT(17) = 0x0000;
+ STM32_TIM_RCR(16) = 0x0000;
+ STM32_TIM_RCR(17) = 0x0000;
+ STM32_TIM_DCR(16) = 0x0000;
+ STM32_TIM_DCR(17) = 0x0000;
+ STM32_TIM_DMAR(16) = 0x0000;
+ STM32_TIM_DMAR(17) = 0x0000;
+
+ /* Prescale to 1 MHz and use ARR to achieve NNN KHz periods. */
+ /* This approach is seen in STM's documentation. */
+ STM32_TIM_PSC(16) = (CPU_CLOCK / MHz) - 1;
+ STM32_TIM_PSC(17) = (CPU_CLOCK / MHz) - 1;
+
+ /* Set the waveform periods based on 1 MHz prescale. */
+ STM32_TIM_ARR(16) = (MHz / SMCLK_WAVEFORM_PERIOD_HZ) - 1;
+ STM32_TIM_ARR(17) = (MHz / SMDAT_WAVEFORM_PERIOD_HZ) - 1;
+
+ /* Set output compare 1 mode to PWM mode 1 and enable preload. */
+ STM32_TIM_CCMR1(16) =
+ STM32_TIM_CCMR1_OC1M_PWM_MODE_1 | STM32_TIM_CCMR1_OC1PE;
+ STM32_TIM_CCMR1(17) =
+ STM32_TIM_CCMR1_OC1M_PWM_MODE_1 | STM32_TIM_CCMR1_OC1PE;
+
+ /* Enable output compare 1. */
+ STM32_TIM_CCER(16) = STM32_TIM_CCER_CC1E;
+ STM32_TIM_CCER(17) = STM32_TIM_CCER_CC1E;
+
+ /* Enable main output. */
+ STM32_TIM_BDTR(16) = STM32_TIM_BDTR_MOE;
+ STM32_TIM_BDTR(17) = STM32_TIM_BDTR_MOE;
+
+ /* Update generation (reinitialize counters). */
+ STM32_TIM_EGR(16) = STM32_TIM_EGR_UG;
+ STM32_TIM_EGR(17) = STM32_TIM_EGR_UG;
+
+ /* Set duty cycle to 0% or 100%, pinning each channel low or high. */
+ STM32_TIM_CCR1(16) = SMCLK_PRE_LEVEL ? 0xFFFF : 0x0000;
+ STM32_TIM_CCR1(17) = SMDAT_PRE_LEVEL ? 0xFFFF : 0x0000;
+
+ /* Enable timer counters. */
+ STM32_TIM_CR1(16) = STM32_TIM_CR1_CEN;
+ STM32_TIM_CR1(17) = STM32_TIM_CR1_CEN;
+
+ /* Set GPIO to alternate mode TIM(16|17)_CH1(N)? */
+ gpio_config_pin(MODULE_I2C_TIMERS, ite_dfu_config.scl, 1);
+ gpio_config_pin(MODULE_I2C_TIMERS, ite_dfu_config.sda, 1);
+
+ msleep(START_DELAY_MS);
+
+ /* Set pulse width to half of waveform period. */
+ STM32_TIM_CCR1(16) = (MHz / SMCLK_WAVEFORM_PERIOD_HZ) / 2;
+ STM32_TIM_CCR1(17) = (MHz / SMDAT_WAVEFORM_PERIOD_HZ) / 2;
+
+ msleep(SPECIAL_WAVEFORM_MS);
+
+ /* Set duty cycle to 0% or 100%, pinning each channel low or high. */
+ STM32_TIM_CCR1(16) = SMCLK_POST_LEVEL ? 0xFFFF : 0x0000;
+ STM32_TIM_CCR1(17) = SMDAT_POST_LEVEL ? 0xFFFF : 0x0000;
+
+ msleep(PLL_STABLE_MS);
+
+ /* Set GPIO back to alternate mode I2C. */
+ gpio_config_pin(MODULE_I2C, ite_dfu_config.scl, 1);
+ gpio_config_pin(MODULE_I2C, ite_dfu_config.sda, 1);
+
+ /* Disable timer counters. */
+ STM32_TIM_CR1(16) = 0x0000;
+ STM32_TIM_CR1(17) = 0x0000;
+
+ /* Disable peripheral clocks. */
+ STM32_RCC_APB2ENR &=
+ ~(STM32_RCC_APB2ENR_TIM16EN | STM32_RCC_APB2ENR_TIM17EN);
+
+ return cprint_ite_chip_id();
+}
+DECLARE_CONSOLE_COMMAND(
+ enable_ite_dfu, command_enable_ite_dfu, "",
+ "Enable ITE Direct Firmware Update (DFU) mode");
+
+/* Read ITE chip ID. Can be used to verify ITE DFU mode. */
+static int command_get_ite_chipid(int argc, char **argv)
+{
+ if (argc > 1)
+ return EC_ERROR_PARAM_COUNT;
+
+ return cprint_ite_chip_id();
+}
+DECLARE_CONSOLE_COMMAND(
+ get_ite_chipid, command_get_ite_chipid, "",
+ "Read ITE EC chip ID, version, flash size (must be in DFU mode)");
diff --git a/include/config.h b/include/config.h
index b54e670bc1..c9222535c4 100644
--- a/include/config.h
+++ b/include/config.h
@@ -2318,6 +2318,12 @@
*/
#undef CONFIG_SMBUS_PEC
+/*
+ * Add hosts-side support for entering programming mode for I2C ITE ECs.
+ * Must define ite_dfu_config_t for configuration in board file.
+ */
+#undef CONFIG_ITE_FLASH_SUPPORT
+
/*****************************************************************************/
/* IPI configuration. Support mt_scp only for now. */
diff --git a/include/i2c_ite_flash_support.h b/include/i2c_ite_flash_support.h
new file mode 100644
index 0000000000..e926fe2539
--- /dev/null
+++ b/include/i2c_ite_flash_support.h
@@ -0,0 +1,27 @@
+/* Copyright 2020 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.
+ */
+/* API for module that provides flash support for ITE-based ECs over i2c */
+
+#ifndef __CROS_EC_I2C_ITE_FLASH_SUPPORT_H
+#define __CROS_EC_I2C_ITE_FLASH_SUPPORT_H
+
+#include "gpio.h"
+#include "stdbool.h"
+
+struct ite_dfu_config_t {
+ /* I2C port to communicate on */
+ int i2c_port;
+ /*
+ * The gpio signals that moved between TIM16/17 (MODULE_I2C_TIMERS) and
+ * I2C (MODULE_I2C).
+ */
+ enum gpio_signal scl;
+ enum gpio_signal sda;
+};
+
+/* Provided by board implementation if CONFIG_ITE_FLASH_SUPPORT is used */
+const extern struct ite_dfu_config_t ite_dfu_config;
+
+#endif /* __CROS_EC_I2C_ITE_FLASH_SUPPORT_H */