summaryrefslogtreecommitdiff
path: root/board/servo_micro
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 /board/servo_micro
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>
Diffstat (limited to 'board/servo_micro')
-rw-r--r--board/servo_micro/board.c304
-rw-r--r--board/servo_micro/board.h33
2 files changed, 11 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)