summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/cr50/board.c53
-rw-r--r--board/cr50/board.h11
-rw-r--r--board/cr50/build.mk2
-rw-r--r--board/cr50/ec_state.c112
-rw-r--r--board/cr50/gpio.inc2
-rw-r--r--board/cr50/rdd.c7
6 files changed, 135 insertions, 52 deletions
diff --git a/board/cr50/board.c b/board/cr50/board.c
index 626535f98e..7fc590ec76 100644
--- a/board/cr50/board.c
+++ b/board/cr50/board.c
@@ -527,11 +527,6 @@ int ap_is_on(void)
return device_get_state(DEVICE_AP) == DEVICE_STATE_ON;
}
-int ec_is_on(void)
-{
- return device_get_state(DEVICE_EC) == DEVICE_STATE_ON;
-}
-
static void configure_board_specific_gpios(void)
{
/* Add a pullup to sys_rst_l */
@@ -710,7 +705,6 @@ static void board_init(void)
/* Enable GPIO interrupts for device state machines */
gpio_enable_interrupt(GPIO_TPM_RST_L);
gpio_enable_interrupt(GPIO_DETECT_AP);
- gpio_enable_interrupt(GPIO_DETECT_EC);
gpio_enable_interrupt(GPIO_DETECT_SERVO);
/*
@@ -953,7 +947,7 @@ static int servo_state_unknowable(void)
return 0;
}
-static void enable_uart(int uart)
+void enable_ccd_uart(int uart)
{
if (uart == UART_EC) {
if (!ccd_is_cap_enabled(CCD_CAP_EC_TX_CR50_RX))
@@ -978,7 +972,7 @@ static void enable_uart(int uart)
uartn_tx_connect(uart);
}
-static void disable_uart(int uart)
+void disable_ccd_uart(int uart)
{
/* Disable RX and TX on the UART peripheral */
uartn_disable(uart);
@@ -992,21 +986,21 @@ 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_uart(UART_AP);
+ 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_uart(UART_AP);
+ 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_uart(UART_EC);
+ 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_uart(UART_EC);
+ enable_ccd_uart(UART_EC);
}
}
DECLARE_HOOK(HOOK_CCD_CHANGE, board_ccd_change_hook, HOOK_PRIO_DEFAULT);
@@ -1087,22 +1081,6 @@ static void ap_deferred(void)
}
DECLARE_DEFERRED(ap_deferred);
-/**
- * Deferred handler for debouncing EC presence detect falling.
- *
- * This is called if DETECT_AP has been low long enough.
- */
-static void ec_deferred(void)
-{
- /*
- * If the EC was still in DEVICE_STATE_UNKNOWN, move it to
- * DEVICE_STATE_OFF and disable its UART.
- */
- if (device_powered_off(DEVICE_EC))
- disable_uart(UART_EC);
-}
-DECLARE_DEFERRED(ec_deferred);
-
/* Note: this must EXACTLY match enum device_type! */
struct device_config device_states[] = {
[DEVICE_SERVO] = {
@@ -1116,12 +1094,6 @@ struct device_config device_states[] = {
.deferred = &ap_deferred_data,
.name = "AP"
},
- [DEVICE_EC] = {
- .state = DEVICE_STATE_UNKNOWN,
- .deferred = &ec_deferred_data,
- .detect = GPIO_DETECT_EC,
- .name = "EC"
- },
};
BUILD_ASSERT(ARRAY_SIZE(device_states) == DEVICE_COUNT);
@@ -1199,15 +1171,6 @@ void device_state_on(enum gpio_signal signal)
if (device_state_changed(DEVICE_AP, DEVICE_STATE_ON))
hook_notify(HOOK_CHIPSET_RESUME);
break;
- case GPIO_DETECT_EC:
- /*
- * Turn the EC device on. If it was previously unknown or
- * off, enable the EC UART.
- */
- if (device_state_changed(DEVICE_EC, DEVICE_STATE_ON) &&
- !uart_bitbang_is_enabled(UART_EC))
- enable_uart(UART_EC);
- break;
case GPIO_DETECT_SERVO:
servo_attached();
break;
@@ -1319,7 +1282,7 @@ static void ap_shutdown(void)
*/
gpio_set_flags(GPIO_INT_AP_L, GPIO_INPUT);
- disable_uart(UART_AP);
+ disable_ccd_uart(UART_AP);
/*
* We don't enable deep sleep on ARM devices yet, as its processing
@@ -1346,7 +1309,7 @@ static void ap_resume(void)
gpio_set_flags(GPIO_INT_AP_L, GPIO_OUT_HIGH);
gpio_set_level(GPIO_INT_AP_L, 1);
- enable_uart(UART_AP);
+ enable_ccd_uart(UART_AP);
disable_deep_sleep();
}
diff --git a/board/cr50/board.h b/board/cr50/board.h
index ea907a351c..5c61eadb4a 100644
--- a/board/cr50/board.h
+++ b/board/cr50/board.h
@@ -174,7 +174,6 @@ enum usb_strings {
/* Device indexes for devices that require debouncing */
enum device_type {
DEVICE_AP = 0,
- DEVICE_EC,
DEVICE_SERVO,
DEVICE_COUNT
@@ -195,6 +194,12 @@ enum device_state {
*/
DEVICE_STATE_INIT_DEBOUNCING,
+ /*
+ * Device was detected at boot, but we can't enable transmit yet
+ * because that would interfere with detection of another device.
+ */
+ DEVICE_STATE_INIT_RX_ONLY,
+
/* Disconnected or off, because detect is deasserted */
DEVICE_STATE_DISCONNECTED,
DEVICE_STATE_OFF,
@@ -230,6 +235,7 @@ enum nvmem_vars {
void board_configure_deep_sleep_wakepins(void);
/* Interrupt handler */
void tpm_rst_deasserted(enum gpio_signal signal);
+void ec_detect_asserted(enum gpio_signal signal);
void device_state_on(enum gpio_signal signal);
void post_reboot_request(void);
void ec_tx_cr50_rx(enum gpio_signal signal);
@@ -261,6 +267,9 @@ 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);
+
int ap_is_on(void);
int ec_is_on(void);
int rdd_is_connected(void);
diff --git a/board/cr50/build.mk b/board/cr50/build.mk
index 1e882e9876..4babeef552 100644
--- a/board/cr50/build.mk
+++ b/board/cr50/build.mk
@@ -29,7 +29,7 @@ dirs-y += chip/$(CHIP)/dcrypto
dirs-y += $(BDIR)/tpm2
# Objects that we need to build
-board-y = board.o
+board-y = board.o ec_state.o
board-${CONFIG_RDD} += rdd.o
board-${CONFIG_USB_SPI} += usb_spi.o
board-${CONFIG_USB_I2C} += usb_i2c.o
diff --git a/board/cr50/ec_state.c b/board/cr50/ec_state.c
new file mode 100644
index 0000000000..5958ea3b79
--- /dev/null
+++ b/board/cr50/ec_state.c
@@ -0,0 +1,112 @@
+/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * EC detect state machine.
+ */
+#include "common.h"
+#include "console.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "uart_bitbang.h"
+#include "uartn.h"
+
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
+
+static enum device_state state = DEVICE_STATE_INIT;
+
+int ec_is_on(void)
+{
+ /* Debouncing and on are both still on */
+ return (state == DEVICE_STATE_DEBOUNCING || state == DEVICE_STATE_ON);
+}
+
+/**
+ * Move the EC to the ON state.
+ *
+ * This can be deferred from the interrupt handler, or called from the state
+ * machine which also runs in HOOK task, so it needs to check the current state
+ * to determine whether we're already on.
+ */
+static void set_ec_on(void)
+{
+ if (state == DEVICE_STATE_INIT ||
+ state == DEVICE_STATE_INIT_DEBOUNCING) {
+ /*
+ * Enable the UART peripheral so we start receiving on EC RX,
+ * but do not call uartn_tx_connect() to connect EC TX yet. We
+ * need to be able to use EC TX to detect servo, so if we drive
+ * it right away that blocks us from detecting servo.
+ */
+ CPRINTS("EC RX only");
+ if (!uart_bitbang_is_enabled(UART_EC))
+ uartn_enable(UART_EC);
+ state = DEVICE_STATE_INIT_RX_ONLY;
+ return;
+ }
+
+ /* If we were debouncing ON->OFF, cancel it because we're still on */
+ if (state == DEVICE_STATE_DEBOUNCING)
+ state = DEVICE_STATE_ON;
+
+ /* If we're already on, done */
+ if (state == DEVICE_STATE_ON)
+ return;
+
+ /* We were previously off */
+ CPRINTS("EC on");
+ 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);
+}
+DECLARE_DEFERRED(set_ec_on);
+
+/**
+ * Interrupt handler for EC detect asserted.
+ */
+void ec_detect_asserted(enum gpio_signal signal)
+{
+ gpio_disable_interrupt(GPIO_DETECT_EC);
+ hook_call_deferred(&set_ec_on_data, 0);
+}
+
+/**
+ * Detect state machine
+ */
+static void ec_detect(void)
+{
+ /* Disable interrupts if we had them on for debouncing */
+ gpio_disable_interrupt(GPIO_DETECT_EC);
+
+ /* If we detect the EC, make sure it's on */
+ if (gpio_get_level(GPIO_DETECT_EC)) {
+ set_ec_on();
+ return;
+ }
+
+ /* EC wasn't detected. If we're already off, done. */
+ if (state == DEVICE_STATE_OFF)
+ return;
+
+ /* If we were debouncing, we're now sure we're off */
+ if (state == DEVICE_STATE_DEBOUNCING ||
+ state == DEVICE_STATE_INIT_DEBOUNCING) {
+ CPRINTS("EC off");
+ state = DEVICE_STATE_OFF;
+ disable_ccd_uart(UART_EC);
+ return;
+ }
+
+ /*
+ * Otherwise, we were on or initializing, and we're not sure if the EC
+ * is actually off or just sending a 0-bit. So start debouncing.
+ */
+ if (state == DEVICE_STATE_INIT)
+ state = DEVICE_STATE_INIT_DEBOUNCING;
+ else
+ state = DEVICE_STATE_DEBOUNCING;
+ gpio_enable_interrupt(GPIO_DETECT_EC);
+}
+DECLARE_HOOK(HOOK_SECOND, ec_detect, HOOK_PRIO_DEFAULT);
diff --git a/board/cr50/gpio.inc b/board/cr50/gpio.inc
index 1be250e379..0bd90555af 100644
--- a/board/cr50/gpio.inc
+++ b/board/cr50/gpio.inc
@@ -57,7 +57,7 @@
*/
GPIO_INT(TPM_RST_L, PIN(1, 0), GPIO_INT_RISING, tpm_rst_deasserted)
GPIO_INT(DETECT_AP, PIN(1, 1), GPIO_INT_HIGH, device_state_on)
-GPIO_INT(DETECT_EC, PIN(1, 2), GPIO_INT_HIGH, device_state_on)
+GPIO_INT(DETECT_EC, PIN(1, 2), GPIO_INT_HIGH, ec_detect_asserted)
/*
* DETECT_SERVO and EC_TX_CR50_RX pins must NOT be changed without also changing
* the pinmux_regval fields in the bitbang_config in board.c. The pinmux values
diff --git a/board/cr50/rdd.c b/board/cr50/rdd.c
index 074ffac858..bfc58a136c 100644
--- a/board/cr50/rdd.c
+++ b/board/cr50/rdd.c
@@ -21,13 +21,12 @@
struct uart_config {
const char *name;
- enum device_type device;
int tx_signal;
};
static struct uart_config uarts[] = {
- [UART_AP] = {"AP", DEVICE_AP, GC_PINMUX_UART1_TX_SEL},
- [UART_EC] = {"EC", DEVICE_EC, GC_PINMUX_UART2_TX_SEL},
+ [UART_AP] = {"AP", GC_PINMUX_UART1_TX_SEL},
+ [UART_EC] = {"EC", GC_PINMUX_UART2_TX_SEL},
};
int rdd_is_connected(void)
@@ -84,7 +83,7 @@ void uartn_tx_connect(int uart)
return;
}
- if (device_get_state(uarts[uart].device) == DEVICE_STATE_ON)
+ 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);