summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatenda Chipeperekwa <tatendac@codeaurora.org>2016-10-25 15:48:05 -0700
committerTatenda Chipeperekwa <tatendac@codeaurora.org>2016-10-25 18:35:00 -0700
commit821b280d6a83e16825039c097829f663b2d7f577 (patch)
tree3673a684e4a6aa71ee8dc3e9f7d65b937c8bb35e
parentf8a5f3e06f0309d37e59a24bed76992e8c032f14 (diff)
msm: mdss: dp: process downstream port status change
Add support to process the downstream port status change if it is detected during HPD IRQ. Change-Id: I967f13216859be4c147e03c7ea318958300b2886 Signed-off-by: Tatenda Chipeperekwa <tatendac@codeaurora.org>
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c64
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.h14
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_aux.c29
3 files changed, 99 insertions, 8 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index fa2e47e06503..dea326a2fc76 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -1311,6 +1311,12 @@ static inline bool mdss_dp_is_link_status_updated(struct mdss_dp_drv_pdata *dp)
return dp->link_status.link_status_updated;
}
+static inline bool mdss_dp_is_downstream_port_status_changed(
+ struct mdss_dp_drv_pdata *dp)
+{
+ return dp->link_status.downstream_port_status_changed;
+}
+
static inline bool mdss_dp_is_link_training_requested(
struct mdss_dp_drv_pdata *dp)
{
@@ -2308,6 +2314,7 @@ static int mdss_dp_hpd_irq_notify_clients(struct mdss_dp_drv_pdata *dp)
if (dp->hpd_irq_toggled) {
mdss_dp_notify_clients(dp, false);
+ dp->hpd_irq_clients_notified = true;
reinit_completion(&dp->irq_comp);
ret = wait_for_completion_timeout(&dp->irq_comp,
@@ -2344,19 +2351,24 @@ static inline void mdss_dp_link_retraining(struct mdss_dp_drv_pdata *dp)
* This function will check for changes in the link status, e.g. clock
* recovery done on all lanes, and trigger link training if there is a
* failure/error on the link.
+ *
+ * The function will return 0 if the a link status update has been processed,
+ * otherwise it will return -EINVAL.
*/
-static void mdss_dp_process_link_status_update(struct mdss_dp_drv_pdata *dp)
+static int mdss_dp_process_link_status_update(struct mdss_dp_drv_pdata *dp)
{
if (!mdss_dp_is_link_status_updated(dp) ||
(mdss_dp_aux_channel_eq_done(dp) &&
mdss_dp_aux_clock_recovery_done(dp)))
- return;
+ return -EINVAL;
pr_info("channel_eq_done = %d, clock_recovery_done = %d\n",
mdss_dp_aux_channel_eq_done(dp),
mdss_dp_aux_clock_recovery_done(dp));
mdss_dp_link_retraining(dp);
+
+ return 0;
}
/**
@@ -2366,11 +2378,14 @@ static void mdss_dp_process_link_status_update(struct mdss_dp_drv_pdata *dp)
* This function will handle new link training requests that are initiated by
* the sink. In particular, it will update the requested lane count and link
* link rate, and then trigger the link retraining procedure.
+ *
+ * The function will return 0 if a link training request has been processed,
+ * otherwise it will return -EINVAL.
*/
-static void mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp)
+static int mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp)
{
if (!mdss_dp_is_link_training_requested(dp))
- return;
+ return -EINVAL;
mdss_dp_send_test_response(dp);
@@ -2383,6 +2398,28 @@ static void mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp)
dp->link_rate = dp->test_data.test_link_rate;
mdss_dp_link_retraining(dp);
+
+ return 0;
+}
+
+/**
+ * mdss_dp_process_downstream_port_status_change() - process port status changes
+ * @dp: Display Port Driver data
+ *
+ * This function will handle downstream port updates that are initiated by
+ * the sink. If the downstream port status has changed, the EDID is read via
+ * AUX.
+ *
+ * The function will return 0 if a downstream port update has been
+ * processed, otherwise it will return -EINVAL.
+ */
+static int mdss_dp_process_downstream_port_status_change(
+ struct mdss_dp_drv_pdata *dp)
+{
+ if (!mdss_dp_is_downstream_port_status_changed(dp))
+ return -EINVAL;
+
+ return mdss_dp_edid_read(dp);
}
/**
@@ -2395,16 +2432,27 @@ static void mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp)
*/
static void mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp)
{
+ int ret = 0;
+
pr_debug("enter: HPD IRQ High\n");
dp->hpd_irq_on = true;
mdss_dp_aux_parse_sink_status_field(dp);
- mdss_dp_process_link_training_request(dp);
+ ret = mdss_dp_process_link_training_request(dp);
+ if (!ret)
+ goto exit;
+
+ ret = mdss_dp_process_link_status_update(dp);
+ if (!ret)
+ goto exit;
- mdss_dp_process_link_status_update(dp);
+ ret = mdss_dp_process_downstream_port_status_change(dp);
+ if (!ret)
+ goto exit;
+exit:
mdss_dp_reset_test_data(dp);
pr_debug("done\n");
@@ -2419,9 +2467,13 @@ static void mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp)
*/
static void mdss_dp_process_hpd_irq_low(struct mdss_dp_drv_pdata *dp)
{
+ if (!dp->hpd_irq_clients_notified)
+ return;
+
pr_debug("enter: HPD IRQ low\n");
dp->hpd_irq_on = false;
+ dp->hpd_irq_clients_notified = false;
mdss_dp_update_cable_status(dp, false);
mdss_dp_mainlink_push_idle(&dp->panel_data);
diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h
index 4ba2d20d4261..0d4e8da90da5 100644
--- a/drivers/video/fbdev/msm/mdss_dp.h
+++ b/drivers/video/fbdev/msm/mdss_dp.h
@@ -228,6 +228,18 @@ struct dp_alt_mode {
#define DP_LINK_RATE_MULTIPLIER 27000000
#define DP_MAX_PIXEL_CLK_KHZ 675000
+struct downstream_port_config {
+ /* Byte 02205h */
+ bool dfp_present;
+ u32 dfp_type;
+ bool format_conversion;
+ bool detailed_cap_info_available;
+ /* Byte 02207h */
+ u32 dfp_count;
+ bool msa_timing_par_ignored;
+ bool oui_support;
+};
+
struct dpcd_cap {
char major;
char minor;
@@ -240,6 +252,7 @@ struct dpcd_cap {
u32 flags;
u32 rx_port0_buf_size;
u32 training_read_interval;/* us */
+ struct downstream_port_config downstream_port;
};
struct dpcd_link_status {
@@ -466,6 +479,7 @@ struct mdss_dp_drv_pdata {
bool wait_for_audio_comp;
bool hpd_irq_on;
bool hpd_irq_toggled;
+ bool hpd_irq_clients_notified;
/* event */
struct workqueue_struct *workq;
diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c
index 91066662e793..25f726a4c05f 100644
--- a/drivers/video/fbdev/msm/mdss_dp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_dp_aux.c
@@ -846,11 +846,36 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
if (--rlen <= 0)
return;
- bp += 3; /* skip 5, 6 and 7 */
- rlen -= 3;
+ data = *bp++; /* Byte 5: DOWN_STREAM_PORT_PRESENT */
+ cap->downstream_port.dfp_present = data & BIT(0);
+ cap->downstream_port.dfp_type = data & 0x6;
+ cap->downstream_port.format_conversion = data & BIT(3);
+ cap->downstream_port.detailed_cap_info_available = data & BIT(4);
+ pr_debug("dfp_present = %d, dfp_type = %d\n",
+ cap->downstream_port.dfp_present,
+ cap->downstream_port.dfp_type);
+ pr_debug("format_conversion = %d, detailed_cap_info_available = %d\n",
+ cap->downstream_port.format_conversion,
+ cap->downstream_port.detailed_cap_info_available);
+ if (--rlen <= 0)
+ return;
+
+ bp += 1; /* Skip Byte 6 */
+ rlen -= 1;
if (rlen <= 0)
return;
+ data = *bp++; /* Byte 7: DOWN_STREAM_PORT_COUNT */
+ cap->downstream_port.dfp_count = data & 0x7;
+ cap->downstream_port.msa_timing_par_ignored = data & BIT(6);
+ cap->downstream_port.oui_support = data & BIT(7);
+ pr_debug("dfp_count = %d, msa_timing_par_ignored = %d\n",
+ cap->downstream_port.dfp_count,
+ cap->downstream_port.msa_timing_par_ignored);
+ pr_debug("oui_support = %d\n", cap->downstream_port.oui_support);
+ if (--rlen <= 0)
+ return;
+
data = *bp++; /* byte 8 */
if (data & BIT(1)) {
cap->flags |= DPCD_PORT_0_EDID_PRESENTED;