summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2017-08-17 13:01:32 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-08-25 19:54:11 -0700
commit1154a307e1c4acee37aaf4e7a6beebe2d2ed67db (patch)
tree4b522d0865f35f94de84f8ee786ccfc64a1f7870
parent07d646ced0da75061ca6b977806954559eafa2b8 (diff)
downloadchrome-ec-1154a307e1c4acee37aaf4e7a6beebe2d2ed67db.tar.gz
cr50: Split EC state machine into its own file
The device state machines aren't quite similar enough to use common code. Split the EC state machine out, the way we split out BattPrsnt and CCD_MODE. BUG=b:35587387 BRANCH=cr50 TEST=manual Pull CCD_MODE_L high, so Cr50 detects/enables CCD Pull EC_DETECT high. reboot -> 'EC RX only', then 'EC on' at 1 second Pull EC_DETECT low --> See 'EC off' message ccd --> EC UART disabled Pull EC_DETECT high --> See 'EC on' message ccd --> EC UART RX+TX Pull EC_DETECT low for <1 sec then back high (don't see EC off/on messages) ccd --> EC UART RX+TX Reboot with EC_DETECT still low -> EC off at 1 second Reboot with EC_DETECT still low and then assert EC_DETECT within a second -> EC RX only, then EC connect at 1 second. Change-Id: I71687e651d625cadd656934f4cb2bbadc0b58816 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/619750 Reviewed-by: Mary Ruthven <mruthven@chromium.org>
-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);