diff options
-rw-r--r-- | board/cr50/board.c | 53 | ||||
-rw-r--r-- | board/cr50/board.h | 11 | ||||
-rw-r--r-- | board/cr50/build.mk | 2 | ||||
-rw-r--r-- | board/cr50/ec_state.c | 112 | ||||
-rw-r--r-- | board/cr50/gpio.inc | 2 | ||||
-rw-r--r-- | board/cr50/rdd.c | 7 |
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); |