summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/dp
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/dp')
-rw-r--r--drivers/gpu/drm/msm/dp/dp_audio.c131
-rw-r--r--drivers/gpu/drm/msm/dp/dp_audio.h27
-rw-r--r--drivers/gpu/drm/msm/dp/dp_ctrl.c171
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.c84
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.h6
-rw-r--r--drivers/gpu/drm/msm/dp/dp_drm.c41
-rw-r--r--drivers/gpu/drm/msm/dp/dp_drm.h6
-rw-r--r--drivers/gpu/drm/msm/dp/dp_link.c18
-rw-r--r--drivers/gpu/drm/msm/dp/dp_link.h4
-rw-r--r--drivers/gpu/drm/msm/dp/dp_panel.c12
10 files changed, 218 insertions, 282 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c
index 70fdc9fe228a..f8bfb908f9b4 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.c
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -13,13 +13,13 @@
#include "dp_catalog.h"
#include "dp_audio.h"
+#include "dp_drm.h"
#include "dp_panel.h"
#include "dp_reg.h"
#include "dp_display.h"
#include "dp_utils.h"
struct msm_dp_audio_private {
- struct platform_device *audio_pdev;
struct platform_device *pdev;
struct drm_device *drm_dev;
struct msm_dp_catalog *catalog;
@@ -160,24 +160,11 @@ static void msm_dp_audio_enable(struct msm_dp_audio_private *audio, bool enable)
msm_dp_catalog_audio_enable(catalog, enable);
}
-static struct msm_dp_audio_private *msm_dp_audio_get_data(struct platform_device *pdev)
+static struct msm_dp_audio_private *msm_dp_audio_get_data(struct msm_dp *msm_dp_display)
{
struct msm_dp_audio *msm_dp_audio;
- struct msm_dp *msm_dp_display;
-
- if (!pdev) {
- DRM_ERROR("invalid input\n");
- return ERR_PTR(-ENODEV);
- }
-
- msm_dp_display = platform_get_drvdata(pdev);
- if (!msm_dp_display) {
- DRM_ERROR("invalid input\n");
- return ERR_PTR(-ENODEV);
- }
msm_dp_audio = msm_dp_display->msm_dp_audio;
-
if (!msm_dp_audio) {
DRM_ERROR("invalid msm_dp_audio data\n");
return ERR_PTR(-EINVAL);
@@ -186,68 +173,16 @@ static struct msm_dp_audio_private *msm_dp_audio_get_data(struct platform_device
return container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio);
}
-static int msm_dp_audio_hook_plugged_cb(struct device *dev, void *data,
- hdmi_codec_plugged_cb fn,
- struct device *codec_dev)
-{
-
- struct platform_device *pdev;
- struct msm_dp *msm_dp_display;
-
- pdev = to_platform_device(dev);
- if (!pdev) {
- pr_err("invalid input\n");
- return -ENODEV;
- }
-
- msm_dp_display = platform_get_drvdata(pdev);
- if (!msm_dp_display) {
- pr_err("invalid input\n");
- return -ENODEV;
- }
-
- return msm_dp_display_set_plugged_cb(msm_dp_display, fn, codec_dev);
-}
-
-static int msm_dp_audio_get_eld(struct device *dev,
- void *data, uint8_t *buf, size_t len)
-{
- struct platform_device *pdev;
- struct msm_dp *msm_dp_display;
-
- pdev = to_platform_device(dev);
-
- if (!pdev) {
- DRM_ERROR("invalid input\n");
- return -ENODEV;
- }
-
- msm_dp_display = platform_get_drvdata(pdev);
- if (!msm_dp_display) {
- DRM_ERROR("invalid input\n");
- return -ENODEV;
- }
-
- mutex_lock(&msm_dp_display->connector->eld_mutex);
- memcpy(buf, msm_dp_display->connector->eld,
- min(sizeof(msm_dp_display->connector->eld), len));
- mutex_unlock(&msm_dp_display->connector->eld_mutex);
-
- return 0;
-}
-
-int msm_dp_audio_hw_params(struct device *dev,
- void *data,
- struct hdmi_codec_daifmt *daifmt,
- struct hdmi_codec_params *params)
+int msm_dp_audio_prepare(struct drm_connector *connector,
+ struct drm_bridge *bridge,
+ struct hdmi_codec_daifmt *daifmt,
+ struct hdmi_codec_params *params)
{
int rc = 0;
struct msm_dp_audio_private *audio;
- struct platform_device *pdev;
struct msm_dp *msm_dp_display;
- pdev = to_platform_device(dev);
- msm_dp_display = platform_get_drvdata(pdev);
+ msm_dp_display = to_dp_bridge(bridge)->msm_dp_display;
/*
* there could be cases where sound card can be opened even
@@ -262,7 +197,7 @@ int msm_dp_audio_hw_params(struct device *dev,
goto end;
}
- audio = msm_dp_audio_get_data(pdev);
+ audio = msm_dp_audio_get_data(msm_dp_display);
if (IS_ERR(audio)) {
rc = PTR_ERR(audio);
goto end;
@@ -281,15 +216,14 @@ end:
return rc;
}
-static void msm_dp_audio_shutdown(struct device *dev, void *data)
+void msm_dp_audio_shutdown(struct drm_connector *connector,
+ struct drm_bridge *bridge)
{
struct msm_dp_audio_private *audio;
- struct platform_device *pdev;
struct msm_dp *msm_dp_display;
- pdev = to_platform_device(dev);
- msm_dp_display = platform_get_drvdata(pdev);
- audio = msm_dp_audio_get_data(pdev);
+ msm_dp_display = to_dp_bridge(bridge)->msm_dp_display;
+ audio = msm_dp_audio_get_data(msm_dp_display);
if (IS_ERR(audio)) {
DRM_ERROR("failed to get audio data\n");
return;
@@ -311,47 +245,6 @@ static void msm_dp_audio_shutdown(struct device *dev, void *data)
msm_dp_display_signal_audio_complete(msm_dp_display);
}
-static const struct hdmi_codec_ops msm_dp_audio_codec_ops = {
- .hw_params = msm_dp_audio_hw_params,
- .audio_shutdown = msm_dp_audio_shutdown,
- .get_eld = msm_dp_audio_get_eld,
- .hook_plugged_cb = msm_dp_audio_hook_plugged_cb,
-};
-
-static struct hdmi_codec_pdata codec_data = {
- .ops = &msm_dp_audio_codec_ops,
- .max_i2s_channels = 8,
- .i2s = 1,
-};
-
-void msm_dp_unregister_audio_driver(struct device *dev, struct msm_dp_audio *msm_dp_audio)
-{
- struct msm_dp_audio_private *audio_priv;
-
- audio_priv = container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio);
-
- if (audio_priv->audio_pdev) {
- platform_device_unregister(audio_priv->audio_pdev);
- audio_priv->audio_pdev = NULL;
- }
-}
-
-int msm_dp_register_audio_driver(struct device *dev,
- struct msm_dp_audio *msm_dp_audio)
-{
- struct msm_dp_audio_private *audio_priv;
-
- audio_priv = container_of(msm_dp_audio,
- struct msm_dp_audio_private, msm_dp_audio);
-
- audio_priv->audio_pdev = platform_device_register_data(dev,
- HDMI_CODEC_DRV_NAME,
- PLATFORM_DEVID_AUTO,
- &codec_data,
- sizeof(codec_data));
- return PTR_ERR_OR_ZERO(audio_priv->audio_pdev);
-}
-
struct msm_dp_audio *msm_dp_audio_get(struct platform_device *pdev,
struct msm_dp_catalog *catalog)
{
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.h b/drivers/gpu/drm/msm/dp/dp_audio.h
index beea34cbab77..58fc14693e48 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.h
+++ b/drivers/gpu/drm/msm/dp/dp_audio.h
@@ -36,23 +36,6 @@ struct msm_dp_audio *msm_dp_audio_get(struct platform_device *pdev,
struct msm_dp_catalog *catalog);
/**
- * msm_dp_register_audio_driver()
- *
- * Registers DP device with hdmi_codec interface.
- *
- * @dev: DP device instance.
- * @msm_dp_audio: an instance of msm_dp_audio module.
- *
- *
- * Returns the error code in case of failure, otherwise
- * zero on success.
- */
-int msm_dp_register_audio_driver(struct device *dev,
- struct msm_dp_audio *msm_dp_audio);
-
-void msm_dp_unregister_audio_driver(struct device *dev, struct msm_dp_audio *msm_dp_audio);
-
-/**
* msm_dp_audio_put()
*
* Cleans the msm_dp_audio instance.
@@ -61,10 +44,12 @@ void msm_dp_unregister_audio_driver(struct device *dev, struct msm_dp_audio *msm
*/
void msm_dp_audio_put(struct msm_dp_audio *msm_dp_audio);
-int msm_dp_audio_hw_params(struct device *dev,
- void *data,
- struct hdmi_codec_daifmt *daifmt,
- struct hdmi_codec_params *params);
+int msm_dp_audio_prepare(struct drm_connector *connector,
+ struct drm_bridge *bridge,
+ struct hdmi_codec_daifmt *daifmt,
+ struct hdmi_codec_params *params);
+void msm_dp_audio_shutdown(struct drm_connector *connector,
+ struct drm_bridge *bridge);
#endif /* _DP_AUDIO_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index 9c463ae2f8fa..a50bfafbb4ea 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -11,6 +11,7 @@
#include <linux/phy/phy.h>
#include <linux/phy/phy-dp.h>
#include <linux/pm_opp.h>
+#include <linux/string_choices.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_fixed.h>
@@ -1033,10 +1034,12 @@ static int msm_dp_ctrl_set_vx_px(struct msm_dp_ctrl_private *ctrl,
return 0;
}
-static int msm_dp_ctrl_update_vx_px(struct msm_dp_ctrl_private *ctrl)
+static int msm_dp_ctrl_update_phy_vx_px(struct msm_dp_ctrl_private *ctrl,
+ enum drm_dp_phy dp_phy)
{
struct msm_dp_link *link = ctrl->link;
- int ret = 0, lane, lane_cnt;
+ int lane, lane_cnt, reg;
+ int ret = 0;
u8 buf[4];
u32 max_level_reached = 0;
u32 voltage_swing_level = link->phy_params.v_level;
@@ -1074,8 +1077,13 @@ static int msm_dp_ctrl_update_vx_px(struct msm_dp_ctrl_private *ctrl)
drm_dbg_dp(ctrl->drm_dev, "sink: p|v=0x%x\n",
voltage_swing_level | pre_emphasis_level);
- ret = drm_dp_dpcd_write(ctrl->aux, DP_TRAINING_LANE0_SET,
- buf, lane_cnt);
+
+ if (dp_phy == DP_PHY_DPRX)
+ reg = DP_TRAINING_LANE0_SET;
+ else
+ reg = DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy);
+
+ ret = drm_dp_dpcd_write(ctrl->aux, reg, buf, lane_cnt);
if (ret == lane_cnt)
ret = 0;
@@ -1083,9 +1091,10 @@ static int msm_dp_ctrl_update_vx_px(struct msm_dp_ctrl_private *ctrl)
}
static bool msm_dp_ctrl_train_pattern_set(struct msm_dp_ctrl_private *ctrl,
- u8 pattern)
+ u8 pattern, enum drm_dp_phy dp_phy)
{
u8 buf;
+ int reg;
int ret = 0;
drm_dbg_dp(ctrl->drm_dev, "sink: pattern=%x\n", pattern);
@@ -1095,31 +1104,26 @@ static bool msm_dp_ctrl_train_pattern_set(struct msm_dp_ctrl_private *ctrl,
if (pattern && pattern != DP_TRAINING_PATTERN_4)
buf |= DP_LINK_SCRAMBLING_DISABLE;
- ret = drm_dp_dpcd_writeb(ctrl->aux, DP_TRAINING_PATTERN_SET, buf);
- return ret == 1;
-}
-
-static int msm_dp_ctrl_read_link_status(struct msm_dp_ctrl_private *ctrl,
- u8 *link_status)
-{
- int ret = 0, len;
-
- len = drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
- if (len != DP_LINK_STATUS_SIZE) {
- DRM_ERROR("DP link status read failed, err: %d\n", len);
- ret = -EINVAL;
- }
+ if (dp_phy == DP_PHY_DPRX)
+ reg = DP_TRAINING_PATTERN_SET;
+ else
+ reg = DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy);
- return ret;
+ ret = drm_dp_dpcd_writeb(ctrl->aux, reg, buf);
+ return ret == 1;
}
static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
- int *training_step)
+ int *training_step, enum drm_dp_phy dp_phy)
{
+ int delay_us;
int tries, old_v_level, ret = 0;
u8 link_status[DP_LINK_STATUS_SIZE];
int const maximum_retries = 4;
+ delay_us = drm_dp_read_clock_recovery_delay(ctrl->aux,
+ ctrl->panel->dpcd, dp_phy, false);
+
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
*training_step = DP_TRAINING_1;
@@ -1128,18 +1132,19 @@ static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
if (ret)
return ret;
msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
- DP_LINK_SCRAMBLING_DISABLE);
+ DP_LINK_SCRAMBLING_DISABLE, dp_phy);
- ret = msm_dp_ctrl_update_vx_px(ctrl);
+ msm_dp_link_reset_phy_params_vx_px(ctrl->link);
+ ret = msm_dp_ctrl_update_phy_vx_px(ctrl, dp_phy);
if (ret)
return ret;
tries = 0;
old_v_level = ctrl->link->phy_params.v_level;
for (tries = 0; tries < maximum_retries; tries++) {
- drm_dp_link_train_clock_recovery_delay(ctrl->aux, ctrl->panel->dpcd);
+ fsleep(delay_us);
- ret = msm_dp_ctrl_read_link_status(ctrl, link_status);
+ ret = drm_dp_dpcd_read_phy_link_status(ctrl->aux, dp_phy, link_status);
if (ret)
return ret;
@@ -1160,7 +1165,7 @@ static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
}
msm_dp_link_adjust_levels(ctrl->link, link_status);
- ret = msm_dp_ctrl_update_vx_px(ctrl);
+ ret = msm_dp_ctrl_update_phy_vx_px(ctrl, dp_phy);
if (ret)
return ret;
}
@@ -1212,21 +1217,31 @@ static int msm_dp_ctrl_link_lane_down_shift(struct msm_dp_ctrl_private *ctrl)
return 0;
}
-static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl)
+static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl,
+ enum drm_dp_phy dp_phy)
{
- msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE);
- drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd);
+ int delay_us;
+
+ msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE, dp_phy);
+
+ delay_us = drm_dp_read_channel_eq_delay(ctrl->aux,
+ ctrl->panel->dpcd, dp_phy, false);
+ fsleep(delay_us);
}
static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
- int *training_step)
+ int *training_step, enum drm_dp_phy dp_phy)
{
+ int delay_us;
int tries = 0, ret = 0;
u8 pattern;
u32 state_ctrl_bit;
int const maximum_retries = 5;
u8 link_status[DP_LINK_STATUS_SIZE];
+ delay_us = drm_dp_read_channel_eq_delay(ctrl->aux,
+ ctrl->panel->dpcd, dp_phy, false);
+
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
*training_step = DP_TRAINING_2;
@@ -1246,12 +1261,12 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
if (ret)
return ret;
- msm_dp_ctrl_train_pattern_set(ctrl, pattern);
+ msm_dp_ctrl_train_pattern_set(ctrl, pattern, dp_phy);
for (tries = 0; tries <= maximum_retries; tries++) {
- drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd);
+ fsleep(delay_us);
- ret = msm_dp_ctrl_read_link_status(ctrl, link_status);
+ ret = drm_dp_dpcd_read_phy_link_status(ctrl->aux, dp_phy, link_status);
if (ret)
return ret;
@@ -1261,7 +1276,7 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
}
msm_dp_link_adjust_levels(ctrl->link, link_status);
- ret = msm_dp_ctrl_update_vx_px(ctrl);
+ ret = msm_dp_ctrl_update_phy_vx_px(ctrl, dp_phy);
if (ret)
return ret;
@@ -1270,9 +1285,32 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
return -ETIMEDOUT;
}
+static int msm_dp_ctrl_link_train_1_2(struct msm_dp_ctrl_private *ctrl,
+ int *training_step, enum drm_dp_phy dp_phy)
+{
+ int ret;
+
+ ret = msm_dp_ctrl_link_train_1(ctrl, training_step, dp_phy);
+ if (ret) {
+ DRM_ERROR("link training #1 on phy %d failed. ret=%d\n", dp_phy, ret);
+ return ret;
+ }
+ drm_dbg_dp(ctrl->drm_dev, "link training #1 on phy %d successful\n", dp_phy);
+
+ ret = msm_dp_ctrl_link_train_2(ctrl, training_step, dp_phy);
+ if (ret) {
+ DRM_ERROR("link training #2 on phy %d failed. ret=%d\n", dp_phy, ret);
+ return ret;
+ }
+ drm_dbg_dp(ctrl->drm_dev, "link training #2 on phy %d successful\n", dp_phy);
+
+ return 0;
+}
+
static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
int *training_step)
{
+ int i;
int ret = 0;
const u8 *dpcd = ctrl->panel->dpcd;
u8 encoding[] = { 0, DP_SET_ANSI_8B10B };
@@ -1285,8 +1323,6 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
link_info.rate = ctrl->link->link_params.rate;
link_info.capabilities = DP_LINK_CAP_ENHANCED_FRAMING;
- msm_dp_link_reset_phy_params_vx_px(ctrl->link);
-
msm_dp_aux_link_configure(ctrl->aux, &link_info);
if (drm_dp_max_downspread(dpcd))
@@ -1301,24 +1337,27 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
&assr, 1);
}
- ret = msm_dp_ctrl_link_train_1(ctrl, training_step);
+ for (i = ctrl->link->lttpr_count - 1; i >= 0; i--) {
+ enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
+
+ ret = msm_dp_ctrl_link_train_1_2(ctrl, training_step, dp_phy);
+ msm_dp_ctrl_clear_training_pattern(ctrl, dp_phy);
+
+ if (ret)
+ break;
+ }
+
if (ret) {
- DRM_ERROR("link training #1 failed. ret=%d\n", ret);
+ DRM_ERROR("link training of LTTPR(s) failed. ret=%d\n", ret);
goto end;
}
- /* print success info as this is a result of user initiated action */
- drm_dbg_dp(ctrl->drm_dev, "link training #1 successful\n");
-
- ret = msm_dp_ctrl_link_train_2(ctrl, training_step);
+ ret = msm_dp_ctrl_link_train_1_2(ctrl, training_step, DP_PHY_DPRX);
if (ret) {
- DRM_ERROR("link training #2 failed. ret=%d\n", ret);
+ DRM_ERROR("link training on sink failed. ret=%d\n", ret);
goto end;
}
- /* print success info as this is a result of user initiated action */
- drm_dbg_dp(ctrl->drm_dev, "link training #2 successful\n");
-
end:
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
@@ -1366,9 +1405,9 @@ int msm_dp_ctrl_core_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl)
drm_dbg_dp(ctrl->drm_dev, "enable core clocks \n");
drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n",
- ctrl->stream_clks_on ? "on" : "off",
- ctrl->link_clks_on ? "on" : "off",
- ctrl->core_clks_on ? "on" : "off");
+ str_on_off(ctrl->stream_clks_on),
+ str_on_off(ctrl->link_clks_on),
+ str_on_off(ctrl->core_clks_on));
return 0;
}
@@ -1385,9 +1424,9 @@ void msm_dp_ctrl_core_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl)
drm_dbg_dp(ctrl->drm_dev, "disable core clocks \n");
drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n",
- ctrl->stream_clks_on ? "on" : "off",
- ctrl->link_clks_on ? "on" : "off",
- ctrl->core_clks_on ? "on" : "off");
+ str_on_off(ctrl->stream_clks_on),
+ str_on_off(ctrl->link_clks_on),
+ str_on_off(ctrl->core_clks_on));
}
static int msm_dp_ctrl_link_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl)
@@ -1416,9 +1455,9 @@ static int msm_dp_ctrl_link_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl)
drm_dbg_dp(ctrl->drm_dev, "enable link clocks\n");
drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n",
- ctrl->stream_clks_on ? "on" : "off",
- ctrl->link_clks_on ? "on" : "off",
- ctrl->core_clks_on ? "on" : "off");
+ str_on_off(ctrl->stream_clks_on),
+ str_on_off(ctrl->link_clks_on),
+ str_on_off(ctrl->core_clks_on));
return 0;
}
@@ -1435,9 +1474,9 @@ static void msm_dp_ctrl_link_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl)
drm_dbg_dp(ctrl->drm_dev, "disabled link clocks\n");
drm_dbg_dp(ctrl->drm_dev, "stream_clks:%s link_clks:%s core_clks:%s\n",
- ctrl->stream_clks_on ? "on" : "off",
- ctrl->link_clks_on ? "on" : "off",
- ctrl->core_clks_on ? "on" : "off");
+ str_on_off(ctrl->stream_clks_on),
+ str_on_off(ctrl->link_clks_on),
+ str_on_off(ctrl->core_clks_on));
}
static int msm_dp_ctrl_enable_mainlink_clocks(struct msm_dp_ctrl_private *ctrl)
@@ -1635,7 +1674,7 @@ static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl)
if (ret)
goto end;
- msm_dp_ctrl_clear_training_pattern(ctrl);
+ msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
@@ -1659,7 +1698,7 @@ static bool msm_dp_ctrl_send_phy_test_pattern(struct msm_dp_ctrl_private *ctrl)
return false;
}
msm_dp_catalog_ctrl_send_phy_pattern(ctrl->catalog, pattern_requested);
- msm_dp_ctrl_update_vx_px(ctrl);
+ msm_dp_ctrl_update_phy_vx_px(ctrl, DP_PHY_DPRX);
msm_dp_link_send_test_response(ctrl->link);
pattern_sent = msm_dp_catalog_ctrl_read_phy_pattern(ctrl->catalog);
@@ -1804,7 +1843,7 @@ static bool msm_dp_ctrl_channel_eq_ok(struct msm_dp_ctrl_private *ctrl)
u8 link_status[DP_LINK_STATUS_SIZE];
int num_lanes = ctrl->link->link_params.num_lanes;
- msm_dp_ctrl_read_link_status(ctrl, link_status);
+ drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
return drm_dp_channel_eq_ok(link_status, num_lanes);
}
@@ -1862,7 +1901,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
if (!msm_dp_catalog_link_is_connected(ctrl->catalog))
break;
- msm_dp_ctrl_read_link_status(ctrl, link_status);
+ drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
rc = msm_dp_ctrl_link_rate_down_shift(ctrl);
if (rc < 0) { /* already in RBR = 1.6G */
@@ -1887,7 +1926,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
if (!msm_dp_catalog_link_is_connected(ctrl->catalog))
break;
- msm_dp_ctrl_read_link_status(ctrl, link_status);
+ drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
if (!drm_dp_clock_recovery_ok(link_status,
ctrl->link->link_params.num_lanes))
@@ -1901,7 +1940,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
}
/* stop link training before start re training */
- msm_dp_ctrl_clear_training_pattern(ctrl);
+ msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
}
rc = msm_dp_ctrl_reinitialize_mainlink(ctrl);
@@ -1925,7 +1964,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
* link training failed
* end txing train pattern here
*/
- msm_dp_ctrl_clear_training_pattern(ctrl);
+ msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
msm_dp_ctrl_deinitialize_mainlink(ctrl);
rc = -ECONNRESET;
@@ -1996,7 +2035,7 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
msm_dp_ctrl_link_retrain(ctrl);
/* stop txing train pattern to end link training */
- msm_dp_ctrl_clear_training_pattern(ctrl);
+ msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
/*
* Set up transfer unit values and set controller state to send
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 3898850739ab..386c4669c831 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -11,7 +11,9 @@
#include <linux/of_irq.h>
#include <linux/phy/phy.h>
#include <linux/delay.h>
+#include <linux/string_choices.h>
#include <drm/display/drm_dp_aux_bus.h>
+#include <drm/display/drm_hdmi_audio_helper.h>
#include <drm/drm_edid.h>
#include "msm_drv.h"
@@ -287,13 +289,6 @@ static int msm_dp_display_bind(struct device *dev, struct device *master,
goto end;
}
-
- rc = msm_dp_register_audio_driver(dev, dp->audio);
- if (rc) {
- DRM_ERROR("Audio registration Dp failed\n");
- goto end;
- }
-
rc = msm_dp_hpd_event_thread_start(dp);
if (rc) {
DRM_ERROR("Event thread create failed\n");
@@ -315,7 +310,6 @@ static void msm_dp_display_unbind(struct device *dev, struct device *master,
of_dp_aux_depopulate_bus(dp->aux);
- msm_dp_unregister_audio_driver(dev, dp->audio);
msm_dp_aux_unregister(dp->aux);
dp->drm_dev = NULL;
dp->aux->drm_dev = NULL;
@@ -343,8 +337,7 @@ static int msm_dp_display_send_hpd_notification(struct msm_dp_display_private *d
{
if ((hpd && dp->msm_dp_display.link_ready) ||
(!hpd && !dp->msm_dp_display.link_ready)) {
- drm_dbg_dp(dp->drm_dev, "HPD already %s\n",
- (hpd ? "on" : "off"));
+ drm_dbg_dp(dp->drm_dev, "HPD already %s\n", str_on_off(hpd));
return 0;
}
@@ -367,11 +360,35 @@ static int msm_dp_display_send_hpd_notification(struct msm_dp_display_private *d
return 0;
}
+static int msm_dp_display_lttpr_init(struct msm_dp_display_private *dp, u8 *dpcd)
+{
+ int rc, lttpr_count;
+
+ if (drm_dp_read_lttpr_common_caps(dp->aux, dpcd, dp->link->lttpr_common_caps))
+ return 0;
+
+ lttpr_count = drm_dp_lttpr_count(dp->link->lttpr_common_caps);
+ rc = drm_dp_lttpr_init(dp->aux, lttpr_count);
+ if (rc) {
+ DRM_ERROR("failed to set LTTPRs transparency mode, rc=%d\n", rc);
+ return 0;
+ }
+
+ return lttpr_count;
+}
+
static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp)
{
struct drm_connector *connector = dp->msm_dp_display.connector;
const struct drm_display_info *info = &connector->display_info;
int rc = 0;
+ u8 dpcd[DP_RECEIVER_CAP_SIZE];
+
+ rc = drm_dp_read_dpcd_caps(dp->aux, dpcd);
+ if (rc)
+ goto end;
+
+ dp->link->lttpr_count = msm_dp_display_lttpr_init(dp, dpcd);
rc = msm_dp_panel_read_sink_caps(dp->panel, connector);
if (rc)
@@ -611,9 +628,9 @@ static void msm_dp_display_handle_plugged_change(struct msm_dp *msm_dp_display,
struct msm_dp_display_private, msm_dp_display);
/* notify audio subsystem only if sink supports audio */
- if (msm_dp_display->plugged_cb && msm_dp_display->codec_dev &&
- dp->audio_supported)
- msm_dp_display->plugged_cb(msm_dp_display->codec_dev, plugged);
+ if (dp->audio_supported)
+ drm_connector_hdmi_audio_plugged_notify(msm_dp_display->connector,
+ plugged);
}
static int msm_dp_hpd_unplug_handle(struct msm_dp_display_private *dp, u32 data)
@@ -892,19 +909,6 @@ static int msm_dp_display_disable(struct msm_dp_display_private *dp)
return 0;
}
-int msm_dp_display_set_plugged_cb(struct msm_dp *msm_dp_display,
- hdmi_codec_plugged_cb fn, struct device *codec_dev)
-{
- bool plugged;
-
- msm_dp_display->plugged_cb = fn;
- msm_dp_display->codec_dev = codec_dev;
- plugged = msm_dp_display->link_ready;
- msm_dp_display_handle_plugged_change(msm_dp_display, plugged);
-
- return 0;
-}
-
/**
* msm_dp_bridge_mode_valid - callback to determine if specified mode is valid
* @bridge: Pointer to drm bridge structure
@@ -1492,13 +1496,13 @@ int msm_dp_modeset_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
}
void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
int rc = 0;
struct msm_dp_display_private *msm_dp_display;
- u32 state;
+ u32 hpd_state;
bool force_link_train = false;
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
@@ -1517,8 +1521,8 @@ void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
return;
}
- state = msm_dp_display->hpd_state;
- if (state != ST_DISPLAY_OFF && state != ST_MAINLINK_READY) {
+ hpd_state = msm_dp_display->hpd_state;
+ if (hpd_state != ST_DISPLAY_OFF && hpd_state != ST_MAINLINK_READY) {
mutex_unlock(&msm_dp_display->event_mutex);
return;
}
@@ -1530,9 +1534,9 @@ void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
return;
}
- state = msm_dp_display->hpd_state;
+ hpd_state = msm_dp_display->hpd_state;
- if (state == ST_DISPLAY_OFF) {
+ if (hpd_state == ST_DISPLAY_OFF) {
msm_dp_display_host_phy_init(msm_dp_display);
force_link_train = true;
}
@@ -1553,7 +1557,7 @@ void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
}
void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
@@ -1565,11 +1569,11 @@ void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
}
void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
- u32 state;
+ u32 hpd_state;
struct msm_dp_display_private *msm_dp_display;
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
@@ -1579,15 +1583,15 @@ void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
mutex_lock(&msm_dp_display->event_mutex);
- state = msm_dp_display->hpd_state;
- if (state != ST_DISCONNECT_PENDING && state != ST_CONNECTED)
+ hpd_state = msm_dp_display->hpd_state;
+ if (hpd_state != ST_DISCONNECT_PENDING && hpd_state != ST_CONNECTED)
drm_dbg_dp(dp->drm_dev, "type=%d wrong hpd_state=%d\n",
- dp->connector_type, state);
+ dp->connector_type, hpd_state);
msm_dp_display_disable(msm_dp_display);
- state = msm_dp_display->hpd_state;
- if (state == ST_DISCONNECT_PENDING) {
+ hpd_state = msm_dp_display->hpd_state;
+ if (hpd_state == ST_DISCONNECT_PENDING) {
/* completed disconnection */
msm_dp_display->hpd_state = ST_DISCONNECTED;
} else {
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index ecbc2d92f546..cc6e2cab36e9 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -7,7 +7,6 @@
#define _DP_DISPLAY_H_
#include "dp_panel.h"
-#include <sound/hdmi-codec.h>
#include "disp/msm_disp_snapshot.h"
#define DP_MAX_PIXEL_CLK_KHZ 675000
@@ -15,7 +14,6 @@
struct msm_dp {
struct drm_device *drm_dev;
struct platform_device *pdev;
- struct device *codec_dev;
struct drm_connector *connector;
struct drm_bridge *next_bridge;
bool link_ready;
@@ -25,14 +23,10 @@ struct msm_dp {
bool is_edp;
bool internal_hpd;
- hdmi_codec_plugged_cb plugged_cb;
-
struct msm_dp_audio *msm_dp_audio;
bool psr_supported;
};
-int msm_dp_display_set_plugged_cb(struct msm_dp *msm_dp_display,
- hdmi_codec_plugged_cb fn, struct device *codec_dev);
int msm_dp_display_get_modes(struct msm_dp *msm_dp_display);
bool msm_dp_display_check_video_test(struct msm_dp *msm_dp_display);
int msm_dp_display_get_test_bpp(struct msm_dp *msm_dp_display);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 16b7913d1eef..f222d7ccaa88 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -3,6 +3,7 @@
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
+#include <linux/string_choices.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_bridge.h>
@@ -11,6 +12,7 @@
#include "msm_drv.h"
#include "msm_kms.h"
+#include "dp_audio.h"
#include "dp_drm.h"
/**
@@ -25,7 +27,7 @@ static enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge)
dp = to_dp_bridge(bridge)->msm_dp_display;
drm_dbg_dp(dp->drm_dev, "link_ready = %s\n",
- (dp->link_ready) ? "true" : "false");
+ str_true_false(dp->link_ready));
return (dp->link_ready) ? connector_status_connected :
connector_status_disconnected;
@@ -41,7 +43,7 @@ static int msm_dp_bridge_atomic_check(struct drm_bridge *bridge,
dp = to_dp_bridge(bridge)->msm_dp_display;
drm_dbg_dp(dp->drm_dev, "link_ready = %s\n",
- (dp->link_ready) ? "true" : "false");
+ str_true_false(dp->link_ready));
/*
* There is no protection in the DRM framework to check if the display
@@ -113,6 +115,9 @@ static const struct drm_bridge_funcs msm_dp_bridge_ops = {
.hpd_disable = msm_dp_bridge_hpd_disable,
.hpd_notify = msm_dp_bridge_hpd_notify,
.debugfs_init = msm_dp_bridge_debugfs_init,
+
+ .dp_audio_prepare = msm_dp_audio_prepare,
+ .dp_audio_shutdown = msm_dp_audio_shutdown,
};
static int msm_edp_bridge_atomic_check(struct drm_bridge *drm_bridge,
@@ -137,9 +142,8 @@ static int msm_edp_bridge_atomic_check(struct drm_bridge *drm_bridge,
}
static void msm_edp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *state)
{
- struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
@@ -151,25 +155,24 @@ static void msm_edp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
* If the panel is in psr, just exit psr state and skip the full
* bridge enable sequence.
*/
- crtc = drm_atomic_get_new_crtc_for_encoder(atomic_state,
+ crtc = drm_atomic_get_new_crtc_for_encoder(state,
drm_bridge->encoder);
if (!crtc)
return;
- old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc);
+ old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
if (old_crtc_state && old_crtc_state->self_refresh_active) {
msm_dp_display_set_psr(dp, false);
return;
}
- msm_dp_bridge_atomic_enable(drm_bridge, old_bridge_state);
+ msm_dp_bridge_atomic_enable(drm_bridge, state);
}
static void msm_edp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *atomic_state)
{
- struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
struct drm_crtc *crtc;
struct drm_crtc_state *new_crtc_state = NULL, *old_crtc_state = NULL;
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
@@ -208,13 +211,12 @@ static void msm_edp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
}
out:
- msm_dp_bridge_atomic_disable(drm_bridge, old_bridge_state);
+ msm_dp_bridge_atomic_disable(drm_bridge, atomic_state);
}
static void msm_edp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
- struct drm_bridge_state *old_bridge_state)
+ struct drm_atomic_state *atomic_state)
{
- struct drm_atomic_state *atomic_state = old_bridge_state->base.state;
struct drm_crtc *crtc;
struct drm_crtc_state *new_crtc_state = NULL;
@@ -233,7 +235,7 @@ static void msm_edp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
if (new_crtc_state->self_refresh_active)
return;
- msm_dp_bridge_atomic_post_disable(drm_bridge, old_bridge_state);
+ msm_dp_bridge_atomic_post_disable(drm_bridge, atomic_state);
}
/**
@@ -298,14 +300,15 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
struct msm_dp_bridge *msm_dp_bridge;
struct drm_bridge *bridge;
- msm_dp_bridge = devm_kzalloc(dev->dev, sizeof(*msm_dp_bridge), GFP_KERNEL);
- if (!msm_dp_bridge)
- return -ENOMEM;
+ msm_dp_bridge = devm_drm_bridge_alloc(dev->dev, struct msm_dp_bridge, bridge,
+ msm_dp_display->is_edp ? &msm_edp_bridge_ops :
+ &msm_dp_bridge_ops);
+ if (IS_ERR(msm_dp_bridge))
+ return PTR_ERR(msm_dp_bridge);
msm_dp_bridge->msm_dp_display = msm_dp_display;
bridge = &msm_dp_bridge->bridge;
- bridge->funcs = msm_dp_display->is_edp ? &msm_edp_bridge_ops : &msm_dp_bridge_ops;
bridge->type = msm_dp_display->connector_type;
bridge->ycbcr_420_allowed = yuv_supported;
@@ -322,9 +325,13 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
*/
if (!msm_dp_display->is_edp) {
bridge->ops =
+ DRM_BRIDGE_OP_DP_AUDIO |
DRM_BRIDGE_OP_DETECT |
DRM_BRIDGE_OP_HPD |
DRM_BRIDGE_OP_MODES;
+ bridge->hdmi_audio_dev = &msm_dp_display->pdev->dev;
+ bridge->hdmi_audio_max_i2s_playback_channels = 8;
+ bridge->hdmi_audio_dai_port = -1;
}
rc = devm_drm_bridge_add(dev->dev, bridge);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index 8eae2f74839f..d8c9b905f8bf 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -26,11 +26,11 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
bool yuv_supported);
void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
- struct drm_bridge_state *old_bridge_state);
+ struct drm_atomic_state *state);
void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
- struct drm_bridge_state *old_bridge_state);
+ struct drm_atomic_state *state);
void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
- struct drm_bridge_state *old_bridge_state);
+ struct drm_atomic_state *state);
enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode);
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index 1a1fbb2d7d4f..92a9077959b3 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -714,21 +714,21 @@ end:
static int msm_dp_link_parse_sink_status_field(struct msm_dp_link_private *link)
{
- int len;
+ int ret;
link->prev_sink_count = link->msm_dp_link.sink_count;
- len = drm_dp_read_sink_count(link->aux);
- if (len < 0) {
+ ret = drm_dp_read_sink_count(link->aux);
+ if (ret < 0) {
DRM_ERROR("DP parse sink count failed\n");
- return len;
+ return ret;
}
- link->msm_dp_link.sink_count = len;
+ link->msm_dp_link.sink_count = ret;
- len = drm_dp_dpcd_read_link_status(link->aux,
- link->link_status);
- if (len < DP_LINK_STATUS_SIZE) {
+ ret = drm_dp_dpcd_read_link_status(link->aux,
+ link->link_status);
+ if (ret < 0) {
DRM_ERROR("DP link status read failed\n");
- return len;
+ return ret;
}
return msm_dp_link_parse_request(link);
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 8db5d5698a97..ba47c6d19fbf 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -7,6 +7,7 @@
#define _DP_LINK_H_
#include "dp_aux.h"
+#include <drm/display/drm_dp_helper.h>
#define DS_PORT_STATUS_CHANGED 0x200
#define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF
@@ -60,6 +61,9 @@ struct msm_dp_link_phy_params {
};
struct msm_dp_link {
+ u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE];
+ int lttpr_count;
+
u32 sink_request;
u32 test_response;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 92415bf8aa16..4e8ab75c771b 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -47,7 +47,7 @@ static void msm_dp_panel_read_psr_cap(struct msm_dp_panel_private *panel)
static int msm_dp_panel_read_dpcd(struct msm_dp_panel *msm_dp_panel)
{
- int rc;
+ int rc, max_lttpr_lanes, max_lttpr_rate;
struct msm_dp_panel_private *panel;
struct msm_dp_link_info *link_info;
u8 *dpcd, major, minor;
@@ -75,6 +75,16 @@ static int msm_dp_panel_read_dpcd(struct msm_dp_panel *msm_dp_panel)
if (link_info->rate > msm_dp_panel->max_dp_link_rate)
link_info->rate = msm_dp_panel->max_dp_link_rate;
+ /* Limit data lanes from LTTPR capabilities, if any */
+ max_lttpr_lanes = drm_dp_lttpr_max_lane_count(panel->link->lttpr_common_caps);
+ if (max_lttpr_lanes && max_lttpr_lanes < link_info->num_lanes)
+ link_info->num_lanes = max_lttpr_lanes;
+
+ /* Limit link rate from LTTPR capabilities, if any */
+ max_lttpr_rate = drm_dp_lttpr_max_link_rate(panel->link->lttpr_common_caps);
+ if (max_lttpr_rate && max_lttpr_rate < link_info->rate)
+ link_info->rate = max_lttpr_rate;
+
drm_dbg_dp(panel->drm_dev, "version: %d.%d\n", major, minor);
drm_dbg_dp(panel->drm_dev, "link_rate=%d\n", link_info->rate);
drm_dbg_dp(panel->drm_dev, "lane_count=%d\n", link_info->num_lanes);