1/* 2* ARM A9 MPCORE Platform base 3*/ 4 5 6#include <linux/kernel.h> 7#include <linux/types.h> 8#include <linux/init.h> 9#include <linux/io.h> 10#include <linux/clk.h> 11#include <linux/errno.h> 12#include <linux/smp.h> 13#include <linux/clockchips.h> 14#include <linux/ioport.h> 15#include <linux/cpumask.h> 16 17#include <asm/mach/map.h> 18#include <asm/smp_twd.h> 19#include <asm/hardware/gic.h> 20 21#include <plat/mpcore.h> 22#include <mach/io_map.h> 23 24/* Globals */ 25static void __iomem * periphbase ; 26extern void __iomem * twd_base; /* declared in arch/arm/kernel/smp_twd.c */ 27 28void __iomem * scu_base_addr(void) 29{ 30 return (periphbase + MPCORE_SCU_OFF); 31} 32 33/* 34 * Local per-CPU timer support 35 * Called from arch/arm/kernel/smp.c 36 * Implemented in arch/arm/kernel/smp_twd.c 37 * All that is needed is to set the base address in mpcore_init() and irq here. 38 */ 39void __cpuinit local_timer_setup(struct clock_event_device *evt) 40{ 41 unsigned int cpu = smp_processor_id(); 42 43 printk(KERN_INFO "MPCORE Private timer setup CPU%u\n", cpu); 44 45 evt->retries = 0; 46 evt->irq = MPCORE_IRQ_LOCALTIMER; 47 twd_timer_setup(evt); 48} 49 50void __init mpcore_map_io( void ) 51{ 52 struct map_desc desc ; 53 phys_addr_t base_addr; 54 55 /* 56 * Cortex A9 Architecture Manual specifies this as a way to get 57 * MPCORE PERHIPHBASE address at run-time 58 */ 59 asm( "mrc p15,4,%0,c15,c0,0 @ Read Configuration Base Address Register" 60 : "=&r" (base_addr) : : "cc" ); 61 62 printk(KERN_INFO "MPCORE found at %p\n", (void *)base_addr); 63 64 /* Fix-map the entire PERIPHBASE 2*4K register block */ 65 desc.virtual = MPCORE_BASE_VA; 66 desc.pfn = __phys_to_pfn( base_addr ); 67 desc.length = SZ_8K; 68 desc.type = MT_DEVICE ; 69 70 iotable_init( &desc, 1); 71 72 periphbase = (void *) MPCORE_BASE_VA; 73 74 /* Local timer code needs just the register base address */ 75 twd_base = periphbase + MPCORE_LTIMER_OFF; 76} 77 78void __init mpcore_init_gic( void ) 79{ 80 printk(KERN_INFO "MPCORE GIC init\n"); 81 82 /* Init GIC interrupt distributor */ 83 gic_dist_init( 0, periphbase + MPCORE_GIC_DIST_OFF, 1 ); 84 85 /* Initialize the GIC CPU interface for the boot processor */ 86 gic_cpu_init( 0, periphbase + MPCORE_GIC_CPUIF_OFF ); 87 88} 89 90void __init mpcore_init_timer( unsigned long perphclk_freq ) 91{ 92 93 /* Init Global Timer */ 94 mpcore_gtimer_init( periphbase + MPCORE_GTIMER_OFF, 95 perphclk_freq, MPCORE_IRQ_GLOBALTIMER ); 96 97} 98 99 100/* 101 * For SMP - initialize GIC CPU interface for secondary cores 102 */ 103void __cpuinit mpcore_cpu_init(void) 104{ 105 /* Initialize the GIC CPU interface for the next processor */ 106 gic_cpu_init( 0, periphbase + MPCORE_GIC_CPUIF_OFF ); 107} 108