mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-30 02:20:48 +00:00
usb_i2c: Fail if board I2C bridge is disabled
Add usb_i2c_board_is_enabled(). On Cr50, this is now also connected to the I2C CCD capability. The USB-I2C bridge can only be used when the capability is available. On other platforms (Servo V4, etc.) where usb_i2c_board_enable() is a no-op, add a dummy implementation which always returns true. See go/cr50-ccd-wp for more information. BUG=b:62537474 BRANCH=cr50 TEST=manual with CR50_DEV=1 Connect host PC to dev board USB port On host PC: sudo servod -c ccd_cr50.xml -c reef_r1_inas.xml dut-control pp3300_ec_shv_reg --> fail, error 0x8001 ccdoops --> reset I2C config ccd i2c disable --> I2C disabled On host PC: sudo servod -c ccd_cr50.xml -c reef_r1_inas.xml dut-control pp3300_ec_shv_reg --> fail, error 0x0006 ccd i2c enable --> I2C enabled ccdunlock --> I2C disabled ccdoops --> I2C enabled ccdset i2c unlesslocked ccdlock --> I2C disabled ccdunlock --> I2C enabled Change-Id: Ia3df32e239a5f7c5915bc6c7e408ce0dc8b26c89 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/590577 Reviewed-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Mary Ruthven <mruthven@chromium.org>
This commit is contained in:
committed by
chrome-bot
parent
ddbfe690e2
commit
00ea73ab16
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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] = {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user