2009-05-16 14:51:14 +04:00
/*
* linux / arch / arm / kernel / smp_scu . c
*
* Copyright ( C ) 2002 ARM Ltd .
* All Rights Reserved
*
* 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/init.h>
# include <linux/io.h>
# include <asm/smp_scu.h>
2009-05-18 19:26:27 +04:00
# include <asm/cacheflush.h>
2011-09-15 14:45:15 +04:00
# include <asm/cputype.h>
2009-05-16 14:51:14 +04:00
# define SCU_CTRL 0x00
# define SCU_CONFIG 0x04
# define SCU_CPU_STATUS 0x08
# define SCU_INVALIDATE 0x0c
# define SCU_FPGA_REVISION 0x10
2011-06-13 18:28:53 +04:00
# ifdef CONFIG_SMP
2009-05-16 14:51:14 +04:00
/*
* Get the number of CPU cores from the SCU configuration
*/
unsigned int __init scu_get_core_count ( void __iomem * scu_base )
{
unsigned int ncores = __raw_readl ( scu_base + SCU_CONFIG ) ;
return ( ncores & 0x03 ) + 1 ;
}
/*
* Enable the SCU
*/
2011-09-25 11:25:43 +04:00
void scu_enable ( void __iomem * scu_base )
2009-05-16 14:51:14 +04:00
{
u32 scu_ctrl ;
2011-09-15 14:45:15 +04:00
# ifdef CONFIG_ARM_ERRATA_764369
/* Cortex-A9 only */
if ( ( read_cpuid ( CPUID_ID ) & 0xff0ffff0 ) = = 0x410fc090 ) {
scu_ctrl = __raw_readl ( scu_base + 0x30 ) ;
if ( ! ( scu_ctrl & 1 ) )
__raw_writel ( scu_ctrl | 0x1 , scu_base + 0x30 ) ;
}
# endif
2009-05-16 14:51:14 +04:00
scu_ctrl = __raw_readl ( scu_base + SCU_CTRL ) ;
2009-11-04 15:16:38 +03:00
/* already enabled? */
if ( scu_ctrl & 1 )
return ;
2009-05-16 14:51:14 +04:00
scu_ctrl | = 1 ;
__raw_writel ( scu_ctrl , scu_base + SCU_CTRL ) ;
2009-05-18 19:26:27 +04:00
/*
* Ensure that the data accessed by CPU0 before the SCU was
* initialised is visible to the other CPUs .
*/
flush_cache_all ( ) ;
2009-05-16 14:51:14 +04:00
}
2011-06-13 18:28:53 +04:00
# endif
2011-02-04 13:36:39 +03:00
/*
* Set the executing CPUs power mode as defined . This will be in
* preparation for it executing a WFI instruction .
*
* This function must be called with preemption disabled , and as it
* has the side effect of disabling coherency , caches must have been
* flushed . Interrupts must also have been disabled .
*/
int scu_power_mode ( void __iomem * scu_base , unsigned int mode )
{
unsigned int val ;
int cpu = smp_processor_id ( ) ;
if ( mode > 3 | | mode = = 1 | | cpu > 3 )
return - EINVAL ;
val = __raw_readb ( scu_base + SCU_CPU_STATUS + cpu ) & ~ 0x03 ;
val | = mode ;
__raw_writeb ( val , scu_base + SCU_CPU_STATUS + cpu ) ;
return 0 ;
}