2010-02-28 17:26:25 +00:00
/*
* Versatile Express Core Tile Cortex A9x4 Support
*/
# include <linux/init.h>
2010-03-30 02:52:45 +09:00
# include <linux/gfp.h>
2010-02-28 17:26:25 +00:00
# include <linux/device.h>
# include <linux/dma-mapping.h>
2010-04-15 10:16:26 +01:00
# include <linux/platform_device.h>
2010-02-28 17:26:25 +00:00
# include <linux/amba/bus.h>
# include <linux/amba/clcd.h>
2010-11-17 10:04:33 +01:00
# include <linux/clkdev.h>
2010-02-28 17:26:25 +00:00
# include <asm/hardware/arm_timer.h>
# include <asm/hardware/cache-l2x0.h>
# include <asm/hardware/gic.h>
2010-04-15 10:16:26 +01:00
# include <asm/pmu.h>
2011-02-28 17:01:04 +01:00
# include <asm/smp_scu.h>
2010-07-09 13:52:09 +01:00
# include <asm/smp_twd.h>
2010-02-28 17:26:25 +00:00
# include <mach/ct-ca9x4.h>
2010-10-06 16:18:08 +01:00
# include <asm/hardware/timer-sp.h>
2010-02-28 17:26:25 +00:00
# include <asm/mach/map.h>
# include <asm/mach/time.h>
# include "core.h"
# include <mach/motherboard.h>
2011-01-18 20:13:51 +00:00
# include <plat/clcd.h>
2010-02-28 17:26:25 +00:00
static struct map_desc ct_ca9x4_io_desc [ ] __initdata = {
{
2012-01-25 15:37:29 +00:00
. virtual = V2T_PERIPH ,
. pfn = __phys_to_pfn ( CT_CA9X4_MPIC ) ,
. length = SZ_8K ,
. type = MT_DEVICE ,
2010-02-28 17:26:25 +00:00
} ,
} ;
static void __init ct_ca9x4_map_io ( void )
{
2012-01-25 15:37:29 +00:00
iotable_init ( ct_ca9x4_io_desc , ARRAY_SIZE ( ct_ca9x4_io_desc ) ) ;
2010-02-28 17:26:25 +00:00
}
2011-08-04 11:57:04 +01:00
# ifdef CONFIG_HAVE_ARM_TWD
static DEFINE_TWD_LOCAL_TIMER ( twd_local_timer , A9_MPCORE_TWD , IRQ_LOCALTIMER ) ;
static void __init ca9x4_twd_init ( void )
{
int err = twd_local_timer_register ( & twd_local_timer ) ;
if ( err )
pr_err ( " twd_local_timer_register failed %d \n " , err ) ;
}
# else
# define ca9x4_twd_init() do {} while(0)
# endif
2010-02-28 17:26:25 +00:00
static void __init ct_ca9x4_init_irq ( void )
{
2012-01-25 15:37:29 +00:00
gic_init ( 0 , 29 , ioremap ( A9_MPCORE_GIC_DIST , SZ_4K ) ,
ioremap ( A9_MPCORE_GIC_CPU , SZ_256 ) ) ;
2011-08-04 11:57:04 +01:00
ca9x4_twd_init ( ) ;
2010-02-28 17:26:25 +00:00
}
static void ct_ca9x4_clcd_enable ( struct clcd_fb * fb )
{
2012-06-12 16:14:03 +01:00
u32 site = v2m_get_master_site ( ) ;
/*
* Old firmware was using the " site " component of the command
* to control the DVI muxer ( while it should be always 0 ie . MB ) .
* Newer firmware uses the data register . Keep both for compatibility .
*/
v2m_cfg_write ( SYS_CFG_MUXFPGA | SYS_CFG_SITE ( site ) , site ) ;
v2m_cfg_write ( SYS_CFG_DVIMODE | SYS_CFG_SITE ( SYS_CFG_SITE_MB ) , 2 ) ;
2010-02-28 17:26:25 +00:00
}
static int ct_ca9x4_clcd_setup ( struct clcd_fb * fb )
{
unsigned long framesize = 1024 * 768 * 2 ;
2011-01-18 20:13:51 +00:00
fb - > panel = versatile_clcd_get_panel ( " XVGA " ) ;
if ( ! fb - > panel )
return - EINVAL ;
2010-02-28 17:26:25 +00:00
2011-01-18 20:13:51 +00:00
return versatile_clcd_setup_dma ( fb , framesize ) ;
2010-02-28 17:26:25 +00:00
}
static struct clcd_board ct_ca9x4_clcd_data = {
. name = " CT-CA9X4 " ,
2011-01-18 20:13:51 +00:00
. caps = CLCD_CAP_5551 | CLCD_CAP_565 ,
2010-02-28 17:26:25 +00:00
. check = clcdfb_check ,
. decode = clcdfb_decode ,
. enable = ct_ca9x4_clcd_enable ,
. setup = ct_ca9x4_clcd_setup ,
2011-01-18 20:13:51 +00:00
. mmap = versatile_clcd_mmap_dma ,
. remove = versatile_clcd_remove_dma ,
2010-02-28 17:26:25 +00:00
} ;
2011-12-18 12:07:09 +00:00
static AMBA_AHB_DEVICE ( clcd , " ct:clcd " , 0 , CT_CA9X4_CLCDC , IRQ_CT_CA9X4_CLCDC , & ct_ca9x4_clcd_data ) ;
static AMBA_APB_DEVICE ( dmc , " ct:dmc " , 0 , CT_CA9X4_DMC , IRQ_CT_CA9X4_DMC , NULL ) ;
static AMBA_APB_DEVICE ( smc , " ct:smc " , 0 , CT_CA9X4_SMC , IRQ_CT_CA9X4_SMC , NULL ) ;
static AMBA_APB_DEVICE ( gpio , " ct:gpio " , 0 , CT_CA9X4_GPIO , IRQ_CT_CA9X4_GPIO , NULL ) ;
2010-02-28 17:26:25 +00:00
static struct amba_device * ct_ca9x4_amba_devs [ ] __initdata = {
& clcd_device ,
& dmc_device ,
& smc_device ,
& gpio_device ,
} ;
2012-07-13 11:48:16 +01:00
static struct v2m_osc ct_osc1 = {
. osc = 1 ,
. rate_min = 10000000 ,
. rate_max = 80000000 ,
. rate_default = 23750000 ,
2010-02-28 17:26:25 +00:00
} ;
2010-04-15 10:16:26 +01:00
static struct resource pmu_resources [ ] = {
[ 0 ] = {
. start = IRQ_CT_CA9X4_PMU_CPU0 ,
. end = IRQ_CT_CA9X4_PMU_CPU0 ,
. flags = IORESOURCE_IRQ ,
} ,
[ 1 ] = {
. start = IRQ_CT_CA9X4_PMU_CPU1 ,
. end = IRQ_CT_CA9X4_PMU_CPU1 ,
. flags = IORESOURCE_IRQ ,
} ,
[ 2 ] = {
. start = IRQ_CT_CA9X4_PMU_CPU2 ,
. end = IRQ_CT_CA9X4_PMU_CPU2 ,
. flags = IORESOURCE_IRQ ,
} ,
[ 3 ] = {
. start = IRQ_CT_CA9X4_PMU_CPU3 ,
. end = IRQ_CT_CA9X4_PMU_CPU3 ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
static struct platform_device pmu_device = {
. name = " arm-pmu " ,
. id = ARM_PMU_DEVICE_CPU ,
. num_resources = ARRAY_SIZE ( pmu_resources ) ,
. resource = pmu_resources ,
} ;
2010-10-05 11:29:28 +01:00
static void __init ct_ca9x4_init ( void )
2010-02-28 17:26:25 +00:00
{
int i ;
2012-07-13 11:48:16 +01:00
struct clk * clk ;
2010-02-28 17:26:25 +00:00
# ifdef CONFIG_CACHE_L2X0
2012-01-25 15:37:29 +00:00
void __iomem * l2x0_base = ioremap ( CT_CA9X4_L2CC , SZ_4K ) ;
2010-09-27 14:55:15 +01:00
/* set RAM latencies to 1 cycle for this core tile. */
writel ( 0 , l2x0_base + L2X0_TAG_LATENCY_CTRL ) ;
writel ( 0 , l2x0_base + L2X0_DATA_LATENCY_CTRL ) ;
l2x0_init ( l2x0_base , 0x00400000 , 0xfe0fffff ) ;
2010-02-28 17:26:25 +00:00
# endif
2012-07-13 11:48:16 +01:00
ct_osc1 . site = v2m_get_master_site ( ) ;
clk = v2m_osc_register ( " ct:osc1 " , & ct_osc1 ) ;
clk_register_clkdev ( clk , NULL , " ct:clcd " ) ;
2010-02-28 17:26:25 +00:00
for ( i = 0 ; i < ARRAY_SIZE ( ct_ca9x4_amba_devs ) ; i + + )
amba_device_register ( ct_ca9x4_amba_devs [ i ] , & iomem_resource ) ;
2010-04-15 10:16:26 +01:00
platform_device_register ( & pmu_device ) ;
2010-02-28 17:26:25 +00:00
}
2011-02-28 17:01:04 +01:00
# ifdef CONFIG_SMP
2012-01-25 15:37:29 +00:00
static void * ct_ca9x4_scu_base __initdata ;
2012-01-18 19:40:13 +00:00
static void __init ct_ca9x4_init_cpu_map ( void )
2011-02-28 17:01:04 +01:00
{
2012-01-25 15:37:29 +00:00
int i , ncores ;
ct_ca9x4_scu_base = ioremap ( A9_MPCORE_SCU , SZ_128 ) ;
if ( WARN_ON ( ! ct_ca9x4_scu_base ) )
return ;
ncores = scu_get_core_count ( ct_ca9x4_scu_base ) ;
2011-02-28 17:01:04 +01:00
2011-10-20 22:04:18 +01:00
if ( ncores > nr_cpu_ids ) {
pr_warn ( " SMP: %u cores greater than maximum (%u), clipping \n " ,
ncores , nr_cpu_ids ) ;
ncores = nr_cpu_ids ;
}
2011-02-28 17:01:04 +01:00
for ( i = 0 ; i < ncores ; + + i )
set_cpu_possible ( i , true ) ;
2011-04-03 13:01:30 +01:00
set_smp_cross_call ( gic_raise_softirq ) ;
2011-02-28 17:01:04 +01:00
}
2012-01-18 19:40:13 +00:00
static void __init ct_ca9x4_smp_enable ( unsigned int max_cpus )
2011-02-28 17:01:04 +01:00
{
2012-01-25 15:37:29 +00:00
scu_enable ( ct_ca9x4_scu_base ) ;
2011-02-28 17:01:04 +01:00
}
# endif
struct ct_desc ct_ca9x4_desc __initdata = {
. id = V2M_CT_ID_CA9 ,
. name = " CA9x4 " ,
2010-02-28 17:26:25 +00:00
. map_io = ct_ca9x4_map_io ,
2011-02-28 17:01:04 +01:00
. init_irq = ct_ca9x4_init_irq ,
. init_tile = ct_ca9x4_init ,
# ifdef CONFIG_SMP
. init_cpu_map = ct_ca9x4_init_cpu_map ,
. smp_enable = ct_ca9x4_smp_enable ,
2010-02-28 17:26:25 +00:00
# endif
2011-02-28 17:01:04 +01:00
} ;