/*
- * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
#define PMC_IO_DPD_REQ 0x1b8
#define PMC_IO_DPD_STATUS 0x1bc
#define PMC_SCRATCH1_ECO 0x264
+#define PMC_POR_DPD_CTRL 0x264
+
+#define FLOW_IPC_STS 0x500
+#define FLOW_IPC_STS_AP2BB_MSC_STS_0 (1 << 4)
#define CLK_RESET_CCLK_BURST 0x20
#define CLK_RESET_CCLK_DIVIDER 0x24
#define CLK_RESET_PLLP_MISC 0xac
#define CLK_RESET_PLLA_MISC 0xbc
#define CLK_RESET_PLLX_MISC 0xe4
+#if !defined(CONFIG_ARCH_TEGRA_3x_SOC)
+#define CLK_RESET_PLLX_MISC3 0x518
+#define CLK_RESET_PLLM_MISC_IDDQ 5
+#define CLK_RESET_PLLC_MISC_IDDQ 26
+#define CLK_RESET_PLLX_MISC3_IDDQ 3
+#endif
#define CLK_RESET_PLLP_OUTA 0xa4
#define CLK_RESET_PLLP_OUTB 0xa8
#define MSELECT_CLKM (0x3 << 30)
+#define TEGRA_RTC_MSEC 0x10
+
#if USE_PLL_LOCK_BITS
#define LOCK_DELAY PLL_POST_LOCK_DELAY
#else
movw r12, \
FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \
FLOW_CTRL_CSR_ENABLE
-#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
mov r4, #(1 << 8) @ wfi bitmap
#else
mov r4, #(1 << 4) @ wfe bitmap
__cpu_reset_again:
dsb
.align 5
-#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
wfi @ CPU should be power gated here
#else
wfe @ CPU should be power gated here
orreq \rd, \rd, #(1<<30)
streq \rd, [\car, #\base]
#if USE_PLL_LOCK_BITS
+ .if \misc
+ ldr \rd, [\car, #\misc]
+ bic \rd, \rd, #(1<<18)
+ str \rd, [\car, #\misc]
+ ldr \rd, [\car, #\misc]
ldr \rd, [\car, #\misc]
orr \rd, \rd, #(1<<18)
str \rd, [\car, #\misc]
+ .endif
#endif
.endm
#endif
.endm
+.macro pll_iddq_exit, rd, car, iddq, iddq_bit
+ ldr \rd, [\car, #\iddq]
+ bic \rd, \rd, #(1<<\iddq_bit)
+ str \rd, [\car, #\iddq]
+.endm
+
+.macro pll_iddq_entry, rd, car, iddq, iddq_bit
+ ldr \rd, [\car, #\iddq]
+ orr \rd, \rd, #(1<<\iddq_bit)
+ str \rd, [\car, #\iddq]
+.endm
+
ENTRY(tegra3_lp1_reset)
/* the CPU and system bus are running at 32KHz and executing from
* IRAM when this code is executed; immediately switch to CLKM and
- * enable PLLP, PLLM, PLLC, PLLA and PLLX. */
+ * enable PLLP, PLLM, PLLC, and PLLX. */
mov32 r0, TEGRA_CLK_RESET_BASE
#ifndef CONFIG_TRUSTED_FOUNDATIONS
/* secure code handles 32KHz to CLKM/OSC clock switch */
str r1, [r0, #CLK_RESET_SCLK_DIVIDER]
str r1, [r0, #CLK_RESET_CCLK_DIVIDER]
#endif
+
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
/* enable PLLM via PMC */
mov32 r2, TEGRA_PMC_BASE
ldr r1, [r2, #PMC_PLLP_WB0_OVERRIDE]
str r1, [r2, #PMC_PLLP_WB0_OVERRIDE]
pll_enable r1, r0, CLK_RESET_PLLM_BASE, CLK_RESET_PLLM_MISC
- pll_enable r1, r0, CLK_RESET_PLLP_BASE, CLK_RESET_PLLP_MISC
- pll_enable r1, r0, CLK_RESET_PLLA_BASE, CLK_RESET_PLLA_MISC
pll_enable r1, r0, CLK_RESET_PLLC_BASE, CLK_RESET_PLLC_MISC
pll_enable r1, r0, CLK_RESET_PLLX_BASE, CLK_RESET_PLLX_MISC
+#else
+ pll_iddq_exit r1, r0, CLK_RESET_PLLM_MISC, CLK_RESET_PLLM_MISC_IDDQ
+ pll_iddq_exit r1, r0, CLK_RESET_PLLC_MISC, CLK_RESET_PLLC_MISC_IDDQ
+ pll_iddq_exit r1, r0, CLK_RESET_PLLX_MISC3, CLK_RESET_PLLX_MISC3_IDDQ
+
+ mov32 r7, TEGRA_TMRUS_BASE
+ ldr r1, [r7]
+ add r1, r1, #2
+ wait_until r1, r7, r3
+
+ /* enable PLLM via PMC */
+ mov32 r2, TEGRA_PMC_BASE
+ ldr r1, [r2, #PMC_PLLP_WB0_OVERRIDE]
+ orr r1, r1, #(1<<12)
+ str r1, [r2, #PMC_PLLP_WB0_OVERRIDE]
+
+ pll_enable r1, r0, CLK_RESET_PLLM_BASE, 0
+ pll_enable r1, r0, CLK_RESET_PLLC_BASE, 0
+ pll_enable r1, r0, CLK_RESET_PLLX_BASE, 0
+#endif
+ pll_enable r1, r0, CLK_RESET_PLLP_BASE, CLK_RESET_PLLP_MISC
pll_locked r1, r0, CLK_RESET_PLLM_BASE
pll_locked r1, r0, CLK_RESET_PLLP_BASE
- pll_locked r1, r0, CLK_RESET_PLLA_BASE
pll_locked r1, r0, CLK_RESET_PLLC_BASE
pll_locked r1, r0, CLK_RESET_PLLX_BASE
add r1, r1, #LOCK_DELAY
wait_until r1, r7, r3
- add r5, pc, #tegra3_sdram_pad_save-(.+8) @ r5 reserved for pad base
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
+ add r5, pc, #tegra3_sdram_pad_save-(.+8) @ r5 --> saved data
+#endif
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+ add r5, pc, #tegra11_sdram_pad_save-(.+8) @ r5 --> saved data
+#endif
ldr r4, [r5, #0x18]
str r4, [r0, #CLK_RESET_CLK_SOURCE_MSELECT]
str r0, [r2, #PMC_REMOVE_CLAMPING_CMD]
#endif
- mov32 r0, TEGRA_EMC_BASE @ r0 reserved for emc base
-
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
+ mov32 r0, TEGRA_EMC_BASE @ r0 reserved for emc base
+#endif
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+ mov32 r0, TEGRA_EMC0_BASE @ r0 reserved for emc base
+#endif
ldr r1, [r5, #0x14] @ PMC_IO_DPD_STATUS
mvn r1, r1
bic r1, r1, #(0x1<<31)
orr r1, r1, #(0x1<<30)
str r1, [r2, #PMC_IO_DPD_REQ]
+
+exit_self_refresh:
ldr r1, [r5, #0xC]
str r1, [r0, #EMC_XM2VTTGENPADCTRL]
ldr r1, [r5, #0x10]
emc_timing_update r1, r0
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+ mov32 r1, TEGRA_EMC1_BASE
+ cmp r0, r1
+#endif
ldr r1, [r0, #EMC_AUTO_CAL_CONFIG]
orr r1, r1, #(0x1<<31) @ set AUTO_CAL_ACTIVE
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+ orreq r1, r1, #(0x1<<27) @ set slave mode for channel 1
+#endif
str r1, [r0, #EMC_AUTO_CAL_CONFIG]
emc_wait_audo_cal_onetime:
ldr r1, [r5, #0x0]
str r1, [r0, #EMC_CFG]
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+ mov32 r1, TEGRA_EMC1_BASE
+ cmp r0, r1
+ movne r0, r1
+ addne r5, r5, #0x20
+ bne exit_self_refresh
+#endif
mov32 r0, TEGRA_PMC_BASE
ldr r0, [r0, #PMC_SCRATCH41]
mov pc, r0
ENDPROC(tegra3_lp1_reset)
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)|| defined(CONFIG_ARCH_TEGRA_14x_SOC)
.align L1_CACHE_SHIFT
.type tegra3_sdram_pad_save, %object
tegra3_sdram_pad_save:
.word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14
.word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18
.word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c
+#endif
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+ .align L1_CACHE_SHIFT
+ .type tegra11_sdram_pad_save, %object
+tegra11_sdram_pad_save:
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
-tegra3_sdram_pad_size:
- .word tegra3_sdram_pad_address - tegra3_sdram_pad_save
+tegra11_sdram_pad_address:
+ .word TEGRA_EMC0_BASE + EMC_CFG @0x0
+ .word TEGRA_EMC0_BASE + EMC_ZCAL_INTERVAL @0x4
+ .word TEGRA_EMC0_BASE + EMC_AUTO_CAL_INTERVAL @0x8
+ .word TEGRA_EMC0_BASE + EMC_XM2VTTGENPADCTRL @0xc
+ .word TEGRA_EMC0_BASE + EMC_XM2VTTGENPADCTRL2 @0x10
+ .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14
+ .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18
+ .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c
+ .word TEGRA_EMC1_BASE + EMC_CFG @0x20
+ .word TEGRA_EMC1_BASE + EMC_ZCAL_INTERVAL @0x24
+ .word TEGRA_EMC1_BASE + EMC_AUTO_CAL_INTERVAL @0x28
+ .word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL @0x2c
+ .word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL2 @0x30
+#endif
#ifdef CONFIG_TEGRA_LP1_950
.globl lp1_register_pmuslave_addr
.word 0
#endif
-/*
- * tegra3_tear_down_core
+/* tegra3_tear_down_core
+ *
+ * LP0 entry check conditions w.r.t BB take place here
+ */
+tegra3_tear_down_core:
+#if defined(CONFIG_ARCH_TEGRA_14x_SOC)
+ /* Checking for BB-idle or Paging case */
+ ldr r0, [r4, #PMC_IPC_STS]
+ ldr r3, [r4, #PMC_SCRATCH37]
+
+ tst r0, #PMC_IPC_STS_MEM_REQ | PMC_IPC_STS_MEM_REQ_SOON
+ moveq r0, #0
+ beq tegra148_lp0_entry
+ andnes r3, r3, #TEGRA_POWER_LP1_AUDIO
+ bne lp1bb_entry
+
+/* lp0_delayed_entry
+ *
+ * If BB has a paging request, a 30msec timeout has to be done before the
+ * PMC_IPC_STS register is queried again
+ */
+lp0_delayed_entry:
+ /* Use RTC MS timer
+ */
+ mov32 r8, TEGRA_RTC_BASE
+ ldr r0, [r8, #TEGRA_RTC_MSEC]
+ add r0, r0, #30
+timer_loop:
+ ldr r1, [r8, #TEGRA_RTC_MSEC]
+ subs r1,r1, r0
+ ble timer_loop
+ ldr r0, [r4, #PMC_IPC_STS]
+ tst r0, #PMC_IPC_STS_MEM_REQ | PMC_IPC_STS_MEM_REQ_SOON
+ moveq r0, #1
+ bne lp1bb_entry
+
+/* R0 contains info whether delay timeout has already taken place or not */
+tegra148_lp0_entry:
+
+ /* Write PMC_IPC_CLR[mem_sts] = 1 */
+ ldr r1, [r4, #PMC_IPC_CLR]
+ orr r1, r1, #PMC_IPC_CLR_MEM_STS
+ str r1, [r4, #PMC_IPC_CLR]
+
+ /* Clear FLOW_I2C_STS[AP2BB_MSC_STS[0]] */
+ ldr r1, [r6, #FLOW_IPC_STS]
+ bic r1, #FLOW_IPC_STS_AP2BB_MSC_STS_0
+ str r1, [r6, #FLOW_IPC_STS]
+
+ /* Check PMC_IPC_STS[mem_req] and PMC_IPC_STS[mem_req_soon]
+ * once again. If both 0 then go to LP0 entry
+ */
+ ldr r3, [r4, #PMC_IPC_STS]
+ tst r3, #PMC_IPC_STS_MEM_REQ | PMC_IPC_STS_MEM_REQ_SOON
+ beq tegra3_lp0_tear_down_core
+
+ /* Check if delay has happened. If yes, then set PMC_IPC_SET[mem_sts]
+ * and then go to LP1BB, else go to delay */
+ cmp r0, #1
+ bne lp0_delayed_entry
+ ldr r1, [r4, #PMC_IPC_SET]
+ orr r1, r1, #PMC_IPC_SET_MEM_STS
+ str r1, [r4, #PMC_IPC_SET]
+ b lp1bb_entry
+
+
+/* lp1bb_entry
+ * Set up mem_req active low to be a wake event.
+ * Configure the EVP reset vector.
+ * Set up LIC to accept pmc wake events as interrupts.
+ * Clear previously set warmboot and side_effect bits
+ * Invoke remaining LP routines.
+ */
+lp1bb_entry:
+
+ /* Clear the PMC_CTRL2_WAKE_DET_EN bit */
+ ldr r0, [r4, #PMC_CTRL2]
+ bic r0, r0, #PMC_CTRL2_WAKE_DET_EN
+ str r0, [r4, #PMC_CTRL2]
+
+ /* Program the wake_level2 registers */
+ ldr r0, [r4, #PMC_WAKE2_LEVEL]
+ bic r0, r0, #PMC_WAKE2_BB_MEM_REQ
+ str r0, [r4, #PMC_WAKE2_LEVEL]
+
+ /* Wait for a few ticks for this to stabilize */
+ ldr r0, =0x300
+wait_stable:
+ subs r0, r0, #1
+ bne wait_stable
+
+ /* Program the auto_wake_lvl regsiters */
+ ldr r0, [r4, #PMC_AUTO_WAKE_LVL]
+ orr r0, r0, #1
+ str r0, [r4, #PMC_AUTO_WAKE_LVL]
+
+ ldr r0, =0x300
+wait_stable2:
+ subs r0, r0, #1
+ bne wait_stable2
+
+ /* Configure mem_req active low to be wake event */
+ ldr r0, [r4, #PMC_WAKE2_MASK]
+ orr r0, r0, #PMC_WAKE2_BB_MEM_REQ
+ str r0, [r4, #PMC_WAKE2_MASK]
+
+ ldr r0, [r4, #PMC_CTRL2]
+ orr r0, r0, #PMC_CTRL2_WAKE_DET_EN
+ str r0, [r4, #PMC_CTRL2]
+
+ /* Configure the EVP reset vector */
+ ldr r0, [r4, #PMC_SCRATCH41]
+ ldr r8, =TEGRA_EXCEPTION_VECTORS_BASE
+ str r0, [r8, #0x100]
+
+ /* Set up the LIC to accept pmc_wake events as interrupts */
+ ldr r8, =TEGRA_TERTIARY_ICTLR_BASE
+ ldr r0, =TRI_ICTLR_PMC_WAKE_INT
+ str r0, [r8, #TRI_ICTLR_CPU_IER_SET]
+
+ bl tegra148_lp1bb_clear_warmboot_flag
+ bl tegra3_cpu_clk32k
+ b tegra3_enter_sleep
+#endif
+
+/* tegra3_lp0_tear_down_core
*
* copied into and executed from IRAM
* puts memory in self-refresh for LP0 and LP1
*/
-tegra3_tear_down_core:
+tegra3_lp0_tear_down_core:
bl tegra3_sdram_self_refresh
bl tegra3_cpu_clk32k
b tegra3_enter_sleep
+/*
+ * tegra148_lp1bb_clear_warmboot_flag
+ * Clears warmboot0 flag, and clears SIDE_EFFECT_BIT.
+ * Called by lp1bb_entry.
+ */
+tegra148_lp1bb_clear_warmboot_flag:
+ ldr r0, [r4, #PMC_SCRATCH0]
+ bic r0, r0, #1
+ str r0, [r4, #PMC_SCRATCH0]
+ ldr r0, [r4, #PMC_CTRL]
+ bic r0, r0, #PMC_CTRL_SIDE_EFFECT_LP0
+ str r0, [r4, #PMC_CTRL]
+ mov pc, lr
+
/*
* tegra3_cpu_clk32k
*
str r1, [r4, #PMC_SCRATCH1_ECO]
#endif
+#if defined(CONFIG_ARCH_TEGRA_14x_SOC)
+ ldr r1, [r4, #PMC_POR_DPD_CTRL]
+ orr r1, r1, #0x47
+ str r1, [r4, #PMC_POR_DPD_CTRL]
+#endif
+
mov pc, lr
lp1_clocks_prepare:
* to clks */
mov r0, #(1 << 28)
str r0, [r5, #CLK_RESET_SCLK_BURST]
+ /* 2 us delay between changing sclk and cclk */
+ wait_for_us r1, r7, r9
+ add r1, r1, #2
+ wait_until r1, r7, r9
+ mov r0, #(1 << 28)
str r0, [r5, #CLK_RESET_CCLK_BURST]
mov r0, #0
str r0, [r5, #CLK_RESET_CCLK_DIVIDER]
add r1, r1, #2
wait_until r1, r7, r9
- /* switch to CLKS */
- mov r0, #0 /* burst policy = 32KHz */
- str r0, [r5, #CLK_RESET_SCLK_BURST]
-
+#if !defined(CONFIG_ARCH_TEGRA_14x_SOC)
/* disable PLLM via PMC in LP1 */
ldr r0, [r4, #PMC_PLLP_WB0_OVERRIDE]
bic r0, r0, #(1 << 12)
str r0, [r4, #PMC_PLLP_WB0_OVERRIDE]
+#endif
b powerdown_pll_pcx
powerdown_pll_pcx:
ldr r0, [r5, #CLK_RESET_PLLX_BASE]
bic r0, r0, #(1<<30)
str r0, [r5, #CLK_RESET_PLLX_BASE]
+#if !defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ /*
+ * FIXME: put PLLM/C into IDDQ (need additional testing)
+ * pll_iddq_entry r1, r5, CLK_RESET_PLLM_MISC, CLK_RESET_PLLM_MISC_IDDQ
+ * pll_iddq_entry r1, r5, CLK_RESET_PLLC_MISC, CLK_RESET_PLLC_MISC_IDDQ
+ */
+ pll_iddq_entry r1, r5, CLK_RESET_PLLX_MISC3, CLK_RESET_PLLX_MISC3_IDDQ
+#endif
+ /* switch to CLKS */
+ mov r0, #0 /* burst policy = 32KHz */
+ str r0, [r5, #CLK_RESET_SCLK_BURST]
mov pc, lr
/*
orr r0, r0, #FLOW_CTRL_CSR_ENABLE
str r0, [r6, r2]
-#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
tst r0, #FLOW_CTRL_IMMEDIATE_WAKE
movne r0, #FLOW_CTRL_WAITEVENT
moveq r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT
tegra3_sdram_self_refresh:
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
adr r2, tegra3_sdram_pad_address
adr r8, tegra3_sdram_pad_save
- mov r9, #0
+#endif
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+ adr r2, tegra11_sdram_pad_address
+ adr r8, tegra11_sdram_pad_save
+#endif
+ mov r9, r2
padsave:
- ldr r0, [r2, r9] @ r0 is emc register address
+ ldr r0, [r2], #4 @ r0 is emc register address
ldr r1, [r0]
- str r1, [r8, r9] @ save emc register
+ str r1, [r8], #4 @ save emc register
- add r9, r9, #4
- ldr r0, tegra3_sdram_pad_size
- cmp r0, r9
+ cmp r8, r9
bne padsave
padsave_done:
dsb
- mov32 r0, TEGRA_EMC_BASE @ r0 reserved for emc base
-
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
+ mov32 r0, TEGRA_EMC_BASE @ r0 reserved for emc base
+#endif
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+ mov32 r0, TEGRA_EMC0_BASE @ r0 reserved for emc base
+#endif
+enter_self_refresh:
mov r1, #0
str r1, [r0, #EMC_ZCAL_INTERVAL]
str r1, [r0, #EMC_AUTO_CAL_INTERVAL]
ldr r1, [r0, #EMC_CFG]
bic r1, r1, #(1<<28)
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
+ bic r1, r1, #(1<<29)
+#endif
str r1, [r0, #EMC_CFG] @ disable DYN_SELF_REF
emc_timing_update r1, r0
and r1, r1, r2
str r1, [r0, #EMC_XM2VTTGENPADCTRL]
ldr r1, [r0, #EMC_XM2VTTGENPADCTRL2]
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
orr r1, r1, #7 @ set E_NO_VTTGEN
+#endif
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
+ orr r1, r1, #0x3f @ set E_NO_VTTGEN
+#endif
str r1, [r0, #EMC_XM2VTTGENPADCTRL2]
emc_timing_update r1, r0
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC)
+ mov32 r1, TEGRA_EMC1_BASE
+ cmp r0, r1
+ movne r0, r1
+ bne enter_self_refresh
+#endif
+
ldr r1, [r4, #PMC_CTRL]
tst r1, #PMC_CTRL_SIDE_EFFECT_LP0
bne pmc_io_dpd_skip