summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/rdd.c2
-rw-r--r--board/cr50/usb_i2c.c40
-rw-r--r--board/hammer/board.c1
-rw-r--r--board/mn50/board.c5
-rw-r--r--board/servo_micro/board.c2
-rw-r--r--board/servo_v4/board.c1
-rw-r--r--board/tigertail/board.c2
-rw-r--r--common/ccd_config.c1
-rw-r--r--common/usb_i2c.c10
-rw-r--r--include/case_closed_debug.h3
-rw-r--r--include/usb_i2c.h23
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 */