summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c100
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_aux.c16
3 files changed, 89 insertions, 29 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index 516cbdc9192b..caaedf2f0ff6 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -1303,17 +1303,23 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
return mdss_dp_on_hpd(dp_drv);
}
-static void mdss_dp_reset_test_data(struct mdss_dp_drv_pdata *dp)
+static inline void mdss_dp_reset_test_data(struct mdss_dp_drv_pdata *dp)
{
dp->test_data = (const struct dpcd_test_request){ 0 };
}
-static bool mdss_dp_is_link_training_requested(struct mdss_dp_drv_pdata *dp)
+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_link_training_requested(
+ struct mdss_dp_drv_pdata *dp)
{
return (dp->test_data.test_requested == TEST_LINK_TRAINING);
}
-static bool mdss_dp_soft_hpd_reset(struct mdss_dp_drv_pdata *dp)
+static inline bool mdss_dp_soft_hpd_reset(struct mdss_dp_drv_pdata *dp)
{
return mdss_dp_is_link_training_requested(dp) &&
dp->alt_mode.dp_status.hpd_irq;
@@ -2281,7 +2287,7 @@ end:
* This function will send the test response to the sink but only after
* any previous link training has been completed.
*/
-static void mdss_dp_send_test_response(struct mdss_dp_drv_pdata *dp)
+static inline void mdss_dp_send_test_response(struct mdss_dp_drv_pdata *dp)
{
mutex_lock(&dp->train_mutex);
mdss_dp_aux_send_test_response(dp);
@@ -2318,11 +2324,76 @@ static int mdss_dp_hpd_irq_notify_clients(struct mdss_dp_drv_pdata *dp)
}
/**
+ * mdss_dp_link_retraining() - initiates link retraining
+ * @dp: Display Port Driver data
+ *
+ * This function will initiate link retraining by first notifying
+ * DP clients and triggering DP shutdown, and then enabling DP after
+ * notification is done successfully.
+ */
+static inline void mdss_dp_link_retraining(struct mdss_dp_drv_pdata *dp)
+{
+ if (mdss_dp_hpd_irq_notify_clients(dp))
+ return;
+
+ mdss_dp_on_irq(dp);
+}
+
+/**
+ * mdss_dp_process_link_status_update() - processes link status updates
+ * @dp: Display Port Driver data
+ *
+ * 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.
+ */
+static void 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;
+
+ 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);
+}
+
+/**
+ * mdss_dp_process_link_training_request() - processes new training requests
+ * @dp: Display Port Driver data
+ *
+ * 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.
+ */
+static void mdss_dp_process_link_training_request(struct mdss_dp_drv_pdata *dp)
+{
+ if (!mdss_dp_is_link_training_requested(dp))
+ return;
+
+ mdss_dp_send_test_response(dp);
+
+ pr_info("%s link rate = 0x%x, lane count = 0x%x\n",
+ mdss_dp_get_test_name(TEST_LINK_TRAINING),
+ dp->test_data.test_link_rate,
+ dp->test_data.test_lane_count);
+ dp->dpcd.max_lane_count =
+ dp->test_data.test_lane_count;
+ dp->link_rate = dp->test_data.test_link_rate;
+
+ mdss_dp_link_retraining(dp);
+}
+
+/**
* mdss_dp_process_hpd_irq_high() - handle HPD IRQ transition to HIGH
* @dp: Display Port Driver data
*
- * This function will handle the HPD IRQ state transitions from HIGH to HIGH
- * or LOW to HIGH, indicating the start of a new test request.
+ * This function will handle the HPD IRQ state transitions from LOW to HIGH
+ * (including cases when there are back to back HPD IRQ HIGH) indicating
+ * the start of a new link training request or sink status update.
*/
static void mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp)
{
@@ -2332,22 +2403,9 @@ static void mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp)
mdss_dp_aux_parse_sink_status_field(dp);
- if (mdss_dp_is_link_training_requested(dp)) {
- mdss_dp_send_test_response(dp);
-
- pr_info("%s requested: link rate = 0x%x, lane count = 0x%x\n",
- mdss_dp_get_test_name(TEST_LINK_TRAINING),
- dp->test_data.test_link_rate,
- dp->test_data.test_lane_count);
- dp->dpcd.max_lane_count =
- dp->test_data.test_lane_count;
- dp->link_rate = dp->test_data.test_link_rate;
+ mdss_dp_process_link_training_request(dp);
- if (mdss_dp_hpd_irq_notify_clients(dp))
- return;
-
- mdss_dp_on_irq(dp);
- }
+ mdss_dp_process_link_status_update(dp);
mdss_dp_reset_test_data(dp);
diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h
index beeb4d4b1a91..4ba2d20d4261 100644
--- a/drivers/video/fbdev/msm/mdss_dp.h
+++ b/drivers/video/fbdev/msm/mdss_dp.h
@@ -585,5 +585,7 @@ int mdss_dp_aux_set_sink_power_state(struct mdss_dp_drv_pdata *ep, char state);
void mdss_dp_aux_send_test_response(struct mdss_dp_drv_pdata *ep);
void *mdss_dp_get_hdcp_data(struct device *dev);
int mdss_dp_hdcp2p2_init(struct mdss_dp_drv_pdata *dp_drv);
+bool mdss_dp_aux_clock_recovery_done(struct mdss_dp_drv_pdata *ep);
+bool mdss_dp_aux_channel_eq_done(struct mdss_dp_drv_pdata *ep);
#endif /* MDSS_DP_H */
diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c
index 4d9a110cf6af..91066662e793 100644
--- a/drivers/video/fbdev/msm/mdss_dp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_dp_aux.c
@@ -1238,7 +1238,7 @@ static int dp_train_pattern_set_write(struct mdss_dp_drv_pdata *ep,
return dp_aux_write_buf(ep, 0x102, buf, 1, 0);
}
-static int dp_sink_clock_recovery_done(struct mdss_dp_drv_pdata *ep)
+bool mdss_dp_aux_clock_recovery_done(struct mdss_dp_drv_pdata *ep)
{
u32 mask;
u32 data;
@@ -1259,12 +1259,12 @@ static int dp_sink_clock_recovery_done(struct mdss_dp_drv_pdata *ep)
pr_debug("data=%x mask=%x\n", data, mask);
data &= mask;
if (data == mask) /* all done */
- return 1;
+ return true;
- return 0;
+ return false;
}
-static int dp_sink_channel_eq_done(struct mdss_dp_drv_pdata *ep)
+bool mdss_dp_aux_channel_eq_done(struct mdss_dp_drv_pdata *ep)
{
u32 mask;
u32 data;
@@ -1293,9 +1293,9 @@ static int dp_sink_channel_eq_done(struct mdss_dp_drv_pdata *ep)
data &= mask;
if (data == mask)/* all done */
- return 1;
+ return true;
- return 0;
+ return false;
}
void dp_sink_train_set_adjust(struct mdss_dp_drv_pdata *ep)
@@ -1446,7 +1446,7 @@ static int dp_start_link_train_1(struct mdss_dp_drv_pdata *ep)
usleep_range(usleep_time, usleep_time);
dp_link_status_read(ep, 6);
- if (dp_sink_clock_recovery_done(ep)) {
+ if (mdss_dp_aux_clock_recovery_done(ep)) {
ret = 0;
break;
}
@@ -1499,7 +1499,7 @@ static int dp_start_link_train_2(struct mdss_dp_drv_pdata *ep)
dp_link_status_read(ep, 6);
- if (dp_sink_channel_eq_done(ep)) {
+ if (mdss_dp_aux_channel_eq_done(ep)) {
ret = 0;
break;
}