diff options
author | Jimmy Zhang <jimmzhang@nvidia.com> | 2014-07-02 17:45:18 -0700 |
---|---|---|
committer | Marc Jones <marc.jones@se-eng.com> | 2015-02-17 01:16:34 +0100 |
commit | b365530bb6341cad601532e43fc899f56ba57acb (patch) | |
tree | 4d936234624b6cbe9921c534823ea5469f4386d8 /src | |
parent | b4fa3fd2aedc2d02c973c664a218e5551b4118a1 (diff) | |
download | coreboot-b365530bb6341cad601532e43fc899f56ba57acb.tar.xz |
tegra124: Correct cpu power on sequence and CPUPWRGOOD_TIME
Based on TRM, cpu clock enabling and reset vector setting should
all be done properly before ungating cpu power partition. Otherwise,
with current code, a race condition could occur where cpu starts but
reset vector has not been set.
BUG=chrome-os-partner:30064
BRANCH=none
TEST=run nyan_big reboot test. No issue is experienced.
Original-Signed-off-by: Jimmy Zhang <jimmzhang@nvidia.com>
Original-Change-Id: I571e128693bb2763ee673bd183b8cf60921dc475
Original-Reviewed-on: https://chromium-review.googlesource.com/206682
Original-Tested-by: Jimmy Zhang <jimmzhang@nvidia.com>
Original-Reviewed-by: Julius Werner <jwerner@chromium.org>
Original-Commit-Queue: Jimmy Zhang <jimmzhang@nvidia.com>
(cherry picked from commit 106480ff32406c899a24544fdfab858db5afd1d9)
Signed-off-by: Marc Jones <marc.jones@se-eng.com>
Change-Id: I3da6018dd68e4c15d2c58db566a9745b0b26c365
Reviewed-on: http://review.coreboot.org/8414
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/soc/nvidia/tegra124/bootblock.c | 11 | ||||
-rw-r--r-- | src/soc/nvidia/tegra124/clock.c | 15 | ||||
-rw-r--r-- | src/soc/nvidia/tegra124/include/soc/clock.h | 9 | ||||
-rw-r--r-- | src/soc/nvidia/tegra124/power.c | 30 | ||||
-rw-r--r-- | src/soc/nvidia/tegra124/power.h | 4 |
5 files changed, 41 insertions, 28 deletions
diff --git a/src/soc/nvidia/tegra124/bootblock.c b/src/soc/nvidia/tegra124/bootblock.c index 5f1e850a81..59001491ff 100644 --- a/src/soc/nvidia/tegra124/bootblock.c +++ b/src/soc/nvidia/tegra124/bootblock.c @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <assert.h> #include <arch/exception.h> #include <bootblock_common.h> #include <cbfs.h> @@ -69,16 +70,16 @@ void main(void) PINMUX_PWR_INT_N_FUNC_PMICINTR | PINMUX_INPUT_ENABLE); - power_enable_cpu_rail(); - power_ungate_cpu(); - if (IS_ENABLED(CONFIG_VBOOT2_VERIFY_FIRMWARE)) entry = (void *)verstage_vboot_main; else entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, "fallback/romstage"); - if (entry) - clock_cpu0_config_and_reset(entry); + ASSERT(entry); + clock_cpu0_config(entry); + + power_enable_and_ungate_cpu(); + clock_cpu0_remove_reset(); clock_halt_avp(); } diff --git a/src/soc/nvidia/tegra124/clock.c b/src/soc/nvidia/tegra124/clock.c index af2f96a5db..e3c0e71a7e 100644 --- a/src/soc/nvidia/tegra124/clock.c +++ b/src/soc/nvidia/tegra124/clock.c @@ -480,7 +480,7 @@ void clock_sdram(u32 m, u32 n, u32 p, u32 setup, u32 ph45, u32 ph90, udelay(IO_STABILIZATION_DELAY); } -void clock_cpu0_config_and_reset(void *entry) +void clock_cpu0_config(void *entry) { void * const evp_cpu_reset = (uint8_t *)TEGRA_EVP_BASE + 0x100; @@ -511,7 +511,10 @@ void clock_cpu0_config_and_reset(void *entry) setbits_le32(&clk_rst->clk_out_enb_l, CLK_L_CPU); setbits_le32(&clk_rst->clk_out_enb_v, CLK_V_CPUG); setbits_le32(&clk_rst->clk_out_enb_v, CLK_V_CPULP); +} +void clock_cpu0_remove_reset(void) +{ // Disable the reset on the non-CPU parts of the fast cluster. write32(CRC_RST_CPUG_CLR_NONCPU, &clk_rst->rst_cpug_cmplx_clr); @@ -559,10 +562,12 @@ void clock_init(void) /* Typical ratios are 1:2:2 or 1:2:3 sclk:hclk:pclk (See: APB DMA * features section in the TRM). */ - write32(1 << HCLK_DIVISOR_SHIFT | 0 << PCLK_DIVISOR_SHIFT, - &clk_rst->clk_sys_rate); /* pclk = hclk = sclk/2 */ - write32(CLK_DIVIDER(TEGRA_PLLC_KHZ, 300000) << PLL_OUT_RATIO_SHIFT | - PLL_OUT_CLKEN | PLL_OUT_RSTN, &clk_rst->pllc_out); + write32(TEGRA_HCLK_RATIO << HCLK_DIVISOR_SHIFT | + TEGRA_PCLK_RATIO << PCLK_DIVISOR_SHIFT, + &clk_rst->clk_sys_rate); + write32(CLK_DIVIDER(TEGRA_PLLC_KHZ, TEGRA_SCLK_KHZ) << + PLL_OUT_RATIO_SHIFT | PLL_OUT_CLKEN | + PLL_OUT_RSTN, &clk_rst->pllc_out); write32(SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT | SCLK_SOURCE_PLLC_OUT1 << SCLK_RUN_SHIFT, &clk_rst->sclk_brst_pol); /* sclk = 300 MHz */ diff --git a/src/soc/nvidia/tegra124/include/soc/clock.h b/src/soc/nvidia/tegra124/include/soc/clock.h index ffe9a4eedb..82b2ad8100 100644 --- a/src/soc/nvidia/tegra124/include/soc/clock.h +++ b/src/soc/nvidia/tegra124/include/soc/clock.h @@ -277,6 +277,12 @@ enum clock_source { /* Careful: Not true for all sources, always check TRM! */ #define TEGRA_PLLD_KHZ (925000) #define TEGRA_PLLU_KHZ (960000) +#define TEGRA_SCLK_KHZ (300000) +#define TEGRA_HCLK_RATIO 1 +#define TEGRA_HCLK_KHZ (TEGRA_SCLK_KHZ / (1 + TEGRA_HCLK_RATIO)) +#define TEGRA_PCLK_RATIO 0 +#define TEGRA_PCLK_KHZ (TEGRA_HCLK_KHZ / (1 + TEGRA_PCLK_RATIO)) + int clock_get_osc_khz(void); int clock_get_pll_input_khz(void); u32 clock_display(u32 frequency); @@ -285,7 +291,8 @@ void clock_external_output(int clk_id); void clock_sdram(u32 m, u32 n, u32 p, u32 setup, u32 ph45, u32 ph90, u32 ph135, u32 kvco, u32 kcp, u32 stable_time, u32 emc_source, u32 same_freq); -void clock_cpu0_config_and_reset(void * entry); +void clock_cpu0_config(void * entry); +void clock_cpu0_remove_reset(void); void clock_halt_avp(void); void clock_enable_clear_reset(u32 l, u32 h, u32 u, u32 v, u32 w, u32 x); void clock_reset_l(u32 l); diff --git a/src/soc/nvidia/tegra124/power.c b/src/soc/nvidia/tegra124/power.c index 760d058712..ec44a0fb02 100644 --- a/src/soc/nvidia/tegra124/power.c +++ b/src/soc/nvidia/tegra124/power.c @@ -21,6 +21,7 @@ #include <arch/io.h> #include <console/console.h> #include <soc/addressmap.h> +#include <soc/clock.h> #include "pmc.h" #include "power.h" @@ -32,6 +33,11 @@ static int partition_powered(int id) return read32(&pmc->pwrgate_status) & (0x1 << id); } +static int partition_clamp_on(int id) +{ + return read32(&pmc->clamp_status) & (0x1 << id); +} + static void power_ungate_partition(uint32_t id) { printk(BIOS_INFO, "Ungating power partition %d.\n", id); @@ -51,34 +57,30 @@ static void power_ungate_partition(uint32_t id) // Wait for the partition to be powered. while (!partition_powered(id)) ; + + // Wait for clamp off. + while (partition_clamp_on(id)) + ; } printk(BIOS_INFO, "Ungated power partition %d.\n", id); } -void power_enable_cpu_rail(void) +void power_enable_and_ungate_cpu(void) { - // Set the power gate timer multiplier to 8 (why 8?). - uint32_t pwrgate_timer_mult = read32(&pmc->pwrgate_timer_mult); - pwrgate_timer_mult |= (0x3 << 0); - /* - * From U-Boot: - * Set CPUPWRGOOD_TIMER - APB clock is 1/2 of SCLK (102MHz), - * set it for 5ms as per SysEng (102MHz/5mS = 510000). + * Set CPUPWRGOOD_TIMER - APB clock is 1/2 of SCLK (150MHz), + * set it for 5ms as per SysEng (5ms * PCLK_KHZ * 1000 / 1s). */ - write32(510000, &pmc->cpupwrgood_timer); - - power_ungate_partition(POWER_PARTID_CRAIL); + write32((TEGRA_PCLK_KHZ * 5), &pmc->cpupwrgood_timer); uint32_t cntrl = read32(&pmc->cntrl); cntrl &= ~PMC_CNTRL_CPUPWRREQ_POLARITY; cntrl |= PMC_CNTRL_CPUPWRREQ_OE; write32(cntrl, &pmc->cntrl); -} -void power_ungate_cpu(void) -{ + power_ungate_partition(POWER_PARTID_CRAIL); + // Ungate power to the non-core parts of the fast cluster. power_ungate_partition(POWER_PARTID_C0NC); diff --git a/src/soc/nvidia/tegra124/power.h b/src/soc/nvidia/tegra124/power.h index 130ed2525a..bce6faf9ec 100644 --- a/src/soc/nvidia/tegra124/power.h +++ b/src/soc/nvidia/tegra124/power.h @@ -22,9 +22,7 @@ // This function does not enable the external power to the rail, it enables // the rail itself internal to the SOC. -void power_enable_cpu_rail(void); - -void power_ungate_cpu(void); +void power_enable_and_ungate_cpu(void); // power_reset_status returns one of the following possible sources for the // most recent reset. |