2012-10-21 01:01:10 -06:00
/*
* OMAP2xxx PRM module functions
*
* Copyright ( C ) 2010 - 2012 Texas Instruments , Inc .
* Copyright ( C ) 2010 Nokia Corporation
* Benoît Cousson
* 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/kernel.h>
# include <linux/errno.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/irq.h>
2012-12-16 11:29:58 -08:00
# include "soc.h"
2012-10-21 01:01:10 -06:00
# include "common.h"
# include "vp.h"
# include "powerdomain.h"
2012-10-21 01:01:11 -06:00
# include "clockdomain.h"
2012-10-21 01:01:10 -06:00
# include "prm2xxx.h"
# include "cm2xxx_3xxx.h"
# include "prm-regbits-24xx.h"
ARM: OMAP2/3: PRM: fix bogus OMAP2xxx powerstate return values
On OMAP2xxx chips, the register bitfields for the
PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED are
different than those used on OMAP3/4. The order is reversed. So, for
example, on OMAP2xxx, 0x0 indicates 'ON'; but on OMAP3/4, 0x0
indicates 'OFF'. Similarly, on OMAP2xxx, 0x3 indicates 'OFF', but on
OMAP3/4, 0x3 indicates 'ON'.
To fix this, we treat the OMAP3/4 values as the powerdomain API
values, and create new low-level powerdomain functions for the
OMAP2xxx chips which translate between the OMAP2xxx values and the
OMAP3/4 values.
Without this patch, the conversion of the OMAP2xxx PM code to the
functional powerstate code results in a non-booting kernel.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
2012-12-28 02:10:44 -07:00
/*
* OMAP24xx PM_PWSTCTRL_ * . POWERSTATE and PM_PWSTST_ * . LASTSTATEENTERED bits -
* these are reversed from the bits used on OMAP3 +
*/
# define OMAP24XX_PWRDM_POWER_ON 0x0
# define OMAP24XX_PWRDM_POWER_RET 0x1
# define OMAP24XX_PWRDM_POWER_OFF 0x3
2012-10-21 01:01:13 -06:00
/*
* omap2xxx_prm_reset_src_map - map from bits in the PRM_RSTST_WKUP
* hardware register ( which are specific to the OMAP2xxx SoCs ) to
* reset source ID bit shifts ( which is an OMAP SoC - independent
* enumeration )
*/
static struct prm_reset_src_map omap2xxx_prm_reset_src_map [ ] = {
{ OMAP_GLOBALCOLD_RST_SHIFT , OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT } ,
{ OMAP_GLOBALWARM_RST_SHIFT , OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT } ,
{ OMAP24XX_SECU_VIOL_RST_SHIFT , OMAP_SECU_VIOL_RST_SRC_ID_SHIFT } ,
{ OMAP24XX_MPU_WD_RST_SHIFT , OMAP_MPU_WD_RST_SRC_ID_SHIFT } ,
{ OMAP24XX_SECU_WD_RST_SHIFT , OMAP_SECU_WD_RST_SRC_ID_SHIFT } ,
{ OMAP24XX_EXTWMPU_RST_SHIFT , OMAP_EXTWARM_RST_SRC_ID_SHIFT } ,
{ - 1 , - 1 } ,
} ;
/**
* omap2xxx_prm_read_reset_sources - return the last SoC reset source
*
* Return a u32 representing the last reset sources of the SoC . The
* returned reset source bits are standardized across OMAP SoCs .
*/
static u32 omap2xxx_prm_read_reset_sources ( void )
{
struct prm_reset_src_map * p ;
u32 r = 0 ;
u32 v ;
v = omap2_prm_read_mod_reg ( WKUP_MOD , OMAP2_RM_RSTST ) ;
p = omap2xxx_prm_reset_src_map ;
while ( p - > reg_shift > = 0 & & p - > std_shift > = 0 ) {
if ( v & ( 1 < < p - > reg_shift ) )
r | = 1 < < p - > std_shift ;
p + + ;
}
return r ;
}
ARM: OMAP2/3: PRM: fix bogus OMAP2xxx powerstate return values
On OMAP2xxx chips, the register bitfields for the
PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED are
different than those used on OMAP3/4. The order is reversed. So, for
example, on OMAP2xxx, 0x0 indicates 'ON'; but on OMAP3/4, 0x0
indicates 'OFF'. Similarly, on OMAP2xxx, 0x3 indicates 'OFF', but on
OMAP3/4, 0x3 indicates 'ON'.
To fix this, we treat the OMAP3/4 values as the powerdomain API
values, and create new low-level powerdomain functions for the
OMAP2xxx chips which translate between the OMAP2xxx values and the
OMAP3/4 values.
Without this patch, the conversion of the OMAP2xxx PM code to the
functional powerstate code results in a non-booting kernel.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
2012-12-28 02:10:44 -07:00
/**
* omap2xxx_pwrst_to_common_pwrst - convert OMAP2xxx pwrst to common pwrst
* @ omap2xxx_pwrst : OMAP2xxx hardware power state to convert
*
* Return the common power state bits corresponding to the OMAP2xxx
* hardware power state bits @ omap2xxx_pwrst , or - EINVAL upon error .
*/
static int omap2xxx_pwrst_to_common_pwrst ( u8 omap2xxx_pwrst )
{
u8 pwrst ;
switch ( omap2xxx_pwrst ) {
case OMAP24XX_PWRDM_POWER_OFF :
pwrst = PWRDM_POWER_OFF ;
break ;
case OMAP24XX_PWRDM_POWER_RET :
pwrst = PWRDM_POWER_RET ;
break ;
case OMAP24XX_PWRDM_POWER_ON :
pwrst = PWRDM_POWER_ON ;
break ;
default :
return - EINVAL ;
}
return pwrst ;
}
2012-10-29 20:55:46 -06:00
/**
* omap2xxx_prm_dpll_reset - use DPLL reset to reboot the OMAP SoC
*
* Set the DPLL reset bit , which should reboot the SoC . This is the
* recommended way to restart the SoC . No return value .
*/
void omap2xxx_prm_dpll_reset ( void )
{
omap2_prm_set_mod_reg_bits ( OMAP_RST_DPLL3_MASK , WKUP_MOD ,
OMAP2_RM_RSTCTRL ) ;
/* OCP barrier */
omap2_prm_read_mod_reg ( WKUP_MOD , OMAP2_RM_RSTCTRL ) ;
}
2012-10-21 01:01:11 -06:00
int omap2xxx_clkdm_sleep ( struct clockdomain * clkdm )
{
omap2_prm_set_mod_reg_bits ( OMAP24XX_FORCESTATE_MASK ,
clkdm - > pwrdm . ptr - > prcm_offs ,
OMAP2_PM_PWSTCTRL ) ;
return 0 ;
}
int omap2xxx_clkdm_wakeup ( struct clockdomain * clkdm )
{
omap2_prm_clear_mod_reg_bits ( OMAP24XX_FORCESTATE_MASK ,
clkdm - > pwrdm . ptr - > prcm_offs ,
OMAP2_PM_PWSTCTRL ) ;
return 0 ;
}
ARM: OMAP2/3: PRM: fix bogus OMAP2xxx powerstate return values
On OMAP2xxx chips, the register bitfields for the
PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED are
different than those used on OMAP3/4. The order is reversed. So, for
example, on OMAP2xxx, 0x0 indicates 'ON'; but on OMAP3/4, 0x0
indicates 'OFF'. Similarly, on OMAP2xxx, 0x3 indicates 'OFF', but on
OMAP3/4, 0x3 indicates 'ON'.
To fix this, we treat the OMAP3/4 values as the powerdomain API
values, and create new low-level powerdomain functions for the
OMAP2xxx chips which translate between the OMAP2xxx values and the
OMAP3/4 values.
Without this patch, the conversion of the OMAP2xxx PM code to the
functional powerstate code results in a non-booting kernel.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
2012-12-28 02:10:44 -07:00
static int omap2xxx_pwrdm_set_next_pwrst ( struct powerdomain * pwrdm , u8 pwrst )
{
u8 omap24xx_pwrst ;
switch ( pwrst ) {
case PWRDM_POWER_OFF :
omap24xx_pwrst = OMAP24XX_PWRDM_POWER_OFF ;
break ;
case PWRDM_POWER_RET :
omap24xx_pwrst = OMAP24XX_PWRDM_POWER_RET ;
break ;
case PWRDM_POWER_ON :
omap24xx_pwrst = OMAP24XX_PWRDM_POWER_ON ;
break ;
default :
return - EINVAL ;
}
omap2_prm_rmw_mod_reg_bits ( OMAP_POWERSTATE_MASK ,
( omap24xx_pwrst < < OMAP_POWERSTATE_SHIFT ) ,
pwrdm - > prcm_offs , OMAP2_PM_PWSTCTRL ) ;
return 0 ;
}
static int omap2xxx_pwrdm_read_next_pwrst ( struct powerdomain * pwrdm )
{
u8 omap2xxx_pwrst ;
omap2xxx_pwrst = omap2_prm_read_mod_bits_shift ( pwrdm - > prcm_offs ,
OMAP2_PM_PWSTCTRL ,
OMAP_POWERSTATE_MASK ) ;
return omap2xxx_pwrst_to_common_pwrst ( omap2xxx_pwrst ) ;
}
static int omap2xxx_pwrdm_read_pwrst ( struct powerdomain * pwrdm )
{
u8 omap2xxx_pwrst ;
omap2xxx_pwrst = omap2_prm_read_mod_bits_shift ( pwrdm - > prcm_offs ,
OMAP2_PM_PWSTST ,
OMAP_POWERSTATEST_MASK ) ;
return omap2xxx_pwrst_to_common_pwrst ( omap2xxx_pwrst ) ;
}
2012-10-21 01:01:10 -06:00
struct pwrdm_ops omap2_pwrdm_operations = {
ARM: OMAP2/3: PRM: fix bogus OMAP2xxx powerstate return values
On OMAP2xxx chips, the register bitfields for the
PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED are
different than those used on OMAP3/4. The order is reversed. So, for
example, on OMAP2xxx, 0x0 indicates 'ON'; but on OMAP3/4, 0x0
indicates 'OFF'. Similarly, on OMAP2xxx, 0x3 indicates 'OFF', but on
OMAP3/4, 0x3 indicates 'ON'.
To fix this, we treat the OMAP3/4 values as the powerdomain API
values, and create new low-level powerdomain functions for the
OMAP2xxx chips which translate between the OMAP2xxx values and the
OMAP3/4 values.
Without this patch, the conversion of the OMAP2xxx PM code to the
functional powerstate code results in a non-booting kernel.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
2012-12-28 02:10:44 -07:00
. pwrdm_set_next_pwrst = omap2xxx_pwrdm_set_next_pwrst ,
. pwrdm_read_next_pwrst = omap2xxx_pwrdm_read_next_pwrst ,
. pwrdm_read_pwrst = omap2xxx_pwrdm_read_pwrst ,
2012-10-21 01:01:10 -06:00
. pwrdm_set_logic_retst = omap2_pwrdm_set_logic_retst ,
. pwrdm_set_mem_onst = omap2_pwrdm_set_mem_onst ,
. pwrdm_set_mem_retst = omap2_pwrdm_set_mem_retst ,
. pwrdm_read_mem_pwrst = omap2_pwrdm_read_mem_pwrst ,
. pwrdm_read_mem_retst = omap2_pwrdm_read_mem_retst ,
. pwrdm_wait_transition = omap2_pwrdm_wait_transition ,
} ;
2012-10-21 01:01:13 -06:00
/*
*
*/
static struct prm_ll_data omap2xxx_prm_ll_data = {
. read_reset_sources = & omap2xxx_prm_read_reset_sources ,
} ;
2012-11-21 16:15:16 -07:00
int __init omap2xxx_prm_init ( void )
2012-10-21 01:01:13 -06:00
{
if ( ! cpu_is_omap24xx ( ) )
return 0 ;
return prm_register ( & omap2xxx_prm_ll_data ) ;
}
static void __exit omap2xxx_prm_exit ( void )
{
if ( ! cpu_is_omap24xx ( ) )
return ;
/* Should never happen */
WARN ( prm_unregister ( & omap2xxx_prm_ll_data ) ,
" %s: prm_ll_data function pointer mismatch \n " , __func__ ) ;
}
__exitcall ( omap2xxx_prm_exit ) ;