diff options
| author | Ajay Singh Parmar <aparmar@codeaurora.org> | 2016-10-26 15:59:21 -0700 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-10-27 15:18:22 -0700 |
| commit | dec2c9c98d4315290da22136f63e7ac561aefa74 (patch) | |
| tree | 3aeba0b3def501198cc4f4f4f665a9b6f104b451 | |
| parent | dc10995a1b0c5ee71ae0221d72018eeac72bf30a (diff) | |
msm: mdss: dp: add support for link retraining at lower link rate
Add support to restart link training at a lower link rate if the
training has failed at the current rate in Clock Recovery phase
or has reached the maximum number of retries in the Channel
Equalization phase.
Change-Id: Ic7ac0b7ac19d19577d4d1223c8638f17ad9d78af
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dp.c | 109 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dp_aux.c | 89 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/msm_ext_display.c | 8 |
3 files changed, 120 insertions, 86 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index dbaf3247e8bb..391d4c24eb7f 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -57,6 +57,10 @@ static u32 supported_modes[] = { HDMI_VFRMT_4096x2160p60_256_135, HDMI_EVFRMT_4096x2160p24_16_9 }; +static int mdss_dp_off_irq(struct mdss_dp_drv_pdata *dp_drv); +static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata); +static inline void mdss_dp_link_retraining(struct mdss_dp_drv_pdata *dp); + static void mdss_dp_put_dt_clk_data(struct device *dev, struct dss_module_power *module_power) { @@ -1156,19 +1160,27 @@ static void mdss_dp_configure_source_params(struct mdss_dp_drv_pdata *dp, * * Initiates training of the DP main link and checks the state of the main * link after the training is complete. + * + * Return: error code. -EINVAL if any invalid data or -EAGAIN if retraining + * is required. */ -static void mdss_dp_train_main_link(struct mdss_dp_drv_pdata *dp) +static int mdss_dp_train_main_link(struct mdss_dp_drv_pdata *dp) { + int ret = 0; int ready = 0; pr_debug("enter\n"); + ret = mdss_dp_link_train(dp); + if (ret) + goto end; - mdss_dp_link_train(dp); mdss_dp_wait4train(dp); ready = mdss_dp_mainlink_ready(dp, BIT(0)); pr_debug("main link %s\n", ready ? "READY" : "NOT READY"); +end: + return ret; } static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv) @@ -1178,33 +1190,43 @@ static int mdss_dp_on_irq(struct mdss_dp_drv_pdata *dp_drv) struct lane_mapping ln_map; /* wait until link training is completed */ - mutex_lock(&dp_drv->train_mutex); - pr_debug("enter\n"); - orientation = usbpd_get_plug_orientation(dp_drv->pd); - pr_debug("plug orientation = %d\n", orientation); + do { + if (ret == -EAGAIN) { + mdss_dp_mainlink_push_idle(&dp_drv->panel_data); + mdss_dp_off_irq(dp_drv); + } - ret = mdss_dp_get_lane_mapping(dp_drv, orientation, &ln_map); - if (ret) - goto exit; + mutex_lock(&dp_drv->train_mutex); - mdss_dp_phy_share_lane_config(&dp_drv->phy_io, - orientation, dp_drv->dpcd.max_lane_count); + orientation = usbpd_get_plug_orientation(dp_drv->pd); + pr_debug("plug orientation = %d\n", orientation); - ret = mdss_dp_enable_mainlink_clocks(dp_drv); - if (ret) - goto exit; + ret = mdss_dp_get_lane_mapping(dp_drv, orientation, &ln_map); + if (ret) + goto exit; - mdss_dp_mainlink_reset(&dp_drv->ctrl_io); + mdss_dp_phy_share_lane_config(&dp_drv->phy_io, + orientation, dp_drv->dpcd.max_lane_count); - reinit_completion(&dp_drv->idle_comp); + ret = mdss_dp_enable_mainlink_clocks(dp_drv); + if (ret) + goto exit; - mdss_dp_configure_source_params(dp_drv, &ln_map); + mdss_dp_mainlink_reset(&dp_drv->ctrl_io); - mdss_dp_train_main_link(dp_drv); + reinit_completion(&dp_drv->idle_comp); + + mdss_dp_configure_source_params(dp_drv, &ln_map); + + dp_drv->power_on = true; + + ret = mdss_dp_train_main_link(dp_drv); + + mutex_unlock(&dp_drv->train_mutex); + } while (ret == -EAGAIN); - dp_drv->power_on = true; pr_debug("end\n"); exit: @@ -1273,7 +1295,14 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv) mdss_dp_configure_source_params(dp_drv, &ln_map); link_training: - mdss_dp_train_main_link(dp_drv); + dp_drv->power_on = true; + + if (-EAGAIN == mdss_dp_train_main_link(dp_drv)) { + mutex_unlock(&dp_drv->train_mutex); + + mdss_dp_link_retraining(dp_drv); + return 0; + } dp_drv->cont_splash = 0; @@ -1419,18 +1448,23 @@ int mdss_dp_off(struct mdss_panel_data *pdata) return mdss_dp_off_hpd(dp); } -static void mdss_dp_send_cable_notification( +static int mdss_dp_send_cable_notification( struct mdss_dp_drv_pdata *dp, int val) { + int ret = 0; if (!dp) { DEV_ERR("%s: invalid input\n", __func__); - return; + ret = -EINVAL; + goto end; } if (dp && dp->ext_audio_data.intf_ops.hpd) - dp->ext_audio_data.intf_ops.hpd(dp->ext_pdev, + ret = dp->ext_audio_data.intf_ops.hpd(dp->ext_pdev, dp->ext_audio_data.type, val); + +end: + return ret; } static void mdss_dp_audio_codec_wait(struct mdss_dp_drv_pdata *dp) @@ -1450,18 +1484,22 @@ static void mdss_dp_audio_codec_wait(struct mdss_dp_drv_pdata *dp) dp->wait_for_audio_comp = false; } -static void mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, bool enable) +static int mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, bool enable) { + int notified = 0; + if (enable) { - mdss_dp_send_cable_notification(dp, enable); + notified = mdss_dp_send_cable_notification(dp, enable); } else { mdss_dp_set_audio_switch_node(dp, enable); mdss_dp_audio_codec_wait(dp); - mdss_dp_send_cable_notification(dp, enable); + notified = mdss_dp_send_cable_notification(dp, enable); } pr_debug("notify state %s done\n", enable ? "ENABLE" : "DISABLE"); + + return notified; } @@ -2336,15 +2374,20 @@ static int mdss_dp_hpd_irq_notify_clients(struct mdss_dp_drv_pdata *dp) int ret = 0; 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, - irq_comp_timeout); - if (ret <= 0) { - pr_warn("irq_comp timed out\n"); - return -EINVAL; + ret = mdss_dp_notify_clients(dp, false); + + if (!IS_ERR_VALUE(ret) && ret) { + reinit_completion(&dp->irq_comp); + ret = wait_for_completion_timeout(&dp->irq_comp, + irq_comp_timeout); + if (ret <= 0) { + pr_warn("irq_comp timed out\n"); + ret = -EINVAL; + } else { + ret = 0; + } } } diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index 25f726a4c05f..9014e3a02d21 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -801,6 +801,8 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep, cap = &ep->dpcd; bp = rp->data; + memset(cap, 0, sizeof(*cap)); + data = *bp++; /* byte 0 */ cap->major = (data >> 4) & 0x0f; cap->minor = data & 0x0f; @@ -819,8 +821,13 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep, if (data & BIT(7)) cap->enhanced_frame++; - if (data & 0x40) + if (data & 0x40) { cap->flags |= DPCD_TPS3; + pr_debug("pattern 3 supported\n"); + } else { + pr_debug("pattern 3 not supported\n"); + } + data &= 0x0f; cap->max_lane_count = data; if (--rlen <= 0) @@ -886,7 +893,7 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep, data = *bp++; /* byte 9 */ cap->rx_port0_buf_size = (data + 1) * 32; - pr_debug("lane_buf_size=%d", cap->rx_port0_buf_size); + pr_debug("lane_buf_size=%d\n", cap->rx_port0_buf_size); if (--rlen <= 0) return; @@ -1456,6 +1463,7 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep) int tries, old_v_level; int ret = 0; int usleep_time; + int const maximum_retries = 5; pr_debug("Entered++"); @@ -1483,7 +1491,7 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep) if (old_v_level == ep->v_level) { tries++; - if (tries >= 5) { + if (tries >= maximum_retries) { ret = -1; break; /* quit */ } @@ -1505,6 +1513,7 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep) int ret = 0; int usleep_time; char pattern; + int const maximum_retries = 5; pr_debug("Entered++"); @@ -1530,7 +1539,7 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep) } tries++; - if (tries > 4) { + if (tries > maximum_retries) { ret = -1; break; } @@ -1543,47 +1552,27 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep) static int dp_link_rate_down_shift(struct mdss_dp_drv_pdata *ep) { - u32 prate, lrate; - int rate, lane, max_lane; - int changed = 0; - - rate = ep->link_rate; - lane = ep->lane_cnt; - max_lane = ep->dpcd.max_lane_count; - - prate = ep->pixel_rate; - prate /= 1000; /* avoid using 64 biits */ - prate *= ep->bpp; - prate /= 8; /* byte */ - - if (rate > DP_LINK_RATE_162 && rate <= DP_LINK_RATE_MAX) { - rate -= 4; /* reduce rate */ - changed++; - } - - if (changed) { - if (lane >= 1 && lane < max_lane) - lane <<= 1; /* increase lane */ + int ret = 0; - lrate = 270000000; /* 270M */ - lrate /= 1000; /* avoid using 64 bits */ - lrate *= rate; - lrate /= 10; /* byte, 10 bits --> 8 bits */ - lrate *= lane; + if (!ep) + return -EINVAL; - pr_debug("new lrate=%u prate=%u rate=%d lane=%d p=%d b=%d\n", - lrate, prate, rate, lane, ep->pixel_rate, ep->bpp); + switch (ep->link_rate) { + case DP_LINK_RATE_540: + ep->link_rate = DP_LINK_RATE_270; + break; + case DP_LINK_RATE_270: + ep->link_rate = DP_LINK_RATE_162; + break; + case DP_LINK_RATE_162: + default: + ret = -EINVAL; + break; + }; - if (lrate > prate) { - ep->link_rate = rate; - ep->lane_cnt = lane; - pr_debug("new rate=%d %d\n", rate, lane); - return 0; - } - } + pr_debug("new rate=%d\n", ep->link_rate); - /* add calculation later */ - return -EINVAL; + return ret; } int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state) @@ -1620,7 +1609,6 @@ int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp) mdss_dp_aux_set_sink_power_state(dp, SINK_POWER_ON); -train_start: dp->v_level = 0; /* start from default level */ dp->p_level = 0; mdss_dp_config_ctrl(dp); @@ -1630,11 +1618,12 @@ train_start: ret = dp_start_link_train_1(dp); if (ret < 0) { - if (dp_link_rate_down_shift(dp) == 0) { - goto train_start; + if (!dp_link_rate_down_shift(dp)) { + pr_debug("retry with lower rate\n"); + return -EAGAIN; } else { pr_err("Training 1 failed\n"); - ret = -1; + ret = -EINVAL; goto clear; } } @@ -1643,21 +1632,21 @@ train_start: ret = dp_start_link_train_2(dp); if (ret < 0) { - if (dp_link_rate_down_shift(dp) == 0) { - goto train_start; + if (!dp_link_rate_down_shift(dp)) { + pr_debug("retry with lower rate\n"); + return -EAGAIN; } else { pr_err("Training 2 failed\n"); - ret = -1; + ret = -EINVAL; goto clear; } } pr_debug("Training 2 completed successfully\n"); - clear: dp_clear_training_pattern(dp); - if (ret != -1) { + if (ret != -EINVAL) { mdss_dp_setup_tr_unit(&dp->ctrl_io, dp->link_rate, dp->lane_cnt, dp->vic); mdss_dp_state_ctrl(&dp->ctrl_io, ST_SEND_VIDEO); diff --git a/drivers/video/fbdev/msm/msm_ext_display.c b/drivers/video/fbdev/msm/msm_ext_display.c index f6c6548bdaa5..36a5530cb761 100644 --- a/drivers/video/fbdev/msm/msm_ext_display.c +++ b/drivers/video/fbdev/msm/msm_ext_display.c @@ -313,14 +313,14 @@ static void msm_ext_disp_remove_intf_data(struct msm_ext_disp *ext_disp, } } -static void msm_ext_disp_send_cable_notification(struct msm_ext_disp *ext_disp, +static int msm_ext_disp_send_cable_notification(struct msm_ext_disp *ext_disp, enum msm_ext_disp_cable_state new_state) { int state = EXT_DISPLAY_CABLE_STATE_MAX; if (!ext_disp) { pr_err("Invalid params\n"); - return; + return -EINVAL; } state = ext_disp->hdmi_sdev.state; @@ -330,6 +330,8 @@ static void msm_ext_disp_send_cable_notification(struct msm_ext_disp *ext_disp, ext_disp->hdmi_sdev.state == state ? "is same" : "switched to", ext_disp->hdmi_sdev.state); + + return ext_disp->hdmi_sdev.state == state ? 0 : 1; } static int msm_ext_disp_hpd(struct platform_device *pdev, @@ -398,7 +400,7 @@ static int msm_ext_disp_hpd(struct platform_device *pdev, ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; } - msm_ext_disp_send_cable_notification(ext_disp, state); + ret = msm_ext_disp_send_cable_notification(ext_disp, state); pr_debug("Hpd (%d) for display (%s)\n", state, msm_ext_disp_name(type)); |
