aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-mvebu
diff options
context:
space:
mode:
authorThomas Petazzoni <thomas.petazzoni@free-electrons.com>2012-11-22 04:55:09 -0500
committerThomas Petazzoni <thomas.petazzoni@free-electrons.com>2012-11-22 04:55:09 -0500
commit1112b36094e48f89ce7dca5aee90b05c30162da9 (patch)
tree747208380ea58dbb7817b8a7b33336d1fdeb20e2 /arch/arm/mach-mvebu
parenta79cfde1b1d44d6ef62bf30e49d0ec8c8300ae68 (diff)
parent45f5984a8a528f7507f3ec860d297934d4449ad1 (diff)
Merge tag 'marvell-armadaxp-smp-for-3.8' of github.com:MISL-EBU-System-SW/mainline-public into mevbu-dt-additions
SMP support for Armada XP The purpose of this series is to add the SMP support for the Armada XP SoCs. Beside the SMP support itself brought by the last 3 commits, this series also adds the support for the coherency fabric unit and the power management service unit. The coherency fabric is responsible for ensuring hardware coherency between all CPUs and between CPUs and I/O masters. This unit is also available for Armada 370 and will be used in an incoming patch set for hardware I/O cache coherency. The power management service unit is responsible for powering down and waking up CPUs and other SOC units. Conflicts: arch/arm/mach-mvebu/armada-370-xp.c
Diffstat (limited to 'arch/arm/mach-mvebu')
-rw-r--r--arch/arm/mach-mvebu/Kconfig3
-rw-r--r--arch/arm/mach-mvebu/Makefile4
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.c3
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.h7
-rw-r--r--arch/arm/mach-mvebu/coherency.c82
-rw-r--r--arch/arm/mach-mvebu/coherency.h24
-rw-r--r--arch/arm/mach-mvebu/coherency_ll.S49
-rw-r--r--arch/arm/mach-mvebu/common.h5
-rw-r--r--arch/arm/mach-mvebu/headsmp.S49
-rw-r--r--arch/arm/mach-mvebu/hotplug.c30
-rw-r--r--arch/arm/mach-mvebu/irq-armada-370-xp.c92
-rw-r--r--arch/arm/mach-mvebu/platsmp.c122
-rw-r--r--arch/arm/mach-mvebu/pmsu.c75
-rw-r--r--arch/arm/mach-mvebu/pmsu.h16
14 files changed, 553 insertions, 8 deletions
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index 79299cd94f0f..c934e1d4933d 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -21,7 +21,8 @@ menu "Marvell SOC with device tree"
21config MACH_ARMADA_370_XP 21config MACH_ARMADA_370_XP
22 bool 22 bool
23 select ARMADA_370_XP_TIMER 23 select ARMADA_370_XP_TIMER
24 select CPU_V7 24 select HAVE_SMP
25 select CPU_PJ4B
25 26
26config MACH_ARMADA_370 27config MACH_ARMADA_370
27 bool "Marvell Armada 370 boards" 28 bool "Marvell Armada 370 boards"
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 57f996b6aa0e..5dcb369b58aa 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -2,4 +2,6 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
2 -I$(srctree)/arch/arm/plat-orion/include 2 -I$(srctree)/arch/arm/plat-orion/include
3 3
4obj-y += system-controller.o 4obj-y += system-controller.o
5obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o 5obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o coherency.o coherency_ll.o pmsu.o
6obj-$(CONFIG_SMP) += platsmp.o headsmp.o
7obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c
index bd4e13f1b1d7..7434b5e36197 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.c
+++ b/arch/arm/mach-mvebu/armada-370-xp.c
@@ -24,6 +24,7 @@
24#include <asm/mach/time.h> 24#include <asm/mach/time.h>
25#include "armada-370-xp.h" 25#include "armada-370-xp.h"
26#include "common.h" 26#include "common.h"
27#include "coherency.h"
27 28
28static struct map_desc armada_370_xp_io_desc[] __initdata = { 29static struct map_desc armada_370_xp_io_desc[] __initdata = {
29 { 30 {
@@ -62,6 +63,7 @@ struct sys_timer armada_370_xp_timer = {
62static void __init armada_370_xp_dt_init(void) 63static void __init armada_370_xp_dt_init(void)
63{ 64{
64 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 65 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
66 coherency_init();
65} 67}
66 68
67static const char * const armada_370_xp_dt_compat[] = { 69static const char * const armada_370_xp_dt_compat[] = {
@@ -70,6 +72,7 @@ static const char * const armada_370_xp_dt_compat[] = {
70}; 72};
71 73
72DT_MACHINE_START(ARMADA_XP_DT, "Marvell Armada 370/XP (Device Tree)") 74DT_MACHINE_START(ARMADA_XP_DT, "Marvell Armada 370/XP (Device Tree)")
75 .smp = smp_ops(armada_xp_smp_ops),
73 .init_machine = armada_370_xp_dt_init, 76 .init_machine = armada_370_xp_dt_init,
74 .map_io = armada_370_xp_map_io, 77 .map_io = armada_370_xp_map_io,
75 .init_early = armada_370_xp_init_early, 78 .init_early = armada_370_xp_init_early,
diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h
index aac9bebc6b03..c6a7d74fddfe 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.h
+++ b/arch/arm/mach-mvebu/armada-370-xp.h
@@ -19,4 +19,11 @@
19#define ARMADA_370_XP_REGS_VIRT_BASE IOMEM(0xfeb00000) 19#define ARMADA_370_XP_REGS_VIRT_BASE IOMEM(0xfeb00000)
20#define ARMADA_370_XP_REGS_SIZE SZ_1M 20#define ARMADA_370_XP_REGS_SIZE SZ_1M
21 21
22#ifdef CONFIG_SMP
23#include <linux/cpumask.h>
24
25void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq);
26void armada_xp_mpic_smp_cpu_init(void);
27#endif
28
22#endif /* __MACH_ARMADA_370_XP_H */ 29#endif /* __MACH_ARMADA_370_XP_H */
diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c
new file mode 100644
index 000000000000..596ee66a9cc4
--- /dev/null
+++ b/arch/arm/mach-mvebu/coherency.c
@@ -0,0 +1,82 @@
1/*
2 * Coherency fabric (Aurora) support for Armada 370 and XP platforms.
3 *
4 * Copyright (C) 2012 Marvell
5 *
6 * Yehuda Yitschak <yehuday@marvell.com>
7 * Gregory Clement <gregory.clement@free-electrons.com>
8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
9 *
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
13 *
14 * The Armada 370 and Armada XP SOCs have a coherency fabric which is
15 * responsible for ensuring hardware coherency between all CPUs and between
16 * CPUs and I/O masters. This file initializes the coherency fabric and
17 * supplies basic routines for configuring and controlling hardware coherency
18 */
19
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/of_address.h>
23#include <linux/io.h>
24#include <linux/smp.h>
25#include <asm/smp_plat.h>
26#include "armada-370-xp.h"
27
28/*
29 * Some functions in this file are called very early during SMP
30 * initialization. At that time the device tree framework is not yet
31 * ready, and it is not possible to get the register address to
32 * ioremap it. That's why the pointer below is given with an initial
33 * value matching its virtual mapping
34 */
35static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200;
36
37/* Coherency fabric registers */
38#define COHERENCY_FABRIC_CFG_OFFSET 0x4
39
40static struct of_device_id of_coherency_table[] = {
41 {.compatible = "marvell,coherency-fabric"},
42 { /* end of list */ },
43};
44
45#ifdef CONFIG_SMP
46int coherency_get_cpu_count(void)
47{
48 int reg, cnt;
49
50 reg = readl(coherency_base + COHERENCY_FABRIC_CFG_OFFSET);
51 cnt = (reg & 0xF) + 1;
52
53 return cnt;
54}
55#endif
56
57/* Function defined in coherency_ll.S */
58int ll_set_cpu_coherent(void __iomem *base_addr, unsigned int hw_cpu_id);
59
60int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id)
61{
62 if (!coherency_base) {
63 pr_warn("Can't make CPU %d cache coherent.\n", hw_cpu_id);
64 pr_warn("Coherency fabric is not initialized\n");
65 return 1;
66 }
67
68 return ll_set_cpu_coherent(coherency_base, hw_cpu_id);
69}
70
71int __init coherency_init(void)
72{
73 struct device_node *np;
74
75 np = of_find_matching_node(NULL, of_coherency_table);
76 if (np) {
77 pr_info("Initializing Coherency fabric\n");
78 coherency_base = of_iomap(np, 0);
79 }
80
81 return 0;
82}
diff --git a/arch/arm/mach-mvebu/coherency.h b/arch/arm/mach-mvebu/coherency.h
new file mode 100644
index 000000000000..2f428137f6fe
--- /dev/null
+++ b/arch/arm/mach-mvebu/coherency.h
@@ -0,0 +1,24 @@
1/*
2 * arch/arm/mach-mvebu/include/mach/coherency.h
3 *
4 *
5 * Coherency fabric (Aurora) support for Armada 370 and XP platforms.
6 *
7 * Copyright (C) 2012 Marvell
8 *
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
12 */
13
14#ifndef __MACH_370_XP_COHERENCY_H
15#define __MACH_370_XP_COHERENCY_H
16
17#ifdef CONFIG_SMP
18int coherency_get_cpu_count(void);
19#endif
20
21int set_cpu_coherent(int cpu_id, int smp_group_id);
22int coherency_init(void);
23
24#endif /* __MACH_370_XP_COHERENCY_H */
diff --git a/arch/arm/mach-mvebu/coherency_ll.S b/arch/arm/mach-mvebu/coherency_ll.S
new file mode 100644
index 000000000000..53e8391192cd
--- /dev/null
+++ b/arch/arm/mach-mvebu/coherency_ll.S
@@ -0,0 +1,49 @@
1/*
2 * Coherency fabric: low level functions
3 *
4 * Copyright (C) 2012 Marvell
5 *
6 * Gregory CLEMENT <gregory.clement@free-electrons.com>
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 *
12 * This file implements the assembly function to add a CPU to the
13 * coherency fabric. This function is called by each of the secondary
14 * CPUs during their early boot in an SMP kernel, this why this
15 * function have to callable from assembly. It can also be called by a
16 * primary CPU from C code during its boot.
17 */
18
19#include <linux/linkage.h>
20#define ARMADA_XP_CFB_CTL_REG_OFFSET 0x0
21#define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4
22
23 .text
24/*
25 * r0: Coherency fabric base register address
26 * r1: HW CPU id
27 */
28ENTRY(ll_set_cpu_coherent)
29 /* Create bit by cpu index */
30 mov r3, #(1 << 24)
31 lsl r1, r3, r1
32
33 /* Add CPU to SMP group - Atomic */
34 add r3, r0, #ARMADA_XP_CFB_CTL_REG_OFFSET
35 ldr r2, [r3]
36 orr r2, r2, r1
37 str r2, [r3]
38
39 /* Enable coherency on CPU - Atomic */
40 add r3, r0, #ARMADA_XP_CFB_CFG_REG_OFFSET
41 ldr r2, [r3]
42 orr r2, r2, r1
43 str r2, [r3]
44
45 dsb
46
47 mov r0, #0
48 mov pc, lr
49ENDPROC(ll_set_cpu_coherent)
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h
index 02f89eaa25fe..aa27bc2ffb60 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -20,4 +20,9 @@ void mvebu_restart(char mode, const char *cmd);
20void armada_370_xp_init_irq(void); 20void armada_370_xp_init_irq(void);
21void armada_370_xp_handle_irq(struct pt_regs *regs); 21void armada_370_xp_handle_irq(struct pt_regs *regs);
22 22
23void armada_xp_cpu_die(unsigned int cpu);
24int armada_370_xp_coherency_init(void);
25int armada_370_xp_pmsu_init(void);
26void armada_xp_secondary_startup(void);
27extern struct smp_operations armada_xp_smp_ops;
23#endif 28#endif
diff --git a/arch/arm/mach-mvebu/headsmp.S b/arch/arm/mach-mvebu/headsmp.S
new file mode 100644
index 000000000000..a06e0ede8c08
--- /dev/null
+++ b/arch/arm/mach-mvebu/headsmp.S
@@ -0,0 +1,49 @@
1/*
2 * SMP support: Entry point for secondary CPUs
3 *
4 * Copyright (C) 2012 Marvell
5 *
6 * Yehuda Yitschak <yehuday@marvell.com>
7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
9 *
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
13 *
14 * This file implements the assembly entry point for secondary CPUs in
15 * an SMP kernel. The only thing we need to do is to add the CPU to
16 * the coherency fabric by writing to 2 registers. Currently the base
17 * register addresses are hard coded due to the early initialisation
18 * problems.
19 */
20
21#include <linux/linkage.h>
22#include <linux/init.h>
23
24/*
25 * At this stage the secondary CPUs don't have acces yet to the MMU, so
26 * we have to provide physical addresses
27 */
28#define ARMADA_XP_CFB_BASE 0xD0020200
29
30 __CPUINIT
31
32/*
33 * Armada XP specific entry point for secondary CPUs.
34 * We add the CPU to the coherency fabric and then jump to secondary
35 * startup
36 */
37ENTRY(armada_xp_secondary_startup)
38
39 /* Read CPU id */
40 mrc p15, 0, r1, c0, c0, 5
41 and r1, r1, #0xF
42
43 /* Add CPU to coherency fabric */
44 ldr r0, =ARMADA_XP_CFB_BASE
45
46 bl ll_set_cpu_coherent
47 b secondary_startup
48
49ENDPROC(armada_xp_secondary_startup)
diff --git a/arch/arm/mach-mvebu/hotplug.c b/arch/arm/mach-mvebu/hotplug.c
new file mode 100644
index 000000000000..b228b6a80c85
--- /dev/null
+++ b/arch/arm/mach-mvebu/hotplug.c
@@ -0,0 +1,30 @@
1/*
2 * Symmetric Multi Processing (SMP) support for Armada XP
3 *
4 * Copyright (C) 2012 Marvell
5 *
6 * Lior Amsalem <alior@marvell.com>
7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
9 *
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
13 */
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/smp.h>
17#include <asm/proc-fns.h>
18
19/*
20 * platform-specific code to shutdown a CPU
21 *
22 * Called with IRQs disabled
23 */
24void __ref armada_xp_cpu_die(unsigned int cpu)
25{
26 cpu_do_idle();
27
28 /* We should never return from idle */
29 panic("mvebu: cpu %d unexpectedly exit from shutdown\n", cpu);
30}
diff --git a/arch/arm/mach-mvebu/irq-armada-370-xp.c b/arch/arm/mach-mvebu/irq-armada-370-xp.c
index 5f5f9394b6b2..549b6846f940 100644
--- a/arch/arm/mach-mvebu/irq-armada-370-xp.c
+++ b/arch/arm/mach-mvebu/irq-armada-370-xp.c
@@ -24,6 +24,7 @@
24#include <linux/irqdomain.h> 24#include <linux/irqdomain.h>
25#include <asm/mach/arch.h> 25#include <asm/mach/arch.h>
26#include <asm/exception.h> 26#include <asm/exception.h>
27#include <asm/smp_plat.h>
27 28
28/* Interrupt Controller Registers Map */ 29/* Interrupt Controller Registers Map */
29#define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) 30#define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48)
@@ -35,6 +36,12 @@
35 36
36#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44) 37#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
37 38
39#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4)
40#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
41#define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS (0x8)
42
43#define ACTIVE_DOORBELLS (8)
44
38static void __iomem *per_cpu_int_base; 45static void __iomem *per_cpu_int_base;
39static void __iomem *main_int_base; 46static void __iomem *main_int_base;
40static struct irq_domain *armada_370_xp_mpic_domain; 47static struct irq_domain *armada_370_xp_mpic_domain;
@@ -51,11 +58,22 @@ static void armada_370_xp_irq_unmask(struct irq_data *d)
51 per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 58 per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
52} 59}
53 60
61#ifdef CONFIG_SMP
62static int armada_xp_set_affinity(struct irq_data *d,
63 const struct cpumask *mask_val, bool force)
64{
65 return 0;
66}
67#endif
68
54static struct irq_chip armada_370_xp_irq_chip = { 69static struct irq_chip armada_370_xp_irq_chip = {
55 .name = "armada_370_xp_irq", 70 .name = "armada_370_xp_irq",
56 .irq_mask = armada_370_xp_irq_mask, 71 .irq_mask = armada_370_xp_irq_mask,
57 .irq_mask_ack = armada_370_xp_irq_mask, 72 .irq_mask_ack = armada_370_xp_irq_mask,
58 .irq_unmask = armada_370_xp_irq_unmask, 73 .irq_unmask = armada_370_xp_irq_unmask,
74#ifdef CONFIG_SMP
75 .irq_set_affinity = armada_xp_set_affinity,
76#endif
59}; 77};
60 78
61static int armada_370_xp_mpic_irq_map(struct irq_domain *h, 79static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
@@ -72,6 +90,41 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
72 return 0; 90 return 0;
73} 91}
74 92
93#ifdef CONFIG_SMP
94void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq)
95{
96 int cpu;
97 unsigned long map = 0;
98
99 /* Convert our logical CPU mask into a physical one. */
100 for_each_cpu(cpu, mask)
101 map |= 1 << cpu_logical_map(cpu);
102
103 /*
104 * Ensure that stores to Normal memory are visible to the
105 * other CPUs before issuing the IPI.
106 */
107 dsb();
108
109 /* submit softirq */
110 writel((map << 8) | irq, main_int_base +
111 ARMADA_370_XP_SW_TRIG_INT_OFFS);
112}
113
114void armada_xp_mpic_smp_cpu_init(void)
115{
116 /* Clear pending IPIs */
117 writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
118
119 /* Enable first 8 IPIs */
120 writel((1 << ACTIVE_DOORBELLS) - 1, per_cpu_int_base +
121 ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
122
123 /* Unmask IPI interrupt */
124 writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
125}
126#endif /* CONFIG_SMP */
127
75static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { 128static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
76 .map = armada_370_xp_mpic_irq_map, 129 .map = armada_370_xp_mpic_irq_map,
77 .xlate = irq_domain_xlate_onecell, 130 .xlate = irq_domain_xlate_onecell,
@@ -91,13 +144,18 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
91 control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL); 144 control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
92 145
93 armada_370_xp_mpic_domain = 146 armada_370_xp_mpic_domain =
94 irq_domain_add_linear(node, (control >> 2) & 0x3ff, 147 irq_domain_add_linear(node, (control >> 2) & 0x3ff,
95 &armada_370_xp_mpic_irq_ops, NULL); 148 &armada_370_xp_mpic_irq_ops, NULL);
96 149
97 if (!armada_370_xp_mpic_domain) 150 if (!armada_370_xp_mpic_domain)
98 panic("Unable to add Armada_370_Xp MPIC irq domain (DT)\n"); 151 panic("Unable to add Armada_370_Xp MPIC irq domain (DT)\n");
99 152
100 irq_set_default_host(armada_370_xp_mpic_domain); 153 irq_set_default_host(armada_370_xp_mpic_domain);
154
155#ifdef CONFIG_SMP
156 armada_xp_mpic_smp_cpu_init();
157#endif
158
101 return 0; 159 return 0;
102} 160}
103 161
@@ -111,14 +169,36 @@ asmlinkage void __exception_irq_entry armada_370_xp_handle_irq(struct pt_regs
111 ARMADA_370_XP_CPU_INTACK_OFFS); 169 ARMADA_370_XP_CPU_INTACK_OFFS);
112 irqnr = irqstat & 0x3FF; 170 irqnr = irqstat & 0x3FF;
113 171
114 if (irqnr < 1023) { 172 if (irqnr > 1022)
115 irqnr = 173 break;
116 irq_find_mapping(armada_370_xp_mpic_domain, irqnr); 174
175 if (irqnr >= 8) {
176 irqnr = irq_find_mapping(armada_370_xp_mpic_domain,
177 irqnr);
117 handle_IRQ(irqnr, regs); 178 handle_IRQ(irqnr, regs);
118 continue; 179 continue;
119 } 180 }
181#ifdef CONFIG_SMP
182 /* IPI Handling */
183 if (irqnr == 0) {
184 u32 ipimask, ipinr;
185
186 ipimask = readl_relaxed(per_cpu_int_base +
187 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
188 & 0xFF;
189
190 writel(0x0, per_cpu_int_base +
191 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
192
193 /* Handle all pending doorbells */
194 for (ipinr = 0; ipinr < ACTIVE_DOORBELLS; ipinr++) {
195 if (ipimask & (0x1 << ipinr))
196 handle_IPI(ipinr, regs);
197 }
198 continue;
199 }
200#endif
120 201
121 break;
122 } while (1); 202 } while (1);
123} 203}
124 204
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c
new file mode 100644
index 000000000000..fe16aaf7c19c
--- /dev/null
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -0,0 +1,122 @@
1/*
2 * Symmetric Multi Processing (SMP) support for Armada XP
3 *
4 * Copyright (C) 2012 Marvell
5 *
6 * Lior Amsalem <alior@marvell.com>
7 * Yehuda Yitschak <yehuday@marvell.com>
8 * Gregory CLEMENT <gregory.clement@free-electrons.com>
9 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
10 *
11 * This file is licensed under the terms of the GNU General Public
12 * License version 2. This program is licensed "as is" without any
13 * warranty of any kind, whether express or implied.
14 *
15 * The Armada XP SoC has 4 ARMv7 PJ4B CPUs running in full HW coherency
16 * This file implements the routines for preparing the SMP infrastructure
17 * and waking up the secondary CPUs
18 */
19
20#include <linux/init.h>
21#include <linux/smp.h>
22#include <linux/clk.h>
23#include <linux/of.h>
24#include <asm/cacheflush.h>
25#include <asm/smp_plat.h>
26#include "common.h"
27#include "armada-370-xp.h"
28#include "pmsu.h"
29#include "coherency.h"
30
31void __init set_secondary_cpus_clock(void)
32{
33 int thiscpu;
34 unsigned long rate;
35 struct clk *cpu_clk = NULL;
36 struct device_node *np = NULL;
37
38 thiscpu = smp_processor_id();
39 for_each_node_by_type(np, "cpu") {
40 int err;
41 int cpu;
42
43 err = of_property_read_u32(np, "reg", &cpu);
44 if (WARN_ON(err))
45 return;
46
47 if (cpu == thiscpu) {
48 cpu_clk = of_clk_get(np, 0);
49 break;
50 }
51 }
52 if (WARN_ON(IS_ERR(cpu_clk)))
53 return;
54 clk_prepare_enable(cpu_clk);
55 rate = clk_get_rate(cpu_clk);
56
57 /* set all the other CPU clk to the same rate than the boot CPU */
58 for_each_node_by_type(np, "cpu") {
59 int err;
60 int cpu;
61
62 err = of_property_read_u32(np, "reg", &cpu);
63 if (WARN_ON(err))
64 return;
65
66 if (cpu != thiscpu) {
67 cpu_clk = of_clk_get(np, 0);
68 clk_set_rate(cpu_clk, rate);
69 }
70 }
71}
72
73static void __cpuinit armada_xp_secondary_init(unsigned int cpu)
74{
75 armada_xp_mpic_smp_cpu_init();
76}
77
78static int __cpuinit armada_xp_boot_secondary(unsigned int cpu,
79 struct task_struct *idle)
80{
81 pr_info("Booting CPU %d\n", cpu);
82
83 armada_xp_boot_cpu(cpu, armada_xp_secondary_startup);
84
85 return 0;
86}
87
88static void __init armada_xp_smp_init_cpus(void)
89{
90 unsigned int i, ncores;
91 ncores = coherency_get_cpu_count();
92
93 /* Limit possible CPUs to defconfig */
94 if (ncores > nr_cpu_ids) {
95 pr_warn("SMP: %d CPUs physically present. Only %d configured.",
96 ncores, nr_cpu_ids);
97 pr_warn("Clipping CPU count to %d\n", nr_cpu_ids);
98 ncores = nr_cpu_ids;
99 }
100
101 for (i = 0; i < ncores; i++)
102 set_cpu_possible(i, true);
103
104 set_smp_cross_call(armada_mpic_send_doorbell);
105}
106
107void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
108{
109 set_secondary_cpus_clock();
110 flush_cache_all();
111 set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
112}
113
114struct smp_operations armada_xp_smp_ops __initdata = {
115 .smp_init_cpus = armada_xp_smp_init_cpus,
116 .smp_prepare_cpus = armada_xp_smp_prepare_cpus,
117 .smp_secondary_init = armada_xp_secondary_init,
118 .smp_boot_secondary = armada_xp_boot_secondary,
119#ifdef CONFIG_HOTPLUG_CPU
120 .cpu_die = armada_xp_cpu_die,
121#endif
122};
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
new file mode 100644
index 000000000000..3cc4bef6401c
--- /dev/null
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -0,0 +1,75 @@
1/*
2 * Power Management Service Unit(PMSU) support for Armada 370/XP platforms.
3 *
4 * Copyright (C) 2012 Marvell
5 *
6 * Yehuda Yitschak <yehuday@marvell.com>
7 * Gregory Clement <gregory.clement@free-electrons.com>
8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
9 *
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
13 *
14 * The Armada 370 and Armada XP SOCs have a power management service
15 * unit which is responsible for powering down and waking up CPUs and
16 * other SOC units
17 */
18
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/of_address.h>
22#include <linux/io.h>
23#include <linux/smp.h>
24#include <asm/smp_plat.h>
25
26static void __iomem *pmsu_mp_base;
27static void __iomem *pmsu_reset_base;
28
29#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x24)
30#define PMSU_RESET_CTL_OFFSET(cpu) (cpu * 0x8)
31
32static struct of_device_id of_pmsu_table[] = {
33 {.compatible = "marvell,armada-370-xp-pmsu"},
34 { /* end of list */ },
35};
36
37#ifdef CONFIG_SMP
38int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
39{
40 int reg, hw_cpu;
41
42 if (!pmsu_mp_base || !pmsu_reset_base) {
43 pr_warn("Can't boot CPU. PMSU is uninitialized\n");
44 return 1;
45 }
46
47 hw_cpu = cpu_logical_map(cpu_id);
48
49 writel(virt_to_phys(boot_addr), pmsu_mp_base +
50 PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
51
52 /* Release CPU from reset by clearing reset bit*/
53 reg = readl(pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu));
54 reg &= (~0x1);
55 writel(reg, pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu));
56
57 return 0;
58}
59#endif
60
61int __init armada_370_xp_pmsu_init(void)
62{
63 struct device_node *np;
64
65 np = of_find_matching_node(NULL, of_pmsu_table);
66 if (np) {
67 pr_info("Initializing Power Management Service Unit\n");
68 pmsu_mp_base = of_iomap(np, 0);
69 pmsu_reset_base = of_iomap(np, 1);
70 }
71
72 return 0;
73}
74
75early_initcall(armada_370_xp_pmsu_init);
diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h
new file mode 100644
index 000000000000..07a737c6b95d
--- /dev/null
+++ b/arch/arm/mach-mvebu/pmsu.h
@@ -0,0 +1,16 @@
1/*
2 * Power Management Service Unit (PMSU) support for Armada 370/XP platforms.
3 *
4 * Copyright (C) 2012 Marvell
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 */
10
11#ifndef __MACH_MVEBU_PMSU_H
12#define __MACH_MVEBU_PMSU_H
13
14int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr);
15
16#endif /* __MACH_370_XP_PMSU_H */