Merge "msm: Add krait scm driver to configure cpu" into msm-3.4
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 702667b..7ccdd0f 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -27,6 +27,7 @@
obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o perf_event_msm_krait_l2.o
+obj-$(CONFIG_ARCH_MSM_KRAIT) += krait-scm.o
obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o
ifndef CONFIG_MSM_SMP
diff --git a/arch/arm/mach-msm/krait-scm.c b/arch/arm/mach-msm/krait-scm.c
new file mode 100644
index 0000000..eb48d35
--- /dev/null
+++ b/arch/arm/mach-msm/krait-scm.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
+#include <linux/percpu.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+#include <linux/sysfs.h>
+#include <linux/sysdev.h>
+
+#include <mach/scm.h>
+
+#define CPU_CONFIG_CMD 5
+#define CPU_CONFIG_QUERY_CMD 6
+
+static int query_cpu_config(void)
+{
+ struct cpu_config_query_req_resp {
+ u32 id;
+ u32 arg0;
+ u32 arg1;
+ u32 arg2;
+ } request;
+ struct cpu_config_query_resp {
+ u32 ret0;
+ u32 ret1;
+ u32 ret2;
+ u32 ret3;
+ } response = {0};
+ int ret;
+
+ request.id = 1;
+ ret = scm_call(SCM_SVC_BOOT, CPU_CONFIG_QUERY_CMD, &request,
+ sizeof(request), &response, sizeof(response));
+ return ret ? : response.ret0;
+}
+
+static void set_cpu_config(int enable)
+{
+ struct cpu_config_req {
+ u32 id;
+ u32 arg0;
+ u32 arg1;
+ u32 arg2;
+ } request;
+
+ request.id = 1;
+ request.arg0 = enable;
+ scm_call(SCM_SVC_BOOT, CPU_CONFIG_CMD, &request, sizeof(request),
+ NULL, 0);
+}
+
+void enable_cpu_config(struct work_struct *work)
+{
+ set_cpu_config(1);
+}
+
+void disable_cpu_config(struct work_struct *work)
+{
+ set_cpu_config(0);
+}
+
+int cpu_config_on_each_cpu(bool enable)
+{
+ work_func_t func = enable ? enable_cpu_config : disable_cpu_config;
+ return schedule_on_each_cpu(func);
+}
+
+static ssize_t show_cpuctl(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", query_cpu_config());
+}
+
+static ssize_t store_cpuctl(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr, const char *buf,
+ size_t count)
+{
+ unsigned val;
+ int ret;
+
+ ret = kstrtouint(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+ ret = cpu_config_on_each_cpu(val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static SYSDEV_CLASS_ATTR(cpuctl, 0600, show_cpuctl, store_cpuctl);
+
+static int __init init_scm_cpu(void)
+{
+ return sysfs_create_file(&cpu_subsys.dev_root->kobj,
+ &attr_cpuctl.attr);
+}
+module_init(init_scm_cpu);