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, ¶m);
- 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) {