diff options
| author | Tatenda Chipeperekwa <tatendac@codeaurora.org> | 2016-10-25 15:48:05 -0700 |
|---|---|---|
| committer | Tatenda Chipeperekwa <tatendac@codeaurora.org> | 2016-10-25 18:35:00 -0700 |
| commit | 821b280d6a83e16825039c097829f663b2d7f577 (patch) | |
| tree | 3673a684e4a6aa71ee8dc3e9f7d65b937c8bb35e | |
| parent | f8a5f3e06f0309d37e59a24bed76992e8c032f14 (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.c | 64 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dp.h | 14 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dp_aux.c | 29 |
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; |
