summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Collyer <scollyer@google.com>2021-03-25 19:47:14 -0700
committerCommit Bot <commit-bot@chromium.org>2021-04-10 21:48:43 +0000
commit62aa709f472b6a4021ccb3396701b2a2036caea7 (patch)
tree29b73d765523ef973c0015fcfa67d34abe661ff6
parent8113e3d1f538039477ec4b1461031da770931055 (diff)
downloadchrome-ec-62aa709f472b6a4021ccb3396701b2a2036caea7.tar.gz
honeybuns: Add power button support
This CL adds support for the power button including a new task to allow for power sequencing delays. The power button is used for two purposes. First, to turn the dock on or off, and second, to allow for a user set preference of the MF for DP 2 or 4 lane selection. If the dock is off, the dock will be turned on as soon as the short press timer expires. If the dock is already on, then a short press action is only recognized on the release so a long press will only change the MF preference. BUG=b:164157329 BRANCH=quiche TEST=manaual short press -> turns dock on off as expected long press -> toggles MF preference and flashes LED Signed-off-by: Scott Collyer <scollyer@google.com> Change-Id: I8519c072a7f10657c369344ead6149fc7d31bb36 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2718268 Tested-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Sam Hurst <shurst@google.com> Commit-Queue: Scott Collyer <scollyer@chromium.org>
-rw-r--r--baseboard/honeybuns/baseboard.c377
-rw-r--r--baseboard/honeybuns/baseboard.h4
-rw-r--r--board/gingerbread/board.c40
-rw-r--r--board/gingerbread/board.h20
-rw-r--r--board/gingerbread/ec.tasklist1
-rw-r--r--board/gingerbread/gpio.inc6
-rw-r--r--board/quiche/board.c44
-rw-r--r--board/quiche/board.h20
-rw-r--r--board/quiche/ec.tasklist1
-rw-r--r--board/quiche/gpio.inc2
10 files changed, 477 insertions, 38 deletions
diff --git a/baseboard/honeybuns/baseboard.c b/baseboard/honeybuns/baseboard.c
index 3b6d4ba626..3425417b81 100644
--- a/baseboard/honeybuns/baseboard.c
+++ b/baseboard/honeybuns/baseboard.c
@@ -11,24 +11,81 @@
#include "i2c.h"
#include "usb_pd.h"
#include "system.h"
+#include "task.h"
#include "timer.h"
+#include "usbc_ppc.h"
+#include "driver/tcpm/tcpm.h"
#include "util.h"
#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args)
+#define POWER_BUTTON_SHORT_USEC (300 * MSEC)
+#define POWER_BUTTON_LONG_USEC (5000 * MSEC)
+#define POWER_BUTTON_DEBOUNCE_USEC (30)
+
+#define BUTTON_PRESSED_LEVEL 1
+#define BUTTON_RELEASED_LEVEL 0
+
+#define BUTTON_EVT_CHANGE BIT(0)
+#define BUTTON_EVT_INFO BIT(1)
+
+enum power {
+ POWER_OFF,
+ POWER_ON
+};
+
+enum button {
+ BUTTON_RELEASE,
+ BUTTON_PRESS,
+ BUTTON_PRESS_POWER_ON,
+ BUTTON_PRESS_SHORT,
+ BUTTON_PRESS_LONG,
+};
+
+#define LED_ON_OFF_BIT BIT(0)
+#define LED_COLOR_BIT BIT(2)
+#define LED_FLASH_SEQ_LENGTH 8
+
+enum led_color {
+ GREEN,
+ YELLOW,
+ OFF,
+};
+
+static enum power dock_state;
+#ifdef SECTION_IS_RW
+static int button_level;
+static int button_level_pending;
+static int dock_mf;
+static int led_count;
+#endif
+
/******************************************************************************/
-static void board_power_sequence(void)
+__maybe_unused static void board_power_sequence(int enable)
{
int i;
- for(i = 0; i < board_power_seq_count; i++) {
- gpio_set_level(board_power_seq[i].signal,
- board_power_seq[i].level);
- if (board_power_seq[i].delay_ms)
- msleep(board_power_seq[i].delay_ms);
+ if (enable) {
+ for(i = 0; i < board_power_seq_count; i++) {
+ gpio_set_level(board_power_seq[i].signal,
+ board_power_seq[i].level);
+ CPRINTS("power seq: rail = %d", i);
+ if (board_power_seq[i].delay_ms)
+ msleep(board_power_seq[i].delay_ms);
+ }
+ } else {
+ for(i = board_power_seq_count - 1; i >= 0; i--) {
+ gpio_set_level(board_power_seq[i].signal,
+ !board_power_seq[i].level);
+ CPRINTS("sequence[%d]: level = %d", i,
+ !board_power_seq[i].level);
+ }
}
+
+ dock_state = enable;
+ CPRINTS("board: Power rails %s", dock_state ? "on" : "off");
}
/******************************************************************************/
@@ -39,31 +96,92 @@ const struct i2c_port_t i2c_ports[] = {
};
const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
+#ifdef SECTION_IS_RW
+static void baseboard_set_led(enum led_color color)
+{
+ /*
+ * TODO(b/164157329): The power button feature should be connected to a
+ * 2 color LED which is part of the button. Currently, the power button
+ * LED is a single color LED which is controlled by on the of the power
+ * rails. Using the status LED now to demonstrate the LED behavior
+ * associated with a power button press.
+ */
+ CPRINTS("led: color = %d", color);
+ if (color == OFF) {
+ gpio_set_level(GPIO_EC_STATUS_LED1, 1);
+ gpio_set_level(GPIO_EC_STATUS_LED2, 1);
+ } else if (color == GREEN) {
+ gpio_set_level(GPIO_EC_STATUS_LED1, 1);
+ gpio_set_level(GPIO_EC_STATUS_LED2, 0);
+ } else if (color == YELLOW) {
+ gpio_set_level(GPIO_EC_STATUS_LED1, 0);
+ gpio_set_level(GPIO_EC_STATUS_LED2, 0);
+ }
+}
+
+static void baseboard_led_callback(void);
+DECLARE_DEFERRED(baseboard_led_callback);
-void baseboard_set_mst_lane_control(int dock_mf)
+static void baseboard_led_callback(void)
{
- /* Check if lane swich level is changing */
- if (dock_mf != gpio_get_level(GPIO_MST_HUB_LANE_SWITCH)) {
+ /*
+ * Flash LED on transition using a simple 3 bit counter. Bit 0 controls
+ * LED on/off and bit 2 controls which color to set during the on phase.
+ */
+ int color = led_count & LED_COLOR_BIT ? dock_mf : dock_mf ^ 1;
+
+ /*
+ * TODO(b/164157329): This function implements a simple flashing
+ * transition when the MF preference bit is changed via a long power
+ * button press sequence. This might need to move to the board function
+ * if not required/desired on all variants.
+ */
+
+ if (led_count & LED_ON_OFF_BIT)
+ baseboard_set_led(color);
+ else
+ baseboard_set_led(OFF);
+
+ /* Flash sequence is 8 steps */
+ if (++led_count < LED_FLASH_SEQ_LENGTH)
+ hook_call_deferred(&baseboard_led_callback_data, 150 * MSEC);
+}
+
+static void baseboard_change_mf_led(void)
+{
+ led_count = 0;
+ baseboard_led_callback();
+}
+
+void baseboard_set_mst_lane_control(int mf)
+{
+ /*
+ * The parameter mf reflects the desired lane control value. If the
+ * current value does not match the desired, then the MST hub must first
+ * be put into reset, so the MST hub will latch in the correct value
+ * when it's taken out of reset.
+ */
+ if (mf != gpio_get_level(GPIO_MST_HUB_LANE_SWITCH)) {
/* put MST into reset */
gpio_set_level(GPIO_MST_RST_L, 0);
msleep(1);
- gpio_set_level(GPIO_MST_HUB_LANE_SWITCH, dock_mf);
- CPRINTS("MST: lane control = %s", dock_mf ? "high" : "low");
+ gpio_set_level(GPIO_MST_HUB_LANE_SWITCH, mf);
+ CPRINTS("MST: lane control = %s", mf ? "high" : "low");
msleep(1);
/* lane control is set, take MST out of reset */
gpio_set_level(GPIO_MST_RST_L, 1);
}
}
+#endif /* SECTION_IS_RW */
static void baseboard_init(void)
{
#ifdef SECTION_IS_RW
- int rv;
uint32_t fw_config;
#endif
/* Turn on power rails */
- board_power_sequence();
+ board_power_sequence(1);
CPRINTS("board: Power rails enabled");
#ifdef SECTION_IS_RW
@@ -77,9 +195,16 @@ static void baseboard_init(void)
* field of the CBI. If this value is programmed, then make sure the
* MST_LANE_CONTROL gpio matches the mf bit.
*/
- rv = cbi_get_fw_config(&fw_config);
- if (!rv)
- baseboard_set_mst_lane_control(fw_config & 1);
+ if (cbi_get_fw_config(&fw_config)) {
+ dock_mf = CBI_FW_MF_PREFERENCE(fw_config);
+ baseboard_set_mst_lane_control(dock_mf);
+ }
+
+ /* Enable power button interrupt */
+ gpio_enable_interrupt(GPIO_PWR_BTN);
+ /* Set dock mf preference LED */
+ baseboard_set_led(dock_mf);
+
#else
/* Set up host port usbc to present Rd on CC lines */
if(baseboard_usbc_init(USB_PD_PORT_HOST))
@@ -91,3 +216,223 @@ static void baseboard_init(void)
* power sequencing as soon as I2C bus is initialized.
*/
DECLARE_HOOK(HOOK_INIT, baseboard_init, HOOK_PRIO_INIT_I2C + 1);
+
+#ifdef SECTION_IS_RW
+static void baseboard_power_on(void)
+{
+ int port_max = board_get_usb_pd_port_count();
+ int port;
+
+ /* Adjust system flags to full PPC init occurs */
+ system_clear_reset_flags(EC_RESET_FLAG_POWER_ON);
+ system_set_reset_flags(EC_RESET_FLAG_EFS);
+ /* Enable power rails and release reset signals */
+ board_power_sequence(1);
+ /*
+ * Lane control (realtek MST) must be set prior to releasing MST
+ * reset.
+ */
+ baseboard_set_mst_lane_control(dock_mf);
+ /*
+ * When the power to the PPC is turned off, then back on, the PPC will
+ * default into dead battery mode. Dead battery resistors are disabled
+ * as part of the full PPC intializaiton sequence. This is required to
+ * force a detach event with port parter which can be attached as usbc
+ * source when honeybuns power rails are off.
+ */
+ for (port = 0; port < port_max; port++) {
+ ppc_init(port);
+ msleep(1000);
+ /* Inform TC state machine that it can resume */
+ pd_set_suspend(port, 0);
+ }
+ /* Enable usbc interrupts */
+ board_enable_usbc_interrupts();
+}
+
+static void baseboard_power_off(void)
+{
+ int port_max = board_get_usb_pd_port_count();
+ int port;
+
+ /* Put ports in TC suspend state */
+ for (port = 0; port < port_max; port++)
+ pd_set_suspend(port, 1);
+
+ /* Disable ucpd peripheral (prevents interrupts) */
+ tcpm_release(USB_PD_PORT_HOST);
+ /* Disable PPC/TCPC interrupts */
+ board_disable_usbc_interrupts();
+ /* Go into power off state */
+ board_power_sequence(0);
+}
+
+static void baseboard_toggle_mf(void)
+{
+ uint32_t fw_config;
+
+ if (!cbi_get_fw_config(&fw_config)) {
+ /* Update the user MF preference stored in CBI */
+ fw_config ^= CBI_FW_MF_MASK;
+ cbi_set_fw_config(fw_config);
+ /* Update variable used to track user MF preference */
+ dock_mf = CBI_FW_MF_PREFERENCE(fw_config);
+ /* Flash led for visual indication of user MF change */
+ baseboard_change_mf_led();
+ /* Power the dock off, then on, to apply user preference */
+ baseboard_power_off();
+ baseboard_power_on();
+ }
+}
+
+/*
+ * Main task entry point for UCPD task
+ */
+void power_button_task(void *u)
+{
+ int timer_us = POWER_BUTTON_DEBOUNCE_USEC * 4;
+ enum button state = BUTTON_RELEASE;
+ uint32_t evt;
+
+ /*
+ * Capture current button level in case it's being pressed when the dock
+ * is powered on. Note timer_us is initialized for debounce time to
+ * double check.
+ */
+ button_level = gpio_get_level(GPIO_PWR_BTN);
+
+ while (1) {
+ evt = task_wait_event(timer_us);
+ timer_us = -1;
+
+ if (evt == BUTTON_EVT_INFO) {
+ /* Only used for console command for debug */
+ CPRINTS("pwrbtn: pwr = %d, state = %d, level = %d",
+ dock_state, state, button_level);
+ continue;
+ }
+
+ switch (state) {
+ case BUTTON_RELEASE:
+ /*
+ * Default wait state: Only need to check if the button
+ * is pressed and start the short press timer.
+ */
+ if (evt & BUTTON_EVT_CHANGE && button_level ==
+ BUTTON_PRESSED_LEVEL) {
+ state = BUTTON_PRESS;
+ timer_us = (POWER_BUTTON_SHORT_USEC -
+ POWER_BUTTON_DEBOUNCE_USEC);
+ }
+ break;
+ case BUTTON_PRESS:
+ /*
+ * Validate short press by ensuring that button is still
+ * pressed after short press timer expires.
+ */
+ if (evt & BUTTON_EVT_CHANGE &&
+ button_level == BUTTON_RELEASED_LEVEL) {
+ state = BUTTON_RELEASE;
+ } else {
+ /* Start long press timer */
+ timer_us = POWER_BUTTON_LONG_USEC -
+ POWER_BUTTON_SHORT_USEC;
+ /*
+ * If dock is currently off, then change to the
+ * power on state. If dock is already on, then
+ * advance to short press state.
+ */
+ if (dock_state == POWER_OFF) {
+ baseboard_power_on();
+ state = BUTTON_PRESS_POWER_ON;
+ } else {
+ state = BUTTON_PRESS_SHORT;
+ }
+ }
+ break;
+ case BUTTON_PRESS_POWER_ON:
+ /*
+ * Short press recognized and dock was just powered
+ * on. If button is no longer pressed, then just return
+ * to the default state. Else, button is still pressed
+ * after long press timer has expired.
+ */
+ if (evt & BUTTON_EVT_CHANGE &&
+ button_level == BUTTON_RELEASED_LEVEL) {
+ state = BUTTON_RELEASE;
+ } else {
+ state = BUTTON_PRESS_LONG;
+ baseboard_toggle_mf();
+ }
+ break;
+ case BUTTON_PRESS_SHORT:
+ /*
+ * Short press was recognized and dock power state was
+ * already on. If button is now released, then turn dock
+ * off.
+ */
+ if (evt & BUTTON_EVT_CHANGE &&
+ button_level == BUTTON_RELEASED_LEVEL) {
+ state = BUTTON_RELEASE;
+ baseboard_power_off();
+ } else {
+ state = BUTTON_PRESS_LONG;
+ baseboard_toggle_mf();
+ }
+ break;
+ case BUTTON_PRESS_LONG:
+ if (evt & BUTTON_EVT_CHANGE &&
+ button_level == BUTTON_RELEASED_LEVEL) {
+ state = BUTTON_RELEASE;
+ }
+ break;
+ }
+ }
+}
+
+static void baseboard_power_button_debounce(void)
+{
+ int level = gpio_get_level(GPIO_PWR_BTN);
+
+ /* Sanity check, level should be same after debounce interval */
+ if (level != button_level_pending)
+ return;
+
+ button_level = level;
+ task_set_event(TASK_ID_POWER_BUTTON, BUTTON_EVT_CHANGE);
+}
+DECLARE_DEFERRED(baseboard_power_button_debounce);
+
+void baseboard_power_button_evt(int level)
+{
+ button_level_pending = level;
+
+ hook_call_deferred(&baseboard_power_button_debounce_data,
+ POWER_BUTTON_DEBOUNCE_USEC);
+}
+
+static int command_pwr_btn(int argc, char **argv)
+{
+
+ if (argc == 1) {
+ task_set_event(TASK_ID_POWER_BUTTON, BUTTON_EVT_INFO);
+ return EC_SUCCESS;
+ }
+
+ if (!strcasecmp(argv[1], "on")) {
+ baseboard_power_on();
+ } else if (!strcasecmp(argv[1], "off")) {
+ baseboard_power_off();
+ } else if (!strcasecmp(argv[1], "mf")) {
+ baseboard_toggle_mf();
+ } else {
+ return EC_ERROR_PARAM1;
+ }
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(pwr_btn, command_pwr_btn,
+ "<on|off|mf>",
+ "Simulate Power Button Press");
+
+#endif
diff --git a/baseboard/honeybuns/baseboard.h b/baseboard/honeybuns/baseboard.h
index 0faf727ab8..76bcaf490d 100644
--- a/baseboard/honeybuns/baseboard.h
+++ b/baseboard/honeybuns/baseboard.h
@@ -87,7 +87,8 @@
#define CONFIG_CROS_BOARD_INFO
#define CONFIG_BOARD_VERSION_CBI
#define CONFIG_CMD_CBI
-#define CONFIG_CMD_CBI_SET
+#define CBI_FW_MF_MASK BIT(0)
+#define CBI_FW_MF_PREFERENCE(val) (val & (CBI_FW_MF_MASK))
/* USB Configuration */
#define CONFIG_USB
@@ -228,6 +229,7 @@ enum adc_channel {
extern const struct power_seq board_power_seq[];
extern const size_t board_power_seq_count;
+void baseboard_power_button_evt(int level);
/*
* Configure the host port to present Rd on both CC lines. This function is
diff --git a/board/gingerbread/board.c b/board/gingerbread/board.c
index d20b09b067..a3cc78598f 100644
--- a/board/gingerbread/board.c
+++ b/board/gingerbread/board.c
@@ -78,6 +78,11 @@ void hpd_interrupt(enum gpio_signal signal)
{
usb_pd_hpd_edge_event(signal);
}
+
+static void board_pwr_btn_interrupt(enum gpio_signal signal)
+{
+ baseboard_power_button_evt(gpio_get_level(signal));
+}
#endif /* SECTION_IS_RW */
#include "gpio_list.h" /* Must come after other header files. */
@@ -91,7 +96,7 @@ const struct power_seq board_power_seq[] = {
{GPIO_EN_AC_JACK, 1, 20},
{GPIO_EN_PP5000_A, 1, 31},
{GPIO_EN_PP3300_A, 1, 35},
- {GPIO_STATUS_LED1, 0, 100},
+ {GPIO_EC_STATUS_LED1, 0, 100},
{GPIO_EN_BB, 1, 30},
{GPIO_EN_PP1100_A, 1, 30},
{GPIO_EN_PP1000_A, 1, 20},
@@ -110,7 +115,7 @@ const struct power_seq board_power_seq[] = {
{GPIO_DEMUX_DP_HDMI_PD_N, 1, 10},
{GPIO_DEMUX_DUAL_DP_MODE, 1, 10},
{GPIO_DEMUX_DP_HDMI_MODE, 1, 1},
- {GPIO_STATUS_LED2, 0, 100},
+ {GPIO_EC_STATUS_LED2, 0, 100},
};
const size_t board_power_seq_count = ARRAY_SIZE(board_power_seq);
@@ -130,6 +135,7 @@ const void *const usb_strings[] = {
BUILD_ASSERT(ARRAY_SIZE(usb_strings) == USB_STR_COUNT);
#ifndef SECTION_IS_RW
+/* USB-C PPC Configuration */
struct ppc_config_t ppc_chips[] = {
[USB_PD_PORT_HOST] = {
.i2c_port = I2C_PORT_I2C3,
@@ -218,7 +224,7 @@ void board_reset_pd_mcu(void)
/* Power Delivery and charging functions */
-void board_tcpc_init(void)
+void board_enable_usbc_interrupts(void)
{
board_reset_pd_mcu();
@@ -232,6 +238,28 @@ void board_tcpc_init(void)
gpio_enable_interrupt(GPIO_DDI_MST_IN_HPD);
}
+
+/* Power Delivery and charging functions */
+void board_disable_usbc_interrupts(void)
+{
+ /* Disable PPC interrupts. */
+ gpio_disable_interrupt(GPIO_HOST_USBC_PPC_INT_ODL);
+
+ /* Disable TCPC interrupts. */
+ gpio_disable_interrupt(GPIO_USBC_DP_MUX_ALERT_ODL);
+
+ /* Disable HPD interrupt */
+ gpio_disable_interrupt(GPIO_DDI_MST_IN_HPD);
+
+}
+
+void board_tcpc_init(void)
+{
+ board_reset_pd_mcu();
+
+ /* Enable board usbc interrupts */
+ board_enable_usbc_interrupts();
+}
DECLARE_HOOK(HOOK_INIT, board_tcpc_init, HOOK_PRIO_INIT_I2C + 2);
enum pd_dual_role_states board_tc_get_initial_drp_mode(int port)
@@ -284,17 +312,17 @@ static void board_debug_gpio_2_pulse(void)
}
DECLARE_DEFERRED(board_debug_gpio_2_pulse);
-void board_debug_gpio(int trigger, int enable, int pulse_usec)
+void board_debug_gpio(enum debug_gpio trigger, int level, int pulse_usec)
{
switch (trigger) {
case TRIGGER_1:
- gpio_set_level(GPIO_TRIGGER_1, enable);
+ gpio_set_level(GPIO_TRIGGER_1, level);
if (pulse_usec)
hook_call_deferred(&board_debug_gpio_1_pulse_data,
pulse_usec);
break;
case TRIGGER_2:
- gpio_set_level(GPIO_TRIGGER_2, enable);
+ gpio_set_level(GPIO_TRIGGER_2, level);
if (pulse_usec)
hook_call_deferred(&board_debug_gpio_2_pulse_data,
pulse_usec);
diff --git a/board/gingerbread/board.h b/board/gingerbread/board.h
index 21883367d0..d0b2994d31 100644
--- a/board/gingerbread/board.h
+++ b/board/gingerbread/board.h
@@ -68,7 +68,25 @@ enum debug_gpio {
TRIGGER_2,
};
-void board_debug_gpio(int trigger, int enable, int pulse_usec);
+/*
+ * Function used to control GPIO signals as a timing marker. This is intended to
+ * be used for development/debugging purposes.
+ *
+ * @param trigger GPIO debug signal selection
+ * @param level desired level of the debug gpio signal
+ * @param pulse_usec pulse width if non-zero
+ */
+void board_debug_gpio(enum debug_gpio trigger, int level, int pulse_usec);
+
+/*
+ * Function called in power on case to enable usbc related interrupts
+ */
+void board_enable_usbc_interrupts(void);
+
+/*
+ * Function called in power off case to disable usbc related interrupts
+ */
+void board_disable_usbc_interrupts(void);
#endif /* !__ASSEMBLER__ */
diff --git a/board/gingerbread/ec.tasklist b/board/gingerbread/ec.tasklist
index a7c0eb9b2c..cc36bf5a74 100644
--- a/board/gingerbread/ec.tasklist
+++ b/board/gingerbread/ec.tasklist
@@ -11,6 +11,7 @@
TASK_ALWAYS_RO(RWSIG, rwsig_task, NULL, 1280) \
TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS_RW(POWER_BUTTON, power_button_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS_RW(PD_C0, pd_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_ALWAYS_RW(PD_C1, pd_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_ALWAYS_RW(PD_INT_C1, pd_interrupt_handler_task, 1, LARGER_TASK_STACK_SIZE) \
diff --git a/board/gingerbread/gpio.inc b/board/gingerbread/gpio.inc
index 0c54a9800d..9d2e3df5d9 100644
--- a/board/gingerbread/gpio.inc
+++ b/board/gingerbread/gpio.inc
@@ -12,10 +12,10 @@
GPIO_INT(HOST_USBC_PPC_INT_ODL, PIN(C, 1), GPIO_INT_FALLING | GPIO_PULL_UP, ppc_interrupt)
GPIO_INT(USBC_DP_MUX_ALERT_ODL, PIN(C, 12), GPIO_INT_FALLING | GPIO_PULL_UP, tcpc_alert_event)
GPIO_INT(DDI_MST_IN_HPD, PIN(C, 14), GPIO_INT_BOTH, hpd_interrupt)
+GPIO_INT(PWR_BTN, PIN(A, 0), GPIO_INT_BOTH, board_pwr_btn_interrupt)
#endif
/* Power sequencing signals */
-GPIO(PWR_BTN, PIN(A, 0), GPIO_INPUT)
GPIO(EN_AC_JACK, PIN(A, 1), GPIO_OUT_LOW)
GPIO(EN_BB, PIN(C, 0), GPIO_OUT_LOW)
GPIO(EN_PP3300_A, PIN(C, 10), GPIO_OUT_LOW)
@@ -25,8 +25,8 @@ GPIO(EN_PP1100_A, PIN(C, 4), GPIO_OUT_LOW)
GPIO(EN_PP1000_A, PIN(C, 5), GPIO_OUT_LOW)
GPIO(EN_PP1050_A, PIN(C, 6), GPIO_OUT_LOW)
GPIO(EN_PP5000_HSPORT, PIN(C, 7), GPIO_OUT_LOW)
-GPIO(STATUS_LED1, PIN(A, 2), GPIO_OUT_HIGH)
-GPIO(STATUS_LED2, PIN(B, 12), GPIO_OUT_HIGH)
+GPIO(EC_STATUS_LED1, PIN(A, 2), GPIO_OUT_HIGH)
+GPIO(EC_STATUS_LED2, PIN(B, 12), GPIO_OUT_HIGH)
/* MST Hub signals */
GPIO(MST_LP_CTL_L, PIN(B, 9), GPIO_OUT_LOW)
diff --git a/board/quiche/board.c b/board/quiche/board.c
index 05fc76d132..782d5ef243 100644
--- a/board/quiche/board.c
+++ b/board/quiche/board.c
@@ -97,6 +97,11 @@ static void board_uf_manage_vbus_interrupt(enum gpio_signal signal)
{
hook_call_deferred(&board_uf_manage_vbus_data, 0);
}
+
+static void board_pwr_btn_interrupt(enum gpio_signal signal)
+{
+ baseboard_power_button_evt(gpio_get_level(signal));
+}
#endif /* SECTION_IS_RW */
#include "gpio_list.h" /* Must come after other header files. */
@@ -243,18 +248,39 @@ void board_reset_pd_mcu(void)
msleep(PS8805_FW_INIT_DELAY_MS);
}
-void board_tcpc_init(void)
+void board_enable_usbc_interrupts(void)
{
- board_reset_pd_mcu();
-
- /* Enable PPC interrupts. */
+ /* Enable C0 PPC interrupt */
gpio_enable_interrupt(GPIO_HOST_USBC_PPC_INT_ODL);
+ /* Enable C1 PPC interrupt */
gpio_enable_interrupt(GPIO_USBC_DP_PPC_INT_ODL);
- /* Enable HPD interrupt */
+ /* Enable C0 HPD interrupt */
gpio_enable_interrupt(GPIO_DDI_MST_IN_HPD);
- /* Enable TCPC interrupts. */
+ /* Enable C1 TCPC interrupt */
gpio_enable_interrupt(GPIO_USBC_DP_MUX_ALERT_ODL);
}
+
+void board_disable_usbc_interrupts(void)
+{
+ /* Disable C0 PPC interrupt */
+ gpio_disable_interrupt(GPIO_HOST_USBC_PPC_INT_ODL);
+ /* Disable C1 PPC interrupt */
+ gpio_disable_interrupt(GPIO_USBC_DP_PPC_INT_ODL);
+ /* Disable C0 HPD interrupt */
+ gpio_disable_interrupt(GPIO_DDI_MST_IN_HPD);
+ /* Disable C1 TCPC interrupt */
+ gpio_disable_interrupt(GPIO_USBC_DP_MUX_ALERT_ODL);
+ /* Disable VBUS control interrupt for C2 */
+ gpio_disable_interrupt(GPIO_USBC_UF_MUX_VBUS_EN);
+}
+
+void board_tcpc_init(void)
+{
+ board_reset_pd_mcu();
+
+ /* Enable board usbc interrupts */
+ board_enable_usbc_interrupts();
+}
DECLARE_HOOK(HOOK_INIT, board_tcpc_init, HOOK_PRIO_INIT_I2C + 2);
enum pd_dual_role_states board_tc_get_initial_drp_mode(int port)
@@ -343,17 +369,17 @@ static void board_debug_gpio_2_pulse(void)
}
DECLARE_DEFERRED(board_debug_gpio_2_pulse);
-void board_debug_gpio(int trigger, int enable, int pulse_usec)
+void board_debug_gpio(enum debug_gpio trigger, int level, int pulse_usec)
{
switch (trigger) {
case TRIGGER_1:
- gpio_set_level(GPIO_TRIGGER_1, enable);
+ gpio_set_level(GPIO_TRIGGER_1, level);
if (pulse_usec)
hook_call_deferred(&board_debug_gpio_1_pulse_data,
pulse_usec);
break;
case TRIGGER_2:
- gpio_set_level(GPIO_TRIGGER_2, enable);
+ gpio_set_level(GPIO_TRIGGER_2, level);
if (pulse_usec)
hook_call_deferred(&board_debug_gpio_2_pulse_data,
pulse_usec);
diff --git a/board/quiche/board.h b/board/quiche/board.h
index 0de8572604..ad9d57d271 100644
--- a/board/quiche/board.h
+++ b/board/quiche/board.h
@@ -57,7 +57,25 @@ enum debug_gpio {
TRIGGER_2,
};
-void board_debug_gpio(int trigger, int enable, int pulse_usec);
+/*
+ * Function used to control GPIO signals as a timing marker. This is intended to
+ * be used for development/debugging purposes.
+ *
+ * @param trigger GPIO debug signal selection
+ * @param level desired level of the debug gpio signal
+ * @param pulse_usec pulse width if non-zero
+ */
+void board_debug_gpio(enum debug_gpio trigger, int level, int pulse_usec);
+
+/*
+ * Function called in power on case to enable usbc related interrupts
+ */
+void board_enable_usbc_interrupts(void);
+
+/*
+ * Function called in power off case to disable usbc related interrupts
+ */
+void board_disable_usbc_interrupts(void);
#endif /* !__ASSEMBLER__ */
diff --git a/board/quiche/ec.tasklist b/board/quiche/ec.tasklist
index a7c0eb9b2c..cc36bf5a74 100644
--- a/board/quiche/ec.tasklist
+++ b/board/quiche/ec.tasklist
@@ -11,6 +11,7 @@
TASK_ALWAYS_RO(RWSIG, rwsig_task, NULL, 1280) \
TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS_RW(POWER_BUTTON, power_button_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS_RW(PD_C0, pd_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_ALWAYS_RW(PD_C1, pd_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_ALWAYS_RW(PD_INT_C1, pd_interrupt_handler_task, 1, LARGER_TASK_STACK_SIZE) \
diff --git a/board/quiche/gpio.inc b/board/quiche/gpio.inc
index 76b1dfb90e..d47f54db74 100644
--- a/board/quiche/gpio.inc
+++ b/board/quiche/gpio.inc
@@ -14,10 +14,10 @@ GPIO_INT(USBC_DP_MUX_ALERT_ODL, PIN(B, 1), GPIO_INT_FALLING | GPIO_PULL_U
GPIO_INT(USBC_DP_PPC_INT_ODL, PIN(E, 7), GPIO_INT_FALLING | GPIO_PULL_UP, ppc_interrupt)
GPIO_INT(DDI_MST_IN_HPD, PIN(C, 14), GPIO_INT_BOTH, hpd_interrupt)
GPIO_INT(USBC_UF_MUX_VBUS_EN, PIN(C, 12), GPIO_INT_BOTH, board_uf_manage_vbus_interrupt)
+GPIO_INT(PWR_BTN, PIN(A, 0), GPIO_INT_BOTH, board_pwr_btn_interrupt)
#endif
/* Power sequencing signals */
-GPIO(PWR_BTN, PIN(A, 0), GPIO_INPUT)
GPIO(EN_AC_JACK, PIN(A, 1), GPIO_OUT_LOW)
GPIO(EN_BB, PIN(A, 8), GPIO_OUT_LOW)
GPIO(EN_PP3300_B, PIN(B, 2), GPIO_OUT_LOW)