2006-04-02 20:46:25 +04:00
/*
* linux / arch / arm / mach - omap1 / pm . c
*
* OMAP Power Management Routines
*
* Original code for the SA11x0 :
* Copyright ( c ) 2001 Cliff Brake < cbrake @ accelent . com >
*
* Modified for the PXA250 by Nicolas Pitre :
* Copyright ( c ) 2002 Monta Vista Software , Inc .
*
* Modified for the OMAP1510 by David Singleton :
* Copyright ( c ) 2002 Monta Vista Software , Inc .
*
* Cleanup 2004 for OMAP1510 / 1610 by Dirk Behme < dirk . behme @ de . bosch . com >
*
* 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 SOFTWARE IS PROVIDED ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF
* USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* 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 . ,
* 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2007-10-18 14:04:39 +04:00
# include <linux/suspend.h>
2006-04-02 20:46:25 +04:00
# include <linux/sched.h>
2013-04-11 22:03:41 +04:00
# include <linux/debugfs.h>
# include <linux/seq_file.h>
2006-04-02 20:46:25 +04:00
# include <linux/interrupt.h>
# include <linux/sysfs.h>
# include <linux/module.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2012-01-05 01:27:48 +04:00
# include <linux/atomic.h>
2013-03-22 01:49:38 +04:00
# include <linux/cpu.h>
2006-04-02 20:46:25 +04:00
2012-10-30 00:54:06 +04:00
# include <asm/fncpy.h>
2012-03-29 20:30:28 +04:00
# include <asm/system_misc.h>
2006-04-02 20:46:25 +04:00
# include <asm/irq.h>
# include <asm/mach/time.h>
# include <asm/mach/irq.h>
2012-10-03 00:39:28 +04:00
# include <mach/tc.h>
2012-09-19 21:46:56 +04:00
# include <mach/mux.h>
2012-11-30 20:41:50 +04:00
# include <linux/omap-dma.h>
2018-02-15 09:01:44 +03:00
# include <clocksource/timer-ti-dm.h>
2006-04-02 20:46:25 +04:00
2012-02-24 22:34:34 +04:00
# include <mach/irqs.h>
# include "iomap.h"
2012-09-27 20:33:34 +04:00
# include "clock.h"
2009-05-15 22:29:28 +04:00
# include "pm.h"
2015-05-22 00:50:23 +03:00
# include "soc.h"
2012-10-30 00:54:06 +04:00
# include "sram.h"
2009-05-15 22:29:28 +04:00
2006-04-02 20:46:25 +04:00
static unsigned int arm_sleep_save [ ARM_SLEEP_SAVE_SIZE ] ;
static unsigned short dsp_sleep_save [ DSP_SLEEP_SAVE_SIZE ] ;
static unsigned short ulpd_sleep_save [ ULPD_SLEEP_SAVE_SIZE ] ;
2009-09-22 13:02:58 +04:00
static unsigned int mpui7xx_sleep_save [ MPUI7XX_SLEEP_SAVE_SIZE ] ;
2006-04-02 20:46:25 +04:00
static unsigned int mpui1510_sleep_save [ MPUI1510_SLEEP_SAVE_SIZE ] ;
static unsigned int mpui1610_sleep_save [ MPUI1610_SLEEP_SAVE_SIZE ] ;
2015-02-07 01:56:07 +03:00
static unsigned short enable_dyn_sleep ;
2006-04-02 20:46:25 +04:00
2007-11-02 23:20:40 +03:00
static ssize_t idle_show ( struct kobject * kobj , struct kobj_attribute * attr ,
char * buf )
2006-04-02 20:46:25 +04:00
{
return sprintf ( buf , " %hu \n " , enable_dyn_sleep ) ;
}
2007-11-02 23:20:40 +03:00
static ssize_t idle_store ( struct kobject * kobj , struct kobj_attribute * attr ,
const char * buf , size_t n )
2006-04-02 20:46:25 +04:00
{
unsigned short value ;
if ( sscanf ( buf , " %hu " , & value ) ! = 1 | |
2015-02-07 01:56:07 +03:00
( value ! = 0 & & value ! = 1 ) | |
( value ! = 0 & & ! IS_ENABLED ( CONFIG_OMAP_32K_TIMER ) ) ) {
pr_err ( " idle_sleep_store: Invalid value \n " ) ;
2006-04-02 20:46:25 +04:00
return - EINVAL ;
}
enable_dyn_sleep = value ;
return n ;
}
2007-11-02 23:20:40 +03:00
static struct kobj_attribute sleep_while_idle_attr =
__ATTR ( sleep_while_idle , 0644 , idle_show , idle_store ) ;
2006-04-02 20:46:25 +04:00
2007-12-11 19:16:31 +03:00
2006-04-02 20:46:25 +04:00
static void ( * omap_sram_suspend ) ( unsigned long r0 , unsigned long r1 ) = NULL ;
/*
* Let ' s power down on idle , but only if we are really
* idle , because once we start down the path of
* going idle we continue to do idle even if we get
* a clock tick interrupt . .
*/
2009-05-15 22:29:28 +04:00
void omap1_pm_idle ( void )
2006-04-02 20:46:25 +04:00
{
extern __u32 arm_idlect1_mask ;
__u32 use_idlect1 = arm_idlect1_mask ;
local_fiq_disable ( ) ;
2011-10-07 04:05:51 +04:00
# if defined(CONFIG_OMAP_MPU_TIMER) && !defined(CONFIG_OMAP_DM_TIMER)
2006-04-02 20:46:25 +04:00
use_idlect1 = use_idlect1 & ~ ( 1 < < 9 ) ;
2007-12-11 19:16:31 +03:00
# endif
2006-04-02 20:46:25 +04:00
# ifdef CONFIG_OMAP_DM_TIMER
use_idlect1 = omap_dm_timer_modify_idlect_mask ( use_idlect1 ) ;
# endif
2007-03-05 18:34:05 +03:00
if ( omap_dma_running ( ) )
2006-04-02 20:46:25 +04:00
use_idlect1 & = ~ ( 1 < < 6 ) ;
2015-02-07 01:56:07 +03:00
/*
* We should be able to remove the do_sleep variable and multiple
2006-04-02 20:46:25 +04:00
* tests above as soon as drivers , timer and DMA code have been fixed .
2015-02-07 01:56:07 +03:00
* Even the sleep block count should become obsolete .
*/
if ( ( use_idlect1 ! = ~ 0 ) | | ! enable_dyn_sleep ) {
2006-04-02 20:46:25 +04:00
__u32 saved_idlect1 = omap_readl ( ARM_IDLECT1 ) ;
if ( cpu_is_omap15xx ( ) )
use_idlect1 & = OMAP1510_BIG_SLEEP_REQUEST ;
else
use_idlect1 & = OMAP1610_IDLECT1_SLEEP_VAL ;
omap_writel ( use_idlect1 , ARM_IDLECT1 ) ;
__asm__ volatile ( " mcr p15, 0, r0, c7, c0, 4 " ) ;
omap_writel ( saved_idlect1 , ARM_IDLECT1 ) ;
local_fiq_enable ( ) ;
return ;
}
omap_sram_suspend ( omap_readl ( ARM_IDLECT1 ) ,
omap_readl ( ARM_IDLECT2 ) ) ;
local_fiq_enable ( ) ;
}
/*
* Configuration of the wakeup event is board specific . For the
* moment we put it into this helper function . Later it may move
* to board specific files .
*/
static void omap_pm_wakeup_setup ( void )
{
u32 level1_wake = 0 ;
u32 level2_wake = OMAP_IRQ_BIT ( INT_UART2 ) ;
/*
* Turn off all interrupts except GPIO bank 1 , L1 - 2 nd level cascade ,
* and the L2 wakeup interrupts : keypad and UART2 . Note that the
* drivers must still separately call omap_set_gpio_wakeup ( ) to
* wake up to a GPIO interrupt .
*/
2009-09-22 09:41:09 +04:00
if ( cpu_is_omap7xx ( ) )
2009-09-18 07:09:39 +04:00
level1_wake = OMAP_IRQ_BIT ( INT_7XX_GPIO_BANK1 ) |
OMAP_IRQ_BIT ( INT_7XX_IH2_IRQ ) ;
2006-04-02 20:46:25 +04:00
else if ( cpu_is_omap15xx ( ) )
level1_wake = OMAP_IRQ_BIT ( INT_GPIO_BANK1 ) |
OMAP_IRQ_BIT ( INT_1510_IH2_IRQ ) ;
else if ( cpu_is_omap16xx ( ) )
level1_wake = OMAP_IRQ_BIT ( INT_GPIO_BANK1 ) |
OMAP_IRQ_BIT ( INT_1610_IH2_IRQ ) ;
omap_writel ( ~ level1_wake , OMAP_IH1_MIR ) ;
2009-09-22 09:41:09 +04:00
if ( cpu_is_omap7xx ( ) ) {
2006-04-02 20:46:25 +04:00
omap_writel ( ~ level2_wake , OMAP_IH2_0_MIR ) ;
2009-09-18 07:09:39 +04:00
omap_writel ( ~ ( OMAP_IRQ_BIT ( INT_7XX_WAKE_UP_REQ ) |
OMAP_IRQ_BIT ( INT_7XX_MPUIO_KEYPAD ) ) ,
2006-04-02 20:46:25 +04:00
OMAP_IH2_1_MIR ) ;
} else if ( cpu_is_omap15xx ( ) ) {
level2_wake | = OMAP_IRQ_BIT ( INT_KEYBOARD ) ;
omap_writel ( ~ level2_wake , OMAP_IH2_MIR ) ;
} else if ( cpu_is_omap16xx ( ) ) {
level2_wake | = OMAP_IRQ_BIT ( INT_KEYBOARD ) ;
omap_writel ( ~ level2_wake , OMAP_IH2_0_MIR ) ;
/* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
omap_writel ( ~ OMAP_IRQ_BIT ( INT_1610_WAKE_UP_REQ ) ,
OMAP_IH2_1_MIR ) ;
omap_writel ( ~ 0x0 , OMAP_IH2_2_MIR ) ;
omap_writel ( ~ 0x0 , OMAP_IH2_3_MIR ) ;
}
/* New IRQ agreement, recalculate in cascade order */
omap_writel ( 1 , OMAP_IH2_CONTROL ) ;
omap_writel ( 1 , OMAP_IH1_CONTROL ) ;
}
# define EN_DSPCK 13 /* ARM_CKCTL */
# define EN_APICK 6 /* ARM_IDLECT2 */
# define DSP_EN 1 /* ARM_RSTCT1 */
2009-05-15 22:29:28 +04:00
void omap1_pm_suspend ( void )
2006-04-02 20:46:25 +04:00
{
unsigned long arg0 = 0 , arg1 = 0 ;
2008-12-11 04:36:31 +03:00
printk ( KERN_INFO " PM: OMAP%x is trying to enter deep sleep... \n " ,
omap_rev ( ) ) ;
2006-04-02 20:46:25 +04:00
omap_serial_wake_trigger ( 1 ) ;
2006-12-07 04:13:48 +03:00
if ( ! cpu_is_omap15xx ( ) )
omap_writew ( 0xffff , ULPD_SOFT_DISABLE_REQ_REG ) ;
2006-04-02 20:46:25 +04:00
/*
* Step 1 : turn off interrupts ( FIXME : NOTE : already disabled )
*/
local_irq_disable ( ) ;
local_fiq_disable ( ) ;
/*
* Step 2 : save registers
*
* The omap is a strange / beautiful device . The caches , memory
* and register state are preserved across power saves .
* We have to save and restore very little register state to
* idle the omap .
*
* Save interrupt , MPUI , ARM and UPLD control registers .
*/
2009-09-22 09:41:09 +04:00
if ( cpu_is_omap7xx ( ) ) {
2009-09-22 13:02:58 +04:00
MPUI7XX_SAVE ( OMAP_IH1_MIR ) ;
MPUI7XX_SAVE ( OMAP_IH2_0_MIR ) ;
MPUI7XX_SAVE ( OMAP_IH2_1_MIR ) ;
MPUI7XX_SAVE ( MPUI_CTRL ) ;
MPUI7XX_SAVE ( MPUI_DSP_BOOT_CONFIG ) ;
MPUI7XX_SAVE ( MPUI_DSP_API_CONFIG ) ;
MPUI7XX_SAVE ( EMIFS_CONFIG ) ;
MPUI7XX_SAVE ( EMIFF_SDRAM_CONFIG ) ;
2006-04-02 20:46:25 +04:00
} else if ( cpu_is_omap15xx ( ) ) {
MPUI1510_SAVE ( OMAP_IH1_MIR ) ;
MPUI1510_SAVE ( OMAP_IH2_MIR ) ;
MPUI1510_SAVE ( MPUI_CTRL ) ;
MPUI1510_SAVE ( MPUI_DSP_BOOT_CONFIG ) ;
MPUI1510_SAVE ( MPUI_DSP_API_CONFIG ) ;
MPUI1510_SAVE ( EMIFS_CONFIG ) ;
MPUI1510_SAVE ( EMIFF_SDRAM_CONFIG ) ;
} else if ( cpu_is_omap16xx ( ) ) {
MPUI1610_SAVE ( OMAP_IH1_MIR ) ;
MPUI1610_SAVE ( OMAP_IH2_0_MIR ) ;
MPUI1610_SAVE ( OMAP_IH2_1_MIR ) ;
MPUI1610_SAVE ( OMAP_IH2_2_MIR ) ;
MPUI1610_SAVE ( OMAP_IH2_3_MIR ) ;
MPUI1610_SAVE ( MPUI_CTRL ) ;
MPUI1610_SAVE ( MPUI_DSP_BOOT_CONFIG ) ;
MPUI1610_SAVE ( MPUI_DSP_API_CONFIG ) ;
MPUI1610_SAVE ( EMIFS_CONFIG ) ;
MPUI1610_SAVE ( EMIFF_SDRAM_CONFIG ) ;
}
ARM_SAVE ( ARM_CKCTL ) ;
ARM_SAVE ( ARM_IDLECT1 ) ;
ARM_SAVE ( ARM_IDLECT2 ) ;
if ( ! ( cpu_is_omap15xx ( ) ) )
ARM_SAVE ( ARM_IDLECT3 ) ;
ARM_SAVE ( ARM_EWUPCT ) ;
ARM_SAVE ( ARM_RSTCT1 ) ;
ARM_SAVE ( ARM_RSTCT2 ) ;
ARM_SAVE ( ARM_SYSST ) ;
ULPD_SAVE ( ULPD_CLOCK_CTRL ) ;
ULPD_SAVE ( ULPD_STATUS_REQ ) ;
/* (Step 3 removed - we now allow deep sleep by default) */
/*
* Step 4 : OMAP DSP Shutdown
*/
/* stop DSP */
omap_writew ( omap_readw ( ARM_RSTCT1 ) & ~ ( 1 < < DSP_EN ) , ARM_RSTCT1 ) ;
2006-06-27 03:16:03 +04:00
/* shut down dsp_ck */
2009-09-22 09:41:09 +04:00
if ( ! cpu_is_omap7xx ( ) )
2006-06-27 03:16:03 +04:00
omap_writew ( omap_readw ( ARM_CKCTL ) & ~ ( 1 < < EN_DSPCK ) , ARM_CKCTL ) ;
2006-04-02 20:46:25 +04:00
/* temporarily enabling api_ck to access DSP registers */
omap_writew ( omap_readw ( ARM_IDLECT2 ) | 1 < < EN_APICK , ARM_IDLECT2 ) ;
/* save DSP registers */
DSP_SAVE ( DSP_IDLECT2 ) ;
/* Stop all DSP domain clocks */
__raw_writew ( 0 , DSP_IDLECT2 ) ;
/*
* Step 5 : Wakeup Event Setup
*/
omap_pm_wakeup_setup ( ) ;
/*
* Step 6 : ARM and Traffic controller shutdown
*/
/* disable ARM watchdog */
omap_writel ( 0x00F5 , OMAP_WDT_TIMER_MODE ) ;
omap_writel ( 0x00A0 , OMAP_WDT_TIMER_MODE ) ;
/*
* Step 6 b : ARM and Traffic controller shutdown
*
* Step 6 continues here . Prepare jump to power management
* assembly code in internal SRAM .
*
* Since the omap_cpu_suspend routine has been copied to
* SRAM , we ' ll do an indirect procedure call to it and pass the
* contents of arm_idlect1 and arm_idlect2 so it can restore
* them when it wakes up and it will return .
*/
arg0 = arm_sleep_save [ ARM_SLEEP_SAVE_ARM_IDLECT1 ] ;
arg1 = arm_sleep_save [ ARM_SLEEP_SAVE_ARM_IDLECT2 ] ;
/*
* Step 6 c : ARM and Traffic controller shutdown
*
* Jump to assembly code . The processor will stay there
* until wake up .
*/
2007-05-11 02:50:16 +04:00
omap_sram_suspend ( arg0 , arg1 ) ;
2006-04-02 20:46:25 +04:00
/*
* If we are here , processor is woken up !
*/
/*
* Restore DSP clocks
*/
/* again temporarily enabling api_ck to access DSP registers */
omap_writew ( omap_readw ( ARM_IDLECT2 ) | 1 < < EN_APICK , ARM_IDLECT2 ) ;
/* Restore DSP domain clocks */
DSP_RESTORE ( DSP_IDLECT2 ) ;
/*
* Restore ARM state , except ARM_IDLECT1 / 2 which omap_cpu_suspend did
*/
if ( ! ( cpu_is_omap15xx ( ) ) )
ARM_RESTORE ( ARM_IDLECT3 ) ;
ARM_RESTORE ( ARM_CKCTL ) ;
ARM_RESTORE ( ARM_EWUPCT ) ;
ARM_RESTORE ( ARM_RSTCT1 ) ;
ARM_RESTORE ( ARM_RSTCT2 ) ;
ARM_RESTORE ( ARM_SYSST ) ;
ULPD_RESTORE ( ULPD_CLOCK_CTRL ) ;
ULPD_RESTORE ( ULPD_STATUS_REQ ) ;
2009-09-22 09:41:09 +04:00
if ( cpu_is_omap7xx ( ) ) {
2009-09-22 13:02:58 +04:00
MPUI7XX_RESTORE ( EMIFS_CONFIG ) ;
MPUI7XX_RESTORE ( EMIFF_SDRAM_CONFIG ) ;
MPUI7XX_RESTORE ( OMAP_IH1_MIR ) ;
MPUI7XX_RESTORE ( OMAP_IH2_0_MIR ) ;
MPUI7XX_RESTORE ( OMAP_IH2_1_MIR ) ;
2006-04-02 20:46:25 +04:00
} else if ( cpu_is_omap15xx ( ) ) {
MPUI1510_RESTORE ( MPUI_CTRL ) ;
MPUI1510_RESTORE ( MPUI_DSP_BOOT_CONFIG ) ;
MPUI1510_RESTORE ( MPUI_DSP_API_CONFIG ) ;
MPUI1510_RESTORE ( EMIFS_CONFIG ) ;
MPUI1510_RESTORE ( EMIFF_SDRAM_CONFIG ) ;
MPUI1510_RESTORE ( OMAP_IH1_MIR ) ;
MPUI1510_RESTORE ( OMAP_IH2_MIR ) ;
} else if ( cpu_is_omap16xx ( ) ) {
MPUI1610_RESTORE ( MPUI_CTRL ) ;
MPUI1610_RESTORE ( MPUI_DSP_BOOT_CONFIG ) ;
MPUI1610_RESTORE ( MPUI_DSP_API_CONFIG ) ;
MPUI1610_RESTORE ( EMIFS_CONFIG ) ;
MPUI1610_RESTORE ( EMIFF_SDRAM_CONFIG ) ;
MPUI1610_RESTORE ( OMAP_IH1_MIR ) ;
MPUI1610_RESTORE ( OMAP_IH2_0_MIR ) ;
MPUI1610_RESTORE ( OMAP_IH2_1_MIR ) ;
MPUI1610_RESTORE ( OMAP_IH2_2_MIR ) ;
MPUI1610_RESTORE ( OMAP_IH2_3_MIR ) ;
}
2006-12-07 04:13:48 +03:00
if ( ! cpu_is_omap15xx ( ) )
omap_writew ( 0 , ULPD_SOFT_DISABLE_REQ_REG ) ;
2006-04-02 20:46:25 +04:00
/*
2007-05-11 23:40:30 +04:00
* Re - enable interrupts
2006-04-02 20:46:25 +04:00
*/
local_irq_enable ( ) ;
local_fiq_enable ( ) ;
omap_serial_wake_trigger ( 0 ) ;
2008-12-11 04:36:31 +03:00
printk ( KERN_INFO " PM: OMAP%x is re-starting from deep sleep... \n " ,
omap_rev ( ) ) ;
2006-04-02 20:46:25 +04:00
}
2013-04-11 22:03:41 +04:00
# ifdef CONFIG_DEBUG_FS
2006-04-02 20:46:25 +04:00
/*
* Read system PM registers for debugging
*/
2013-04-11 22:03:41 +04:00
static int omap_pm_debug_show ( struct seq_file * m , void * v )
2006-04-02 20:46:25 +04:00
{
ARM_SAVE ( ARM_CKCTL ) ;
ARM_SAVE ( ARM_IDLECT1 ) ;
ARM_SAVE ( ARM_IDLECT2 ) ;
if ( ! ( cpu_is_omap15xx ( ) ) )
ARM_SAVE ( ARM_IDLECT3 ) ;
ARM_SAVE ( ARM_EWUPCT ) ;
ARM_SAVE ( ARM_RSTCT1 ) ;
ARM_SAVE ( ARM_RSTCT2 ) ;
ARM_SAVE ( ARM_SYSST ) ;
ULPD_SAVE ( ULPD_IT_STATUS ) ;
ULPD_SAVE ( ULPD_CLOCK_CTRL ) ;
ULPD_SAVE ( ULPD_SOFT_REQ ) ;
ULPD_SAVE ( ULPD_STATUS_REQ ) ;
ULPD_SAVE ( ULPD_DPLL_CTRL ) ;
ULPD_SAVE ( ULPD_POWER_CTRL ) ;
2009-09-22 09:41:09 +04:00
if ( cpu_is_omap7xx ( ) ) {
2009-09-22 13:02:58 +04:00
MPUI7XX_SAVE ( MPUI_CTRL ) ;
MPUI7XX_SAVE ( MPUI_DSP_STATUS ) ;
MPUI7XX_SAVE ( MPUI_DSP_BOOT_CONFIG ) ;
MPUI7XX_SAVE ( MPUI_DSP_API_CONFIG ) ;
MPUI7XX_SAVE ( EMIFF_SDRAM_CONFIG ) ;
MPUI7XX_SAVE ( EMIFS_CONFIG ) ;
2006-04-02 20:46:25 +04:00
} else if ( cpu_is_omap15xx ( ) ) {
MPUI1510_SAVE ( MPUI_CTRL ) ;
MPUI1510_SAVE ( MPUI_DSP_STATUS ) ;
MPUI1510_SAVE ( MPUI_DSP_BOOT_CONFIG ) ;
MPUI1510_SAVE ( MPUI_DSP_API_CONFIG ) ;
MPUI1510_SAVE ( EMIFF_SDRAM_CONFIG ) ;
MPUI1510_SAVE ( EMIFS_CONFIG ) ;
} else if ( cpu_is_omap16xx ( ) ) {
MPUI1610_SAVE ( MPUI_CTRL ) ;
MPUI1610_SAVE ( MPUI_DSP_STATUS ) ;
MPUI1610_SAVE ( MPUI_DSP_BOOT_CONFIG ) ;
MPUI1610_SAVE ( MPUI_DSP_API_CONFIG ) ;
MPUI1610_SAVE ( EMIFF_SDRAM_CONFIG ) ;
MPUI1610_SAVE ( EMIFS_CONFIG ) ;
}
2013-04-11 22:03:41 +04:00
seq_printf ( m ,
2006-04-02 20:46:25 +04:00
" ARM_CKCTL_REG: 0x%-8x \n "
" ARM_IDLECT1_REG: 0x%-8x \n "
" ARM_IDLECT2_REG: 0x%-8x \n "
" ARM_IDLECT3_REG: 0x%-8x \n "
" ARM_EWUPCT_REG: 0x%-8x \n "
" ARM_RSTCT1_REG: 0x%-8x \n "
" ARM_RSTCT2_REG: 0x%-8x \n "
" ARM_SYSST_REG: 0x%-8x \n "
" ULPD_IT_STATUS_REG: 0x%-4x \n "
" ULPD_CLOCK_CTRL_REG: 0x%-4x \n "
" ULPD_SOFT_REQ_REG: 0x%-4x \n "
" ULPD_DPLL_CTRL_REG: 0x%-4x \n "
" ULPD_STATUS_REQ_REG: 0x%-4x \n "
" ULPD_POWER_CTRL_REG: 0x%-4x \n " ,
ARM_SHOW ( ARM_CKCTL ) ,
ARM_SHOW ( ARM_IDLECT1 ) ,
ARM_SHOW ( ARM_IDLECT2 ) ,
ARM_SHOW ( ARM_IDLECT3 ) ,
ARM_SHOW ( ARM_EWUPCT ) ,
ARM_SHOW ( ARM_RSTCT1 ) ,
ARM_SHOW ( ARM_RSTCT2 ) ,
ARM_SHOW ( ARM_SYSST ) ,
ULPD_SHOW ( ULPD_IT_STATUS ) ,
ULPD_SHOW ( ULPD_CLOCK_CTRL ) ,
ULPD_SHOW ( ULPD_SOFT_REQ ) ,
ULPD_SHOW ( ULPD_DPLL_CTRL ) ,
ULPD_SHOW ( ULPD_STATUS_REQ ) ,
ULPD_SHOW ( ULPD_POWER_CTRL ) ) ;
2013-04-11 22:03:41 +04:00
if ( cpu_is_omap7xx ( ) ) {
seq_printf ( m ,
2009-09-22 13:02:58 +04:00
" MPUI7XX_CTRL_REG 0x%-8x \n "
" MPUI7XX_DSP_STATUS_REG: 0x%-8x \n "
" MPUI7XX_DSP_BOOT_CONFIG_REG: 0x%-8x \n "
" MPUI7XX_DSP_API_CONFIG_REG: 0x%-8x \n "
" MPUI7XX_SDRAM_CONFIG_REG: 0x%-8x \n "
" MPUI7XX_EMIFS_CONFIG_REG: 0x%-8x \n " ,
MPUI7XX_SHOW ( MPUI_CTRL ) ,
MPUI7XX_SHOW ( MPUI_DSP_STATUS ) ,
MPUI7XX_SHOW ( MPUI_DSP_BOOT_CONFIG ) ,
MPUI7XX_SHOW ( MPUI_DSP_API_CONFIG ) ,
MPUI7XX_SHOW ( EMIFF_SDRAM_CONFIG ) ,
MPUI7XX_SHOW ( EMIFS_CONFIG ) ) ;
2013-04-11 22:03:41 +04:00
} else if ( cpu_is_omap15xx ( ) ) {
seq_printf ( m ,
2006-04-02 20:46:25 +04:00
" MPUI1510_CTRL_REG 0x%-8x \n "
" MPUI1510_DSP_STATUS_REG: 0x%-8x \n "
" MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n "
" MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n "
" MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n "
" MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n " ,
MPUI1510_SHOW ( MPUI_CTRL ) ,
MPUI1510_SHOW ( MPUI_DSP_STATUS ) ,
MPUI1510_SHOW ( MPUI_DSP_BOOT_CONFIG ) ,
MPUI1510_SHOW ( MPUI_DSP_API_CONFIG ) ,
MPUI1510_SHOW ( EMIFF_SDRAM_CONFIG ) ,
MPUI1510_SHOW ( EMIFS_CONFIG ) ) ;
2013-04-11 22:03:41 +04:00
} else if ( cpu_is_omap16xx ( ) ) {
seq_printf ( m ,
2006-04-02 20:46:25 +04:00
" MPUI1610_CTRL_REG 0x%-8x \n "
" MPUI1610_DSP_STATUS_REG: 0x%-8x \n "
" MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n "
" MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n "
" MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n "
" MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n " ,
MPUI1610_SHOW ( MPUI_CTRL ) ,
MPUI1610_SHOW ( MPUI_DSP_STATUS ) ,
MPUI1610_SHOW ( MPUI_DSP_BOOT_CONFIG ) ,
MPUI1610_SHOW ( MPUI_DSP_API_CONFIG ) ,
MPUI1610_SHOW ( EMIFF_SDRAM_CONFIG ) ,
MPUI1610_SHOW ( EMIFS_CONFIG ) ) ;
}
2013-04-11 22:03:41 +04:00
return 0 ;
}
2018-11-06 17:35:16 +03:00
DEFINE_SHOW_ATTRIBUTE ( omap_pm_debug ) ;
2013-04-11 22:03:41 +04:00
static void omap_pm_init_debugfs ( void )
2006-04-02 20:46:25 +04:00
{
2013-04-11 22:03:41 +04:00
struct dentry * d ;
d = debugfs_create_dir ( " pm_debug " , NULL ) ;
if ( ! d )
return ;
( void ) debugfs_create_file ( " omap_pm " , S_IWUSR | S_IRUGO ,
d , NULL , & omap_pm_debug_fops ) ;
2006-04-02 20:46:25 +04:00
}
2013-04-11 22:03:41 +04:00
# endif /* CONFIG_DEBUG_FS */
2006-04-02 20:46:25 +04:00
/*
* omap_pm_prepare - Do preliminary suspend work .
*
*/
2007-10-18 14:04:41 +04:00
static int omap_pm_prepare ( void )
2006-04-02 20:46:25 +04:00
{
/* We cannot sleep in idle until we have resumed */
2013-03-22 01:49:38 +04:00
cpu_idle_poll_ctrl ( true ) ;
2007-10-18 14:04:41 +04:00
return 0 ;
2006-04-02 20:46:25 +04:00
}
/*
* omap_pm_enter - Actually enter a sleep state .
* @ state : State we ' re entering .
*
*/
static int omap_pm_enter ( suspend_state_t state )
{
switch ( state )
{
case PM_SUSPEND_MEM :
2009-05-15 22:29:28 +04:00
omap1_pm_suspend ( ) ;
2006-04-02 20:46:25 +04:00
break ;
default :
return - EINVAL ;
}
return 0 ;
}
/**
* omap_pm_finish - Finish up suspend sequence .
*
* This is called after we wake back up ( or if entering the sleep state
* failed ) .
*/
2007-10-18 14:04:41 +04:00
static void omap_pm_finish ( void )
2006-04-02 20:46:25 +04:00
{
2013-03-22 01:49:38 +04:00
cpu_idle_poll_ctrl ( false ) ;
2006-04-02 20:46:25 +04:00
}
2007-10-26 13:40:25 +04:00
static irqreturn_t omap_wakeup_interrupt ( int irq , void * dev )
2006-04-02 20:46:25 +04:00
{
return IRQ_HANDLED ;
}
static struct irqaction omap_wakeup_irq = {
. name = " peripheral wakeup " ,
. handler = omap_wakeup_interrupt
} ;
2010-11-16 16:14:02 +03:00
static const struct platform_suspend_ops omap_pm_ops = {
2006-04-02 20:46:25 +04:00
. prepare = omap_pm_prepare ,
. enter = omap_pm_enter ,
. finish = omap_pm_finish ,
2007-10-18 14:04:40 +04:00
. valid = suspend_valid_only_mem ,
2006-04-02 20:46:25 +04:00
} ;
static int __init omap_pm_init ( void )
{
2015-02-07 01:56:07 +03:00
int error = 0 ;
2006-12-07 04:14:04 +03:00
2010-12-10 20:46:24 +03:00
if ( ! cpu_class_is_omap1 ( ) )
return - ENODEV ;
2015-02-07 01:56:07 +03:00
pr_info ( " Power Management for TI OMAP. \n " ) ;
if ( ! IS_ENABLED ( CONFIG_OMAP_32K_TIMER ) )
pr_info ( " OMAP1 PM: sleep states in idle disabled due to no 32KiHz timer \n " ) ;
if ( ! IS_ENABLED ( CONFIG_OMAP_DM_TIMER ) )
pr_info ( " OMAP1 PM: sleep states in idle disabled due to no DMTIMER support \n " ) ;
if ( IS_ENABLED ( CONFIG_OMAP_32K_TIMER ) & &
IS_ENABLED ( CONFIG_OMAP_DM_TIMER ) ) {
/* OMAP16xx only */
pr_info ( " OMAP1 PM: sleep states in idle enabled \n " ) ;
enable_dyn_sleep = 1 ;
}
2006-04-02 20:46:25 +04:00
/*
* We copy the assembler sleep / wakeup routines to SRAM .
* These routines need to be in SRAM as that ' s the only
* memory the MPU can see when it wakes up .
*/
2009-09-22 09:41:09 +04:00
if ( cpu_is_omap7xx ( ) ) {
2009-09-22 13:02:58 +04:00
omap_sram_suspend = omap_sram_push ( omap7xx_cpu_suspend ,
omap7xx_cpu_suspend_sz ) ;
2006-04-02 20:46:25 +04:00
} else if ( cpu_is_omap15xx ( ) ) {
omap_sram_suspend = omap_sram_push ( omap1510_cpu_suspend ,
omap1510_cpu_suspend_sz ) ;
} else if ( cpu_is_omap16xx ( ) ) {
omap_sram_suspend = omap_sram_push ( omap1610_cpu_suspend ,
omap1610_cpu_suspend_sz ) ;
}
2007-12-17 12:56:33 +03:00
if ( omap_sram_suspend = = NULL ) {
2006-04-02 20:46:25 +04:00
printk ( KERN_ERR " PM not initialized: Missing SRAM support \n " ) ;
return - ENODEV ;
}
2012-01-05 01:27:48 +04:00
arm_pm_idle = omap1_pm_idle ;
2006-04-02 20:46:25 +04:00
2009-09-22 09:41:09 +04:00
if ( cpu_is_omap7xx ( ) )
2009-09-18 07:09:39 +04:00
setup_irq ( INT_7XX_WAKE_UP_REQ , & omap_wakeup_irq ) ;
2006-04-02 20:46:25 +04:00
else if ( cpu_is_omap16xx ( ) )
setup_irq ( INT_1610_WAKE_UP_REQ , & omap_wakeup_irq ) ;
/* Program new power ramp-up time
* ( 0 for most boards since we don ' t lower voltage when in deep sleep )
*/
omap_writew ( ULPD_SETUP_ANALOG_CELL_3_VAL , ULPD_SETUP_ANALOG_CELL_3 ) ;
/* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
omap_writew ( ULPD_POWER_CTRL_REG_VAL , ULPD_POWER_CTRL ) ;
/* Configure IDLECT3 */
2009-09-22 09:41:09 +04:00
if ( cpu_is_omap7xx ( ) )
2009-09-22 13:02:58 +04:00
omap_writel ( OMAP7XX_IDLECT3_VAL , OMAP7XX_IDLECT3 ) ;
2006-04-02 20:46:25 +04:00
else if ( cpu_is_omap16xx ( ) )
omap_writel ( OMAP1610_IDLECT3_VAL , OMAP1610_IDLECT3 ) ;
2007-10-18 14:04:40 +04:00
suspend_set_ops ( & omap_pm_ops ) ;
2006-04-02 20:46:25 +04:00
2013-04-11 22:03:41 +04:00
# ifdef CONFIG_DEBUG_FS
omap_pm_init_debugfs ( ) ;
2006-04-02 20:46:25 +04:00
# endif
2008-02-25 06:08:26 +03:00
error = sysfs_create_file ( power_kobj , & sleep_while_idle_attr . attr ) ;
2006-12-07 04:14:04 +03:00
if ( error )
2007-11-02 23:20:40 +03:00
printk ( KERN_ERR " sysfs_create_file failed: %d \n " , error ) ;
2006-04-02 20:46:25 +04:00
if ( cpu_is_omap16xx ( ) ) {
/* configure LOW_PWR pin */
omap_cfg_reg ( T20_1610_LOW_PWR ) ;
}
2015-02-07 01:56:07 +03:00
return error ;
2006-04-02 20:46:25 +04:00
}
__initcall ( omap_pm_init ) ;