summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt2
-rw-r--r--drivers/char/diag/diag_dci.c126
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/drm_edid.c15
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c17
-rw-r--r--drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c8
-rw-r--r--drivers/gpu/drm/msm/msm_atomic.c24
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h3
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c28
-rw-r--r--drivers/soc/qcom/icnss.c109
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_util.c8
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c14
-rw-r--r--include/soc/qcom/icnss.h4
15 files changed, 272 insertions, 95 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 69b096e6ac45..f9500fb1498b 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -948,7 +948,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
The filter can be disabled or changed to another
driver later using sysfs.
- drm_kms_helper.edid_firmware=[<connector>:]<file>[,[<connector>:]<file>]
+ drm.edid_firmware=[<connector>:]<file>[,[<connector>:]<file>]
Broken monitors, graphic adapters, KVMs and EDIDless
panels may send no or incorrect EDID data sets.
This parameter allows to specify an EDID data sets
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index d18768b0e9da..19fbd702c0e6 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -727,32 +727,47 @@ int diag_dci_query_event_mask(struct diag_dci_client_tbl *entry,
return ((*event_mask_ptr & byte_mask) == byte_mask) ? 1 : 0;
}
-static int diag_dci_filter_commands(struct diag_pkt_header_t *header)
+static int diag_dci_filter_commands(struct diag_pkt_header_t *header,
+ int header_len)
{
if (!header)
return -ENOMEM;
- switch (header->cmd_code) {
- case 0x7d: /* Msg Mask Configuration */
- case 0x73: /* Log Mask Configuration */
- case 0x81: /* Event Mask Configuration */
- case 0x82: /* Event Mask Change */
- case 0x60: /* Event Mask Toggle */
- return 1;
- }
+ if (header_len <= 0)
+ return -EIO;
- if (header->cmd_code == 0x4b && header->subsys_id == 0x12) {
- switch (header->subsys_cmd_code) {
- case 0x60: /* Extended Event Mask Config */
- case 0x61: /* Extended Msg Mask Config */
- case 0x62: /* Extended Log Mask Config */
- case 0x20C: /* Set current Preset ID */
- case 0x20D: /* Get current Preset ID */
- case 0x218: /* HDLC Disabled Command */
+ if (header_len) {
+ switch (header->cmd_code) {
+ case 0x7d: /* Msg Mask Configuration */
+ case 0x73: /* Log Mask Configuration */
+ case 0x81: /* Event Mask Configuration */
+ case 0x82: /* Event Mask Change */
+ case 0x60: /* Event Mask Toggle */
+ DIAG_LOG(DIAG_DEBUG_DCI,
+ "diag: command not supported: %d\n",
+ header->cmd_code);
return 1;
}
}
+ if (header_len >= (3*sizeof(uint8_t))) {
+ if (header->cmd_code == 0x4b && header->subsys_id == 0x12) {
+ switch (header->subsys_cmd_code) {
+ case 0x60: /* Extended Event Mask Config */
+ case 0x61: /* Extended Msg Mask Config */
+ case 0x62: /* Extended Log Mask Config */
+ case 0x20C: /* Set current Preset ID */
+ case 0x20D: /* Get current Preset ID */
+ case 0x218: /* HDLC Disabled Command */
+ DIAG_LOG(DIAG_DEBUG_DCI,
+ "diag: command not supported %d %d %d\n",
+ header->cmd_code, header->subsys_id,
+ header->subsys_cmd_code);
+ return 1;
+ }
+ }
+ }
+
return 0;
}
@@ -1796,7 +1811,7 @@ int diag_dci_send_handshake_pkt(int index)
static int diag_dci_process_apps_pkt(struct diag_pkt_header_t *pkt_header,
unsigned char *req_buf, int req_len,
- int tag)
+ int tag, int pkt_header_len)
{
uint8_t cmd_code, subsys_id, i, goto_download = 0;
uint8_t header_len = sizeof(struct diag_dci_pkt_header_t);
@@ -1806,12 +1821,16 @@ static int diag_dci_process_apps_pkt(struct diag_pkt_header_t *pkt_header,
unsigned char *payload_ptr = driver->apps_dci_buf + header_len;
struct diag_dci_pkt_header_t dci_header;
- if (!pkt_header || !req_buf || req_len <= 0 || tag < 0)
+ if (!pkt_header || !req_buf || req_len <= 0 || tag < 0 ||
+ pkt_header_len <= 0)
return -EIO;
- cmd_code = pkt_header->cmd_code;
- subsys_id = pkt_header->subsys_id;
- ss_cmd_code = pkt_header->subsys_cmd_code;
+ if (pkt_header_len >= (sizeof(uint8_t)))
+ cmd_code = pkt_header->cmd_code;
+ if (pkt_header_len >= (2 * sizeof(uint8_t)))
+ subsys_id = pkt_header->subsys_id;
+ if (pkt_header_len >= (3 * sizeof(uint8_t)))
+ ss_cmd_code = pkt_header->subsys_cmd_code;
if (cmd_code == DIAG_CMD_DOWNLOAD) {
*payload_ptr = DIAG_CMD_DOWNLOAD;
@@ -1931,7 +1950,7 @@ fill_buffer:
static int diag_process_dci_pkt_rsp(unsigned char *buf, int len)
{
int ret = DIAG_DCI_TABLE_ERR;
- int common_cmd = 0;
+ int common_cmd = 0, header_len = 0;
struct diag_pkt_header_t *header = NULL;
unsigned char *temp = buf;
unsigned char *req_buf = NULL;
@@ -1947,8 +1966,7 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len)
if (!buf)
return -EIO;
- if (len < (sizeof(struct dci_pkt_req_t) +
- sizeof(struct diag_pkt_header_t)) ||
+ if (len < sizeof(struct dci_pkt_req_t) ||
len > DCI_REQ_BUF_SIZE) {
pr_err("diag: dci: Invalid length %d len in %s", len, __func__);
return -EIO;
@@ -1959,13 +1977,6 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len)
read_len += sizeof(struct dci_pkt_req_t);
req_len -= sizeof(struct dci_pkt_req_t);
req_buf = temp; /* Start of the Request */
- header = (struct diag_pkt_header_t *)temp;
- read_len += sizeof(struct diag_pkt_header_t);
- if (read_len >= DCI_REQ_BUF_SIZE) {
- pr_err("diag: dci: In %s, invalid read_len: %d\n", __func__,
- read_len);
- return -EIO;
- }
mutex_lock(&driver->dci_mutex);
dci_entry = diag_dci_get_client_entry(req_hdr.client_id);
@@ -1976,11 +1987,40 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len)
return DIAG_DCI_NO_REG;
}
+ header = (void *)temp;
+ header_len = len - sizeof(struct dci_pkt_req_t);
+ if (header_len <= 0) {
+ mutex_unlock(&driver->dci_mutex);
+ return -EIO;
+ }
+ if (header_len >= sizeof(uint8_t)) {
+ header->cmd_code = (uint16_t)(*(uint8_t *)temp);
+ read_len += sizeof(uint8_t);
+ }
+ if (header_len >= (2 * sizeof(uint8_t))) {
+ temp += sizeof(uint8_t);
+ header->subsys_id = (uint16_t)(*(uint8_t *)temp);
+ read_len += sizeof(uint8_t);
+ }
+ if (header_len == (3 * sizeof(uint8_t))) {
+ temp += sizeof(uint8_t);
+ header->subsys_cmd_code = (uint16_t)(*(uint8_t *)temp);
+ read_len += sizeof(uint8_t);
+ } else if (header_len >=
+ (2 * sizeof(uint8_t)) + sizeof(uint16_t)) {
+ temp += sizeof(uint8_t);
+ header->subsys_cmd_code = (uint16_t)(*(uint16_t *)temp);
+ read_len += sizeof(uint16_t);
+ }
+ if (read_len > DCI_REQ_BUF_SIZE) {
+ pr_err("diag: dci: In %s, invalid read_len: %d\n", __func__,
+ read_len);
+ mutex_unlock(&driver->dci_mutex);
+ return -EIO;
+ }
+
/* Check if the command is allowed on DCI */
- if (diag_dci_filter_commands(header)) {
- pr_debug("diag: command not supported %d %d %d",
- header->cmd_code, header->subsys_id,
- header->subsys_cmd_code);
+ if (diag_dci_filter_commands(header, header_len)) {
mutex_unlock(&driver->dci_mutex);
return DIAG_DCI_SEND_DATA_FAIL;
}
@@ -2034,14 +2074,18 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len)
/* Check if it is a dedicated Apps command */
ret = diag_dci_process_apps_pkt(header, req_buf, req_len,
- req_entry->tag);
+ req_entry->tag, header_len);
if ((ret == DIAG_DCI_NO_ERROR && !common_cmd) || ret < 0)
return ret;
- reg_entry.cmd_code = header->cmd_code;
- reg_entry.subsys_id = header->subsys_id;
- reg_entry.cmd_code_hi = header->subsys_cmd_code;
- reg_entry.cmd_code_lo = header->subsys_cmd_code;
+ if (header_len >= (sizeof(uint8_t)))
+ reg_entry.cmd_code = header->cmd_code;
+ if (header_len >= (2 * sizeof(uint8_t)))
+ reg_entry.subsys_id = header->subsys_id;
+ if (header_len >= (3 * sizeof(uint8_t))) {
+ reg_entry.cmd_code_hi = header->subsys_cmd_code;
+ reg_entry.cmd_code_lo = header->subsys_cmd_code;
+ }
mutex_lock(&driver->cmd_reg_mutex);
temp_entry = diag_cmd_search(&reg_entry, ALL_PROC);
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 021d8391abea..65d6e1db8db8 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -63,7 +63,7 @@ config DRM_FBDEV_EMULATION
config DRM_LOAD_EDID_FIRMWARE
bool "Allow to specify an EDID data set instead of probing for it"
- depends on DRM_KMS_HELPER
+ depends on DRM
help
Say Y here, if you want to use EDID data to be loaded from the
/lib/firmware directory or one of the provided built-in
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index ea0d5ea57213..d4e3cf4356d7 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -20,12 +20,12 @@ drm-$(CONFIG_PCI) += ati_pcigart.o
drm-$(CONFIG_DRM_PANEL) += drm_panel.o
drm-$(CONFIG_OF) += drm_of.o
drm-$(CONFIG_AGP) += drm_agpsupport.o
+drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
drm-y += $(drm-m)
drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o
-drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index fbd717324328..d3f3e33230f2 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1501,6 +1501,10 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len)
* level, drivers must make all reasonable efforts to expose it as an I2C
* adapter and use drm_get_edid() instead of abusing this function.
*
+ * The EDID may be overridden using debugfs override_edid or firmare EDID
+ * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority
+ * order. Having either of them bypasses actual EDID reads.
+ *
* Return: Pointer to valid EDID or NULL if we couldn't find any.
*/
struct edid *drm_do_get_edid(struct drm_connector *connector,
@@ -1511,6 +1515,17 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
int i, j = 0, valid_extensions = 0;
u8 *block, *new;
bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_UT_KMS);
+ struct edid *override = NULL;
+
+ if (connector->override_edid)
+ override = drm_edid_duplicate((const struct edid *)
+ connector->edid_blob_ptr->data);
+
+ if (!override)
+ override = drm_load_edid_firmware(connector);
+
+ if (!IS_ERR_OR_NULL(override))
+ return override;
if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
return NULL;
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 7c6fc77c0b7b..81dfc23e1c6a 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -199,22 +199,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
goto prune;
}
- if (connector->override_edid) {
- struct edid *edid = (struct edid *) connector->edid_blob_ptr->data;
-
- count = drm_add_edid_modes(connector, edid);
- drm_edid_to_eld(connector, edid);
- } else {
- struct edid *edid = drm_load_edid_firmware(connector);
- if (!IS_ERR_OR_NULL(edid)) {
- drm_mode_connector_update_edid_property(connector, edid);
- count = drm_add_edid_modes(connector, edid);
- drm_edid_to_eld(connector, edid);
- kfree(edid);
- }
- if (count == 0)
- count = (*connector_funcs->get_modes)(connector);
- }
+ count = (*connector_funcs->get_modes)(connector);
if (count == 0 && connector->status == connector_status_connected)
count = drm_add_modes_noedid(connector, 1024, 768);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 252a6289881f..75543c768d45 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019, 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
@@ -123,6 +123,9 @@ static ssize_t debugfs_state_info_read(struct file *file,
dsi_ctrl->clk_info.link_clks.pixel_clk_rate,
dsi_ctrl->clk_info.link_clks.esc_clk_rate);
+ if (len > count)
+ len = count;
+
/* TODO: make sure that this does not exceed 4K */
if (copy_to_user(buff, buf, len)) {
kfree(buf);
@@ -162,6 +165,9 @@ static ssize_t debugfs_reg_dump_read(struct file *file,
"Core clocks are not turned on, cannot read\n");
}
+ if (len > count)
+ len = count;
+
/* TODO: make sure that this does not exceed 4K */
if (copy_to_user(buff, buf, len)) {
kfree(buf);
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 99f89841a74a..8467be8c3f0b 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
* Copyright (C) 2014 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@@ -27,22 +27,26 @@ struct msm_commit {
uint32_t fence;
struct msm_fence_cb fence_cb;
uint32_t crtc_mask;
+ uint32_t plane_mask;
struct kthread_work commit_work;
};
/* block until specified crtcs are no longer pending update, and
* atomically mark them as pending update
*/
-static int start_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
+static int start_atomic(struct msm_drm_private *priv, uint32_t crtc_mask,
+ uint32_t plane_mask)
{
int ret;
spin_lock(&priv->pending_crtcs_event.lock);
ret = wait_event_interruptible_locked(priv->pending_crtcs_event,
- !(priv->pending_crtcs & crtc_mask));
+ !(priv->pending_crtcs & crtc_mask) &&
+ !(priv->pending_planes & plane_mask));
if (ret == 0) {
DBG("start: %08x", crtc_mask);
priv->pending_crtcs |= crtc_mask;
+ priv->pending_planes |= plane_mask;
}
spin_unlock(&priv->pending_crtcs_event.lock);
@@ -51,18 +55,21 @@ static int start_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
/* clear specified crtcs (no longer pending update)
*/
-static void end_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
+static void end_atomic(struct msm_drm_private *priv, uint32_t crtc_mask,
+ uint32_t plane_mask)
{
spin_lock(&priv->pending_crtcs_event.lock);
DBG("end: %08x", crtc_mask);
priv->pending_crtcs &= ~crtc_mask;
+ priv->pending_planes &= ~plane_mask;
wake_up_all_locked(&priv->pending_crtcs_event);
spin_unlock(&priv->pending_crtcs_event.lock);
}
static void commit_destroy(struct msm_commit *commit)
{
- end_atomic(commit->dev->dev_private, commit->crtc_mask);
+ end_atomic(commit->dev->dev_private, commit->crtc_mask,
+ commit->plane_mask);
kfree(commit);
}
@@ -593,7 +600,7 @@ int msm_atomic_commit(struct drm_device *dev,
struct drm_crtc *crtc = state->crtcs[i];
if (!crtc)
continue;
- commit->crtc_mask |= (1 << drm_crtc_index(crtc));
+ commit->crtc_mask |= (1 << i);
}
/*
@@ -608,13 +615,16 @@ int msm_atomic_commit(struct drm_device *dev,
if ((plane->state->fb != new_state->fb) && new_state->fb)
commit_set_fence(commit, new_state->fb);
+
+ commit->plane_mask |= (1 << i);
}
/*
* Wait for pending updates on any of the same crtc's and then
* mark our set of crtc's as busy:
*/
- ret = start_atomic(dev->dev_private, commit->crtc_mask);
+ ret = start_atomic(dev->dev_private, commit->crtc_mask,
+ commit->plane_mask);
if (ret) {
DRM_ERROR("start_atomic failed: %d\n", ret);
commit_destroy(commit);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 87649f7ec3dd..a9c28feb11ce 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@@ -319,6 +319,7 @@ struct msm_drm_private {
/* crtcs pending async atomic updates: */
uint32_t pending_crtcs;
+ uint32_t pending_planes;
wait_queue_head_t pending_crtcs_event;
/* Registered address spaces.. currently this is fixed per # of
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index f021707a53cd..1af55fe257af 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -616,12 +616,9 @@ static void msm_isp_update_framedrop_reg(struct msm_vfe_axi_stream *stream_info,
MSM_VFE_STREAM_STOP_PERIOD;
}
- if (stream_info->undelivered_request_cnt > 0 &&
- drop_reconfig != 1)
+ if (stream_info->undelivered_request_cnt > 0)
stream_info->current_framedrop_period =
MSM_VFE_STREAM_STOP_PERIOD;
- if (stream_info->controllable_output && drop_reconfig == 1)
- stream_info->current_framedrop_period = 1;
/*
* re-configure the period pattern, only if it's not already
* set to what we want
@@ -3624,9 +3621,10 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
(stream_info->undelivered_request_cnt <=
MAX_BUFFERS_IN_HW)
) {
- pr_debug("%s:%d invalid time to request frame %d\n",
+ pr_debug("%s:%d invalid time to request frame %d try drop_reconfig\n",
__func__, __LINE__, frame_id);
vfe_dev->isp_page->drop_reconfig = 1;
+ return 0;
} else if ((vfe_dev->axi_data.src_info[frame_src].active) &&
((frame_id ==
vfe_dev->axi_data.src_info[frame_src].frame_id) ||
@@ -3634,10 +3632,11 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
(stream_info->undelivered_request_cnt <=
MAX_BUFFERS_IN_HW)) {
vfe_dev->isp_page->drop_reconfig = 1;
- pr_debug("%s: vfe_%d request_frame %d cur frame id %d pix %d\n",
+ pr_debug("%s: vfe_%d request_frame %d cur frame id %d pix %d try drop_reconfig\n",
__func__, vfe_dev->pdev->id, frame_id,
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id,
vfe_dev->axi_data.src_info[VFE_PIX_0].active);
+ return 0;
} else if ((vfe_dev->axi_data.src_info[frame_src].active && (frame_id !=
vfe_dev->axi_data.src_info[frame_src].frame_id + vfe_dev->
axi_data.src_info[frame_src].sof_counter_step)) ||
@@ -3658,19 +3657,18 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
if ((frame_src == VFE_PIX_0) && !stream_info->undelivered_request_cnt &&
MSM_VFE_STREAM_STOP_PERIOD !=
stream_info->activated_framedrop_period) {
+ /* wm is reloaded if undelivered_request_cnt is zero.
+ * As per the hw behavior wm should be disabled or skip writing
+ * before reload happens other wise wm could start writing from
+ * middle of the frame and could result in image corruption.
+ * instead of dropping frame in this error scenario use
+ * drop_reconfig flag to process the request in next sof.
+ */
pr_debug("%s:%d vfe %d frame_id %d prev_pattern %x stream_id %x\n",
__func__, __LINE__, vfe_dev->pdev->id, frame_id,
stream_info->activated_framedrop_period,
stream_info->stream_id);
-
- rc = msm_isp_return_empty_buffer(vfe_dev, stream_info,
- user_stream_id, frame_id, buf_index, frame_src);
- if (rc < 0)
- pr_err("%s:%d failed: return_empty_buffer src %d\n",
- __func__, __LINE__, frame_src);
- stream_info->current_framedrop_period =
- MSM_VFE_STREAM_STOP_PERIOD;
- msm_isp_cfg_framedrop_reg(stream_info);
+ vfe_dev->isp_page->drop_reconfig = 1;
return 0;
}
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 17bfb06a5651..714a4f16cd01 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -196,6 +196,8 @@ enum icnss_driver_event_type {
ICNSS_DRIVER_EVENT_REGISTER_DRIVER,
ICNSS_DRIVER_EVENT_UNREGISTER_DRIVER,
ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
+ ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
+ ICNSS_DRIVER_EVENT_IDLE_RESTART,
ICNSS_DRIVER_EVENT_MAX,
};
@@ -303,6 +305,7 @@ enum icnss_driver_state {
ICNSS_REJUVENATE,
ICNSS_BLOCK_SHUTDOWN,
ICNSS_PDR,
+ ICNSS_MODEM_CRASHED,
};
struct ce_irq_list {
@@ -636,6 +639,10 @@ static char *icnss_driver_event_to_str(enum icnss_driver_event_type type)
return "UNREGISTER_DRIVER";
case ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN:
return "PD_SERVICE_DOWN";
+ case ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
+ return "IDLE_SHUTDOWN";
+ case ICNSS_DRIVER_EVENT_IDLE_RESTART:
+ return "IDLE_RESTART";
case ICNSS_DRIVER_EVENT_MAX:
return "EVENT_MAX";
}
@@ -2303,6 +2310,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv)
icnss_call_driver_shutdown(priv);
clear_bit(ICNSS_PDR, &priv->state);
+ clear_bit(ICNSS_MODEM_CRASHED, &priv->state);
clear_bit(ICNSS_REJUVENATE, &priv->state);
clear_bit(ICNSS_PD_RESTART, &priv->state);
priv->is_ssr = false;
@@ -2494,6 +2502,52 @@ out:
return ret;
}
+static int icnss_driver_event_idle_shutdown(void *data)
+{
+ int ret = 0;
+
+ if (!penv->ops || !penv->ops->idle_shutdown)
+ return 0;
+
+ if (test_bit(ICNSS_MODEM_CRASHED, &penv->state) ||
+ test_bit(ICNSS_PDR, &penv->state) ||
+ test_bit(ICNSS_REJUVENATE, &penv->state)) {
+ icnss_pr_err("SSR/PDR is already in-progress during idle shutdown callback\n");
+ ret = -EBUSY;
+ } else {
+ icnss_pr_dbg("Calling driver idle shutdown, state: 0x%lx\n",
+ penv->state);
+ icnss_block_shutdown(true);
+ ret = penv->ops->idle_shutdown(&penv->pdev->dev);
+ icnss_block_shutdown(false);
+ }
+
+ return ret;
+}
+
+static int icnss_driver_event_idle_restart(void *data)
+{
+ int ret = 0;
+
+ if (!penv->ops || !penv->ops->idle_restart)
+ return 0;
+
+ if (test_bit(ICNSS_MODEM_CRASHED, &penv->state) ||
+ test_bit(ICNSS_PDR, &penv->state) ||
+ test_bit(ICNSS_REJUVENATE, &penv->state)) {
+ icnss_pr_err("SSR/PDR is already in-progress during idle restart callback\n");
+ ret = -EBUSY;
+ } else {
+ icnss_pr_dbg("Calling driver idle restart, state: 0x%lx\n",
+ penv->state);
+ icnss_block_shutdown(true);
+ ret = penv->ops->idle_restart(&penv->pdev->dev);
+ icnss_block_shutdown(false);
+ }
+
+ return ret;
+}
+
static void icnss_driver_event_work(struct work_struct *work)
{
struct icnss_driver_event *event;
@@ -2535,6 +2589,12 @@ static void icnss_driver_event_work(struct work_struct *work)
ret = icnss_driver_event_pd_service_down(penv,
event->data);
break;
+ case ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN:
+ ret = icnss_driver_event_idle_shutdown(event->data);
+ break;
+ case ICNSS_DRIVER_EVENT_IDLE_RESTART:
+ ret = icnss_driver_event_idle_restart(event->data);
+ break;
default:
icnss_pr_err("Invalid Event type: %d", event->type);
kfree(event);
@@ -2641,6 +2701,9 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
priv->is_ssr = true;
+ if (notif->crashed)
+ set_bit(ICNSS_MODEM_CRASHED, &priv->state);
+
if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed &&
test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) {
if (!wait_for_completion_timeout(&priv->unblock_shutdown,
@@ -3597,6 +3660,48 @@ out:
}
EXPORT_SYMBOL(icnss_trigger_recovery);
+int icnss_idle_shutdown(struct device *dev)
+{
+ struct icnss_priv *priv = dev_get_drvdata(dev);
+
+ if (!priv) {
+ icnss_pr_err("Invalid drvdata: dev %pK", dev);
+ return -EINVAL;
+ }
+
+ if (test_bit(ICNSS_MODEM_CRASHED, &priv->state) ||
+ test_bit(ICNSS_PDR, &priv->state) ||
+ test_bit(ICNSS_REJUVENATE, &penv->state)) {
+ icnss_pr_err("SSR/PDR is already in-progress during idle shutdown\n");
+ return -EBUSY;
+ }
+
+ return icnss_driver_event_post(ICNSS_DRIVER_EVENT_IDLE_SHUTDOWN,
+ ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
+}
+EXPORT_SYMBOL(icnss_idle_shutdown);
+
+int icnss_idle_restart(struct device *dev)
+{
+ struct icnss_priv *priv = dev_get_drvdata(dev);
+
+ if (!priv) {
+ icnss_pr_err("Invalid drvdata: dev %pK", dev);
+ return -EINVAL;
+ }
+
+ if (test_bit(ICNSS_MODEM_CRASHED, &priv->state) ||
+ test_bit(ICNSS_PDR, &priv->state) ||
+ test_bit(ICNSS_REJUVENATE, &penv->state)) {
+ icnss_pr_err("SSR/PDR is already in-progress during idle restart\n");
+ return -EBUSY;
+ }
+
+ return icnss_driver_event_post(ICNSS_DRIVER_EVENT_IDLE_RESTART,
+ ICNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL);
+}
+EXPORT_SYMBOL(icnss_idle_restart);
+
static int icnss_smmu_init(struct icnss_priv *priv)
{
@@ -4053,6 +4158,10 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
continue;
case ICNSS_PDR:
seq_puts(s, "PDR TRIGGERED");
+ continue;
+ case ICNSS_MODEM_CRASHED:
+ seq_puts(s, "MODEM CRASHED");
+ continue;
}
seq_printf(s, "UNKNOWN-%d", i);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index 4f30f7864bb0..0778e43fe0ff 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2017, 2019, 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
@@ -3742,7 +3742,8 @@ static int hdmi_tx_hdcp_off(struct hdmi_tx_ctrl *hdmi_ctrl)
DEV_DBG("%s: Turning off HDCP\n", __func__);
hdmi_ctrl->hdcp_ops->off(hdmi_ctrl->hdcp_data);
- flush_delayed_work(&hdmi_ctrl->hdcp_cb_work);
+ hdmi_ctrl->hdcp_status = HDCP_STATE_INACTIVE;
+ cancel_delayed_work(&hdmi_ctrl->hdcp_cb_work);
hdmi_ctrl->hdcp_ops = NULL;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c
index c7a9c530eedb..8e854c54bae8 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c
@@ -790,11 +790,13 @@ static void hdmi_ddc_trigger(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
if (mode == TRIGGER_READ && seg) {
DSS_REG_W_ND(io, HDMI_DDC_DATA, BIT(31) | (seg_addr << 8));
DSS_REG_W_ND(io, HDMI_DDC_DATA, seg_num << 8);
+ DSS_REG_W_ND(io, HDMI_DDC_DATA, (ddc_data->dev_addr << 8));
+ } else {
+ /* handle portion #1 */
+ DSS_REG_W_ND(io, HDMI_DDC_DATA,
+ BIT(31) | (ddc_data->dev_addr << 8));
}
- /* handle portion #1 */
- DSS_REG_W_ND(io, HDMI_DDC_DATA, BIT(31) | (ddc_data->dev_addr << 8));
-
/* handle portion #2 */
DSS_REG_W_ND(io, HDMI_DDC_DATA, ddc_data->offset << 8);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 324e5e9ca60d..daeed5d45072 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2019, 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
@@ -5762,12 +5762,14 @@ static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd)
panel_on:
if (mdp5_data->vsync_en) {
- pr_info("reenabling vsync for fb%d\n", mfd->index);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
- rc = ctl->ops.add_vsync_handler(ctl, &ctl->vsync_handler);
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
+ if ((ctl) && (ctl->ops.add_vsync_handler)) {
+ pr_info("reenabling vsync for fb%d\n", mfd->index);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
+ rc = ctl->ops.add_vsync_handler(ctl,
+ &ctl->vsync_handler);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
+ }
}
-
if (IS_ERR_VALUE(rc)) {
pr_err("Failed to turn on fb%d\n", mfd->index);
mdss_mdp_overlay_off(mfd);
diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h
index 4de4cd5e89dc..716e28054e60 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -56,6 +56,8 @@ struct icnss_driver_ops {
int (*suspend_noirq)(struct device *dev);
int (*resume_noirq)(struct device *dev);
int (*uevent)(struct device *dev, struct icnss_uevent_data *uevent);
+ int (*idle_shutdown)(struct device *dev);
+ int (*idle_restart)(struct device *dev);
};
@@ -159,4 +161,6 @@ extern u8 *icnss_get_wlan_mac_address(struct device *dev, uint32_t *num);
extern int icnss_trigger_recovery(struct device *dev);
extern void icnss_block_shutdown(bool status);
extern bool icnss_is_pdr(void);
+extern int icnss_idle_restart(struct device *dev);
+extern int icnss_idle_shutdown(struct device *dev);
#endif /* _ICNSS_WLAN_H_ */