18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2014 Marvell 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 78c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any 88c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "mvebu-cpureset: " fmt 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/of_address.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci#include <linux/resource.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "common.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic void __iomem *cpu_reset_base; 228c2ecf20Sopenharmony_cistatic size_t cpu_reset_size; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define CPU_RESET_OFFSET(cpu) (cpu * 0x8) 258c2ecf20Sopenharmony_ci#define CPU_RESET_ASSERT BIT(0) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciint mvebu_cpu_reset_deassert(int cpu) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci u32 reg; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (!cpu_reset_base) 328c2ecf20Sopenharmony_ci return -ENODEV; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (CPU_RESET_OFFSET(cpu) >= cpu_reset_size) 358c2ecf20Sopenharmony_ci return -EINVAL; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci reg = readl(cpu_reset_base + CPU_RESET_OFFSET(cpu)); 388c2ecf20Sopenharmony_ci reg &= ~CPU_RESET_ASSERT; 398c2ecf20Sopenharmony_ci writel(reg, cpu_reset_base + CPU_RESET_OFFSET(cpu)); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci return 0; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int mvebu_cpu_reset_map(struct device_node *np, int res_idx) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct resource res; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (of_address_to_resource(np, res_idx, &res)) { 498c2ecf20Sopenharmony_ci pr_err("unable to get resource\n"); 508c2ecf20Sopenharmony_ci return -ENOENT; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (!request_mem_region(res.start, resource_size(&res), 548c2ecf20Sopenharmony_ci np->full_name)) { 558c2ecf20Sopenharmony_ci pr_err("unable to request region\n"); 568c2ecf20Sopenharmony_ci return -EBUSY; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci cpu_reset_base = ioremap(res.start, resource_size(&res)); 608c2ecf20Sopenharmony_ci if (!cpu_reset_base) { 618c2ecf20Sopenharmony_ci pr_err("unable to map registers\n"); 628c2ecf20Sopenharmony_ci release_mem_region(res.start, resource_size(&res)); 638c2ecf20Sopenharmony_ci return -ENOMEM; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci cpu_reset_size = resource_size(&res); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int __init mvebu_cpu_reset_init(void) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct device_node *np; 748c2ecf20Sopenharmony_ci int res_idx; 758c2ecf20Sopenharmony_ci int ret; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, 788c2ecf20Sopenharmony_ci "marvell,armada-370-cpu-reset"); 798c2ecf20Sopenharmony_ci if (np) { 808c2ecf20Sopenharmony_ci res_idx = 0; 818c2ecf20Sopenharmony_ci } else { 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * This code is kept for backward compatibility with 848c2ecf20Sopenharmony_ci * old Device Trees. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, 878c2ecf20Sopenharmony_ci "marvell,armada-370-xp-pmsu"); 888c2ecf20Sopenharmony_ci if (np) { 898c2ecf20Sopenharmony_ci pr_warn(FW_WARN "deprecated pmsu binding\n"); 908c2ecf20Sopenharmony_ci res_idx = 1; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* No reset node found */ 958c2ecf20Sopenharmony_ci if (!np) 968c2ecf20Sopenharmony_ci return -ENODEV; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci ret = mvebu_cpu_reset_map(np, res_idx); 998c2ecf20Sopenharmony_ci of_node_put(np); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return ret; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciearly_initcall(mvebu_cpu_reset_init); 105