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 static 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); 104