2010-09-21 20:34:10 +04:00
/*
* OMAP2 / 3 PRM module functions
*
2011-12-17 01:36:58 +04:00
* Copyright ( C ) 2010 - 2011 Texas Instruments , Inc .
2010-09-21 20:34:10 +04:00
* Copyright ( C ) 2010 Nokia Corporation
* Benoît Cousson
* Paul Walmsley
*
* 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>
2010-12-22 01:30:55 +03:00
# include <linux/io.h>
2010-09-21 20:34:10 +04:00
# include <plat/common.h>
# include <plat/cpu.h>
# include <plat/prcm.h>
2011-03-28 21:52:04 +04:00
# include "vp.h"
2010-12-22 01:30:55 +03:00
# include "prm2xxx_3xxx.h"
# include "cm2xxx_3xxx.h"
2010-09-21 20:34:10 +04:00
# include "prm-regbits-24xx.h"
# include "prm-regbits-34xx.h"
2010-12-22 07:05:14 +03:00
u32 omap2_prm_read_mod_reg ( s16 module , u16 idx )
2010-12-22 01:30:55 +03:00
{
return __raw_readl ( prm_base + module + idx ) ;
}
2010-12-22 07:05:14 +03:00
void omap2_prm_write_mod_reg ( u32 val , s16 module , u16 idx )
2010-12-22 01:30:55 +03:00
{
__raw_writel ( val , prm_base + module + idx ) ;
}
/* Read-modify-write a register in a PRM module. Caller must lock */
2010-12-22 07:05:14 +03:00
u32 omap2_prm_rmw_mod_reg_bits ( u32 mask , u32 bits , s16 module , s16 idx )
2010-12-22 01:30:55 +03:00
{
u32 v ;
2010-12-22 07:05:14 +03:00
v = omap2_prm_read_mod_reg ( module , idx ) ;
2010-12-22 01:30:55 +03:00
v & = ~ mask ;
v | = bits ;
2010-12-22 07:05:14 +03:00
omap2_prm_write_mod_reg ( v , module , idx ) ;
2010-12-22 01:30:55 +03:00
return v ;
}
/* Read a PRM register, AND it, and shift the result down to bit 0 */
2010-12-22 07:05:14 +03:00
u32 omap2_prm_read_mod_bits_shift ( s16 domain , s16 idx , u32 mask )
2010-12-22 01:30:55 +03:00
{
u32 v ;
2010-12-22 07:05:14 +03:00
v = omap2_prm_read_mod_reg ( domain , idx ) ;
2010-12-22 01:30:55 +03:00
v & = mask ;
v > > = __ffs ( mask ) ;
return v ;
}
2010-12-22 07:05:14 +03:00
u32 omap2_prm_set_mod_reg_bits ( u32 bits , s16 module , s16 idx )
2010-12-22 01:30:55 +03:00
{
2010-12-22 07:05:14 +03:00
return omap2_prm_rmw_mod_reg_bits ( bits , bits , module , idx ) ;
2010-12-22 01:30:55 +03:00
}
2010-12-22 07:05:14 +03:00
u32 omap2_prm_clear_mod_reg_bits ( u32 bits , s16 module , s16 idx )
2010-12-22 01:30:55 +03:00
{
2010-12-22 07:05:14 +03:00
return omap2_prm_rmw_mod_reg_bits ( bits , 0x0 , module , idx ) ;
2010-12-22 01:30:55 +03:00
}
2010-09-21 20:34:10 +04:00
/**
* omap2_prm_is_hardreset_asserted - read the HW reset line state of
* submodules contained in the hwmod module
* @ prm_mod : PRM submodule base ( e . g . CORE_MOD )
* @ shift : register bit shift corresponding to the reset line to check
*
* Returns 1 if the ( sub ) module hardreset line is currently asserted ,
* 0 if the ( sub ) module hardreset line is not currently asserted , or
* - EINVAL if called while running on a non - OMAP2 / 3 chip .
*/
int omap2_prm_is_hardreset_asserted ( s16 prm_mod , u8 shift )
{
if ( ! ( cpu_is_omap24xx ( ) | | cpu_is_omap34xx ( ) ) )
return - EINVAL ;
2010-12-22 07:05:14 +03:00
return omap2_prm_read_mod_bits_shift ( prm_mod , OMAP2_RM_RSTCTRL ,
2010-09-21 20:34:10 +04:00
( 1 < < shift ) ) ;
}
/**
* omap2_prm_assert_hardreset - assert the HW reset line of a submodule
* @ prm_mod : PRM submodule base ( e . g . CORE_MOD )
* @ shift : register bit shift corresponding to the reset line to assert
*
* Some IPs like dsp or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the
* IP . These modules may have multiple hard - reset lines that reset
* different ' submodules ' inside the IP block . This function will
* place the submodule into reset . Returns 0 upon success or - EINVAL
* upon an argument error .
*/
int omap2_prm_assert_hardreset ( s16 prm_mod , u8 shift )
{
u32 mask ;
if ( ! ( cpu_is_omap24xx ( ) | | cpu_is_omap34xx ( ) ) )
return - EINVAL ;
mask = 1 < < shift ;
2010-12-22 07:05:14 +03:00
omap2_prm_rmw_mod_reg_bits ( mask , mask , prm_mod , OMAP2_RM_RSTCTRL ) ;
2010-09-21 20:34:10 +04:00
return 0 ;
}
/**
* omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait
* @ prm_mod : PRM submodule base ( e . g . CORE_MOD )
2011-03-04 23:32:44 +03:00
* @ rst_shift : register bit shift corresponding to the reset line to deassert
* @ st_shift : register bit shift for the status of the deasserted submodule
2010-09-21 20:34:10 +04:00
*
* Some IPs like dsp or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the
* IP . These modules may have multiple hard - reset lines that reset
* different ' submodules ' inside the IP block . This function will
* take the submodule out of reset and wait until the PRCM indicates
* that the reset has completed before returning . Returns 0 upon success or
* - EINVAL upon an argument error , - EEXIST if the submodule was already out
* of reset , or - EBUSY if the submodule did not exit reset promptly .
*/
2011-03-04 23:32:44 +03:00
int omap2_prm_deassert_hardreset ( s16 prm_mod , u8 rst_shift , u8 st_shift )
2010-09-21 20:34:10 +04:00
{
2011-03-04 23:32:44 +03:00
u32 rst , st ;
2010-09-21 20:34:10 +04:00
int c ;
if ( ! ( cpu_is_omap24xx ( ) | | cpu_is_omap34xx ( ) ) )
return - EINVAL ;
2011-03-04 23:32:44 +03:00
rst = 1 < < rst_shift ;
st = 1 < < st_shift ;
2010-09-21 20:34:10 +04:00
/* Check the current status to avoid de-asserting the line twice */
2011-03-04 23:32:44 +03:00
if ( omap2_prm_read_mod_bits_shift ( prm_mod , OMAP2_RM_RSTCTRL , rst ) = = 0 )
2010-09-21 20:34:10 +04:00
return - EEXIST ;
/* Clear the reset status by writing 1 to the status bit */
2011-03-04 23:32:44 +03:00
omap2_prm_rmw_mod_reg_bits ( 0xffffffff , st , prm_mod , OMAP2_RM_RSTST ) ;
2010-09-21 20:34:10 +04:00
/* de-assert the reset control line */
2011-03-04 23:32:44 +03:00
omap2_prm_rmw_mod_reg_bits ( rst , 0 , prm_mod , OMAP2_RM_RSTCTRL ) ;
2010-09-21 20:34:10 +04:00
/* wait the status to be set */
2010-12-22 07:05:14 +03:00
omap_test_timeout ( omap2_prm_read_mod_bits_shift ( prm_mod , OMAP2_RM_RSTST ,
2011-03-04 23:32:44 +03:00
st ) ,
2010-09-21 20:34:10 +04:00
MAX_MODULE_HARDRESET_WAIT , c ) ;
return ( c = = MAX_MODULE_HARDRESET_WAIT ) ? - EBUSY : 0 ;
}
2011-03-28 21:52:04 +04:00
/* PRM VP */
/*
* struct omap3_vp - OMAP3 VP register access description .
* @ tranxdone_status : VP_TRANXDONE_ST bitmask in PRM_IRQSTATUS_MPU reg
*/
struct omap3_vp {
u32 tranxdone_status ;
} ;
2011-03-28 21:25:12 +04:00
static struct omap3_vp omap3_vp [ ] = {
2011-03-28 21:52:04 +04:00
[ OMAP3_VP_VDD_MPU_ID ] = {
. tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK ,
} ,
[ OMAP3_VP_VDD_CORE_ID ] = {
. tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK ,
} ,
} ;
# define MAX_VP_ID ARRAY_SIZE(omap3_vp);
u32 omap3_prm_vp_check_txdone ( u8 vp_id )
{
struct omap3_vp * vp = & omap3_vp [ vp_id ] ;
u32 irqstatus ;
irqstatus = omap2_prm_read_mod_reg ( OCP_MOD ,
OMAP3_PRM_IRQSTATUS_MPU_OFFSET ) ;
return irqstatus & vp - > tranxdone_status ;
}
void omap3_prm_vp_clear_txdone ( u8 vp_id )
{
struct omap3_vp * vp = & omap3_vp [ vp_id ] ;
omap2_prm_write_mod_reg ( vp - > tranxdone_status ,
OCP_MOD , OMAP3_PRM_IRQSTATUS_MPU_OFFSET ) ;
}
2011-03-28 21:25:12 +04:00
u32 omap3_prm_vcvp_read ( u8 offset )
{
return omap2_prm_read_mod_reg ( OMAP3430_GR_MOD , offset ) ;
}
void omap3_prm_vcvp_write ( u32 val , u8 offset )
{
omap2_prm_write_mod_reg ( val , OMAP3430_GR_MOD , offset ) ;
}
u32 omap3_prm_vcvp_rmw ( u32 mask , u32 bits , u8 offset )
{
return omap2_prm_rmw_mod_reg_bits ( mask , bits , OMAP3430_GR_MOD , offset ) ;
}
2011-12-17 01:36:58 +04:00
/**
* omap3xxx_prm_read_pending_irqs - read pending PRM MPU IRQs into @ events
* @ events : ptr to a u32 , preallocated by caller
*
* Read PRM_IRQSTATUS_MPU bits , AND ' ed with the currently - enabled PRM
* MPU IRQs , and store the result into the u32 pointed to by @ events .
* No return value .
*/
void omap3xxx_prm_read_pending_irqs ( unsigned long * events )
{
u32 mask , st ;
/* XXX Can the mask read be avoided (e.g., can it come from RAM?) */
mask = omap2_prm_read_mod_reg ( OCP_MOD , OMAP3_PRM_IRQENABLE_MPU_OFFSET ) ;
st = omap2_prm_read_mod_reg ( OCP_MOD , OMAP3_PRM_IRQSTATUS_MPU_OFFSET ) ;
events [ 0 ] = mask & st ;
}
/**
* omap3xxx_prm_ocp_barrier - force buffered MPU writes to the PRM to complete
*
* Force any buffered writes to the PRM IP block to complete . Needed
* by the PRM IRQ handler , which reads and writes directly to the IP
* block , to avoid race conditions after acknowledging or clearing IRQ
* bits . No return value .
*/
void omap3xxx_prm_ocp_barrier ( void )
{
omap2_prm_read_mod_reg ( OCP_MOD , OMAP3_PRM_REVISION_OFFSET ) ;
}
2011-12-17 01:36:58 +04:00
/**
* omap3xxx_prm_save_and_clear_irqen - save / clear PRM_IRQENABLE_MPU reg
* @ saved_mask : ptr to a u32 array to save IRQENABLE bits
*
* Save the PRM_IRQENABLE_MPU register to @ saved_mask . @ saved_mask
* must be allocated by the caller . Intended to be used in the PRM
* interrupt handler suspend callback . The OCP barrier is needed to
* ensure the write to disable PRM interrupts reaches the PRM before
* returning ; otherwise , spurious interrupts might occur . No return
* value .
*/
void omap3xxx_prm_save_and_clear_irqen ( u32 * saved_mask )
{
saved_mask [ 0 ] = omap2_prm_read_mod_reg ( OCP_MOD ,
OMAP3_PRM_IRQENABLE_MPU_OFFSET ) ;
omap2_prm_write_mod_reg ( 0 , OCP_MOD , OMAP3_PRM_IRQENABLE_MPU_OFFSET ) ;
/* OCP barrier */
omap2_prm_read_mod_reg ( OCP_MOD , OMAP3_PRM_REVISION_OFFSET ) ;
}
/**
* omap3xxx_prm_restore_irqen - set PRM_IRQENABLE_MPU register from args
* @ saved_mask : ptr to a u32 array of IRQENABLE bits saved previously
*
* Restore the PRM_IRQENABLE_MPU register from @ saved_mask . Intended
* to be used in the PRM interrupt handler resume callback to restore
* values saved by omap3xxx_prm_save_and_clear_irqen ( ) . No OCP
* barrier should be needed here ; any pending PRM interrupts will fire
* once the writes reach the PRM . No return value .
*/
void omap3xxx_prm_restore_irqen ( u32 * saved_mask )
{
omap2_prm_write_mod_reg ( saved_mask [ 0 ] , OCP_MOD ,
OMAP3_PRM_IRQENABLE_MPU_OFFSET ) ;
}