blob: 02772d42c169349e3287a4b629e047f5e9e83138 [file] [log] [blame]
/*
* (C) Copyright 2010 - 2012
* NVIDIA Corporation <www.nvidia.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch-tegra/clk_rst.h>
#include <asm/arch-tegra/pmc.h>
#include <asm/arch-tegra/flow.h>
#include <asm/arch-tegra/ap20.h>
#include <asm/arch-tegra/power.h>
#include <asm/arch/ahb.h>
#include <asm/arch-tegra/warmboot.h>
#include <asm/arch-tegra/warmboot_avp.h>
#include <asm/arch/clock.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/tegra.h>
#include <asm/arch/sdmmc.h>
#define RESET_CORESIGHT
void wb_start(void)
{
struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
struct sdmmc_ctlr *sdmmc4 = (struct sdmmc_ctlr *)NV_PA_SDMMC4_BASE;
struct clk_rst_ctlr *clkrst =
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
struct ahb_ctlr *ahb = (struct ahb_ctlr *)TEGRA2_AHB_BASE;
struct clk_pll *pllp = &clkrst->crc_pll[CLOCK_ID_PERIPH];
u32 reg, saved_reg;
u32 divm, divn;
u32 cpcon, lfcon;
u32 base, misc;
u32 status_mask, toggle, clamp;
u32 internal_periph_id;
/* enable JTAG & TBE */
writel(CONFIG_CTL_TBE | CONFIG_CTL_JTAG, &pmt->pmt_cfg_ctl);
/* Are we running where we're supposed to be? */
asm volatile (
"adr %0, wb_start;" /* reg: wb_start address */
: "=r"(reg) /* output */
/* no input, no clobber list */
);
if (reg != AP20_WB_RUN_ADDRESS)
goto do_reset;
/* Are we running with AVP? */
if (readl(NV_PA_PG_UP_BASE + PG_UP_TAG_0) != PG_UP_TAG_AVP)
goto do_reset;
/*
* Save the current setting for CLK_BURST_POLICY and change clock
* source to CLKM
*/
saved_reg = readl(&clkrst->crc_sclk_brst_pol);
reg = SCLK_SWAKE_FIQ_SRC_CLKM | SCLK_SWAKE_IRQ_SRC_CLKM |
SCLK_SWAKE_RUN_SRC_CLKM | SCLK_SWAKE_IDLE_SRC_CLKM |
SCLK_SYS_STATE_RUN;
writel(reg, &clkrst->crc_sclk_brst_pol);
/* Update PLLP output dividers for 408 MHz operation */
/* Set OUT1 to 9.6MHz and OUT2 to 48MHz (based on 408MHz of PLLP) */
writel(PLLP_408_OUTA, &pllp->pll_out);
writel(PLLP_408_OUTB, &pllp->pll_out_b);
/* Set oscillator the drive strength */
reg = readl(&clkrst->crc_osc_ctrl);
reg &= ~(OSC_CTRL_XOE | OSC_CTRL_XOFS);
reg |= OSC_CTRL_XOE_ENABLE | OSC_CTRL_XOFS_4;
writel(reg, &clkrst->crc_osc_ctrl);
/* Set CPCON and enable PLLP lock bit */
writel(PLLP_MISC_PLLP_CPCON_8 | PLLP_MISC_PLLP_LOCK_ENABLE,
&pllp->pll_misc);
/* Find out the current osc frequency */
reg = readl(&clkrst->crc_osc_ctrl);
/* Find out the PLLP_BASE value to use */
/*
* Note: can not use switch statement: compiler builds tables on the
* local stack. We don't want to use anything on the stack.
*/
reg >>= OSC_CTRL_OSC_FREQ_SHIFT;
if ((reg == OSC_FREQ_OSC12) || (reg == OSC_FREQ_OSC48)) {
divm = 0x0c;
divn = 0x198;
} else if (reg == OSC_FREQ_OSC16P8) {
divm = 0x0e;
divn = 0x154;
} else if ((reg == OSC_FREQ_OSC19P2) || (reg == OSC_FREQ_OSC38P4)) {
divm = 0x10;
divn = 0x154;
} else if (reg == OSC_FREQ_OSC26) {
divm = 0x1a;
divn = 0x198;
} else {
/*
* Unused code in OSC_FREQ is mapped to 13MHz - use 13MHz as
* default settings.
*/
divm = 0x0d;
divn = 0x198;
}
/* Change PLLP to be 408MHz */
reg = (divm << PLLP_BASE_PLLP_DIVM_SHIFT) |
(divn << PLLP_BASE_PLLP_DIVN_SHIFT) |
PLLP_BASE_OVRRIDE_ENABLE |
PLLP_BASE_PLLP_ENABLE;
writel(reg, &pllp->pll_base);
/* Wait till PLLP locks */
while (1) {
reg = readl(&pllp->pll_base);
if (reg & PLLP_BASE_PLLP_LOCK_LOCK)
break;
}
/*
* Wait for 250uS after lock bit is set to make sure pll is stable.
* The typical wait time is 300uS. Since we already check the lock
* bit, reduce the wait time to 250uS.
*/
reg = EVENT_ZERO_VAL_250 | EVENT_USEC | EVENT_MODE_STOP;
writel(reg, &flow->halt_cop_events);
/* Restore setting for SCLK_BURST_POLICY */
writel(saved_reg, &clkrst->crc_sclk_brst_pol);
/*
* Enable the PPSB_STOPCLK feature to allow SCLK to be run at
* higher frequencies. See bug 811773.
*/
reg = readl(&clkrst->crc_misc_clk_enb);
reg |= MISC_CLK_ENB_EN_PPSB_STOPCLK_ENABLE;
writel(reg, &clkrst->crc_misc_clk_enb);
reg = readl(&ahb->arbitration_xbar_ctrl);
reg |= ARBITRATION_XBAR_CTRL_PPSB_ENABLE_ENABLE;
writel(reg, &ahb->arbitration_xbar_ctrl);
#ifdef RESET_CORESIGHT
/* Assert CoreSight reset */
writel(SWR_CSITE_RST, &clkrst->crc_rst_dev_ex[TEGRA_DEV_U].set);
#endif
/*
* Halt the G complex CPUs at the flow controller in case the G
* complex was running in a uni-processor configuration.
*/
writel(EVENT_MODE_STOP, &flow->halt_cpu_events);
writel(EVENT_MODE_STOP, &flow->halt_cpu1_events);
writel(EVENT_MODE_STOP, &flow->halt_cpu2_events);
writel(EVENT_MODE_STOP, &flow->halt_cpu3_events);
/*
* Find out which CPU (LP or G) to wake up. The default setting
* in flow controller is to wake up GCPU.
*
* Select the LP CPU cluster. All accesses to the cluster-dependent
* CPU registers (legacy clock enables, resets, burst policy, flow
* controller) now refer to the LP CPU.
*/
reg = readl(&pmc->pmc_scratch4);
reg &= CPU_WAKEUP_CLUSTER;
if (reg)
setbits_le32(&flow->cluster_control, ACTIVE_LP);
/* Hold all CPUs in reset. */
reg = CPU_CMPLX_CPURESET0 | CPU_CMPLX_CPURESET1 |
CPU_CMPLX_CPURESET2 | CPU_CMPLX_CPURESET3 |
CPU_CMPLX_DERESET0 | CPU_CMPLX_DERESET1 |
CPU_CMPLX_DERESET2 | CPU_CMPLX_DERESET3 |
CPU_CMPLX_DBGRESET0 | CPU_CMPLX_DBGRESET1 |
CPU_CMPLX_DBGRESET2 | CPU_CMPLX_DBGRESET3;
writel(reg, &clkrst->crc_cpu_cmplx_set);
/* Assert CPU complex reset. */
reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_L]);
reg |= CPU_RST;
writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_L]);
/* Program SUPER_CCLK_DIVIDER */
writel(SUPER_CDIV_ENB, &clkrst->crc_super_cclk_div);
/* Stop the clock to all CPUs. */
reg = SET_CPU0_CLK_STP | SET_CPU1_CLK_STP | SET_CPU2_CLK_STP |
SET_CPU3_CLK_STP;
writel(reg, &clkrst->crc_clk_cpu_cmplx_set);
/* Make sure the resets are held for at least 2 microseconds. */
reg = readl(TIMER_USEC_CNTR);
while ((int)(readl(TIMER_USEC_CNTR) - reg) < 3)
{}
writel(CLK_ENB_CSITE, &clkrst->crc_clk_enb_ex[TEGRA_DEV_U].set);
/* De-assert CoreSight reset */
writel(SWR_CSITE_RST, &clkrst->crc_rst_dev_ex[TEGRA_DEV_U].clr);
/* Unlock debugger access. */
writel(0xC5ACCE55, CSITE_CPU_DBG0_LAR);
/* Find out the current osc frequency */
reg = readl(&clkrst->crc_osc_ctrl);
reg >>= OSC_CTRL_OSC_FREQ_SHIFT;
if ((reg == OSC_FREQ_OSC12) || (reg == OSC_FREQ_OSC48)) {
divm = 0x0c;
divn = 0x3c0;
cpcon = 0x0c;
lfcon = 0x01;
} else if (reg == OSC_FREQ_OSC16P8) {
divm = 0x07;
divn = 0x190;
cpcon = 0x05;
lfcon = 0x00;
} else if ((reg == OSC_FREQ_OSC19P2) || (reg == OSC_FREQ_OSC38P4)) {
divm = 0x04;
divn = 0xc8;
cpcon = 0x03;
lfcon = 0x00;
} else if (reg == OSC_FREQ_OSC26) {
divm = 0x1a;
divn = 0x3c0;
cpcon = 0x0c;
lfcon = 0x01;
} else {
/*
* Unused code in OSC_FREQ is mapped to 13MHz - use 13MHz as
* default settings.
*/
divm = 0x0d;
divn = 0x3c0;
cpcon = 0x0c;
lfcon = 0x01;
}
base = PLLU_BYPASS_ENABLE | (divn << 8) | (divm << 0);
writel(base, &clkrst->crc_pll[CLOCK_ID_USB].pll_base);
misc = (cpcon << 8) | (lfcon << 4);
writel(misc, &clkrst->crc_pll[CLOCK_ID_USB].pll_misc);
base &= ~PLLU_BYPASS_ENABLE;
base |= PLLU_ENABLE;
writel(base, &clkrst->crc_pll[CLOCK_ID_USB].pll_base);
misc |= PLLU_LOCK_ENABLE;
writel(misc, &clkrst->crc_pll[CLOCK_ID_USB].pll_misc);
/*
* Reenable eMMC boot block write protection
* 1. Enable SDMMC4 clock (it's OK to leave it on the default clock
* source, CLK_M, since only one register will be written).
* 2. Take SDMMC4 controller out of reset.
* 3. Set SDMMC4_VENDOR_CLOCK_CNTRL_0_HW_RSTN_OVERRIDE.
* 4. Restore SDMMC4 reset state.
* 5. Stop the clock to SDMMC4 controller.
*/
writel(SET_CLK_ENB_SDMMC4, &clkrst->crc_clk_enb_ex[TEGRA_DEV_L].set);
saved_reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_L]);
reg = CLR_SDMMC4_RST_ENABLE;
writel(reg, &clkrst->crc_rst_dev_ex[TEGRA_DEV_L].clr);
reg = readl(sdmmc4->vendor_clk_cntrl);
reg |= HW_RSTN_OVERRIDE_OVERRIDE;
writel(reg, &sdmmc4->vendor_clk_cntrl);
writel(saved_reg, &clkrst->crc_rst_dev[TEGRA_DEV_L]);
writel(CLR_CLK_ENB_SDMMC4_ENABLE,
&clkrst->crc_clk_enb_ex[TEGRA_DEV_L].clr);
/*
* Set the CPU reset vector. SCRATCH41 contains the physical
* address of the CPU-side restoration code.
*/
reg = readl(&pmc->pmc_scratch41);
writel(reg, EXCEP_VECTOR_CPU_RESET_VECTOR);
/* Select CPU complex clock source */
writel(CCLK_PLLP_BURST_POLICY, &clkrst->crc_cclk_brst_pol);
/* Enable CPU0 clock */
reg = CPU_CMPLX_CLR_CPU0_CLK_STP;
writel(reg, &clkrst->crc_clk_cpu_cmplx_clr);
/* Enable the CPU complex clock */
writel(CLK_ENB_CPU, &clkrst->crc_clk_enb_ex[TEGRA_DEV_L].set);
/* Set MSELECT clock source to PLL_P */
reg = MSELECT_CLK_SRC_PLLP_OUT0;
internal_periph_id = 1;
writel(reg, &clkrst->crc_clk_src_vw[internal_periph_id]);
/* Enable clock to MSELECT */
writel(SET_CLK_ENB_MSELECT,
&clkrst->crc_clk_enb_ex_vw[TEGRA_DEV_V].set);
/* Bring MSELECT out of reset */
writel(SET_MSELECT_RST_ENABLE,
&clkrst->crc_rst_dev_ex_vw[TEGRA_DEV_V].clr);
/*
* Find out which CPU (LP or G) to power on
* Power up the CPU0 partition if necessary.
* status_mask: bit mask for CPU enable in APBDEV_PMC_PWRGATE_STATUS_0
* toggle: value to power on cpu
* clamp: value to remove clamping to CPU
*/
reg = readl(&pmc->pmc_scratch4);
if (reg & CPU_WAKEUP_CLUSTER) {
/*
* Setup registers for powering up LPCPU
* - PWRGATE_STATUS, A9LP
* - PWRGATE_TOGGLE, PARTID, A9LP , START, ENABLE
* - REMOVE_CLAMPING_CMD, A9LP, ENABLE
*/
status_mask = PWRGATE_STATUS_A9LP_ENABLE;
toggle = PWRGATE_TOGGLE_START | PWRGATE_TOGGLE_PARTID_A9LP;
clamp = REMOVE_CLAMPING_CMD_A9LP_ENABLE;
} else {
/*
* Setup registers for powering up GCPU
* - PWRGATE_STATUS, CPU
* - PWRGATE_TOGGLE, PARTID, CP , START, ENABLE
* - REMOVE_CLAMPING_CMD, CPU, ENABLE
*/
status_mask = PWRGATE_STATUS_CPU_ENABLE;
toggle = PWRGATE_TOGGLE_START | PWRGATE_TOGGLE_PARTID_CP;
clamp = REMOVE_CLAMPING_CMD_CPU_ENABLE;
}
reg = readl(&pmc->pmc_pwrgate_status);
if (!(reg & status_mask))
writel(toggle, &pmc->pmc_pwrgate_toggle);
while (!(readl(&pmc->pmc_pwrgate_status) & status_mask))
{}
/* Remove the I/O clamps from the CPU0 power partition. */
writel(clamp, &pmc->pmc_remove_clamping);
/* Give I/O signals 20ms to stabilize. */
writel(EVENT_ZERO_VAL_20 | EVENT_MSEC | EVENT_MODE_STOP,
&flow->halt_cop_events);
/* Take CPU0 out of reset. */
writel(CPU_CMPLX_CPURESET0 | CPU_CMPLX_DERESET0 | CPU_CMPLX_DBGRESET0,
&clkrst->crc_cpu_cmplx_clr);
/* De-assert CPU complex reset. */
writel(CPU_RST, &clkrst->crc_rst_dev_ex[TEGRA_DEV_L].clr);
/* Unhalt the CPU at the flow controller. */
writel(0, &flow->halt_cpu_events);
/* avp_resume: no return after the write */
reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_L]);
reg &= ~CPU_RST;
writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_L]);
/* avp_halt: */
while (1)
writel(EVENT_MODE_STOP | EVENT_JTAG, &flow->halt_cop_events);
do_reset:
/*
* Execution comes here if something goes wrong. The chip is reset and
* a cold boot is performed.
*/
while (1)
writel(SWR_TRIG_SYS_RST, &clkrst->crc_rst_dev[TEGRA_DEV_L]);
}
/*
* wb_end() is a dummy function, and must be directly following wb_start(),
* and is used to calculate the size of wb_start().
*/
void wb_end(void)
{
}