aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorJason Cooper <jason@lakedaemon.net>2014-05-08 12:06:57 -0400
committerJason Cooper <jason@lakedaemon.net>2014-05-08 12:06:57 -0400
commitd269a36ae7002d96a5691cdef96b5bb6f41330f6 (patch)
tree0754d512fa12633b484e2760fea9be1254152899 /arch/arm
parentd0de9323822fada543f2f244eb67f520aa21ed77 (diff)
parent02e7b06795fc129e45ed39983673efbb05d69506 (diff)
Merge branch 'mvebu/soc-pmsu' into mvebu/soc
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-mvebu/Makefile2
-rw-r--r--arch/arm/mach-mvebu/common.h1
-rw-r--r--arch/arm/mach-mvebu/cpu-reset.c103
-rw-r--r--arch/arm/mach-mvebu/pmsu.c79
4 files changed, 165 insertions, 20 deletions
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index a63e43b6b451..f9cfab05c5f9 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -3,7 +3,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
3 3
4AFLAGS_coherency_ll.o := -Wa,-march=armv7-a 4AFLAGS_coherency_ll.o := -Wa,-march=armv7-a
5 5
6obj-y += system-controller.o mvebu-soc-id.o 6obj-y += system-controller.o mvebu-soc-id.o cpu-reset.o
7obj-$(CONFIG_MACH_MVEBU_V7) += board-v7.o 7obj-$(CONFIG_MACH_MVEBU_V7) += board-v7.o
8obj-$(CONFIG_MACH_DOVE) += dove.o 8obj-$(CONFIG_MACH_DOVE) += dove.o
9obj-$(CONFIG_ARCH_MVEBU) += coherency.o coherency_ll.o pmsu.o 9obj-$(CONFIG_ARCH_MVEBU) += coherency.o coherency_ll.o pmsu.o
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h
index 55449c487c9e..cfb129b144c0 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -18,6 +18,7 @@
18#include <linux/reboot.h> 18#include <linux/reboot.h>
19 19
20void mvebu_restart(enum reboot_mode mode, const char *cmd); 20void mvebu_restart(enum reboot_mode mode, const char *cmd);
21int mvebu_cpu_reset_deassert(int cpu);
21 22
22void armada_xp_cpu_die(unsigned int cpu); 23void armada_xp_cpu_die(unsigned int cpu);
23 24
diff --git a/arch/arm/mach-mvebu/cpu-reset.c b/arch/arm/mach-mvebu/cpu-reset.c
new file mode 100644
index 000000000000..4a8f9eebebea
--- /dev/null
+++ b/arch/arm/mach-mvebu/cpu-reset.c
@@ -0,0 +1,103 @@
1/*
2 * Copyright (C) 2014 Marvell
3 *
4 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
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#define pr_fmt(fmt) "mvebu-cpureset: " fmt
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/of_address.h>
16#include <linux/io.h>
17#include <linux/resource.h>
18#include "armada-370-xp.h"
19
20static void __iomem *cpu_reset_base;
21static size_t cpu_reset_size;
22
23#define CPU_RESET_OFFSET(cpu) (cpu * 0x8)
24#define CPU_RESET_ASSERT BIT(0)
25
26int mvebu_cpu_reset_deassert(int cpu)
27{
28 u32 reg;
29
30 if (!cpu_reset_base)
31 return -ENODEV;
32
33 if (CPU_RESET_OFFSET(cpu) >= cpu_reset_size)
34 return -EINVAL;
35
36 reg = readl(cpu_reset_base + CPU_RESET_OFFSET(cpu));
37 reg &= ~CPU_RESET_ASSERT;
38 writel(reg, cpu_reset_base + CPU_RESET_OFFSET(cpu));
39
40 return 0;
41}
42
43static int mvebu_cpu_reset_map(struct device_node *np, int res_idx)
44{
45 struct resource res;
46
47 if (of_address_to_resource(np, res_idx, &res)) {
48 pr_err("unable to get resource\n");
49 return -ENOENT;
50 }
51
52 if (!request_mem_region(res.start, resource_size(&res),
53 np->full_name)) {
54 pr_err("unable to request region\n");
55 return -EBUSY;
56 }
57
58 cpu_reset_base = ioremap(res.start, resource_size(&res));
59 if (!cpu_reset_base) {
60 pr_err("unable to map registers\n");
61 release_mem_region(res.start, resource_size(&res));
62 return -ENOMEM;
63 }
64
65 cpu_reset_size = resource_size(&res);
66
67 return 0;
68}
69
70int __init mvebu_cpu_reset_init(void)
71{
72 struct device_node *np;
73 int res_idx;
74 int ret;
75
76 np = of_find_compatible_node(NULL, NULL,
77 "marvell,armada-370-cpu-reset");
78 if (np) {
79 res_idx = 0;
80 } else {
81 /*
82 * This code is kept for backward compatibility with
83 * old Device Trees.
84 */
85 np = of_find_compatible_node(NULL, NULL,
86 "marvell,armada-370-xp-pmsu");
87 if (np) {
88 pr_warn(FW_WARN "deprecated pmsu binding\n");
89 res_idx = 1;
90 }
91 }
92
93 /* No reset node found */
94 if (!np)
95 return -ENODEV;
96
97 ret = mvebu_cpu_reset_map(np, res_idx);
98 of_node_put(np);
99
100 return ret;
101}
102
103early_initcall(mvebu_cpu_reset_init);
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index d71ef53107c4..8361281f9180 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -16,44 +16,56 @@
16 * other SOC units 16 * other SOC units
17 */ 17 */
18 18
19#define pr_fmt(fmt) "mvebu-pmsu: " fmt
20
19#include <linux/kernel.h> 21#include <linux/kernel.h>
20#include <linux/init.h> 22#include <linux/init.h>
21#include <linux/of_address.h> 23#include <linux/of_address.h>
22#include <linux/io.h> 24#include <linux/io.h>
23#include <linux/smp.h> 25#include <linux/smp.h>
26#include <linux/resource.h>
24#include <asm/smp_plat.h> 27#include <asm/smp_plat.h>
28#include "common.h"
25#include "pmsu.h" 29#include "pmsu.h"
26 30
27static void __iomem *pmsu_mp_base; 31static void __iomem *pmsu_mp_base;
28static void __iomem *pmsu_reset_base;
29 32
30#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x24) 33#define PMSU_BASE_OFFSET 0x100
31#define PMSU_RESET_CTL_OFFSET(cpu) (cpu * 0x8) 34#define PMSU_REG_SIZE 0x1000
35
36#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x124)
32 37
33static struct of_device_id of_pmsu_table[] = { 38static struct of_device_id of_pmsu_table[] = {
34 {.compatible = "marvell,armada-370-xp-pmsu"}, 39 { .compatible = "marvell,armada-370-pmsu", },
40 { .compatible = "marvell,armada-370-xp-pmsu", },
35 { /* end of list */ }, 41 { /* end of list */ },
36}; 42};
37 43
44static void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
45{
46 writel(virt_to_phys(boot_addr), pmsu_mp_base +
47 PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
48}
49
38#ifdef CONFIG_SMP 50#ifdef CONFIG_SMP
39int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr) 51int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
40{ 52{
41 int reg, hw_cpu; 53 int hw_cpu, ret;
42 54
43 if (!pmsu_mp_base || !pmsu_reset_base) { 55 if (!pmsu_mp_base) {
44 pr_warn("Can't boot CPU. PMSU is uninitialized\n"); 56 pr_warn("Can't boot CPU. PMSU is uninitialized\n");
45 return 1; 57 return -ENODEV;
46 } 58 }
47 59
48 hw_cpu = cpu_logical_map(cpu_id); 60 hw_cpu = cpu_logical_map(cpu_id);
49 61
50 writel(virt_to_phys(boot_addr), pmsu_mp_base + 62 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, boot_addr);
51 PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
52 63
53 /* Release CPU from reset by clearing reset bit*/ 64 ret = mvebu_cpu_reset_deassert(hw_cpu);
54 reg = readl(pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu)); 65 if (ret) {
55 reg &= (~0x1); 66 pr_warn("unable to boot CPU: %d\n", ret);
56 writel(reg, pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu)); 67 return ret;
68 }
57 69
58 return 0; 70 return 0;
59} 71}
@@ -62,16 +74,45 @@ int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
62static int __init armada_370_xp_pmsu_init(void) 74static int __init armada_370_xp_pmsu_init(void)
63{ 75{
64 struct device_node *np; 76 struct device_node *np;
77 struct resource res;
78 int ret = 0;
65 79
66 np = of_find_matching_node(NULL, of_pmsu_table); 80 np = of_find_matching_node(NULL, of_pmsu_table);
67 if (np) { 81 if (!np)
68 pr_info("Initializing Power Management Service Unit\n"); 82 return 0;
69 pmsu_mp_base = of_iomap(np, 0); 83
70 pmsu_reset_base = of_iomap(np, 1); 84 pr_info("Initializing Power Management Service Unit\n");
71 of_node_put(np); 85
86 if (of_address_to_resource(np, 0, &res)) {
87 pr_err("unable to get resource\n");
88 ret = -ENOENT;
89 goto out;
72 } 90 }
73 91
74 return 0; 92 if (of_device_is_compatible(np, "marvell,armada-370-xp-pmsu")) {
93 pr_warn(FW_WARN "deprecated pmsu binding\n");
94 res.start = res.start - PMSU_BASE_OFFSET;
95 res.end = res.start + PMSU_REG_SIZE - 1;
96 }
97
98 if (!request_mem_region(res.start, resource_size(&res),
99 np->full_name)) {
100 pr_err("unable to request region\n");
101 ret = -EBUSY;
102 goto out;
103 }
104
105 pmsu_mp_base = ioremap(res.start, resource_size(&res));
106 if (!pmsu_mp_base) {
107 pr_err("unable to map registers\n");
108 release_mem_region(res.start, resource_size(&res));
109 ret = -ENOMEM;
110 goto out;
111 }
112
113 out:
114 of_node_put(np);
115 return ret;
75} 116}
76 117
77early_initcall(armada_370_xp_pmsu_init); 118early_initcall(armada_370_xp_pmsu_init);