diff options
27 files changed, 774 insertions, 15 deletions
diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt index 70c0dc5f00ed..61df564c0d23 100644 --- a/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt +++ b/Documentation/devicetree/bindings/arm/armada-370-xp-mpic.txt | |||
@@ -6,9 +6,15 @@ Required properties: | |||
6 | - interrupt-controller: Identifies the node as an interrupt controller. | 6 | - interrupt-controller: Identifies the node as an interrupt controller. |
7 | - #interrupt-cells: The number of cells to define the interrupts. Should be 1. | 7 | - #interrupt-cells: The number of cells to define the interrupts. Should be 1. |
8 | The cell is the IRQ number | 8 | The cell is the IRQ number |
9 | |||
9 | - reg: Should contain PMIC registers location and length. First pair | 10 | - reg: Should contain PMIC registers location and length. First pair |
10 | for the main interrupt registers, second pair for the per-CPU | 11 | for the main interrupt registers, second pair for the per-CPU |
11 | interrupt registers | 12 | interrupt registers. For this last pair, to be compliant with SMP |
13 | support, the "virtual" must be use (For the record, these registers | ||
14 | automatically map to the interrupt controller registers of the | ||
15 | current CPU) | ||
16 | |||
17 | |||
12 | 18 | ||
13 | Example: | 19 | Example: |
14 | 20 | ||
@@ -18,6 +24,6 @@ Example: | |||
18 | #address-cells = <1>; | 24 | #address-cells = <1>; |
19 | #size-cells = <1>; | 25 | #size-cells = <1>; |
20 | interrupt-controller; | 26 | interrupt-controller; |
21 | reg = <0xd0020000 0x1000>, | 27 | reg = <0xd0020a00 0x1d0>, |
22 | <0xd0021000 0x1000>; | 28 | <0xd0021070 0x58>; |
23 | }; | 29 | }; |
diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt new file mode 100644 index 000000000000..926b4d6aae7e --- /dev/null +++ b/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt | |||
@@ -0,0 +1,20 @@ | |||
1 | Power Management Service Unit(PMSU) | ||
2 | ----------------------------------- | ||
3 | Available on Marvell SOCs: Armada 370 and Armada XP | ||
4 | |||
5 | Required properties: | ||
6 | |||
7 | - compatible: "marvell,armada-370-xp-pmsu" | ||
8 | |||
9 | - reg: Should contain PMSU registers location and length. First pair | ||
10 | for the per-CPU SW Reset Control registers, second pair for the | ||
11 | Power Management Service Unit. | ||
12 | |||
13 | Example: | ||
14 | |||
15 | armada-370-xp-pmsu@d0022000 { | ||
16 | compatible = "marvell,armada-370-xp-pmsu"; | ||
17 | reg = <0xd0022100 0x430>, | ||
18 | <0xd0020800 0x20>; | ||
19 | }; | ||
20 | |||
diff --git a/Documentation/devicetree/bindings/arm/coherency-fabric.txt b/Documentation/devicetree/bindings/arm/coherency-fabric.txt new file mode 100644 index 000000000000..17d8cd107559 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/coherency-fabric.txt | |||
@@ -0,0 +1,21 @@ | |||
1 | Coherency fabric | ||
2 | ---------------- | ||
3 | Available on Marvell SOCs: Armada 370 and Armada XP | ||
4 | |||
5 | Required properties: | ||
6 | |||
7 | - compatible: "marvell,coherency-fabric" | ||
8 | |||
9 | - reg: Should contain coherency fabric registers location and | ||
10 | length. First pair for the coherency fabric registers, second pair | ||
11 | for the per-CPU fabric registers registers. | ||
12 | |||
13 | Example: | ||
14 | |||
15 | coherency-fabric@d0020200 { | ||
16 | compatible = "marvell,coherency-fabric"; | ||
17 | reg = <0xd0020200 0xb0>, | ||
18 | <0xd0021810 0x1c>; | ||
19 | |||
20 | }; | ||
21 | |||
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi index 70c35f8ccf90..cb09d0882c3d 100644 --- a/arch/arm/boot/dts/armada-370-xp.dtsi +++ b/arch/arm/boot/dts/armada-370-xp.dtsi | |||
@@ -36,6 +36,12 @@ | |||
36 | interrupt-controller; | 36 | interrupt-controller; |
37 | }; | 37 | }; |
38 | 38 | ||
39 | coherency-fabric@d0020200 { | ||
40 | compatible = "marvell,coherency-fabric"; | ||
41 | reg = <0xd0020200 0xb0>, | ||
42 | <0xd0021810 0x1c>; | ||
43 | }; | ||
44 | |||
39 | soc { | 45 | soc { |
40 | #address-cells = <1>; | 46 | #address-cells = <1>; |
41 | #size-cells = <1>; | 47 | #size-cells = <1>; |
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi index 3c52e7ab1910..45a567c2e9ba 100644 --- a/arch/arm/boot/dts/armada-xp.dtsi +++ b/arch/arm/boot/dts/armada-xp.dtsi | |||
@@ -24,7 +24,13 @@ | |||
24 | 24 | ||
25 | mpic: interrupt-controller@d0020000 { | 25 | mpic: interrupt-controller@d0020000 { |
26 | reg = <0xd0020a00 0x1d0>, | 26 | reg = <0xd0020a00 0x1d0>, |
27 | <0xd0021870 0x58>; | 27 | <0xd0021070 0x58>; |
28 | }; | ||
29 | |||
30 | armada-370-xp-pmsu@d0022000 { | ||
31 | compatible = "marvell,armada-370-xp-pmsu"; | ||
32 | reg = <0xd0022100 0x430>, | ||
33 | <0xd0020800 0x20>; | ||
28 | }; | 34 | }; |
29 | 35 | ||
30 | soc { | 36 | soc { |
diff --git a/arch/arm/configs/mvebu_defconfig b/arch/arm/configs/mvebu_defconfig index 73b53fc06638..a702fb345c01 100644 --- a/arch/arm/configs/mvebu_defconfig +++ b/arch/arm/configs/mvebu_defconfig | |||
@@ -12,6 +12,9 @@ CONFIG_ARCH_MVEBU=y | |||
12 | CONFIG_MACH_ARMADA_370=y | 12 | CONFIG_MACH_ARMADA_370=y |
13 | CONFIG_MACH_ARMADA_XP=y | 13 | CONFIG_MACH_ARMADA_XP=y |
14 | # CONFIG_CACHE_L2X0 is not set | 14 | # CONFIG_CACHE_L2X0 is not set |
15 | # CONFIG_SWP_EMULATE is not set | ||
16 | CONFIG_SMP=y | ||
17 | # CONFIG_LOCAL_TIMERS is not set | ||
15 | CONFIG_AEABI=y | 18 | CONFIG_AEABI=y |
16 | CONFIG_HIGHMEM=y | 19 | CONFIG_HIGHMEM=y |
17 | # CONFIG_COMPACTION is not set | 20 | # CONFIG_COMPACTION is not set |
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 23004847bb05..98d4dabb2c10 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h | |||
@@ -111,6 +111,8 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size, | |||
111 | 111 | ||
112 | extern int dma_supported(struct device *dev, u64 mask); | 112 | extern int dma_supported(struct device *dev, u64 mask); |
113 | 113 | ||
114 | extern int arm_dma_set_mask(struct device *dev, u64 dma_mask); | ||
115 | |||
114 | /** | 116 | /** |
115 | * arm_dma_alloc - allocate consistent memory for DMA | 117 | * arm_dma_alloc - allocate consistent memory for DMA |
116 | * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices | 118 | * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices |
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" | |||
21 | config MACH_ARMADA_370_XP | 21 | config 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 | ||
26 | config MACH_ARMADA_370 | 27 | config 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 | ||
4 | obj-y += system-controller.o | 4 | obj-y += system-controller.o |
5 | obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o | 5 | obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o coherency.o coherency_ll.o pmsu.o |
6 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | ||
7 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | ||
diff --git a/arch/arm/mach-mvebu/addr-map.c b/arch/arm/mach-mvebu/addr-map.c index fe454a4430be..595f6b722a8f 100644 --- a/arch/arm/mach-mvebu/addr-map.c +++ b/arch/arm/mach-mvebu/addr-map.c | |||
@@ -108,6 +108,9 @@ static int __init armada_setup_cpu_mbus(void) | |||
108 | 108 | ||
109 | addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base; | 109 | addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base; |
110 | 110 | ||
111 | if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric")) | ||
112 | addr_map_cfg.hw_io_coherency = 1; | ||
113 | |||
111 | /* | 114 | /* |
112 | * Disable, clear and configure windows. | 115 | * Disable, clear and configure windows. |
113 | */ | 116 | */ |
diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index cd6eac17fb67..a9cf335c7cb0 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 | ||
28 | static struct map_desc armada_370_xp_io_desc[] __initdata = { | 29 | static struct map_desc armada_370_xp_io_desc[] __initdata = { |
29 | { | 30 | { |
@@ -62,6 +63,7 @@ struct sys_timer armada_370_xp_timer = { | |||
62 | static void __init armada_370_xp_dt_init(void) | 63 | static 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 | ||
67 | static const char * const armada_370_xp_dt_board_dt_compat[] = { | 69 | static const char * const armada_370_xp_dt_board_dt_compat[] = { |
@@ -71,6 +73,7 @@ static const char * const armada_370_xp_dt_board_dt_compat[] = { | |||
71 | }; | 73 | }; |
72 | 74 | ||
73 | DT_MACHINE_START(ARMADA_XP_DT, "Marvell Aramada 370/XP (Device Tree)") | 75 | DT_MACHINE_START(ARMADA_XP_DT, "Marvell Aramada 370/XP (Device Tree)") |
76 | .smp = smp_ops(armada_xp_smp_ops), | ||
74 | .init_machine = armada_370_xp_dt_init, | 77 | .init_machine = armada_370_xp_dt_init, |
75 | .map_io = armada_370_xp_map_io, | 78 | .map_io = armada_370_xp_map_io, |
76 | .init_early = armada_370_xp_init_early, | 79 | .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 | |||
25 | void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq); | ||
26 | void 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..8278960066c3 --- /dev/null +++ b/arch/arm/mach-mvebu/coherency.c | |||
@@ -0,0 +1,155 @@ | |||
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 <linux/dma-mapping.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <asm/smp_plat.h> | ||
28 | #include "armada-370-xp.h" | ||
29 | |||
30 | /* | ||
31 | * Some functions in this file are called very early during SMP | ||
32 | * initialization. At that time the device tree framework is not yet | ||
33 | * ready, and it is not possible to get the register address to | ||
34 | * ioremap it. That's why the pointer below is given with an initial | ||
35 | * value matching its virtual mapping | ||
36 | */ | ||
37 | static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200; | ||
38 | static void __iomem *coherency_cpu_base; | ||
39 | |||
40 | /* Coherency fabric registers */ | ||
41 | #define COHERENCY_FABRIC_CFG_OFFSET 0x4 | ||
42 | |||
43 | #define IO_SYNC_BARRIER_CTL_OFFSET 0x0 | ||
44 | |||
45 | static struct of_device_id of_coherency_table[] = { | ||
46 | {.compatible = "marvell,coherency-fabric"}, | ||
47 | { /* end of list */ }, | ||
48 | }; | ||
49 | |||
50 | #ifdef CONFIG_SMP | ||
51 | int coherency_get_cpu_count(void) | ||
52 | { | ||
53 | int reg, cnt; | ||
54 | |||
55 | reg = readl(coherency_base + COHERENCY_FABRIC_CFG_OFFSET); | ||
56 | cnt = (reg & 0xF) + 1; | ||
57 | |||
58 | return cnt; | ||
59 | } | ||
60 | #endif | ||
61 | |||
62 | /* Function defined in coherency_ll.S */ | ||
63 | int ll_set_cpu_coherent(void __iomem *base_addr, unsigned int hw_cpu_id); | ||
64 | |||
65 | int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id) | ||
66 | { | ||
67 | if (!coherency_base) { | ||
68 | pr_warn("Can't make CPU %d cache coherent.\n", hw_cpu_id); | ||
69 | pr_warn("Coherency fabric is not initialized\n"); | ||
70 | return 1; | ||
71 | } | ||
72 | |||
73 | return ll_set_cpu_coherent(coherency_base, hw_cpu_id); | ||
74 | } | ||
75 | |||
76 | static inline void mvebu_hwcc_sync_io_barrier(void) | ||
77 | { | ||
78 | writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET); | ||
79 | while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1); | ||
80 | } | ||
81 | |||
82 | static dma_addr_t mvebu_hwcc_dma_map_page(struct device *dev, struct page *page, | ||
83 | unsigned long offset, size_t size, | ||
84 | enum dma_data_direction dir, | ||
85 | struct dma_attrs *attrs) | ||
86 | { | ||
87 | if (dir != DMA_TO_DEVICE) | ||
88 | mvebu_hwcc_sync_io_barrier(); | ||
89 | return pfn_to_dma(dev, page_to_pfn(page)) + offset; | ||
90 | } | ||
91 | |||
92 | |||
93 | static void mvebu_hwcc_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, | ||
94 | size_t size, enum dma_data_direction dir, | ||
95 | struct dma_attrs *attrs) | ||
96 | { | ||
97 | if (dir != DMA_TO_DEVICE) | ||
98 | mvebu_hwcc_sync_io_barrier(); | ||
99 | } | ||
100 | |||
101 | static void mvebu_hwcc_dma_sync(struct device *dev, dma_addr_t dma_handle, | ||
102 | size_t size, enum dma_data_direction dir) | ||
103 | { | ||
104 | if (dir != DMA_TO_DEVICE) | ||
105 | mvebu_hwcc_sync_io_barrier(); | ||
106 | } | ||
107 | |||
108 | static struct dma_map_ops mvebu_hwcc_dma_ops = { | ||
109 | .alloc = arm_dma_alloc, | ||
110 | .free = arm_dma_free, | ||
111 | .mmap = arm_dma_mmap, | ||
112 | .map_page = mvebu_hwcc_dma_map_page, | ||
113 | .unmap_page = mvebu_hwcc_dma_unmap_page, | ||
114 | .get_sgtable = arm_dma_get_sgtable, | ||
115 | .map_sg = arm_dma_map_sg, | ||
116 | .unmap_sg = arm_dma_unmap_sg, | ||
117 | .sync_single_for_cpu = mvebu_hwcc_dma_sync, | ||
118 | .sync_single_for_device = mvebu_hwcc_dma_sync, | ||
119 | .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu, | ||
120 | .sync_sg_for_device = arm_dma_sync_sg_for_device, | ||
121 | .set_dma_mask = arm_dma_set_mask, | ||
122 | }; | ||
123 | |||
124 | static int mvebu_hwcc_platform_notifier(struct notifier_block *nb, | ||
125 | unsigned long event, void *__dev) | ||
126 | { | ||
127 | struct device *dev = __dev; | ||
128 | |||
129 | if (event != BUS_NOTIFY_ADD_DEVICE) | ||
130 | return NOTIFY_DONE; | ||
131 | set_dma_ops(dev, &mvebu_hwcc_dma_ops); | ||
132 | |||
133 | return NOTIFY_OK; | ||
134 | } | ||
135 | |||
136 | static struct notifier_block mvebu_hwcc_platform_nb = { | ||
137 | .notifier_call = mvebu_hwcc_platform_notifier, | ||
138 | }; | ||
139 | |||
140 | int __init coherency_init(void) | ||
141 | { | ||
142 | struct device_node *np; | ||
143 | |||
144 | np = of_find_matching_node(NULL, of_coherency_table); | ||
145 | if (np) { | ||
146 | pr_info("Initializing Coherency fabric\n"); | ||
147 | coherency_base = of_iomap(np, 0); | ||
148 | coherency_cpu_base = of_iomap(np, 1); | ||
149 | set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); | ||
150 | bus_register_notifier(&platform_bus_type, | ||
151 | &mvebu_hwcc_platform_nb); | ||
152 | } | ||
153 | |||
154 | return 0; | ||
155 | } | ||
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 | ||
18 | int coherency_get_cpu_count(void); | ||
19 | #endif | ||
20 | |||
21 | int set_cpu_coherent(int cpu_id, int smp_group_id); | ||
22 | int 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 | */ | ||
28 | ENTRY(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 | ||
49 | ENDPROC(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); | |||
20 | void armada_370_xp_init_irq(void); | 20 | void armada_370_xp_init_irq(void); |
21 | void armada_370_xp_handle_irq(struct pt_regs *regs); | 21 | void armada_370_xp_handle_irq(struct pt_regs *regs); |
22 | 22 | ||
23 | void armada_xp_cpu_die(unsigned int cpu); | ||
24 | int armada_370_xp_coherency_init(void); | ||
25 | int armada_370_xp_pmsu_init(void); | ||
26 | void armada_xp_secondary_startup(void); | ||
27 | extern 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 | */ | ||
37 | ENTRY(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 | |||
49 | ENDPROC(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 | */ | ||
24 | void __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 | |||
38 | static void __iomem *per_cpu_int_base; | 45 | static void __iomem *per_cpu_int_base; |
39 | static void __iomem *main_int_base; | 46 | static void __iomem *main_int_base; |
40 | static struct irq_domain *armada_370_xp_mpic_domain; | 47 | static 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 | ||
62 | static 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 | |||
54 | static struct irq_chip armada_370_xp_irq_chip = { | 69 | static 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 | ||
61 | static int armada_370_xp_mpic_irq_map(struct irq_domain *h, | 79 | static 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 | ||
94 | void 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 | |||
114 | void 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 | |||
75 | static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { | 128 | static 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 | |||
31 | void __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 | |||
73 | static void __cpuinit armada_xp_secondary_init(unsigned int cpu) | ||
74 | { | ||
75 | armada_xp_mpic_smp_cpu_init(); | ||
76 | } | ||
77 | |||
78 | static 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 | |||
88 | static 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 | |||
107 | void __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 | |||
114 | struct 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 | |||
26 | static void __iomem *pmsu_mp_base; | ||
27 | static 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 | |||
32 | static struct of_device_id of_pmsu_table[] = { | ||
33 | {.compatible = "marvell,armada-370-xp-pmsu"}, | ||
34 | { /* end of list */ }, | ||
35 | }; | ||
36 | |||
37 | #ifdef CONFIG_SMP | ||
38 | int 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 | |||
61 | int __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 | |||
75 | early_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 | |||
14 | int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr); | ||
15 | |||
16 | #endif /* __MACH_370_XP_PMSU_H */ | ||
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 94186b6c685f..3fd629d5a513 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
@@ -352,6 +352,10 @@ config CPU_PJ4 | |||
352 | select ARM_THUMBEE | 352 | select ARM_THUMBEE |
353 | select CPU_V7 | 353 | select CPU_V7 |
354 | 354 | ||
355 | config CPU_PJ4B | ||
356 | bool | ||
357 | select CPU_V7 | ||
358 | |||
355 | # ARMv6 | 359 | # ARMv6 |
356 | config CPU_V6 | 360 | config CPU_V6 |
357 | bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX | 361 | bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX |
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 58bc3e4d3bd0..5383bc018571 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c | |||
@@ -124,8 +124,6 @@ static void arm_dma_sync_single_for_device(struct device *dev, | |||
124 | __dma_page_cpu_to_dev(page, offset, size, dir); | 124 | __dma_page_cpu_to_dev(page, offset, size, dir); |
125 | } | 125 | } |
126 | 126 | ||
127 | static int arm_dma_set_mask(struct device *dev, u64 dma_mask); | ||
128 | |||
129 | struct dma_map_ops arm_dma_ops = { | 127 | struct dma_map_ops arm_dma_ops = { |
130 | .alloc = arm_dma_alloc, | 128 | .alloc = arm_dma_alloc, |
131 | .free = arm_dma_free, | 129 | .free = arm_dma_free, |
@@ -971,7 +969,7 @@ int dma_supported(struct device *dev, u64 mask) | |||
971 | } | 969 | } |
972 | EXPORT_SYMBOL(dma_supported); | 970 | EXPORT_SYMBOL(dma_supported); |
973 | 971 | ||
974 | static int arm_dma_set_mask(struct device *dev, u64 dma_mask) | 972 | int arm_dma_set_mask(struct device *dev, u64 dma_mask) |
975 | { | 973 | { |
976 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) | 974 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) |
977 | return -EIO; | 975 | return -EIO; |
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 846d279f3176..7cd0028cab8e 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S | |||
@@ -169,6 +169,63 @@ __v7_ca15mp_setup: | |||
169 | orreq r0, r0, r10 @ Enable CPU-specific SMP bits | 169 | orreq r0, r0, r10 @ Enable CPU-specific SMP bits |
170 | mcreq p15, 0, r0, c1, c0, 1 | 170 | mcreq p15, 0, r0, c1, c0, 1 |
171 | #endif | 171 | #endif |
172 | |||
173 | __v7_pj4b_setup: | ||
174 | #ifdef CONFIG_CPU_PJ4B | ||
175 | |||
176 | /* Auxiliary Debug Modes Control 1 Register */ | ||
177 | #define PJ4B_STATIC_BP (1 << 2) /* Enable Static BP */ | ||
178 | #define PJ4B_INTER_PARITY (1 << 8) /* Disable Internal Parity Handling */ | ||
179 | #define PJ4B_BCK_OFF_STREX (1 << 5) /* Enable the back off of STREX instr */ | ||
180 | #define PJ4B_CLEAN_LINE (1 << 16) /* Disable data transfer for clean line */ | ||
181 | |||
182 | /* Auxiliary Debug Modes Control 2 Register */ | ||
183 | #define PJ4B_FAST_LDR (1 << 23) /* Disable fast LDR */ | ||
184 | #define PJ4B_SNOOP_DATA (1 << 25) /* Do not interleave write and snoop data */ | ||
185 | #define PJ4B_CWF (1 << 27) /* Disable Critical Word First feature */ | ||
186 | #define PJ4B_OUTSDNG_NC (1 << 29) /* Disable outstanding non cacheable rqst */ | ||
187 | #define PJ4B_L1_REP_RR (1 << 30) /* L1 replacement - Strict round robin */ | ||
188 | #define PJ4B_AUX_DBG_CTRL2 (PJ4B_SNOOP_DATA | PJ4B_CWF |\ | ||
189 | PJ4B_OUTSDNG_NC | PJ4B_L1_REP_RR) | ||
190 | |||
191 | /* Auxiliary Functional Modes Control Register 0 */ | ||
192 | #define PJ4B_SMP_CFB (1 << 1) /* Set SMP mode. Join the coherency fabric */ | ||
193 | #define PJ4B_L1_PAR_CHK (1 << 2) /* Support L1 parity checking */ | ||
194 | #define PJ4B_BROADCAST_CACHE (1 << 8) /* Broadcast Cache and TLB maintenance */ | ||
195 | |||
196 | /* Auxiliary Debug Modes Control 0 Register */ | ||
197 | #define PJ4B_WFI_WFE (1 << 22) /* WFI/WFE - serve the DVM and back to idle */ | ||
198 | |||
199 | /* Auxiliary Debug Modes Control 1 Register */ | ||
200 | mrc p15, 1, r0, c15, c1, 1 | ||
201 | orr r0, r0, #PJ4B_CLEAN_LINE | ||
202 | orr r0, r0, #PJ4B_BCK_OFF_STREX | ||
203 | orr r0, r0, #PJ4B_INTER_PARITY | ||
204 | bic r0, r0, #PJ4B_STATIC_BP | ||
205 | mcr p15, 1, r0, c15, c1, 1 | ||
206 | |||
207 | /* Auxiliary Debug Modes Control 2 Register */ | ||
208 | mrc p15, 1, r0, c15, c1, 2 | ||
209 | bic r0, r0, #PJ4B_FAST_LDR | ||
210 | orr r0, r0, #PJ4B_AUX_DBG_CTRL2 | ||
211 | mcr p15, 1, r0, c15, c1, 2 | ||
212 | |||
213 | /* Auxiliary Functional Modes Control Register 0 */ | ||
214 | mrc p15, 1, r0, c15, c2, 0 | ||
215 | #ifdef CONFIG_SMP | ||
216 | orr r0, r0, #PJ4B_SMP_CFB | ||
217 | #endif | ||
218 | orr r0, r0, #PJ4B_L1_PAR_CHK | ||
219 | orr r0, r0, #PJ4B_BROADCAST_CACHE | ||
220 | mcr p15, 1, r0, c15, c2, 0 | ||
221 | |||
222 | /* Auxiliary Debug Modes Control 0 Register */ | ||
223 | mrc p15, 1, r0, c15, c1, 0 | ||
224 | orr r0, r0, #PJ4B_WFI_WFE | ||
225 | mcr p15, 1, r0, c15, c1, 0 | ||
226 | |||
227 | #endif /* CONFIG_CPU_PJ4B */ | ||
228 | |||
172 | __v7_setup: | 229 | __v7_setup: |
173 | adr r12, __v7_setup_stack @ the local stack | 230 | adr r12, __v7_setup_stack @ the local stack |
174 | stmia r12, {r0-r5, r7, r9, r11, lr} | 231 | stmia r12, {r0-r5, r7, r9, r11, lr} |
@@ -342,6 +399,16 @@ __v7_ca9mp_proc_info: | |||
342 | .long 0xff0ffff0 | 399 | .long 0xff0ffff0 |
343 | __v7_proc __v7_ca9mp_setup | 400 | __v7_proc __v7_ca9mp_setup |
344 | .size __v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info | 401 | .size __v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info |
402 | |||
403 | /* | ||
404 | * Marvell PJ4B processor. | ||
405 | */ | ||
406 | .type __v7_pj4b_proc_info, #object | ||
407 | __v7_pj4b_proc_info: | ||
408 | .long 0x562f5840 | ||
409 | .long 0xfffffff0 | ||
410 | __v7_proc __v7_pj4b_setup | ||
411 | .size __v7_pj4b_proc_info, . - __v7_pj4b_proc_info | ||
345 | #endif /* CONFIG_ARM_LPAE */ | 412 | #endif /* CONFIG_ARM_LPAE */ |
346 | 413 | ||
347 | /* | 414 | /* |
diff --git a/arch/arm/plat-orion/addr-map.c b/arch/arm/plat-orion/addr-map.c index a7b8060c293a..febe3862873c 100644 --- a/arch/arm/plat-orion/addr-map.c +++ b/arch/arm/plat-orion/addr-map.c | |||
@@ -42,6 +42,8 @@ EXPORT_SYMBOL_GPL(mv_mbus_dram_info); | |||
42 | #define WIN_REMAP_LO_OFF 0x0008 | 42 | #define WIN_REMAP_LO_OFF 0x0008 |
43 | #define WIN_REMAP_HI_OFF 0x000c | 43 | #define WIN_REMAP_HI_OFF 0x000c |
44 | 44 | ||
45 | #define ATTR_HW_COHERENCY (0x1 << 4) | ||
46 | |||
45 | /* | 47 | /* |
46 | * Default implementation | 48 | * Default implementation |
47 | */ | 49 | */ |
@@ -163,6 +165,8 @@ void __init orion_setup_cpu_mbus_target(const struct orion_addr_map_cfg *cfg, | |||
163 | w = &orion_mbus_dram_info.cs[cs++]; | 165 | w = &orion_mbus_dram_info.cs[cs++]; |
164 | w->cs_index = i; | 166 | w->cs_index = i; |
165 | w->mbus_attr = 0xf & ~(1 << i); | 167 | w->mbus_attr = 0xf & ~(1 << i); |
168 | if (cfg->hw_io_coherency) | ||
169 | w->mbus_attr |= ATTR_HW_COHERENCY; | ||
166 | w->base = base & 0xffff0000; | 170 | w->base = base & 0xffff0000; |
167 | w->size = (size | 0x0000ffff) + 1; | 171 | w->size = (size | 0x0000ffff) + 1; |
168 | } | 172 | } |
diff --git a/arch/arm/plat-orion/include/plat/addr-map.h b/arch/arm/plat-orion/include/plat/addr-map.h index ec63e4a627d0..b76c06569fe5 100644 --- a/arch/arm/plat-orion/include/plat/addr-map.h +++ b/arch/arm/plat-orion/include/plat/addr-map.h | |||
@@ -17,6 +17,7 @@ struct orion_addr_map_cfg { | |||
17 | const int num_wins; /* Total number of windows */ | 17 | const int num_wins; /* Total number of windows */ |
18 | const int remappable_wins; | 18 | const int remappable_wins; |
19 | void __iomem *bridge_virt_base; | 19 | void __iomem *bridge_virt_base; |
20 | int hw_io_coherency; | ||
20 | 21 | ||
21 | /* If NULL, the default cpu_win_can_remap will be used, using | 22 | /* If NULL, the default cpu_win_can_remap will be used, using |
22 | the value in remappable_wins */ | 23 | the value in remappable_wins */ |