Merge "msm: mdss: Fix Iommu page fault for splash logo enabled feature"
diff --git a/arch/arm/boot/dts/msm8226-mdss.dtsi b/arch/arm/boot/dts/msm8226-mdss.dtsi
index cedec5f..ff6fee4 100644
--- a/arch/arm/boot/dts/msm8226-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8226-mdss.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 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
@@ -96,8 +96,6 @@
mdss_fb0: qcom,mdss_fb_primary {
cell-index = <0>;
compatible = "qcom,mdss-fb";
- qcom,memory-reservation-type = "EBI1";
- qcom,memory-reservation-size = <0x800000>;
qcom,memblock-reserve = <0x03200000 0xFA0000>;
};
@@ -126,9 +124,9 @@
qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
qcom,platform-regulator-settings = [07 09 03 00 20 00 01];
qcom,platform-lane-config = [00 00 00 00 00 00 00 01 97
- 00 00 00 00 05 00 00 01 97
- 00 00 00 00 0a 00 00 01 97
- 00 00 00 00 0f 00 00 01 97
+ 00 00 00 00 00 00 00 01 97
+ 00 00 00 00 00 00 00 01 97
+ 00 00 00 00 00 00 00 01 97
00 c0 00 00 00 00 00 01 bb];
qcom,platform-supply-entry1 {
qcom,supply-name = "vdd";
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
index a22355a..44b7f13 100644
--- a/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-liquid.dtsi
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015, 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
@@ -68,7 +68,7 @@
reg = <0x0>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,mount-angle = <90>;
+ qcom,mount-angle = <0>;
qcom,actuator-src = <&actuator0>;
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
@@ -134,30 +134,25 @@
reg = <0x02>;
qcom,csiphy-sd-index = <2>;
qcom,csid-sd-index = <2>;
- qcom,mount-angle = <90>;
+ qcom,mount-angle = <180>;
cam_vdig-supply = <&pm8941_l3>;
cam_vana-supply = <&pm8941_l17>;
- cam_vio-supply = <&pm8941_lvs3>;
- cam_vaf-supply = <&pm8941_l23>;
- qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
- "cam_vaf";
- qcom,cam-vreg-type = <0 1 0 0>;
- qcom,cam-vreg-min-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
- qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ cam_vio-supply = <&pm8941_lvs2>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+ qcom,cam-vreg-type = <0 0 1>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-op-mode = <105000 80000 0>;
qcom,gpio-no-mux = <0>;
gpios = <&msmgpio 17 0>,
- <&msmgpio 18 0>,
- <&msmgpio 28 0>;
+ <&msmgpio 18 0>;
qcom,gpio-reset = <1>;
- qcom,gpio-standby = <2>;
- qcom,gpio-req-tbl-num = <0 1 2>;
- qcom,gpio-req-tbl-flags = <1 0 0>;
- qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
- "CAM_RESET2",
- "CAM_STANDBY2";
+ qcom,gpio-req-tbl-num = <0 1 >;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1";
qcom,sensor-position = <1>;
- qcom,sensor-mode = <0>;
+ qcom,sensor-mode = <1>;
qcom,cci-master = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8974-mdss.dtsi b/arch/arm/boot/dts/msm8974-mdss.dtsi
index 3fef47a..db8a55e 100644
--- a/arch/arm/boot/dts/msm8974-mdss.dtsi
+++ b/arch/arm/boot/dts/msm8974-mdss.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 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
@@ -103,8 +103,6 @@
mdss_fb0: qcom,mdss_fb_primary {
cell-index = <0>;
compatible = "qcom,mdss-fb";
- qcom,memory-reservation-type = "EBI1";
- qcom,memory-reservation-size = <0x800000>;
qcom,memblock-reserve = <0x03200000 0x01E00000>;
};
@@ -139,9 +137,9 @@
qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
qcom,platform-regulator-settings = [07 09 03 00 20 00 01];
qcom,platform-lane-config = [00 00 00 00 00 00 00 01 97
- 00 00 00 00 05 00 00 01 97
- 00 00 00 00 0a 00 00 01 97
- 00 00 00 00 0f 00 00 01 97
+ 00 00 00 00 00 00 00 01 97
+ 00 00 00 00 00 00 00 01 97
+ 00 00 00 00 00 00 00 01 97
00 c0 00 00 00 00 00 01 bb];
qcom,platform-supply-entry1 {
qcom,supply-name = "vdd";
@@ -195,9 +193,9 @@
qcom,platform-bist-ctrl = [00 00 b1 ff 00 00];
qcom,platform-regulator-settings = [07 09 03 00 20 00 01];
qcom,platform-lane-config = [00 00 00 00 00 00 00 01 97
- 00 00 00 00 05 00 00 01 97
- 00 00 00 00 0a 00 00 01 97
- 00 00 00 00 0f 00 00 01 97
+ 00 00 00 00 00 00 00 01 97
+ 00 00 00 00 00 00 00 01 97
+ 00 00 00 00 00 00 00 01 97
00 c0 00 00 00 00 00 01 bb];
qcom,platform-supply-entry1 {
qcom,supply-name = "vdd";
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 4dd8e5f..a2f3c34 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -167,7 +167,7 @@
}
static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev,
- uint32_t buff_mgr_ops);
+ uint32_t buff_mgr_ops, uint8_t put_buf);
static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin);
static void cpp_timer_callback(unsigned long data);
@@ -634,20 +634,22 @@
if (tx_fifo[i] == MSM_CPP_MSG_ID_CMD) {
cmd_len = tx_fifo[i+1];
msg_id = tx_fifo[i+2];
- if (msg_id == MSM_CPP_MSG_ID_FRAME_ACK) {
+ if ((msg_id == MSM_CPP_MSG_ID_FRAME_ACK)
+ && (atomic_read(&cpp_timer.used))) {
CPP_DBG("Frame done!!\n");
/* delete CPP timer */
CPP_DBG("delete timer.\n");
msm_cpp_clear_timer(cpp_dev);
msm_cpp_notify_frame_done(cpp_dev,
- VIDIOC_MSM_BUF_MNGR_BUF_DONE);
- } else if (msg_id ==
- MSM_CPP_MSG_ID_FRAME_NACK) {
+ VIDIOC_MSM_BUF_MNGR_BUF_DONE, 0);
+ } else if ((msg_id ==
+ MSM_CPP_MSG_ID_FRAME_NACK)
+ && (atomic_read(&cpp_timer.used))) {
pr_err("NACK error from hw!!\n");
CPP_DBG("delete timer.\n");
msm_cpp_clear_timer(cpp_dev);
msm_cpp_notify_frame_done(cpp_dev,
- VIDIOC_MSM_BUF_MNGR_PUT_BUF);
+ VIDIOC_MSM_BUF_MNGR_PUT_BUF, 0);
}
i += cmd_len + 2;
}
@@ -1075,7 +1077,7 @@
}
static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev,
- uint32_t buff_mgr_ops)
+ uint32_t buff_mgr_ops, uint8_t put_buf)
{
struct v4l2_event v4l2_evt;
struct msm_queue_cmd *frame_qcmd = NULL;
@@ -1110,12 +1112,22 @@
buff_mgr_info.timestamp = processed_frame->timestamp;
buff_mgr_info.index =
processed_frame->output_buffer_info[0].index;
- rc = msm_cpp_buffer_ops(cpp_dev,
- buff_mgr_ops,
- &buff_mgr_info);
- if (rc < 0) {
- pr_err("error putting buffer\n");
- rc = -EINVAL;
+ if (put_buf) {
+ rc = msm_cpp_buffer_ops(cpp_dev,
+ buff_mgr_ops,
+ &buff_mgr_info);
+ if (rc < 0) {
+ pr_err("error putting buffer\n");
+ rc = -EINVAL;
+ }
+ } else {
+ rc = msm_cpp_buffer_ops(cpp_dev,
+ buff_mgr_ops,
+ &buff_mgr_info);
+ if (rc < 0) {
+ pr_err("error putting buffer\n");
+ rc = -EINVAL;
+ }
}
}
@@ -1132,12 +1144,22 @@
buff_mgr_info.timestamp = processed_frame->timestamp;
buff_mgr_info.index =
processed_frame->output_buffer_info[1].index;
- rc = msm_cpp_buffer_ops(cpp_dev,
- buff_mgr_ops,
- &buff_mgr_info);
- if (rc < 0) {
- pr_err("error putting buffer\n");
- rc = -EINVAL;
+ if (put_buf) {
+ rc = msm_cpp_buffer_ops(cpp_dev,
+ buff_mgr_ops,
+ &buff_mgr_info);
+ if (rc < 0) {
+ pr_err("error putting buffer\n");
+ rc = -EINVAL;
+ }
+ } else {
+ rc = msm_cpp_buffer_ops(cpp_dev,
+ buff_mgr_ops,
+ &buff_mgr_info);
+ if (rc < 0) {
+ pr_err("error putting buffer\n");
+ rc = -EINVAL;
+ }
}
}
v4l2_evt.id = processed_frame->inst_id;
@@ -1166,9 +1188,6 @@
static void msm_cpp_do_timeout_work(struct work_struct *work)
{
- int ret;
- uint32_t i = 0;
- struct msm_cpp_frame_info_t *this_frame = NULL;
pr_err("cpp_timer_callback called. (jiffies=%lu)\n",
jiffies);
@@ -1184,7 +1203,13 @@
disable_irq(cpp_timer.data.cpp_dev->irq->start);
pr_err("Reloading firmware\n");
- cpp_load_fw(cpp_timer.data.cpp_dev, NULL);
+ if (!atomic_read(&cpp_timer.used)) {
+ pr_err("Delayed trigger, IRQ serviced\n");
+ return;
+ }
+ atomic_set(&cpp_timer.used, 0);
+ cpp_load_fw(cpp_timer.data.cpp_dev,
+ cpp_timer.data.cpp_dev->fw_name_bin);
pr_err("Firmware loading done\n");
enable_irq(cpp_timer.data.cpp_dev->irq->start);
msm_camera_io_w_mb(0x8, cpp_timer.data.cpp_dev->base +
@@ -1192,39 +1217,16 @@
msm_camera_io_w_mb(0xFFFF,
cpp_timer.data.cpp_dev->base +
MSM_CPP_MICRO_IRQGEN_CLR);
-
- if (!atomic_read(&cpp_timer.used)) {
- pr_err("Delayed trigger, IRQ serviced\n");
- return;
- }
-
- if (cpp_timer.data.cpp_dev->timeout_trial_cnt >=
- MSM_CPP_MAX_TIMEOUT_TRIAL) {
- pr_info("Max trial reached\n");
- msm_cpp_notify_frame_done(cpp_timer.data.cpp_dev,
- VIDIOC_MSM_BUF_MNGR_PUT_BUF);
- cpp_timer.data.cpp_dev->timeout_trial_cnt = 0;
- return;
- }
-
- this_frame = cpp_timer.data.processed_frame;
- pr_err("Starting timer to fire in %d ms. (jiffies=%lu)\n",
- CPP_CMD_TIMEOUT_MS, jiffies);
- ret = mod_timer(&cpp_timer.cpp_timer,
- jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
- if (ret)
- pr_err("error in mod_timer\n");
-
- pr_err("Rescheduling for identity=0x%x, frame_id=%03d\n",
- this_frame->identity, this_frame->frame_id);
- msm_cpp_write(0x6, cpp_timer.data.cpp_dev->base);
- msm_cpp_dump_frame_cmd(this_frame->cpp_cmd_msg,
- this_frame->msg_len);
- for (i = 0; i < this_frame->msg_len; i++)
- msm_cpp_write(this_frame->cpp_cmd_msg[i],
- cpp_timer.data.cpp_dev->base);
- cpp_timer.data.cpp_dev->timeout_trial_cnt++;
- return;
+ mutex_lock(&cpp_timer.data.cpp_dev->mutex);
+ msm_cpp_dump_frame_cmd(cpp_timer.data.processed_frame->cpp_cmd_msg,
+ cpp_timer.data.processed_frame->msg_len);
+ msm_cpp_notify_frame_done(cpp_timer.data.cpp_dev,
+ VIDIOC_MSM_BUF_MNGR_PUT_BUF, 1);
+ atomic_set(&cpp_timer.used, 0);
+ cpp_timer.data.processed_frame = NULL;
+ cpp_timer.data.cpp_dev->timeout_trial_cnt = 0;
+ mutex_unlock(&cpp_timer.data.cpp_dev->mutex);
+ pr_info("exit\n");
}
void cpp_timer_callback(unsigned long data)
@@ -1536,8 +1538,8 @@
return -EINVAL;
}
- if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)){
- pr_err("ioctl_ptr OR ioctl_ptr->len is NULL %p %d \n",
+ if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) {
+ pr_err("ioctl_ptr OR ioctl_ptr->len is NULL %p %d\n",
ioctl_ptr, ioctl_ptr->len);
return -EINVAL;
}
@@ -1562,7 +1564,7 @@
cpp_dev->fw_name_bin = NULL;
}
if (ioctl_ptr->len >= MSM_CPP_MAX_FW_NAME_LEN) {
- pr_err("Error: ioctl_ptr->len = %d \n",
+ pr_err("Error: ioctl_ptr->len = %d\n",
ioctl_ptr->len);
mutex_unlock(&cpp_dev->mutex);
return -EINVAL;
@@ -1748,31 +1750,36 @@
struct msm_device_queue *queue = &cpp_dev->eventData_q;
struct msm_queue_cmd *event_qcmd;
struct msm_cpp_frame_info_t *process_frame;
+
+ CPP_DBG("VIDIOC_MSM_CPP_GET_EVENTPAYLOAD\n");
event_qcmd = msm_dequeue(queue, list_eventdata);
- if(event_qcmd) {
- process_frame = event_qcmd->command;
- CPP_DBG("fid %d\n", process_frame->frame_id);
- if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+ if (!event_qcmd) {
+ pr_err("no queue cmd available");
+ mutex_unlock(&cpp_dev->mutex);
+ return -EINVAL;
+ }
+ process_frame = event_qcmd->command;
+ CPP_DBG("fid %d\n", process_frame->frame_id);
+ if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
process_frame,
sizeof(struct msm_cpp_frame_info_t))) {
+ mutex_unlock(&cpp_dev->mutex);
kfree(process_frame->cpp_cmd_msg);
process_frame->cpp_cmd_msg = NULL;
kfree(process_frame);
process_frame = NULL;
kfree(event_qcmd);
event_qcmd = NULL;
- mutex_unlock(&cpp_dev->mutex);
return -EINVAL;
}
kfree(process_frame->cpp_cmd_msg);
+ process_frame->cpp_cmd_msg = NULL;
kfree(process_frame);
+ process_frame = NULL;
kfree(event_qcmd);
- } else {
- pr_err("Empty command list\n");
- return -EFAULT;
- }
- break;
+ event_qcmd = NULL;
+ break;
}
case VIDIOC_MSM_CPP_SET_CLOCK: {
struct msm_cpp_clock_settings_t clock_settings;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index af1af2d..3556879 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -79,7 +79,7 @@
#define MSM_CPP_START_ADDRESS 0x0
#define MSM_CPP_END_ADDRESS 0x3F00
-#define MSM_CPP_POLL_RETRIES 20
+#define MSM_CPP_POLL_RETRIES 200
#define MSM_CPP_TASKLETQ_SIZE 16
#define MSM_CPP_TX_FIFO_LEVEL 16
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index 4c0fa81..66f3fc9 100755
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -20,6 +20,7 @@
#include <mach/rpm-regulator-smd.h>
#include <linux/regulator/consumer.h>
+#define I2C_USER_REG_DATA_MAX 1024
/*#define CONFIG_MSMB_CAMERA_DEBUG*/
#undef CDBG
#ifdef CONFIG_MSMB_CAMERA_DEBUG
@@ -739,7 +740,7 @@
}
if ((!conf_array.size) ||
- (conf_array.size > I2C_SEQ_REG_DATA_MAX)) {
+ (conf_array.size > I2C_USER_REG_DATA_MAX )) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
@@ -914,7 +915,7 @@
}
if ((!conf_array.size) ||
- (conf_array.size > I2C_SEQ_REG_DATA_MAX)) {
+ (conf_array.size > I2C_USER_REG_DATA_MAX )) {
pr_err("%s:%d failed\n", __func__, __LINE__);
rc = -EFAULT;
break;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 8d198a6..38b4876 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -55,6 +55,7 @@
#define WCNSS_DISABLE_PC_LATENCY 100
#define WCNSS_ENABLE_PC_LATENCY PM_QOS_DEFAULT_VALUE
#define WCNSS_PM_QOS_TIMEOUT 15000
+#define WAIT_FOR_CBC_IND 2
/* module params */
#define WCNSS_CONFIG_UNSPECIFIED (-1)
@@ -215,6 +216,7 @@
#define WCNSS_BUILD_VER_REQ (WCNSS_CTRL_MSG_START + 9)
#define WCNSS_BUILD_VER_RSP (WCNSS_CTRL_MSG_START + 10)
#define WCNSS_PM_CONFIG_REQ (WCNSS_CTRL_MSG_START + 11)
+#define WCNSS_CBC_COMPLETE_IND (WCNSS_CTRL_MSG_START + 12)
/* max 20mhz channel count */
#define WCNSS_MAX_CH_NUM 45
@@ -407,6 +409,7 @@
void __iomem *alarms_tactl;
void __iomem *fiq_reg;
int nv_downloaded;
+ int is_cbc_done;
unsigned char *fw_cal_data;
unsigned char *user_cal_data;
int fw_cal_rcvd;
@@ -899,7 +902,6 @@
return 0;
pmu_conf_reg = penv->msm_wcnss_base + PRONTO_PMU_OFFSET;
- writel_relaxed(0, pmu_conf_reg);
reg = readl_relaxed(pmu_conf_reg);
reg |= WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP;
writel_relaxed(reg, pmu_conf_reg);
@@ -1075,6 +1077,7 @@
pr_debug("wcnss: closing WCNSS SMD channel :%s",
WCNSS_CTRL_CHANNEL);
penv->nv_downloaded = 0;
+ penv->is_cbc_done = 0;
break;
default:
@@ -1283,6 +1286,15 @@
}
EXPORT_SYMBOL(wcnss_device_ready);
+bool wcnss_cbc_complete(void)
+{
+ if (penv && penv->pdev && penv->is_cbc_done &&
+ !wcnss_device_is_shutdown())
+ return true;
+ return false;
+}
+EXPORT_SYMBOL(wcnss_cbc_complete);
+
int wcnss_device_is_shutdown(void)
{
if (penv && penv->is_shutdown)
@@ -1911,6 +1923,8 @@
fw_status = wcnss_fw_status();
pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
fw_status);
+ if (fw_status != WAIT_FOR_CBC_IND)
+ penv->is_cbc_done = 1;
wcnss_setup_vbat_monitoring();
break;
@@ -1920,6 +1934,10 @@
pr_debug("wcnss: received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n",
fw_status);
break;
+ case WCNSS_CBC_COMPLETE_IND:
+ penv->is_cbc_done = 1;
+ pr_debug("wcnss: received WCNSS_CBC_COMPLETE_IND from FW\n");
+ break;
case WCNSS_CALDATA_UPLD_REQ:
extract_cal_data(len);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 715aef2..8e55a07 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -347,6 +347,33 @@
EXPORT_SYMBOL(of_get_next_child);
/**
+ * of_get_next_available_child - Find the next available child node
+ * @node: parent node
+ * @prev: previous child of the parent node, or NULL to get first
+ *
+ * This function is like of_get_next_child(), except that it
+ * automatically skips any disabled nodes (i.e. status = "disabled").
+ */
+struct device_node *of_get_next_available_child(const struct device_node *node,
+ struct device_node *prev)
+{
+ struct device_node *next;
+
+ read_lock(&devtree_lock);
+ next = prev ? prev->sibling : node->child;
+ for (; next; next = next->sibling) {
+ if (!of_device_is_available(next))
+ continue;
+ if (of_node_get(next))
+ break;
+ }
+ of_node_put(prev);
+ read_unlock(&devtree_lock);
+ return next;
+}
+EXPORT_SYMBOL(of_get_next_available_child);
+
+/**
* of_find_node_by_path - Find a node matching a full OF path
* @path: The full path to match
*
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 3029744..af16e9d 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -3407,14 +3407,15 @@
pr_err("failed to write SEC_ACCESS rc=%d\n", rc);
return rc;
}
-
- rc = qpnp_chg_masked_write(chip,
- chip->usb_chgpth_base + COMP_OVR1,
- 0xFF,
- 0x2F, 1);
- if (rc) {
- pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
- return rc;
+ if (chip->type != SMBBP) {
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + COMP_OVR1,
+ 0xFF,
+ 0x2F, 1);
+ if (rc) {
+ pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+ return rc;
+ }
}
}
@@ -3513,16 +3514,16 @@
pr_err("failed to write SEC_ACCESS rc=%d\n", rc);
return rc;
}
-
- rc = qpnp_chg_masked_write(chip,
- chip->usb_chgpth_base + COMP_OVR1,
- 0xFF,
- 0x00, 1);
- if (rc) {
- pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
- return rc;
+ if (chip->type != SMBBP) {
+ rc = qpnp_chg_masked_write(chip,
+ chip->usb_chgpth_base + COMP_OVR1,
+ 0xFF,
+ 0x00, 1);
+ if (rc) {
+ pr_err("failed to write COMP_OVR1 rc=%d\n", rc);
+ return rc;
+ }
}
-
usleep(1000);
qpnp_chg_usb_suspend_enable(chip, 0);
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index e4f56b6..76047cb 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -521,10 +521,16 @@
}
EXPORT_SYMBOL(dwc3_set_notifier);
-void dwc3_notify_event(struct dwc3 *dwc, unsigned event)
+int dwc3_notify_event(struct dwc3 *dwc, unsigned event)
{
+ int ret = 0;
+
if (dwc->notify_event)
dwc->notify_event(dwc, event);
+ else
+ ret = -ENODEV;
+
+ return ret;
}
EXPORT_SYMBOL(dwc3_notify_event);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index b338c2d..863631c 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -703,6 +703,8 @@
* @hwparams: copy of hwparams registers
* @root: debugfs root folder pointer
* @tx_fifo_size: Available RAM size for TX fifo allocation
+ * @err_evt_seen: previous event in queue was erratic error
+ * @irq_cnt: total irq count
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
@@ -791,6 +793,8 @@
void (*notify_event) (struct dwc3 *, unsigned);
int tx_fifo_size;
bool tx_fifo_reduced;
+ bool err_evt_seen;
+ unsigned long irq_cnt;
};
/* -------------------------------------------------------------------------- */
@@ -944,7 +948,7 @@
extern void dwc3_set_notifier(
void (*notify) (struct dwc3 *dwc3, unsigned event));
-extern void dwc3_notify_event(struct dwc3 *dwc3, unsigned event);
+extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned event);
extern int dwc3_get_device_id(void);
extern void dwc3_put_device_id(int id);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 7d4ecd6..475729c 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -176,6 +176,7 @@
struct device *dev;
void __iomem *base;
struct resource *io_res;
+ struct platform_device *dwc3;
int dbm_num_eps;
u8 ep_num_mapping[DBM_MAX_EPS];
const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
@@ -208,7 +209,7 @@
bool lpm_irq_seen;
struct delayed_work resume_work;
struct work_struct restart_usb_work;
- struct work_struct usb_block_reset_work;
+ bool in_restart;
struct dwc3_charger charger;
struct usb_phy *otg_xceiv;
struct delayed_work chg_work;
@@ -1056,10 +1057,16 @@
}
EXPORT_SYMBOL(dwc3_tx_fifo_resize_request);
+static void dwc3_resume_work(struct work_struct *w);
+static void dwc3_msm_block_reset(struct dwc3_ext_xceiv *xceiv, bool core_reset);
+
static void dwc3_restart_usb_work(struct work_struct *w)
{
struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
restart_usb_work);
+ struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+ enum dwc3_chg_type chg_type;
+ unsigned timeout = 50;
dev_dbg(mdwc->dev, "%s\n", __func__);
@@ -1068,19 +1075,46 @@
return;
}
+ /* guard against concurrent VBUS handling */
+ mdwc->in_restart = true;
+
if (!mdwc->ext_xceiv.bsv) {
dev_dbg(mdwc->dev, "%s bailing out in disconnect\n", __func__);
+ dwc->err_evt_seen = false;
+ mdwc->in_restart = false;
return;
}
+ dbg_event(0xFF, "RestartUSB", 0);
+ chg_type = mdwc->charger.chg_type;
+
/* Reset active USB connection */
mdwc->ext_xceiv.bsv = false;
- queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
- /* Make sure disconnect is processed before sending connect */
- flush_delayed_work(&mdwc->resume_work);
+ dwc3_resume_work(&mdwc->resume_work.work);
- mdwc->ext_xceiv.bsv = true;
- queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
+ /* Make sure disconnect is processed before sending connect */
+ while (--timeout && !pm_runtime_suspended(mdwc->dev))
+ msleep(20);
+
+ if (!timeout) {
+ dev_warn(mdwc->dev, "Not in LPM after disconnect, forcing suspend...\n");
+ pm_runtime_suspend(mdwc->dev);
+ }
+
+ /* perform block reset after ERROR events */
+ if (dwc->err_evt_seen) {
+ dev_dbg(mdwc->dev, "%s initiating block reset\n", __func__);
+ dwc3_msm_block_reset(&mdwc->ext_xceiv, true);
+ }
+ dwc->err_evt_seen = false;
+ /* Force reconnect only if cable is still connected */
+ if (mdwc->vbus_active) {
+ mdwc->ext_xceiv.bsv = true;
+ mdwc->charger.chg_type = chg_type;
+ dwc3_resume_work(&mdwc->resume_work.work);
+ }
+
+ mdwc->in_restart = false;
}
/**
@@ -1550,20 +1584,27 @@
static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
{
struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
+ u32 reg;
if (dwc->revision < DWC3_REVISION_230A)
return;
switch (event) {
case DWC3_CONTROLLER_ERROR_EVENT:
- dev_info(mdwc->dev, "DWC3_CONTROLLER_ERROR_EVENT received\n");
+ dev_info(mdwc->dev,
+ "DWC3_CONTROLLER_ERROR_EVENT received, irq cnt %lu\n",
+ dwc->irq_cnt);
+
dwc3_msm_dump_phy_info(mdwc);
dwc3_msm_write_reg(mdwc->base, DWC3_DEVTEN, 0);
- /*
- * schedule work for doing block reset for recovery from erratic
- * error event.
- */
- queue_work(system_nrt_wq, &mdwc->usb_block_reset_work);
+
+ /* prevent core from generating interrupts until recovery */
+ reg = dwc3_msm_read_reg(mdwc->base, DWC3_GCTL);
+ reg |= DWC3_GCTL_CORESOFTRESET;
+ dwc3_msm_write_reg(mdwc->base, DWC3_GCTL, reg);
+
+ /* restart USB which performs full reset and reconnect */
+ queue_work(system_nrt_wq, &mdwc->restart_usb_work);
break;
case DWC3_CONTROLLER_RESET_EVENT:
dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
@@ -1611,29 +1652,6 @@
dwc3_msm_dbm_soft_reset(mdwc, 0);
}
-static void dwc3_block_reset_usb_work(struct work_struct *w)
-{
- struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
- usb_block_reset_work);
- u32 reg;
-
- dev_dbg(mdwc->dev, "%s\n", __func__);
-
- dwc3_msm_block_reset(&mdwc->ext_xceiv, true);
-
- reg = (DWC3_DEVTEN_EVNTOVERFLOWEN |
- DWC3_DEVTEN_CMDCMPLTEN |
- DWC3_DEVTEN_ERRTICERREN |
- DWC3_DEVTEN_WKUPEVTEN |
- DWC3_DEVTEN_ULSTCNGEN |
- DWC3_DEVTEN_CONNECTDONEEN |
- DWC3_DEVTEN_USBRSTEN |
- DWC3_DEVTEN_DISCONNEVTEN);
- dwc3_msm_write_reg(mdwc->base, DWC3_DEVTEN, reg);
-
-
-}
-
static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
{
u32 chg_ctrl;
@@ -2387,8 +2405,12 @@
/* Process PMIC notification in PRESENT prop */
case POWER_SUPPLY_PROP_PRESENT:
dev_dbg(mdwc->dev, "%s: notify xceiv event\n", __func__);
- if (mdwc->otg_xceiv && !mdwc->ext_inuse &&
+ mdwc->vbus_active = val->intval;
+ if (mdwc->otg_xceiv && !mdwc->ext_inuse && !mdwc->in_restart &&
(mdwc->ext_xceiv.otg_capability || !init)) {
+ if (mdwc->ext_xceiv.bsv == val->intval)
+ break;
+
mdwc->ext_xceiv.bsv = val->intval;
/*
* set debouncing delay to 120msec. Otherwise battery
@@ -2400,7 +2422,6 @@
if (!init)
init = true;
}
- mdwc->vbus_active = val->intval;
break;
case POWER_SUPPLY_PROP_ONLINE:
mdwc->online = val->intval;
@@ -2849,7 +2870,7 @@
static int __devinit dwc3_msm_probe(struct platform_device *pdev)
{
- struct device_node *node = pdev->dev.of_node;
+ struct device_node *node = pdev->dev.of_node, *dwc3_node;
struct dwc3_msm *mdwc;
struct resource *res;
void __iomem *tcsr;
@@ -2871,7 +2892,6 @@
INIT_DELAYED_WORK(&mdwc->chg_work, dwc3_chg_detect_work);
INIT_DELAYED_WORK(&mdwc->resume_work, dwc3_resume_work);
INIT_WORK(&mdwc->restart_usb_work, dwc3_restart_usb_work);
- INIT_WORK(&mdwc->usb_block_reset_work, dwc3_block_reset_usb_work);
INIT_WORK(&mdwc->id_work, dwc3_id_work);
INIT_DELAYED_WORK(&mdwc->init_adc_work, dwc3_init_adc_work);
init_completion(&mdwc->ext_chg_wait);
@@ -3198,6 +3218,14 @@
"unable to read platform data qdss tx fifo size\n");
dwc3_set_notifier(&dwc3_msm_notify_event);
+
+ /* Assumes dwc3 is the only DT child of dwc3-msm */
+ dwc3_node = of_get_next_available_child(node, NULL);
+ if (!dwc3_node) {
+ dev_err(&pdev->dev, "failed to find dwc3 child\n");
+ goto disable_hs_ldo;
+ }
+
/* usb_psy required only for vbus_notifications or charging support */
if (mdwc->ext_xceiv.otg_capability ||
!mdwc->charger.charging_disabled) {
@@ -3221,17 +3249,24 @@
dev_err(&pdev->dev,
"%s:power_supply_register usb failed\n",
__func__);
+ of_node_put(dwc3_node);
goto disable_hs_ldo;
}
}
- if (node) {
- ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
- if (ret) {
- dev_err(&pdev->dev,
- "failed to add create dwc3 core\n");
- goto put_psupply;
- }
+ ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to add create dwc3 core\n");
+ of_node_put(dwc3_node);
+ goto put_psupply;
+ }
+
+ mdwc->dwc3 = of_find_device_by_node(dwc3_node);
+ of_node_put(dwc3_node);
+ if (!mdwc->dwc3) {
+ dev_err(&pdev->dev, "failed to get dwc3 platform device\n");
+ goto put_psupply;
}
mdwc->bus_scale_table = msm_bus_cl_get_pdata(pdev);
@@ -3301,6 +3336,7 @@
return 0;
put_xcvr:
+ platform_device_put(mdwc->dwc3);
usb_put_transceiver(mdwc->otg_xceiv);
put_psupply:
if (mdwc->usb_psy.dev)
@@ -3366,6 +3402,7 @@
power_supply_unregister(&mdwc->usb_psy);
if (mdwc->vbus_otg)
regulator_disable(mdwc->vbus_otg);
+ platform_device_put(mdwc->dwc3);
pm_runtime_disable(mdwc->dev);
device_init_wakeup(mdwc->dev, 0);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index c6974cc..9ea3957 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2707,8 +2707,6 @@
dbg_print_reg("OCTL", dwc3_readl(dwc->regs, DWC3_OCTL));
dbg_print_reg("OEVT", dwc3_readl(dwc->regs, DWC3_OEVT));
dbg_print_reg("OSTS", dwc3_readl(dwc->regs, DWC3_OSTS));
-
- dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT);
}
static void dwc3_gadget_interrupt(struct dwc3 *dwc,
@@ -2737,9 +2735,11 @@
dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
break;
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
- dbg_event(0xFF, "ERROR", 0);
- dev_vdbg(dwc->dev, "Erratic Error\n");
- dwc3_dump_reg_info(dwc);
+ if (!dwc->err_evt_seen) {
+ dbg_event(0xFF, "ERROR", 0);
+ dev_vdbg(dwc->dev, "Erratic Error\n");
+ dwc3_dump_reg_info(dwc);
+ }
break;
case DWC3_DEVICE_EVENT_CMD_CMPL:
dev_vdbg(dwc->dev, "Command Complete\n");
@@ -2779,6 +2779,8 @@
default:
dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
}
+
+ dwc->err_evt_seen = (event->type == DWC3_DEVICE_EVENT_ERRATIC_ERROR);
}
static void dwc3_process_event_entry(struct dwc3 *dwc,
@@ -2820,6 +2822,22 @@
event.raw = *(u32 *) (evt->buf + evt->lpos);
dwc3_process_event_entry(dwc, &event);
+
+ if (dwc->err_evt_seen) {
+ /*
+ * if erratic error, skip remaining events
+ * while controller undergoes reset
+ */
+ evt->lpos = (evt->lpos + left) %
+ DWC3_EVENT_BUFFERS_SIZE;
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf),
+ left);
+ if (dwc3_notify_event(dwc,
+ DWC3_CONTROLLER_ERROR_EVENT))
+ dwc->err_evt_seen = 0;
+ break;
+ }
+
/*
* XXX we wrap around correctly to the next entry as almost all
* entries are 4 bytes in size. There is one entry which has 12
@@ -2844,12 +2862,23 @@
spin_lock(&dwc->lock);
+ dwc->irq_cnt++;
+
+ if (dwc->err_evt_seen) {
+ /* controller reset is still pending */
+ spin_unlock(&dwc->lock);
+ return IRQ_HANDLED;
+ }
+
for (i = 0; i < dwc->num_event_buffers; i++) {
irqreturn_t status;
status = dwc3_process_event_buf(dwc, i);
if (status == IRQ_HANDLED)
ret = status;
+
+ if (dwc->err_evt_seen)
+ break;
}
spin_unlock(&dwc->lock);
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index e8c938b..153d203 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -127,6 +127,7 @@
u32 has_decimation;
u8 has_wfd_blk;
u32 has_no_lut_read;
+ atomic_t sd_client_count;
u8 has_wb_ad;
u32 rotator_ot_limit;
@@ -252,4 +253,12 @@
return mdss_res->iommu_map[type].domain_idx;
}
+
+static inline int mdss_get_sd_client_cnt(void)
+{
+ if (!mdss_res)
+ return 0;
+ else
+ return atomic_read(&mdss_res->sd_client_count);
+}
#endif /* MDSS_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 045de27..c95afaf 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -1321,6 +1321,10 @@
struct dcs_cmd_req *req;
int ret = -EINVAL;
int rc = 0;
+
+ if (mdss_get_sd_client_cnt())
+ return -EPERM;
+
mutex_lock(&ctrl->cmd_mutex);
req = mdss_dsi_cmdlist_get(ctrl);
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 31e21f6..bec45c5 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -49,6 +49,7 @@
#include <mach/memory.h>
#include <mach/msm_memtypes.h>
#include <mach/rpm-regulator-smd.h>
+#include <mach/scm.h>
#include "mdss.h"
#include "mdss_fb.h"
@@ -81,6 +82,8 @@
#define IB_QUOTA 800000000
#define AB_QUOTA 800000000
+#define MEM_PROTECT_SD_CTRL 0xF
+
static DEFINE_SPINLOCK(mdp_lock);
static DEFINE_MUTEX(mdp_clk_lock);
static DEFINE_MUTEX(bus_bw_lock);
@@ -1228,6 +1231,7 @@
platform_set_drvdata(pdev, mdata);
mdss_res = mdata;
mutex_init(&mdata->reg_lock);
+ atomic_set(&mdata->sd_client_count, 0);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdp_phys");
if (!res) {
@@ -2636,6 +2640,26 @@
return 0;
}
+int mdss_mdp_secure_display_ctrl(unsigned int enable)
+{
+ struct sd_ctrl_req {
+ unsigned int enable;
+ } __attribute__ ((__packed__)) request;
+ unsigned int resp = -1;
+ int ret = 0;
+
+ request.enable = enable;
+
+ ret = scm_call(SCM_SVC_MP, MEM_PROTECT_SD_CTRL,
+ &request, sizeof(request), &resp, sizeof(resp));
+ pr_debug("scm_call MEM_PROTECT_SD_CTRL(%u): ret=%d, resp=%x",
+ enable, ret, resp);
+ if (ret)
+ return ret;
+
+ return resp;
+}
+
static inline int mdss_mdp_suspend_sub(struct mdss_data_type *mdata)
{
mdata->suspend_fs_ena = mdata->fs_ena;
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index f5f5770..0b23f5d 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -227,6 +227,7 @@
void *priv_data;
u32 wb_type;
+ u64 bw_pending;
};
struct mdss_mdp_mixer {
@@ -519,6 +520,15 @@
return MAX_LINE_BUFFER_WIDTH;
}
+static inline void mdss_update_sd_client(struct mdss_data_type *mdata,
+ bool status)
+{
+ if (status)
+ atomic_inc(&mdata->sd_client_count);
+ else
+ atomic_add_unless(&mdss_res->sd_client_count, -1, 0);
+}
+
irqreturn_t mdss_mdp_isr(int irq, void *ptr);
int mdss_iommu_attach(struct mdss_data_type *mdata);
int mdss_iommu_dettach(struct mdss_data_type *mdata);
@@ -541,6 +551,7 @@
int mdss_mdp_vsync_clk_enable(int enable);
void mdss_mdp_clk_ctrl(int enable, int isr);
struct mdss_data_type *mdss_mdp_get_mdata(void);
+int mdss_mdp_secure_display_ctrl(unsigned int enable);
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
int mdss_mdp_overlay_req_check(struct msm_fb_data_type *mfd,
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index b0b5a61..44f645f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -699,7 +699,8 @@
{
struct mdss_data_type *mdata = ctl->mdata;
struct mdss_mdp_perf_params perf;
- u32 bw, threshold;
+ u32 bw, threshold, i;
+ u64 bw_sum_of_intfs = 0;
/* we only need bandwidth check on real-time clients (interfaces) */
if (ctl->intf_type == MDSS_MDP_NO_INTF)
@@ -707,13 +708,23 @@
__mdss_mdp_perf_calc_ctl_helper(ctl, &perf,
left_plist, left_cnt, right_plist, right_cnt);
+ ctl->bw_pending = perf.bw_ctl;
+
+ for (i = 0; i < mdata->nctl; i++) {
+ struct mdss_mdp_ctl *temp = mdata->ctl_off + i;
+ if (temp->power_on && (temp->intf_type != MDSS_MDP_NO_INTF))
+ bw_sum_of_intfs += temp->bw_pending;
+ }
/* convert bandwidth to kb */
- bw = DIV_ROUND_UP_ULL(perf.bw_ctl, 1000);
+ bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000);
pr_debug("calculated bandwidth=%uk\n", bw);
- threshold = ctl->is_video_mode ? mdata->max_bw_low : mdata->max_bw_high;
+ threshold = (ctl->is_video_mode ||
+ mdss_mdp_video_mode_intf_connected(ctl)) ?
+ mdata->max_bw_low : mdata->max_bw_high;
if (bw > threshold) {
+ ctl->bw_pending = 0;
pr_debug("exceeds bandwidth: %ukb > %ukb\n", bw, threshold);
return -E2BIG;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 5b99105..516d819 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 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
@@ -46,14 +46,8 @@
#define PP_CLK_CFG_OFF 0
#define PP_CLK_CFG_ON 1
-#define MEM_PROTECT_SD_CTRL 0xF
-
#define OVERLAY_MAX 10
-struct sd_ctrl_req {
- unsigned int enable;
-} __attribute__ ((__packed__));
-
static atomic_t ov_active_panels = ATOMIC_INIT(0);
static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
@@ -67,26 +61,6 @@
return ctl->mixer_left->width;
}
-static int mdss_mdp_overlay_sd_ctrl(struct msm_fb_data_type *mfd,
- unsigned int enable)
-{
- struct sd_ctrl_req request;
- unsigned int resp = -1;
- int ret = 0;
- pr_debug("sd_ctrl %u\n", enable);
-
- request.enable = enable;
-
- ret = scm_call(SCM_SVC_MP, MEM_PROTECT_SD_CTRL,
- &request, sizeof(request), &resp, sizeof(resp));
- pr_debug("scm_call MEM_PROTECT_SD_CTRL(%u): ret=%d, resp=%x",
- enable, ret, resp);
- if (ret)
- return ret;
-
- return resp;
-}
-
static int mdss_mdp_overlay_get(struct msm_fb_data_type *mfd,
struct mdp_overlay *req)
{
@@ -941,18 +915,24 @@
memset(buf, 0, sizeof(*buf));
}
-static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
+/**
+ * mdss_mdp_overlay_cleanup() - handles cleanup after frame commit
+ * @mfd: Msm frame buffer data structure for the associated fb
+ * @destroy_pipes: list of pipes that should be destroyed as part of cleanup
+ *
+ * Goes through destroy_pipes list and ensures they are ready to be destroyed
+ * and cleaned up. Also cleanup of any pipe buffers after flip.
+ */
+static void mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd,
+ struct list_head *destroy_pipes)
{
struct mdss_mdp_pipe *pipe, *tmp;
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
bool recovery_mode = false;
- LIST_HEAD(destroy_pipes);
mutex_lock(&mdp5_data->list_lock);
- list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup, list) {
- list_move(&pipe->list, &destroy_pipes);
-
+ list_for_each_entry(pipe, destroy_pipes, list) {
/* make sure pipe fetch has been halted before freeing buffer */
if (mdss_mdp_pipe_fetch_halt(pipe)) {
/*
@@ -987,7 +967,7 @@
}
}
- list_for_each_entry_safe(pipe, tmp, &destroy_pipes, list) {
+ list_for_each_entry_safe(pipe, tmp, destroy_pipes, list) {
/*
* in case of secure UI, the buffer needs to be released as
* soon as session is closed.
@@ -1160,7 +1140,7 @@
* When secure display is enabled, if there is a non secure
* display pipe, skip that
*/
- if ((mdp5_data->sd_enabled) &&
+ if (mdss_get_sd_client_cnt() &&
!(pipe->flags & MDP_SECURE_DISPLAY_OVERLAY_SESSION)) {
pr_warn("Non secure pipe during secure display: %u: %08X, skip\n",
pipe->num, pipe->flags);
@@ -1239,11 +1219,12 @@
struct mdp_display_commit *data)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
- struct mdss_mdp_pipe *pipe;
+ struct mdss_mdp_pipe *pipe, *tmp;
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
int ret = 0;
int sd_in_pipe = 0;
bool need_cleanup = false;
+ LIST_HEAD(destroy_pipes);
ATRACE_BEGIN(__func__);
if (ctl->shared_lock) {
@@ -1253,6 +1234,7 @@
}
mutex_lock(&mdp5_data->ov_lock);
+ ctl->bw_pending = 0;
mutex_lock(&mdp5_data->list_lock);
/*
@@ -1270,8 +1252,13 @@
* secure display session
*/
if (!sd_in_pipe && mdp5_data->sd_enabled) {
- if (0 == mdss_mdp_overlay_sd_ctrl(mfd, 0))
+ /* disable the secure display on last client */
+ if (mdss_get_sd_client_cnt() == 1)
+ ret = mdss_mdp_secure_display_ctrl(0);
+ if (!ret) {
+ mdss_update_sd_client(mdp5_data->mdata, false);
mdp5_data->sd_enabled = 0;
+ }
}
if (!ctl->shared_lock)
@@ -1286,9 +1273,10 @@
* Setup pipe in solid fill before unstaging,
* to ensure no fetches are happening after dettach or reattach.
*/
- list_for_each_entry(pipe, &mdp5_data->pipes_cleanup, list) {
+ list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup, list) {
mdss_mdp_pipe_queue_data(pipe, NULL);
mdss_mdp_mixer_pipe_unstage(pipe);
+ list_move(&pipe->list, &destroy_pipes);
need_cleanup = true;
}
@@ -1324,17 +1312,20 @@
mutex_lock(&mdp5_data->ov_lock);
if (ret == 0) {
- if (!mdp5_data->sd_enabled && (sd_in_pipe == 1)) {
- ret = mdss_mdp_overlay_sd_ctrl(mfd, 1);
- if (ret == 0)
+ if (!mdp5_data->sd_enabled && sd_in_pipe) {
+ if (!mdss_get_sd_client_cnt())
+ ret = mdss_mdp_secure_display_ctrl(1);
+ if (!ret) {
mdp5_data->sd_enabled = 1;
+ mdss_update_sd_client(mdp5_data->mdata, true);
+ }
}
}
mdss_fb_update_notify_update(mfd);
commit_fail:
ATRACE_BEGIN("overlay_cleanup");
- mdss_mdp_overlay_cleanup(mfd);
+ mdss_mdp_overlay_cleanup(mfd, &destroy_pipes);
ATRACE_END("overlay_cleanup");
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
mdss_mdp_ctl_notify(ctl, MDP_NOTIFY_FRAME_FLUSHED);
@@ -1557,6 +1548,8 @@
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
+ struct mdss_mdp_pipe *pipe, *tmp;
+ LIST_HEAD(destroy_pipes);
int ret;
pr_debug("forcing cleanup to unset dma pipes on fb%d\n", mfd->index);
@@ -1571,7 +1564,12 @@
mdss_mdp_display_wait4comp(ctl);
}
- mdss_mdp_overlay_cleanup(mfd);
+ mutex_lock(&mdp5_data->list_lock);
+ list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_cleanup, list) {
+ list_move(&pipe->list, &destroy_pipes);
+ }
+ mutex_unlock(&mdp5_data->list_lock);
+ mdss_mdp_overlay_cleanup(mfd, &destroy_pipes);
}
static void mdss_mdp_overlay_force_dma_cleanup(struct mdss_data_type *mdata)
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 134a3d9..6e5975b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -564,6 +564,8 @@
* shared as long as its attached to a writeback mixer
*/
pipe = mdata->dma_pipes + mixer->num;
+ if (pipe->mixer->type != MDSS_MDP_MIXER_TYPE_WRITEBACK)
+ return NULL;
kref_get(&pipe->kref);
pr_debug("pipe sharing for pipe=%d\n", pipe->num);
} else {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 2daffcd..bec01b3 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -1902,7 +1902,7 @@
(ad->sts & PP_STS_ENABLE)) {
ad->last_bl = bl;
linear_map(bl, &ad->bl_data,
- ad->bl_mfd->panel_info->bl_max,
+ bl_mfd->panel_info->bl_max,
MDSS_MDP_AD_BL_SCALE);
pp_ad_input_write(&mdata->ad_off[dspp_num], ad);
}
@@ -4655,7 +4655,7 @@
ad->calc_itr = ad->cfg.stab_itr;
ad->sts |= PP_AD_STS_DIRTY_VSYNC;
linear_map(bl, &ad->bl_data,
- ad->bl_mfd->panel_info->bl_max,
+ bl_mfd->panel_info->bl_max,
MDSS_MDP_AD_BL_SCALE);
}
ad->reg_sts |= PP_AD_STS_DIRTY_DATA;
diff --git a/include/linux/of.h b/include/linux/of.h
index fa7fb1d..af2be13 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -189,10 +189,17 @@
extern struct device_node *of_get_next_parent(struct device_node *node);
extern struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev);
+extern struct device_node *of_get_next_available_child(
+ const struct device_node *node, struct device_node *prev);
+
#define for_each_child_of_node(parent, child) \
for (child = of_get_next_child(parent, NULL); child != NULL; \
child = of_get_next_child(parent, child))
+#define for_each_available_child_of_node(parent, child) \
+ for (child = of_get_next_available_child(parent, NULL); child != NULL; \
+ child = of_get_next_available_child(parent, child))
+
extern struct device_node *of_find_node_with_property(
struct device_node *from, const char *prop_name);
#define for_each_node_with_property(dn, prop_name) \
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 55d6b1e..5023a0c 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -41,6 +41,7 @@
#define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1
#define HAVE_WCNSS_RESET_INTR 1
#define HAVE_WCNSS_CAL_DOWNLOAD 1
+#define HAVE_CBC_DONE 1
#define HAVE_WCNSS_RX_BUFF_COUNT 1
#define WLAN_MAC_ADDR_SIZE (6)
#define PRONTO_PMU_OFFSET 0x1004
@@ -82,6 +83,7 @@
void wcnss_pronto_log_debug_regs(void);
int wcnss_is_hw_pronto_ver3(void);
int wcnss_device_ready(void);
+bool wcnss_cbc_complete(void);
int wcnss_device_is_shutdown(void);
void wcnss_riva_dump_pmic_regs(void);
int wcnss_xo_auto_detect_enabled(void);
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 63b3dc7..fac0668 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -153,6 +153,7 @@
if (sk_hashed(sk)) {
write_lock_bh(&ping_table.lock);
hlist_nulls_del(&sk->sk_nulls_node);
+ sk_nulls_node_init(&sk->sk_nulls_node);
sock_put(sk);
isk->inet_num = 0;
isk->inet_sport = 0;
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
index c4c219c..1bc5e46 100644
--- a/sound/soc/codecs/wcd9xxx-common.c
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -954,7 +954,6 @@
if ((clsh_d->state == WCD9XXX_CLSH_STATE_LO) ||
(req_state == WCD9XXX_CLSH_STATE_LO)) {
wcd9xxx_dynamic_bypass_buck_ctrl_lo(codec, false);
- wcd9xxx_enable_buck(codec, clsh_d, true);
wcd9xxx_set_fclk_get_ncp(codec, clsh_d,
NCP_FCLK_LEVEL_8);
if (req_state & WCD9XXX_CLSH_STATE_HPH_ST) {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 4fe2459..8e62151 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 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
@@ -493,7 +493,11 @@
pr_debug("%s: pkt_len =%d, frame.pktlen=%d, timestamp=%d\n",
__func__, pkt_len, buf_node->frame.pktlen, timestamp);
- prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
+ if (prtd->mode == MODE_PCM)
+ prtd->pcm_capture_irq_pos += buf_node->frame.pktlen;
+ else
+ prtd->pcm_capture_irq_pos += prtd->pcm_capture_count;
+
spin_unlock_irqrestore(&prtd->dsp_ul_lock, dsp_flags);
snd_pcm_period_elapsed(prtd->capture_substream);
} else {
@@ -654,7 +658,11 @@
}
pr_debug("%s: frame.pktlen=%d\n", __func__, buf_node->frame.pktlen);
- prtd->pcm_playback_irq_pos += prtd->pcm_count;
+ if (prtd->mode == MODE_PCM)
+ prtd->pcm_playback_irq_pos += buf_node->frame.pktlen;
+ else
+ prtd->pcm_playback_irq_pos += prtd->pcm_count;
+
spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
snd_pcm_period_elapsed(prtd->playback_substream);
} else {