summaryrefslogtreecommitdiff
path: root/arch/arm/mach-shmobile/platsmp-apmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-shmobile/platsmp-apmu.c')
-rw-r--r--arch/arm/mach-shmobile/platsmp-apmu.c282
1 files changed, 118 insertions, 164 deletions
diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c
index 3ca2c13346f0..ec6f421c0f4d 100644
--- a/arch/arm/mach-shmobile/platsmp-apmu.c
+++ b/arch/arm/mach-shmobile/platsmp-apmu.c
@@ -1,18 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* SMP support for SoCs with APMU
*
* Copyright (C) 2014 Renesas Electronics Corporation
* Copyright (C) 2013 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
*/
#include <linux/cpu_pm.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/smp.h>
#include <linux/suspend.h>
@@ -23,7 +21,6 @@
#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include "common.h"
-#include "platsmp-apmu.h"
#include "rcar-gen2.h"
static struct {
@@ -87,148 +84,6 @@ static int __maybe_unused apmu_wrap(int cpu, int (*fn)(void __iomem *p, int cpu)
return p ? fn(p, apmu_cpus[cpu].bit) : -EINVAL;
}
-#ifdef CONFIG_SMP
-static void apmu_init_cpu(struct resource *res, int cpu, int bit)
-{
- u32 x;
-
- if ((cpu >= ARRAY_SIZE(apmu_cpus)) || apmu_cpus[cpu].iomem)
- return;
-
- apmu_cpus[cpu].iomem = ioremap_nocache(res->start, resource_size(res));
- apmu_cpus[cpu].bit = bit;
-
- pr_debug("apmu ioremap %d %d %pr\n", cpu, bit, res);
-
- /* Setup for debug mode */
- x = readl(apmu_cpus[cpu].iomem + DBGRCR_OFFS);
- x |= DBGCPUREN | DBGCPUNREN(bit) | DBGCPUPREN;
- writel(x, apmu_cpus[cpu].iomem + DBGRCR_OFFS);
-}
-
-static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit),
- struct rcar_apmu_config *apmu_config, int num)
-{
- int id;
- int k;
- int bit, index;
- bool is_allowed;
-
- for (k = 0; k < num; k++) {
- /* only enable the cluster that includes the boot CPU */
- is_allowed = false;
- for (bit = 0; bit < ARRAY_SIZE(apmu_config[k].cpus); bit++) {
- id = apmu_config[k].cpus[bit];
- if (id >= 0) {
- if (id == cpu_logical_map(0))
- is_allowed = true;
- }
- }
- if (!is_allowed)
- continue;
-
- for (bit = 0; bit < ARRAY_SIZE(apmu_config[k].cpus); bit++) {
- id = apmu_config[k].cpus[bit];
- if (id >= 0) {
- index = get_logical_index(id);
- if (index >= 0)
- fn(&apmu_config[k].iomem, index, bit);
- }
- }
- }
-}
-
-static const struct of_device_id apmu_ids[] = {
- { .compatible = "renesas,apmu" },
- { /*sentinel*/ }
-};
-
-static void apmu_parse_dt(void (*fn)(struct resource *res, int cpu, int bit))
-{
- struct device_node *np_apmu, *np_cpu;
- struct resource res;
- int bit, index;
- u32 id;
-
- for_each_matching_node(np_apmu, apmu_ids) {
- /* only enable the cluster that includes the boot CPU */
- bool is_allowed = false;
-
- for (bit = 0; bit < CONFIG_NR_CPUS; bit++) {
- np_cpu = of_parse_phandle(np_apmu, "cpus", bit);
- if (np_cpu) {
- if (!of_property_read_u32(np_cpu, "reg", &id)) {
- if (id == cpu_logical_map(0)) {
- is_allowed = true;
- of_node_put(np_cpu);
- break;
- }
-
- }
- of_node_put(np_cpu);
- }
- }
- if (!is_allowed)
- continue;
-
- for (bit = 0; bit < CONFIG_NR_CPUS; bit++) {
- np_cpu = of_parse_phandle(np_apmu, "cpus", bit);
- if (np_cpu) {
- if (!of_property_read_u32(np_cpu, "reg", &id)) {
- index = get_logical_index(id);
- if ((index >= 0) &&
- !of_address_to_resource(np_apmu,
- 0, &res))
- fn(&res, index, bit);
- }
- of_node_put(np_cpu);
- }
- }
- }
-}
-
-static void __init shmobile_smp_apmu_setup_boot(void)
-{
- /* install boot code shared by all CPUs */
- shmobile_boot_fn = __pa_symbol(shmobile_smp_boot);
-}
-
-void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus,
- struct rcar_apmu_config *apmu_config,
- int num)
-{
- shmobile_smp_apmu_setup_boot();
- apmu_parse_cfg(apmu_init_cpu, apmu_config, num);
-}
-
-int shmobile_smp_apmu_boot_secondary(unsigned int cpu, struct task_struct *idle)
-{
- /* For this particular CPU register boot vector */
- shmobile_smp_hook(cpu, __pa_symbol(secondary_startup), 0);
-
- return apmu_wrap(cpu, apmu_power_on);
-}
-
-static void __init shmobile_smp_apmu_prepare_cpus_dt(unsigned int max_cpus)
-{
- shmobile_smp_apmu_setup_boot();
- apmu_parse_dt(apmu_init_cpu);
- rcar_gen2_pm_init();
-}
-
-static struct smp_operations apmu_smp_ops __initdata = {
- .smp_prepare_cpus = shmobile_smp_apmu_prepare_cpus_dt,
- .smp_boot_secondary = shmobile_smp_apmu_boot_secondary,
-#ifdef CONFIG_HOTPLUG_CPU
- .cpu_can_disable = shmobile_smp_cpu_can_disable,
- .cpu_die = shmobile_smp_apmu_cpu_die,
- .cpu_kill = shmobile_smp_apmu_cpu_kill,
-#endif
-};
-
-CPU_METHOD_OF_DECLARE(shmobile_smp_apmu, "renesas,apmu", &apmu_smp_ops);
-#endif /* CONFIG_SMP */
-
#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_SUSPEND)
/* nicked from arch/arm/mach-exynos/hotplug.c */
static inline void cpu_enter_lowpower_a15(void)
@@ -269,25 +124,10 @@ static void shmobile_smp_apmu_cpu_shutdown(unsigned int cpu)
/* Do ARM specific CPU shutdown */
cpu_enter_lowpower_a15();
}
-
-static inline void cpu_leave_lowpower(void)
-{
- unsigned int v;
-
- asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
- " orr %0, %0, %1\n"
- " mcr p15, 0, %0, c1, c0, 0\n"
- " mrc p15, 0, %0, c1, c0, 1\n"
- " orr %0, %0, %2\n"
- " mcr p15, 0, %0, c1, c0, 1\n"
- : "=&r" (v)
- : "Ir" (CR_C), "Ir" (0x40)
- : "cc");
-}
#endif
#if defined(CONFIG_HOTPLUG_CPU)
-void shmobile_smp_apmu_cpu_die(unsigned int cpu)
+static void shmobile_smp_apmu_cpu_die(unsigned int cpu)
{
/* For this particular CPU deregister boot vector */
shmobile_smp_hook(cpu, 0, 0);
@@ -299,7 +139,7 @@ void shmobile_smp_apmu_cpu_die(unsigned int cpu)
shmobile_smp_sleep();
}
-int shmobile_smp_apmu_cpu_kill(unsigned int cpu)
+static int shmobile_smp_apmu_cpu_kill(unsigned int cpu)
{
return apmu_wrap(cpu, apmu_power_off_poll);
}
@@ -314,6 +154,21 @@ static int shmobile_smp_apmu_do_suspend(unsigned long cpu)
return 1;
}
+static inline void cpu_leave_lowpower(void)
+{
+ unsigned int v;
+
+ asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
+ " orr %0, %0, %1\n"
+ " mcr p15, 0, %0, c1, c0, 0\n"
+ " mrc p15, 0, %0, c1, c0, 1\n"
+ " orr %0, %0, %2\n"
+ " mcr p15, 0, %0, c1, c0, 1\n"
+ : "=&r" (v)
+ : "Ir" (CR_C), "Ir" (0x40)
+ : "cc");
+}
+
static int shmobile_smp_apmu_enter_suspend(suspend_state_t state)
{
cpu_suspend(smp_processor_id(), shmobile_smp_apmu_do_suspend);
@@ -326,3 +181,102 @@ void __init shmobile_smp_apmu_suspend_init(void)
shmobile_suspend_ops.enter = shmobile_smp_apmu_enter_suspend;
}
#endif
+
+#ifdef CONFIG_SMP
+static void apmu_init_cpu(struct resource *res, int cpu, int bit)
+{
+ u32 x;
+
+ if ((cpu >= ARRAY_SIZE(apmu_cpus)) || apmu_cpus[cpu].iomem)
+ return;
+
+ apmu_cpus[cpu].iomem = ioremap(res->start, resource_size(res));
+ apmu_cpus[cpu].bit = bit;
+
+ pr_debug("apmu ioremap %d %d %pr\n", cpu, bit, res);
+
+ /* Setup for debug mode */
+ x = readl(apmu_cpus[cpu].iomem + DBGRCR_OFFS);
+ x |= DBGCPUREN | DBGCPUNREN(bit) | DBGCPUPREN;
+ writel(x, apmu_cpus[cpu].iomem + DBGRCR_OFFS);
+}
+
+static const struct of_device_id apmu_ids[] = {
+ { .compatible = "renesas,apmu" },
+ { /*sentinel*/ }
+};
+
+static void apmu_parse_dt(void (*fn)(struct resource *res, int cpu, int bit))
+{
+ struct device_node *np_apmu, *np_cpu;
+ struct resource res;
+ int bit, index;
+
+ for_each_matching_node(np_apmu, apmu_ids) {
+ /* only enable the cluster that includes the boot CPU */
+ bool is_allowed = false;
+
+ for (bit = 0; bit < CONFIG_NR_CPUS; bit++) {
+ np_cpu = of_parse_phandle(np_apmu, "cpus", bit);
+ if (!np_cpu)
+ break;
+ if (of_cpu_node_to_id(np_cpu) == 0) {
+ is_allowed = true;
+ of_node_put(np_cpu);
+ break;
+ }
+ of_node_put(np_cpu);
+ }
+ if (!is_allowed)
+ continue;
+
+ for (bit = 0; bit < CONFIG_NR_CPUS; bit++) {
+ np_cpu = of_parse_phandle(np_apmu, "cpus", bit);
+ if (!np_cpu)
+ break;
+
+ index = of_cpu_node_to_id(np_cpu);
+ if ((index >= 0) &&
+ !of_address_to_resource(np_apmu, 0, &res))
+ fn(&res, index, bit);
+
+ of_node_put(np_cpu);
+ }
+ }
+}
+
+static void __init shmobile_smp_apmu_setup_boot(void)
+{
+ /* install boot code shared by all CPUs */
+ shmobile_boot_fn = __pa_symbol(shmobile_smp_boot);
+ shmobile_boot_fn_gen2 = shmobile_boot_fn;
+}
+
+static int shmobile_smp_apmu_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ /* For this particular CPU register boot vector */
+ shmobile_smp_hook(cpu, __pa_symbol(shmobile_boot_apmu), 0);
+
+ return apmu_wrap(cpu, apmu_power_on);
+}
+
+static void __init shmobile_smp_apmu_prepare_cpus_dt(unsigned int max_cpus)
+{
+ shmobile_smp_apmu_setup_boot();
+ apmu_parse_dt(apmu_init_cpu);
+ rcar_gen2_pm_init();
+}
+
+static struct smp_operations apmu_smp_ops __initdata = {
+ .smp_prepare_cpus = shmobile_smp_apmu_prepare_cpus_dt,
+ .smp_boot_secondary = shmobile_smp_apmu_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_can_disable = shmobile_smp_cpu_can_disable,
+ .cpu_die = shmobile_smp_apmu_cpu_die,
+ .cpu_kill = shmobile_smp_apmu_cpu_kill,
+#endif
+};
+
+CPU_METHOD_OF_DECLARE(shmobile_smp_apmu, "renesas,apmu", &apmu_smp_ops);
+#endif /* CONFIG_SMP */