cr50: Add ccdblock command to block ports

Currently, when CCD is opened, there is no way to disable the EC
and/or AP UARTs.  But if there is some problem with the EC and/or AP,
and their UARTs are spamming interrupts, it can make debugging more
difficult.

If servo detection malfunctions, then CCD may drive the ports and
interfere with servo.

Add a new ccdblock command to disable the AP UART, EC UART, or any
ports shared with servo, until the next cr50 reboot.

BUG=b:65639347
BRANCH=cr50
TEST=manual with CR50_DEV=1 image, AP/EC powered on, suzyq connected
	ccdblock --> (none)
	ccdstate --> UARTAP+TX UARTEC+TX I2C SPI

	ccdblock AP on
	ccdstate --> UARTEC+TX I2C SPI

	ccdblock EC on
	ccdstate --> I2C SPI

	ccdblock -> AP EC

	ccdblock AP off
	ccdstate --> UARTAP+TX I2C SPI

	ccdblock EC off --> (none)
	ccdstate --> UARTAP+TX UARTEC+TX I2C SPI

	ccdblock SERVO on
	ccdstate --> UARTAP UARTEC

	ccd lock
	ccdblock AP on --> access denied

Change-Id: I3dcc8314fc98a17af57f2fe0d150ecd1a19ccf52
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/693041
Reviewed-by: Mary Ruthven <mruthven@chromium.org>
This commit is contained in:
Randall Spangler
2017-09-29 13:08:59 -07:00
committed by chrome-bot
parent 90d8e5460f
commit 7d816dbff5

View File

@@ -28,6 +28,26 @@ USB_SPI_CONFIG(ccd_usb_spi, USB_IFACE_SPI, USB_EP_SPI);
static enum device_state state = DEVICE_STATE_INIT;
/* Flags for CCD blocking */
enum ccd_block_flags {
/*
* UARTs. Disabling these can be helpful if the AP or EC is doing
* something which creates an interrupt storm on these ports.
*/
CCD_BLOCK_AP_UART = (1 << 0),
CCD_BLOCK_EC_UART = (1 << 1),
/*
* Any ports shared with servo. Disabling these will stop CCD from
* interfering with servo, in the case where both CCD and servo is
* connected but servo isn't properly detected.
*/
CCD_BLOCK_SERVO_SHARED = (1 << 2)
};
/* Which UARTs are blocked by console command */
static uint8_t ccd_block;
int ccd_ext_is_enabled(void)
{
return state == DEVICE_STATE_CONNECTED;
@@ -217,7 +237,7 @@ static void ccd_state_change_hook(void)
/* Then disable flags we can't have */
/* Servo takes over UART TX, I2C, and SPI */
if (servo_is_connected())
if (servo_is_connected() || (ccd_block & CCD_BLOCK_SERVO_SHARED))
flags_want &= ~(CCD_ENABLE_UART_AP_TX | CCD_ENABLE_UART_EC_TX |
CCD_ENABLE_UART_EC_BITBANG | CCD_ENABLE_I2C |
CCD_ENABLE_SPI);
@@ -247,6 +267,12 @@ static void ccd_state_change_hook(void)
if (flags_want & CCD_ENABLE_UART_EC_BITBANG)
flags_want &= ~CCD_ENABLE_UART_EC_TX;
/* UARTs can be specifically blocked by console command */
if (ccd_block & CCD_BLOCK_AP_UART)
flags_want &= ~CCD_ENABLE_UART_AP;
if (ccd_block & CCD_BLOCK_EC_UART)
flags_want &= ~CCD_ENABLE_UART_EC;
/* UARTs are either RX-only or RX+TX, so no RX implies no TX */
if (!(flags_want & CCD_ENABLE_UART_AP))
flags_want &= ~CCD_ENABLE_UART_AP_TX;
@@ -353,6 +379,21 @@ static void ccd_ext_detect(void)
}
DECLARE_HOOK(HOOK_SECOND, ccd_ext_detect, HOOK_PRIO_DEFAULT);
static void print_ccd_ports_blocked(void)
{
/* Regardless, print current state */
ccputs("CCD ports blocked:");
if (ccd_block & CCD_BLOCK_AP_UART)
ccputs(" AP");
if (ccd_block & CCD_BLOCK_EC_UART)
ccputs(" EC");
if (ccd_block & CCD_BLOCK_SERVO_SHARED)
ccputs(" SERVO");
if (!ccd_block)
ccputs(" (none)");
ccputs("\n");
}
static int command_ccd_state(int argc, char **argv)
{
print_ap_state();
@@ -367,9 +408,45 @@ static int command_ccd_state(int argc, char **argv)
print_state_flags(CC_COMMAND, get_state_flags());
ccprintf("\n");
print_ccd_ports_blocked();
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(ccdstate, command_ccd_state,
"",
"Print the case closed debug device state");
static int command_ccd_block(int argc, char **argv)
{
uint8_t block_flag = 0;
int new_state;
if (argc == 3) {
if (!strcasecmp(argv[1], "AP"))
block_flag = CCD_BLOCK_AP_UART;
else if (!strcasecmp(argv[1], "EC"))
block_flag = CCD_BLOCK_EC_UART;
else if (!strcasecmp(argv[1], "SERVO"))
block_flag = CCD_BLOCK_SERVO_SHARED;
else
return EC_ERROR_PARAM1;
if (!parse_bool(argv[2], &new_state))
return EC_ERROR_PARAM2;
if (new_state)
ccd_block |= block_flag;
else
ccd_block &= ~block_flag;
/* Update blocked state in deferred function */
ccd_update_state();
}
print_ccd_ports_blocked();
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(ccdblock, command_ccd_block,
"[<AP | EC | SERVO> [BOOLEAN]]",
"Force CCD ports disabled");