soc: cpupm: support c2 state idle
authorPark Bumgyu <bumgyu.park@samsung.com>
Fri, 26 Jan 2018 10:15:49 +0000 (19:15 +0900)
committerChungwoo Park <cww.park@samsung.com>
Mon, 21 May 2018 08:30:28 +0000 (17:30 +0900)
Change-Id: I27d951d61470de912fde7fe21419ecaa3d9ffecb
Signed-off-by: Park Bumgyu <bumgyu.park@samsung.com>
drivers/cpuidle/cpuidle-exynos64.c
drivers/soc/samsung/Makefile
drivers/soc/samsung/exynos-cpupm.c [new file with mode: 0644]
include/soc/samsung/exynos-cpupm.h [new file with mode: 0644]

index e6191fd48ef02a197b835703b95c9d674e1434c9..705a6432e28e7bd640400bca390794b0c96ad01c 100644 (file)
@@ -23,7 +23,7 @@
 #include <asm/cpuidle.h>
 #include <asm/topology.h>
 
-#include <soc/samsung/exynos-powermode.h>
+#include <soc/samsung/exynos-cpupm.h>
 
 #include "dt_idle_states.h"
 #include "profiler.h"
index 4bf06f88ef4f7d47074f83659b4a8c06c56806a1..34eb685df2e51211535c67a7de217d083d2e0109 100644 (file)
@@ -34,3 +34,6 @@ obj-$(CONFIG_EXYNOS_PD)        += exynos-pd.o exynos-pd-dbg.o
 obj-$(CONFIG_EXYNOS_PM_DOMAINS) += pm_domains.o
 #CPUHOTPLUG
 obj-$(CONFIG_ARCH_EXYNOS)      += exynos-cpu_hotplug.o
+
+#CPU Power Management
+obj-$(CONFIG_ARCH_EXYNOS)      += exynos-cpupm.o
diff --git a/drivers/soc/samsung/exynos-cpupm.c b/drivers/soc/samsung/exynos-cpupm.c
new file mode 100644 (file)
index 0000000..ec33586
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018 Park Bumgyu, Samsung Electronics Co., Ltd <bumgyu.park@samsung.com>
+ *
+ * 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.
+ *
+ * Exynos CPU Power Management driver implementation
+ */
+
+#include <linux/cpumask.h>
+#include <linux/slab.h>
+
+#include <soc/samsung/cal-if.h>
+
+/******************************************************************************
+ *                                CAL interfaces                              *
+ ******************************************************************************/
+static void cpu_enable(unsigned int cpu)
+{
+       cal_cpu_enable(cpu);
+}
+
+static void cpu_disable(unsigned int cpu)
+{
+       cal_cpu_disable(cpu);
+}
+
+/******************************************************************************
+ *                            CPU idle management                             *
+ ******************************************************************************/
+/*
+ * State of CPUPM objects
+ * All CPUPM objects have 2 states, RUN and POWERDOWN.
+ *
+ * @RUN
+ * a state in which the power domain referred to by the object is turned on.
+ *
+ * @POWERDOWN
+ * a state in which the power domain referred to by the object is turned off.
+ * However, the power domain is not necessarily turned off even if the object
+ * is in POEWRDOWN state because the cpu may be booting or executing power off
+ * sequence.
+ */
+enum {
+       CPUPM_STATE_RUN = 0,
+       CPUPM_STATE_POWERDOWN,
+};
+
+/* Macros for CPUPM state */
+#define set_state_run(object)          (object)->state = CPUPM_STATE_RUN
+#define set_state_powerdown(object)    (object)->state = CPUPM_STATE_POWERDOWN
+
+/*
+ * Main struct of CPUPM
+ * Each cpu has its own data structure and main purpose of this struct is to
+ * manage the state of the cpu.
+ */
+struct exynos_cpupm {
+       /* cpu state, RUN or POWERDOWN */
+       int                     state;
+};
+
+static DEFINE_PER_CPU(struct exynos_cpupm, cpupm);
+
+/*
+ * State of each cpu is managed by a structure declared by percpu, so there
+ * is no need for protection for synchronization. However, when entering
+ * the power mode, it is necessary to set the critical section to check the
+ * state of cpus in the power domain, cpupm_lock is used for it.
+ */
+static spinlock_t cpupm_lock;
+
+/*
+ * Exynos cpuidle driver call exynos_cpu_pm_enter() and exynos_cpu_pm_exit()
+ * to handle platform specific configuration to control cpu power domain.
+ */
+int exynos_cpu_pm_enter(int cpu, int index)
+{
+       struct exynos_cpupm *pm;
+
+       spin_lock(&cpupm_lock);
+       pm = &per_cpu(cpupm, cpu);
+
+       /* Configure PMUCAL to power down core */
+       cpu_disable(cpu);
+
+       /* Set cpu state to POWERDOWN */
+       set_state_powerdown(pm);
+
+       spin_unlock(&cpupm_lock);
+
+       return index;
+}
+
+void exynos_cpu_pm_exit(int cpu, int cancel)
+{
+       struct exynos_cpupm *pm;
+
+       spin_lock(&cpupm_lock);
+       pm = &per_cpu(cpupm, cpu);
+
+       /* Set cpu state to RUN */
+       set_state_run(pm);
+
+       /* Configure PMUCAL to power up core */
+       cpu_enable(cpu);
+
+       spin_unlock(&cpupm_lock);
+}
+
+/******************************************************************************
+ *                                Initialization                              *
+ ******************************************************************************/
+static int __init exynos_cpupm_init(void)
+{
+       spin_lock_init(&cpupm_lock);
+
+       return 0;
+}
+arch_initcall(exynos_cpupm_init);
diff --git a/include/soc/samsung/exynos-cpupm.h b/include/soc/samsung/exynos-cpupm.h
new file mode 100644 (file)
index 0000000..41281a2
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2018 Park Bumgyu, Samsung Electronics Co., Ltd <bumgyu.park@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef __EXYNOS_CPUPM_H
+#define __EXYNOS_CPUPM_H __FILE__
+
+extern int exynos_cpu_pm_enter(int cpu, int index);
+extern void exynos_cpu_pm_exit(int cpu, int cancel);
+
+#endif /* __EXYNOS_CPUPM_H */