summaryrefslogtreecommitdiff
path: root/board
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2017-08-09 16:19:47 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2017-09-07 22:34:52 +0000
commit0ebe39fc29a85cbf3fa25346d427c6fe5fa2f5e5 (patch)
tree4e98c72772e370d57e7bdc1a61acd4e1fb9afbdb /board
parent930e7036473f4094a2a4c22cab2fae69f35877cf (diff)
downloadchrome-ec-0ebe39fc29a85cbf3fa25346d427c6fe5fa2f5e5.tar.gz
cr50: Consolidate CCD device enable
Currently, the Cr50 state machines (EC, AP, RDD, bitbang, etc.) manage their own enabling and disabling of the ports (UART, SPI, etc.) This is tricky because the rules for when ports should be enabled are non-trivial and must be applied in the correct order. In additionl the changes all need to be serialized, so that the hardware ends up in the correct state even if multiple state machines are changing simultaneously. Consolidate all of that into chip/g/rdd.c. The debug command for it is now 'ccdstate', which just prints the state machines. This will allow subsequent renaming of the 'ccdopen', etc. commands to 'ccd open', etc. Also include UART bit-banging into that state which must be consistent. Previously, it was possible for bit-banging to leave UART TX connected, instead of returning it to the previous state. Use better names for CCD config fields for UART. I'd had them backwards. BUG=b:62537474 BRANCH=cr50 TEST=manual, with a CR50_DEV=1 image 1) No servo or CCD Pull SERVO_DETECT low (disconnected) Pull CCD_MODE_L high (disabled) Pull EC_DETECT and AP_DETECT high (on) Reboot. RX is enabled even if cables are disconnected so we buffer. ccdstate -> UARTAP UARTEC Pull EC_DETECT low. ccdstate -> UARTAP Pull EC_DETECT high and AP_DETECT low. ccdstate -> UARTEC Pull AP_DETECT high. ccdstate -> UARTAP UARTEC 2) Servo only still allows UART RX Pull SERVO_DETECT high (connected). ccdstate -> UARTAP UARTEC 3) Both servo and CCD prioritizes servo. Pull CCD_MODE_L low (enabled). ccdstate -> UARTAP UARTEC Reboot, to make sure servo wins at boot time. ccdstate -> UARTAP UARTEC Bit-banging doesn't work when servo is connected. bitbang 2 9600 even -> superseded by servo bitbang -> disabled ccdstate -> UARTAP UARTEC 4) CCD only allows more ports and remembers we wanted to bit-bang Pull SERVO_DETECT low. ccdstate --> UARTAP+TX UARTEC+BB I2C SPI bitbang 2 disable ccdstate --> UARTAP+TX UARTEC+TX I2C SPI Reboot and see we don't take over servo ports until we're sure servo isn't present. ccdstate --> UARTAP UARTEC (for first second) ccdstate --> UARTAP+TX UARTEC+TX I2C SPI (after that) 5) Bit-banging takes over ECTX bitbang 2 9600 even bitbang -> baud rate 9600, parity even ccdstate -> UARTAP+TX UARTEC+BB I2C SPI bitbang 2 disable ccdstate -> UARTAP+TX UARTEC+TX I2C SPI 6) Permissions work. Allow easy access to full console and ccdopen: ccdset OpenNoTPMWipe always ccdset OpenNoLongPP always ccdset GscFullConsole always Default when locked is full AP UART EC RO, no I2C or SPI ccdlock ccdstate -> UARTAP+TX UARTEC No EC transmit permission means no bit-banging bitbang 2 9600 even bitbang -> disabled ccdstate -> UARTAP+TX UARTEC But it remembers that we wanted to ccdopen ccdstate -> UARTAP+TX UARTEC+BB I2C SPI bitbang 2 disable ccdstate -> UARTAP+TX UARTEC+TX I2C SPI Try turning on/off permissions ccdset UartGscTxECRx always ccdlock ccdstate -> UARTAP+TX UARTEC+TX No read means no write either ccdset UartGscRxECTx ifopened ccdlock ccdstate -> UARTAP+TX ccdopen ccdset UartGscRXAPTx ifopened ccdlock ccdstate -> (nothing) Check AP transmit permissions too ccdopen ccdset UartGscRxAPTx always ccdset UartGscTxAPRx ifopened ccdlock ccdstate -> UARTAP Check I2C ccdopen ccdset I2C always ccdlock ccdstate -> UARTAP I2C SPI port is enabled if either EC or AP flash is allowed ccdopen ccdset flashap always ccdlock ccdstate -> UARTAP I2C SPI ccdopen ccdset flashec always ccdset flashap ifopened ccdlock ccdstate -> UARTAP I2C SPI Back to defaults ccdoops Change-Id: I641f7ab2354570812e3fb37b470de32e5bd10db7 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/615928 Reviewed-by: Mary Ruthven <mruthven@chromium.org> (cherry picked from commit a285acd36f898a394b82b8cb865bf60922f7ae2c) Reviewed-on: https://chromium-review.googlesource.com/656425 Commit-Queue: Vadim Bendebury <vbendeb@chromium.org> Tested-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
Diffstat (limited to 'board')
-rw-r--r--board/cr50/ap_state.c4
-rw-r--r--board/cr50/board.c96
-rw-r--r--board/cr50/board.h11
-rw-r--r--board/cr50/ec_state.c16
-rw-r--r--board/cr50/rdd.c308
-rw-r--r--board/cr50/servo_state.c24
-rw-r--r--board/cr50/usb_i2c.c37
-rw-r--r--board/cr50/wp.c2
8 files changed, 275 insertions, 223 deletions
diff --git a/board/cr50/ap_state.c b/board/cr50/ap_state.c
index 4e95d1c1c4..0a42e9a41a 100644
--- a/board/cr50/ap_state.c
+++ b/board/cr50/ap_state.c
@@ -63,7 +63,7 @@ static void set_ap_off(void)
*/
gpio_set_flags(GPIO_INT_AP_L, GPIO_INPUT);
- disable_ccd_uart(UART_AP);
+ ccd_update_state();
/*
* We don't enable deep sleep on ARM devices yet, as its processing
@@ -92,7 +92,7 @@ static void set_ap_on(void)
gpio_set_flags(GPIO_INT_AP_L, GPIO_OUT_HIGH);
gpio_set_level(GPIO_INT_AP_L, 1);
- enable_ccd_uart(UART_AP);
+ ccd_update_state();
if (board_deep_sleep_allowed())
disable_deep_sleep();
diff --git a/board/cr50/board.c b/board/cr50/board.c
index 5d270184f4..238ee2eea5 100644
--- a/board/cr50/board.c
+++ b/board/cr50/board.c
@@ -594,17 +594,6 @@ static void configure_board_specific_gpios(void)
/* Enable powerdown exit on DIOM0 */
GWRITE_FIELD(PINMUX, EXITEN0, DIOM0, 1);
}
-
- /*
- * If the TPM_RST_L signal is already high when cr50 wakes up or
- * transitions to high before we are able to configure the gpio then
- * we will have missed the edge and the tpm reset isr will not get
- * called. Check that we haven't already missed the rising edge. If we
- * have alert tpm_rst_isr.
- */
- if (gpio_get_level(GPIO_TPM_RST_L))
- hook_call_deferred(&deferred_tpm_rst_isr_data, 0);
-
if (!board_detect_ap_with_tpm_rst()) {
/* Use AP UART TX as the DETECT AP signal. */
GWRITE(PINMUX, GPIO1_GPIO1_SEL, GC_PINMUX_DIOA3_SEL);
@@ -708,8 +697,18 @@ static void board_init(void)
check_board_id_mismatch();
check_board_id_mismatch();
- /* Enable TPM reset GPIO interrupt */
+ /*
+ * Enable TPM reset GPIO interrupt.
+ *
+ * If the TPM_RST_L signal is already high when cr50 wakes up or
+ * transitions to high before we are able to configure the gpio then we
+ * will have missed the edge and the tpm reset isr will not get
+ * called. Check that we haven't already missed the rising edge. If we
+ * have alert tpm_rst_isr.
+ */
gpio_enable_interrupt(GPIO_TPM_RST_L);
+ if (gpio_get_level(GPIO_TPM_RST_L))
+ hook_call_deferred(&deferred_tpm_rst_isr_data, 0);
/*
* Start monitoring AC detect to wake Cr50 from deep sleep. This is
@@ -743,6 +742,9 @@ static void board_ccd_config_changed(void)
GREG32(PMU, LONG_LIFE_SCRATCH1) |= (ccd_get_state() << BOARD_CCD_SHIFT)
& BOARD_CCD_STATE;
GWRITE_FIELD(PMU, LONG_LIFE_SCRATCH_WR_EN, REG1, 0);
+
+ /* Update CCD state */
+ ccd_update_state();
}
DECLARE_HOOK(HOOK_CCD_CHANGE, board_ccd_config_changed, HOOK_PRIO_DEFAULT);
@@ -927,76 +929,6 @@ int is_ec_rst_asserted(void)
return GREAD(RBOX, ASSERT_EC_RST);
}
-void enable_ccd_uart(int uart)
-{
- /*
- * 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.
- */
- if (uart_bitbang_is_enabled(uart))
- return;
- }
-
- /* Enable RX and TX on the UART peripheral */
- uartn_enable(uart);
-
- /* Connect the TX pin to the UART TX signal */
- if (!uart_tx_is_connected(uart))
- uartn_tx_connect(uart);
-}
-
-void disable_ccd_uart(int uart)
-{
- /* Disable RX and TX on the UART peripheral */
- uartn_disable(uart);
-
- /* Disconnect the TX pin from the UART peripheral */
- uartn_tx_disconnect(uart);
-}
-
-static void board_ccd_change_hook(void)
-{
- if (uartn_is_enabled(UART_AP) &&
- !ccd_is_cap_enabled(CCD_CAP_AP_TX_CR50_RX)) {
- /* Receiving from AP, but no longer allowed */
- disable_ccd_uart(UART_AP);
- } else if (!uartn_is_enabled(UART_AP) &&
- ccd_is_cap_enabled(CCD_CAP_AP_TX_CR50_RX)) {
- /* Not receiving from AP, but allowed now */
- enable_ccd_uart(UART_AP);
- }
-
- if (uartn_is_enabled(UART_EC) &&
- !ccd_is_cap_enabled(CCD_CAP_EC_TX_CR50_RX)) {
- /* Receiving from EC, but no longer allowed */
- disable_ccd_uart(UART_EC);
- } else if (!uartn_is_enabled(UART_EC) &&
- ccd_is_cap_enabled(CCD_CAP_EC_TX_CR50_RX)) {
- /* Not receiving from EC, but allowed now */
- enable_ccd_uart(UART_EC);
- }
-}
-DECLARE_HOOK(HOOK_CCD_CHANGE, board_ccd_change_hook, HOOK_PRIO_DEFAULT);
-
/*
* This function duplicates some of the functionality in chip/g/gpio.c in order
* to configure a given strap pin to be either a low gpio output, a gpio input
diff --git a/board/cr50/board.h b/board/cr50/board.h
index a82c63720c..363ad8e755 100644
--- a/board/cr50/board.h
+++ b/board/cr50/board.h
@@ -248,6 +248,13 @@ void assert_ec_rst(void);
void deassert_ec_rst(void);
int is_ec_rst_asserted(void);
+/**
+ * Set up a deferred call to update CCD state.
+ *
+ * This will enable/disable UARTs, SPI, I2C, etc. as needed.
+ */
+void ccd_update_state(void);
+
int board_use_plt_rst(void);
int board_rst_pullup_needed(void);
int board_tpm_uses_i2c(void);
@@ -267,15 +274,13 @@ void board_reboot_ap(void);
int board_wipe_tpm(void);
int board_is_first_factory_boot(void);
-void enable_ccd_uart(int uart);
-void disable_ccd_uart(int uart);
-
void print_ap_state(void);
void print_ec_state(void);
void print_servo_state(void);
int ap_is_on(void);
int ec_is_on(void);
+int ec_is_rx_allowed(void);
int servo_is_connected(void);
void set_ap_on_deferred(void);
diff --git a/board/cr50/ec_state.c b/board/cr50/ec_state.c
index a324bdf772..4fe8400568 100644
--- a/board/cr50/ec_state.c
+++ b/board/cr50/ec_state.c
@@ -26,6 +26,11 @@ int ec_is_on(void)
return (state == DEVICE_STATE_DEBOUNCING || state == DEVICE_STATE_ON);
}
+int ec_is_rx_allowed(void)
+{
+ return ec_is_on() || state == DEVICE_STATE_INIT_RX_ONLY;
+}
+
/**
* Set the EC state.
*
@@ -64,10 +69,8 @@ static void set_ec_on(void)
* it right away that blocks us from detecting servo.
*/
CPRINTS("EC RX only");
- if (!uart_bitbang_is_enabled(UART_EC))
- uartn_enable(UART_EC);
-
set_state(DEVICE_STATE_INIT_RX_ONLY);
+ ccd_update_state();
return;
}
@@ -82,10 +85,7 @@ static void set_ec_on(void)
/* We were previously off */
CPRINTS("EC on");
set_state(DEVICE_STATE_ON);
-
- /* Enable UART RX if we're not bit-banging */
- if (!uart_bitbang_is_enabled(UART_EC))
- enable_ccd_uart(UART_EC);
+ ccd_update_state();
}
DECLARE_DEFERRED(set_ec_on);
@@ -121,7 +121,7 @@ static void ec_detect(void)
state == DEVICE_STATE_INIT_DEBOUNCING) {
CPRINTS("EC off");
set_state(DEVICE_STATE_OFF);
- disable_ccd_uart(UART_EC);
+ ccd_update_state();
return;
}
diff --git a/board/cr50/rdd.c b/board/cr50/rdd.c
index e55737387d..037d5bbc7d 100644
--- a/board/cr50/rdd.c
+++ b/board/cr50/rdd.c
@@ -12,6 +12,7 @@
#include "rdd.h"
#include "registers.h"
#include "system.h"
+#include "uart_bitbang.h"
#include "uartn.h"
#include "usb_api.h"
#include "usb_console.h"
@@ -22,6 +23,7 @@
USB_SPI_CONFIG(ccd_usb_spi, USB_IFACE_SPI, USB_EP_SPI);
#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args)
static enum device_state state = DEVICE_STATE_INIT;
@@ -68,7 +70,7 @@ void uartn_tx_connect(int uart)
return;
if (uart == UART_AP) {
- if (!ccd_is_cap_enabled(CCD_CAP_AP_RX_CR50_TX))
+ if (!ccd_is_cap_enabled(CCD_CAP_GSC_TX_AP_RX))
return;
if (!ap_is_on())
@@ -76,7 +78,7 @@ void uartn_tx_connect(int uart)
uart_select_tx(UART_AP, GC_PINMUX_UART1_TX_SEL);
} else {
- if (!ccd_is_cap_enabled(CCD_CAP_EC_RX_CR50_TX))
+ if (!ccd_is_cap_enabled(CCD_CAP_GSC_TX_EC_RX))
return;
if (!ec_is_on())
@@ -92,7 +94,219 @@ void uartn_tx_disconnect(int uart)
uart_select_tx(uart, 0);
}
-static void rdd_check_pin(void)
+/*
+ * Flags for the current CCD device state. This is used for determining what
+ * hardware devices we've enabled now, and which we want enabled.
+ */
+enum ccd_state_flag {
+ /* Flags for individual devices/ports */
+
+ /* AP UART is enabled. RX-only, unless TX is also enabled. */
+ CCD_ENABLE_UART_AP = (1 << 0),
+
+ /* AP UART transmit is enabled. Requires AP UART enabled. */
+ CCD_ENABLE_UART_AP_TX = (1 << 1),
+
+ /* EC UART is enabled. RX-only, unless TX is also enabled. */
+ CCD_ENABLE_UART_EC = (1 << 2),
+
+ /* EC UART transmit is enabled. Requires EC UART enabled. */
+ CCD_ENABLE_UART_EC_TX = (1 << 3),
+
+ /*
+ * EC UART bit-banging is enabled. Requires EC UART enabled, and
+ * blocks EC UART transmit.
+ */
+ CCD_ENABLE_UART_EC_BITBANG = (1 << 4),
+
+ /* I2C port is enabled */
+ CCD_ENABLE_I2C = (1 << 5),
+
+ /* SPI port is enabled for AP and/or EC flash */
+ CCD_ENABLE_SPI = (1 << 6),
+};
+
+/**
+ * Return the currently enabled state flags (see enum ccd_state_flag).
+ */
+static uint32_t get_state_flags(void)
+{
+ uint32_t flags_now = 0;
+
+ if (uartn_is_enabled(UART_AP))
+ flags_now |= CCD_ENABLE_UART_AP;
+ if (uart_tx_is_connected(UART_AP))
+ flags_now |= CCD_ENABLE_UART_AP_TX;
+ if (uartn_is_enabled(UART_EC))
+ flags_now |= CCD_ENABLE_UART_EC;
+ if (uart_tx_is_connected(UART_EC))
+ flags_now |= CCD_ENABLE_UART_EC_TX;
+
+#ifdef CONFIG_UART_BITBANG
+ if (uart_bitbang_is_enabled(UART_EC))
+ flags_now |= CCD_ENABLE_UART_EC_BITBANG;
+#endif
+
+ if (usb_i2c_board_is_enabled())
+ flags_now |= CCD_ENABLE_I2C;
+
+ if (ccd_usb_spi.state->enabled_device)
+ flags_now |= CCD_ENABLE_SPI;
+
+ return flags_now;
+}
+
+/**
+ * Print the state flags to the specified output channel
+ *
+ * @param channel Console channel
+ * @param flags Flags to print
+ */
+static void print_state_flags(enum console_channel channel, uint32_t flags)
+{
+ if (flags & CCD_ENABLE_UART_AP)
+ cprintf(channel, " UARTAP");
+ if (flags & CCD_ENABLE_UART_AP_TX)
+ cprintf(channel, "+TX");
+ if (flags & CCD_ENABLE_UART_EC)
+ cprintf(channel, " UARTEC");
+ if (flags & CCD_ENABLE_UART_EC_TX)
+ cprintf(channel, "+TX");
+ if (flags & CCD_ENABLE_UART_EC_BITBANG)
+ cprintf(channel, "+BB");
+ if (flags & CCD_ENABLE_I2C)
+ cprintf(channel, " I2C");
+ if (flags & CCD_ENABLE_SPI)
+ cprintf(channel, " SPI");
+}
+
+static void ccd_state_change_hook(void)
+{
+ uint32_t flags_now;
+ uint32_t flags_want = 0;
+ uint32_t delta;
+
+ /* Check what's enabled now */
+ flags_now = get_state_flags();
+
+ /* Start out by figuring what flags we might want enabled */
+
+ /* Enable EC/AP UART RX if that device is on */
+ if (ap_is_on())
+ flags_want |= CCD_ENABLE_UART_AP;
+ if (ec_is_rx_allowed())
+ flags_want |= CCD_ENABLE_UART_EC;
+
+#ifdef CONFIG_UART_BITBANG
+ /* EC must be all the way on for bit-banging the EC UART */
+ if (ec_is_on() && uart_bitbang_is_wanted(UART_EC))
+ flags_want |= CCD_ENABLE_UART_EC_BITBANG;
+#endif
+
+ /* External CCD will try to enable all the ports */
+ if (ccd_ext_is_enabled())
+ flags_want |= (CCD_ENABLE_UART_AP_TX | CCD_ENABLE_UART_EC_TX |
+ CCD_ENABLE_I2C | CCD_ENABLE_SPI);
+
+ /* Then disable flags we can't have */
+
+ /* Servo takes over UART TX, I2C, and SPI */
+ if (servo_is_connected())
+ flags_want &= ~(CCD_ENABLE_UART_AP_TX | CCD_ENABLE_UART_EC_TX |
+ CCD_ENABLE_UART_EC_BITBANG | CCD_ENABLE_I2C |
+ CCD_ENABLE_SPI);
+
+ /* Disable based on capabilities */
+ if (!ccd_is_cap_enabled(CCD_CAP_GSC_RX_AP_TX))
+ flags_want &= ~CCD_ENABLE_UART_AP;
+ if (!ccd_is_cap_enabled(CCD_CAP_GSC_TX_AP_RX))
+ flags_want &= ~CCD_ENABLE_UART_AP_TX;
+ if (!ccd_is_cap_enabled(CCD_CAP_GSC_RX_EC_TX))
+ flags_want &= ~CCD_ENABLE_UART_EC;
+ if (!ccd_is_cap_enabled(CCD_CAP_GSC_TX_EC_RX))
+ flags_want &= ~(CCD_ENABLE_UART_EC_TX |
+ CCD_ENABLE_UART_EC_BITBANG);
+ if (!ccd_is_cap_enabled(CCD_CAP_I2C))
+ flags_want &= ~CCD_ENABLE_I2C;
+
+ /*
+ * EC and AP flash block on a per-packet basis, but if we don't have
+ * access to either one, turn off SPI.
+ */
+ if (!ccd_is_cap_enabled(CCD_CAP_AP_FLASH) &&
+ !ccd_is_cap_enabled(CCD_CAP_EC_FLASH))
+ flags_want &= ~CCD_ENABLE_SPI;
+
+ /* EC UART TX blocked by bit-banging */
+ if (flags_want & CCD_ENABLE_UART_EC_BITBANG)
+ flags_want &= ~CCD_ENABLE_UART_EC_TX;
+
+ /* 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;
+ if (!(flags_want & CCD_ENABLE_UART_EC))
+ flags_want &= ~CCD_ENABLE_UART_EC_TX;
+
+ /* If no change, we're done */
+ if (flags_now == flags_want)
+ return;
+
+ CPRINTF("[%T CCD state:");
+ print_state_flags(CC_USB, flags_want);
+ CPRINTF("]\n");
+
+ /* Handle turning things off */
+ delta = flags_now & ~flags_want;
+ if (delta & CCD_ENABLE_UART_AP)
+ uartn_disable(UART_AP);
+ if (delta & CCD_ENABLE_UART_AP_TX)
+ uartn_tx_disconnect(UART_AP);
+ if (delta & CCD_ENABLE_UART_EC)
+ uartn_disable(UART_EC);
+ if (delta & CCD_ENABLE_UART_EC_TX)
+ uartn_tx_disconnect(UART_EC);
+#ifdef CONFIG_UART_BITBANG
+ if (delta & CCD_ENABLE_UART_EC_BITBANG)
+ uart_bitbang_disable(UART_EC);
+#endif
+ if (delta & CCD_ENABLE_I2C)
+ usb_i2c_board_disable();
+ if (delta & CCD_ENABLE_SPI)
+ usb_spi_enable(&ccd_usb_spi, 0);
+
+ /* Handle turning things on */
+ delta = flags_want & ~flags_now;
+ if (delta & CCD_ENABLE_UART_AP)
+ uartn_enable(UART_AP);
+ if (delta & CCD_ENABLE_UART_AP_TX)
+ uartn_tx_connect(UART_AP);
+ if (delta & CCD_ENABLE_UART_EC)
+ uartn_enable(UART_EC);
+ if (delta & CCD_ENABLE_UART_EC_TX)
+ uartn_tx_connect(UART_EC);
+#ifdef CONFIG_UART_BITBANG
+ if (delta & CCD_ENABLE_UART_EC_BITBANG)
+ uart_bitbang_enable(UART_EC);
+#endif
+ if (delta & CCD_ENABLE_I2C)
+ usb_i2c_board_enable();
+ if (delta & CCD_ENABLE_SPI)
+ usb_spi_enable(&ccd_usb_spi, 1);
+}
+DECLARE_DEFERRED(ccd_state_change_hook);
+
+void ccd_update_state(void)
+{
+ /*
+ * Use a deferred call to serialize changes from CCD config, RDD
+ * attach/detach, EC/AP startup or shutdown, etc.
+ */
+ hook_call_deferred(&ccd_state_change_hook_data, 0);
+}
+
+/*****************************************************************************/
+
+static void ccd_ext_detect(void)
{
/* The CCD mode pin is active low. */
int enable = !gpio_get_level(GPIO_CCD_MODE_L);
@@ -110,6 +324,8 @@ static void rdd_check_pin(void)
* that also has CCD_MODE_PARTIAL, and the only way to go
* cleanly between ENABLED and PARTIAL is to disable things and
* then re-enable only what's needed?
+ *
+ * TODO(rspangler): Figure out whether we can delete this.
*/
if (state != DEVICE_STATE_DISCONNECTED)
usb_release();
@@ -117,80 +333,24 @@ static void rdd_check_pin(void)
CPRINTS("CCD EXT enable");
state = DEVICE_STATE_CONNECTED;
- usb_console_enable(1, 0);
- usb_spi_enable(&ccd_usb_spi, 1);
usb_init();
-
- /* Attempt to connect UART TX */
- uartn_tx_connect(UART_AP);
- uartn_tx_connect(UART_EC);
-
- /* Turn on 3.3V rail used for INAs and initialize I2CM module */
- usb_i2c_board_enable();
+ usb_console_enable(1, 0);
} else {
CPRINTS("CCD EXT disable");
state = DEVICE_STATE_DISCONNECTED;
usb_release();
usb_console_enable(0, 0);
- usb_spi_enable(&ccd_usb_spi, 0);
-
- /* Disconnect from AP and EC UART TX peripheral from gpios */
- uartn_tx_disconnect(UART_EC);
- uartn_tx_disconnect(UART_AP);
-
- /* Turn off 3.3V rail to INAs and disconnect I2CM module */
- usb_i2c_board_disable();
- }
-}
-DECLARE_HOOK(HOOK_SECOND, rdd_check_pin, HOOK_PRIO_DEFAULT);
-
-static void rdd_ccd_change_hook(void)
-{
- if (uart_tx_is_connected(UART_AP) &&
- !ccd_is_cap_enabled(CCD_CAP_AP_RX_CR50_TX)) {
- /* Transmitting to AP, but no longer allowed */
- uartn_tx_disconnect(UART_AP);
- } else if (!uart_tx_is_connected(UART_AP) &&
- ccd_is_cap_enabled(CCD_CAP_AP_RX_CR50_TX)) {
- /* Not transmitting to AP, but allowed now */
- uartn_tx_connect(UART_AP);
}
- if (uart_tx_is_connected(UART_EC) &&
- !ccd_is_cap_enabled(CCD_CAP_EC_RX_CR50_TX)) {
- /* Transmitting to EC, but no longer allowed */
- uartn_tx_disconnect(UART_EC);
- } else if (!uart_tx_is_connected(UART_EC) &&
- ccd_is_cap_enabled(CCD_CAP_EC_RX_CR50_TX)) {
- /* Not transmitting to EC, but allowed now */
- uartn_tx_connect(UART_EC);
- }
+ ccd_update_state();
}
-DECLARE_HOOK(HOOK_CCD_CHANGE, rdd_ccd_change_hook, HOOK_PRIO_DEFAULT);
-
-static int command_ccd(int argc, char **argv)
-{
- int val;
+DECLARE_HOOK(HOOK_SECOND, ccd_ext_detect, HOOK_PRIO_DEFAULT);
- if (argc > 1) {
- if (!parse_bool(argv[argc - 1], &val))
- return argc == 2 ? EC_ERROR_PARAM1 : EC_ERROR_PARAM2;
-
- if (!strcasecmp("uart", argv[1])) {
- if (val)
- uartn_tx_connect(UART_EC);
- else
- uartn_tx_disconnect(UART_EC);
- } else if (!strcasecmp("i2c", argv[1])) {
- if (val)
- usb_i2c_board_enable();
- else
- usb_i2c_board_disable();
- } else
- return EC_ERROR_PARAM1;
- }
+/*****************************************************************************/
+static int command_ccd_state(int argc, char **argv)
+{
print_ap_state();
print_ec_state();
print_rdd_state();
@@ -198,20 +358,16 @@ static int command_ccd(int argc, char **argv)
ccprintf("CCD EXT: %s\n",
ccd_ext_is_enabled() ? "enabled" : "disabled");
- ccprintf("AP UART: %s\n",
- uartn_is_enabled(UART_AP) ?
- uart_tx_is_connected(UART_AP) ? "RX+TX" : "RX" : "disabled");
- ccprintf("EC UART: %s\n",
- uartn_is_enabled(UART_EC) ?
- uart_tx_is_connected(UART_EC) ? "RX+TX" : "RX" : "disabled");
- ccprintf("I2C: %s\n",
- usb_i2c_board_is_enabled() ? "enabled" : "disabled");
+
+ ccprintf("State flags:");
+ print_state_flags(CC_COMMAND, get_state_flags());
+ ccprintf("\n");
return EC_SUCCESS;
}
-DECLARE_CONSOLE_COMMAND(ccd, command_ccd,
- "[uart|i2c] [<BOOLEAN>]",
- "Get/set the case closed debug state");
+DECLARE_CONSOLE_COMMAND(ccdstate, command_ccd_state,
+ "",
+ "Print the case closed debug device state");
static int command_sys_rst(int argc, char **argv)
{
diff --git a/board/cr50/servo_state.c b/board/cr50/servo_state.c
index 5192549ec6..8c574f5a4e 100644
--- a/board/cr50/servo_state.c
+++ b/board/cr50/servo_state.c
@@ -85,10 +85,7 @@ static void servo_disconnect(void)
CPRINTS("Servo disconnect");
set_state(DEVICE_STATE_DISCONNECTED);
-
- /* Reconnect AP and EC UART TX if needed */
- uartn_tx_connect(UART_AP);
- uartn_tx_connect(UART_EC);
+ ccd_update_state();
}
/**
@@ -116,24 +113,7 @@ static void servo_connect(void)
*/
CPRINTS("Servo connect");
set_state(DEVICE_STATE_CONNECTED);
-
- /*
- * Disable UART bit banging. Note this must be done before
- * uartn_tx_disconnect() below, because this call will currently call
- * uartn_tx_connect()!
- */
- uart_bitbang_disable(bitbang_config.uart);
-
- /*
- * Disconnect AP and EC UART TX when servo is attached. It's ok to
- * leave RX enabled, because only TX interferes with TX from servo;
- * that's why we don't call disable_ccd_uart() here.
- */
- uartn_tx_disconnect(UART_AP);
- uartn_tx_disconnect(UART_EC);
-
- /* Disconnect i2cm interface to ina */
- usb_i2c_board_disable();
+ ccd_update_state();
}
DECLARE_DEFERRED(servo_connect);
diff --git a/board/cr50/usb_i2c.c b/board/cr50/usb_i2c.c
index 66d5aaa632..6536e00ca7 100644
--- a/board/cr50/usb_i2c.c
+++ b/board/cr50/usb_i2c.c
@@ -18,12 +18,18 @@
int usb_i2c_board_is_enabled(void)
{
+ /*
+ * Note that this signal requires an external pullup, because this is
+ * one of the real open drain pins; we cannot pull it up or drive it
+ * high. On test boards without the pullup, this will mis-detect as
+ * enabled.
+ */
return !gpio_get_level(GPIO_EN_PP3300_INA_L);
}
static void ina_disconnect(void)
{
- CPRINTS("Disabling I2C");
+ CPRINTS("I2C disconnect");
/* Disonnect I2C0 SDA/SCL output to B1/B0 pads */
GWRITE(PINMUX, DIOB1_SEL, 0);
@@ -38,7 +44,7 @@ static void ina_disconnect(void)
static void ina_connect(void)
{
- CPRINTS("Enabling I2C");
+ CPRINTS("I2C connect");
/* Apply power to INA chips */
gpio_set_level(GPIO_EN_PP3300_INA_L, 0);
@@ -89,30 +95,3 @@ int usb_i2c_board_enable(void)
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/cr50/wp.c b/board/cr50/wp.c
index 17714307d8..74a44f8ee0 100644
--- a/board/cr50/wp.c
+++ b/board/cr50/wp.c
@@ -325,7 +325,7 @@ int board_fwmp_allows_unlock(void)
int console_is_restricted(void)
{
- return !ccd_is_cap_enabled(CCD_CAP_CR50_RESTRICTED_CONSOLE);
+ return !ccd_is_cap_enabled(CCD_CAP_GSC_RESTRICTED_CONSOLE);
}
/****************************************************************************/