Merge "msm: Kconfig: add an entry for msm8910"
diff --git a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
index 5b4d3cf..b7dd427 100644
--- a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
+++ b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
@@ -7,10 +7,14 @@
 
 - qcom,core-core-type:	indicates whether this core is a CPU(0) or a GPU(1)
 
+- qcom,num-cores:	The number of cores this entry represents
+- qcom,sensors:		The vector of sensor ids for the cores
+
 - qcom,algo-disable-pc-threshold:	sets highest frequency at which DCVS
 					will allow the CPU to power collapse.
 - qcom,algo-em-win-size-min-us:		sets minimum Energy Minimization(EM)
 					window size.
+
 - qcom,algo-em-win-size-max-us:		sets maximum EM window size.
 - qcom,algo-em-max-util-pct:		sets maximum CPU utilization that will
 					not be exceeded by any core when
@@ -67,7 +71,7 @@
 
 			compatible = "qcom,dcvs-core-info";
 
-			qcom,num_cores = <1>;
+			qcom,num-cores = <1>;
 			qcom,sensors = <0>;
 
 			qcom,core-core-type = <1>;
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 16925fb..38b2721 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -62,6 +62,7 @@
 - qcom,chipid:		   If it exists this property is used to replace
 			   the chip identification read from the GPU hardware.
 			   This is used to override faulty hardware readings.
+- qcom,strtstp-sleepwake:  Boolean. Enables use of GPU SLUMBER instead of SLEEP for power savings
 
 Example of A330 GPU in MSM8974:
 
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 017aea9..6d00b01 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -25,6 +25,7 @@
 
 		qcom,idle-timeout = <83>; //<HZ/12>
 		qcom,nap-allowed = <1>;
+		qcom,strtstp-sleepwake;
 		qcom,clk-map = <0x00000016>; //KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE
 
 		/* Bus Scale Settings */
@@ -85,6 +86,9 @@
 
 			compatible = "qcom,dcvs-core-info";
 
+			qcom,num-cores = <1>;
+			qcom,sensors = <0>;
+
 			qcom,core-core-type = <1>;
 
 			qcom,algo-disable-pc-threshold = <0>;
diff --git a/arch/arm/boot/dts/msm9625-ion.dtsi b/arch/arm/boot/dts/msm9625-ion.dtsi
new file mode 100644
index 0000000..8183264
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-ion.dtsi
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, Linux Foundation. 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.
+ */
+
+/ {
+	qcom,ion {
+		compatible = "qcom,msm-ion";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,ion-heap@30 { /* SYSTEM HEAP */
+			reg = <30>;
+		};
+
+		qcom,ion-heap@25 { /* IOMMU HEAP */
+			reg = <25>;
+		};
+
+		qcom,ion-heap@28 { /* AUDIO HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <28>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+			qcom,memory-reservation-size = <0xAF000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index f50d14f..a8a2bf1 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -11,6 +11,7 @@
  */
 
 /include/ "skeleton.dtsi"
+/include/ "msm9625-ion.dtsi"
 
 / {
 	model = "Qualcomm MSM 9625";
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 3be7fc6..c7075bc 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -32,6 +32,8 @@
 
 static struct msm_dcvs_core_info grp3d_core_info = {
 	.freq_tbl	= &grp3d_freq[0],
+	.num_cores	= 1,
+	.sensors	= (int[]){0},
 	.core_param	= {
 		.core_type	= MSM_DCVS_CORE_TYPE_GPU,
 	},
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index e8baf6a..3cd4b2f 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2671,6 +2671,8 @@
 
 static struct msm_dcvs_core_info apq8064_core_info = {
 	.freq_tbl	= &apq8064_freq[0],
+	.num_cores	= 4,
+	.sensors	= (int[]){7, 8, 9, 10},
 	.core_param	= {
 		.core_type	= MSM_DCVS_CORE_TYPE_CPU,
 	},
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
index 490a34b..3ac0e74 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -46,6 +46,17 @@
 };
 
 /**
+ * struct msm_dcvs_freq
+ *
+ * API for clock driver code to register and receive frequency change
+ * request for the core from the msm_dcvs driver.
+ */
+struct msm_dcvs_freq {
+	const char *core_name;
+	/* Callback from msm_dcvs to set the core frequency */
+};
+
+/**
  * msm_dcvs_idle_source_register
  * @drv: Pointer to the source driver
  * @return: Handle to be used for sending idle state notifications.
@@ -90,6 +101,8 @@
  * before the sink driver can be registered.
  */
 struct msm_dcvs_core_info {
+	int					num_cores;
+	int					*sensors;
 	struct msm_dcvs_freq_entry		*freq_tbl;
 	struct msm_dcvs_core_param		core_param;
 	struct msm_dcvs_algo_param		algo_param;
@@ -101,6 +114,7 @@
  * msm_dcvs_register_core
  * @core_name: Unique name identifier for the core.
  * @info: The core specific algorithm parameters.
+ * @sensor: The thermal sensor number of the core in question
  * @return :
  *	0 on success,
  *	-ENOSYS,
@@ -110,35 +124,25 @@
  * msm_dcvs_freq_sink_register
  * Cores that need to run synchronously must share the same group id.
  */
-extern int msm_dcvs_register_core(const char *core_name,
-		struct msm_dcvs_core_info *info);
+extern int msm_dcvs_register_core(
+	const char *core_name,
+	struct msm_dcvs_core_info *info,
+	int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq),
+	unsigned int (*get_frequency)(struct msm_dcvs_freq *self),
+	int sensor);
 
 /**
- * struct msm_dcvs_freq
- *
- * API for clock driver code to register and receive frequency change
- * request for the core from the msm_dcvs driver.
- */
-struct msm_dcvs_freq {
-	const char *core_name;
-	/* Callback from msm_dcvs to set the core frequency */
-	int (*set_frequency)(struct msm_dcvs_freq *self,
-			unsigned int freq);
-	unsigned int (*get_frequency)(struct msm_dcvs_freq *self);
-};
-
-/**
- * msm_dcvs_freq_sink_register
+ * msm_dcvs_freq_sink_start
  * @drv: The sink driver
  * @return: Handle unique to the core.
  *
  * Register the clock driver code with the msm_dvs driver to get notified about
  * frequency change requests.
  */
-extern int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv);
+extern int msm_dcvs_freq_sink_start(struct msm_dcvs_freq *drv);
 
 /**
- * msm_dcvs_freq_sink_unregister
+ * msm_dcvs_freq_sink_stop
  * @drv: The sink driver
  * @return:
  *	0 on success,
@@ -147,6 +151,13 @@
  * Unregister the sink driver for the core. This will cause the source driver
  * for the core to stop sending idle pulses.
  */
-extern int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv);
+extern int msm_dcvs_freq_sink_stop(struct msm_dcvs_freq *drv);
 
+/**
+ * msm_dcvs_update_limits
+ * @drv: The sink driver
+ *
+ * Update the frequency known to dcvs when the limits are changed.
+ */
+extern void msm_dcvs_update_limits(struct msm_dcvs_freq *drv);
 #endif
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 9601b7e..288d6bb 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -23,6 +23,7 @@
 #include <linux/spinlock.h>
 #include <linux/stringify.h>
 #include <linux/debugfs.h>
+#include <linux/msm_tsens.h>
 #include <asm/atomic.h>
 #include <asm/page.h>
 #include <mach/msm_dcvs.h>
@@ -73,7 +74,6 @@
 
 struct dcvs_core {
 	char core_name[CORE_NAME_MAX];
-	uint32_t new_freq[MAX_PENDING];
 	uint32_t actual_freq;
 	uint32_t freq_change_us;
 
@@ -91,19 +91,21 @@
 	struct task_struct *task;
 	struct core_attribs attrib;
 	uint32_t handle;
-	uint32_t freq_pending;
 	struct hrtimer timer;
 	int32_t timer_disabled;
-	/* track if kthread for change_freq is active */
-	int32_t change_freq_activated;
 	struct msm_dcvs_core_info *info;
+	int sensor;
+	int pending_freq;
+	wait_queue_head_t wait_q;
+	int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq);
+	unsigned int (*get_frequency)(struct msm_dcvs_freq *self);
 };
 
 static int msm_dcvs_debug;
 static int msm_dcvs_enabled = 1;
 module_param_named(enable, msm_dcvs_enabled, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
-static struct dentry *debugfs_base;
+static struct dentry		*debugfs_base;
 
 static struct dcvs_core core_list[CORES_MAX];
 static DEFINE_MUTEX(core_list_lock);
@@ -123,28 +125,16 @@
 	uint32_t slack_us = 0;
 	uint32_t ret1 = 0;
 
-	if (!core->freq_driver || !core->freq_driver->set_frequency) {
+	if (!core->freq_driver || !core->set_frequency) {
 		/* Core may have unregistered or hotplugged */
 		return -ENODEV;
 	}
-repeat:
 	spin_lock_irqsave(&core->cpu_lock, flags);
-	if (unlikely(!core->freq_pending)) {
-		spin_unlock_irqrestore(&core->cpu_lock, flags);
-		return ret;
-	}
-	requested_freq = core->new_freq[core->freq_pending - 1];
-	if (unlikely(core->freq_pending > 1) &&
-		(msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)) {
-		int i;
-		for (i = 0; i < core->freq_pending - 1; i++) {
-			__info("Core %s missing freq %u\n",
-				core->core_name, core->new_freq[i]);
-		}
-	}
+repeat:
+
+	requested_freq = core->pending_freq;
 	time_start = core->time_start;
 	core->time_start = 0;
-	core->freq_pending = 0;
 	/**
 	 * Cancel the timers, we dont want the timer firing as we are
 	 * changing the clock rate. Dont let idle_exit and others setup
@@ -152,18 +142,18 @@
 	 */
 	hrtimer_cancel(&core->timer);
 	core->timer_disabled = 1;
+	if (requested_freq == core->actual_freq)
+		goto out;
+
 	spin_unlock_irqrestore(&core->cpu_lock, flags);
 
-	if (requested_freq == core->actual_freq)
-		return ret;
 
 	/**
 	 * Call the frequency sink driver to change the frequency
 	 * We will need to get back the actual frequency in KHz and
 	 * the record the time taken to change it.
 	 */
-	ret = core->freq_driver->set_frequency(core->freq_driver,
-				requested_freq);
+	ret = core->set_frequency(core->freq_driver, requested_freq);
 	if (ret <= 0) {
 		__err("Core %s failed to set freq %u\n",
 				core->core_name, requested_freq);
@@ -229,14 +219,40 @@
 			core->actual_freq, prev_freq,
 			core->freq_change_us, slack_us);
 
+	spin_lock_irqsave(&core->cpu_lock, flags);
 	/**
 	 * By the time we are done with freq changes, we could be asked to
 	 * change again. Check before exiting.
 	 */
-	if (core->freq_pending)
+	if (core->pending_freq)
 		goto repeat;
 
-	core->change_freq_activated = 0;
+
+out: /* should always be jumped to with the spin_lock held */
+	core->pending_freq = 0;
+	spin_unlock_irqrestore(&core->cpu_lock, flags);
+
+	return ret;
+}
+
+static int __msm_dcvs_report_temp(struct dcvs_core *core)
+{
+	struct msm_dcvs_core_info *info = core->info;
+	struct tsens_device tsens_dev;
+	int ret;
+	unsigned long temp = 0;
+
+	tsens_dev.sensor_num = core->sensor;
+	ret = tsens_get_temp(&tsens_dev, &temp);
+	if (!ret) {
+		tsens_dev.sensor_num = 0;
+		ret = tsens_get_temp(&tsens_dev, &temp);
+		if (!ret)
+			return -ENODEV;
+	}
+
+	ret = msm_dcvs_scm_set_power_params(core->handle, &info->power_param,
+			&info->freq_tbl[0], &core->coeffs);
 	return ret;
 }
 
@@ -246,23 +262,21 @@
 	static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
 
 	sched_setscheduler(current, SCHED_FIFO, &param);
-	set_current_state(TASK_UNINTERRUPTIBLE);
 
 	while (!kthread_should_stop()) {
-		mutex_lock(&core->lock);
-		__msm_dcvs_change_freq(core);
-		mutex_unlock(&core->lock);
-
-		schedule();
+		wait_event(core->wait_q, !(core->pending_freq == 0 ||
+					  core->pending_freq == -1) ||
+					  kthread_should_stop());
 
 		if (kthread_should_stop())
 			break;
 
-		set_current_state(TASK_UNINTERRUPTIBLE);
+		mutex_lock(&core->lock);
+		__msm_dcvs_change_freq(core);
+		__msm_dcvs_report_temp(core);
+		mutex_unlock(&core->lock);
 	}
 
-	__set_current_state(TASK_RUNNING);
-
 	return 0;
 }
 
@@ -278,33 +292,25 @@
 	ret = msm_dcvs_scm_event(core->handle, event, param0,
 				core->actual_freq, &new_freq, ret1);
 	if (ret) {
-		__err("Error (%d) sending SCM event %d for core %s\n",
+		if (ret == -13)
+			ret = 0;
+		else
+			__err("Error (%d) sending SCM event %d for core %s\n",
 				ret, event, core->core_name);
-		goto freq_done;
+		goto out;
 	}
 
-	if ((core->actual_freq != new_freq) &&
-			(core->new_freq[core->freq_pending] != new_freq)) {
-		if (core->freq_pending >= MAX_PENDING - 1)
-			core->freq_pending = MAX_PENDING - 1;
-		core->new_freq[core->freq_pending++] = new_freq;
+	if (core->actual_freq != new_freq && core->pending_freq != new_freq) {
+		core->pending_freq = new_freq;
 		core->time_start = ktime_to_ns(ktime_get());
 
-		/* Schedule the frequency change */
-		if (!core->task)
-			__err("Uninitialized task for core %s\n",
-					core->core_name);
-		else {
-			if (freq_changed)
-				*freq_changed = 1;
-			core->change_freq_activated = 1;
-			wake_up_process(core->task);
-		}
+		if (core->task)
+			wake_up(&core->wait_q);
 	} else {
 		if (freq_changed)
 			*freq_changed = 0;
 	}
-freq_done:
+out:
 	spin_unlock_irqrestore(&core->cpu_lock, flags);
 
 	return ret;
@@ -571,7 +577,10 @@
 }
 
 int msm_dcvs_register_core(const char *core_name,
-		struct msm_dcvs_core_info *info)
+	struct msm_dcvs_core_info *info,
+	int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq),
+	unsigned int (*get_frequency)(struct msm_dcvs_freq *self),
+	int sensor)
 {
 	int ret = -EINVAL;
 	struct dcvs_core *core = NULL;
@@ -587,6 +596,9 @@
 
 	mutex_lock(&core->lock);
 
+	core->set_frequency = set_frequency;
+	core->get_frequency = get_frequency;
+
 	core->info = info;
 	memcpy(&core->algo_param, &info->algo_param,
 			sizeof(struct msm_dcvs_algo_param));
@@ -594,6 +606,9 @@
 	memcpy(&core->coeffs, &info->energy_coeffs,
 			sizeof(struct msm_dcvs_energy_curve_coeffs));
 
+	pr_debug("registering core with sensor %d\n", sensor);
+	core->sensor = sensor;
+
 	ret = msm_dcvs_scm_register_core(core->handle, &info->core_param);
 	if (ret)
 		goto bail;
@@ -618,14 +633,27 @@
 		core_handles[core->handle - CORE_HANDLE_OFFSET] = NULL;
 		goto bail;
 	}
-
+	init_waitqueue_head(&core->wait_q);
+	core->task = kthread_run(msm_dcvs_do_freq, (void *)core,
+			"msm_dcvs/%d", core->handle);
 bail:
 	mutex_unlock(&core->lock);
 	return ret;
 }
 EXPORT_SYMBOL(msm_dcvs_register_core);
 
-int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv)
+void msm_dcvs_update_limits(struct msm_dcvs_freq *drv)
+{
+	struct dcvs_core *core;
+
+	if (!drv || !drv->core_name)
+		return;
+
+	core = msm_dcvs_get_core(drv->core_name, false);
+	core->actual_freq = core->get_frequency(drv);
+}
+
+int msm_dcvs_freq_sink_start(struct msm_dcvs_freq *drv)
 {
 	int ret = -EINVAL;
 	struct dcvs_core *core = NULL;
@@ -644,8 +672,6 @@
 		__info("Frequency notifier for %s being replaced\n",
 				core->core_name);
 	core->freq_driver = drv;
-	core->task = kthread_create(msm_dcvs_do_freq, (void *)core,
-			"msm_dcvs/%d", core->handle);
 	if (IS_ERR(core->task)) {
 		mutex_unlock(&core->lock);
 		return -EFAULT;
@@ -655,7 +681,7 @@
 		__info("Enabling idle pulse for %s\n", core->core_name);
 
 	if (core->idle_driver) {
-		core->actual_freq = core->freq_driver->get_frequency(drv);
+		core->actual_freq = core->get_frequency(drv);
 		/* Notify TZ to start receiving idle info for the core */
 		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 1,
 					   &ret1, &ret2);
@@ -667,9 +693,9 @@
 
 	return core->handle;
 }
-EXPORT_SYMBOL(msm_dcvs_freq_sink_register);
+EXPORT_SYMBOL(msm_dcvs_freq_sink_start);
 
-int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv)
+int msm_dcvs_freq_sink_stop(struct msm_dcvs_freq *drv)
 {
 	int ret = -EINVAL;
 	struct dcvs_core *core = NULL;
@@ -698,14 +724,12 @@
 		if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
 			__info("Enabling LPM for %s\n", core->core_name);
 	}
-	core->freq_pending = 0;
 	core->freq_driver = NULL;
 	mutex_unlock(&core->lock);
-	kthread_stop(core->task);
 
 	return 0;
 }
-EXPORT_SYMBOL(msm_dcvs_freq_sink_unregister);
+EXPORT_SYMBOL(msm_dcvs_freq_sink_stop);
 
 int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv)
 {
@@ -785,7 +809,7 @@
 			__err("Error (%d) sending idle exit for %s\n",
 					ret, core->core_name);
 		/* only start slack timer if change_freq won't */
-		if (freq_changed || core->change_freq_activated)
+		if (freq_changed)
 			break;
 		if (timer_interval_us && !core->timer_disabled) {
 			ret = hrtimer_start(&core->timer,
diff --git a/drivers/cpufreq/cpufreq_gov_msm.c b/drivers/cpufreq/cpufreq_gov_msm.c
index 4eeff35..9ad1811 100644
--- a/drivers/cpufreq/cpufreq_gov_msm.c
+++ b/drivers/cpufreq/cpufreq_gov_msm.c
@@ -36,11 +36,13 @@
 static void msm_gov_check_limits(struct cpufreq_policy *policy)
 {
 	struct msm_gov *gov = &per_cpu(msm_gov_info, policy->cpu);
+	struct msm_dcvs_freq *dcvs_notifier =
+			&(per_cpu(msm_gov_info, policy->cpu).gov_notifier);
 
 	if (policy->max < gov->cur_freq)
 		__cpufreq_driver_target(policy, policy->max,
 				CPUFREQ_RELATION_H);
-	else if (policy->min > gov->min_freq)
+	else if (policy->min > gov->cur_freq)
 		__cpufreq_driver_target(policy, policy->min,
 				CPUFREQ_RELATION_L);
 	else
@@ -50,6 +52,7 @@
 	gov->cur_freq = policy->cur;
 	gov->min_freq = policy->min;
 	gov->max_freq = policy->max;
+	msm_dcvs_update_limits(dcvs_notifier);
 }
 
 static int msm_dcvs_freq_set(struct msm_dcvs_freq *self,
@@ -66,13 +69,17 @@
 	if (freq > gov->max_freq)
 		freq = gov->max_freq;
 
-	ret = __cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L);
-	gov->cur_freq = gov->policy->cur;
-
 	mutex_unlock(&per_cpu(gov_mutex, gov->cpu));
 
-	if (!ret)
-		return gov->cur_freq;
+	ret = cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L);
+
+	if (!ret) {
+		gov->cur_freq = cpufreq_quick_get(gov->cpu);
+		if (freq != gov->cur_freq)
+			pr_err("cpu %d freq %u gov->cur_freq %u didn't match",
+						gov->cpu, freq, gov->cur_freq);
+	}
+	ret = gov->cur_freq;
 
 	return ret;
 }
@@ -82,7 +89,12 @@
 	struct msm_gov *gov =
 		container_of(self, struct msm_gov, gov_notifier);
 
-	return gov->cur_freq;
+	/*
+	 * the rw_sem in cpufreq is always held when this is called.
+	 * The policy->cur won't be updated in this case - so it is safe to
+	 * access policy->cur
+	 */
+	return gov->policy->cur;
 }
 
 static int cpufreq_governor_msm(struct cpufreq_policy *policy,
@@ -104,18 +116,14 @@
 		per_cpu(msm_gov_info, cpu).cpu = cpu;
 		gov->policy = policy;
 		dcvs_notifier->core_name = core_name[cpu];
-		dcvs_notifier->set_frequency = msm_dcvs_freq_set;
-		dcvs_notifier->get_frequency = msm_dcvs_freq_get;
-		handle = msm_dcvs_freq_sink_register(dcvs_notifier);
+		handle = msm_dcvs_freq_sink_start(dcvs_notifier);
 		BUG_ON(handle < 0);
 		msm_gov_check_limits(policy);
 		mutex_unlock(&per_cpu(gov_mutex, cpu));
 		break;
 
 	case CPUFREQ_GOV_STOP:
-		mutex_lock(&per_cpu(gov_mutex, cpu));
-		msm_dcvs_freq_sink_unregister(dcvs_notifier);
-		mutex_unlock(&per_cpu(gov_mutex, cpu));
+		msm_dcvs_freq_sink_stop(dcvs_notifier);
 		break;
 
 	case CPUFREQ_GOV_LIMITS:
@@ -139,13 +147,19 @@
 	int ret = 0;
 	int cpu;
 	struct msm_dcvs_core_info *core = NULL;
+	int sensor = 0;
 
 	core = pdev->dev.platform_data;
 
 	for_each_possible_cpu(cpu) {
 		mutex_init(&per_cpu(gov_mutex, cpu));
 		snprintf(core_name[cpu], 10, "cpu%d", cpu);
-		ret = msm_dcvs_register_core(core_name[cpu], core);
+		if (cpu < core->num_cores)
+			sensor = core->sensors[cpu];
+		ret = msm_dcvs_register_core(core_name[cpu], core,
+						msm_dcvs_freq_set,
+						msm_dcvs_freq_get,
+						sensor);
 		if (ret)
 			pr_err("Unable to register core for %d\n", cpu);
 	}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 573e0a6..97711e2 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -896,6 +896,19 @@
 			info->freq_tbl[index].leakage_energy_offset = 0;
 	}
 
+	if (adreno_of_read_property(node, "qcom,num-cores", &info->num_cores))
+		goto err;
+
+	info->sensors = kzalloc(info->num_cores *
+			sizeof(int),
+			GFP_KERNEL);
+
+	for (count = 0; count < info->num_cores; count++) {
+		if (adreno_of_read_property(node, "qcom,sensors",
+			&(info->sensors[count])))
+			goto err;
+	}
+
 	if (adreno_of_read_property(node, "qcom,core-core-type",
 		&info->core_param.core_type))
 		goto err;
@@ -1094,6 +1107,9 @@
 		&pdata->nap_allowed))
 		pdata->nap_allowed = 1;
 
+	pdata->strtstp_sleepwake = of_property_read_bool(pdev->dev.of_node,
+						"qcom,strtstp-sleepwake");
+
 	if (adreno_of_read_property(pdev->dev.of_node, "qcom,clk-map",
 		&pdata->clk_map))
 		goto err;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index acf22ac..3f9b3d7 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -171,7 +171,9 @@
 	low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
 	for (i = 0; i <= low_level; i++)
 		tbl[i].freq = pwr->pwrlevels[low_level - i].gpu_freq / 1000;
-	ret = msm_dcvs_register_core(device->name, priv->core_info);
+	ret = msm_dcvs_register_core(device->name, priv->core_info,
+			msm_set_freq, msm_get_freq,
+			priv->core_info->sensors[0]);
 	if (ret) {
 		KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
 		goto err;
@@ -188,9 +190,7 @@
 	}
 
 	priv->freq_sink.core_name = device->name;
-	priv->freq_sink.set_frequency = msm_set_freq;
-	priv->freq_sink.get_frequency = msm_get_freq;
-	ret = msm_dcvs_freq_sink_register(&priv->freq_sink);
+	ret = msm_dcvs_freq_sink_start(&priv->freq_sink);
 	if (ret >= 0) {
 		if (device->ftbl->isidle(device)) {
 			priv->gpu_busy = 0;
@@ -220,7 +220,7 @@
 	if (pwrscale->priv == NULL)
 		return;
 	msm_dcvs_idle_source_unregister(&priv->idle_source);
-	msm_dcvs_freq_sink_unregister(&priv->freq_sink);
+	msm_dcvs_freq_sink_stop(&priv->freq_sink);
 	kfree(pwrscale->priv);
 	pwrscale->priv = NULL;
 	msm_restore_io_fraction(device);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.c b/drivers/media/video/msm_vidc/msm_vidc_debug.c
index 7921f84..fa62988 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.c
@@ -104,6 +104,7 @@
 		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
 		goto failed_create_dir;
 	}
+	msm_vidc_debug = 0x3;
 failed_create_dir:
 	return dir;
 }
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.h b/drivers/media/video/msm_vidc/msm_vidc_debug.h
index b7928e9..f7aa742 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.h
@@ -18,19 +18,24 @@
 
 #define VIDC_DBG_TAG "msm_vidc: %d: "
 
+/*To enable messages OR these values and
+* echo the result to debugfs file*/
+
 enum vidc_msg_prio {
-	VIDC_ERR,
-	VIDC_WARN,
-	VIDC_INFO,
-	VIDC_DBG,
+	VIDC_ERR  = 0x0001,
+	VIDC_WARN = 0x0002,
+	VIDC_INFO = 0x0004,
+	VIDC_DBG  = 0x0008,
+	VIDC_PROF = 0x0010,
+	VIDC_FW   = 0x1000,
 };
 
 extern int msm_vidc_debug;
-#define dprintk(level, fmt, arg...)	\
-	do {							\
-		if (msm_vidc_debug >= level) \
-			printk(KERN_DEBUG VIDC_DBG_TAG fmt, \
-				level, ## arg); \
+#define dprintk(__level, __fmt, arg...)	\
+	do { \
+		if (msm_vidc_debug & __level) \
+			printk(KERN_DEBUG VIDC_DBG_TAG __fmt,\
+				__level, ## arg); \
 	} while (0)
 
 struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 32d3aef..9cc0de4 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -284,7 +284,8 @@
 			uint32_t rate, uint32_t channels);
 
 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
-				uint32_t rate, uint32_t channels);
+				uint32_t rate, uint32_t channels,
+				char *channel_map);
 
 int q6asm_media_format_block_aac(struct audio_client *ac,
 			struct asm_aac_cfg *cfg);
diff --git a/sound/soc/msm/msm-lowlatency-pcm-q6.c b/sound/soc/msm/msm-lowlatency-pcm-q6.c
index 129f69f..fcfcb66 100644
--- a/sound/soc/msm/msm-lowlatency-pcm-q6.c
+++ b/sound/soc/msm/msm-lowlatency-pcm-q6.c
@@ -218,8 +218,27 @@
 	if (prtd->enabled)
 		return 0;
 
+	if (!prtd->set_channel_map) {
+		memset(prtd->channel_map, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+		if (prtd->channel_mode == 1) {
+			prtd->channel_map[0] = PCM_CHANNEL_FL;
+		} else if (prtd->channel_mode == 2) {
+			prtd->channel_map[0] = PCM_CHANNEL_FL;
+			prtd->channel_map[0] = PCM_CHANNEL_FR;
+		} else if (prtd->channel_mode == 6) {
+			prtd->channel_map[0] = PCM_CHANNEL_FC;
+			prtd->channel_map[0] = PCM_CHANNEL_FL;
+			prtd->channel_map[0] = PCM_CHANNEL_FR;
+			prtd->channel_map[0] = PCM_CHANNEL_LB;
+			prtd->channel_map[0] = PCM_CHANNEL_RB;
+			prtd->channel_map[0] = PCM_CHANNEL_LFE;
+		} else {
+			pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+				prtd->channel_mode);
+		}
+	}
 	ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
-			runtime->rate, runtime->channels);
+			runtime->rate, runtime->channels, prtd->channel_map);
 	if (ret < 0)
 		pr_info("%s: CMD Format block failed\n", __func__);
 
@@ -389,6 +408,7 @@
 	}
 
 	prtd->dsp_cnt = 0;
+	prtd->set_channel_map = false;
 	runtime->private_data = prtd;
 	pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
 	pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index 5b0759c..7d04f95 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -269,9 +269,29 @@
 	prtd->channel_mode = runtime->channels;
 	if (prtd->enabled)
 		return 0;
-
+	pr_debug("prtd->set_channel_map: %d", prtd->set_channel_map);
+	if (!prtd->set_channel_map) {
+		pr_debug("using default channel map");
+		memset(prtd->channel_map, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+		if (prtd->channel_mode == 1) {
+			prtd->channel_map[0] = PCM_CHANNEL_FL;
+		} else if (prtd->channel_mode == 2) {
+			prtd->channel_map[1] = PCM_CHANNEL_FL;
+			prtd->channel_map[2] = PCM_CHANNEL_FR;
+		} else if (prtd->channel_mode == 6) {
+			prtd->channel_map[0] = PCM_CHANNEL_FC;
+			prtd->channel_map[1] = PCM_CHANNEL_FL;
+			prtd->channel_map[2] = PCM_CHANNEL_FR;
+			prtd->channel_map[3] = PCM_CHANNEL_LB;
+			prtd->channel_map[4] = PCM_CHANNEL_RB;
+			prtd->channel_map[5] = PCM_CHANNEL_LFE;
+		} else {
+			pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+				prtd->channel_mode);
+		}
+	}
 	ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
-			runtime->rate, runtime->channels);
+			runtime->rate, runtime->channels, prtd->channel_map);
 	if (ret < 0)
 		pr_info("%s: CMD Format block failed\n", __func__);
 
@@ -452,6 +472,7 @@
 	}
 
 	prtd->dsp_cnt = 0;
+	prtd->set_channel_map = false;
 	runtime->private_data = prtd;
 	pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
 	pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
@@ -492,6 +513,15 @@
 	return rc;
 }
 
+void multi_ch_pcm_set_channel_map(char *channel_mapping)
+{
+	pr_debug("%s\n", __func__);
+	if (multi_ch_pcm_audio.prtd) {
+		multi_ch_pcm_audio.prtd->set_channel_map = true;
+		memcpy(multi_ch_pcm_audio.prtd->channel_map, channel_mapping,
+			 PCM_FORMAT_MAX_NUM_CHANNEL);
+	}
+}
 
 static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
 	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
diff --git a/sound/soc/msm/msm-pcm-q6.h b/sound/soc/msm/msm-pcm-q6.h
index f1af99a..2678498 100644
--- a/sound/soc/msm/msm-pcm-q6.h
+++ b/sound/soc/msm/msm-pcm-q6.h
@@ -81,6 +81,8 @@
 	int periods;
 	int mmap_flag;
 	atomic_t pending_buffer;
+	bool set_channel_map;
+	char channel_map[8];
 };
 
 struct output_meta_data_st {
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 4d0caa3..f28d01a 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -78,6 +78,7 @@
 static const DECLARE_TLV_DB_LINEAR(compressed2_rx_vol_gain, 0,
 			INT_RX_VOL_MAX_STEPS);
 static int msm_route_ec_ref_rx;
+static char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
 
 /* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
 #define MAX_EQ_SESSIONS		MSM_FRONTEND_DAI_CS_VOICE
@@ -862,6 +863,27 @@
 	return 0;
 }
 
+static int msm_routing_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+		ucontrol->value.integer.value[i] = channel_mapping[i];
+	return 0;
+}
+
+static int msm_routing_put_channel_map_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+		channel_mapping[i] = (char)(ucontrol->value.integer.value[i]);
+	multi_ch_pcm_set_channel_map(channel_mapping);
+
+	return 0;
+}
+
 static int msm_routing_set_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1891,6 +1913,12 @@
 	msm_routing_set_compressed2_vol_mixer, compressed2_rx_vol_gain),
 };
 
+static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
+	SOC_SINGLE_MULTI_EXT("Playback Channel Map", SND_SOC_NOPM, 0, 8,
+	0, 8, msm_routing_get_channel_map_mixer,
+	msm_routing_put_channel_map_mixer),
+};
+
 static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
 	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "SRS TruMedia",
@@ -2867,6 +2895,10 @@
 	snd_soc_add_platform_controls(platform,
 				ec_ref_rx_mixer_controls,
 			ARRAY_SIZE(ec_ref_rx_mixer_controls));
+
+	snd_soc_add_platform_controls(platform,
+				multi_ch_channel_map_mixer_controls,
+			ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
 	return 0;
 }
 
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 6b87475..14f330b 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -126,4 +126,6 @@
 
 int compressed_set_volume(unsigned volume);
 
+void multi_ch_pcm_set_channel_map(char *channel_mapping);
+
 #endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 6865871..0aad217 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -2317,7 +2317,7 @@
 }
 
 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
-				uint32_t rate, uint32_t channels)
+			uint32_t rate, uint32_t channels, char *channel_map)
 {
 	struct asm_stream_media_format_update fmt;
 	u8 *channel_mapping;
@@ -2340,39 +2340,7 @@
 	channel_mapping =
 		fmt.write_cfg.multi_ch_pcm_cfg.channel_mapping;
 
-	memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
-
-	if (channels == 1)  {
-		channel_mapping[0] = PCM_CHANNEL_FL;
-	} else if (channels == 2) {
-		channel_mapping[0] = PCM_CHANNEL_FL;
-		channel_mapping[1] = PCM_CHANNEL_FR;
-	} else if (channels == 4) {
-		channel_mapping[0] = PCM_CHANNEL_FL;
-		channel_mapping[1] = PCM_CHANNEL_FR;
-		channel_mapping[1] = PCM_CHANNEL_LB;
-		channel_mapping[1] = PCM_CHANNEL_RB;
-	} else if (channels == 6) {
-		channel_mapping[0] = PCM_CHANNEL_FC;
-		channel_mapping[1] = PCM_CHANNEL_FL;
-		channel_mapping[2] = PCM_CHANNEL_FR;
-		channel_mapping[3] = PCM_CHANNEL_LB;
-		channel_mapping[4] = PCM_CHANNEL_RB;
-		channel_mapping[5] = PCM_CHANNEL_LFE;
-	} else if (channels == 8) {
-		channel_mapping[0] = PCM_CHANNEL_FC;
-		channel_mapping[1] = PCM_CHANNEL_FL;
-		channel_mapping[2] = PCM_CHANNEL_FR;
-		channel_mapping[3] = PCM_CHANNEL_LB;
-		channel_mapping[4] = PCM_CHANNEL_RB;
-		channel_mapping[5] = PCM_CHANNEL_LFE;
-		channel_mapping[6] = PCM_CHANNEL_FLC;
-		channel_mapping[7] = PCM_CHANNEL_FRC;
-	} else {
-		pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
-				channels);
-		return -EINVAL;
-	}
+	memcpy(channel_mapping, channel_map, PCM_FORMAT_MAX_NUM_CHANNEL);
 
 	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
 	if (rc < 0) {