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>
This commit is contained in:
parent
b4fa3fd2ae
commit
b365530bb6
|
@ -17,6 +17,7 @@
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <arch/exception.h>
|
#include <arch/exception.h>
|
||||||
#include <bootblock_common.h>
|
#include <bootblock_common.h>
|
||||||
#include <cbfs.h>
|
#include <cbfs.h>
|
||||||
|
@ -69,16 +70,16 @@ void main(void)
|
||||||
PINMUX_PWR_INT_N_FUNC_PMICINTR |
|
PINMUX_PWR_INT_N_FUNC_PMICINTR |
|
||||||
PINMUX_INPUT_ENABLE);
|
PINMUX_INPUT_ENABLE);
|
||||||
|
|
||||||
power_enable_cpu_rail();
|
|
||||||
power_ungate_cpu();
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_VBOOT2_VERIFY_FIRMWARE))
|
if (IS_ENABLED(CONFIG_VBOOT2_VERIFY_FIRMWARE))
|
||||||
entry = (void *)verstage_vboot_main;
|
entry = (void *)verstage_vboot_main;
|
||||||
else
|
else
|
||||||
entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, "fallback/romstage");
|
entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, "fallback/romstage");
|
||||||
|
|
||||||
if (entry)
|
ASSERT(entry);
|
||||||
clock_cpu0_config_and_reset(entry);
|
clock_cpu0_config(entry);
|
||||||
|
|
||||||
|
power_enable_and_ungate_cpu();
|
||||||
|
clock_cpu0_remove_reset();
|
||||||
|
|
||||||
clock_halt_avp();
|
clock_halt_avp();
|
||||||
}
|
}
|
||||||
|
|
|
@ -480,7 +480,7 @@ void clock_sdram(u32 m, u32 n, u32 p, u32 setup, u32 ph45, u32 ph90,
|
||||||
udelay(IO_STABILIZATION_DELAY);
|
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;
|
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_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_CPUG);
|
||||||
setbits_le32(&clk_rst->clk_out_enb_v, CLK_V_CPULP);
|
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.
|
// Disable the reset on the non-CPU parts of the fast cluster.
|
||||||
write32(CRC_RST_CPUG_CLR_NONCPU,
|
write32(CRC_RST_CPUG_CLR_NONCPU,
|
||||||
&clk_rst->rst_cpug_cmplx_clr);
|
&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
|
/* Typical ratios are 1:2:2 or 1:2:3 sclk:hclk:pclk (See: APB DMA
|
||||||
* features section in the TRM). */
|
* features section in the TRM). */
|
||||||
write32(1 << HCLK_DIVISOR_SHIFT | 0 << PCLK_DIVISOR_SHIFT,
|
write32(TEGRA_HCLK_RATIO << HCLK_DIVISOR_SHIFT |
|
||||||
&clk_rst->clk_sys_rate); /* pclk = hclk = sclk/2 */
|
TEGRA_PCLK_RATIO << PCLK_DIVISOR_SHIFT,
|
||||||
write32(CLK_DIVIDER(TEGRA_PLLC_KHZ, 300000) << PLL_OUT_RATIO_SHIFT |
|
&clk_rst->clk_sys_rate);
|
||||||
PLL_OUT_CLKEN | PLL_OUT_RSTN, &clk_rst->pllc_out);
|
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 |
|
write32(SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT |
|
||||||
SCLK_SOURCE_PLLC_OUT1 << SCLK_RUN_SHIFT,
|
SCLK_SOURCE_PLLC_OUT1 << SCLK_RUN_SHIFT,
|
||||||
&clk_rst->sclk_brst_pol); /* sclk = 300 MHz */
|
&clk_rst->sclk_brst_pol); /* sclk = 300 MHz */
|
||||||
|
|
|
@ -277,6 +277,12 @@ enum clock_source { /* Careful: Not true for all sources, always check TRM! */
|
||||||
#define TEGRA_PLLD_KHZ (925000)
|
#define TEGRA_PLLD_KHZ (925000)
|
||||||
#define TEGRA_PLLU_KHZ (960000)
|
#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_osc_khz(void);
|
||||||
int clock_get_pll_input_khz(void);
|
int clock_get_pll_input_khz(void);
|
||||||
u32 clock_display(u32 frequency);
|
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,
|
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 ph135, u32 kvco, u32 kcp, u32 stable_time, u32 emc_source,
|
||||||
u32 same_freq);
|
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_halt_avp(void);
|
||||||
void clock_enable_clear_reset(u32 l, u32 h, u32 u, u32 v, u32 w, u32 x);
|
void clock_enable_clear_reset(u32 l, u32 h, u32 u, u32 v, u32 w, u32 x);
|
||||||
void clock_reset_l(u32 l);
|
void clock_reset_l(u32 l);
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <soc/addressmap.h>
|
#include <soc/addressmap.h>
|
||||||
|
#include <soc/clock.h>
|
||||||
|
|
||||||
#include "pmc.h"
|
#include "pmc.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
|
@ -32,6 +33,11 @@ static int partition_powered(int id)
|
||||||
return read32(&pmc->pwrgate_status) & (0x1 << 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)
|
static void power_ungate_partition(uint32_t id)
|
||||||
{
|
{
|
||||||
printk(BIOS_INFO, "Ungating power partition %d.\n", 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.
|
// Wait for the partition to be powered.
|
||||||
while (!partition_powered(id))
|
while (!partition_powered(id))
|
||||||
;
|
;
|
||||||
|
|
||||||
|
// Wait for clamp off.
|
||||||
|
while (partition_clamp_on(id))
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(BIOS_INFO, "Ungated power partition %d.\n", 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 (150MHz),
|
||||||
* Set CPUPWRGOOD_TIMER - APB clock is 1/2 of SCLK (102MHz),
|
* set it for 5ms as per SysEng (5ms * PCLK_KHZ * 1000 / 1s).
|
||||||
* set it for 5ms as per SysEng (102MHz/5mS = 510000).
|
|
||||||
*/
|
*/
|
||||||
write32(510000, &pmc->cpupwrgood_timer);
|
write32((TEGRA_PCLK_KHZ * 5), &pmc->cpupwrgood_timer);
|
||||||
|
|
||||||
power_ungate_partition(POWER_PARTID_CRAIL);
|
|
||||||
|
|
||||||
uint32_t cntrl = read32(&pmc->cntrl);
|
uint32_t cntrl = read32(&pmc->cntrl);
|
||||||
cntrl &= ~PMC_CNTRL_CPUPWRREQ_POLARITY;
|
cntrl &= ~PMC_CNTRL_CPUPWRREQ_POLARITY;
|
||||||
cntrl |= PMC_CNTRL_CPUPWRREQ_OE;
|
cntrl |= PMC_CNTRL_CPUPWRREQ_OE;
|
||||||
write32(cntrl, &pmc->cntrl);
|
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.
|
// Ungate power to the non-core parts of the fast cluster.
|
||||||
power_ungate_partition(POWER_PARTID_C0NC);
|
power_ungate_partition(POWER_PARTID_C0NC);
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,7 @@
|
||||||
|
|
||||||
// This function does not enable the external power to the rail, it enables
|
// This function does not enable the external power to the rail, it enables
|
||||||
// the rail itself internal to the SOC.
|
// the rail itself internal to the SOC.
|
||||||
void power_enable_cpu_rail(void);
|
void power_enable_and_ungate_cpu(void);
|
||||||
|
|
||||||
void power_ungate_cpu(void);
|
|
||||||
|
|
||||||
// power_reset_status returns one of the following possible sources for the
|
// power_reset_status returns one of the following possible sources for the
|
||||||
// most recent reset.
|
// most recent reset.
|
||||||
|
|
Loading…
Reference in New Issue