Path: blob/master/arch/avr32/mach-at32ap/pm-at32ap700x.S
10817 views
/*1* Low-level Power Management code.2*3* Copyright (C) 2008 Atmel Corporation4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License version 2 as7* published by the Free Software Foundation.8*/9#include <asm/asm.h>10#include <asm/asm-offsets.h>11#include <asm/thread_info.h>12#include <mach/pm.h>1314#include "pm.h"15#include "sdramc.h"1617/* Same as 0xfff00000 but fits in a 21 bit signed immediate */18#define PM_BASE -0x1000001920.section .bss, "wa", @nobits21.global disable_idle_sleep22.type disable_idle_sleep, @object23disable_idle_sleep:24.int 425.size disable_idle_sleep, . - disable_idle_sleep2627/* Keep this close to the irq handlers */28.section .irq.text, "ax", @progbits2930/*31* void cpu_enter_idle(void)32*33* Put the CPU into "idle" mode, in which it will consume34* significantly less power.35*36* If an interrupt comes along in the window between37* unmask_interrupts and the sleep instruction below, the38* interrupt code will adjust the return address so that we39* never execute the sleep instruction. This is required40* because the AP7000 doesn't unmask interrupts when entering41* sleep modes; later CPUs may not need this workaround.42*/43.global cpu_enter_idle44.type cpu_enter_idle, @function45cpu_enter_idle:46mask_interrupts47get_thread_info r848ld.w r9, r8[TI_flags]49bld r9, TIF_NEED_RESCHED50brcs .Lret_from_sleep51sbr r9, TIF_CPU_GOING_TO_SLEEP52st.w r8[TI_flags], r953unmask_interrupts54sleep CPU_SLEEP_IDLE55.size cpu_enter_idle, . - cpu_enter_idle5657/*58* Common return path for PM functions that don't run from59* SRAM.60*/61.global cpu_idle_skip_sleep62.type cpu_idle_skip_sleep, @function63cpu_idle_skip_sleep:64mask_interrupts65ld.w r9, r8[TI_flags]66cbr r9, TIF_CPU_GOING_TO_SLEEP67st.w r8[TI_flags], r968.Lret_from_sleep:69unmask_interrupts70retal r1271.size cpu_idle_skip_sleep, . - cpu_idle_skip_sleep7273#ifdef CONFIG_PM74.section .init.text, "ax", @progbits7576.global pm_exception77.type pm_exception, @function78pm_exception:79/*80* Exceptions are masked when we switch to this handler, so81* we'll only get "unrecoverable" exceptions (offset 0.)82*/83sub r12, pc, . - .Lpanic_msg84lddpc pc, .Lpanic_addr8586.align 287.Lpanic_addr:88.long panic89.Lpanic_msg:90.asciz "Unrecoverable exception during suspend\n"91.size pm_exception, . - pm_exception9293.global pm_irq094.type pm_irq0, @function95pm_irq0:96/* Disable interrupts and return after the sleep instruction */97mfsr r9, SYSREG_RSR_INT098mtsr SYSREG_RAR_INT0, r899sbr r9, SYSREG_GM_OFFSET100mtsr SYSREG_RSR_INT0, r9101rete102103/*104* void cpu_enter_standby(unsigned long sdramc_base)105*106* Enter PM_SUSPEND_STANDBY mode. At this point, all drivers107* are suspended and interrupts are disabled. Interrupts108* marked as 'wakeup' event sources may still come along and109* get us out of here.110*111* The SDRAM will be put into self-refresh mode (which does112* not require a clock from the CPU), and the CPU will be put113* into "frozen" mode (HSB bus stopped). The SDRAM controller114* will automatically bring the SDRAM into normal mode on the115* first access, and the power manager will automatically116* start the HSB and CPU clocks upon a wakeup event.117*118* This code uses the same "skip sleep" technique as above.119* It is very important that we jump directly to120* cpu_after_sleep after the sleep instruction since that's121* where we'll end up if the interrupt handler decides that we122* need to skip the sleep instruction.123*/124.global pm_standby125.type pm_standby, @function126pm_standby:127/*128* interrupts are already masked at this point, and EVBA129* points to pm_exception above.130*/131ld.w r10, r12[SDRAMC_LPR]132sub r8, pc, . - 1f /* return address for irq handler */133mov r11, SDRAMC_LPR_LPCB_SELF_RFR134bfins r10, r11, 0, 2 /* LPCB <- self Refresh */135sync 0 /* flush write buffer */136st.w r12[SDRAMC_LPR], r10 /* put SDRAM in self-refresh mode */137ld.w r11, r12[SDRAMC_LPR]138unmask_interrupts139sleep CPU_SLEEP_FROZEN1401: mask_interrupts141retal r12142.size pm_standby, . - pm_standby143144.global pm_suspend_to_ram145.type pm_suspend_to_ram, @function146pm_suspend_to_ram:147/*148* interrupts are already masked at this point, and EVBA149* points to pm_exception above.150*/151mov r11, 0152cache r11[2], 8 /* clean all dcache lines */153sync 0 /* flush write buffer */154ld.w r10, r12[SDRAMC_LPR]155sub r8, pc, . - 1f /* return address for irq handler */156mov r11, SDRAMC_LPR_LPCB_SELF_RFR157bfins r10, r11, 0, 2 /* LPCB <- self refresh */158st.w r12[SDRAMC_LPR], r10 /* put SDRAM in self-refresh mode */159ld.w r11, r12[SDRAMC_LPR]160161unmask_interrupts162sleep CPU_SLEEP_STOP1631: mask_interrupts164165retal r12166.size pm_suspend_to_ram, . - pm_suspend_to_ram167168.global pm_sram_end169.type pm_sram_end, @function170pm_sram_end:171.size pm_sram_end, 0172173#endif /* CONFIG_PM */174175176