2007-04-30 22:37:19 +04:00
/*
* TI DaVinci Power and Sleep Controller ( PSC )
*
* Copyright ( C ) 2006 Texas Instruments .
*
* 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 program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* 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 .
*
*/
# include <linux/kernel.h>
# include <linux/init.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2007-04-30 22:37:19 +04:00
2009-03-21 03:29:01 +03:00
# include <mach/cputype.h>
2008-08-05 19:14:15 +04:00
# include <mach/psc.h>
2007-04-30 22:37:19 +04:00
2011-07-06 10:01:21 +04:00
# include "clock.h"
2009-03-21 03:29:01 +03:00
/* Return nonzero iff the domain's clock is active */
2009-04-15 23:39:33 +04:00
int __init davinci_psc_is_clk_active ( unsigned int ctlr , unsigned int id )
2007-04-30 22:37:19 +04:00
{
2009-04-15 23:39:33 +04:00
void __iomem * psc_base ;
u32 mdstat ;
struct davinci_soc_info * soc_info = & davinci_soc_info ;
if ( ! soc_info - > psc_bases | | ( ctlr > = soc_info - > psc_bases_num ) ) {
2013-01-11 04:23:21 +04:00
pr_warn ( " PSC: Bad psc data: 0x%x[%d] \n " ,
2009-04-15 23:39:33 +04:00
( int ) soc_info - > psc_bases , ctlr ) ;
return 0 ;
}
2010-05-08 01:06:36 +04:00
psc_base = ioremap ( soc_info - > psc_bases [ ctlr ] , SZ_4K ) ;
2009-04-15 23:39:33 +04:00
mdstat = __raw_readl ( psc_base + MDSTAT + 4 * id ) ;
2010-05-08 01:06:36 +04:00
iounmap ( psc_base ) ;
2009-03-21 03:29:01 +03:00
/* if clocked, state can be "Enable" or "SyncReset" */
return mdstat & BIT ( 12 ) ;
2007-04-30 22:37:19 +04:00
}
2013-01-11 04:23:23 +04:00
/* Control "reset" line associated with PSC domain */
void davinci_psc_reset ( unsigned int ctlr , unsigned int id , bool reset )
{
u32 mdctl ;
void __iomem * psc_base ;
struct davinci_soc_info * soc_info = & davinci_soc_info ;
if ( ! soc_info - > psc_bases | | ( ctlr > = soc_info - > psc_bases_num ) ) {
pr_warn ( " PSC: Bad psc data: 0x%x[%d] \n " ,
( int ) soc_info - > psc_bases , ctlr ) ;
return ;
}
psc_base = ioremap ( soc_info - > psc_bases [ ctlr ] , SZ_4K ) ;
mdctl = readl ( psc_base + MDCTL + 4 * id ) ;
if ( reset )
mdctl & = ~ MDCTL_LRST ;
else
mdctl | = MDCTL_LRST ;
writel ( mdctl , psc_base + MDCTL + 4 * id ) ;
iounmap ( psc_base ) ;
}
2007-04-30 22:37:19 +04:00
/* Enable or disable a PSC domain */
2009-04-15 23:39:33 +04:00
void davinci_psc_config ( unsigned int domain , unsigned int ctlr ,
2011-07-06 10:01:21 +04:00
unsigned int id , bool enable , u32 flags )
2007-04-30 22:37:19 +04:00
{
2011-11-15 00:12:07 +04:00
u32 epcpr , ptcmd , ptstat , pdstat , pdctl , mdstat , mdctl ;
2009-04-15 23:39:33 +04:00
void __iomem * psc_base ;
struct davinci_soc_info * soc_info = & davinci_soc_info ;
2011-07-06 10:01:21 +04:00
u32 next_state = PSC_STATE_ENABLE ;
2007-04-30 22:37:19 +04:00
2009-04-15 23:39:33 +04:00
if ( ! soc_info - > psc_bases | | ( ctlr > = soc_info - > psc_bases_num ) ) {
2013-01-11 04:23:21 +04:00
pr_warn ( " PSC: Bad psc data: 0x%x[%d] \n " ,
2009-04-15 23:39:33 +04:00
( int ) soc_info - > psc_bases , ctlr ) ;
return ;
}
2010-05-08 01:06:36 +04:00
psc_base = ioremap ( soc_info - > psc_bases [ ctlr ] , SZ_4K ) ;
2009-04-15 23:39:33 +04:00
2011-07-06 10:01:21 +04:00
if ( ! enable ) {
if ( flags & PSC_SWRSTDISABLE )
next_state = PSC_STATE_SWRSTDISABLE ;
else
next_state = PSC_STATE_DISABLE ;
}
2009-03-21 03:29:01 +03:00
mdctl = __raw_readl ( psc_base + MDCTL + 4 * id ) ;
2009-03-27 05:33:21 +03:00
mdctl & = ~ MDSTAT_STATE_MASK ;
mdctl | = next_state ;
2011-07-06 10:01:22 +04:00
if ( flags & PSC_FORCE )
mdctl | = MDCTL_FORCE ;
2009-03-21 03:29:01 +03:00
__raw_writel ( mdctl , psc_base + MDCTL + 4 * id ) ;
2007-07-10 16:10:04 +04:00
2011-11-15 00:12:07 +04:00
pdstat = __raw_readl ( psc_base + PDSTAT + 4 * domain ) ;
2011-11-15 00:12:06 +04:00
if ( ( pdstat & PDSTAT_STATE_MASK ) = = 0 ) {
2011-11-15 00:12:07 +04:00
pdctl = __raw_readl ( psc_base + PDCTL + 4 * domain ) ;
pdctl | = PDCTL_NEXT ;
__raw_writel ( pdctl , psc_base + PDCTL + 4 * domain ) ;
2007-07-10 16:10:04 +04:00
ptcmd = 1 < < domain ;
2009-03-21 03:29:01 +03:00
__raw_writel ( ptcmd , psc_base + PTCMD ) ;
2007-04-30 22:37:19 +04:00
2007-07-10 16:10:04 +04:00
do {
2009-03-21 03:29:01 +03:00
epcpr = __raw_readl ( psc_base + EPCPR ) ;
2007-07-10 16:10:04 +04:00
} while ( ( ( ( epcpr > > domain ) & 1 ) = = 0 ) ) ;
2007-04-30 22:37:19 +04:00
2011-11-15 00:12:07 +04:00
pdctl = __raw_readl ( psc_base + PDCTL + 4 * domain ) ;
pdctl | = PDCTL_EPCGOOD ;
__raw_writel ( pdctl , psc_base + PDCTL + 4 * domain ) ;
2007-04-30 22:37:19 +04:00
} else {
2007-07-10 16:10:04 +04:00
ptcmd = 1 < < domain ;
2009-03-21 03:29:01 +03:00
__raw_writel ( ptcmd , psc_base + PTCMD ) ;
2007-04-30 22:37:19 +04:00
}
2010-10-25 16:41:18 +04:00
do {
ptstat = __raw_readl ( psc_base + PTSTAT ) ;
} while ( ! ( ( ( ptstat > > domain ) & 1 ) = = 0 ) ) ;
2007-07-10 16:10:04 +04:00
do {
2009-03-21 03:29:01 +03:00
mdstat = __raw_readl ( psc_base + MDSTAT + 4 * id ) ;
2009-03-27 05:33:21 +03:00
} while ( ! ( ( mdstat & MDSTAT_STATE_MASK ) = = next_state ) ) ;
2010-05-08 01:06:36 +04:00
iounmap ( psc_base ) ;
2007-04-30 22:37:19 +04:00
}