cr50: Only enable UART RX when EC/AP is on

Previously, some code paths such as CCD permissions change could
result in enabling EC or AP UART RX when the EC or AP is off.  This
could result in interrupt storms.

BUG=none
BRANCH=cr50
TEST=manual
	// Initial conditions
	Assert CCD_MODE_L
	Deassert DETECT_SERVO

	// Both RX and TX disabled when processor turns off
	// and re-enabled when it turns back on
	Deassert DETECT_EC
	ccd -> EC UART disabled
	Assert DETECT_EC
	ccd --> EC UART RX+TX

	Deassert DETECT_AP
	ccd -> AP UART disabled
	Assert DETECT_AP
	ccd --> AP UART RX+TX

	// TX disabled when CCD disabled
	Deassert CCD_MODE_L
	ccd --> EC UART RX, AP UART RX

	Assert DETECT_SERVO
	ccd --> EC UART RX, AP UART RX

	// Don't enable TX when detecting EC, if servo is connected
	Deassert DETECT_EC
	ccd -> EC UART disabled
	Assert DETECT_EC
	ccd --> EC UART RX

	// Don't enable TX when detecting CCD, if servo is connected
	Assert CCD_MODE_L
	ccd --> EC UART RX, AP UART RX

	// When servo disconnects, enable TX if CCD is connected
	Deassert DETECT_SERVO
	ccd --> EC UART RX+TX, AP UART RX+TX

Change-Id: Icb144c23e949afb0384c242965aa729b078b03eb
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/642349
Reviewed-by: Mary Ruthven <mruthven@chromium.org>
This commit is contained in:
Randall Spangler
2017-08-29 14:31:03 -07:00
committed by chrome-bot
parent b52f9b8ea6
commit 8202ddaa95
2 changed files with 37 additions and 29 deletions

View File

@@ -976,10 +976,25 @@ static int servo_state_unknowable(void)
void enable_ccd_uart(int uart)
{
if (uart == UART_EC) {
/*
* Only enable the UART if we have receive permission, and if the
* processor we're talking to is on. When the processor is off, its
* transmit line (our receive line) may float, leading to interrupt
* storms.
*/
if (uart == UART_AP) {
if (!ccd_is_cap_enabled(CCD_CAP_AP_TX_CR50_RX))
return;
if (!ap_is_on())
return;
} else {
if (!ccd_is_cap_enabled(CCD_CAP_EC_TX_CR50_RX))
return;
if (!ec_is_on())
return;
/*
* For the EC UART, we can't connect the TX pin to the UART
* block when it's in bit bang mode.
@@ -988,13 +1003,10 @@ void enable_ccd_uart(int uart)
return;
}
if (uart == UART_AP && !ccd_is_cap_enabled(CCD_CAP_AP_TX_CR50_RX))
return;
/* Enable RX and TX on the UART peripheral */
uartn_enable(uart);
/* Connect the TX pin to the UART TX Signal */
/* Connect the TX pin to the UART TX signal */
if (!uart_tx_is_connected(uart))
uartn_tx_connect(uart);
}

View File

@@ -19,16 +19,6 @@
#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)
struct uart_config {
const char *name;
int tx_signal;
};
static struct uart_config uarts[] = {
[UART_AP] = {"AP", GC_PINMUX_UART1_TX_SEL},
[UART_EC] = {"EC", GC_PINMUX_UART2_TX_SEL},
};
int rdd_is_connected(void)
{
return ccd_get_mode() == CCD_MODE_ENABLED;
@@ -68,25 +58,31 @@ int servo_is_connected(void)
void uartn_tx_connect(int uart)
{
if (uart == UART_AP && !ccd_is_cap_enabled(CCD_CAP_AP_RX_CR50_TX))
/*
* Don't drive TX unless the debug cable is connected (we have
* something to transmit) and servo is disconnected (we won't be
* drive-fighting with servo).
*/
if (servo_is_connected() || !rdd_is_connected())
return;
if (uart == UART_EC && !ccd_is_cap_enabled(CCD_CAP_EC_RX_CR50_TX))
return;
if (uart == UART_AP) {
if (!ccd_is_cap_enabled(CCD_CAP_AP_RX_CR50_TX))
return;
if (!rdd_is_connected())
return;
if (!ap_is_on())
return;
if (servo_is_connected()) {
CPRINTS("Servo is attached cannot enable %s UART",
uarts[uart].name);
return;
uart_select_tx(UART_AP, GC_PINMUX_UART1_TX_SEL);
} else {
if (!ccd_is_cap_enabled(CCD_CAP_EC_RX_CR50_TX))
return;
if (!ec_is_on())
return;
uart_select_tx(UART_EC, GC_PINMUX_UART2_TX_SEL);
}
if (uart == UART_AP ? ap_is_on() : ec_is_on())
uart_select_tx(uart, uarts[uart].tx_signal);
else if (!uart_tx_is_connected(uart))
CPRINTS("%s is powered off", uarts[uart].name);
}
void uartn_tx_disconnect(int uart)