diff --git a/board/cr50/ap_uart_state.c b/board/cr50/ap_uart_state.c index 42e2feeab4..c21e8b518c 100644 --- a/board/cr50/ap_uart_state.c +++ b/board/cr50/ap_uart_state.c @@ -21,6 +21,12 @@ void print_ap_uart_state(void) ccprintf("AP UART: %s\n", device_state_name(state)); } +int ap_is_suspended(void) +{ + /* When the AP uart is off, that means the device is suspended. */ + return state == DEVICE_STATE_OFF; +} + int ap_uart_is_on(void) { /* Debouncing and on are both still on */ diff --git a/board/cr50/board.c b/board/cr50/board.c index 3a3eaf6d5a..b01b3571a3 100644 --- a/board/cr50/board.c +++ b/board/cr50/board.c @@ -149,6 +149,11 @@ int board_rst_pullup_needed(void) return !!(board_properties & BOARD_NEEDS_SYS_RST_PULL_UP); } +int board_needs_s3_term(void) +{ + return !!(board_properties & BOARD_NEEDS_S3_TERM); +} + int board_tpm_uses_i2c(void) { return !!(board_properties & BOARD_SLAVE_CONFIG_I2C); diff --git a/board/cr50/board.h b/board/cr50/board.h index c87cd3e651..75f25cc533 100644 --- a/board/cr50/board.h +++ b/board/cr50/board.h @@ -262,6 +262,9 @@ int board_tpm_uses_spi(void); int board_id_is_mismatched(void); /* Allow for deep sleep to be enabled on AP shutdown */ int board_deep_sleep_allowed(void); +int board_needs_s3_term(void); +int board_s3_term_is_enabled(void); +void board_s3_term(int enable); void power_button_record(void); @@ -282,6 +285,7 @@ void print_servo_state(void); int ap_is_on(void); int ap_uart_is_on(void); +int ap_is_suspended(void); int ec_is_on(void); int ec_is_rx_allowed(void); int servo_is_connected(void); diff --git a/board/cr50/build.mk b/board/cr50/build.mk index 049e29eafc..c245920bcd 100644 --- a/board/cr50/build.mk +++ b/board/cr50/build.mk @@ -39,6 +39,7 @@ board-${CONFIG_RDD} += rdd.o board-${CONFIG_USB_SPI} += usb_spi.o board-${CONFIG_USB_I2C} += usb_i2c.o board-y += recovery_button.o +board-y += s3_term.o board-y += tpm2/NVMem.o board-y += tpm2/aes.o board-y += tpm2/ecc.o diff --git a/board/cr50/rdd.c b/board/cr50/rdd.c index d59ca7d803..15173ba70a 100644 --- a/board/cr50/rdd.c +++ b/board/cr50/rdd.c @@ -145,6 +145,9 @@ enum ccd_state_flag { /* SPI port is enabled for AP and/or EC flash */ CCD_ENABLE_SPI = (1 << 6), + + /* S3 Terminations are enabled */ + CCD_ENABLE_S3_TERM = (1 << 7), }; int console_is_restricted(void) @@ -179,6 +182,9 @@ static uint32_t get_state_flags(void) if (ccd_usb_spi.state->enabled_device) flags_now |= CCD_ENABLE_SPI; + if (board_s3_term_is_enabled()) + flags_now |= CCD_ENABLE_S3_TERM; + return flags_now; } @@ -204,6 +210,8 @@ static void print_state_flags(enum console_channel channel, uint32_t flags) cprintf(channel, " I2C"); if (flags & CCD_ENABLE_SPI) cprintf(channel, " SPI"); + if (flags & CCD_ENABLE_S3_TERM) + cprintf(channel, " S3_TERM"); } static void ccd_state_change_hook(void) @@ -242,6 +250,10 @@ static void ccd_state_change_hook(void) CCD_ENABLE_UART_EC_BITBANG | CCD_ENABLE_I2C | CCD_ENABLE_SPI); + /* Enable S3 Terminations */ + if (ap_is_suspended() && board_needs_s3_term()) + flags_want |= CCD_ENABLE_S3_TERM; + /* Disable based on capabilities */ if (!ccd_is_cap_enabled(CCD_CAP_GSC_RX_AP_TX)) flags_want &= ~CCD_ENABLE_UART_AP; @@ -305,6 +317,8 @@ static void ccd_state_change_hook(void) usb_i2c_board_disable(); if (delta & CCD_ENABLE_SPI) usb_spi_enable(&ccd_usb_spi, 0); + if (delta & CCD_ENABLE_S3_TERM) + board_s3_term(0); /* Handle turning things on */ delta = flags_want & ~flags_now; @@ -324,6 +338,8 @@ static void ccd_state_change_hook(void) usb_i2c_board_enable(); if (delta & CCD_ENABLE_SPI) usb_spi_enable(&ccd_usb_spi, 1); + if (delta & CCD_ENABLE_S3_TERM) + board_s3_term(1); } DECLARE_DEFERRED(ccd_state_change_hook); diff --git a/board/cr50/s3_term.c b/board/cr50/s3_term.c new file mode 100644 index 0000000000..bb486d207e --- /dev/null +++ b/board/cr50/s3_term.c @@ -0,0 +1,88 @@ +/* Copyright 2018 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. + */ + +#include "console.h" +#include "registers.h" + +#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) +#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args) + +#define AP_TX_TERM (1 << 0) +#define SPS_TERM (1 << 1) + +int term_enabled; + +static void update_term_state(int term, int enable) +{ + if (enable) + term_enabled |= term; + else + term_enabled &= ~term; +} + +int board_s3_term_is_enabled(void) +{ + return term_enabled; +} + +static void ap_tx_term_enable(int term_enable) +{ + /* Add a pulldown to AP TX Cr50 RX */ + GWRITE_FIELD(PINMUX, DIOA3_CTL, PD, term_enable); + update_term_state(AP_TX_TERM, term_enable); +} + +static void sps_enable_pd(int term_enable) +{ + GWRITE_FIELD(PINMUX, DIOA2_CTL, PD, term_enable); /* SPS_MOSI */ + GWRITE_FIELD(PINMUX, DIOA6_CTL, PD, term_enable); /* SPS_CLK */ + GWRITE_FIELD(PINMUX, DIOA10_CTL, PD, term_enable); /* SPS_MISO */ + GWRITE_FIELD(PINMUX, DIOA12_CTL, PD, term_enable); /* SPS_CS_L */ +} + +static void sps_enable_inputs(int input_enable) +{ + GWRITE_FIELD(PINMUX, DIOA2_CTL, IE, input_enable); /* SPS_MOSI */ + GWRITE_FIELD(PINMUX, DIOA6_CTL, IE, input_enable); /* SPS_CLK */ + GWRITE_FIELD(PINMUX, DIOA10_CTL, IE, 0); /* SPS_MISO */ + GWRITE_FIELD(PINMUX, DIOA12_CTL, IE, input_enable); /* SPS_CS_L */ +} + +static void sps_term_enable(int term_enable) +{ + /* Disable the sps inputs before enabling the pulldowns */ + if (!term_enable) + sps_enable_inputs(!term_enable); + + /* Control the pulldowns on the SPS signals */ + sps_enable_pd(term_enable); + + /* Reenable the sps inputs after enabling the pulldowns */ + if (term_enable) + sps_enable_inputs(!term_enable); + update_term_state(SPS_TERM, term_enable); +} + +void board_s3_term(int term_enable) +{ + if (!board_needs_s3_term() || (!term_enable == !term_enabled)) + return; + CPRINTS("%sable S3 signal terminations", term_enable ? "En" : "Dis"); + + ap_tx_term_enable(term_enable); + + if (!board_tpm_uses_i2c()) + sps_term_enable(term_enable); +} + +static int command_s3term(int argc, char **argv) +{ + ccprintf("Terminations:%s%s\n", + term_enabled & AP_TX_TERM ? " AP" : "", + term_enabled & SPS_TERM ? " SPS" : ""); + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(s3term, command_s3term, "", + "Get the state of the S3 termination signals"); diff --git a/board/cr50/scratch_reg1.h b/board/cr50/scratch_reg1.h index 4462212941..8802a9f5c5 100644 --- a/board/cr50/scratch_reg1.h +++ b/board/cr50/scratch_reg1.h @@ -49,12 +49,15 @@ #define BOARD_DEEP_SLEEP_DISABLED (1 << 13) /* Use Cr50_RX_AP_TX to determine if the AP is off or on */ #define BOARD_DETECT_AP_WITH_UART (1 << 14) +/* Add terminations to signals in S3 */ +#define BOARD_NEEDS_S3_TERM (1 << 15) /* * Macro to capture all properties related to board strapping pins. This must be * updated if additional strap related properties are added. */ #define BOARD_ALL_PROPERTIES (BOARD_SLAVE_CONFIG_SPI | BOARD_SLAVE_CONFIG_I2C \ | BOARD_NEEDS_SYS_RST_PULL_UP | BOARD_USE_PLT_RESET | \ - BOARD_DEEP_SLEEP_DISABLED | BOARD_DETECT_AP_WITH_UART) + BOARD_DEEP_SLEEP_DISABLED | BOARD_DETECT_AP_WITH_UART | \ + BOARD_NEEDS_S3_TERM) #endif /* ! __EC_BOARD_CR50_SCRATCH_REG1_H */