summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandru M Stan <amstan@chromium.org>2014-08-26 15:51:01 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-09-04 15:50:13 +0000
commit27a2fdf6651c2f2096c1555afcc8cba982be5f08 (patch)
treef7e09233ceb9115e7ae03e2b2844d2d2af757280
parent41fdea92b53b6e186046dd1c1db3ff83b780504a (diff)
downloadchrome-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.inc4
-rw-r--r--power/rockchip.c97
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);
}
}