diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-tegra/suspend-t2.c | 23 | ||||
-rw-r--r-- | arch/arm/mach-tegra/suspend.c | 37 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra2_save.S | 30 |
4 files changed, 86 insertions, 8 deletions
diff --git a/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c b/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c index fab62d92bfcd..841798ed9d73 100644 --- a/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c +++ b/arch/arm/mach-tegra/odm_kit/query/whistler/nvodm_query.c @@ -581,8 +581,8 @@ static NvOdmWakeupPadInfo s_NvOdmWakeupPadInfo[] = {NV_FALSE, 13, NvOdmWakeupPadPolarity_Low}, // Wake Event 13 - sdio1_dat1 {NV_FALSE, 14, NvOdmWakeupPadPolarity_AnyEdge}, // Wake Event 14 - gp3_pv[6] (WLAN_INT) {NV_FALSE, 15, NvOdmWakeupPadPolarity_AnyEdge}, // Wake Event 15 - gmi_ad16 (SPI3_DOUT, DTV_SPI4_CS1) - {NV_FALSE, 16, NvOdmWakeupPadPolarity_High}, // Wake Event 16 - rtc_irq - {NV_TRUE, 17, NvOdmWakeupPadPolarity_High}, // Wake Event 17 - kbc_interrupt + {NV_TRUE, 16, NvOdmWakeupPadPolarity_High}, // Wake Event 16 - rtc_irq + {NV_FALSE, 17, NvOdmWakeupPadPolarity_High}, // Wake Event 17 - kbc_interrupt {NV_FALSE, 18, NvOdmWakeupPadPolarity_Low}, // Wake Event 18 - pwr_int (PMIC_INT) {NV_FALSE, 19, NvOdmWakeupPadPolarity_AnyEdge}, // Wake Event 19 - usb_vbus_wakeup[0] {NV_FALSE, 20, NvOdmWakeupPadPolarity_High}, // Wake Event 20 - usb_vbus_wakeup[1] diff --git a/arch/arm/mach-tegra/suspend-t2.c b/arch/arm/mach-tegra/suspend-t2.c index ed1055687baf..1cff68f878e9 100644 --- a/arch/arm/mach-tegra/suspend-t2.c +++ b/arch/arm/mach-tegra/suspend-t2.c @@ -24,6 +24,8 @@ #include <linux/init.h> #include <asm/io.h> #include <mach/iomap.h> +#include "nvbootargs.h" +#include <nvrm_memmgr.h> #define PMC_SCRATCH3 0x5c #define PMC_SCRATCH5 0x64 @@ -49,6 +51,7 @@ #define PMC_SCRATCH35 0x128 #define PMC_SCRATCH36 0x12c #define PMC_SCRATCH40 0x13c +#define PMC_SCRATCH41 0x140 struct pmc_scratch_field { void __iomem *addr; @@ -328,9 +331,16 @@ static const struct pmc_scratch_reg scratch[] __initdata = { scratch(PMC_SCRATCH40, xm2_cfgd), }; +extern void tegra_lp2_startup(void); +extern NvRmDeviceHandle s_hRmGlobal; +unsigned int s_AvpWarmbootEntry; +static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); + void __init lp0_suspend_init(void) { int i; + NvBootArgsWarmboot WarmbootArgs; + NvRmMemHandle s_hWarmboot = NULL; for (i=0; i<ARRAY_SIZE(scratch); i++) { unsigned int r = 0; @@ -346,4 +356,17 @@ void __init lp0_suspend_init(void) writel(r, scratch[i].scratch_addr); } + + NvOsBootArgGet(NvBootArgKey_WarmBoot, + &WarmbootArgs, sizeof(NvBootArgsWarmboot)); + if (NvRmMemHandleClaimPreservedHandle(s_hRmGlobal, + WarmbootArgs.MemHandleKey, &s_hWarmboot)) { + printk("Could not locate Warm booloader!\n"); + } + else { + s_AvpWarmbootEntry = NvRmMemPin(s_hWarmboot); + } + + //Write the CPU LP0 reset vector address in SCRATCH41 + writel(virt_to_phys(tegra_lp2_startup), pmc + PMC_SCRATCH41); } diff --git a/arch/arm/mach-tegra/suspend.c b/arch/arm/mach-tegra/suspend.c index c0e944c79364..240ab30b1793 100644 --- a/arch/arm/mach-tegra/suspend.c +++ b/arch/arm/mach-tegra/suspend.c @@ -78,6 +78,7 @@ static void __iomem *tmrus = IO_ADDRESS(TEGRA_TMRUS_BASE); #define PMC_SW_WAKE_STATUS 0x18 #define PMC_COREPWRGOOD_TIMER 0x3c +#define PMC_SCRATCH0 0x50 #define PMC_SCRATCH1 0x54 #define PMC_CPUPWRGOOD_TIMER 0xc8 #define PMC_CPUPWROFF_TIMER 0xcc @@ -194,6 +195,7 @@ static noinline void restore_cpu_complex(void) } extern unsigned long tegra_pgd_phys; +extern unsigned int s_AvpWarmbootEntry; static noinline void suspend_cpu_complex(void) { @@ -279,6 +281,19 @@ static void pmc_32kwritel(u32 val, unsigned long offs) udelay(130); } +static void tegra_setup_warmboot(void) +{ + u32 scratch0; + + //Turn the WARMBOOT flag on in scratch0 + scratch0 = readl(pmc + PMC_SCRATCH0); + scratch0 |= 1; + pmc_32kwritel(scratch0, PMC_SCRATCH0); + + //Write the AVP warmboot entry address in SCRATCH1 + pmc_32kwritel(s_AvpWarmbootEntry, PMC_SCRATCH1); +} + static void tegra_setup_wakepads(bool lp0_ok) { u32 temp, status, lvl; @@ -290,10 +305,9 @@ static void tegra_setup_wakepads(bool lp0_ok) pmc_32kwritel(0, PMC_SW_WAKE_STATUS); temp = readl(pmc + PMC_CTRL); temp |= PMC_CTRL_LATCH_WAKEUPS; - pmc_32kwritel(0, PMC_CTRL); + pmc_32kwritel(temp, PMC_CTRL); temp &= ~PMC_CTRL_LATCH_WAKEUPS; - pmc_32kwritel(0, PMC_CTRL); - + pmc_32kwritel(temp, PMC_CTRL); status = readl(pmc + PMC_SW_WAKE_STATUS); lvl = readl(pmc + PMC_WAKE_LEVEL); @@ -304,8 +318,8 @@ static void tegra_setup_wakepads(bool lp0_ok) lvl |= pdata->wake_high; lvl ^= status; - writel(lvl, PMC_WAKE_LEVEL); - writel(pdata->wake_enb, PMC_WAKE_MASK); + writel(lvl, pmc + PMC_WAKE_LEVEL); + writel(pdata->wake_enb, pmc + PMC_WAKE_MASK); } extern void __tegra_lp1_reset(void); @@ -314,6 +328,7 @@ extern void __tegra_iram_end(void); static u8 *iram_save = NULL; static unsigned int iram_save_size = 0; static void __iomem *iram_code = IO_ADDRESS(TEGRA_IRAM_CODE_AREA); +static void __iomem *iram_avp_resume = IO_ADDRESS(TEGRA_IRAM_BASE); static void tegra_suspend_dram(bool lp0_ok) { @@ -344,6 +359,7 @@ static void tegra_suspend_dram(bool lp0_ok) } else { NvRmPrivPowerSetState(s_hRmGlobal, NvRmPowerState_LP0); set_power_timers(pdata->cpu_timer, pdata->cpu_off_timer); + tegra_setup_warmboot(); mode |= TEGRA_POWER_SYSCLK_OE; mode |= TEGRA_POWER_PWRREQ_OE; mode |= TEGRA_POWER_EFFECT_LP0; @@ -365,6 +381,8 @@ static void tegra_suspend_dram(bool lp0_ok) reg |= ((mode & TEGRA_POWER_PMC_MASK) << TEGRA_POWER_PMC_SHIFT); pmc_32kwritel(reg, PMC_CTRL); } + else + mode |= TEGRA_POWER_CPU_PWRREQ_OE; tegra_setup_wakepads(lp0_ok); suspend_cpu_complex(); @@ -390,7 +408,9 @@ static void tegra_suspend_dram(bool lp0_ok) } else if (!lp0_ok) writel(lp2_timer, pmc + PMC_CPUPWRGOOD_TIMER); - memcpy(iram_code, iram_save, iram_save_size); + if (!lp0_ok) + memcpy(iram_code, iram_save, iram_save_size); + wmb(); } @@ -489,6 +509,11 @@ static int tegra_suspend_prepare_late(void) __func__, e); return -EIO; } + + //The AVP stores its resume address in the first word of IRAM + //Write this resume address to SCRATCH39, where the warmboot + //code can later find it + writel(*(volatile unsigned int *)iram_avp_resume, pmc + PMC_SCRATCH39); #endif disable_irq(INT_SYS_STATS_MON); return tegra_iovmm_suspend(); diff --git a/arch/arm/mach-tegra/tegra2_save.S b/arch/arm/mach-tegra/tegra2_save.S index 6f7fd086a366..b5353803e0b5 100644 --- a/arch/arm/mach-tegra/tegra2_save.S +++ b/arch/arm/mach-tegra/tegra2_save.S @@ -69,6 +69,9 @@ #define FLOW_CTRL_HALT_CPU_EVENTS 0x0 +#define DEBUG_FORCE_RTC_WAKEUP_SEC 0 +#define RTC_PA_BASE 0x7000e000 + #include "power-macros.S" .macro emc_device_mask, rd, base @@ -366,6 +369,33 @@ __tear_down_master_pll_cpu: bic r0, r0, #(1<<30) str r0, [r5, #CLK_RESET_PLLC_BASE] +#if DEBUG_FORCE_RTC_WAKEUP_SEC + //r0 = RTC_BASE + mov32 r0, RTC_PA_BASE + //setup rtc wake + ldr r2, [r0, #0x10] /* milli */ + ldr r2, [r0, #0x8] /* shadow */ + + add r2, r2, #DEBUG_FORCE_RTC_WAKEUP_SEC +rtc_idle1: + ldr r1, [r0, #0x4] + tst r1, #0x1 + bne rtc_idle1 + str r2, [r0, #0x14] +rtc_idle2: + ldr r1, [r0, #0x4] + tst r1, #0x1 + bne rtc_idle2 + /* intr mask alarm0 */ + mov r2, #1 + str r2, [r0, #0x28] + str r2, [r0, #0x2c] +rtc_idle3: + ldr r1, [r0, #0x4] + tst r1, #0x1 + bne rtc_idle3 +#endif + __cclk_burst_set: mov r0, #(4<<29) /* STOP_UNTIL_IRQ */ orr r0, r0, #(1<<10) | (1<<8) /* IRQ_0, FIQ_0 */ |