diff options
author | Jason Cooper <jason@lakedaemon.net> | 2014-05-08 12:06:57 -0400 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2014-05-08 12:06:57 -0400 |
commit | d269a36ae7002d96a5691cdef96b5bb6f41330f6 (patch) | |
tree | 0754d512fa12633b484e2760fea9be1254152899 /arch/arm | |
parent | d0de9323822fada543f2f244eb67f520aa21ed77 (diff) | |
parent | 02e7b06795fc129e45ed39983673efbb05d69506 (diff) |
Merge branch 'mvebu/soc-pmsu' into mvebu/soc
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-mvebu/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/common.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/cpu-reset.c | 103 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/pmsu.c | 79 |
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 | ||
4 | AFLAGS_coherency_ll.o := -Wa,-march=armv7-a | 4 | AFLAGS_coherency_ll.o := -Wa,-march=armv7-a |
5 | 5 | ||
6 | obj-y += system-controller.o mvebu-soc-id.o | 6 | obj-y += system-controller.o mvebu-soc-id.o cpu-reset.o |
7 | obj-$(CONFIG_MACH_MVEBU_V7) += board-v7.o | 7 | obj-$(CONFIG_MACH_MVEBU_V7) += board-v7.o |
8 | obj-$(CONFIG_MACH_DOVE) += dove.o | 8 | obj-$(CONFIG_MACH_DOVE) += dove.o |
9 | obj-$(CONFIG_ARCH_MVEBU) += coherency.o coherency_ll.o pmsu.o | 9 | obj-$(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 | ||
20 | void mvebu_restart(enum reboot_mode mode, const char *cmd); | 20 | void mvebu_restart(enum reboot_mode mode, const char *cmd); |
21 | int mvebu_cpu_reset_deassert(int cpu); | ||
21 | 22 | ||
22 | void armada_xp_cpu_die(unsigned int cpu); | 23 | void 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 | |||
20 | static void __iomem *cpu_reset_base; | ||
21 | static size_t cpu_reset_size; | ||
22 | |||
23 | #define CPU_RESET_OFFSET(cpu) (cpu * 0x8) | ||
24 | #define CPU_RESET_ASSERT BIT(0) | ||
25 | |||
26 | int 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 | |||
43 | static 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 | |||
70 | int __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 | |||
103 | early_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 | ||
27 | static void __iomem *pmsu_mp_base; | 31 | static void __iomem *pmsu_mp_base; |
28 | static 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 | ||
33 | static struct of_device_id of_pmsu_table[] = { | 38 | static 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 | ||
44 | static 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 |
39 | int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr) | 51 | int 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) | |||
62 | static int __init armada_370_xp_pmsu_init(void) | 74 | static 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 | ||
77 | early_initcall(armada_370_xp_pmsu_init); | 118 | early_initcall(armada_370_xp_pmsu_init); |