2006-04-02 20:46:20 +04:00
/*
* linux / arch / arm / mach - omap2 / prcm . c
*
* OMAP 24 xx Power Reset and Clock Management ( PRCM ) functions
*
* Copyright ( C ) 2005 Nokia Corporation
*
* Written by Tony Lindgren < tony . lindgren @ nokia . com >
*
* Some pieces of code Copyright ( C ) 2005 Texas Instruments , Inc .
*
* 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/module.h>
# include <linux/init.h>
# include <linux/clk.h>
2008-07-03 13:24:44 +04:00
# include <linux/io.h>
2009-07-25 05:44:03 +04:00
# include <linux/delay.h>
2006-04-02 20:46:20 +04:00
2008-08-05 19:14:15 +04:00
# include <mach/common.h>
# include <mach/prcm.h>
2008-03-18 11:04:51 +03:00
2008-07-03 13:24:44 +04:00
# include "clock.h"
2008-03-18 11:04:51 +03:00
# include "prm.h"
# include "prm-regbits-24xx.h"
2006-04-02 20:46:20 +04:00
2008-07-03 13:24:44 +04:00
static void __iomem * prm_base ;
static void __iomem * cm_base ;
2009-07-25 05:44:03 +04:00
# define MAX_MODULE_ENABLE_WAIT 100000
2006-04-02 20:46:20 +04:00
u32 omap_prcm_get_reset_sources ( void )
{
2008-07-03 13:24:44 +04:00
/* XXX This presumably needs modification for 34XX */
2008-03-18 11:04:51 +03:00
return prm_read_mod_reg ( WKUP_MOD , RM_RSTST ) & 0x7f ;
2006-04-02 20:46:20 +04:00
}
EXPORT_SYMBOL ( omap_prcm_get_reset_sources ) ;
/* Resets clock rates and reboots the system. Only called from system.h */
void omap_prcm_arch_reset ( char mode )
{
2008-07-03 13:24:44 +04:00
s16 prcm_offs ;
2006-09-25 13:41:20 +04:00
omap2_clk_prepare_for_reboot ( ) ;
2008-03-18 11:04:51 +03:00
2008-07-03 13:24:44 +04:00
if ( cpu_is_omap24xx ( ) )
prcm_offs = WKUP_MOD ;
else if ( cpu_is_omap34xx ( ) )
prcm_offs = OMAP3430_GR_MOD ;
else
WARN_ON ( 1 ) ;
prm_set_mod_reg_bits ( OMAP_RST_DPLL3 , prcm_offs , RM_RSTCTRL ) ;
2006-04-02 20:46:20 +04:00
}
2008-07-03 13:24:44 +04:00
static inline u32 __omap_prcm_read ( void __iomem * base , s16 module , u16 reg )
{
BUG_ON ( ! base ) ;
return __raw_readl ( base + module + reg ) ;
}
static inline void __omap_prcm_write ( u32 value , void __iomem * base ,
s16 module , u16 reg )
{
BUG_ON ( ! base ) ;
__raw_writel ( value , base + module + reg ) ;
}
/* Read a register in a PRM module */
u32 prm_read_mod_reg ( s16 module , u16 idx )
{
return __omap_prcm_read ( prm_base , module , idx ) ;
}
EXPORT_SYMBOL ( prm_read_mod_reg ) ;
/* Write into a register in a PRM module */
void prm_write_mod_reg ( u32 val , s16 module , u16 idx )
{
__omap_prcm_write ( val , prm_base , module , idx ) ;
}
EXPORT_SYMBOL ( prm_write_mod_reg ) ;
2008-07-03 13:24:44 +04:00
/* Read-modify-write a register in a PRM module. Caller must lock */
u32 prm_rmw_mod_reg_bits ( u32 mask , u32 bits , s16 module , s16 idx )
{
u32 v ;
v = prm_read_mod_reg ( module , idx ) ;
v & = ~ mask ;
v | = bits ;
prm_write_mod_reg ( v , module , idx ) ;
return v ;
}
EXPORT_SYMBOL ( prm_rmw_mod_reg_bits ) ;
2008-07-03 13:24:44 +04:00
/* Read a register in a CM module */
u32 cm_read_mod_reg ( s16 module , u16 idx )
{
return __omap_prcm_read ( cm_base , module , idx ) ;
}
EXPORT_SYMBOL ( cm_read_mod_reg ) ;
/* Write into a register in a CM module */
void cm_write_mod_reg ( u32 val , s16 module , u16 idx )
{
__omap_prcm_write ( val , cm_base , module , idx ) ;
}
EXPORT_SYMBOL ( cm_write_mod_reg ) ;
2008-07-03 13:24:44 +04:00
/* Read-modify-write a register in a CM module. Caller must lock */
u32 cm_rmw_mod_reg_bits ( u32 mask , u32 bits , s16 module , s16 idx )
{
u32 v ;
v = cm_read_mod_reg ( module , idx ) ;
v & = ~ mask ;
v | = bits ;
cm_write_mod_reg ( v , module , idx ) ;
return v ;
}
EXPORT_SYMBOL ( cm_rmw_mod_reg_bits ) ;
2009-07-25 05:44:03 +04:00
/**
* omap2_cm_wait_idlest - wait for IDLEST bit to indicate module readiness
* @ reg : physical address of module IDLEST register
* @ mask : value to mask against to determine if the module is active
* @ name : name of the clock ( for printk )
*
* Returns 1 if the module indicated readiness in time , or 0 if it
* failed to enable in roughly MAX_MODULE_ENABLE_WAIT microseconds .
*/
int omap2_cm_wait_idlest ( void __iomem * reg , u32 mask , const char * name )
{
int i = 0 ;
int ena = 0 ;
/*
* 24 xx uses 0 to indicate not ready , and 1 to indicate ready .
* 34 xx reverses this , just to keep us on our toes
*/
if ( cpu_is_omap24xx ( ) )
ena = mask ;
else if ( cpu_is_omap34xx ( ) )
ena = 0 ;
else
BUG ( ) ;
/* Wait for lock */
while ( ( ( __raw_readl ( reg ) & mask ) ! = ena ) & &
( i + + < MAX_MODULE_ENABLE_WAIT ) )
udelay ( 1 ) ;
if ( i < MAX_MODULE_ENABLE_WAIT )
pr_debug ( " cm: Module associated with clock %s ready after %d "
" loops \n " , name , i ) ;
else
pr_err ( " cm: Module associated with clock %s didn't enable in "
" %d tries \n " , name , MAX_MODULE_ENABLE_WAIT ) ;
return ( i < MAX_MODULE_ENABLE_WAIT ) ? 1 : 0 ;
} ;
2008-07-03 13:24:44 +04:00
void __init omap2_set_globals_prcm ( struct omap_globals * omap2_globals )
{
prm_base = omap2_globals - > prm ;
cm_base = omap2_globals - > cm ;
}