Merge tag 'iwlwifi-for-kalle-2015-07-30' of https://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / arch / arm / mach-uniphier / platsmp.c
1 /*
2  * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 #include <linux/sizes.h>
16 #include <linux/compiler.h>
17 #include <linux/init.h>
18 #include <linux/io.h>
19 #include <linux/regmap.h>
20 #include <linux/mfd/syscon.h>
21 #include <asm/smp.h>
22 #include <asm/smp_scu.h>
23
24 static struct regmap *sbcm_regmap;
25
26 static void __init uniphier_smp_prepare_cpus(unsigned int max_cpus)
27 {
28         static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
29         unsigned long scu_base_phys = 0;
30         void __iomem *scu_base;
31
32         sbcm_regmap = syscon_regmap_lookup_by_compatible(
33                         "socionext,uniphier-system-bus-controller-misc");
34         if (IS_ERR(sbcm_regmap)) {
35                 pr_err("failed to regmap system-bus-controller-misc\n");
36                 goto err;
37         }
38
39         if (scu_a9_has_base())
40                 scu_base_phys = scu_a9_get_base();
41
42         if (!scu_base_phys) {
43                 pr_err("failed to get scu base\n");
44                 goto err;
45         }
46
47         scu_base = ioremap(scu_base_phys, SZ_128);
48         if (!scu_base) {
49                 pr_err("failed to remap scu base (0x%08lx)\n", scu_base_phys);
50                 goto err;
51         }
52
53         scu_enable(scu_base);
54         iounmap(scu_base);
55
56         return;
57 err:
58         pr_warn("disabling SMP\n");
59         init_cpu_present(&only_cpu_0);
60         sbcm_regmap = NULL;
61 }
62
63 static void __naked uniphier_secondary_startup(void)
64 {
65         asm("bl         v7_invalidate_l1\n"
66             "b          secondary_startup\n");
67 };
68
69 static int uniphier_boot_secondary(unsigned int cpu,
70                                    struct task_struct *idle)
71 {
72         int ret;
73
74         if (!sbcm_regmap)
75                 return -ENODEV;
76
77         ret = regmap_write(sbcm_regmap, 0x1208,
78                            virt_to_phys(uniphier_secondary_startup));
79         if (!ret)
80                 asm("sev"); /* wake up secondary CPU */
81
82         return ret;
83 }
84
85 struct smp_operations uniphier_smp_ops __initdata = {
86         .smp_prepare_cpus       = uniphier_smp_prepare_cpus,
87         .smp_boot_secondary     = uniphier_boot_secondary,
88 };
89 CPU_METHOD_OF_DECLARE(uniphier_smp, "socionext,uniphier-smp",
90                       &uniphier_smp_ops);