1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2014 Marvell
4 *
5 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
6 */
7
8#define pr_fmt(fmt) "mvebu-cpureset: " fmt
9
10#include <linux/kernel.h>
11#include <linux/init.h>
12#include <linux/of_address.h>
13#include <linux/io.h>
14#include <linux/resource.h>
15
16#include "common.h"
17
18static void __iomem *cpu_reset_base;
19static size_t cpu_reset_size;
20
21#define CPU_RESET_OFFSET(cpu) (cpu * 0x8)
22#define CPU_RESET_ASSERT      BIT(0)
23
24int mvebu_cpu_reset_deassert(int cpu)
25{
26	u32 reg;
27
28	if (!cpu_reset_base)
29		return -ENODEV;
30
31	if (CPU_RESET_OFFSET(cpu) >= cpu_reset_size)
32		return -EINVAL;
33
34	reg = readl(cpu_reset_base + CPU_RESET_OFFSET(cpu));
35	reg &= ~CPU_RESET_ASSERT;
36	writel(reg, cpu_reset_base + CPU_RESET_OFFSET(cpu));
37
38	return 0;
39}
40
41static int mvebu_cpu_reset_map(struct device_node *np, int res_idx)
42{
43	struct resource res;
44
45	if (of_address_to_resource(np, res_idx, &res)) {
46		pr_err("unable to get resource\n");
47		return -ENOENT;
48	}
49
50	if (!request_mem_region(res.start, resource_size(&res),
51				np->full_name)) {
52		pr_err("unable to request region\n");
53		return -EBUSY;
54	}
55
56	cpu_reset_base = ioremap(res.start, resource_size(&res));
57	if (!cpu_reset_base) {
58		pr_err("unable to map registers\n");
59		release_mem_region(res.start, resource_size(&res));
60		return -ENOMEM;
61	}
62
63	cpu_reset_size = resource_size(&res);
64
65	return 0;
66}
67
68static int __init mvebu_cpu_reset_init(void)
69{
70	struct device_node *np;
71	int res_idx;
72	int ret;
73
74	np = of_find_compatible_node(NULL, NULL,
75				     "marvell,armada-370-cpu-reset");
76	if (np) {
77		res_idx = 0;
78	} else {
79		/*
80		 * This code is kept for backward compatibility with
81		 * old Device Trees.
82		 */
83		np = of_find_compatible_node(NULL, NULL,
84					     "marvell,armada-370-xp-pmsu");
85		if (np) {
86			pr_warn(FW_WARN "deprecated pmsu binding\n");
87			res_idx = 1;
88		}
89	}
90
91	/* No reset node found */
92	if (!np)
93		return -ENODEV;
94
95	ret = mvebu_cpu_reset_map(np, res_idx);
96	of_node_put(np);
97
98	return ret;
99}
100
101early_initcall(mvebu_cpu_reset_init);
102