From 90d83d2a6743a48d7ec8209781c4e820e8bdf296 Mon Sep 17 00:00:00 2001 From: Louis Yung-Chieh Lo Date: Thu, 21 Nov 2013 16:35:12 -0800 Subject: nyan: force shutdown uses PMIC THERM instead. Add a new pin PMIC_THERM_L (PA1) since AP_RESET_L (PA15) is removed. To force shutdown, drive PMIC_THERM_L to low (default high) for 32us. Also rename set_pmic_pwrok() -> set_pmic_pwron(). And add a debounce time for PMIC_PWRON_L pin. BUG=chrome-os-partner:24206 BRANCH=nyan TEST=Verified on the frank's rework board. 'power off' shutdowns the AP immediately. 'reboot' reboots the EC and resets the AP as well. 'sysjump RW' still keeps AP alive. Change-Id: I8643e19081a824e1f6adc812dfad0269222db8ea Signed-off-by: Louis Yung-Chieh Lo Reviewed-on: https://chromium-review.googlesource.com/178631 --- board/nyan/board.c | 1 + board/nyan/board.h | 1 + power/tegra.c | 67 ++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/board/nyan/board.c b/board/nyan/board.c index ef30a130d5..29c35045fc 100644 --- a/board/nyan/board.c +++ b/board/nyan/board.c @@ -82,6 +82,7 @@ const struct gpio_info gpio_list[] = { {"BAT_LED1", GPIO_A, (1<<8), GPIO_OUT_LOW, NULL}, {"CHARGING", GPIO_A, (1<<11), GPIO_OUT_LOW, NULL}, {"EC_BL_OVERRIDE", GPIO_H, (1<<1), GPIO_ODR_HIGH, NULL}, + {"PMIC_THERM_L", GPIO_A, (1<<1), GPIO_ODR_HIGH, NULL}, }; BUILD_ASSERT(ARRAY_SIZE(gpio_list) == GPIO_COUNT); diff --git a/board/nyan/board.h b/board/nyan/board.h index 1b1c5aed48..57483b20d0 100644 --- a/board/nyan/board.h +++ b/board/nyan/board.h @@ -86,6 +86,7 @@ enum gpio_signal { GPIO_BAT_LED1, GPIO_CHARGING, GPIO_EC_BL_OVERRIDE, + GPIO_PMIC_THERM_L, /* Number of GPIOs; not an actual GPIO */ GPIO_COUNT }; diff --git a/power/tegra.c b/power/tegra.c index 99c350c658..9b44d39f56 100644 --- a/power/tegra.c +++ b/power/tegra.c @@ -45,6 +45,19 @@ /* Long power key press to force shutdown */ #define DELAY_FORCE_SHUTDOWN (10200 * MSEC) /* 10.2 seconds */ +/* + * The minimum time to assert the PMIC PWRON pin is 20ms. + * Give it longer to ensure the PMIC doesn't lose it. + */ +#define PMIC_PWRON_DEBOUNCE_TIME (20 * MSEC * 3) + +/* + * The minimum time to assert the PMIC THERM pin is 32us. However, + * it needs to be extended to about 50ms to let the 5V rail + * dissipate fully. + */ +#define PMIC_THERM_HOLD_TIME (50 * MSEC) + /* * If the power key is pressed to turn on, then held for this long, we * power off. @@ -132,27 +145,29 @@ static int wait_in_signal(enum gpio_signal signal, int value, int timeout) } /** - * Set the PMIC PWROK signal. + * Set the PMIC PWRON signal. + * + * Note that asserting requires holding for PMIC_PWRON_DEBOUNCE_TIME. * * @param asserted Assert (=1) or deassert (=0) the signal. This is the * logical level of the pin, not the physical level. */ -static void set_pmic_pwrok(int asserted) +static void set_pmic_pwron(int asserted) { /* Signal is active-low */ gpio_set_level(GPIO_PMIC_PWRON_L, asserted ? 0 : 1); } /** - * Set the AP RESET signal. + * Set the PMIC THERM to force shutdown the AP. * * @param asserted Assert (=1) or deassert (=0) the signal. This is the * logical level of the pin, not the physical level. */ -static void set_ap_reset(int asserted) +static void set_pmic_therm(int asserted) { /* Signal is active-low */ - gpio_set_level(GPIO_AP_RESET_L, asserted ? 0 : 1); + gpio_set_level(GPIO_PMIC_THERM_L, asserted ? 0 : 1); } /** @@ -188,7 +203,8 @@ static int check_for_power_off_event(void) now = get_time(); if (pressed) { - set_pmic_pwrok(1); + set_pmic_pwron(1); + usleep(PMIC_PWRON_DEBOUNCE_TIME); if (!power_button_was_pressed) { power_off_deadline.val = now.val + DELAY_FORCE_SHUTDOWN; @@ -202,7 +218,7 @@ static int check_for_power_off_event(void) } } else if (power_button_was_pressed) { CPRINTF("[%T power off cancel]\n"); - set_pmic_pwrok(0); + set_pmic_pwron(0); } power_button_was_pressed = pressed; @@ -283,6 +299,15 @@ static int tegra_power_init(void) gpio_enable_interrupt(GPIO_SOC1V8_XPSHOLD); gpio_enable_interrupt(GPIO_SUSPEND_L); + /* + * Force the AP shutdown unless we are doing SYSJUMP. Otherwise, + * the AP could stay in strange state. + */ + if (!(system_get_reset_flags() & RESET_FLAG_SYSJUMP)) { + CPRINTF("[%T not sysjump; forcing AP shutdown]\n"); + chipset_force_shutdown(); + } + /* Leave power off only if requested by reset flags */ if (!(system_get_reset_flags() & RESET_FLAG_AP_OFF)) { CPRINTF("[%T auto_power_on is set due to reset_flag 0x%x]\n", @@ -341,11 +366,13 @@ void chipset_reset(int is_cold) void chipset_force_shutdown(void) { - /* Assert AP reset to shutdown immediately */ - set_ap_reset(1); - /* Release the power button, if it was asserted */ - set_pmic_pwrok(0); + set_pmic_pwron(0); + + /* Assert AP reset to shutdown immediately */ + set_pmic_therm(1); + udelay(PMIC_THERM_HOLD_TIME); + set_pmic_therm(0); } /*****************************************************************************/ @@ -360,13 +387,8 @@ void chipset_force_shutdown(void) */ static int check_for_power_on_event(void) { - /* - * check if system is already ON: - * 1. XPSHOLD is high (power is supplied), and - * 2. AP_RESET_L is high (not a force shutdown). - */ - if (gpio_get_level(GPIO_SOC1V8_XPSHOLD) && - gpio_get_level(GPIO_AP_RESET_L)) { + /* check if system is already ON */ + if (gpio_get_level(GPIO_SOC1V8_XPSHOLD)) { CPRINTF("[%T system is on, thus clear auto_power_on]\n"); auto_power_on = 0; /* no need to arrange another power on */ return 1; @@ -406,11 +428,12 @@ static int check_for_power_on_event(void) */ static int power_on(void) { - /* Make sure we de-assert the AP_RESET_L pin. */ - set_ap_reset(0); + /* Make sure we de-assert the PMI_THERM_L pin. */ + set_pmic_therm(0); /* Push the power button */ - set_pmic_pwrok(1); + set_pmic_pwron(1); + usleep(PMIC_PWRON_DEBOUNCE_TIME); /* Initialize non-AP components if the AP is off. */ if (!ap_on) @@ -553,7 +576,7 @@ void chipset_task(void) DELAY_SHUTDOWN_ON_POWER_HOLD)) continue_power = 1; } - set_pmic_pwrok(0); + set_pmic_pwron(0); if (continue_power) { power_button_was_pressed = 0; while (!(value = check_for_power_off_event())) -- cgit v1.2.1