linux/arch/arm/mach-mvebu/cpu-reset.c
<<
>>
Prefs
   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
  19#include "common.h"
  20
  21static void __iomem *cpu_reset_base;
  22static size_t cpu_reset_size;
  23
  24#define CPU_RESET_OFFSET(cpu) (cpu * 0x8)
  25#define CPU_RESET_ASSERT      BIT(0)
  26
  27int mvebu_cpu_reset_deassert(int cpu)
  28{
  29        u32 reg;
  30
  31        if (!cpu_reset_base)
  32                return -ENODEV;
  33
  34        if (CPU_RESET_OFFSET(cpu) >= cpu_reset_size)
  35                return -EINVAL;
  36
  37        reg = readl(cpu_reset_base + CPU_RESET_OFFSET(cpu));
  38        reg &= ~CPU_RESET_ASSERT;
  39        writel(reg, cpu_reset_base + CPU_RESET_OFFSET(cpu));
  40
  41        return 0;
  42}
  43
  44static int mvebu_cpu_reset_map(struct device_node *np, int res_idx)
  45{
  46        struct resource res;
  47
  48        if (of_address_to_resource(np, res_idx, &res)) {
  49                pr_err("unable to get resource\n");
  50                return -ENOENT;
  51        }
  52
  53        if (!request_mem_region(res.start, resource_size(&res),
  54                                np->full_name)) {
  55                pr_err("unable to request region\n");
  56                return -EBUSY;
  57        }
  58
  59        cpu_reset_base = ioremap(res.start, resource_size(&res));
  60        if (!cpu_reset_base) {
  61                pr_err("unable to map registers\n");
  62                release_mem_region(res.start, resource_size(&res));
  63                return -ENOMEM;
  64        }
  65
  66        cpu_reset_size = resource_size(&res);
  67
  68        return 0;
  69}
  70
  71static int __init mvebu_cpu_reset_init(void)
  72{
  73        struct device_node *np;
  74        int res_idx;
  75        int ret;
  76
  77        np = of_find_compatible_node(NULL, NULL,
  78                                     "marvell,armada-370-cpu-reset");
  79        if (np) {
  80                res_idx = 0;
  81        } else {
  82                /*
  83                 * This code is kept for backward compatibility with
  84                 * old Device Trees.
  85                 */
  86                np = of_find_compatible_node(NULL, NULL,
  87                                             "marvell,armada-370-xp-pmsu");
  88                if (np) {
  89                        pr_warn(FW_WARN "deprecated pmsu binding\n");
  90                        res_idx = 1;
  91                }
  92        }
  93
  94        /* No reset node found */
  95        if (!np)
  96                return -ENODEV;
  97
  98        ret = mvebu_cpu_reset_map(np, res_idx);
  99        of_node_put(np);
 100
 101        return ret;
 102}
 103
 104early_initcall(mvebu_cpu_reset_init);
 105