Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2014 Marvell
0004  *
0005  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
0006  */
0007 
0008 #define pr_fmt(fmt) "mvebu-cpureset: " fmt
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/of_address.h>
0013 #include <linux/io.h>
0014 #include <linux/resource.h>
0015 
0016 #include "common.h"
0017 
0018 static void __iomem *cpu_reset_base;
0019 static size_t cpu_reset_size;
0020 
0021 #define CPU_RESET_OFFSET(cpu) (cpu * 0x8)
0022 #define CPU_RESET_ASSERT      BIT(0)
0023 
0024 int mvebu_cpu_reset_deassert(int cpu)
0025 {
0026     u32 reg;
0027 
0028     if (!cpu_reset_base)
0029         return -ENODEV;
0030 
0031     if (CPU_RESET_OFFSET(cpu) >= cpu_reset_size)
0032         return -EINVAL;
0033 
0034     reg = readl(cpu_reset_base + CPU_RESET_OFFSET(cpu));
0035     reg &= ~CPU_RESET_ASSERT;
0036     writel(reg, cpu_reset_base + CPU_RESET_OFFSET(cpu));
0037 
0038     return 0;
0039 }
0040 
0041 static int mvebu_cpu_reset_map(struct device_node *np, int res_idx)
0042 {
0043     struct resource res;
0044 
0045     if (of_address_to_resource(np, res_idx, &res)) {
0046         pr_err("unable to get resource\n");
0047         return -ENOENT;
0048     }
0049 
0050     if (!request_mem_region(res.start, resource_size(&res),
0051                 np->full_name)) {
0052         pr_err("unable to request region\n");
0053         return -EBUSY;
0054     }
0055 
0056     cpu_reset_base = ioremap(res.start, resource_size(&res));
0057     if (!cpu_reset_base) {
0058         pr_err("unable to map registers\n");
0059         release_mem_region(res.start, resource_size(&res));
0060         return -ENOMEM;
0061     }
0062 
0063     cpu_reset_size = resource_size(&res);
0064 
0065     return 0;
0066 }
0067 
0068 static int __init mvebu_cpu_reset_init(void)
0069 {
0070     struct device_node *np;
0071     int res_idx;
0072     int ret;
0073 
0074     np = of_find_compatible_node(NULL, NULL,
0075                      "marvell,armada-370-cpu-reset");
0076     if (np) {
0077         res_idx = 0;
0078     } else {
0079         /*
0080          * This code is kept for backward compatibility with
0081          * old Device Trees.
0082          */
0083         np = of_find_compatible_node(NULL, NULL,
0084                          "marvell,armada-370-xp-pmsu");
0085         if (np) {
0086             pr_warn(FW_WARN "deprecated pmsu binding\n");
0087             res_idx = 1;
0088         }
0089     }
0090 
0091     /* No reset node found */
0092     if (!np)
0093         return -ENODEV;
0094 
0095     ret = mvebu_cpu_reset_map(np, res_idx);
0096     of_node_put(np);
0097 
0098     return ret;
0099 }
0100 
0101 early_initcall(mvebu_cpu_reset_init);