Merge "crypto: msm: fix hmac ahashing issues with simultaneous multiple requests."
diff --git a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
index 5ebb516..39b10b3 100644
--- a/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-ssd2080m-720p-video.dtsi
@@ -118,5 +118,7 @@
qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>;
+ qcom,mdss-dsi-lp11-init;
+ qcom,mdss-dsi-init-delay-us = <50000>;
};
};
diff --git a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
index 6b62391..d4bb37b 100644
--- a/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ab-pm8941-mtp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The 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
@@ -22,5 +22,5 @@
};
&sdhc_1 {
- qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
};
diff --git a/arch/arm/mach-msm/smp2p.c b/arch/arm/mach-msm/smp2p.c
index df241f8..5574eae 100644
--- a/arch/arm/mach-msm/smp2p.c
+++ b/arch/arm/mach-msm/smp2p.c
@@ -940,7 +940,7 @@
if (size < sizeof(struct smp2p_smem)) {
SMP2P_ERR(
- "%s pid %d item size too small; expected: %d actual: %d\n",
+ "%s pid %d item size too small; expected: %zu actual: %d\n",
__func__, remote_pid,
sizeof(struct smp2p_smem), size);
smem_item = NULL;
diff --git a/arch/arm/mach-msm/smp2p_private.h b/arch/arm/mach-msm/smp2p_private.h
index 8e0d7a3..7174950 100644
--- a/arch/arm/mach-msm/smp2p_private.h
+++ b/arch/arm/mach-msm/smp2p_private.h
@@ -1,6 +1,6 @@
/* arch/arm/mach-msm/smp2p_private.h
*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The 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
@@ -44,10 +44,10 @@
#define SMP2P_GET_BITS(hdr_val, mask, bit) \
(((hdr_val) & (mask)) >> (bit))
#define SMP2P_SET_BITS(hdr_val, mask, bit, new_value) \
- do {\
+ {\
hdr_val = (hdr_val & ~(mask)) \
| (((new_value) << (bit)) & (mask)); \
- } while (0)
+ }
#define SMP2P_GET_LOCAL_PID(hdr) \
SMP2P_GET_BITS(hdr, SMP2P_LOCAL_PID_MASK, SMP2P_LOCAL_PID_BIT)
diff --git a/drivers/devfreq/governor_cpubw_hwmon.c b/drivers/devfreq/governor_cpubw_hwmon.c
index fb5a562..e7d373b 100644
--- a/drivers/devfreq/governor_cpubw_hwmon.c
+++ b/drivers/devfreq/governor_cpubw_hwmon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The 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
@@ -77,13 +77,15 @@
static int l2pm_irq;
static unsigned int bytes_per_beat;
-static unsigned int sample_ms = 50;
static unsigned int tolerance_percent = 10;
static unsigned int guard_band_mbps = 100;
static unsigned int decay_rate = 90;
-static unsigned int io_percent = 15;
-static unsigned int bw_step = 200;
+static unsigned int io_percent = 16;
+static unsigned int bw_step = 190;
+#define MIN_MS 10U
+#define MAX_MS 500U
+static unsigned int sample_ms = 50;
static u32 prev_r_start_val;
static u32 prev_w_start_val;
static unsigned long prev_ab;
@@ -245,7 +247,7 @@
}
*ab = roundup(mbps, bw_step);
- *freq = roundup((mbps * 100) / io_percent, bw_step);
+ *freq = (mbps * 100) / io_percent;
}
#define TOO_SOON_US (1 * USEC_PER_MSEC)
@@ -343,7 +345,6 @@
return 0;
}
-gov_attr(sample_ms, 10U, 500U);
gov_attr(tolerance_percent, 0U, 30U);
gov_attr(guard_band_mbps, 0U, 2000U);
gov_attr(decay_rate, 0U, 100U);
@@ -351,7 +352,6 @@
gov_attr(bw_step, 50U, 1000U);
static struct attribute *dev_attr[] = {
- &dev_attr_sample_ms.attr,
&dev_attr_tolerance_percent.attr,
&dev_attr_guard_band_mbps.attr,
&dev_attr_decay_rate.attr,
@@ -378,7 +378,13 @@
ret = sysfs_create_group(&df->dev.kobj, &dev_attr_group);
if (ret)
return ret;
+
+ sample_ms = df->profile->polling_ms;
+ sample_ms = max(MIN_MS, sample_ms);
+ sample_ms = min(MAX_MS, sample_ms);
+ df->profile->polling_ms = sample_ms;
devfreq_monitor_start(df);
+
pr_debug("Enabled CPU BW HW monitor governor\n");
break;
@@ -391,7 +397,10 @@
break;
case DEVFREQ_GOV_INTERVAL:
- devfreq_interval_update(df, (unsigned int *)data);
+ sample_ms = *(unsigned int *)data;
+ sample_ms = max(MIN_MS, sample_ms);
+ sample_ms = min(MAX_MS, sample_ms);
+ devfreq_interval_update(df, &sample_ms);
break;
}
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index a39ceef..95e4017 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The 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
@@ -397,7 +397,7 @@
*/
if (count)
- wake_up_interruptible_all(&drawctxt->wq);
+ wake_up_all(&drawctxt->wq);
/*
* Return positive if the context submitted commands or if we figured
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 6007a3f..d727423 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2014, The 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
@@ -138,7 +138,7 @@
u32 timestamp, u32 type)
{
struct adreno_context *drawctxt = priv;
- wake_up_interruptible_all(&drawctxt->waiting);
+ wake_up_all(&drawctxt->waiting);
}
#define adreno_wait_event_interruptible_timeout(wq, condition, timeout, io) \
@@ -266,7 +266,7 @@
{
struct adreno_context *drawctxt = priv;
- wake_up_interruptible_all(&drawctxt->waiting);
+ wake_up_all(&drawctxt->waiting);
kgsl_context_put(&drawctxt->base);
}
@@ -310,7 +310,7 @@
mutex_unlock(&device->mutex);
if (timeout) {
- ret = (int) wait_event_interruptible_timeout(drawctxt->waiting,
+ ret = (int) wait_event_timeout(drawctxt->waiting,
_check_global_timestamp(device, timestamp),
msecs_to_jiffies(timeout));
@@ -319,7 +319,7 @@
else if (ret > 0)
ret = 0;
} else {
- ret = (int) wait_event_interruptible(drawctxt->waiting,
+ wait_event(drawctxt->waiting,
_check_global_timestamp(device, timestamp));
}
@@ -386,8 +386,8 @@
mutex_unlock(&drawctxt->mutex);
/* Give the bad news to everybody waiting around */
- wake_up_interruptible_all(&drawctxt->waiting);
- wake_up_interruptible_all(&drawctxt->wq);
+ wake_up_all(&drawctxt->waiting);
+ wake_up_all(&drawctxt->wq);
}
/**
@@ -543,6 +543,14 @@
ret = adreno_drawctxt_wait_global(adreno_dev, context,
drawctxt->internal_timestamp, 10 * 1000);
+ /*
+ * If the wait for global fails then nothing after this point is likely
+ * to work very well - BUG_ON() so we can take advantage of the debug
+ * tools to figure out what the h - e - double hockey sticks happened
+ */
+
+ BUG_ON(ret);
+
kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(context->id, soptimestamp),
drawctxt->timestamp);
@@ -557,8 +565,8 @@
drawctxt->ops->detach(drawctxt);
/* wake threads waiting to submit commands from this context */
- wake_up_interruptible_all(&drawctxt->waiting);
- wake_up_interruptible_all(&drawctxt->wq);
+ wake_up_all(&drawctxt->waiting);
+ wake_up_all(&drawctxt->wq);
return ret;
}
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c6996a4..cd6989c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2550,6 +2550,15 @@
.resume = mxt_resume,
#endif
};
+#else
+static int mxt_suspend(struct device *dev)
+{
+ return 0;
+};
+static int mxt_resume(struct device *dev)
+{
+ return 0;
+};
#endif
static int mxt_debugfs_object_show(struct seq_file *m, void *v)
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 7da0376..e577353 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -1559,7 +1559,7 @@
}
dev_dbg(&fwu->rmi4_data->i2c_client->dev,
- "%s: Firmware image size = %d\n",
+ "%s: Firmware image size = %zu\n",
__func__, fw_entry->size);
fwu->data_buffer = fw_entry->data;
@@ -1670,7 +1670,7 @@
if (count < fwu->config_size) {
dev_err(&rmi4_data->i2c_client->dev,
- "%s: Not enough space (%d bytes) in buffer\n",
+ "%s: Not enough space (%zu bytes) in buffer\n",
__func__, count);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
index c8a4366..567a263 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, The 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
@@ -34,12 +34,20 @@
#define ISPIF_VFE_m_INTF_CMD_0(m) (0x0004 + ISPIF_VFE(m))
#define ISPIF_VFE_m_INTF_CMD_1(m) (0x0030 + ISPIF_VFE(m))
#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) (0x0010 + ISPIF_VFE(m) + 4*(n))
-#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x0014 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) (0x0014 + ISPIF_VFE(m) + \
+ ((n > 0) ? (0x20) : 0) \
+ + 8*(n))
#define ISPIF_VFE_m_PIX_OUTPUT_n_MISR(m, n) (0x0290 + ISPIF_VFE(m) + 4*(n))
-#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x0298 + ISPIF_VFE(m) + 8*(n))
-#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x029C + ISPIF_VFE(m) + 8*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_0(m, n) (0x001C + ISPIF_VFE(m) + \
+ ((n > 0) ? (0x24) : 0) \
+ + 0xc*(n))
+#define ISPIF_VFE_m_RDI_OUTPUT_n_MISR_1(m, n) (0x0020 + ISPIF_VFE(m) + \
+ ((n > 0) ? (0x24) : 0) \
+ + 0xc*(n))
#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) (0x0024 + ISPIF_VFE(m) + 4*(n))
-#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x0028 + ISPIF_VFE(m) + 4*(n))
+#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) (0x0028 + ISPIF_VFE(m) + \
+ ((n > 0) ? (0x34) : 0) \
+ + 8*(n))
/* Defines for compatibility with newer ISPIF versions */
#define ISPIF_RST_CMD_1_ADDR (0x0000)
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 035fc4b..9774c3c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -246,38 +246,38 @@
return ret;
}
-struct buffer_info *get_same_fd_buffer(struct msm_vidc_inst *inst,
- struct list_head *list, int fd, int *plane)
+struct msm_smem *get_same_fd_buffer(struct msm_vidc_inst *inst,
+ struct list_head *list, int fd)
{
struct buffer_info *temp;
- struct buffer_info *ret = NULL;
+ struct msm_smem *same_fd_handle = NULL;
+
int i;
if (fd == 0)
return NULL;
- if (!list || fd < 0 || !plane) {
+ if (!list || fd < 0) {
dprintk(VIDC_ERR, "Invalid input\n");
goto err_invalid_input;
}
- *plane = 0;
mutex_lock(&inst->lock);
list_for_each_entry(temp, list, list) {
for (i = 0; (i < temp->num_planes)
&& (i < VIDEO_MAX_PLANES); i++) {
- if (temp && temp->fd[i] == fd) {
+ if (temp && (temp->fd[i] == fd) &&
+ temp->handle[i] && temp->mapped[i]) {
temp->same_fd_ref[i]++;
dprintk(VIDC_INFO,
"Found same fd buffer\n");
- ret = temp;
- *plane = i;
+ same_fd_handle = temp->handle[i];
break;
}
}
- if (ret)
+ if (same_fd_handle)
break;
}
mutex_unlock(&inst->lock);
err_invalid_input:
- return ret;
+ return same_fd_handle;
}
struct buffer_info *device_to_uvaddr(struct msm_vidc_inst *inst,
@@ -423,6 +423,7 @@
struct buffer_info *temp = NULL;
int plane = 0;
int i = 0, rc = 0;
+ struct msm_smem *same_fd_handle = NULL;
if (!b || !inst) {
dprintk(VIDC_ERR, "%s: invalid input\n", __func__);
@@ -480,16 +481,17 @@
if (rc < 0)
goto exit;
- temp = get_same_fd_buffer(inst, &inst->registered_bufs,
- b->m.planes[i].reserved[0], &plane);
+ same_fd_handle = get_same_fd_buffer(inst,
+ &inst->registered_bufs,
+ b->m.planes[i].reserved[0]);
populate_buf_info(binfo, b, i);
- if (temp) {
+ if (same_fd_handle) {
binfo->device_addr[i] =
- temp->handle[plane]->device_addr + binfo->buff_off[i];
+ same_fd_handle->device_addr + binfo->buff_off[i];
b->m.planes[i].m.userptr = binfo->device_addr[i];
binfo->mapped[i] = false;
- binfo->handle[i] = temp->handle[i];
+ binfo->handle[i] = same_fd_handle;
} else {
if (inst->map_output_buffer) {
binfo->handle[i] =
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index 8090b95..d7fa87b 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2009 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
- * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2014, The 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 as
@@ -318,7 +318,7 @@
value |= (haptic->pdata->mode_ctrl << 3) |
(haptic->pdata->overdrive_high << 5) |
- (haptic->pdata->overdrive_en << 5) |
+ (haptic->pdata->overdrive_en << 6) |
(haptic->pdata->chip_en << 7);
rc = isa1200_write_reg(client, ISA1200_HCTRL0, value);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 2fe9c72..aad7fb3 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -71,6 +71,9 @@
#define RPMB_SERVICE 0x2000
+#define QSEECOM_SEND_CMD_CRYPTO_TIMEOUT 2000
+#define QSEECOM_LOAD_APP_CRYPTO_TIMEOUT 2000
+
enum qseecom_clk_definitions {
CLK_DFAB = 0,
CLK_SFPB,
@@ -162,6 +165,12 @@
struct qseecom_clk qsee;
struct qseecom_clk ce_drv;
struct cdev cdev;
+
+ bool support_bus_scaling;
+ uint32_t cumulative_mode;
+ enum qseecom_bandwidth_request_mode current_mode;
+ struct timer_list bw_scale_down_timer;
+ struct work_struct bw_inactive_req_ws;
};
struct qseecom_client_handle {
@@ -191,6 +200,7 @@
atomic_t ioctl_count;
bool perf_enabled;
bool fast_load_enabled;
+ enum qseecom_bandwidth_request_mode mode;
};
enum qseecom_set_clear_key_flag {
@@ -328,6 +338,7 @@
return -EFAULT;
data->listener.id = 0;
+ data->type = QSEECOM_LISTENER_SERVICE;
if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
pr_err("Service is not unique and is already registered\n");
data->released = true;
@@ -437,6 +448,157 @@
return ret;
}
+static int __qseecom_set_msm_bus_request(uint32_t mode)
+{
+ int ret = 0;
+ struct qseecom_clk *qclk;
+
+ qclk = &qseecom.qsee;
+ if (qclk->ce_core_src_clk != NULL) {
+ if (mode == INACTIVE) {
+ __qseecom_disable_clk(CLK_QSEE);
+ } else {
+ ret = __qseecom_enable_clk(CLK_QSEE);
+ if (ret)
+ pr_err("CLK enabling failed (%d) MODE (%d)\n",
+ ret, mode);
+ }
+ }
+
+ if ((!ret) && (qseecom.current_mode != mode)) {
+ ret = msm_bus_scale_client_update_request(
+ qseecom.qsee_perf_client, mode);
+ if (ret) {
+ pr_err("Bandwidth req failed(%d) MODE (%d)\n",
+ ret, mode);
+ if (qclk->ce_core_src_clk != NULL) {
+ if (mode == INACTIVE)
+ __qseecom_enable_clk(CLK_QSEE);
+ else
+ __qseecom_disable_clk(CLK_QSEE);
+ }
+ }
+ qseecom.current_mode = mode;
+ }
+ return ret;
+}
+
+static void qseecom_bw_inactive_req_work(struct work_struct *work)
+{
+ mutex_lock(&app_access_lock);
+ mutex_lock(&qsee_bw_mutex);
+ __qseecom_set_msm_bus_request(INACTIVE);
+ pr_debug("current_mode = %d, cumulative_mode = %d\n",
+ qseecom.current_mode, qseecom.cumulative_mode);
+ mutex_unlock(&qsee_bw_mutex);
+ mutex_unlock(&app_access_lock);
+ return;
+}
+
+static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
+{
+ schedule_work(&qseecom.bw_inactive_req_ws);
+ return;
+}
+
+static int qseecom_scale_bus_bandwidth_timer(uint32_t mode, uint32_t duration)
+{
+ int32_t ret = 0;
+ int32_t request_mode = INACTIVE;
+
+ mutex_lock(&qsee_bw_mutex);
+ if (mode == 0) {
+ if (qseecom.cumulative_mode > MEDIUM)
+ request_mode = HIGH;
+ else
+ request_mode = qseecom.cumulative_mode;
+ } else {
+ request_mode = mode;
+ }
+ __qseecom_set_msm_bus_request(request_mode);
+
+ del_timer_sync(&(qseecom.bw_scale_down_timer));
+ qseecom.bw_scale_down_timer.expires = jiffies +
+ msecs_to_jiffies(duration);
+ add_timer(&(qseecom.bw_scale_down_timer));
+
+ mutex_unlock(&qsee_bw_mutex);
+ return ret;
+}
+
+
+static int qseecom_unregister_bus_bandwidth_needs(
+ struct qseecom_dev_handle *data)
+{
+ int32_t ret = 0;
+
+ qseecom.cumulative_mode -= data->mode;
+ data->mode = INACTIVE;
+
+ return ret;
+}
+
+static int __qseecom_register_bus_bandwidth_needs(
+ struct qseecom_dev_handle *data, uint32_t request_mode)
+{
+ int32_t ret = 0;
+
+ if (data->mode == INACTIVE) {
+ qseecom.cumulative_mode += request_mode;
+ data->mode = request_mode;
+ } else {
+ if (data->mode != request_mode) {
+ qseecom.cumulative_mode -= data->mode;
+ qseecom.cumulative_mode += request_mode;
+ data->mode = request_mode;
+ }
+ }
+ return ret;
+}
+
+static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
+ void __user *argp)
+{
+ int32_t ret = 0;
+ int32_t req_mode;
+
+ ret = copy_from_user(&req_mode, argp, sizeof(req_mode));
+ if (ret) {
+ pr_err("copy_from_user failed\n");
+ return ret;
+ }
+ if (req_mode > HIGH) {
+ pr_err("Invalid bandwidth mode (%d)\n", req_mode);
+ return ret;
+ }
+ mutex_lock(&qsee_bw_mutex);
+ ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
+ mutex_unlock(&qsee_bw_mutex);
+
+ return ret;
+}
+
+static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
+{
+ if (!qseecom.support_bus_scaling)
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ return;
+}
+
+static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
+{
+ int ret = 0;
+ if (qseecom.support_bus_scaling) {
+ qseecom_scale_bus_bandwidth_timer(
+ MEDIUM, QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
+ } else {
+ ret = qsee_vote_for_clock(data, CLK_SFPB);
+ if (ret)
+ pr_err("Fail vote for clk SFPB ret %d\n", ret);
+ }
+ return ret;
+}
+
static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
void __user *argp)
{
@@ -626,7 +788,7 @@
u32 app_id = 0;
struct ion_handle *ihandle; /* Ion handle */
struct qseecom_load_img_req load_img_req;
- int32_t ret;
+ int32_t ret = 0;
ion_phys_addr_t pa = 0;
uint32_t len;
struct qseecom_command_scm_resp resp;
@@ -641,16 +803,16 @@
return -EFAULT;
}
/* Vote for the SFPB clock */
- ret = qsee_vote_for_clock(data, CLK_SFPB);
+ ret = __qseecom_enable_clk_scale_up(data);
if (ret)
- pr_warning("Unable to vote for SFPB clock");
+ return ret;
req.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
load_img_req.img_name[MAX_APP_NAME_SIZE-1] = '\0';
memcpy(req.app_name, load_img_req.img_name, MAX_APP_NAME_SIZE);
ret = __qseecom_check_app_exists(req);
if (ret < 0) {
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return ret;
}
@@ -676,7 +838,7 @@
load_img_req.ifd_data_fd);
if (IS_ERR_OR_NULL(ihandle)) {
pr_err("Ion client could not retrieve the handle\n");
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return -ENOMEM;
}
@@ -701,7 +863,7 @@
pr_err("scm_call to load app failed\n");
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return -EINVAL;
}
@@ -709,7 +871,7 @@
pr_err("scm_call rsp.result is QSEOS_RESULT_FAILURE\n");
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return -EFAULT;
}
@@ -720,7 +882,7 @@
ret);
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return ret;
}
}
@@ -730,7 +892,7 @@
resp.result);
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return -EFAULT;
}
@@ -739,7 +901,7 @@
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
pr_err("kmalloc failed\n");
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return -ENOMEM;
}
entry->app_id = app_id;
@@ -762,10 +924,10 @@
if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
pr_err("copy_to_user failed\n");
kzfree(entry);
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return -EFAULT;
}
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return 0;
}
@@ -953,6 +1115,8 @@
return -EINVAL;
}
+ data->type = QSEECOM_SECURE_SERVICE;
+
switch (req.cmd_id) {
case QSEOS_RPMB_PROVISION_KEY_COMMAND:
case QSEOS_RPMB_ERASE_COMMAND:
@@ -965,15 +1129,25 @@
return -EINVAL;
}
- ret = qsee_vote_for_clock(data, CLK_DFAB);
- if (ret) {
- pr_err("Failed to vote for DFAB clock%d\n", ret);
- return ret;
- }
- ret = qsee_vote_for_clock(data, CLK_SFPB);
- if (ret) {
- pr_err("Failed to vote for SFPB clock%d\n", ret);
- goto exit_reset_dfab_freq;
+ if (qseecom.support_bus_scaling) {
+ qseecom_scale_bus_bandwidth_timer(HIGH,
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (ret) {
+ pr_err("Fail to set bw HIGH%d\n", ret);
+ return ret;
+ }
+ } else {
+ ret = qsee_vote_for_clock(data, CLK_DFAB);
+ if (ret) {
+ pr_err("Failed to vote for DFAB clock%d\n", ret);
+ return ret;
+ }
+ ret = qsee_vote_for_clock(data, CLK_SFPB);
+ if (ret) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ pr_err("Failed to vote for SFPB clock%d\n", ret);
+ goto exit;
+ }
}
msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
@@ -987,7 +1161,11 @@
ION_IOC_INV_CACHES);
if (ret) {
pr_err("qseecom_scm_call failed with err: %d\n", ret);
- goto exit_reset_sdfab_freq;
+ if (!qseecom.support_bus_scaling) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
+ goto exit;
}
switch (resp.result) {
@@ -1010,10 +1188,7 @@
ret = -EINVAL;
break;
}
-exit_reset_sdfab_freq:
- qsee_disable_clock_vote(data, CLK_SFPB);
-exit_reset_dfab_freq:
- qsee_disable_clock_vote(data, CLK_DFAB);
+exit:
return ret;
}
@@ -1484,10 +1659,9 @@
/* Populate the remaining parameters */
load_req.qsee_cmd_id = QSEOS_APP_START_COMMAND;
memcpy(load_req.app_name, appname, MAX_APP_NAME_SIZE);
- ret = qsee_vote_for_clock(data, CLK_SFPB);
+ ret = __qseecom_enable_clk_scale_up(data);
if (ret) {
kzfree(img_data);
- pr_warning("Unable to vote for SFPB clock");
return -EIO;
}
@@ -1499,7 +1673,7 @@
kzfree(img_data);
if (ret) {
pr_err("scm_call to load failed : ret %d\n", ret);
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return -EIO;
}
@@ -1522,7 +1696,7 @@
ret = -EINVAL;
break;
}
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return ret;
}
@@ -1551,9 +1725,8 @@
/* Populate the remaining parameters */
load_req.qsee_cmd_id = QSEOS_LOAD_SERV_IMAGE_COMMAND;
/* Vote for the SFPB clock */
- ret = qsee_vote_for_clock(data, CLK_SFPB);
+ ret = __qseecom_enable_clk_scale_up(data);
if (ret) {
- pr_err("Unable to vote for SFPB clock: ret = %d", ret);
kzfree(img_data);
return -EIO;
}
@@ -1589,7 +1762,7 @@
}
}
kzfree(img_data);
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
return ret;
}
@@ -1799,10 +1972,24 @@
pr_err("Unable to find the handle, exiting\n");
else
ret = qseecom_unload_app(data);
- if (data->fast_load_enabled == true)
- qsee_disable_clock_vote(data, CLK_SFPB);
- if (data->perf_enabled == true)
- qsee_disable_clock_vote(data, CLK_DFAB);
+
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ if (data->mode != INACTIVE) {
+ qseecom_unregister_bus_bandwidth_needs(data);
+ if (qseecom.cumulative_mode == INACTIVE) {
+ ret = __qseecom_set_msm_bus_request(INACTIVE);
+ if (ret)
+ pr_err("Fail to scale down bus\n");
+ }
+ }
+ mutex_unlock(&qsee_bw_mutex);
+ } else {
+ if (data->fast_load_enabled == true)
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ if (data->perf_enabled == true)
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ }
if (ret == 0) {
kzfree(data);
kzfree(*handle);
@@ -1833,7 +2020,9 @@
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
-
+ if (qseecom.support_bus_scaling)
+ qseecom_scale_bus_bandwidth_timer(INACTIVE,
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
ret = __qseecom_send_cmd(data, &req);
atomic_dec(&data->ioctl_count);
@@ -1856,17 +2045,30 @@
return -EINVAL;
}
if (high) {
- ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
- if (ret)
- pr_err("Failed to vote for DFAB clock%d\n", ret);
- ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
- if (ret) {
- pr_err("Failed to vote for SFPB clock%d\n", ret);
- qsee_disable_clock_vote(handle->dev, CLK_DFAB);
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ __qseecom_register_bus_bandwidth_needs(handle->dev,
+ HIGH);
+ mutex_unlock(&qsee_bw_mutex);
+ if (ret)
+ pr_err("Failed to scale bus (med) %d\n", ret);
+ } else {
+ ret = qsee_vote_for_clock(handle->dev, CLK_DFAB);
+ if (ret)
+ pr_err("Failed to vote for DFAB clock%d\n",
+ ret);
+ ret = qsee_vote_for_clock(handle->dev, CLK_SFPB);
+ if (ret) {
+ pr_err("Failed to vote for SFPB clock%d\n",
+ ret);
+ qsee_disable_clock_vote(handle->dev, CLK_DFAB);
+ }
}
} else {
- qsee_disable_clock_vote(handle->dev, CLK_DFAB);
- qsee_disable_clock_vote(handle->dev, CLK_SFPB);
+ if (!qseecom.support_bus_scaling) {
+ qsee_disable_clock_vote(handle->dev, CLK_DFAB);
+ qsee_disable_clock_vote(handle->dev, CLK_SFPB);
+ }
}
return ret;
}
@@ -2231,9 +2433,8 @@
}
/* Vote for the SFPB clock */
- ret = qsee_vote_for_clock(data, CLK_SFPB);
+ ret = __qseecom_enable_clk_scale_up(data);
if (ret) {
- pr_err("Unable to vote for SFPB clock: ret = %d", ret);
ret = -EIO;
goto exit_cpu_restore;
}
@@ -2271,7 +2472,7 @@
}
exit_disable_clock:
- qsee_disable_clock_vote(data, CLK_SFPB);
+ __qseecom_disable_clk_scale_down(data);
exit_cpu_restore:
/* Restore the CPU mask */
mask = CPU_MASK_ALL;
@@ -2914,6 +3115,7 @@
break;
}
case QSEECOM_IOCTL_SEND_CMD_REQ: {
+ pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
if ((data->client.app_id == 0) ||
(data->type != QSEECOM_CLIENT_APP)) {
pr_err("send cmd req: invalid handle (%d) app_id(%d)\n",
@@ -2923,6 +3125,9 @@
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
+ if (qseecom.support_bus_scaling)
+ qseecom_scale_bus_bandwidth_timer(INACTIVE,
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
atomic_inc(&data->ioctl_count);
ret = qseecom_send_cmd(data, argp);
atomic_dec(&data->ioctl_count);
@@ -2933,6 +3138,7 @@
break;
}
case QSEECOM_IOCTL_SEND_MODFD_CMD_REQ: {
+ pr_debug("qseecom.current_mode %d\n", qseecom.current_mode);
if ((data->client.app_id == 0) ||
(data->type != QSEECOM_CLIENT_APP)) {
pr_err("send mdfd cmd: invalid handle (%d) appid(%d)\n",
@@ -2942,6 +3148,9 @@
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
+ if (qseecom.support_bus_scaling)
+ qseecom_scale_bus_bandwidth_timer(INACTIVE,
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
atomic_inc(&data->ioctl_count);
ret = qseecom_send_modfd_cmd(data, argp);
atomic_dec(&data->ioctl_count);
@@ -3068,12 +3277,18 @@
break;
}
atomic_inc(&data->ioctl_count);
- ret = qsee_vote_for_clock(data, CLK_DFAB);
- if (ret)
- pr_err("Failed to vote for DFAB clock%d\n", ret);
- ret = qsee_vote_for_clock(data, CLK_SFPB);
- if (ret)
- pr_err("Failed to vote for SFPB clock%d\n", ret);
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ __qseecom_register_bus_bandwidth_needs(data, HIGH);
+ mutex_unlock(&qsee_bw_mutex);
+ } else {
+ ret = qsee_vote_for_clock(data, CLK_DFAB);
+ if (ret)
+ pr_err("Fail to vote for DFAB clock%d\n", ret);
+ ret = qsee_vote_for_clock(data, CLK_SFPB);
+ if (ret)
+ pr_err("Fail to vote for SFPB clock%d\n", ret);
+ }
atomic_dec(&data->ioctl_count);
break;
}
@@ -3093,8 +3308,24 @@
break;
}
atomic_inc(&data->ioctl_count);
+ if (!qseecom.support_bus_scaling) {
qsee_disable_clock_vote(data, CLK_DFAB);
qsee_disable_clock_vote(data, CLK_SFPB);
+ }
+ atomic_dec(&data->ioctl_count);
+ break;
+ }
+
+ case QSEECOM_IOCTL_SET_BUS_SCALING_REQ: {
+ if ((data->client.app_id == 0) ||
+ (data->type != QSEECOM_CLIENT_APP)) {
+ pr_err("set bus scale: invalid handle (%d) appid(%d)\n",
+ data->type, data->client.app_id);
+ ret = -EINVAL;
+ break;
+ }
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_scale_bus_bandwidth(data, argp);
atomic_dec(&data->ioctl_count);
break;
}
@@ -3292,6 +3523,7 @@
data->abort = 0;
data->type = QSEECOM_GENERIC;
data->released = false;
+ data->mode = INACTIVE;
init_waitqueue_head(&data->abort_wq);
atomic_set(&data->ioctl_count, 0);
@@ -3304,8 +3536,8 @@
int ret = 0;
if (data->released == false) {
- pr_warn("data: released = false, type = %d, data = 0x%x\n",
- data->type, (u32)data);
+ pr_warn("data: released=false, type=%d, mode=%d, data=0x%x\n",
+ data->type, data->mode, (u32)data);
switch (data->type) {
case QSEECOM_LISTENER_SERVICE:
ret = qseecom_unregister_listener(data);
@@ -3328,11 +3560,23 @@
}
}
- if (data->fast_load_enabled == true)
- qsee_disable_clock_vote(data, CLK_SFPB);
- if (data->perf_enabled == true)
- qsee_disable_clock_vote(data, CLK_DFAB);
-
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ if (data->mode != INACTIVE) {
+ qseecom_unregister_bus_bandwidth_needs(data);
+ if (qseecom.cumulative_mode == INACTIVE) {
+ ret = __qseecom_set_msm_bus_request(INACTIVE);
+ if (ret)
+ pr_err("Fail to scale down bus\n");
+ }
+ }
+ mutex_unlock(&qsee_bw_mutex);
+ } else {
+ if (data->fast_load_enabled == true)
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ if (data->perf_enabled == true)
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ }
kfree(data);
return ret;
@@ -3475,6 +3719,10 @@
qseecom.qsee.ce_core_src_clk = NULL;
qseecom.qsee.ce_bus_clk = NULL;
+ qseecom.cumulative_mode = 0;
+ qseecom.current_mode = INACTIVE;
+ qseecom.support_bus_scaling = false;
+
qseecom.ce_drv.ce_core_clk = NULL;
qseecom.ce_drv.ce_clk = NULL;
qseecom.ce_drv.ce_core_src_clk = NULL;
@@ -3554,7 +3802,11 @@
/* register client for bus scaling */
if (pdev->dev.of_node) {
-
+ qseecom.support_bus_scaling =
+ of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,support-bus-scaling");
+ pr_warn("support_bus_scaling=0x%x",
+ qseecom.support_bus_scaling);
if (of_property_read_u32((&pdev->dev)->of_node,
"qcom,disk-encrypt-pipe-pair",
&qseecom.ce_info.disk_encrypt_pipe)) {
@@ -3647,7 +3899,13 @@
qseecom_platform_support = (struct msm_bus_scale_pdata *)
pdev->dev.platform_data;
}
-
+ if (qseecom.support_bus_scaling) {
+ init_timer(&(qseecom.bw_scale_down_timer));
+ INIT_WORK(&qseecom.bw_inactive_req_ws,
+ qseecom_bw_inactive_req_work);
+ qseecom.bw_scale_down_timer.function =
+ qseecom_scale_bus_bandwidth_timer_callback;
+ }
qseecom.qsee_perf_client = msm_bus_scale_register_client(
qseecom_platform_support);
@@ -3713,6 +3971,11 @@
if (pdev->dev.platform_data != NULL)
msm_bus_scale_unregister_client(qseecom.qsee_perf_client);
+ if (qseecom.support_bus_scaling) {
+ cancel_work_sync(&qseecom.bw_inactive_req_ws);
+ del_timer_sync(&qseecom.bw_scale_down_timer);
+ }
+
/* register client for bus scaling */
if (pdev->dev.of_node) {
__qseecom_deinit_clk(CLK_QSEE);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index a29fb751..9985c71 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -20,6 +20,7 @@
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/types.h>
+#include <linux/msm_hdmi.h>
#include <mach/msm_hdmi_audio_codec.h>
#define REG_DUMP 0
@@ -222,6 +223,77 @@
{20480, 247500} } },
};
+int register_hdmi_cable_notification(struct hdmi_cable_notify *handler)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+ struct list_head *pos;
+
+ if (!hdmi_tx_hw.ptr) {
+ DEV_WARN("%s: HDMI Tx core not ready\n", __func__);
+ return -EPROBE_DEFER;
+ }
+
+ if (!handler) {
+ DEV_ERR("%s: Empty handler\n", __func__);
+ return -ENODEV;
+ }
+
+ hdmi_ctrl = (struct hdmi_tx_ctrl *) hdmi_tx_hw.ptr;
+
+ mutex_lock(&hdmi_ctrl->cable_notify_mutex);
+ handler->status = hdmi_ctrl->hpd_state;
+ list_for_each(pos, &hdmi_ctrl->cable_notify_handlers);
+ list_add_tail(&handler->link, pos);
+ mutex_unlock(&hdmi_ctrl->cable_notify_mutex);
+
+ return handler->status;
+} /* register_hdmi_cable_notification */
+
+int unregister_hdmi_cable_notification(struct hdmi_cable_notify *handler)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+
+ if (!hdmi_tx_hw.ptr) {
+ DEV_WARN("%s: HDMI Tx core not ready\n", __func__);
+ return -ENODEV;
+ }
+
+ if (!handler) {
+ DEV_ERR("%s: Empty handler\n", __func__);
+ return -ENODEV;
+ }
+
+ hdmi_ctrl = (struct hdmi_tx_ctrl *) hdmi_tx_hw.ptr;
+
+ mutex_lock(&hdmi_ctrl->cable_notify_mutex);
+ list_del(&handler->link);
+ mutex_unlock(&hdmi_ctrl->cable_notify_mutex);
+
+ return 0;
+} /* unregister_hdmi_cable_notification */
+
+static void hdmi_tx_cable_notify_work(struct work_struct *work)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+ struct hdmi_cable_notify *pos;
+
+ hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, cable_notify_work);
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid hdmi data\n", __func__);
+ return;
+ }
+
+ mutex_lock(&hdmi_ctrl->cable_notify_mutex);
+ list_for_each_entry(pos, &hdmi_ctrl->cable_notify_handlers, link) {
+ if (pos->status != hdmi_ctrl->hpd_state) {
+ pos->status = hdmi_ctrl->hpd_state;
+ pos->hpd_notify(pos);
+ }
+ }
+ mutex_unlock(&hdmi_ctrl->cable_notify_mutex);
+} /* hdmi_tx_cable_notify_work */
+
static bool hdmi_tx_is_cea_format(int mode)
{
bool cea_fmt;
@@ -327,6 +399,9 @@
if (!hdmi_ctrl->pdata.primary && (hdmi_ctrl->sdev.state != val))
switch_set_state(&hdmi_ctrl->sdev, val);
+
+ /* Notify all registered modules of cable connection status */
+ schedule_work(&hdmi_ctrl->cable_notify_work);
} /* hdmi_tx_send_cable_notification */
static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -2835,6 +2910,7 @@
if (hdmi_ctrl->workq)
destroy_workqueue(hdmi_ctrl->workq);
mutex_destroy(&hdmi_ctrl->lut_lock);
+ mutex_destroy(&hdmi_ctrl->cable_notify_mutex);
mutex_destroy(&hdmi_ctrl->mutex);
hdmi_tx_hw.ptr = NULL;
@@ -2864,6 +2940,10 @@
hdmi_setup_video_mode_lut();
mutex_init(&hdmi_ctrl->mutex);
mutex_init(&hdmi_ctrl->lut_lock);
+ mutex_init(&hdmi_ctrl->cable_notify_mutex);
+
+ INIT_LIST_HEAD(&hdmi_ctrl->cable_notify_handlers);
+
hdmi_ctrl->workq = create_workqueue("hdmi_tx_workq");
if (!hdmi_ctrl->workq) {
DEV_ERR("%s: hdmi_tx_workq creation failed.\n", __func__);
@@ -2881,8 +2961,9 @@
hdmi_ctrl->hpd_initialized = false;
hdmi_ctrl->hpd_off_pending = false;
init_completion(&hdmi_ctrl->hpd_done);
- INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
+ INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
+ INIT_WORK(&hdmi_ctrl->cable_notify_work, hdmi_tx_cable_notify_work);
INIT_WORK(&hdmi_ctrl->power_off_work, hdmi_tx_power_off_work);
spin_lock_init(&hdmi_ctrl->hpd_state_lock);
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index 0787dee..8233ba8 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2014, The 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
@@ -55,6 +55,8 @@
struct mutex mutex;
struct mutex lut_lock;
+ struct mutex cable_notify_mutex;
+ struct list_head cable_notify_handlers;
struct kobject *kobj;
struct switch_dev sdev;
struct switch_dev audio_sdev;
@@ -78,6 +80,7 @@
struct work_struct hpd_int_work;
struct work_struct power_off_work;
+ struct work_struct cable_notify_work;
bool hdcp_feature_on;
u32 present_hdcp;
diff --git a/include/linux/msm_hdmi.h b/include/linux/msm_hdmi.h
new file mode 100644
index 0000000..70fae94
--- /dev/null
+++ b/include/linux/msm_hdmi.h
@@ -0,0 +1,57 @@
+/* include/linux/msm_hdmi.h
+ *
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#ifndef _MSM_HDMI_H_
+#define _MSM_HDMI_H_
+
+/*
+ * HDMI cable notify handler sturcture.
+ * link A link for the linked list
+ * status Current status of HDMI cable connection
+ * hpd_notify Callback function to provide cable status
+ */
+struct hdmi_cable_notify {
+ struct list_head link;
+ int status;
+ void (*hpd_notify) (struct hdmi_cable_notify *h);
+};
+
+#ifdef CONFIG_FB_MSM_MDSS_HDMI_PANEL
+/*
+ * Register for HDMI cable connect or disconnect notification.
+ * @param handler callback handler for notification
+ * @return negative value as error otherwise current status of cable
+ */
+int register_hdmi_cable_notification(
+ struct hdmi_cable_notify *handler);
+
+/*
+ * Un-register for HDMI cable connect or disconnect notification.
+ * @param handler callback handler for notification
+ * @return negative value as error
+ */
+int unregister_hdmi_cable_notification(
+ struct hdmi_cable_notify *handler);
+#else
+int register_hdmi_cable_notification(
+ struct hdmi_cable_notify *handler) {
+ return 0;
+}
+
+int unregister_hdmi_cable_notification(
+ struct hdmi_cable_notify *handler) {
+ return 0;
+}
+#endif /* CONFIG_FB_MSM_MDSS_HDMI_PANEL */
+
+#endif /*_MSM_HDMI_H_*/
diff --git a/include/linux/qrng.h b/include/linux/qrng.h
index 35708e3..8c09627 100644
--- a/include/linux/qrng.h
+++ b/include/linux/qrng.h
@@ -1,5 +1,5 @@
-#ifndef __QRNG_H_
-#define __QRNG_H_
+#ifndef _QRNG_H_
+#define _QRNG_H_
#include <linux/types.h>
#include <linux/ioctl.h>
@@ -9,4 +9,4 @@
#define QRNG_IOCTL_RESET_BUS_BANDWIDTH\
_IO(QRNG_IOC_MAGIC, 1)
-#endif /* __QRNG_H_ */
+#endif /* _QRNG_H_ */