Merge "netlink: Queue the kernel socket after setting the flag"
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index d97d3c3..588688c 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -1,6 +1,11 @@
#Android makefile to build kernel as a part of Android Build
PERL = perl
+KERNEL_TARGET := $(strip $(INSTALLED_KERNEL_TARGET))
+ifeq ($(KERNEL_TARGET),)
+INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel
+endif
+
ifeq ($(TARGET_PREBUILT_KERNEL),)
KERNEL_OUT := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index c4b4707..afbae5e 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -293,6 +293,15 @@
- qcom,panel-roi-alignment: Specifies the panel ROI alignment restrictions on its
left, top, width, height alignments and minimum width and
height values
+- qcom,dynamic-mode-switch-enabled: Boolean used to mention whether panel supports
+ dynamic switching from video mode to command mode
+ and vice versa.
+- qcom,video-to-cmd-mode-switch-commands: List of commands that need to be sent
+ to panel in order to switch from video mode to command mode dynamically.
+ Refer to "qcom,mdss-dsi-on-command" section for adding commands.
+- qcom,cmd-to-video-mode-switch-commands: List of commands that need to be sent
+ to panel in order to switch from command mode to video mode dynamically.
+ Refer to "qcom,mdss-dsi-on-command" section for adding commands.
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@@ -399,5 +408,9 @@
qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>;
qcom,mdss-tear-check-frame-rate = <6000>;
qcom,panel-roi-alignment = <4 4 2 2 20 20>;
+ qcom,dynamic-mode-switch-enabled;
+ qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 00 00 02 C2 0B
+ 15 01 00 00 00 00 02 C2 08];
+ qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03];
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index 9a18a31..bab1735 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -511,6 +511,10 @@
05 01 00 00 78 00 02 10 00];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,dynamic-mode-switch-enabled;
+ qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 14 00 02 C2 0B
+ 15 01 00 00 00 00 02 C2 08];
+ qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03];
qcom,mdss-dsi-h-sync-pulse = <1>;
qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index d243b78..ad029ee 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -470,14 +470,25 @@
qcom,clock-a7@f9011050 {
compatible = "qcom,clock-a7-8226";
- reg = <0xf9011050 0x8>;
- reg-names = "rcg-base";
+ reg = <0xf9011050 0x8>,
+ <0xfc4b80b8 0x8>;
+ reg-names = "rcg-base", "efuse";
clock-names = "clk-4", "clk-5";
qcom,speed0-bin-v0 =
< 0 0>,
< 384000000 1>,
< 787200000 2>,
<1190400000 3>;
+ qcom,speed1-bin-v0 =
+ < 0 0>,
+ < 384000000 1>,
+ < 787200000 2>,
+ <1094400000 3>;
+ qcom,speed1-bin-v2 =
+ < 0 0>,
+ < 384000000 1>,
+ < 787200000 2>,
+ <1094400000 3>;
cpu-vdd-supply = <&apc_vreg_corner>;
};
@@ -500,6 +511,7 @@
< 600000 1525 >,
< 787200 1525 >,
< 998400 2540 >,
+ < 1094400 2540 >,
< 1190400 2540 >;
};
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index e9c749a..482981c 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -559,6 +559,7 @@
F_APCS_PLL( 768000000, 40, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 787200000, 41, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
PLL_F_END
};
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 486d740..52bbe12 100755
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1033,6 +1033,11 @@
dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
}
+ if (ptype == HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER) {
+ dprintk(VIDC_WARN, "Smoothstreaming is not supported\n");
+ return -ENOTSUPP;
+ }
+
dev = session->device;
dprintk(VIDC_DBG, "in set_prop,with prop id: 0x%x", ptype);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 0c70746..97de664 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -30,6 +30,7 @@
#include <linux/blkdev.h>
#include <linux/mutex.h>
#include <linux/scatterlist.h>
+#include <linux/bitops.h>
#include <linux/string_helpers.h>
#include <linux/delay.h>
#include <linux/capability.h>
@@ -2469,7 +2470,7 @@
areq = mmc_start_req(card->host, areq, (int *) &status);
if (!areq) {
if (status == MMC_BLK_NEW_REQUEST)
- mq->flags |= MMC_QUEUE_NEW_REQUEST;
+ set_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags);
return 0;
}
@@ -2490,7 +2491,7 @@
mmc_blk_reinsert_req(areq);
}
- mq->flags |= MMC_QUEUE_URGENT_REQUEST;
+ set_bit(MMC_QUEUE_URGENT_REQUEST, &mq->flags);
ret = 0;
break;
case MMC_BLK_URGENT_DONE:
@@ -2649,6 +2650,7 @@
struct mmc_card *card = md->queue.card;
struct mmc_host *host = card->host;
unsigned long flags;
+ unsigned int cmd_flags = req ? req->cmd_flags : 0;
if (req && !mq->mqrq_prev->req) {
mmc_rpm_hold(host, &card->dev);
@@ -2674,23 +2676,23 @@
mmc_blk_write_packing_control(mq, req);
- mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
- mq->flags &= ~MMC_QUEUE_URGENT_REQUEST;
- if (req && req->cmd_flags & REQ_SANITIZE) {
+ clear_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags);
+ clear_bit(MMC_QUEUE_URGENT_REQUEST, &mq->flags);
+ if (cmd_flags & REQ_SANITIZE) {
/* complete ongoing async transfer before issuing sanitize */
if (card->host && card->host->areq)
mmc_blk_issue_rw_rq(mq, NULL);
ret = mmc_blk_issue_sanitize_rq(mq, req);
- } else if (req && req->cmd_flags & REQ_DISCARD) {
+ } else if (cmd_flags & REQ_DISCARD) {
/* complete ongoing async transfer before issuing discard */
if (card->host->areq)
mmc_blk_issue_rw_rq(mq, NULL);
- if (req->cmd_flags & REQ_SECURE &&
+ if (cmd_flags & REQ_SECURE &&
!(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN))
ret = mmc_blk_issue_secdiscard_rq(mq, req);
else
ret = mmc_blk_issue_discard_rq(mq, req);
- } else if (req && req->cmd_flags & REQ_FLUSH) {
+ } else if (cmd_flags & REQ_FLUSH) {
/* complete ongoing async transfer before issuing flush */
if (card->host->areq)
mmc_blk_issue_rw_rq(mq, NULL);
@@ -2711,10 +2713,9 @@
* - urgent notification in progress and current request is not urgent
* (all existing requests completed or reinserted to the block layer)
*/
- if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) ||
- ((mq->flags & MMC_QUEUE_URGENT_REQUEST) &&
- !(mq->mqrq_cur->req->cmd_flags &
- MMC_REQ_NOREINSERT_MASK))) {
+ if ((!req && !(test_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags))) ||
+ ((test_bit(MMC_QUEUE_URGENT_REQUEST, &mq->flags)) &&
+ !(cmd_flags & MMC_REQ_NOREINSERT_MASK))) {
if (mmc_card_need_bkops(card))
mmc_start_bkops(card, false);
/* release host only when there are no more requests */
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index fa3dcdc..cceb8d9 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -15,6 +15,7 @@
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/scatterlist.h>
+#include <linux/bitops.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -75,12 +76,12 @@
if (req || mq->mqrq_prev->req) {
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
- if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
+ if (test_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags)) {
continue; /* fetch again */
- } else if ((mq->flags & MMC_QUEUE_URGENT_REQUEST) &&
- (mq->mqrq_cur->req &&
- !(mq->mqrq_cur->req->cmd_flags &
- MMC_REQ_NOREINSERT_MASK))) {
+ } else if (test_bit(MMC_QUEUE_URGENT_REQUEST,
+ &mq->flags) && (mq->mqrq_cur->req &&
+ !(mq->mqrq_cur->req->cmd_flags &
+ MMC_REQ_NOREINSERT_MASK))) {
/*
* clean current request when urgent request
* processing in progress and current request is
@@ -474,9 +475,7 @@
unsigned long flags;
int rc = 0;
- if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
- mq->flags |= MMC_QUEUE_SUSPENDED;
-
+ if (!(test_and_set_bit(MMC_QUEUE_SUSPENDED, &mq->flags))) {
spin_lock_irqsave(q->queue_lock, flags);
blk_stop_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
@@ -487,7 +486,7 @@
* Failed to take the lock so better to abort the
* suspend because mmcqd thread is processing requests.
*/
- mq->flags &= ~MMC_QUEUE_SUSPENDED;
+ clear_bit(MMC_QUEUE_SUSPENDED, &mq->flags);
spin_lock_irqsave(q->queue_lock, flags);
blk_start_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
@@ -509,8 +508,7 @@
struct request_queue *q = mq->queue;
unsigned long flags;
- if (mq->flags & MMC_QUEUE_SUSPENDED) {
- mq->flags &= ~MMC_QUEUE_SUSPENDED;
+ if (test_and_clear_bit(MMC_QUEUE_SUSPENDED, &mq->flags)) {
up(&mq->thread_sem);
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index d1fe01c..0ed7f36 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -38,10 +38,10 @@
struct mmc_card *card;
struct task_struct *thread;
struct semaphore thread_sem;
- unsigned int flags;
-#define MMC_QUEUE_SUSPENDED (1 << 0)
-#define MMC_QUEUE_NEW_REQUEST (1 << 1)
-#define MMC_QUEUE_URGENT_REQUEST (1 << 2)
+ unsigned long flags;
+#define MMC_QUEUE_SUSPENDED 0
+#define MMC_QUEUE_NEW_REQUEST 1
+#define MMC_QUEUE_URGENT_REQUEST 2
int (*issue_fn)(struct mmc_queue *, struct request *);
void *data;
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 8eb5573..54c46c8 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1998,8 +1998,11 @@
if (tty->ops->flush_chars)
tty->ops->flush_chars(tty);
} else {
+
while (nr > 0) {
+ mutex_lock(&tty->output_lock);
c = tty->ops->write(tty, b, nr);
+ mutex_unlock(&tty->output_lock);
if (c < 0) {
retval = c;
goto break_out;
diff --git a/drivers/usb/class/ccid_bridge.c b/drivers/usb/class/ccid_bridge.c
index a914902..7d2f1c3 100644
--- a/drivers/usb/class/ccid_bridge.c
+++ b/drivers/usb/class/ccid_bridge.c
@@ -21,6 +21,8 @@
#include <linux/usb.h>
#include <linux/wait.h>
#include <linux/cdev.h>
+#include <linux/ktime.h>
+#include <linux/debugfs.h>
#include <linux/usb/ccid_bridge.h>
@@ -71,6 +73,14 @@
struct cdev cdev;
struct class *class;
struct device *device;
+
+ struct dentry *dbg_root;
+ unsigned n_write;
+ unsigned n_read;
+ unsigned n_write_timeout;
+ unsigned n_read_timeout;
+ unsigned long write_max_time;
+ unsigned long read_max_time;
};
static struct ccid_bridge *__ccid_bridge_dev;
@@ -260,6 +270,7 @@
struct ccid_bridge *ccid = fp->private_data;
int ret;
char *kbuf;
+ ktime_t start_t, delta_t;
pr_debug("called with %d", count);
@@ -270,6 +281,9 @@
mutex_lock(&ccid->write_mutex);
+ ccid->n_write++;
+ start_t = ktime_get();
+
if (!count || count > CCID_BRIDGE_MSG_SZ) {
pr_err("invalid count");
ret = -EINVAL;
@@ -311,12 +325,20 @@
msecs_to_jiffies(ccid_bulk_msg_timeout));
if (!ret || ret == -ERESTARTSYS) { /* timedout or interrupted */
usb_kill_urb(ccid->writeurb);
- if (!ret)
+ if (!ret) {
+ ccid->n_write_timeout++;
ret = -ETIMEDOUT;
+ }
} else {
ret = ccid->write_result;
}
+ if (ret >= 0) {
+ delta_t = ktime_sub(ktime_get(), start_t);
+ if (ktime_to_ms(delta_t) > ccid->write_max_time)
+ ccid->write_max_time = ktime_to_ms(delta_t);
+ }
+
pr_debug("returning %d", ret);
put_pm:
@@ -336,6 +358,7 @@
struct ccid_bridge *ccid = fp->private_data;
int ret;
char *kbuf;
+ ktime_t start_t, delta_t;
pr_debug("called with %d", count);
if (!ccid->intf) {
@@ -345,6 +368,9 @@
mutex_lock(&ccid->read_mutex);
+ ccid->n_read++;
+ start_t = ktime_get();
+
if (!count || count > CCID_BRIDGE_MSG_SZ) {
pr_err("invalid count");
ret = -EINVAL;
@@ -376,22 +402,26 @@
goto free_kbuf;
}
-
ret = wait_event_interruptible_timeout(ccid->read_wq,
ccid->read_result != 0,
msecs_to_jiffies(ccid_bulk_msg_timeout));
if (!ret || ret == -ERESTARTSYS) { /* timedout or interrupted */
usb_kill_urb(ccid->readurb);
- if (!ret)
+ if (!ret) {
+ ccid->n_read_timeout++;
ret = -ETIMEDOUT;
+ }
} else {
ret = ccid->read_result;
}
-
if (ret > 0) {
if (copy_to_user(ubuf, kbuf, ret))
ret = -EFAULT;
+
+ delta_t = ktime_sub(ktime_get(), start_t);
+ if (ktime_to_ms(delta_t) > ccid->read_max_time)
+ ccid->read_max_time = ktime_to_ms(delta_t);
}
usb_autopm_put_interface(ccid->intf);
@@ -537,12 +567,30 @@
return ret;
}
+static void ccid_bridge_reset_stats(struct ccid_bridge *ccid)
+{
+ ccid->n_write = 0;
+ ccid->n_read = 0;
+ ccid->n_write_timeout = 0;
+ ccid->n_read_timeout = 0;
+ ccid->write_max_time = 0;
+ ccid->read_max_time = 0;
+}
+
static int ccid_bridge_release(struct inode *ip, struct file *fp)
{
struct ccid_bridge *ccid = fp->private_data;
pr_debug("called");
+ mutex_lock(&ccid->open_mutex);
+ if (ccid->intf == NULL) {
+ ccid->opened = false;
+ mutex_unlock(&ccid->open_mutex);
+ goto done;
+ }
+ mutex_unlock(&ccid->open_mutex);
+
usb_kill_urb(ccid->writeurb);
usb_kill_urb(ccid->readurb);
if (ccid->int_pipe)
@@ -554,6 +602,8 @@
mutex_lock(&ccid->open_mutex);
ccid->opened = false;
mutex_unlock(&ccid->open_mutex);
+done:
+ ccid_bridge_reset_stats(ccid);
return 0;
}
@@ -783,6 +833,80 @@
.supports_autosuspend = 1,
};
+static int ccid_bridge_stats_show(struct seq_file *s, void *unused)
+{
+ struct ccid_bridge *ccid = s->private;
+
+ seq_printf(s, "ccid_bridge: %s\n",
+ ccid->intf ? "connected" : "disconnected");
+ seq_printf(s, "ccid_bridge: %s\n",
+ ccid->opened ? "opened" : "closed");
+
+ seq_printf(s, "total writes: %u\n", ccid->n_write);
+ seq_printf(s, "total reads: %u\n", ccid->n_write);
+
+ seq_printf(s, "write/read timeout val: %u\n", ccid_bulk_msg_timeout);
+
+ seq_printf(s, "write_timeout: %u\n", ccid->n_write_timeout);
+ seq_printf(s, "read_timeout: %u\n", ccid->n_read_timeout);
+
+ seq_printf(s, "write_max_time (msec): %lu\n", ccid->write_max_time);
+ seq_printf(s, "read_max_time: (msec): %lu\n", ccid->read_max_time);
+
+ return 0;
+}
+
+static int ccid_bridge_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ccid_bridge_stats_show, inode->i_private);
+}
+
+static ssize_t ccid_bridge_stats_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *s = file->private_data;
+ struct ccid_bridge *ccid = s->private;
+
+ ccid_bridge_reset_stats(ccid);
+ return count;
+}
+
+const struct file_operations ccid_bridge_stats_ops = {
+ .open = ccid_bridge_stats_open,
+ .read = seq_read,
+ .write = ccid_bridge_stats_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int ccid_bridge_debugfs_init(struct ccid_bridge *ccid)
+{
+ struct dentry *dir;
+ int ret = 0;
+
+ dir = debugfs_create_dir("ccid_bridge", NULL);
+
+ if (!dir || IS_ERR(dir)) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ccid->dbg_root = dir;
+
+ dir = debugfs_create_file("stats", 0644, ccid->dbg_root, ccid,
+ &ccid_bridge_stats_ops);
+
+ if (!dir) {
+ debugfs_remove_recursive(ccid->dbg_root);
+ ccid->dbg_root = NULL;
+ ret = -ENODEV;
+ }
+
+out:
+ return ret;
+}
+
static int __init ccid_bridge_init(void)
{
int ret;
@@ -840,6 +964,8 @@
goto del_cdev;
}
+ ccid_bridge_debugfs_init(ccid);
+
pr_info("success");
return 0;
@@ -868,6 +994,8 @@
struct ccid_bridge *ccid = __ccid_bridge_dev;
pr_debug("called");
+
+ debugfs_remove_recursive(ccid->dbg_root);
device_destroy(ccid->class, ccid->chrdev);
cdev_del(&ccid->cdev);
class_destroy(ccid->class);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 4be032a..0f86879 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2113,6 +2113,8 @@
break;
} while (1);
+ dwc->gadget.xfer_isr_count++;
+
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->req_queued)) {
if (list_empty(&dep->request_list))
@@ -2276,6 +2278,7 @@
dwc->gadget_driver->disconnect(&dwc->gadget);
spin_lock(&dwc->lock);
}
+ dwc->gadget.xfer_isr_count = 0;
}
static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 30a678b..ad0e464 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2295,6 +2295,7 @@
udc->configured = 0;
spin_unlock_irqrestore(udc->lock, flags);
+ gadget->xfer_isr_count = 0;
gadget->b_hnp_enable = 0;
gadget->a_hnp_support = 0;
gadget->host_request = 0;
@@ -3688,6 +3689,7 @@
isr_statistics.uei++;
if (USBi_UI & intr) {
isr_statistics.ui++;
+ udc->gadget.xfer_isr_count++;
isr_tr_complete_handler(udc);
}
if (USBi_SLI & intr) {
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 99e1c21..454fd15 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -578,15 +578,20 @@
pr_debug("msm_dsi_op_mode_config\n");
dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL);
- /*If Video enabled, Keep Video and Cmd mode ON */
-
- dsi_ctrl &= ~0x06;
-
- if (mode == DSI_VIDEO_MODE)
- dsi_ctrl |= 0x02;
+ if (dsi_ctrl & DSI_VIDEO_MODE_EN)
+ dsi_ctrl &= ~(DSI_CMD_MODE_EN|DSI_EN);
else
- dsi_ctrl |= 0x04;
+ dsi_ctrl &= ~(DSI_CMD_MODE_EN|DSI_VIDEO_MODE_EN|DSI_EN);
+
+ if (mode == DSI_VIDEO_MODE) {
+ dsi_ctrl |= (DSI_VIDEO_MODE_EN|DSI_EN);
+ } else { /* command mode */
+ dsi_ctrl |= (DSI_CMD_MODE_EN|DSI_EN);
+ /*For Video mode panel, keep Video and Cmd mode ON */
+ if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
+ dsi_ctrl |= DSI_VIDEO_MODE_EN;
+ }
pr_debug("%s: dsi_ctrl=%x\n", __func__, dsi_ctrl);
@@ -1070,13 +1075,15 @@
mutex_lock(&ctrl_pdata->mutex);
- ret = msm_dss_enable_vreg(
- ctrl_pdata->power_data.vreg_config,
- ctrl_pdata->power_data.num_vreg, 1);
- if (ret) {
- pr_err("%s: DSI power on failed\n", __func__);
- mutex_unlock(&ctrl_pdata->mutex);
- return ret;
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ ret = msm_dss_enable_vreg(
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 1);
+ if (ret) {
+ pr_err("%s: DSI power on failed\n", __func__);
+ mutex_unlock(&ctrl_pdata->mutex);
+ return ret;
+ }
}
msm_dsi_ahb_ctrl(1);
@@ -1194,11 +1201,13 @@
msm_dsi_phy_off(dsi_host_private->dsi_base);
msm_dsi_ahb_ctrl(0);
- ret = msm_dss_enable_vreg(
- ctrl_pdata->power_data.vreg_config,
- ctrl_pdata->power_data.num_vreg, 0);
- if (ret) {
- pr_err("%s: Panel power off failed\n", __func__);
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ ret = msm_dss_enable_vreg(
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 0);
+ if (ret) {
+ pr_err("%s: Panel power off failed\n", __func__);
+ }
}
dsi_host_private->clk_count = 0;
dsi_host_private->dsi_on = 0;
diff --git a/drivers/video/msm/mdss/dsi_host_v2.h b/drivers/video/msm/mdss/dsi_host_v2.h
index 0f3ea8d..991a769 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.h
+++ b/drivers/video/msm/mdss/dsi_host_v2.h
@@ -171,4 +171,8 @@
#define DSI_DSIPHY_BIST_CTRL4 0x049C
#define DSI_DSIPHY_BIST_CTRL5 0x04A0
+#define DSI_EN BIT(0)
+#define DSI_VIDEO_MODE_EN BIT(1)
+#define DSI_CMD_MODE_EN BIT(2)
+
#endif /* DSI_HOST_V2_H */
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index bc76fd0..f12d03a 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -52,6 +52,37 @@
return rc;
}
+static int dsi_update_pconfig(struct mdss_panel_data *pdata,
+ int mode)
+{
+ int ret = 0;
+ struct mdss_panel_info *pinfo = &pdata->panel_info;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ if (!pdata)
+ return -ENODEV;
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ if (mode == DSI_CMD_MODE) {
+ pinfo->mipi.mode = DSI_CMD_MODE;
+ pinfo->type = MIPI_CMD_PANEL;
+ pinfo->mipi.vsync_enable = 1;
+ pinfo->mipi.hw_vsync_mode = 1;
+ } else {
+ pinfo->mipi.mode = DSI_VIDEO_MODE;
+ pinfo->type = MIPI_VIDEO_PANEL;
+ pinfo->mipi.vsync_enable = 0;
+ pinfo->mipi.hw_vsync_mode = 0;
+ }
+
+ ctrl_pdata->panel_mode = pinfo->mipi.mode;
+ mdss_panel_get_dst_fmt(pinfo->bpp, pinfo->mipi.mode,
+ pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format));
+ pinfo->cont_splash_enabled = 0;
+
+ return ret;
+}
+
static int dsi_panel_handler(struct mdss_panel_data *pdata, int enable)
{
int rc = 0;
@@ -64,19 +95,47 @@
panel_data);
if (enable) {
- dsi_ctrl_gpio_request(ctrl_pdata);
- mdss_dsi_panel_reset(pdata, 1);
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ if (pdata->panel_info.type == MIPI_CMD_PANEL)
+ dsi_ctrl_gpio_request(ctrl_pdata);
+ mdss_dsi_panel_reset(pdata, 1);
+ }
pdata->panel_info.panel_power_on = 1;
- rc = ctrl_pdata->on(pdata);
- if (rc)
- pr_err("dsi_panel_handler panel on failed %d\n", rc);
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ rc = ctrl_pdata->on(pdata);
+ if (rc)
+ pr_err("%s: panel on failed!\n", __func__);
+ }
+ if (pdata->panel_info.type == MIPI_CMD_PANEL &&
+ pdata->panel_info.dynamic_switch_pending) {
+ dsi_ctrl_gpio_request(ctrl_pdata);
+ mdss_dsi_set_tear_on(ctrl_pdata);
+ }
} else {
+ msm_dsi_sw_reset();
if (dsi_intf.op_mode_config)
dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
- rc = ctrl_pdata->off(pdata);
+ if (pdata->panel_info.dynamic_switch_pending) {
+ pr_info("%s: switching to %s mode\n", __func__,
+ (pdata->panel_info.mipi.mode ? "video" : "command"));
+ if (pdata->panel_info.type == MIPI_CMD_PANEL) {
+ ctrl_pdata->switch_mode(pdata, DSI_VIDEO_MODE);
+ dsi_ctrl_gpio_free(ctrl_pdata);
+ } else if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
+ ctrl_pdata->switch_mode(pdata, DSI_CMD_MODE);
+ dsi_ctrl_gpio_request(ctrl_pdata);
+ mdss_dsi_set_tear_off(ctrl_pdata);
+ dsi_ctrl_gpio_free(ctrl_pdata);
+ }
+ }
+ if (!pdata->panel_info.dynamic_switch_pending)
+ rc = ctrl_pdata->off(pdata);
pdata->panel_info.panel_power_on = 0;
- mdss_dsi_panel_reset(pdata, 0);
- dsi_ctrl_gpio_free(ctrl_pdata);
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ if (pdata->panel_info.type == MIPI_CMD_PANEL)
+ mdss_dsi_panel_reset(pdata, 0);
+ dsi_ctrl_gpio_free(ctrl_pdata);
+ }
}
return rc;
}
@@ -138,6 +197,9 @@
case MDSS_EVENT_PANEL_CLK_CTRL:
rc = dsi_clk_ctrl(pdata, (int)arg);
break;
+ case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
+ rc = dsi_update_pconfig(pdata, (int)(unsigned long) arg);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
@@ -158,7 +220,8 @@
__func__, __LINE__);
ctrl_pdata->disp_te_gpio = -1;
- if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE) {
+ if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE ||
+ ctrl_pdata->panel_data.panel_info.mipi.dynamic_switch_enabled) {
ctrl_pdata->disp_te_gpio = of_get_named_gpio(np,
"qcom,platform-te-gpio", 0);
if (!gpio_is_valid(ctrl_pdata->disp_te_gpio))
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index b8c91da..1474570 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -56,4 +56,5 @@
int mdp3_panel_get_boot_cfg(void);
+void msm_dsi_sw_reset(void);
#endif /* DSI_V2_H */
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 8acb9b0..f448c46 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -672,16 +672,16 @@
mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
- rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
- if (rc)
- pr_debug("fail to stop the MDP3 dma\n");
-
-
if (panel->event_handler)
rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
if (rc)
pr_err("fail to turn off the panel\n");
+ rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+ if (rc)
+ pr_debug("fail to stop the MDP3 dma\n");
+ msleep(20);
+
mdp3_irq_deregister();
pr_debug("mdp3_ctrl_off stop clock\n");
@@ -708,10 +708,12 @@
mdp3_session->in_splash_screen = 0;
off_error:
mdp3_session->status = 0;
- mdp3_bufq_deinit(&mdp3_session->bufq_out);
- if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
- mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
- mdp3_bufq_deinit(&mdp3_session->bufq_in);
+ if (!panel->panel_info.dynamic_switch_pending) {
+ mdp3_bufq_deinit(&mdp3_session->bufq_out);
+ if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
+ mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
+ mdp3_bufq_deinit(&mdp3_session->bufq_in);
+ }
}
mutex_unlock(&mdp3_session->lock);
return 0;
@@ -1775,6 +1777,48 @@
return rc;
}
+static int mdp3_update_panel_info(struct msm_fb_data_type *mfd, int mode)
+{
+ int ret = 0;
+ struct mdp3_session_data *mdp3_session;
+ struct mdss_panel_data *panel;
+ u32 intf_type = 0;
+
+ if (!mfd || !mfd->mdp.private1)
+ return -EINVAL;
+
+ mdp3_session = mfd->mdp.private1;
+ panel = mdp3_session->panel;
+
+ if (!panel->event_handler)
+ return 0;
+ ret = panel->event_handler(panel, MDSS_EVENT_DSI_DYNAMIC_SWITCH,
+ (void *)(unsigned long)mode);
+ if (ret)
+ pr_err("Dynamic switch to %s mode failed!\n",
+ mode ? "command" : "video");
+ if (mode == 1)
+ mfd->panel.type = MIPI_CMD_PANEL;
+ else
+ mfd->panel.type = MIPI_VIDEO_PANEL;
+
+ if (mfd->panel.type != MIPI_VIDEO_PANEL)
+ mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done;
+
+ intf_type = mdp3_ctrl_get_intf_type(mfd);
+ mdp3_session->intf->cfg.type = intf_type;
+ mdp3_session->intf->available = 1;
+ mdp3_session->intf->in_use = 1;
+ mdp3_res->intf[intf_type].in_use = 1;
+
+ mdp3_intf_init(mdp3_session->intf);
+
+ mdp3_session->dma->output_config.out_sel = intf_type;
+ mdp3_session->status = mdp3_session->intf->active;
+
+ return 0;
+}
+
int mdp3_ctrl_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
@@ -1797,6 +1841,7 @@
mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff;
mdp3_interface->lut_update = mdp3_ctrl_lut_update;
+ mdp3_interface->configure_panel = mdp3_update_panel_info;
mdp3_session = kmalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
if (!mdp3_session) {
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 8fa04cd..993645a 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -62,6 +62,9 @@
panel_data);
pr_debug("%s: enable=%d\n", __func__, enable);
+ if (pdata->panel_info.dynamic_switch_pending)
+ return 0;
+
if (enable) {
ret = msm_dss_enable_vreg(
ctrl_pdata->power_data.vreg_config,
@@ -594,6 +597,31 @@
return ret;
}
+static int mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+ int mode)
+{
+ int ret = 0;
+ struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
+
+ if (mode == DSI_CMD_MODE) {
+ pinfo->mipi.mode = DSI_CMD_MODE;
+ pinfo->type = MIPI_CMD_PANEL;
+ pinfo->mipi.vsync_enable = 1;
+ pinfo->mipi.hw_vsync_mode = 1;
+ } else { /*video mode*/
+ pinfo->mipi.mode = DSI_VIDEO_MODE;
+ pinfo->type = MIPI_VIDEO_PANEL;
+ pinfo->mipi.vsync_enable = 0;
+ pinfo->mipi.hw_vsync_mode = 0;
+ }
+
+ ctrl_pdata->panel_mode = pinfo->mipi.mode;
+ mdss_panel_get_dst_fmt(pinfo->bpp, pinfo->mipi.mode,
+ pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format));
+ pinfo->cont_splash_enabled = 0;
+
+ return ret;
+}
static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
int enable)
{
@@ -727,11 +755,13 @@
mipi = &pdata->panel_info.mipi;
if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
- ret = ctrl_pdata->on(pdata);
- if (ret) {
- pr_err("%s: unable to initialize the panel\n",
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ ret = ctrl_pdata->on(pdata);
+ if (ret) {
+ pr_err("%s: unable to initialize the panel\n",
__func__);
- return ret;
+ return ret;
+ }
}
ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
}
@@ -784,6 +814,17 @@
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+ if (pdata->panel_info.dynamic_switch_pending) {
+ pr_info("%s: switching to %s mode\n", __func__,
+ (pdata->panel_info.mipi.mode ? "video" : "command"));
+ if (pdata->panel_info.type == MIPI_CMD_PANEL) {
+ ctrl_pdata->switch_mode(pdata, DSI_VIDEO_MODE);
+ } else if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
+ ctrl_pdata->switch_mode(pdata, DSI_CMD_MODE);
+ mdss_dsi_set_tear_off(ctrl_pdata);
+ }
+ }
+
if (pdata->panel_info.type == MIPI_CMD_PANEL) {
if (mipi->vsync_enable && mipi->hw_vsync_mode
&& gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
@@ -792,10 +833,12 @@
}
if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
- ret = ctrl_pdata->off(pdata);
- if (ret) {
- pr_err("%s: Panel OFF failed\n", __func__);
- return ret;
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ ret = ctrl_pdata->off(pdata);
+ if (ret) {
+ pr_err("%s: Panel OFF failed\n", __func__);
+ return ret;
+ }
}
ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
}
@@ -1037,6 +1080,9 @@
case MDSS_EVENT_REGISTER_RECOVERY_HANDLER:
rc = mdss_dsi_register_recovery_handler(ctrl_pdata,
(struct mdss_panel_recovery *)arg);
+ case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
+ rc = mdss_dsi_update_panel_config(ctrl_pdata,
+ (int)(unsigned long) arg);
break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 5ab06e0..609b7ce 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -243,6 +243,7 @@
int (*partial_update_fnc) (struct mdss_panel_data *pdata);
int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+ void (*switch_mode) (struct mdss_panel_data *pdata, int mode);
struct mdss_panel_data panel_data;
unsigned char *ctrl_base;
struct dss_io_data ctrl_io;
@@ -286,6 +287,9 @@
struct dsi_panel_cmds on_cmds;
struct dsi_panel_cmds off_cmds;
+ struct dsi_panel_cmds video2cmd;
+ struct dsi_panel_cmds cmd2video;
+
struct dcs_cmd_list cmdlist;
struct completion dma_comp;
struct completion mdp_comp;
@@ -364,6 +368,8 @@
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
bool cmd_cfg_cont_splash);
+int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
+ char *dst_format);
int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl,
struct mdss_panel_recovery *recovery);
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 0e1cd66..1ac37dc 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -317,6 +317,36 @@
return rc;
}
+static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata,
+ int mode)
+{
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mipi_panel_info *mipi;
+ struct dsi_panel_cmds *pcmds;
+
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return;
+ }
+
+ mipi = &pdata->panel_info.mipi;
+
+ if (!mipi->dynamic_switch_enabled)
+ return;
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ if (mode == DSI_CMD_MODE)
+ pcmds = &ctrl_pdata->video2cmd;
+ else
+ pcmds = &ctrl_pdata->cmd2video;
+
+ mdss_dsi_panel_cmds_send(ctrl_pdata, pcmds);
+
+ return;
+}
+
static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
u32 bl_level)
{
@@ -524,11 +554,16 @@
len -= dchdr->dlen;
}
- data = of_get_property(np, link_key, NULL);
- if (data && !strcmp(data, "dsi_hs_mode"))
- pcmds->link_state = DSI_HS_MODE;
- else
- pcmds->link_state = DSI_LP_MODE;
+ /*Set default link state to LP Mode*/
+ pcmds->link_state = DSI_LP_MODE;
+
+ if (link_key) {
+ data = of_get_property(np, link_key, NULL);
+ if (data && !strcmp(data, "dsi_hs_mode"))
+ pcmds->link_state = DSI_HS_MODE;
+ else
+ pcmds->link_state = DSI_LP_MODE;
+ }
pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__,
pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state);
@@ -541,7 +576,7 @@
}
-static int mdss_panel_dt_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
+int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
char *dst_format)
{
int rc = 0;
@@ -788,6 +823,25 @@
pr_info("%s: ulps feature %s", __func__,
(pinfo->ulps_feature_enabled ? "enabled" : "disabled"));
+ pinfo->mipi.dynamic_switch_enabled = of_property_read_bool(np,
+ "qcom,dynamic-mode-switch-enabled");
+
+ if (pinfo->mipi.dynamic_switch_enabled) {
+ mdss_dsi_parse_dcs_cmds(np, &ctrl->video2cmd,
+ "qcom,video-to-cmd-mode-switch-commands", NULL);
+
+ mdss_dsi_parse_dcs_cmds(np, &ctrl->cmd2video,
+ "qcom,cmd-to-video-mode-switch-commands", NULL);
+
+ if (!ctrl->video2cmd.cmd_cnt || !ctrl->cmd2video.cmd_cnt) {
+ pr_warn("No commands specified for dynamic switch\n");
+ pinfo->mipi.dynamic_switch_enabled = 0;
+ }
+ }
+
+ pr_info("%s: dynamic switch feature enabled: %d", __func__,
+ pinfo->mipi.dynamic_switch_enabled);
+
return 0;
}
@@ -845,9 +899,11 @@
tmp = 0;
data = of_get_property(np, "qcom,mdss-dsi-pixel-packing", NULL);
if (data && !strcmp(data, "loose"))
- tmp = 1;
- rc = mdss_panel_dt_get_dst_fmt(pinfo->bpp,
- pinfo->mipi.mode, tmp,
+ pinfo->mipi.pixel_packing = 1;
+ else
+ pinfo->mipi.pixel_packing = 0;
+ rc = mdss_panel_get_dst_fmt(pinfo->bpp,
+ pinfo->mipi.mode, pinfo->mipi.pixel_packing,
&(pinfo->mipi.dst_format));
if (rc) {
pr_debug("%s: problem determining dst format. Set Default\n",
@@ -1119,9 +1175,13 @@
pr_info("%s: Continuous splash %s", __func__,
pinfo->cont_splash_enabled ? "enabled" : "disabled");
+ pinfo->dynamic_switch_pending = false;
+ pinfo->is_lpm_mode = false;
+
ctrl_pdata->on = mdss_dsi_panel_on;
ctrl_pdata->off = mdss_dsi_panel_off;
ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
+ ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode;
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index a66f4b6..511fa00 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -96,6 +96,7 @@
static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
int event, void *arg);
+static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd);
void mdss_fb_no_update_notify_timer_cb(unsigned long data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
@@ -393,6 +394,91 @@
return ret;
}
+/*
+ * mdss_fb_lpm_enable() - Function to Control LowPowerMode
+ * @mfd: Framebuffer data structure for display
+ * @mode: Enabled/Disable LowPowerMode
+ * 1: Enter into LowPowerMode
+ * 0: Exit from LowPowerMode
+ *
+ * This Function dynamically switches to and from LowPowerMode
+ * based on the argument @mode.
+ */
+static int mdss_fb_lpm_enable(struct msm_fb_data_type *mfd, int mode)
+{
+ int ret = 0;
+ u32 bl_lvl = 0;
+ struct mdss_panel_info *pinfo = NULL;
+ struct mdss_panel_data *pdata;
+
+ if (!mfd || !mfd->panel_info)
+ return -EINVAL;
+
+ pinfo = mfd->panel_info;
+
+ if (!pinfo->mipi.dynamic_switch_enabled) {
+ pr_warn("Panel does not support dynamic switch!\n");
+ return 0;
+ }
+
+ if (mode == pinfo->mipi.mode) {
+ pr_debug("Already in requested mode!\n");
+ return 0;
+ }
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+
+ pr_debug("Enter mode: %d\n", mode);
+ pdata->panel_info.dynamic_switch_pending = true;
+
+ mutex_lock(&mfd->bl_lock);
+ bl_lvl = mfd->bl_level;
+ mdss_fb_set_backlight(mfd, 0);
+ mutex_unlock(&mfd->bl_lock);
+
+ lock_fb_info(mfd->fbi);
+ ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
+ mfd->op_enable);
+ if (ret) {
+ pr_err("can't turn off display!\n");
+ unlock_fb_info(mfd->fbi);
+ return ret;
+ }
+
+ mfd->op_enable = false;
+
+ ret = mfd->mdp.configure_panel(mfd, mode);
+ mdss_fb_set_mdp_sync_pt_threshold(mfd);
+
+ mfd->op_enable = true;
+
+ ret = mdss_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,
+ mfd->op_enable);
+ if (ret) {
+ pr_err("can't turn on display!\n");
+ unlock_fb_info(mfd->fbi);
+ return ret;
+ }
+ unlock_fb_info(mfd->fbi);
+
+ mutex_lock(&mfd->bl_lock);
+ mfd->bl_updated = true;
+ mdss_fb_set_backlight(mfd, bl_lvl);
+ mutex_unlock(&mfd->bl_lock);
+
+ pdata->panel_info.dynamic_switch_pending = false;
+ pdata->panel_info.is_lpm_mode = mode ? 1 : 0;
+
+ if (ret) {
+ pr_err("can't turn on display!\n");
+ return ret;
+ }
+
+ pr_debug("Exit mode: %d\n", mode);
+
+ return 0;
+}
+
static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
static DEVICE_ATTR(msm_fb_split, S_IRUGO, mdss_fb_get_split, NULL);
static DEVICE_ATTR(show_blank_event, S_IRUGO, mdss_mdp_show_blank_event, NULL);
@@ -539,6 +625,21 @@
__mdss_fb_sync_buf_done_callback;
}
+ mdss_fb_set_mdp_sync_pt_threshold(mfd);
+
+ if (mfd->mdp.splash_init_fnc)
+ mfd->mdp.splash_init_fnc(mfd);
+
+ INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);
+
+ return rc;
+}
+
+static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd)
+{
+ if (!mfd)
+ return;
+
switch (mfd->panel.type) {
case WRITEBACK_PANEL:
mfd->mdp_sync_pt_data.threshold = 1;
@@ -553,15 +654,7 @@
mfd->mdp_sync_pt_data.retire_threshold = 0;
break;
}
-
- if (mfd->mdp.splash_init_fnc)
- mfd->mdp.splash_init_fnc(mfd);
-
- INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);
-
- return rc;
}
-
static int mdss_fb_remove(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
@@ -933,6 +1026,7 @@
static int mdss_fb_blank(int blank_mode, struct fb_info *info)
{
+ struct mdss_panel_data *pdata;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
mdss_fb_pan_idle(mfd);
@@ -943,6 +1037,18 @@
mfd->suspend.panel_power_on = false;
return 0;
}
+ pr_debug("mode: %d\n", blank_mode);
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+
+ if (pdata->panel_info.is_lpm_mode &&
+ blank_mode == FB_BLANK_UNBLANK) {
+ pr_debug("panel is in lpm mode\n");
+ mfd->mdp.configure_panel(mfd, 0);
+ mdss_fb_set_mdp_sync_pt_threshold(mfd);
+ pdata->panel_info.is_lpm_mode = false;
+ }
+
return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
@@ -2377,6 +2483,7 @@
int ret = -ENOSYS;
struct mdp_buf_sync buf_sync;
struct msm_sync_pt_data *sync_pt_data = NULL;
+ unsigned int dsi_mode = 0;
if (!info || !info->par)
return -EINVAL;
@@ -2443,6 +2550,16 @@
ret = mdss_fb_display_commit(info, argp);
break;
+ case MSMFB_LPM_ENABLE:
+ ret = copy_from_user(&dsi_mode, argp, sizeof(dsi_mode));
+ if (ret) {
+ pr_err("%s: MSMFB_LPM_ENABLE ioctl failed\n", __func__);
+ goto exit;
+ }
+
+ ret = mdss_fb_lpm_enable(mfd, dsi_mode);
+ break;
+
default:
if (mfd->mdp.ioctl_handler)
ret = mfd->mdp.ioctl_handler(mfd, cmd, argp);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index ce0a7f9..5ab3d41 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -129,6 +129,7 @@
struct msm_sync_pt_data *(*get_sync_fnc)(struct msm_fb_data_type *mfd,
const struct mdp_buf_sync *buf_sync);
void (*check_dsi_status)(struct work_struct *work, uint32_t interval);
+ int (*configure_panel)(struct msm_fb_data_type *mfd, int mode);
void *private1;
};
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 2141659..f371f9c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -3049,6 +3049,27 @@
return 0;
}
+static int mdss_mdp_update_panel_info(struct msm_fb_data_type *mfd, int mode)
+{
+ int ret = 0;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+ struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
+
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_DYNAMIC_SWITCH,
+ (void *)(unsigned long)mode);
+ if (ret)
+ pr_err("Dynamic switch to %s mode failed!\n",
+ mode ? "command" : "video");
+ /*
+ * Destroy current ctrl sturcture as this is
+ * going to be re-initialized with the requested mode.
+ */
+ mdss_mdp_ctl_destroy(mdp5_data->ctl);
+ mdp5_data->ctl = NULL;
+
+ return 0;
+}
+
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
@@ -3067,6 +3088,7 @@
mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff;
mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get;
mdp5_interface->splash_init_fnc = mdss_mdp_splash_init;
+ mdp5_interface->configure_panel = mdss_mdp_update_panel_info;
mdp5_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
if (!mdp5_data) {
@@ -3117,7 +3139,10 @@
pr_err("Error dfps sysfs creation ret=%d\n", rc);
goto init_fail;
}
- } else if (mfd->panel_info->type == MIPI_CMD_PANEL) {
+ }
+
+ if (mfd->panel_info->mipi.dynamic_switch_enabled ||
+ mfd->panel_info->type == MIPI_CMD_PANEL) {
rc = __vsync_retire_setup(mfd);
if (IS_ERR_VALUE(rc)) {
pr_err("unable to create vsync timeline\n");
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index c43cdd3..084cba4 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -132,6 +132,10 @@
* event arguments can have one of these values:
* - 0: Disable ULPS mode
* - 1: Enable ULPS mode
+ * @MDSS_EVENT_DSI_DYNAMIC_SWITCH: Event to update the dsi driver structures
+ * based on the dsi mode passed as argument.
+ * - 0: update to video mode
+ * - 1: update to command mode
*/
enum mdss_intf_events {
MDSS_EVENT_RESET = 1,
@@ -152,6 +156,7 @@
MDSS_EVENT_ENABLE_PARTIAL_UPDATE,
MDSS_EVENT_DSI_ULPS_CTRL,
MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
+ MDSS_EVENT_DSI_DYNAMIC_SWITCH,
};
struct lcd_panel_info {
@@ -222,6 +227,9 @@
char stream; /* 0 or 1 */
char mdp_trigger;
char dma_trigger;
+ /*Dynamic Switch Support*/
+ bool dynamic_switch_enabled;
+ u32 pixel_packing;
u32 dsi_pclk_rate;
/* The packet-size should not bet changed */
char no_max_pkt_size;
@@ -337,6 +345,9 @@
u32 panel_power_on;
uint32_t panel_dead;
+ bool dynamic_switch_pending;
+ bool is_lpm_mode;
+
struct mdss_mdp_pp_tear_check te;
struct lcd_panel_info lcdc;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 34e383e..584ffe7 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -64,7 +64,8 @@
goto mdss_dsi_clk_err;
}
- if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) {
+ if ((ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) ||
+ ctrl_pdata->panel_data.panel_info.mipi.dynamic_switch_enabled) {
ctrl_pdata->mmss_misc_ahb_clk = clk_get(dev, "core_mmss_clk");
if (IS_ERR(ctrl_pdata->mmss_misc_ahb_clk)) {
rc = PTR_ERR(ctrl_pdata->mmss_misc_ahb_clk);
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index fd2cc6c..b295fcc 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -81,6 +81,7 @@
#define MSMFB_ASYNC_BLIT _IOW(MSMFB_IOCTL_MAGIC, 168, unsigned int)
#define MSMFB_OVERLAY_PREPARE _IOWR(MSMFB_IOCTL_MAGIC, 169, \
struct mdp_overlay_list)
+#define MSMFB_LPM_ENABLE _IOWR(MSMFB_IOCTL_MAGIC, 170, unsigned int)
#define FB_TYPE_3D_PANEL 0x10101010
#define MDP_IMGTYPE2_START 0x10000
#define MSMFB_DRIVER_VERSION 0xF9E8D701
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 3844f41..1a94910 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -509,6 +509,7 @@
* @usb_core_id: Identifies the usb core controlled by this usb_gadget.
* Used in case of more then one core operates concurrently.
* @streaming_enabled: Enable streaming mode with usb core.
+ * @xfer_isr_count: UI (transfer complete) interrupts count
*
* Gadgets have a mostly-portable "gadget driver" implementing device
* functions, handling all usb configurations and interfaces. Gadget
@@ -548,6 +549,7 @@
u8 usb_core_id;
bool l1_supported;
bool streaming_enabled;
+ u32 xfer_isr_count;
};
static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index d9e1f1d..56b2b86 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -6919,9 +6919,6 @@
hotcpu_notifier(cpuset_cpu_active, CPU_PRI_CPUSET_ACTIVE);
hotcpu_notifier(cpuset_cpu_inactive, CPU_PRI_CPUSET_INACTIVE);
- /* RT runtime code needs to handle some hotplug events */
- hotcpu_notifier(update_runtime, 0);
-
init_hrtick();
/* Move init over to a non-isolated CPU */
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 3d4b1e2..e32ab1d 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -691,15 +691,6 @@
}
}
-static void disable_runtime(struct rq *rq)
-{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&rq->lock, flags);
- __disable_runtime(rq);
- raw_spin_unlock_irqrestore(&rq->lock, flags);
-}
-
static void __enable_runtime(struct rq *rq)
{
rt_rq_iter_t iter;
@@ -724,37 +715,6 @@
}
}
-static void enable_runtime(struct rq *rq)
-{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&rq->lock, flags);
- __enable_runtime(rq);
- raw_spin_unlock_irqrestore(&rq->lock, flags);
-}
-
-int update_runtime(struct notifier_block *nfb, unsigned long action, void *hcpu)
-{
- int cpu = (int)(long)hcpu;
-
- switch (action) {
- case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
- disable_runtime(cpu_rq(cpu));
- return NOTIFY_OK;
-
- case CPU_DOWN_FAILED:
- case CPU_DOWN_FAILED_FROZEN:
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- enable_runtime(cpu_rq(cpu));
- return NOTIFY_OK;
-
- default:
- return NOTIFY_DONE;
- }
-}
-
static int balance_runtime(struct rt_rq *rt_rq)
{
int more = 0;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 34fe64f..73ae84a 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -878,7 +878,6 @@
extern void sched_init_granularity(void);
extern void update_max_interval(void);
extern void update_group_power(struct sched_domain *sd, int cpu);
-extern int update_runtime(struct notifier_block *nfb, unsigned long action, void *hcpu);
extern void init_sched_rt_class(void);
extern void init_sched_fair_class(void);
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 87f05b2..8e64f2f 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -248,26 +248,33 @@
struct net *net = sock_net(sk);
gid_t group = current_egid();
gid_t range[2];
- struct group_info *group_info = get_current_groups();
- int i, j, count = group_info->ngroups;
+ struct group_info *group_info;
+ int i, j, count ;
+ int ret = 0;
inet_get_ping_group_range_net(net, range, range+1);
if (range[0] <= group && group <= range[1])
return 0;
+ group_info = get_current_groups();
+ count = group_info->ngroups;
for (i = 0; i < group_info->nblocks; i++) {
int cp_count = min_t(int, NGROUPS_PER_BLOCK, count);
for (j = 0; j < cp_count; j++) {
group = group_info->blocks[i][j];
if (range[0] <= group && group <= range[1])
- return 0;
+ goto out_release_group;
}
count -= cp_count;
}
- return -EACCES;
+ ret = -EACCES;
+
+out_release_group:
+ put_group_info(group_info);
+ return ret;
}
EXPORT_SYMBOL_GPL(ping_init_sock);
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index 548d655..f503aa2 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -41,6 +41,7 @@
allowed_warnings = set([
"return_address.c:62",
+ "hci_conn.c:407",
])
# Capture the name of the object file, can find it.