aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile/smp-sh73a0.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-shmobile/smp-sh73a0.c')
-rw-r--r--arch/arm/mach-shmobile/smp-sh73a0.c70
1 files changed, 36 insertions, 34 deletions
diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c
index 624f00f70abf..acb46a94ccdf 100644
--- a/arch/arm/mach-shmobile/smp-sh73a0.c
+++ b/arch/arm/mach-shmobile/smp-sh73a0.c
@@ -23,12 +23,13 @@
23#include <linux/spinlock.h> 23#include <linux/spinlock.h>
24#include <linux/io.h> 24#include <linux/io.h>
25#include <linux/delay.h> 25#include <linux/delay.h>
26#include <linux/irqchip/arm-gic.h>
26#include <mach/common.h> 27#include <mach/common.h>
28#include <asm/cacheflush.h>
27#include <asm/smp_plat.h> 29#include <asm/smp_plat.h>
28#include <mach/sh73a0.h> 30#include <mach/sh73a0.h>
29#include <asm/smp_scu.h> 31#include <asm/smp_scu.h>
30#include <asm/smp_twd.h> 32#include <asm/smp_twd.h>
31#include <asm/hardware/gic.h>
32 33
33#define WUPCR IOMEM(0xe6151010) 34#define WUPCR IOMEM(0xe6151010)
34#define SRESCR IOMEM(0xe6151018) 35#define SRESCR IOMEM(0xe6151018)
@@ -36,14 +37,13 @@
36#define SBAR IOMEM(0xe6180020) 37#define SBAR IOMEM(0xe6180020)
37#define APARMBAREA IOMEM(0xe6f10020) 38#define APARMBAREA IOMEM(0xe6f10020)
38 39
40#define PSTR_SHUTDOWN_MODE 3
41
39static void __iomem *scu_base_addr(void) 42static void __iomem *scu_base_addr(void)
40{ 43{
41 return (void __iomem *)0xf0000000; 44 return (void __iomem *)0xf0000000;
42} 45}
43 46
44static DEFINE_SPINLOCK(scu_lock);
45static unsigned long tmp;
46
47#ifdef CONFIG_HAVE_ARM_TWD 47#ifdef CONFIG_HAVE_ARM_TWD
48static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29); 48static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, 0xf0000600, 29);
49void __init sh73a0_register_twd(void) 49void __init sh73a0_register_twd(void)
@@ -52,20 +52,6 @@ void __init sh73a0_register_twd(void)
52} 52}
53#endif 53#endif
54 54
55static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
56{
57 void __iomem *scu_base = scu_base_addr();
58
59 spin_lock(&scu_lock);
60 tmp = __raw_readl(scu_base + 8);
61 tmp &= ~clr;
62 tmp |= set;
63 spin_unlock(&scu_lock);
64
65 /* disable cache coherency after releasing the lock */
66 __raw_writel(tmp, scu_base + 8);
67}
68
69static unsigned int __init sh73a0_get_core_count(void) 55static unsigned int __init sh73a0_get_core_count(void)
70{ 56{
71 void __iomem *scu_base = scu_base_addr(); 57 void __iomem *scu_base = scu_base_addr();
@@ -82,9 +68,6 @@ static int __cpuinit sh73a0_boot_secondary(unsigned int cpu, struct task_struct
82{ 68{
83 cpu = cpu_logical_map(cpu); 69 cpu = cpu_logical_map(cpu);
84 70
85 /* enable cache coherency */
86 modify_scu_cpu_psr(0, 3 << (cpu * 8));
87
88 if (((__raw_readl(PSTR) >> (4 * cpu)) & 3) == 3) 71 if (((__raw_readl(PSTR) >> (4 * cpu)) & 3) == 3)
89 __raw_writel(1 << cpu, WUPCR); /* wake up */ 72 __raw_writel(1 << cpu, WUPCR); /* wake up */
90 else 73 else
@@ -95,16 +78,14 @@ static int __cpuinit sh73a0_boot_secondary(unsigned int cpu, struct task_struct
95 78
96static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus) 79static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus)
97{ 80{
98 int cpu = cpu_logical_map(0);
99
100 scu_enable(scu_base_addr()); 81 scu_enable(scu_base_addr());
101 82
102 /* Map the reset vector (in headsmp.S) */ 83 /* Map the reset vector (in headsmp-sh73a0.S) */
103 __raw_writel(0, APARMBAREA); /* 4k */ 84 __raw_writel(0, APARMBAREA); /* 4k */
104 __raw_writel(__pa(shmobile_secondary_vector), SBAR); 85 __raw_writel(__pa(sh73a0_secondary_vector), SBAR);
105 86
106 /* enable cache coherency on CPU0 */ 87 /* enable cache coherency on booting CPU */
107 modify_scu_cpu_psr(0, 3 << (cpu * 8)); 88 scu_power_mode(scu_base_addr(), SCU_PM_NORMAL);
108} 89}
109 90
110static void __init sh73a0_smp_init_cpus(void) 91static void __init sh73a0_smp_init_cpus(void)
@@ -114,16 +95,20 @@ static void __init sh73a0_smp_init_cpus(void)
114 shmobile_smp_init_cpus(ncores); 95 shmobile_smp_init_cpus(ncores);
115} 96}
116 97
117static int __maybe_unused sh73a0_cpu_kill(unsigned int cpu) 98#ifdef CONFIG_HOTPLUG_CPU
99static int sh73a0_cpu_kill(unsigned int cpu)
118{ 100{
101
119 int k; 102 int k;
103 u32 pstr;
120 104
121 /* this function is running on another CPU than the offline target, 105 /*
122 * here we need wait for shutdown code in platform_cpu_die() to 106 * wait until the power status register confirms the shutdown of the
123 * finish before asking SoC-specific code to power off the CPU core. 107 * offline target
124 */ 108 */
125 for (k = 0; k < 1000; k++) { 109 for (k = 0; k < 1000; k++) {
126 if (shmobile_cpu_is_dead(cpu)) 110 pstr = (__raw_readl(PSTR) >> (4 * cpu)) & 3;
111 if (pstr == PSTR_SHUTDOWN_MODE)
127 return 1; 112 return 1;
128 113
129 mdelay(1); 114 mdelay(1);
@@ -132,6 +117,23 @@ static int __maybe_unused sh73a0_cpu_kill(unsigned int cpu)
132 return 0; 117 return 0;
133} 118}
134 119
120static void sh73a0_cpu_die(unsigned int cpu)
121{
122 /*
123 * The ARM MPcore does not issue a cache coherency request for the L1
124 * cache when powering off single CPUs. We must take care of this and
125 * further caches.
126 */
127 dsb();
128 flush_cache_all();
129
130 /* Set power off mode. This takes the CPU out of the MP cluster */
131 scu_power_mode(scu_base_addr(), SCU_PM_POWEROFF);
132
133 /* Enter shutdown mode */
134 cpu_do_idle();
135}
136#endif /* CONFIG_HOTPLUG_CPU */
135 137
136struct smp_operations sh73a0_smp_ops __initdata = { 138struct smp_operations sh73a0_smp_ops __initdata = {
137 .smp_init_cpus = sh73a0_smp_init_cpus, 139 .smp_init_cpus = sh73a0_smp_init_cpus,
@@ -140,7 +142,7 @@ struct smp_operations sh73a0_smp_ops __initdata = {
140 .smp_boot_secondary = sh73a0_boot_secondary, 142 .smp_boot_secondary = sh73a0_boot_secondary,
141#ifdef CONFIG_HOTPLUG_CPU 143#ifdef CONFIG_HOTPLUG_CPU
142 .cpu_kill = sh73a0_cpu_kill, 144 .cpu_kill = sh73a0_cpu_kill,
143 .cpu_die = shmobile_cpu_die, 145 .cpu_die = sh73a0_cpu_die,
144 .cpu_disable = shmobile_cpu_disable, 146 .cpu_disable = shmobile_cpu_disable_any,
145#endif 147#endif
146}; 148};