diff options
-rw-r--r-- | board/cr50/rdd.c | 2 | ||||
-rw-r--r-- | board/cr50/usb_i2c.c | 40 | ||||
-rw-r--r-- | board/hammer/board.c | 1 | ||||
-rw-r--r-- | board/mn50/board.c | 5 | ||||
-rw-r--r-- | board/servo_micro/board.c | 2 | ||||
-rw-r--r-- | board/servo_v4/board.c | 1 | ||||
-rw-r--r-- | board/tigertail/board.c | 2 | ||||
-rw-r--r-- | common/ccd_config.c | 1 | ||||
-rw-r--r-- | common/usb_i2c.c | 10 | ||||
-rw-r--r-- | include/case_closed_debug.h | 3 | ||||
-rw-r--r-- | include/usb_i2c.h | 23 |
11 files changed, 84 insertions, 6 deletions
diff --git a/board/cr50/rdd.c b/board/cr50/rdd.c index 622bd8f986..bf5a3ed8f0 100644 --- a/board/cr50/rdd.c +++ b/board/cr50/rdd.c @@ -289,6 +289,8 @@ static int command_ccd(int argc, char **argv) ccprintf("AP UART: %s\nEC UART: %s\n", uart_tx_is_connected(UART_AP) ? " enabled" : "disabled", uart_tx_is_connected(UART_EC) ? " enabled" : "disabled"); + ccprintf("I2C: %s\n", + usb_i2c_board_is_enabled() ? " enabled" : "disabled"); return EC_SUCCESS; } diff --git a/board/cr50/usb_i2c.c b/board/cr50/usb_i2c.c index 24a6fbdea6..0bc5b3f215 100644 --- a/board/cr50/usb_i2c.c +++ b/board/cr50/usb_i2c.c @@ -3,6 +3,7 @@ * found in the LICENSE file. */ +#include "case_closed_debug.h" #include "console.h" #include "device_state.h" #include "gpio.h" @@ -16,7 +17,7 @@ #define CPRINTS(format, args...) cprints(CC_USB, format, ## args) -static int i2c_enabled(void) +int usb_i2c_board_is_enabled(void) { return !gpio_get_level(GPIO_EN_PP3300_INA_L); } @@ -64,7 +65,7 @@ static void ina_connect(void) void usb_i2c_board_disable(void) { - if (!i2c_enabled()) + if (!usb_i2c_board_is_enabled()) return; ina_disconnect(); @@ -78,8 +79,41 @@ int usb_i2c_board_enable(void) return EC_ERROR_BUSY; } - if (!i2c_enabled()) + if (ccd_get_mode() != CCD_MODE_ENABLED) + return EC_ERROR_BUSY; + + if (!ccd_is_cap_enabled(CCD_CAP_I2C)) + return EC_ERROR_ACCESS_DENIED; + + if (!usb_i2c_board_is_enabled()) ina_connect(); return EC_SUCCESS; } + +/** + * CCD config change hook + */ +static void ccd_change_i2c(void) +{ + /* + * If the capability state doesn't match the current I2C enable state, + * try to make them match. + */ + if (usb_i2c_board_is_enabled() && !ccd_is_cap_enabled(CCD_CAP_I2C)) { + /* I2C bridge is enabled, but it's no longer allowed to be */ + usb_i2c_board_disable(); + } else if (!usb_i2c_board_is_enabled() && + ccd_is_cap_enabled(CCD_CAP_I2C)) { + /* + * I2C bridge is disabled, but is allowed to be enabled. Try + * enabling it. Note that this could fail for several reasons, + * such as CCD not connected, or servo attached. That's ok; + * those things will also attempt usb_i2c_board_enable() if + * their state changes later. + */ + usb_i2c_board_enable(); + } +} + +DECLARE_HOOK(HOOK_CCD_CHANGE, ccd_change_i2c, HOOK_PRIO_DEFAULT); diff --git a/board/hammer/board.c b/board/hammer/board.c index dcab35ca20..a3e90dc14b 100644 --- a/board/hammer/board.c +++ b/board/hammer/board.c @@ -80,6 +80,7 @@ BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT); int usb_i2c_board_enable(void) { return EC_SUCCESS; } void usb_i2c_board_disable(void) {} +int usb_i2c_board_is_enabled(void) { return 1; } #ifdef CONFIG_KEYBOARD_BOARD_CONFIG struct keyboard_scan_config keyscan_config = { diff --git a/board/mn50/board.c b/board/mn50/board.c index 992fceb93c..39746a1745 100644 --- a/board/mn50/board.c +++ b/board/mn50/board.c @@ -103,6 +103,11 @@ int usb_i2c_board_enable(void) return EC_SUCCESS; } +int usb_i2c_board_is_enabled(void) +{ + return 1; +} + /* Initialize board. */ static void board_init(void) { diff --git a/board/servo_micro/board.c b/board/servo_micro/board.c index 505a6d628a..71b780917d 100644 --- a/board/servo_micro/board.c +++ b/board/servo_micro/board.c @@ -244,6 +244,8 @@ const struct i2c_port_t i2c_ports[] = { }; const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); +int usb_i2c_board_is_enabled(void) { return 1; } + /****************************************************************************** * Initialize board. */ diff --git a/board/servo_v4/board.c b/board/servo_v4/board.c index eb9c068520..f7bd390129 100644 --- a/board/servo_v4/board.c +++ b/board/servo_v4/board.c @@ -238,6 +238,7 @@ const struct i2c_port_t i2c_ports[] = { }; const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); +int usb_i2c_board_is_enabled(void) { return 1; } /****************************************************************************** * Initialize board. diff --git a/board/tigertail/board.c b/board/tigertail/board.c index 86d3a79d47..d2908fa394 100644 --- a/board/tigertail/board.c +++ b/board/tigertail/board.c @@ -111,7 +111,7 @@ const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports); int usb_i2c_board_enable(void) {return EC_SUCCESS; } void usb_i2c_board_disable(void) {} - +int usb_i2c_board_is_enabled(void) { return 1; } /****************************************************************************** * Console commands. diff --git a/common/ccd_config.c b/common/ccd_config.c index 5b6b11c1b8..e068d2c46c 100644 --- a/common/ccd_config.c +++ b/common/ccd_config.c @@ -136,6 +136,7 @@ static const struct ccd_capability_info cap_info[CCD_CAP_COUNT] = { {"OpenNoLongPP", CCD_CAP_STATE_IF_OPENED}, {"BatteryBypassPP", CCD_CAP_STATE_ALWAYS}, {"UpdateNoTPMWipe", CCD_CAP_STATE_ALWAYS}, + {"I2C", CCD_CAP_STATE_IF_OPENED}, }; static const char *ccd_state_names[CCD_STATE_COUNT] = { diff --git a/common/usb_i2c.c b/common/usb_i2c.c index 64d7135a89..a6f5acc99c 100644 --- a/common/usb_i2c.c +++ b/common/usb_i2c.c @@ -90,7 +90,9 @@ void usb_i2c_execute(struct usb_i2c_config const *config) if (!count || (!read_count && !write_count)) return; - if (write_count > CONFIG_USB_I2C_MAX_WRITE_COUNT || + if (!usb_i2c_board_is_enabled()) { + config->buffer[0] = USB_I2C_DISABLED; + } else if (write_count > CONFIG_USB_I2C_MAX_WRITE_COUNT || write_count != (count - 4)) { config->buffer[0] = USB_I2C_WRITE_COUNT_INVALID; } else if (read_count > USB_I2C_MAX_READ_COUNT) { @@ -98,6 +100,12 @@ void usb_i2c_execute(struct usb_i2c_config const *config) } else if (portindex >= i2c_ports_used) { config->buffer[0] = USB_I2C_PORT_INVALID; } else { + /* + * TODO (crbug.com/750397): Add security. This currently + * blindly passes through ALL I2C commands on any bus the EC + * knows about. It should behave closer to + * EC_CMD_I2C_PASSTHRU, which can protect ports and ranges. + */ port = i2c_ports[portindex].port; config->buffer[0] = usb_i2c_map_error( i2c_xfer(port, slave_addr, diff --git a/include/case_closed_debug.h b/include/case_closed_debug.h index 2283d6474d..2edbf1763d 100644 --- a/include/case_closed_debug.h +++ b/include/case_closed_debug.h @@ -130,6 +130,9 @@ enum ccd_capability { /* Allow Cr50 firmware update without wiping TPM data */ CCD_CAP_CR50_FW_UPDATE_WITHOUT_TPM_WIPE = 14, + /* Access to I2C via USB */ + CCD_CAP_I2C = 15, + /* Number of currently defined capabilities */ CCD_CAP_COUNT }; diff --git a/include/usb_i2c.h b/include/usb_i2c.h index 335550b66e..c464e062a5 100644 --- a/include/usb_i2c.h +++ b/include/usb_i2c.h @@ -45,6 +45,7 @@ * 0x0003: Write count invalid (mismatch with merged payload) * 0x0004: Read count invalid (> 60 bytes) * 0x0005: The port specified is invalid. + * 0x0006: The I2C interface is disabled. * 0x8000: Unknown error mask * The bottom 15 bits will contain the bottom 15 bits from the EC * error code. @@ -60,6 +61,7 @@ enum usb_i2c_error { USB_I2C_WRITE_COUNT_INVALID = 0x0003, USB_I2C_READ_COUNT_INVALID = 0x0004, USB_I2C_PORT_INVALID = 0x0005, + USB_I2C_DISABLED = 0x0006, USB_I2C_UNKNOWN_ERROR = 0x8000, }; @@ -149,8 +151,27 @@ void usb_i2c_deferred(struct usb_i2c_config const *config); /* * These functions should be implemented by the board to provide any board - * specific operations required to enable or disable access to the I2C device. + * specific operations required to enable or disable access to the I2C device, + * and to return the current board enable state. + */ + +/** + * Enable the I2C device + * + * @return EC_SUCCESS or non-zero error code. */ int usb_i2c_board_enable(void); + +/** + * Disable the I2C device + */ void usb_i2c_board_disable(void); + +/** + * Check if the I2C device is enabled + * + * @return 1 if enabled, 0 if disabled. + */ +int usb_i2c_board_is_enabled(void); + #endif /* __CROS_USB_I2C_H */ |