2010-05-03 07:39:02 +01:00
/*
* Copyright ( C ) ST - Ericsson SA 2010
*
* Author : Rabin Vincent < rabin . vincent @ stericsson . com > for ST - Ericsson
* License terms : GNU General Public License ( GPL ) version 2
*/
# include <linux/platform_device.h>
# include <linux/io.h>
# include <linux/clk.h>
2010-09-08 21:21:40 +05:30
# include <asm/cacheflush.h>
2010-05-03 07:39:02 +01:00
# include <asm/hardware/cache-l2x0.h>
# include <asm/hardware/gic.h>
# include <asm/mach/map.h>
2010-05-03 08:28:05 +01:00
# include <asm/localtimer.h>
2010-05-03 07:39:02 +01:00
2010-05-03 08:28:05 +01:00
# include <plat/mtu.h>
2010-05-03 07:39:02 +01:00
# include <mach/hardware.h>
# include <mach/setup.h>
2010-05-03 07:46:56 +01:00
# include <mach/devices.h>
2010-12-02 16:20:42 +01:00
# include <mach/prcmu.h>
2010-05-03 07:39:02 +01:00
# include "clock.h"
2010-12-08 11:07:57 +05:30
# ifdef CONFIG_CACHE_L2X0
static void __iomem * l2x0_base ;
# endif
2010-05-03 07:39:02 +01:00
void __init ux500_init_irq ( void )
{
2010-12-08 11:07:57 +05:30
void __iomem * dist_base ;
void __iomem * cpu_base ;
if ( cpu_is_u5500 ( ) ) {
dist_base = __io_address ( U5500_GIC_DIST_BASE ) ;
cpu_base = __io_address ( U5500_GIC_CPU_BASE ) ;
} else if ( cpu_is_u8500 ( ) ) {
dist_base = __io_address ( U8500_GIC_DIST_BASE ) ;
cpu_base = __io_address ( U8500_GIC_CPU_BASE ) ;
} else
ux500_unknown_soc ( ) ;
gic_init ( 0 , 29 , dist_base , cpu_base ) ;
2010-05-26 07:38:54 +01:00
/*
* Init clocks here so that they are available for system timer
* initialization .
*/
2010-12-05 12:27:05 +01:00
if ( cpu_is_u8500 ( ) )
prcmu_early_init ( ) ;
2010-05-26 07:38:54 +01:00
clk_init ( ) ;
2010-05-03 07:39:02 +01:00
}
# ifdef CONFIG_CACHE_L2X0
2010-09-08 21:21:40 +05:30
static inline void ux500_cache_wait ( void __iomem * reg , unsigned long mask )
{
/* wait for the operation to complete */
2010-11-15 14:31:17 +01:00
while ( readl_relaxed ( reg ) & mask )
2010-09-08 21:21:40 +05:30
;
}
static inline void ux500_cache_sync ( void )
{
2010-12-08 11:07:57 +05:30
void __iomem * base = l2x0_base ;
2010-11-15 14:31:17 +01:00
writel_relaxed ( 0 , base + L2X0_CACHE_SYNC ) ;
2010-09-08 21:21:40 +05:30
ux500_cache_wait ( base + L2X0_CACHE_SYNC , 1 ) ;
}
/*
* The L2 cache cannot be turned off in the non - secure world .
* Dummy until a secure service is in place .
*/
static void ux500_l2x0_disable ( void )
{
}
/*
* This is only called when doing a kexec , just after turning off the L2
* and L1 cache , and it is surrounded by a spinlock in the generic version .
* However , we ' re not really turning off the L2 cache right now and the
* PL310 does not support exclusive accesses ( used to implement the spinlock ) .
* So , the invalidation needs to be done without the spinlock .
*/
static void ux500_l2x0_inv_all ( void )
{
2010-12-08 11:07:57 +05:30
void __iomem * base = l2x0_base ;
2010-09-08 21:21:40 +05:30
uint32_t l2x0_way_mask = ( 1 < < 16 ) - 1 ; /* Bitmask of active ways */
/* invalidate all ways */
2010-12-08 11:07:57 +05:30
writel_relaxed ( l2x0_way_mask , base + L2X0_INV_WAY ) ;
ux500_cache_wait ( base + L2X0_INV_WAY , l2x0_way_mask ) ;
2010-09-08 21:21:40 +05:30
ux500_cache_sync ( ) ;
}
2010-05-03 07:39:02 +01:00
static int ux500_l2x0_init ( void )
{
2010-12-08 11:07:57 +05:30
if ( cpu_is_u5500 ( ) )
l2x0_base = __io_address ( U5500_L2CC_BASE ) ;
else if ( cpu_is_u8500 ( ) )
l2x0_base = __io_address ( U8500_L2CC_BASE ) ;
else
ux500_unknown_soc ( ) ;
2010-05-03 07:39:02 +01:00
/* 64KB way size, 8 way associativity, force WA */
l2x0_init ( l2x0_base , 0x3e060000 , 0xc0000fff ) ;
2010-09-08 21:21:40 +05:30
/* Override invalidate function */
outer_cache . disable = ux500_l2x0_disable ;
outer_cache . inv_all = ux500_l2x0_inv_all ;
2010-05-03 07:39:02 +01:00
return 0 ;
}
early_initcall ( ux500_l2x0_init ) ;
# endif
2010-05-03 08:28:05 +01:00
static void __init ux500_timer_init ( void )
{
# ifdef CONFIG_LOCAL_TIMERS
/* Setup the local timer base */
2010-12-08 11:07:57 +05:30
if ( cpu_is_u5500 ( ) )
twd_base = __io_address ( U5500_TWD_BASE ) ;
else if ( cpu_is_u8500 ( ) )
twd_base = __io_address ( U8500_TWD_BASE ) ;
else
ux500_unknown_soc ( ) ;
2010-05-03 08:28:05 +01:00
# endif
2010-12-08 11:07:57 +05:30
if ( cpu_is_u5500 ( ) )
mtu_base = __io_address ( U5500_MTU0_BASE ) ;
else if ( cpu_is_u8500ed ( ) )
2010-05-03 08:28:05 +01:00
mtu_base = __io_address ( U8500_MTU0_BASE_ED ) ;
2010-12-08 11:07:57 +05:30
else if ( cpu_is_u8500 ( ) )
mtu_base = __io_address ( U8500_MTU0_BASE ) ;
2010-05-03 08:28:05 +01:00
else
2010-12-08 11:07:57 +05:30
ux500_unknown_soc ( ) ;
2010-05-03 08:28:05 +01:00
nmdk_timer_init ( ) ;
}
struct sys_timer ux500_timer = {
. init = ux500_timer_init ,
} ;