xref: /openbmc/linux/arch/arm/mach-omap2/omap-smp.c (revision 4dc7ccf7)
1 /*
2  * OMAP4 SMP source file. It contains platform specific fucntions
3  * needed for the linux smp kernel.
4  *
5  * Copyright (C) 2009 Texas Instruments, Inc.
6  *
7  * Author:
8  *      Santosh Shilimkar <santosh.shilimkar@ti.com>
9  *
10  * Platform file needed for the OMAP4 SMP. This file is based on arm
11  * realview smp platform.
12  * * Copyright (c) 2002 ARM Limited.
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License version 2 as
16  * published by the Free Software Foundation.
17  */
18 #include <linux/init.h>
19 #include <linux/device.h>
20 #include <linux/smp.h>
21 #include <linux/io.h>
22 
23 #include <asm/cacheflush.h>
24 #include <asm/localtimer.h>
25 #include <asm/smp_scu.h>
26 #include <mach/hardware.h>
27 #include <plat/common.h>
28 
29 /* SCU base address */
30 static void __iomem *scu_base;
31 
32 /*
33  * Use SCU config register to count number of cores
34  */
35 static inline unsigned int get_core_count(void)
36 {
37 	if (scu_base)
38 		return scu_get_core_count(scu_base);
39 	return 1;
40 }
41 
42 static DEFINE_SPINLOCK(boot_lock);
43 
44 void __cpuinit platform_secondary_init(unsigned int cpu)
45 {
46 	trace_hardirqs_off();
47 
48 	/*
49 	 * If any interrupts are already enabled for the primary
50 	 * core (e.g. timer irq), then they will not have been enabled
51 	 * for us: do so
52 	 */
53 	gic_cpu_init(0, gic_cpu_base_addr);
54 
55 	/*
56 	 * Synchronise with the boot thread.
57 	 */
58 	spin_lock(&boot_lock);
59 	spin_unlock(&boot_lock);
60 }
61 
62 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
63 {
64 	/*
65 	 * Set synchronisation state between this boot processor
66 	 * and the secondary one
67 	 */
68 	spin_lock(&boot_lock);
69 
70 	/*
71 	 * Update the AuxCoreBoot0 with boot state for secondary core.
72 	 * omap_secondary_startup() routine will hold the secondary core till
73 	 * the AuxCoreBoot1 register is updated with cpu state
74 	 * A barrier is added to ensure that write buffer is drained
75 	 */
76 	omap_modify_auxcoreboot0(0x200, 0x0);
77 	flush_cache_all();
78 	smp_wmb();
79 
80 	/*
81 	 * Now the secondary core is starting up let it run its
82 	 * calibrations, then wait for it to finish
83 	 */
84 	spin_unlock(&boot_lock);
85 
86 	return 0;
87 }
88 
89 static void __init wakeup_secondary(void)
90 {
91 	/*
92 	 * Write the address of secondary startup routine into the
93 	 * AuxCoreBoot1 where ROM code will jump and start executing
94 	 * on secondary core once out of WFE
95 	 * A barrier is added to ensure that write buffer is drained
96 	 */
97 	omap_auxcoreboot_addr(virt_to_phys(omap_secondary_startup));
98 	smp_wmb();
99 
100 	/*
101 	 * Send a 'sev' to wake the secondary core from WFE.
102 	 * Drain the outstanding writes to memory
103 	 */
104 	dsb();
105 	set_event();
106 	mb();
107 }
108 
109 /*
110  * Initialise the CPU possible map early - this describes the CPUs
111  * which may be present or become present in the system.
112  */
113 void __init smp_init_cpus(void)
114 {
115 	unsigned int i, ncores;
116 
117 	/* Never released */
118 	scu_base = ioremap(OMAP44XX_SCU_BASE, SZ_256);
119 	BUG_ON(!scu_base);
120 
121 	ncores = get_core_count();
122 
123 	for (i = 0; i < ncores; i++)
124 		set_cpu_possible(i, true);
125 }
126 
127 void __init smp_prepare_cpus(unsigned int max_cpus)
128 {
129 	unsigned int ncores = get_core_count();
130 	unsigned int cpu = smp_processor_id();
131 	int i;
132 
133 	/* sanity check */
134 	if (ncores == 0) {
135 		printk(KERN_ERR
136 		       "OMAP4: strange core count of 0? Default to 1\n");
137 		ncores = 1;
138 	}
139 
140 	if (ncores > NR_CPUS) {
141 		printk(KERN_WARNING
142 		       "OMAP4: no. of cores (%d) greater than configured "
143 		       "maximum of %d - clipping\n",
144 		       ncores, NR_CPUS);
145 		ncores = NR_CPUS;
146 	}
147 	smp_store_cpu_info(cpu);
148 
149 	/*
150 	 * are we trying to boot more cores than exist?
151 	 */
152 	if (max_cpus > ncores)
153 		max_cpus = ncores;
154 
155 	/*
156 	 * Initialise the present map, which describes the set of CPUs
157 	 * actually populated at the present time.
158 	 */
159 	for (i = 0; i < max_cpus; i++)
160 		set_cpu_present(i, true);
161 
162 	if (max_cpus > 1) {
163 		/*
164 		 * Enable the local timer or broadcast device for the
165 		 * boot CPU, but only if we have more than one CPU.
166 		 */
167 		percpu_timer_setup();
168 
169 		/*
170 		 * Initialise the SCU and wake up the secondary core using
171 		 * wakeup_secondary().
172 		 */
173 		scu_enable(scu_base);
174 		wakeup_secondary();
175 	}
176 }
177