diff options
author | Alexandru M Stan <amstan@chromium.org> | 2014-08-26 15:51:01 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-09-04 15:50:13 +0000 |
commit | 27a2fdf6651c2f2096c1555afcc8cba982be5f08 (patch) | |
tree | f7e09233ceb9115e7ae03e2b2844d2d2af757280 | |
parent | 41fdea92b53b6e186046dd1c1db3ff83b780504a (diff) | |
download | chrome-ec-27a2fdf6651c2f2096c1555afcc8cba982be5f08.tar.gz |
Veyron: Reset the PMIC properly at power on
There was a way to brick the PMIC by programming its registers with a bad
configuration, this could prevent the AP from powering up properly (thus not
being able to unbrick it). The PMIC retains register state through S5 (presumably
due to RTC business) and they do not get reset at bootup unless the OTP reset is
asserted.
The OTP reset actually has to be asserted in a special(rather long as well)
sequence.
A bug was discovered while making this change(crosbug.com/p/31635): usleep does
not work for long delays. Since I needed at least 300ms on one of the delays I
used a workaround with a loop.
I also cleaned up some old tegra stuff and renamed things to be more semantic.
BUG=None
BRANCH=None
TEST=From the AP set a PMIC register from the default value of 0x7d to 0xfd:
user@ap~$ modprobe i2c-dev
user@ap~$ i2cget -f -y 0 0x1b 0x24
Check what the default state is, mine was 0x7d
user@ap~$ i2cset -f -y 0 0x1b 0x24 0xfd #or change 0xfd to something!=default
Cold reboot the dut("apreset" or "power on\npower off" will work) then check if
the PMIC registers got reset:
user@ap~$ modprobe i2c-dev
user@ap~$ i2cget -f -y 0 0x1b 0x24
0x7d(or whatever your default state was) #good
0xfd #bad, did not reset properly
Using "user@ap~$ i2cset -f -y 0 0x1b 0x24 0x00" instead will prove the bricking
of the PMIC/AP.
Change-Id: Iad96781ffde085befe6dea20edd255ca3e7e1357
Signed-off-by: Alexandru M Stan <amstan@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/214360
Reviewed-by: Doug Anderson <dianders@chromium.org>
-rw-r--r-- | board/veyron/gpio.inc | 4 | ||||
-rw-r--r-- | power/rockchip.c | 97 |
2 files changed, 64 insertions, 37 deletions
diff --git a/board/veyron/gpio.inc b/board/veyron/gpio.inc index 86dc7b7060..ec464bc9b7 100644 --- a/board/veyron/gpio.inc +++ b/board/veyron/gpio.inc @@ -27,7 +27,6 @@ GPIO(KB_IN07, D, 2, GPIO_KB_INPUT, keyboard_raw_gpio_interrupt) GPIO(WP_L, B, 4, GPIO_INPUT, NULL) /* Outputs */ -GPIO(AP_RESET, B, 3, GPIO_OUT_HIGH, NULL) GPIO(BAT_LED0, B, 11, GPIO_OUT_LOW, NULL) GPIO(BAT_LED1, A, 11, GPIO_OUT_LOW, NULL) GPIO(EC_BL_OVERRIDE, F, 1, GPIO_OUT_LOW, NULL) @@ -48,7 +47,8 @@ GPIO(KB_OUT09, B, 1, GPIO_KB_OUTPUT, NULL) GPIO(KB_OUT10, C, 5, GPIO_KB_OUTPUT, NULL) GPIO(KB_OUT11, C, 4, GPIO_KB_OUTPUT, NULL) GPIO(KB_OUT12, A, 13, GPIO_KB_OUTPUT, NULL) -GPIO(PMIC_PWREN, A, 12, GPIO_OUT_HIGH, NULL) +GPIO(PMIC_PWREN, A, 12, GPIO_OUT_LOW, NULL) +GPIO(PMIC_RESET, B, 3, GPIO_OUT_LOW, NULL) GPIO(PMIC_SOURCE_PWREN, B, 10, GPIO_OUT_LOW, NULL) GPIO(PMIC_WARM_RESET_L, C, 3, GPIO_ODR_HIGH, NULL) diff --git a/power/rockchip.c b/power/rockchip.c index a3a5492a66..24257730b3 100644 --- a/power/rockchip.c +++ b/power/rockchip.c @@ -69,10 +69,25 @@ #define PMIC_WARM_RESET_L_HOLD_TIME (4 * MSEC) /* - * The first time the PMIC sees power (AC or battery) it needs 200ms (+/-12% - * oscillator tolerance) for the RTC startup. In addition there is a startup - * time of approx. 0.5msec until V2_5 regulator starts up. */ -#define PMIC_RTC_STARTUP (225 * MSEC) + * Startup time for the PMIC source regulator. + */ +#define PMIC_SOURCE_STARTUP_TIME (50 * MSEC) + +/* + * Time before PMIC can be reset. + */ +#define PMIC_STARTUP_MS 300 + +/* + * Hold time fo the RK808 PMIC reset. + */ +#define PMIC_RESET_HOLD_TIME (50 * MSEC) + +/* + * Time until AP is ready to talk SPI, before then there's SPI garbage + */ +#define PMIC_SPI_READY_TIME (100 * MSEC) + /* TODO(crosbug.com/p/25047): move to HOOK_POWER_BUTTON_CHANGE */ /* 1 if the power button was pressed last time we checked */ @@ -103,14 +118,26 @@ static void chipset_turn_off_power_rails(void); /** - * Set the AP RESET signal. + * Set the PMIC RESET signal. * * @param asserted Resetting (=1) or idle (=0) */ -static void set_ap_reset(int asserted) +static void set_pmic_reset(int asserted) { /* Signal is active-high */ - gpio_set_level(GPIO_AP_RESET, asserted ? 1 : 0); + gpio_set_level(GPIO_PMIC_RESET, asserted ? 1 : 0); +} + + +/** + * Set the PMIC WARM RESET signal. + * + * @param asserted Resetting (=1) or idle (=0) + */ +static void set_pmic_warm_reset(int asserted) +{ + /* Signal is active-low */ + gpio_set_level(GPIO_PMIC_WARM_RESET_L, asserted ? 0 : 1); } @@ -262,8 +289,8 @@ static void chipset_turn_off_power_rails(void) /* Close the pmic power source immediately */ set_pmic_source(0); - /* Hold the reset pin so that the AP stays in off mode (rev <= 2.0) */ - set_ap_reset(1); + /* Keep AP and PMIC in reset the whole time */ + set_pmic_warm_reset(1); } void chipset_force_shutdown(void) @@ -336,44 +363,44 @@ static int check_for_power_on_event(void) */ static void power_on(void) { - uint64_t t; + int i; + + set_pmic_source(1); + usleep(PMIC_SOURCE_STARTUP_TIME); + + set_pmic_pwren(1); + /* + * BUG Workaround(crosbug.com/p/31635): usleep hangs in task when using + * big delays. + */ + for (i = 0; i < PMIC_STARTUP_MS; i++) + usleep(1 * MSEC); + + /* Reset the PMIC to make sure it's in a known state. */ + set_pmic_reset(1); + usleep(PMIC_RESET_HOLD_TIME); + set_pmic_reset(0); + set_pmic_warm_reset(0); + + /* Wait till the AP has SPI ready */ + usleep(PMIC_SPI_READY_TIME); + + gpio_set_flags(GPIO_SPI1_NSS, GPIO_INPUT | GPIO_INT_BOTH + | GPIO_PULL_UP); /* enable interrupt */ gpio_set_flags(GPIO_SUSPEND_L, GPIO_INPUT | GPIO_INT_BOTH | GPIO_PULL_DOWN); gpio_set_flags(GPIO_EC_INT, GPIO_OUTPUT | GPIO_OUT_HIGH); - /* Make sure we de-assert the PMI_SOURCE and AP_RESET_L pin. */ - set_pmic_source(1); - set_ap_reset(0); - - /* - * Before we push PMIC power button, wait for the PMI RTC ready, which - * takes PMIC_RTC_STARTUP from the AC/battery is plugged in. - */ - t = get_time().val; - if (t < PMIC_RTC_STARTUP) { - uint32_t wait = PMIC_RTC_STARTUP - t; - CPRINTS("wait for %dms for PMIC RTC start-up", - wait / MSEC); - usleep(wait); - } /* * When power_on() is called, we are at S5S3. Initialize components * to ready state before AP is up. */ hook_notify(HOOK_CHIPSET_PRE_INIT); - /* Change SPI1_NSS pin to high-Z to reduce power draw, - * until AP running - */ - gpio_set_flags(GPIO_SPI1_NSS, GPIO_INPUT); - set_pmic_pwren(1); - gpio_set_flags(GPIO_SPI1_NSS, GPIO_INPUT | GPIO_INT_BOTH - | GPIO_PULL_UP); disable_sleep(SLEEP_MASK_AP_RUN); - powerled_set_state(POWERLED_STATE_ON); /* Call hooks now that AP is running */ @@ -446,9 +473,9 @@ void chipset_reset(int is_cold) CPRINTS("EC triggered warm reboot"); CPRINTS("assert GPIO_PMIC_WARM_RESET_L for %d ms", PMIC_WARM_RESET_L_HOLD_TIME / MSEC); - gpio_set_level(GPIO_PMIC_WARM_RESET_L, 0); + set_pmic_warm_reset(1); usleep(PMIC_WARM_RESET_L_HOLD_TIME); - gpio_set_level(GPIO_PMIC_WARM_RESET_L, 1); + set_pmic_warm_reset(0); } } |