Commit | Line | Data |
---|---|---|
3f20fb11 TP |
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 | ||
49754ffe | 43 | static int mvebu_cpu_reset_map(struct device_node *np, int res_idx) |
3f20fb11 | 44 | { |
3f20fb11 | 45 | struct resource res; |
3f20fb11 | 46 | |
49754ffe | 47 | if (of_address_to_resource(np, res_idx, &res)) { |
3f20fb11 | 48 | pr_err("unable to get resource\n"); |
49754ffe | 49 | return -ENOENT; |
3f20fb11 TP |
50 | } |
51 | ||
52 | if (!request_mem_region(res.start, resource_size(&res), | |
53 | np->full_name)) { | |
54 | pr_err("unable to request region\n"); | |
49754ffe | 55 | return -EBUSY; |
3f20fb11 TP |
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)); | |
49754ffe | 62 | return -ENOMEM; |
3f20fb11 TP |
63 | } |
64 | ||
65 | cpu_reset_size = resource_size(&res); | |
66 | ||
49754ffe TP |
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); | |
3f20fb11 | 98 | of_node_put(np); |
49754ffe | 99 | |
3f20fb11 TP |
100 | return ret; |
101 | } | |
102 | ||
103 | early_initcall(mvebu_cpu_reset_init); |