summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWai-Hong Tam <waihong@google.com>2018-09-19 15:10:57 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-10-30 01:04:51 -0700
commitb47ed2a108c679de26be89fa258931ddf040e446 (patch)
treea170884ea21d2a7c21f0a72ed06d299a11ed857b
parent5f068e277ba6de108615aa3190ccb14b316b67f0 (diff)
downloadchrome-ec-b47ed2a108c679de26be89fa258931ddf040e446.tar.gz
cheza: Monitor the WARM_RESET_L signal to hold AP
This change is a backup solution if JTAG_SRST gets fused out. The WARM_RESET_L signal is wired to JTAG_SRST, such that we can hold AP when servo/H1 programs the AP SPI flash. But when JTAG_SRST gets fused out (just in case it happens), still have a way to hold AP, i.e. overdriving the AP_RST_L and PS_HOLD signals. The WARM_RESET_L signal is pulled by a rail from PMIC, the same as POWER_GOOD. The drop of WARM_RESET_L may be caused by either servo/ cr50 holds the signal or its pull-up rail drops. We should handle both cases. Also add WARM_RESET_L as one of the power signals for debug purpose. BRANCH=none BUG=b:78194018, b:112723105, b:112564635 TEST=Ran "dut-control warm_reset:on" and "dut-control warm_reset:off". Scoped the signal of AP_RST_L and PS_HOLD to verify the correctness. Verified AP hold and back booting up. TEST=Changed to the gpio.inc to swap LID_OPEN and WARM_RESET_L and ran "dut-control lid_open:no" and "dut-control lid_open:yes" to emualte the case JTAG_SRST gets fused out. Scoped the signal correctness. Verified AP hold and back booting up. Ran flashrom to program AP SPI flash through servo. Change-Id: I71ebd920171da9994192f7742675feb7cb39ce2f Signed-off-by: Wai-Hong Tam <waihong@google.com> Reviewed-on: https://chromium-review.googlesource.com/1234743
-rw-r--r--board/cheza/board.c4
-rw-r--r--board/cheza/board.h1
-rw-r--r--board/cheza/gpio.inc12
-rw-r--r--include/chipset.h9
-rw-r--r--power/sdm845.c65
5 files changed, 85 insertions, 6 deletions
diff --git a/board/cheza/board.c b/board/cheza/board.c
index e1d85f91f2..4bf71eab01 100644
--- a/board/cheza/board.c
+++ b/board/cheza/board.c
@@ -204,6 +204,10 @@ const struct power_signal_info power_signal_list[] = {
GPIO_POWER_GOOD,
POWER_SIGNAL_ACTIVE_HIGH,
"POWER_GOOD"},
+ [SDM845_WARM_RESET] = {
+ GPIO_WARM_RESET_L,
+ POWER_SIGNAL_ACTIVE_HIGH,
+ "WARM_RESET_L"},
};
BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);
diff --git a/board/cheza/board.h b/board/cheza/board.h
index ce83a439b6..9998233356 100644
--- a/board/cheza/board.h
+++ b/board/cheza/board.h
@@ -172,6 +172,7 @@ enum power_signal {
SDM845_PS_HOLD,
SDM845_PMIC_FAULT_L,
SDM845_POWER_GOOD,
+ SDM845_WARM_RESET,
/* Number of power signals */
POWER_SIGNAL_COUNT
};
diff --git a/board/cheza/gpio.inc b/board/cheza/gpio.inc
index 49dbfdc008..3ba7840340 100644
--- a/board/cheza/gpio.inc
+++ b/board/cheza/gpio.inc
@@ -27,12 +27,17 @@ GPIO_INT(VOLUME_UP_L, PIN(F, 2), GPIO_INT_BOTH | GPIO_PULL_UP, button_inte
GPIO_INT(WP_L, PIN(A, 1), GPIO_INT_BOTH, switch_interrupt) /* EC_WP_ODL */
GPIO_INT(LID_OPEN, PIN(D, 2), GPIO_INT_BOTH | GPIO_HIB_WAKE_HIGH, lid_interrupt) /* LID_OPEN_EC */
GPIO_INT(AP_RST_REQ, PIN(C, 2), GPIO_INT_RISING | GPIO_PULL_DOWN | GPIO_SEL_1P8V, chipset_reset_request_interrupt) /* Reset request from AP */
-/* AP_RST_L and PS_HOLD are used for PMIC and AP negotiation. Don't change their states. */
GPIO_INT(AP_RST_L, PIN(C, 1), GPIO_INT_BOTH | GPIO_SEL_1P8V, power_signal_interrupt)
GPIO_INT(PS_HOLD, PIN(D, 4), GPIO_INT_BOTH | GPIO_PULL_DOWN | GPIO_SEL_1P8V, power_signal_interrupt) /* Indicate when AP triggers reset/shutdown */
GPIO_INT(PMIC_FAULT_L, PIN(7, 6), GPIO_INT_BOTH | GPIO_SEL_1P8V, power_signal_interrupt) /* Any PMIC fault? */
-/* When switch-cap is off, the POWER_GOOD signal is floating. Need a pull-down to make it low. */
-GPIO_INT(POWER_GOOD, PIN(5, 4), GPIO_INT_BOTH | GPIO_PULL_DOWN | GPIO_SEL_1P8V, power_signal_interrupt) /* SRC_PP1800_S4A from PMIC */
+/*
+ * When switch-cap is off, the POWER_GOOD signal is floating. Need a pull-down
+ * to make it low. Overload the interrupt function chipset_warm_reset_interrupt
+ * for not only signalling power_signal_interrupt but also handling the logic
+ * of WARM_RESET_L which is pulled-up by the same rail of POWER_GOOD.
+ */
+GPIO_INT(POWER_GOOD, PIN(5, 4), GPIO_INT_BOTH | GPIO_PULL_DOWN | GPIO_SEL_1P8V, chipset_warm_reset_interrupt) /* SRC_PP1800_S4A from PMIC */
+GPIO_INT(WARM_RESET_L, PIN(F, 4), GPIO_INT_BOTH | GPIO_SEL_1P8V, chipset_warm_reset_interrupt) /* AP warm reset */
GPIO_INT(SHI_CS_L, PIN(5, 3), GPIO_INT_FALLING | GPIO_PULL_DOWN | GPIO_SEL_1P8V, shi_cs_event) /* AP_EC_SPI_CS_L */
GPIO_INT(CC_LID_BASE_ADC, PIN(4, 5), GPIO_INT_BOTH, base_detect_interrupt) /* Base detection */
@@ -54,7 +59,6 @@ GPIO(PROCHOT_L, PIN(3, 4), GPIO_INPUT)
/* PMIC/AP 1.8V */
GPIO(PM845_RESIN_L, PIN(3, 2), GPIO_ODR_HIGH | GPIO_SEL_1P8V) /* PMIC reset trigger */
-GPIO(WARM_RESET_L, PIN(F, 4), GPIO_ODR_HIGH | GPIO_SEL_1P8V) /* AP warm reset */
GPIO(PMIC_KPD_PWR_ODL, PIN(D, 6), GPIO_ODR_HIGH | GPIO_SEL_1P8V) /* PMIC power button */
GPIO(EC_INT_L, PIN(A, 2), GPIO_ODR_HIGH | GPIO_SEL_1P8V) /* Interrupt line between AP and EC */
GPIO(AP_SUSPEND_L, PIN(5, 7), GPIO_INPUT | GPIO_SEL_1P8V) /* Suspend signal from AP */
diff --git a/include/chipset.h b/include/chipset.h
index b4b630f032..7363707b38 100644
--- a/include/chipset.h
+++ b/include/chipset.h
@@ -185,8 +185,8 @@ static inline void power_interrupt(enum gpio_signal signal) { }
static inline void chipset_handle_espi_reset_assert(void) { }
static inline void chipset_handle_reboot(void) { }
static inline void chipset_reset_request_interrupt(enum gpio_signal signal) { }
+static inline void chipset_warm_reset_interrupt(enum gpio_signal signal) { }
static inline void chipset_watchdog_interrupt(enum gpio_signal signal) { }
-static inline void chipset_power_signal_interrupt(enum gpio_signal signal) { }
#endif /* !HAS_TASK_CHIPSET */
@@ -210,6 +210,13 @@ void chipset_handle_reboot(void);
void chipset_reset_request_interrupt(enum gpio_signal signal);
/**
+ * GPIO interrupt handler of warm reset signal from servo or H1.
+ *
+ * It is used in SDM845 chipset power sequence.
+ */
+void chipset_warm_reset_interrupt(enum gpio_signal signal);
+
+/**
* GPIO interrupt handler of watchdog from AP.
*
* It is used in MT8183 chipset, where it must be setup to trigger on falling
diff --git a/power/sdm845.c b/power/sdm845.c
index 6c5f033b44..36e041f96d 100644
--- a/power/sdm845.c
+++ b/power/sdm845.c
@@ -89,6 +89,9 @@ static char power_button_was_pressed;
/* 1 if lid-open event has been detected */
static char lid_opened;
+/* 1 if AP_RST_L and PS_HOLD is overdriven by EC */
+static char ap_rst_overdriven;
+
/*
* 1 if power state is controlled by special functions, like a console command
* or an interrupt handler, for bypassing POWER_GOOD lost trigger. It is
@@ -153,6 +156,64 @@ void chipset_reset_request_interrupt(enum gpio_signal signal)
hook_call_deferred(&chipset_reset_request_handler_data, 0);
}
+void chipset_warm_reset_interrupt(enum gpio_signal signal)
+{
+ /*
+ * The warm_reset signal is pulled-up by a rail from PMIC. If the
+ * warm_reset drops, it means:
+ * * Servo or Cr50 holds the signal, or
+ * * its pull-up rail POWER_GOOD drops.
+ */
+ if (!gpio_get_level(GPIO_WARM_RESET_L)) {
+ if (gpio_get_level(GPIO_POWER_GOOD)) {
+ /*
+ * Servo or Cr50 holds the WARM_RESET_L signal.
+ *
+ * Overdrive AP_RST_L to hold AP. Overdrive PS_HOLD to
+ * emulate AP being up to trick the PMIC into thinking
+ * there’s nothing weird going on.
+ */
+ ap_rst_overdriven = 1;
+ gpio_set_flags(GPIO_PS_HOLD, GPIO_INT_BOTH |
+ GPIO_SEL_1P8V | GPIO_OUT_HIGH);
+ gpio_set_flags(GPIO_AP_RST_L, GPIO_INT_BOTH |
+ GPIO_SEL_1P8V | GPIO_OUT_LOW);
+ } else {
+ /*
+ * The pull-up rail POWER_GOOD drops.
+ *
+ * High-Z both AP_RST_L and PS_HOLD to restore their
+ * states.
+ */
+ gpio_set_flags(GPIO_AP_RST_L, GPIO_INT_BOTH |
+ GPIO_SEL_1P8V);
+ gpio_set_flags(GPIO_PS_HOLD, GPIO_INT_BOTH |
+ GPIO_SEL_1P8V);
+ ap_rst_overdriven = 0;
+ }
+ } else {
+ if (ap_rst_overdriven) {
+ /*
+ * Servo or Cr50 releases the WARM_RESET_L signal.
+ *
+ * High-Z both AP_RST_L and PS_HOLD to restore their
+ * state. Cold reset the PMIC, doing S0->S5->S0
+ * transition, to recover the system.
+ */
+ gpio_set_flags(GPIO_AP_RST_L, GPIO_INT_BOTH |
+ GPIO_SEL_1P8V);
+ gpio_set_flags(GPIO_PS_HOLD, GPIO_INT_BOTH |
+ GPIO_SEL_1P8V);
+ ap_rst_overdriven = 0;
+
+ /* TODO(b/112723105): Do S0->S5->S0 transition here. */
+ }
+ /* If not overdriven, just a normal power-up, do nothing. */
+ }
+
+ power_signal_interrupt(signal);
+}
+
static void sdm845_lid_event(void)
{
/* Power task only cares about lid-open events */
@@ -328,8 +389,10 @@ enum power_state power_chipset_init(void)
int init_power_state;
uint32_t reset_flags = system_get_reset_flags();
- /* Enable reboot control input from AP */
+ /* Enable interrupts */
gpio_enable_interrupt(GPIO_AP_RST_REQ);
+ gpio_enable_interrupt(GPIO_WARM_RESET_L);
+ gpio_enable_interrupt(GPIO_POWER_GOOD);
/*
* Force the AP shutdown unless we are doing SYSJUMP. Otherwise,