diff options
author | Keith Short <keithshort@chromium.org> | 2018-12-19 16:17:28 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-01-08 01:59:12 -0800 |
commit | 90d177e3f0ae729bea7e24934a3c6ef9f2520d45 (patch) | |
tree | da02f562f4d768beb09aaf198c252972347c232b | |
parent | 5079009d35d8900bb030cbc7d9ebc34cf3ad1696 (diff) | |
download | chrome-ec-90d177e3f0ae729bea7e24934a3c6ef9f2520d45.tar.gz |
cr50: Changes to support closed source EC factory mode
Drives OEM specific GPIOs to enable and disable factory mode to a closed
source EC.
BUG=b:118683718
BRANCH=none
TEST=make buildall. Verified GPIO states with scope in both factory mode
enable and disable conditions. Verified GPIO states are reapplied
correctly after reboot, deep sleep, and power cycle.
Change-Id: I9bc547504478fded5f95c515027e1da0f245d524
Signed-off-by: Keith Short <keithshort@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1358733
Reviewed-by: Mary Ruthven <mruthven@chromium.org>
-rw-r--r-- | board/cr50/board.c | 12 | ||||
-rw-r--r-- | board/cr50/board.h | 26 | ||||
-rw-r--r-- | board/cr50/build.mk | 1 | ||||
-rw-r--r-- | board/cr50/closed_source_set1.c | 151 | ||||
-rw-r--r-- | board/cr50/closed_source_set1.h | 25 | ||||
-rw-r--r-- | board/cr50/gpio.inc | 12 | ||||
-rw-r--r-- | board/cr50/usb_i2c.c | 12 | ||||
-rw-r--r-- | common/ccd_config.c | 14 | ||||
-rw-r--r-- | include/ccd_config.h | 12 |
9 files changed, 265 insertions, 0 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c index 4477e1bfe8..ef8a91ec98 100644 --- a/board/cr50/board.c +++ b/board/cr50/board.c @@ -5,6 +5,7 @@ #include "board_id.h" #include "ccd_config.h" #include "clock.h" +#include "closed_source_set1.h" #include "common.h" #include "console.h" #include "dcrypto/dcrypto.h" @@ -157,6 +158,11 @@ int board_tpm_uses_spi(void) return !!(board_properties & BOARD_SLAVE_CONFIG_SPI); } +int board_uses_closed_source_set1(void) +{ + return !!(board_properties & BOARD_CLOSED_SOURCE_SET1); +} + /* Get header address of the backup RW copy. */ const struct SignedHeader *get_other_rw_addr(void) { @@ -597,6 +603,9 @@ static void configure_board_specific_gpios(void) /* Enable powerdown exit on DIOM0 */ GWRITE_FIELD(PINMUX, EXITEN0, DIOM0, 1); } + + if (board_uses_closed_source_set1()) + closed_source_set1_configure_gpios(); } void decrement_retry_counter(void) @@ -769,6 +778,9 @@ static void board_ccd_config_changed(void) & BOARD_CCD_STATE; GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG1, 0); + if (board_uses_closed_source_set1()) + closed_source_set1_update_factory_mode(); + /* Update CCD state */ ccd_update_state(); } diff --git a/board/cr50/board.h b/board/cr50/board.h index e3c844c182..95a74e1af6 100644 --- a/board/cr50/board.h +++ b/board/cr50/board.h @@ -260,10 +260,36 @@ int is_ec_rst_asserted(void); */ void ccd_update_state(void); +/** + * Return the state of the BOARD_USE_PLT_RST board strap option. + * + * @return 0 if option is not set, !=0 if option set. + */ int board_use_plt_rst(void); +/** + * Return the state of the BOARD_NEEDS_SYS_RST_PULL_UP board strap option. + * + * @return 0 if option is not set, !=0 if option set. + */ int board_rst_pullup_needed(void); +/** + * Return the state of the BOARD_SLAVE_CONFIG_I2C board strap option. + * + * @return 0 if option is not set, !=0 if option set. + */ int board_tpm_uses_i2c(void); +/** + * Return the state of the BOARD_SLAVE_CONFIG_SPI board strap option. + * + * @return 0 if option is not set, !=0 if option set. + */ int board_tpm_uses_spi(void); +/** + * Return the state of the BOARD_CLOSED_SOURCE_SET1 board strap option. + * + * @return 0 if option is not set, !=0 if option set. + */ +int board_uses_closed_source_set1(void); int board_id_is_mismatched(void); /* Allow for deep sleep to be enabled on AP shutdown */ int board_deep_sleep_allowed(void); diff --git a/board/cr50/build.mk b/board/cr50/build.mk index b65bdda1c6..b12bdc5f8b 100644 --- a/board/cr50/build.mk +++ b/board/cr50/build.mk @@ -31,6 +31,7 @@ dirs-y += $(BDIR)/tpm2 # Objects that we need to build board-y = board.o board-y += ap_state.o +board-y += closed_source_set1.o board-y += ec_state.o board-y += power_button.o board-y += servo_state.o diff --git a/board/cr50/closed_source_set1.c b/board/cr50/closed_source_set1.c new file mode 100644 index 0000000000..8c0a7f2829 --- /dev/null +++ b/board/cr50/closed_source_set1.c @@ -0,0 +1,151 @@ +/* + * Copyright 2018 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. + * + * Board specific routines used only when BOARD_CLOSED_SOURCE_SET1 is + * enabled. + */ +#include "ccd_config.h" +#include "closed_source_set1.h" +#include "common.h" +#include "console.h" +#include "gpio.h" +#include "hooks.h" +#include "registers.h" + +#define CPRINTF(format, args...) \ + cprintf(CC_SYSTEM, "Closed Source Set1: " format, ## args) + +/* + * Map common gpio.inc pin names to descriptive names specific to the + * BOARD_CLOSED_SOURCE_SET1 option. + */ +#define GPIO_FACTORY_MODE GPIO_I2C_SCL_INA +#define GPIO_CHROME_SEL GPIO_EN_PP3300_INA_L +#define GPIO_EXIT_FACTORY_MODE GPIO_I2C_SDA_INA + +enum ec_trust_level { + EC_TL_FACTORY_MODE, + EC_TL_DIAGNOSTIC_MODE, + EC_TL_COREBOOT, +}; + +void closed_source_set1_configure_gpios(void) +{ + CPRINTF("configuring GPIOs\n"); + + /* + * Connect GPIO outputs to pads: + * GPIO0_12 (FACTORY_MODE) : B0 + * GPIO0_13 (EXIT_FACTORY_MODE) : B1 + * GPIO0_11 (CHROME_SEL) : B7 + */ + GWRITE(PINMUX, DIOB0_SEL, GC_PINMUX_GPIO0_GPIO12_SEL); + GWRITE(PINMUX, DIOB1_SEL, GC_PINMUX_GPIO0_GPIO13_SEL); + GWRITE(PINMUX, DIOB7_SEL, GC_PINMUX_GPIO0_GPIO11_SEL); + + /* + * The PINMUX entries in gpio.inc already write to the GPIOn_GPOIn_SEL + * and DIOBn_CTL registers with values that work for GPIO output + * operation. If gpio.inc makes changes to the GPIO_I2C_SCL_INA, + * GPIO_I2C_SDA_INA, or GPIO_EN_PP3300_INA_L pinmux, then explicitly + * configure the corresponding GPIOn_GPIOn_SEL and DIOBn_CTL registers + * here. + */ + + /* Enable falling edge interrupt on I2C_SDA_SCL/EXIT_FACTORY_MODE */ + + /* + * TODO (keithshort): closed source EC documentation defines + * EXIT_FACTORY_MODE as an output from the EC that is driven low + * to indicate that factory mode must be terminated. However, the + * EC firmware has not yet (and may never) add this capability. + */ +// gpio_set_flags(GPIO_EXIT_FACTORY_MODE, GPIO_INPUT | GPIO_INT_F_FALLING); + + closed_source_set1_update_factory_mode(); +} + +static void closed_source_set1_update_ec_trust_level(enum ec_trust_level tl) +{ + /* + * The EC state is partially controlled by the FACTORY_MODE and + * CHROME_SEL signals. + * + * State Description + * CHROME_SEL=0,FACTORY_MODE=1 TL0: EC factory mode + * CHROME_SEL=0,FACTORY_MODE=0 TL1: EC diagnostic mode + * CHROME_SEL=1,FACTORY_MODE=0 TL2: EC coreboot mode + * CHROME_SEL=1,FACTORY_MODE=1 Undefined + */ + switch (tl) { + case EC_TL_FACTORY_MODE: + CPRINTF("enable factory mode\n"); + /* + * Enable factory mode, CHROME_SEL must be set low first so + * that CHROME_SEL and FACTORY_MODE are not high + * simultaneously. + */ + gpio_set_flags(GPIO_CHROME_SEL, GPIO_OUT_LOW); + gpio_set_flags(GPIO_FACTORY_MODE, GPIO_OUT_HIGH); + break; + + case EC_TL_DIAGNOSTIC_MODE: + CPRINTF("enable diagnostic mode\n"); + + gpio_set_flags(GPIO_CHROME_SEL, GPIO_OUT_LOW); + gpio_set_flags(GPIO_FACTORY_MODE, GPIO_OUT_LOW); + break; + + case EC_TL_COREBOOT: + CPRINTF("disable factory mode\n"); + /* + * Disable factory mode, set FACTORY_MODE low first to avoid + * undefined state. + */ + gpio_set_flags(GPIO_FACTORY_MODE, GPIO_OUT_LOW); + gpio_set_flags(GPIO_CHROME_SEL, GPIO_OUT_HIGH); + break; + default: + CPRINTF("unsupported EC trust level %d\n", tl); + } +} + +void closed_source_set1_update_factory_mode(void) +{ + if (ccd_get_factory_mode()) + closed_source_set1_update_ec_trust_level(EC_TL_FACTORY_MODE); + else + closed_source_set1_update_ec_trust_level(EC_TL_COREBOOT); +} + + +#ifdef CR50_DEV +/* Debug command to manually set the EC trust level */ +static int ec_trust_level(int argc, char **argv) +{ + enum ec_trust_level tl; + + if (argc > 1) { + tl = (enum ec_trust_level)atoi(argv[1]); + + closed_source_set1_update_ec_trust_level(tl); + } + + ccprintf("CCD factory mode = %d\n", ccd_get_factory_mode()); + + ccprintf("FACTORY_MODE = %d\n", + gpio_get_level(GPIO_FACTORY_MODE)); + ccprintf("CHROME_SEL = %d\n", + gpio_get_level(GPIO_CHROME_SEL)); + ccprintf("EXIT_FACTORY_MODE = %d\n", + gpio_get_level(GPIO_EXIT_FACTORY_MODE)); + + return 0; +} +DECLARE_SAFE_CONSOLE_COMMAND(ectrust, ec_trust_level, + "[0|1|2]", + "Get/set the EC trust level"); +#endif + diff --git a/board/cr50/closed_source_set1.h b/board/cr50/closed_source_set1.h new file mode 100644 index 0000000000..44f7e39be0 --- /dev/null +++ b/board/cr50/closed_source_set1.h @@ -0,0 +1,25 @@ +/* + * Copyright 2018 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. + */ + +#ifndef __EC_BOARD_CR50_CLOSED_SOURCE_SET1_H +#define __EC_BOARD_CR50_CLOSED_SOURCE_SET1_H + + +/** + * Configure the GPIOs specific to the BOARD_CLOSED_SOURCE_SET1 board strapping + * option. This includes the FACTORY_MODE, CHROME_SEL, and EXIT_FACTORY_MODE + * signals. + */ +void closed_source_set1_configure_gpios(void); + +/** + * Drive the GPIOs specific to BOARD_CLOSED_SOURCE_SET1 to match the current + * factory mode setting. + */ +void closed_source_set1_update_factory_mode(void); + + +#endif /* ! __EC_BOARD_CR50_CLOSED_SOURCE_SET1_H */ diff --git a/board/cr50/gpio.inc b/board/cr50/gpio.inc index 2943573b18..d9b0a8ff32 100644 --- a/board/cr50/gpio.inc +++ b/board/cr50/gpio.inc @@ -102,6 +102,10 @@ GPIO(STRAP_A1, PIN(1, 13), GPIO_INPUT) GPIO(STRAP_B0, PIN(1, 14), GPIO_INPUT) GPIO(STRAP_B1, PIN(1, 15), GPIO_INPUT) +/* + * If you change the names of EN_PP3300_INA_L, I2C_SCL_INA, or I2C_SDA_INA, + * you also need to update the usage in closed_source_set1.c + */ /* Control the load switch powering the INA 3.3V rail */ GPIO(EN_PP3300_INA_L, PIN(0, 11), GPIO_ODR_HIGH) /* GPIOs used for I2CM pins for INAs */ @@ -143,6 +147,10 @@ PINMUX(GPIO(INT_AP_L), A5, DIO_INPUT) /* DIOB7 is p_digitial_od */ /* We can't pull it up */ PINMUX(GPIO(EC_FLASH_SELECT), B2, DIO_INPUT) PINMUX(GPIO(AP_FLASH_SELECT), B3, DIO_INPUT) +/* + * Update closed_source_set1.c if pinmux for EN_PP3300_INA_L is changed or + * removed. + */ PINMUX(GPIO(EN_PP3300_INA_L), B7, DIO_INPUT) /* * To allow the EC to drive the signal we set sys_rst_l_out as an input here and @@ -157,6 +165,10 @@ PINMUX(GPIO(SYS_RST_L_OUT), M0, DIO_INPUT) */ PINMUX(GPIO(CCD_MODE_L), M1, DIO_INPUT | DIO_OUTPUT) PINMUX(GPIO(BATT_PRES_L), M2, 0) +/* + * Update closed_source_set1.c if pinmux for I2C_SCL_INA or I2C_SDA_INA is + * changed or removed. + */ PINMUX(GPIO(I2C_SCL_INA), B0, DIO_INPUT) PINMUX(GPIO(I2C_SDA_INA), B1, DIO_INPUT) /* UARTs */ diff --git a/board/cr50/usb_i2c.c b/board/cr50/usb_i2c.c index 1aa18012c3..b21c555858 100644 --- a/board/cr50/usb_i2c.c +++ b/board/cr50/usb_i2c.c @@ -20,6 +20,12 @@ int usb_i2c_board_is_enabled(void) { /* + * Closed source set1 board options use the INA pins as GPIOs + */ + if (board_uses_closed_source_set1()) + return 0; + + /* * Note that this signal requires an external pullup, because this is * one of the real open drain pins; we cannot pull it up or drive it * high. On test boards without the pullup, this will mis-detect as @@ -79,6 +85,12 @@ void usb_i2c_board_disable(void) int usb_i2c_board_enable(void) { + /* + * Closed source set1 board options use the INA pins as GPIOs + */ + if (board_uses_closed_source_set1()) + return EC_SUCCESS; + if (servo_is_connected()) { CPRINTS("Servo attached; cannot enable I2C"); usb_i2c_board_disable(); diff --git a/common/ccd_config.c b/common/ccd_config.c index c6946522c5..8569ab6beb 100644 --- a/common/ccd_config.c +++ b/common/ccd_config.c @@ -474,6 +474,8 @@ int ccd_reset_config(unsigned int flags) for (i = 0; i < CCD_CAP_COUNT; i++) raw_set_cap(i, CCD_CAP_STATE_ALWAYS); + raw_set_flag(CCD_FLAG_FACTORY_MODE_ENABLED, 1); + /* Force WP disabled at boot */ raw_set_flag(CCD_FLAG_OVERRIDE_WP_AT_BOOT, 1); raw_set_flag(CCD_FLAG_OVERRIDE_WP_STATE_ENABLED, 0); @@ -679,6 +681,11 @@ void ccd_disable(void) ccd_set_state(CCD_STATE_LOCKED); } +int ccd_get_factory_mode(void) +{ + return ccd_get_flag(CCD_FLAG_FACTORY_MODE_ENABLED); +} + /******************************************************************************/ /* Console commands */ @@ -1511,6 +1518,13 @@ static enum vendor_cmd_rc ccd_disable_factory_mode(enum vendor_cmd_cc code, */ set_wp_follow_ccd_config(); + /* + * Use raw_set_flag() because the factory mode flag is internal + */ + mutex_lock(&ccd_config_mutex); + raw_set_flag(CCD_FLAG_FACTORY_MODE_ENABLED, 0); + mutex_unlock(&ccd_config_mutex); + *response_size = 0; return VENDOR_RC_SUCCESS; } while (0); diff --git a/include/ccd_config.h b/include/ccd_config.h index 5f21479cef..e670eb012a 100644 --- a/include/ccd_config.h +++ b/include/ccd_config.h @@ -39,6 +39,11 @@ enum ccd_flag { */ CCD_FLAG_PASSWORD_SET_WHEN_UNLOCKED = (1 << 1), + /* + * Factory mode state + */ + CCD_FLAG_FACTORY_MODE_ENABLED = (1 << 2), + /* (flags in the middle are unused) */ /* Flags that can be set via ccd_set_flags(); fill from top down */ @@ -279,6 +284,13 @@ enum ccd_state ccd_get_state(void); */ void ccd_disable(void); +/** + * Get the factory mode state. + * + * @return 0 if factory mode is disabled, !=0 if factory mode is enabled. + */ +int ccd_get_factory_mode(void); + /* Flags for ccd_reset_config() */ enum ccd_reset_config_flags { /* Also reset test lab flag */ |