2010-12-22 06:01:18 +03:00
/*
* OMAP4 powerdomain control
*
2012-09-24 03:28:19 +04:00
* Copyright ( C ) 2009 - 2010 , 2012 Texas Instruments , Inc .
2010-12-22 06:01:18 +03:00
* Copyright ( C ) 2007 - 2009 Nokia Corporation
*
* Derived from mach - omap2 / powerdomain . c written by Paul Walmsley
* Rajendra Nayak < rnayak @ ti . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/io.h>
# include <linux/errno.h>
# include <linux/delay.h>
2012-03-08 22:20:14 +04:00
# include <linux/bug.h>
2010-12-22 06:01:20 +03:00
2010-12-22 07:05:16 +03:00
# include "powerdomain.h"
2010-12-22 06:01:18 +03:00
# include <plat/prcm.h>
2010-12-22 01:30:55 +03:00
# include "prm2xxx_3xxx.h"
2010-12-22 01:30:54 +03:00
# include "prm44xx.h"
2010-12-22 07:05:14 +03:00
# include "prminst44xx.h"
2010-12-22 06:01:18 +03:00
# include "prm-regbits-44xx.h"
static int omap4_pwrdm_set_next_pwrst ( struct powerdomain * pwrdm , u8 pwrst )
{
2010-12-22 07:05:14 +03:00
omap4_prminst_rmw_inst_reg_bits ( OMAP_POWERSTATE_MASK ,
( pwrst < < OMAP_POWERSTATE_SHIFT ) ,
pwrdm - > prcm_partition ,
pwrdm - > prcm_offs , OMAP4_PM_PWSTCTRL ) ;
2010-12-22 06:01:18 +03:00
return 0 ;
}
static int omap4_pwrdm_read_next_pwrst ( struct powerdomain * pwrdm )
{
2010-12-22 07:05:14 +03:00
u32 v ;
v = omap4_prminst_read_inst_reg ( pwrdm - > prcm_partition , pwrdm - > prcm_offs ,
OMAP4_PM_PWSTCTRL ) ;
v & = OMAP_POWERSTATE_MASK ;
v > > = OMAP_POWERSTATE_SHIFT ;
return v ;
2010-12-22 06:01:18 +03:00
}
static int omap4_pwrdm_read_pwrst ( struct powerdomain * pwrdm )
{
2010-12-22 07:05:14 +03:00
u32 v ;
v = omap4_prminst_read_inst_reg ( pwrdm - > prcm_partition , pwrdm - > prcm_offs ,
OMAP4_PM_PWSTST ) ;
v & = OMAP_POWERSTATEST_MASK ;
v > > = OMAP_POWERSTATEST_SHIFT ;
return v ;
2010-12-22 06:01:18 +03:00
}
static int omap4_pwrdm_read_prev_pwrst ( struct powerdomain * pwrdm )
{
2010-12-22 07:05:14 +03:00
u32 v ;
v = omap4_prminst_read_inst_reg ( pwrdm - > prcm_partition , pwrdm - > prcm_offs ,
OMAP4_PM_PWSTST ) ;
v & = OMAP4430_LASTPOWERSTATEENTERED_MASK ;
v > > = OMAP4430_LASTPOWERSTATEENTERED_SHIFT ;
return v ;
2010-12-22 06:01:18 +03:00
}
2010-12-22 06:01:19 +03:00
static int omap4_pwrdm_set_lowpwrstchange ( struct powerdomain * pwrdm )
{
2010-12-22 07:05:14 +03:00
omap4_prminst_rmw_inst_reg_bits ( OMAP4430_LOWPOWERSTATECHANGE_MASK ,
( 1 < < OMAP4430_LOWPOWERSTATECHANGE_SHIFT ) ,
pwrdm - > prcm_partition ,
pwrdm - > prcm_offs , OMAP4_PM_PWSTCTRL ) ;
2010-12-22 06:01:19 +03:00
return 0 ;
}
2010-12-22 06:01:19 +03:00
static int omap4_pwrdm_clear_all_prev_pwrst ( struct powerdomain * pwrdm )
{
2010-12-22 07:05:14 +03:00
omap4_prminst_rmw_inst_reg_bits ( OMAP4430_LASTPOWERSTATEENTERED_MASK ,
OMAP4430_LASTPOWERSTATEENTERED_MASK ,
pwrdm - > prcm_partition ,
pwrdm - > prcm_offs , OMAP4_PM_PWSTST ) ;
2010-12-22 06:01:19 +03:00
return 0 ;
}
2010-12-22 06:01:18 +03:00
static int omap4_pwrdm_set_logic_retst ( struct powerdomain * pwrdm , u8 pwrst )
{
u32 v ;
v = pwrst < < __ffs ( OMAP4430_LOGICRETSTATE_MASK ) ;
2010-12-22 07:05:14 +03:00
omap4_prminst_rmw_inst_reg_bits ( OMAP4430_LOGICRETSTATE_MASK , v ,
pwrdm - > prcm_partition , pwrdm - > prcm_offs ,
OMAP4_PM_PWSTCTRL ) ;
2010-12-22 06:01:18 +03:00
return 0 ;
}
2010-12-22 06:01:19 +03:00
static int omap4_pwrdm_set_mem_onst ( struct powerdomain * pwrdm , u8 bank ,
2010-12-22 07:05:14 +03:00
u8 pwrst )
2010-12-22 06:01:19 +03:00
{
u32 m ;
m = omap2_pwrdm_get_mem_bank_onstate_mask ( bank ) ;
2010-12-22 07:05:14 +03:00
omap4_prminst_rmw_inst_reg_bits ( m , ( pwrst < < __ffs ( m ) ) ,
pwrdm - > prcm_partition , pwrdm - > prcm_offs ,
OMAP4_PM_PWSTCTRL ) ;
2010-12-22 06:01:19 +03:00
return 0 ;
}
static int omap4_pwrdm_set_mem_retst ( struct powerdomain * pwrdm , u8 bank ,
2010-12-22 07:05:14 +03:00
u8 pwrst )
2010-12-22 06:01:19 +03:00
{
u32 m ;
m = omap2_pwrdm_get_mem_bank_retst_mask ( bank ) ;
2010-12-22 07:05:14 +03:00
omap4_prminst_rmw_inst_reg_bits ( m , ( pwrst < < __ffs ( m ) ) ,
pwrdm - > prcm_partition , pwrdm - > prcm_offs ,
OMAP4_PM_PWSTCTRL ) ;
2010-12-22 06:01:19 +03:00
return 0 ;
}
2010-12-22 06:01:18 +03:00
static int omap4_pwrdm_read_logic_pwrst ( struct powerdomain * pwrdm )
{
2010-12-22 07:05:14 +03:00
u32 v ;
v = omap4_prminst_read_inst_reg ( pwrdm - > prcm_partition , pwrdm - > prcm_offs ,
OMAP4_PM_PWSTST ) ;
v & = OMAP4430_LOGICSTATEST_MASK ;
v > > = OMAP4430_LOGICSTATEST_SHIFT ;
return v ;
2010-12-22 06:01:18 +03:00
}
static int omap4_pwrdm_read_logic_retst ( struct powerdomain * pwrdm )
{
2010-12-22 07:05:14 +03:00
u32 v ;
v = omap4_prminst_read_inst_reg ( pwrdm - > prcm_partition , pwrdm - > prcm_offs ,
OMAP4_PM_PWSTCTRL ) ;
v & = OMAP4430_LOGICRETSTATE_MASK ;
v > > = OMAP4430_LOGICRETSTATE_SHIFT ;
return v ;
2010-12-22 06:01:18 +03:00
}
2012-09-24 03:28:19 +04:00
/**
* omap4_pwrdm_read_prev_logic_pwrst - read the previous logic powerstate
* @ pwrdm : struct powerdomain * to read the state for
*
* Reads the previous logic powerstate for a powerdomain . This
* function must determine the previous logic powerstate by first
* checking the previous powerstate for the domain . If that was OFF ,
* then logic has been lost . If previous state was RETENTION , the
* function reads the setting for the next retention logic state to
* see the actual value . In every other case , the logic is
* retained . Returns either PWRDM_POWER_OFF or PWRDM_POWER_RET
* depending whether the logic was retained or not .
*/
static int omap4_pwrdm_read_prev_logic_pwrst ( struct powerdomain * pwrdm )
{
int state ;
state = omap4_pwrdm_read_prev_pwrst ( pwrdm ) ;
if ( state = = PWRDM_POWER_OFF )
return PWRDM_POWER_OFF ;
if ( state ! = PWRDM_POWER_RET )
return PWRDM_POWER_RET ;
return omap4_pwrdm_read_logic_retst ( pwrdm ) ;
}
2010-12-22 06:01:19 +03:00
static int omap4_pwrdm_read_mem_pwrst ( struct powerdomain * pwrdm , u8 bank )
{
2010-12-22 07:05:14 +03:00
u32 m , v ;
2010-12-22 06:01:19 +03:00
m = omap2_pwrdm_get_mem_bank_stst_mask ( bank ) ;
2010-12-22 07:05:14 +03:00
v = omap4_prminst_read_inst_reg ( pwrdm - > prcm_partition , pwrdm - > prcm_offs ,
OMAP4_PM_PWSTST ) ;
v & = m ;
v > > = __ffs ( m ) ;
return v ;
2010-12-22 06:01:19 +03:00
}
static int omap4_pwrdm_read_mem_retst ( struct powerdomain * pwrdm , u8 bank )
{
2010-12-22 07:05:14 +03:00
u32 m , v ;
2010-12-22 06:01:19 +03:00
m = omap2_pwrdm_get_mem_bank_retst_mask ( bank ) ;
2010-12-22 07:05:14 +03:00
v = omap4_prminst_read_inst_reg ( pwrdm - > prcm_partition , pwrdm - > prcm_offs ,
OMAP4_PM_PWSTCTRL ) ;
v & = m ;
v > > = __ffs ( m ) ;
return v ;
2010-12-22 06:01:19 +03:00
}
2012-09-24 03:28:19 +04:00
/**
* omap4_pwrdm_read_prev_mem_pwrst - reads the previous memory powerstate
* @ pwrdm : struct powerdomain * to read mem powerstate for
* @ bank : memory bank index
*
* Reads the previous memory powerstate for a powerdomain . This
* function must determine the previous memory powerstate by first
* checking the previous powerstate for the domain . If that was OFF ,
* then logic has been lost . If previous state was RETENTION , the
* function reads the setting for the next memory retention state to
* see the actual value . In every other case , the logic is
* retained . Returns either PWRDM_POWER_OFF or PWRDM_POWER_RET
* depending whether logic was retained or not .
*/
static int omap4_pwrdm_read_prev_mem_pwrst ( struct powerdomain * pwrdm , u8 bank )
{
int state ;
state = omap4_pwrdm_read_prev_pwrst ( pwrdm ) ;
if ( state = = PWRDM_POWER_OFF )
return PWRDM_POWER_OFF ;
if ( state ! = PWRDM_POWER_RET )
return PWRDM_POWER_RET ;
return omap4_pwrdm_read_mem_retst ( pwrdm , bank ) ;
}
2010-12-22 06:01:19 +03:00
static int omap4_pwrdm_wait_transition ( struct powerdomain * pwrdm )
{
u32 c = 0 ;
/*
* REVISIT : pwrdm_wait_transition ( ) may be better implemented
* via a callback and a periodic timer check - - how long do we expect
* powerdomain transitions to take ?
*/
/* XXX Is this udelay() value meaningful? */
2010-12-22 07:05:14 +03:00
while ( ( omap4_prminst_read_inst_reg ( pwrdm - > prcm_partition ,
pwrdm - > prcm_offs ,
OMAP4_PM_PWSTST ) &
2010-12-22 06:01:19 +03:00
OMAP_INTRANSITION_MASK ) & &
2010-12-22 07:05:14 +03:00
( c + + < PWRDM_TRANSITION_BAILOUT ) )
udelay ( 1 ) ;
2010-12-22 06:01:19 +03:00
if ( c > PWRDM_TRANSITION_BAILOUT ) {
2012-07-26 10:54:26 +04:00
pr_err ( " powerdomain: %s: waited too long to complete transition \n " ,
pwrdm - > name ) ;
2010-12-22 06:01:19 +03:00
return - EAGAIN ;
}
pr_debug ( " powerdomain: completed transition in %d loops \n " , c ) ;
return 0 ;
}
2010-12-22 06:01:18 +03:00
struct pwrdm_ops omap4_pwrdm_operations = {
. pwrdm_set_next_pwrst = omap4_pwrdm_set_next_pwrst ,
. pwrdm_read_next_pwrst = omap4_pwrdm_read_next_pwrst ,
. pwrdm_read_pwrst = omap4_pwrdm_read_pwrst ,
. pwrdm_read_prev_pwrst = omap4_pwrdm_read_prev_pwrst ,
2010-12-22 06:01:19 +03:00
. pwrdm_set_lowpwrstchange = omap4_pwrdm_set_lowpwrstchange ,
2010-12-22 06:01:19 +03:00
. pwrdm_clear_all_prev_pwrst = omap4_pwrdm_clear_all_prev_pwrst ,
2010-12-22 06:01:18 +03:00
. pwrdm_set_logic_retst = omap4_pwrdm_set_logic_retst ,
. pwrdm_read_logic_pwrst = omap4_pwrdm_read_logic_pwrst ,
2012-09-24 03:28:19 +04:00
. pwrdm_read_prev_logic_pwrst = omap4_pwrdm_read_prev_logic_pwrst ,
2010-12-22 06:01:18 +03:00
. pwrdm_read_logic_retst = omap4_pwrdm_read_logic_retst ,
2010-12-22 06:01:19 +03:00
. pwrdm_read_mem_pwrst = omap4_pwrdm_read_mem_pwrst ,
. pwrdm_read_mem_retst = omap4_pwrdm_read_mem_retst ,
2012-09-24 03:28:19 +04:00
. pwrdm_read_prev_mem_pwrst = omap4_pwrdm_read_prev_mem_pwrst ,
2010-12-22 06:01:19 +03:00
. pwrdm_set_mem_onst = omap4_pwrdm_set_mem_onst ,
. pwrdm_set_mem_retst = omap4_pwrdm_set_mem_retst ,
. pwrdm_wait_transition = omap4_pwrdm_wait_transition ,
2010-12-22 06:01:18 +03:00
} ;