summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/dp
diff options
context:
space:
mode:
authorThomas Zimmermann <tzimmermann@suse.de>2022-06-20 19:21:25 +0300
committerThomas Zimmermann <tzimmermann@suse.de>2022-06-20 19:21:25 +0300
commit2b1333b80885b896807ffb6ccf4bc21d29aa65e0 (patch)
tree51cc2d13d65603383db82c87f01a0aa93bd26010 /drivers/gpu/drm/msm/dp
parentcad564ca557f8d3bb3b1fa965d9a2b3f6490ec69 (diff)
parent0f95ee9a0c579ebed0309657f6918673927189f2 (diff)
downloadlinux-2b1333b80885b896807ffb6ccf4bc21d29aa65e0.tar.xz
Merge drm/drm-next into drm-misc-next
Backmerging to get new regmap APIs of v5.19-rc1. Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Diffstat (limited to 'drivers/gpu/drm/msm/dp')
-rw-r--r--drivers/gpu/drm/msm/dp/dp_audio.c50
-rw-r--r--drivers/gpu/drm/msm/dp/dp_aux.c21
-rw-r--r--drivers/gpu/drm/msm/dp/dp_aux.h3
-rw-r--r--drivers/gpu/drm/msm/dp/dp_catalog.c98
-rw-r--r--drivers/gpu/drm/msm/dp/dp_catalog.h3
-rw-r--r--drivers/gpu/drm/msm/dp/dp_ctrl.c175
-rw-r--r--drivers/gpu/drm/msm/dp/dp_ctrl.h2
-rw-r--r--drivers/gpu/drm/msm/dp/dp_debug.c2
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.c444
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.h7
-rw-r--r--drivers/gpu/drm/msm/dp/dp_drm.c215
-rw-r--r--drivers/gpu/drm/msm/dp/dp_drm.h22
-rw-r--r--drivers/gpu/drm/msm/dp/dp_link.c103
-rw-r--r--drivers/gpu/drm/msm/dp/dp_panel.c60
-rw-r--r--drivers/gpu/drm/msm/dp/dp_panel.h4
-rw-r--r--drivers/gpu/drm/msm/dp/dp_parser.c25
-rw-r--r--drivers/gpu/drm/msm/dp/dp_parser.h14
-rw-r--r--drivers/gpu/drm/msm/dp/dp_power.c25
18 files changed, 723 insertions, 550 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c
index 077d3b6507e7..6666783e1468 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.c
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -26,6 +26,7 @@
struct dp_audio_private {
struct platform_device *audio_pdev;
struct platform_device *pdev;
+ struct drm_device *drm_dev;
struct dp_catalog *catalog;
struct dp_panel *panel;
@@ -136,7 +137,8 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_1_BIT)
| (parity_byte << PARITY_BYTE_1_BIT));
- DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
@@ -148,7 +150,8 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_2_BIT)
| (parity_byte << PARITY_BYTE_2_BIT));
- DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
@@ -162,7 +165,8 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_3_BIT)
| (parity_byte << PARITY_BYTE_3_BIT));
- DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
@@ -183,8 +187,9 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_1_BIT)
| (parity_byte << PARITY_BYTE_1_BIT));
- DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
- value, parity_byte);
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
@@ -196,7 +201,8 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_2_BIT)
| (parity_byte << PARITY_BYTE_2_BIT));
- DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
@@ -209,7 +215,8 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_3_BIT)
| (parity_byte << PARITY_BYTE_3_BIT));
- DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
@@ -229,7 +236,8 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_1_BIT)
| (parity_byte << PARITY_BYTE_1_BIT));
- DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
@@ -242,7 +250,8 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_2_BIT)
| (parity_byte << PARITY_BYTE_2_BIT));
- DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
@@ -255,7 +264,8 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_3_BIT)
| (parity_byte << PARITY_BYTE_3_BIT));
- DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
new_value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
@@ -275,7 +285,8 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_1_BIT)
| (parity_byte << PARITY_BYTE_1_BIT));
- DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
@@ -288,7 +299,8 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_2_BIT)
| (parity_byte << PARITY_BYTE_2_BIT));
- DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
@@ -301,7 +313,8 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_3_BIT)
| (parity_byte << PARITY_BYTE_3_BIT));
- DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
@@ -321,7 +334,8 @@ static void dp_audio_isrc_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_1_BIT)
| (parity_byte << PARITY_BYTE_1_BIT));
- DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
@@ -334,7 +348,8 @@ static void dp_audio_isrc_sdp(struct dp_audio_private *audio)
parity_byte = dp_audio_calculate_parity(new_value);
value |= ((new_value << HEADER_BYTE_2_BIT)
| (parity_byte << PARITY_BYTE_2_BIT));
- DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
+ drm_dbg_dp(audio->drm_dev,
+ "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
value, parity_byte);
dp_audio_set_header(catalog, value,
DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
@@ -370,7 +385,7 @@ static void dp_audio_setup_acr(struct dp_audio_private *audio)
select = 3;
break;
default:
- DRM_DEBUG_DP("Unknown link rate\n");
+ drm_dbg_dp(audio->drm_dev, "Unknown link rate\n");
select = 0;
break;
}
@@ -395,7 +410,8 @@ static void dp_audio_safe_to_exit_level(struct dp_audio_private *audio)
safe_to_exit_level = 5;
break;
default:
- DRM_DEBUG_DP("setting the default safe_to_exit_level = %u\n",
+ drm_dbg_dp(audio->drm_dev,
+ "setting the default safe_to_exit_level = %u\n",
safe_to_exit_level);
safe_to_exit_level = 14;
break;
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 6d36f63c3338..d030a93a08c3 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -34,6 +34,7 @@ struct dp_aux_private {
bool no_send_addr;
bool no_send_stop;
bool initted;
+ bool is_edp;
u32 offset;
u32 segment;
@@ -337,6 +338,22 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux,
goto exit;
}
+ /*
+ * For eDP it's important to give a reasonably long wait here for HPD
+ * to be asserted. This is because the panel driver may have _just_
+ * turned on the panel and then tried to do an AUX transfer. The panel
+ * driver has no way of knowing when the panel is ready, so it's up
+ * to us to wait. For DP we never get into this situation so let's
+ * avoid ever doing the extra long wait for DP.
+ */
+ if (aux->is_edp) {
+ ret = dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog);
+ if (ret) {
+ DRM_DEBUG_DP("Panel not ready for aux transactions\n");
+ goto exit;
+ }
+ }
+
dp_aux_update_offset_and_segment(aux, msg);
dp_aux_transfer_helper(aux, msg, true);
@@ -491,7 +508,8 @@ void dp_aux_unregister(struct drm_dp_aux *dp_aux)
drm_dp_aux_unregister(dp_aux);
}
-struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog)
+struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,
+ bool is_edp)
{
struct dp_aux_private *aux;
@@ -506,6 +524,7 @@ struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog)
init_completion(&aux->comp);
aux->cmd_busy = false;
+ aux->is_edp = is_edp;
mutex_init(&aux->mutex);
aux->dev = dev;
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index c64951215ab5..e930974bcb5b 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -16,7 +16,8 @@ void dp_aux_init(struct drm_dp_aux *dp_aux);
void dp_aux_deinit(struct drm_dp_aux *dp_aux);
void dp_aux_reconfig(struct drm_dp_aux *dp_aux);
-struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog);
+struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog,
+ bool is_edp);
void dp_aux_put(struct drm_dp_aux *aux);
#endif /*__DP_AUX_H_*/
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index b5dd0240d1dc..7257515871a9 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -24,6 +24,8 @@
#define DP_INTERRUPT_STATUS_ACK_SHIFT 1
#define DP_INTERRUPT_STATUS_MASK_SHIFT 2
+#define DP_INTF_CONFIG_DATABUS_WIDEN BIT(4)
+
#define DP_INTERRUPT_STATUS1 \
(DP_INTR_AUX_I2C_DONE| \
DP_INTR_WRONG_ADDR | DP_INTR_TIMEOUT | \
@@ -47,6 +49,7 @@
struct dp_catalog_private {
struct device *dev;
+ struct drm_device *drm_dev;
struct dp_io *io;
u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX];
struct dp_catalog dp_catalog;
@@ -80,7 +83,7 @@ static inline void dp_write_aux(struct dp_catalog_private *catalog,
writel(data, catalog->io->dp_controller.aux.base + offset);
}
-static inline u32 dp_read_ahb(struct dp_catalog_private *catalog, u32 offset)
+static inline u32 dp_read_ahb(const struct dp_catalog_private *catalog, u32 offset)
{
return readl_relaxed(catalog->io->dp_controller.ahb.base + offset);
}
@@ -242,6 +245,19 @@ void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog)
phy_calibrate(phy);
}
+int dp_catalog_aux_wait_for_hpd_connect_state(struct dp_catalog *dp_catalog)
+{
+ u32 state;
+ struct dp_catalog_private *catalog = container_of(dp_catalog,
+ struct dp_catalog_private, dp_catalog);
+
+ /* poll for hpd connected status every 2ms and timeout after 500ms */
+ return readl_poll_timeout(catalog->io->dp_controller.aux.base +
+ REG_DP_DP_HPD_INT_STATUS,
+ state, state & DP_DP_HPD_STATE_STATUS_CONNECTED,
+ 2000, 500000);
+}
+
static void dump_regs(void __iomem *base, int len)
{
int i;
@@ -322,7 +338,7 @@ void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 cfg)
struct dp_catalog_private *catalog = container_of(dp_catalog,
struct dp_catalog_private, dp_catalog);
- DRM_DEBUG_DP("DP_CONFIGURATION_CTRL=0x%x\n", cfg);
+ drm_dbg_dp(catalog->drm_dev, "DP_CONFIGURATION_CTRL=0x%x\n", cfg);
dp_write_link(catalog, REG_DP_CONFIGURATION_CTRL, cfg);
}
@@ -350,7 +366,7 @@ void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog,
struct dp_catalog_private *catalog = container_of(dp_catalog,
struct dp_catalog_private, dp_catalog);
- DRM_DEBUG_DP("enable=%d\n", enable);
+ drm_dbg_dp(catalog->drm_dev, "enable=%d\n", enable);
if (enable) {
/*
* To make sure link reg writes happens before other operation,
@@ -395,7 +411,7 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog,
/* Configure clock to synchronous mode */
misc_val |= DP_MISC0_SYNCHRONOUS_CLK;
- DRM_DEBUG_DP("misc settings = 0x%x\n", misc_val);
+ drm_dbg_dp(catalog->drm_dev, "misc settings = 0x%x\n", misc_val);
dp_write_link(catalog, REG_DP_MISC1_MISC0, misc_val);
}
@@ -450,7 +466,7 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
if (link_rate_hbr3 == rate)
nvid *= 3;
- DRM_DEBUG_DP("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
+ drm_dbg_dp(catalog->drm_dev, "mvid=0x%x, nvid=0x%x\n", mvid, nvid);
dp_write_link(catalog, REG_DP_SOFTWARE_MVID, mvid);
dp_write_link(catalog, REG_DP_SOFTWARE_NVID, nvid);
dp_write_p0(catalog, MMSS_DP_DSC_DTO, 0x0);
@@ -465,7 +481,7 @@ int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog,
struct dp_catalog_private, dp_catalog);
bit = BIT(state_bit - 1);
- DRM_DEBUG_DP("hw: bit=%d train=%d\n", bit, state_bit);
+ drm_dbg_dp(catalog->drm_dev, "hw: bit=%d train=%d\n", bit, state_bit);
dp_catalog_ctrl_state_ctrl(dp_catalog, bit);
bit = BIT(state_bit - 1) << DP_MAINLINK_READY_LINK_TRAINING_SHIFT;
@@ -483,6 +499,22 @@ int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog,
}
/**
+ * dp_catalog_hw_revision() - retrieve DP hw revision
+ *
+ * @dp_catalog: DP catalog structure
+ *
+ * Return: DP controller hw revision
+ *
+ */
+u32 dp_catalog_hw_revision(const struct dp_catalog *dp_catalog)
+{
+ const struct dp_catalog_private *catalog = container_of(dp_catalog,
+ struct dp_catalog_private, dp_catalog);
+
+ return dp_read_ahb(catalog, REG_DP_HW_VERSION);
+}
+
+/**
* dp_catalog_ctrl_reset() - reset DP controller
*
* @dp_catalog: DP catalog structure
@@ -557,7 +589,8 @@ void dp_catalog_hpd_config_intr(struct dp_catalog *dp_catalog,
config = (en ? config | intr_mask : config & ~intr_mask);
- DRM_DEBUG_DP("intr_mask=%#x config=%#x\n", intr_mask, config);
+ drm_dbg_dp(catalog->drm_dev, "intr_mask=%#x config=%#x\n",
+ intr_mask, config);
dp_write_aux(catalog, REG_DP_DP_HPD_INT_MASK,
config & DP_DP_HPD_INT_MASK);
}
@@ -569,10 +602,6 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog)
u32 reftimer = dp_read_aux(catalog, REG_DP_DP_HPD_REFTIMER);
- /* enable HPD plug and unplug interrupts */
- dp_catalog_hpd_config_intr(dp_catalog,
- DP_DP_HPD_PLUG_INT_MASK | DP_DP_HPD_UNPLUG_INT_MASK, true);
-
/* Configure REFTIMER and enable it */
reftimer |= DP_DP_HPD_REFTIMER_ENABLE;
dp_write_aux(catalog, REG_DP_DP_HPD_REFTIMER, reftimer);
@@ -588,7 +617,7 @@ u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog)
u32 status;
status = dp_read_aux(catalog, REG_DP_DP_HPD_INT_STATUS);
- DRM_DEBUG_DP("aux status: %#x\n", status);
+ drm_dbg_dp(catalog->drm_dev, "aux status: %#x\n", status);
status >>= DP_DP_HPD_STATE_STATUS_BITS_SHIFT;
status &= DP_DP_HPD_STATE_STATUS_BITS_MASK;
@@ -599,13 +628,21 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog)
{
struct dp_catalog_private *catalog = container_of(dp_catalog,
struct dp_catalog_private, dp_catalog);
- int isr = 0;
+ int isr, mask;
isr = dp_read_aux(catalog, REG_DP_DP_HPD_INT_STATUS);
dp_write_aux(catalog, REG_DP_DP_HPD_INT_ACK,
(isr & DP_DP_HPD_INT_MASK));
+ mask = dp_read_aux(catalog, REG_DP_DP_HPD_INT_MASK);
- return isr;
+ /*
+ * We only want to return interrupts that are unmasked to the caller.
+ * However, the interrupt status field also contains other
+ * informational bits about the HPD state status, so we only mask
+ * out the part of the register that tells us about which interrupts
+ * are pending.
+ */
+ return isr & (mask | ~DP_DP_HPD_INT_MASK);
}
int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog)
@@ -664,7 +701,7 @@ void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
/* Make sure to clear the current pattern before starting a new one */
dp_write_link(catalog, REG_DP_STATE_CTRL, 0x0);
- DRM_DEBUG_DP("pattern: %#x\n", pattern);
+ drm_dbg_dp(catalog->drm_dev, "pattern: %#x\n", pattern);
switch (pattern) {
case DP_PHY_TEST_PATTERN_D10_2:
dp_write_link(catalog, REG_DP_STATE_CTRL,
@@ -725,7 +762,8 @@ void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
DP_STATE_CTRL_LINK_TRAINING_PATTERN4);
break;
default:
- DRM_DEBUG_DP("No valid test pattern requested: %#x\n", pattern);
+ drm_dbg_dp(catalog->drm_dev,
+ "No valid test pattern requested: %#x\n", pattern);
break;
}
}
@@ -743,6 +781,7 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog)
{
struct dp_catalog_private *catalog = container_of(dp_catalog,
struct dp_catalog_private, dp_catalog);
+ u32 reg;
dp_write_link(catalog, REG_DP_TOTAL_HOR_VER,
dp_catalog->total);
@@ -751,7 +790,18 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog)
dp_write_link(catalog, REG_DP_HSYNC_VSYNC_WIDTH_POLARITY,
dp_catalog->width_blanking);
dp_write_link(catalog, REG_DP_ACTIVE_HOR_VER, dp_catalog->dp_active);
- dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, 0);
+
+ reg = dp_read_p0(catalog, MMSS_DP_INTF_CONFIG);
+
+ if (dp_catalog->wide_bus_en)
+ reg |= DP_INTF_CONFIG_DATABUS_WIDEN;
+ else
+ reg &= ~DP_INTF_CONFIG_DATABUS_WIDEN;
+
+
+ DRM_DEBUG_DP("wide_bus_en=%d reg=%#x\n", dp_catalog->wide_bus_en, reg);
+
+ dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, reg);
return 0;
}
@@ -820,7 +870,7 @@ void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog,
DP_BIST_ENABLE_DPBIST_EN);
dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN,
DP_TIMING_ENGINE_EN_EN);
- DRM_DEBUG_DP("%s: enabled tpg\n", __func__);
+ drm_dbg_dp(catalog->drm_dev, "%s: enabled tpg\n", __func__);
}
void dp_catalog_panel_tpg_disable(struct dp_catalog *dp_catalog)
@@ -909,7 +959,8 @@ void dp_catalog_audio_config_acr(struct dp_catalog *dp_catalog)
select = dp_catalog->audio_data;
acr_ctrl = select << 4 | BIT(31) | BIT(8) | BIT(14);
- DRM_DEBUG_DP("select: %#x, acr_ctrl: %#x\n", select, acr_ctrl);
+ drm_dbg_dp(catalog->drm_dev, "select: %#x, acr_ctrl: %#x\n",
+ select, acr_ctrl);
dp_write_link(catalog, MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl);
}
@@ -934,7 +985,7 @@ void dp_catalog_audio_enable(struct dp_catalog *dp_catalog)
else
audio_ctrl &= ~BIT(0);
- DRM_DEBUG_DP("dp_audio_cfg = 0x%x\n", audio_ctrl);
+ drm_dbg_dp(catalog->drm_dev, "dp_audio_cfg = 0x%x\n", audio_ctrl);
dp_write_link(catalog, MMSS_DP_AUDIO_CFG, audio_ctrl);
/* make sure audio engine is disabled */
@@ -965,7 +1016,7 @@ void dp_catalog_audio_config_sdp(struct dp_catalog *dp_catalog)
/* AUDIO_INFOFRAME_SDP_EN */
sdp_cfg |= BIT(20);
- DRM_DEBUG_DP("sdp_cfg = 0x%x\n", sdp_cfg);
+ drm_dbg_dp(catalog->drm_dev, "sdp_cfg = 0x%x\n", sdp_cfg);
dp_write_link(catalog, MMSS_DP_SDP_CFG, sdp_cfg);
@@ -975,7 +1026,7 @@ void dp_catalog_audio_config_sdp(struct dp_catalog *dp_catalog)
/* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */
sdp_cfg2 &= ~BIT(1);
- DRM_DEBUG_DP("sdp_cfg2 = 0x%x\n", sdp_cfg2);
+ drm_dbg_dp(catalog->drm_dev, "sdp_cfg2 = 0x%x\n", sdp_cfg2);
dp_write_link(catalog, MMSS_DP_SDP_CFG2, sdp_cfg2);
}
@@ -1037,7 +1088,8 @@ void dp_catalog_audio_sfe_level(struct dp_catalog *dp_catalog)
mainlink_levels &= 0xFE0;
mainlink_levels |= safe_to_exit_level;
- DRM_DEBUG_DP("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n",
+ drm_dbg_dp(catalog->drm_dev,
+ "mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n",
mainlink_levels, safe_to_exit_level);
dp_write_link(catalog, REG_DP_MAINLINK_LEVELS, mainlink_levels);
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 7dea1012ae66..1f717f45c115 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -70,6 +70,7 @@ struct dp_catalog {
enum dp_catalog_audio_sdp_type sdp_type;
enum dp_catalog_audio_header_type sdp_header;
u32 audio_data;
+ bool wide_bus_en;
};
/* Debug module */
@@ -84,6 +85,7 @@ int dp_catalog_aux_clear_hw_interrupts(struct dp_catalog *dp_catalog);
void dp_catalog_aux_reset(struct dp_catalog *dp_catalog);
void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, bool enable);
void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog);
+int dp_catalog_aux_wait_for_hpd_connect_state(struct dp_catalog *dp_catalog);
u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog);
/* DP Controller APIs */
@@ -95,6 +97,7 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, u32 cc, u32 tb);
void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 rate,
u32 stream_rate_khz, bool fixed_nvid);
int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, u32 pattern);
+u32 dp_catalog_hw_revision(const struct dp_catalog *dp_catalog);
void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog);
bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog *dp_catalog);
void dp_catalog_ctrl_enable_irq(struct dp_catalog *dp_catalog, bool enable);
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index a96f6a8fa9bd..b7f5b8d3bbd6 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -70,6 +70,7 @@ struct dp_vc_tu_mapping_table {
struct dp_ctrl_private {
struct dp_ctrl dp_ctrl;
+ struct drm_device *drm_dev;
struct device *dev;
struct drm_dp_aux *aux;
struct dp_panel *panel;
@@ -114,7 +115,7 @@ void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl)
IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES))
pr_warn("PUSH_IDLE pattern timedout\n");
- DRM_DEBUG_DP("mainlink off done\n");
+ drm_dbg_dp(ctrl->drm_dev, "mainlink off\n");
}
static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
@@ -603,8 +604,9 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu)
}
}
-static void _dp_ctrl_calc_tu(struct dp_tu_calc_input *in,
- struct dp_vc_tu_mapping_table *tu_table)
+static void _dp_ctrl_calc_tu(struct dp_ctrl_private *ctrl,
+ struct dp_tu_calc_input *in,
+ struct dp_vc_tu_mapping_table *tu_table)
{
struct tu_algo_data *tu;
int compare_result_1, compare_result_2;
@@ -687,8 +689,8 @@ static void _dp_ctrl_calc_tu(struct dp_tu_calc_input *in,
if (tu->dsc_en && compare_result_1 && compare_result_2) {
HBLANK_MARGIN += 4;
- DRM_DEBUG_DP("Info: increase HBLANK_MARGIN to %d\n",
- HBLANK_MARGIN);
+ drm_dbg_dp(ctrl->drm_dev,
+ "increase HBLANK_MARGIN to %d\n", HBLANK_MARGIN);
}
tu_size_calc:
@@ -722,8 +724,10 @@ tu_size_calc:
tu->n_tus += 1;
tu->even_distribution_legacy = tu->n_tus % tu->nlanes == 0 ? 1 : 0;
- DRM_DEBUG_DP("Info: n_sym = %d, num_of_tus = %d\n",
- tu->valid_boundary_link, tu->n_tus);
+
+ drm_dbg_dp(ctrl->drm_dev,
+ "n_sym = %d, num_of_tus = %d\n",
+ tu->valid_boundary_link, tu->n_tus);
temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1);
temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp);
@@ -916,19 +920,20 @@ tu_size_calc:
tu_table->lower_boundary_count = tu->lower_boundary_count;
tu_table->tu_size_minus1 = tu->tu_size_minus1;
- DRM_DEBUG_DP("TU: valid_boundary_link: %d\n",
+ drm_dbg_dp(ctrl->drm_dev, "TU: valid_boundary_link: %d\n",
tu_table->valid_boundary_link);
- DRM_DEBUG_DP("TU: delay_start_link: %d\n",
+ drm_dbg_dp(ctrl->drm_dev, "TU: delay_start_link: %d\n",
tu_table->delay_start_link);
- DRM_DEBUG_DP("TU: boundary_moderation_en: %d\n",
+ drm_dbg_dp(ctrl->drm_dev, "TU: boundary_moderation_en: %d\n",
tu_table->boundary_moderation_en);
- DRM_DEBUG_DP("TU: valid_lower_boundary_link: %d\n",
+ drm_dbg_dp(ctrl->drm_dev, "TU: valid_lower_boundary_link: %d\n",
tu_table->valid_lower_boundary_link);
- DRM_DEBUG_DP("TU: upper_boundary_count: %d\n",
+ drm_dbg_dp(ctrl->drm_dev, "TU: upper_boundary_count: %d\n",
tu_table->upper_boundary_count);
- DRM_DEBUG_DP("TU: lower_boundary_count: %d\n",
+ drm_dbg_dp(ctrl->drm_dev, "TU: lower_boundary_count: %d\n",
tu_table->lower_boundary_count);
- DRM_DEBUG_DP("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1);
+ drm_dbg_dp(ctrl->drm_dev, "TU: tu_size_minus1: %d\n",
+ tu_table->tu_size_minus1);
kfree(tu);
}
@@ -954,7 +959,7 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
in.num_of_dsc_slices = 0;
in.compress_ratio = 100;
- _dp_ctrl_calc_tu(&in, tu_table);
+ _dp_ctrl_calc_tu(ctrl, &in, tu_table);
}
static void dp_ctrl_setup_tr_unit(struct dp_ctrl_private *ctrl)
@@ -1005,8 +1010,9 @@ static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
u32 voltage_swing_level = link->phy_params.v_level;
u32 pre_emphasis_level = link->phy_params.p_level;
- DRM_DEBUG_DP("voltage level: %d emphasis level: %d\n", voltage_swing_level,
- pre_emphasis_level);
+ drm_dbg_dp(ctrl->drm_dev,
+ "voltage level: %d emphasis level: %d\n",
+ voltage_swing_level, pre_emphasis_level);
ret = dp_catalog_ctrl_update_vx_px(ctrl->catalog,
voltage_swing_level, pre_emphasis_level);
@@ -1014,13 +1020,15 @@ static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
return ret;
if (voltage_swing_level >= DP_TRAIN_VOLTAGE_SWING_MAX) {
- DRM_DEBUG_DP("max. voltage swing level reached %d\n",
+ drm_dbg_dp(ctrl->drm_dev,
+ "max. voltage swing level reached %d\n",
voltage_swing_level);
max_level_reached |= DP_TRAIN_MAX_SWING_REACHED;
}
if (pre_emphasis_level >= DP_TRAIN_PRE_EMPHASIS_MAX) {
- DRM_DEBUG_DP("max. pre-emphasis level reached %d\n",
+ drm_dbg_dp(ctrl->drm_dev,
+ "max. pre-emphasis level reached %d\n",
pre_emphasis_level);
max_level_reached |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
}
@@ -1032,8 +1040,8 @@ static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
buf[lane] = voltage_swing_level | pre_emphasis_level
| max_level_reached;
- DRM_DEBUG_DP("sink: p|v=0x%x\n", voltage_swing_level
- | pre_emphasis_level);
+ 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 (ret == lane_cnt)
@@ -1048,7 +1056,7 @@ static bool dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
u8 buf;
int ret = 0;
- DRM_DEBUG_DP("sink: pattern=%x\n", pattern);
+ drm_dbg_dp(ctrl->drm_dev, "sink: pattern=%x\n", pattern);
buf = pattern;
@@ -1119,8 +1127,6 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl,
old_v_level = ctrl->link->phy_params.v_level;
}
- DRM_DEBUG_DP("clock recovery not done, adjusting vx px\n");
-
dp_link_adjust_levels(ctrl->link, link_status);
ret = dp_ctrl_update_vx_px(ctrl);
if (ret)
@@ -1151,8 +1157,10 @@ static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
break;
}
- if (!ret)
- DRM_DEBUG_DP("new rate=0x%x\n", ctrl->link->link_params.rate);
+ if (!ret) {
+ drm_dbg_dp(ctrl->drm_dev, "new rate=0x%x\n",
+ ctrl->link->link_params.rate);
+ }
return ret;
}
@@ -1271,7 +1279,7 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl,
}
/* print success info as this is a result of user initiated action */
- DRM_DEBUG_DP("link training #1 successful\n");
+ drm_dbg_dp(ctrl->drm_dev, "link training #1 successful\n");
ret = dp_ctrl_link_train_2(ctrl, training_step);
if (ret) {
@@ -1280,7 +1288,7 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl,
}
/* print success info as this is a result of user initiated action */
- DRM_DEBUG_DP("link training #2 successful\n");
+ drm_dbg_dp(ctrl->drm_dev, "link training #2 successful\n");
end:
dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
@@ -1320,7 +1328,8 @@ static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl,
cfg++;
}
- DRM_DEBUG_DP("setting rate=%lu on clk=%s\n", rate, name);
+ drm_dbg_dp(ctrl->drm_dev, "setting rate=%lu on clk=%s\n",
+ rate, name);
if (num)
cfg->rate = rate;
@@ -1350,7 +1359,7 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl)
if (ret)
DRM_ERROR("Unable to start link clocks. ret=%d\n", ret);
- DRM_DEBUG_DP("link rate=%d pixel_clk=%d\n",
+ drm_dbg_dp(ctrl->drm_dev, "link rate=%d pixel_clk=%d\n",
ctrl->link->link_params.rate, ctrl->dp_ctrl.pixel_rate);
return ret;
@@ -1367,7 +1376,7 @@ static int dp_ctrl_enable_stream_clocks(struct dp_ctrl_private *ctrl)
if (ret)
DRM_ERROR("Unabled to start pixel clocks. ret=%d\n", ret);
- DRM_DEBUG_DP("link rate=%d pixel_clk=%d\n",
+ drm_dbg_dp(ctrl->drm_dev, "link rate=%d pixel_clk=%d\n",
ctrl->link->link_params.rate, ctrl->dp_ctrl.pixel_rate);
return ret;
@@ -1381,8 +1390,13 @@ void dp_ctrl_reset_irq_ctrl(struct dp_ctrl *dp_ctrl, bool enable)
dp_catalog_ctrl_reset(ctrl->catalog);
- if (enable)
- dp_catalog_ctrl_enable_irq(ctrl->catalog, enable);
+ /*
+ * all dp controller programmable registers will not
+ * be reset to default value after DP_SW_RESET
+ * therefore interrupt mask bits have to be updated
+ * to enable/disable interrupts
+ */
+ dp_catalog_ctrl_enable_irq(ctrl->catalog, enable);
}
void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl)
@@ -1397,7 +1411,8 @@ void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl)
dp_catalog_ctrl_phy_reset(ctrl->catalog);
phy_init(phy);
- DRM_DEBUG_DP("phy=%p init=%d power_on=%d\n",
+
+ drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n",
phy, phy->init_count, phy->power_count);
}
@@ -1413,7 +1428,7 @@ void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl)
dp_catalog_ctrl_phy_reset(ctrl->catalog);
phy_exit(phy);
- DRM_DEBUG_DP("phy=%p init=%d power_on=%d\n",
+ drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n",
phy, phy->init_count, phy->power_count);
}
@@ -1489,7 +1504,7 @@ static int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl)
phy_exit(phy);
phy_init(phy);
- DRM_DEBUG_DP("phy=%p init=%d power_on=%d\n",
+ drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n",
phy, phy->init_count, phy->power_count);
return 0;
}
@@ -1524,7 +1539,8 @@ static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)
int ret = 0;
if (!ctrl->link->phy_params.phy_test_pattern_sel) {
- DRM_DEBUG_DP("no test pattern selected by sink\n");
+ drm_dbg_dp(ctrl->drm_dev,
+ "no test pattern selected by sink\n");
return ret;
}
@@ -1533,7 +1549,7 @@ static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)
* running. Add the global reset just before disabling the
* link clocks and core clocks.
*/
- ret = dp_ctrl_off_link_stream(&ctrl->dp_ctrl);
+ ret = dp_ctrl_off(&ctrl->dp_ctrl);
if (ret) {
DRM_ERROR("failed to disable DP controller\n");
return ret;
@@ -1554,7 +1570,7 @@ static bool dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
u32 pattern_sent = 0x0;
u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel;
- DRM_DEBUG_DP("request: 0x%x\n", pattern_requested);
+ drm_dbg_dp(ctrl->drm_dev, "request: 0x%x\n", pattern_requested);
if (dp_catalog_ctrl_update_vx_px(ctrl->catalog,
ctrl->link->phy_params.v_level,
@@ -1595,8 +1611,8 @@ static bool dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
success = false;
}
- DRM_DEBUG_DP("%s: test->0x%x\n", success ? "success" : "failed",
- pattern_requested);
+ drm_dbg_dp(ctrl->drm_dev, "%s: test->0x%x\n",
+ success ? "success" : "failed", pattern_requested);
return success;
}
@@ -1614,7 +1630,7 @@ void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl)
sink_request = ctrl->link->sink_request;
if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
- DRM_DEBUG_DP("PHY_TEST_PATTERN request\n");
+ drm_dbg_dp(ctrl->drm_dev, "PHY_TEST_PATTERN request\n");
if (dp_ctrl_process_phy_test_request(ctrl)) {
DRM_ERROR("process phy_test_req failed\n");
return;
@@ -1686,7 +1702,8 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
dp_power_clk_enable(ctrl->power, DP_CORE_PM, true);
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
- DRM_DEBUG_DP("using phy test link parameters\n");
+ drm_dbg_dp(ctrl->drm_dev,
+ "using phy test link parameters\n");
if (!ctrl->panel->dp_mode.drm_mode.clock)
ctrl->dp_ctrl.pixel_rate = phy_cts_pixel_clk_khz;
} else {
@@ -1696,12 +1713,10 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;
}
- DRM_DEBUG_DP("rate=%d, num_lanes=%d, pixel_rate=%d\n",
- ctrl->link->link_params.rate,
- ctrl->link->link_params.num_lanes, ctrl->dp_ctrl.pixel_rate);
+ drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%d\n",
+ ctrl->link->link_params.rate, ctrl->link->link_params.num_lanes,
+ ctrl->dp_ctrl.pixel_rate);
- ctrl->link->phy_params.p_level = 0;
- ctrl->link->phy_params.v_level = 0;
rc = dp_ctrl_enable_mainlink_clocks(ctrl);
if (rc)
@@ -1803,6 +1818,7 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
int ret = 0;
bool mainlink_ready = false;
struct dp_ctrl_private *ctrl;
+ unsigned long pixel_rate_orig;
if (!dp_ctrl)
return -EINVAL;
@@ -1811,7 +1827,11 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;
- DRM_DEBUG_DP("rate=%d, num_lanes=%d, pixel_rate=%d\n",
+ pixel_rate_orig = ctrl->dp_ctrl.pixel_rate;
+ if (dp_ctrl->wide_bus_en)
+ ctrl->dp_ctrl.pixel_rate >>= 1;
+
+ drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%d\n",
ctrl->link->link_params.rate,
ctrl->link->link_params.num_lanes, ctrl->dp_ctrl.pixel_rate);
@@ -1823,12 +1843,6 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
}
}
- if (!dp_ctrl_channel_eq_ok(ctrl))
- dp_ctrl_link_retrain(ctrl);
-
- /* stop txing train pattern to end link training */
- dp_ctrl_clear_training_pattern(ctrl);
-
ret = dp_ctrl_enable_stream_clocks(ctrl);
if (ret) {
DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);
@@ -1840,6 +1854,12 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
return 0;
}
+ if (!dp_ctrl_channel_eq_ok(ctrl))
+ dp_ctrl_link_retrain(ctrl);
+
+ /* stop txing train pattern to end link training */
+ dp_ctrl_clear_training_pattern(ctrl);
+
/*
* Set up transfer unit values and set controller state to send
* video.
@@ -1850,7 +1870,7 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
dp_catalog_ctrl_config_msa(ctrl->catalog,
ctrl->link->link_params.rate,
- ctrl->dp_ctrl.pixel_rate, dp_ctrl_use_fixed_nvid(ctrl));
+ pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl));
dp_ctrl_setup_tr_unit(ctrl);
@@ -1861,7 +1881,8 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
return ret;
mainlink_ready = dp_catalog_ctrl_mainlink_ready(ctrl->catalog);
- DRM_DEBUG_DP("mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
+ drm_dbg_dp(ctrl->drm_dev,
+ "mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
end:
return ret;
@@ -1897,20 +1918,46 @@ int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
return ret;
}
- DRM_DEBUG_DP("Before, phy=%x init_count=%d power_on=%d\n",
- (u32)(uintptr_t)phy, phy->init_count, phy->power_count);
-
phy_power_off(phy);
/* aux channel down, reinit phy */
phy_exit(phy);
phy_init(phy);
- DRM_DEBUG_DP("phy=%p init=%d power_on=%d\n",
+ drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n",
phy, phy->init_count, phy->power_count);
return ret;
}
+int dp_ctrl_off_link(struct dp_ctrl *dp_ctrl)
+{
+ struct dp_ctrl_private *ctrl;
+ struct dp_io *dp_io;
+ struct phy *phy;
+ int ret;
+
+ ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
+ dp_io = &ctrl->parser->io;
+ phy = dp_io->phy;
+
+ dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
+
+ ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
+ if (ret) {
+ DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
+ }
+
+ DRM_DEBUG_DP("Before, phy=%p init_count=%d power_on=%d\n",
+ phy, phy->init_count, phy->power_count);
+
+ phy_power_off(phy);
+
+ DRM_DEBUG_DP("After, phy=%p init_count=%d power_on=%d\n",
+ phy, phy->init_count, phy->power_count);
+
+ return ret;
+}
+
int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
{
struct dp_ctrl_private *ctrl;
@@ -1939,7 +1986,7 @@ int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
}
phy_power_off(phy);
- DRM_DEBUG_DP("phy=%p init=%d power_on=%d\n",
+ drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n",
phy, phy->init_count, phy->power_count);
return ret;
@@ -1958,12 +2005,12 @@ void dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
isr = dp_catalog_ctrl_get_interrupt(ctrl->catalog);
if (isr & DP_CTRL_INTR_READY_FOR_VIDEO) {
- DRM_DEBUG_DP("dp_video_ready\n");
+ drm_dbg_dp(ctrl->drm_dev, "dp_video_ready\n");
complete(&ctrl->video_comp);
}
if (isr & DP_CTRL_INTR_IDLE_PATTERN_SENT) {
- DRM_DEBUG_DP("idle_patterns_sent\n");
+ drm_dbg_dp(ctrl->drm_dev, "idle_patterns_sent\n");
complete(&ctrl->idle_comp);
}
}
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 2433edbc70a6..0745fde01b45 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -17,11 +17,13 @@ struct dp_ctrl {
bool orientation;
atomic_t aborted;
u32 pixel_rate;
+ bool wide_bus_en;
};
int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl);
int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl);
int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl);
+int dp_ctrl_off_link(struct dp_ctrl *dp_ctrl);
int dp_ctrl_off(struct dp_ctrl *dp_ctrl);
void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl);
void dp_ctrl_isr(struct dp_ctrl *dp_ctrl);
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index 2f9c943f12d5..5e35033ba3e4 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -44,8 +44,6 @@ static int dp_debug_show(struct seq_file *seq, void *p)
drm_mode = &debug->panel->dp_mode.drm_mode;
seq_printf(seq, "\tname = %s\n", DEBUG_NAME);
- seq_printf(seq, "\tdp_panel\n\t\tmax_pclk_khz = %d\n",
- debug->panel->max_pclk_khz);
seq_printf(seq, "\tdrm_dp_link\n\t\trate = %u\n",
debug->panel->link_info.rate);
seq_printf(seq, "\t\tnum_lanes = %u\n",
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index a42732b67349..bce77935394f 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -10,7 +10,7 @@
#include <linux/component.h>
#include <linux/of_irq.h>
#include <linux/delay.h>
-#include <drm/drm_panel.h>
+#include <drm/display/drm_dp_aux_bus.h>
#include "msm_drv.h"
#include "msm_kms.h"
@@ -42,7 +42,7 @@ enum {
/* event thread connection state */
enum {
ST_DISCONNECTED,
- ST_CONNECT_PENDING,
+ ST_MAINLINK_READY,
ST_CONNECTED,
ST_DISCONNECT_PENDING,
ST_DISPLAY_OFF,
@@ -57,14 +57,11 @@ enum {
EV_IRQ_HPD_INT,
EV_HPD_UNPLUG_INT,
EV_USER_NOTIFICATION,
- EV_CONNECT_PENDING_TIMEOUT,
- EV_DISCONNECT_PENDING_TIMEOUT,
};
#define EVENT_TIMEOUT (HZ/10) /* 100ms */
#define DP_EVENT_Q_MAX 8
-#define DP_TIMEOUT_5_SECOND (5000/EVENT_TIMEOUT)
#define DP_TIMEOUT_NONE 0
#define WAIT_FOR_RESUME_TIMEOUT_JIFFIES (HZ / 2)
@@ -87,6 +84,7 @@ struct dp_display_private {
bool hpd_irq_on;
bool audio_supported;
+ struct drm_device *drm_dev;
struct platform_device *pdev;
struct dentry *root;
@@ -113,15 +111,19 @@ struct dp_display_private {
u32 hpd_state;
u32 event_pndx;
u32 event_gndx;
+ struct task_struct *ev_tsk;
struct dp_event event_list[DP_EVENT_Q_MAX];
spinlock_t event_lock;
+ bool wide_bus_en;
+
struct dp_audio *audio;
};
struct msm_dp_desc {
phys_addr_t io_start;
unsigned int connector_type;
+ bool wide_bus_en;
};
struct msm_dp_config {
@@ -138,8 +140,8 @@ static const struct msm_dp_config sc7180_dp_cfg = {
static const struct msm_dp_config sc7280_dp_cfg = {
.descs = (const struct msm_dp_desc[]) {
- [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
- [MSM_DP_CONTROLLER_1] = { .io_start = 0x0aea0000, .connector_type = DRM_MODE_CONNECTOR_eDP },
+ [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+ [MSM_DP_CONTROLLER_1] = { .io_start = 0x0aea0000, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
},
.num_descs = 2,
};
@@ -249,6 +251,8 @@ void dp_display_signal_audio_complete(struct msm_dp *dp_display)
complete_all(&dp->audio_comp);
}
+static int dp_hpd_event_thread_start(struct dp_display_private *dp_priv);
+
static int dp_display_bind(struct device *dev, struct device *master,
void *data)
{
@@ -260,14 +264,14 @@ static int dp_display_bind(struct device *dev, struct device *master,
dp->dp_display.drm_dev = drm;
priv->dp[dp->id] = &dp->dp_display;
- rc = dp->parser->parse(dp->parser, dp->dp_display.connector_type);
+ rc = dp->parser->parse(dp->parser);
if (rc) {
DRM_ERROR("device tree parsing failed\n");
goto end;
}
- dp->dp_display.next_bridge = dp->parser->next_bridge;
+ dp->drm_dev = drm;
dp->aux->drm_dev = drm;
rc = dp_aux_register(dp->aux);
if (rc) {
@@ -282,9 +286,18 @@ static int dp_display_bind(struct device *dev, struct device *master,
}
rc = dp_register_audio_driver(dev, dp->audio);
- if (rc)
+ if (rc) {
DRM_ERROR("Audio registration Dp failed\n");
+ goto end;
+ }
+
+ rc = dp_hpd_event_thread_start(dp);
+ if (rc) {
+ DRM_ERROR("Event thread create failed\n");
+ goto end;
+ }
+ return 0;
end:
return rc;
}
@@ -295,6 +308,11 @@ static void dp_display_unbind(struct device *dev, struct device *master,
struct dp_display_private *dp = dev_get_dp_display_private(dev);
struct msm_drm_private *priv = dev_get_drvdata(master);
+ /* disable all HPD interrupts */
+ dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, false);
+
+ kthread_stop(dp->ev_tsk);
+
dp_power_client_deinit(dp->power);
dp_aux_unregister(dp->aux);
priv->dp[dp->id] = NULL;
@@ -313,7 +331,8 @@ static bool dp_display_is_ds_bridge(struct dp_panel *panel)
static bool dp_display_is_sink_count_zero(struct dp_display_private *dp)
{
- DRM_DEBUG_DP("present=%#x sink_count=%d\n", dp->panel->dpcd[DP_DOWNSTREAMPORT_PRESENT],
+ drm_dbg_dp(dp->drm_dev, "present=%#x sink_count=%d\n",
+ dp->panel->dpcd[DP_DOWNSTREAMPORT_PRESENT],
dp->link->sink_count);
return dp_display_is_ds_bridge(dp->panel) &&
(dp->link->sink_count == 0);
@@ -336,7 +355,8 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp,
{
if ((hpd && dp->dp_display.is_connected) ||
(!hpd && !dp->dp_display.is_connected)) {
- DRM_DEBUG_DP("HPD already %s\n", (hpd ? "on" : "off"));
+ drm_dbg_dp(dp->drm_dev, "HPD already %s\n",
+ (hpd ? "on" : "off"));
return 0;
}
@@ -346,7 +366,8 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp,
dp->dp_display.is_connected = hpd;
- DRM_DEBUG_DP("hpd=%d\n", hpd);
+ drm_dbg_dp(dp->drm_dev, "type=%d hpd=%d\n",
+ dp->dp_display.connector_type, hpd);
dp_display_send_hpd_event(&dp->dp_display);
return 0;
@@ -370,7 +391,6 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
dp->audio_supported = drm_detect_monitor_audio(edid);
dp_panel_handle_sink_request(dp->panel);
- dp->dp_display.max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ;
dp->dp_display.max_dp_lanes = dp->parser->max_dp_lanes;
/*
@@ -394,7 +414,7 @@ end:
static void dp_display_host_phy_init(struct dp_display_private *dp)
{
- DRM_DEBUG_DP("type=%d core_init=%d phy_init=%d\n",
+ drm_dbg_dp(dp->drm_dev, "type=%d core_init=%d phy_init=%d\n",
dp->dp_display.connector_type, dp->core_initialized,
dp->phy_initialized);
@@ -406,7 +426,7 @@ static void dp_display_host_phy_init(struct dp_display_private *dp)
static void dp_display_host_phy_exit(struct dp_display_private *dp)
{
- DRM_DEBUG_DP("type=%d core_init=%d phy_init=%d\n",
+ drm_dbg_dp(dp->drm_dev, "type=%d core_init=%d phy_init=%d\n",
dp->dp_display.connector_type, dp->core_initialized,
dp->phy_initialized);
@@ -418,7 +438,7 @@ static void dp_display_host_phy_exit(struct dp_display_private *dp)
static void dp_display_host_init(struct dp_display_private *dp)
{
- DRM_DEBUG_DP("type=%d core_init=%d phy_init=%d\n",
+ drm_dbg_dp(dp->drm_dev, "type=%d core_init=%d phy_init=%d\n",
dp->dp_display.connector_type, dp->core_initialized,
dp->phy_initialized);
@@ -430,7 +450,7 @@ static void dp_display_host_init(struct dp_display_private *dp)
static void dp_display_host_deinit(struct dp_display_private *dp)
{
- DRM_DEBUG_DP("type=%d core_init=%d phy_init=%d\n",
+ drm_dbg_dp(dp->drm_dev, "type=%d core_init=%d phy_init=%d\n",
dp->dp_display.connector_type, dp->core_initialized,
dp->phy_initialized);
@@ -451,6 +471,11 @@ static int dp_display_usbpd_configure_cb(struct device *dev)
static int dp_display_usbpd_disconnect_cb(struct device *dev)
{
+ return 0;
+}
+
+static int dp_display_notify_disconnect(struct device *dev)
+{
struct dp_display_private *dp = dev_get_dp_display_private(dev);
dp_add_event(dp, EV_USER_NOTIFICATION, false, 0);
@@ -471,14 +496,14 @@ static int dp_display_handle_port_ststus_changed(struct dp_display_private *dp)
int rc = 0;
if (dp_display_is_sink_count_zero(dp)) {
- DRM_DEBUG_DP("sink count is zero, nothing to do\n");
+ drm_dbg_dp(dp->drm_dev, "sink count is zero, nothing to do\n");
if (dp->hpd_state != ST_DISCONNECTED) {
dp->hpd_state = ST_DISCONNECT_PENDING;
dp_add_event(dp, EV_USER_NOTIFICATION, false, 0);
}
} else {
if (dp->hpd_state == ST_DISCONNECTED) {
- dp->hpd_state = ST_CONNECT_PENDING;
+ dp->hpd_state = ST_MAINLINK_READY;
rc = dp_display_process_hpd_high(dp);
if (rc)
dp->hpd_state = ST_DISCONNECTED;
@@ -492,10 +517,11 @@ static int dp_display_handle_irq_hpd(struct dp_display_private *dp)
{
u32 sink_request = dp->link->sink_request;
- DRM_DEBUG_DP("%d\n", sink_request);
+ drm_dbg_dp(dp->drm_dev, "%d\n", sink_request);
if (dp->hpd_state == ST_DISCONNECTED) {
if (sink_request & DP_LINK_STATUS_UPDATED) {
- DRM_DEBUG_DP("Disconnected sink_request: %d\n", sink_request);
+ drm_dbg_dp(dp->drm_dev, "Disconnected sink_request: %d\n",
+ sink_request);
DRM_ERROR("Disconnected, no DP_LINK_STATUS_UPDATED\n");
return -EINVAL;
}
@@ -519,7 +545,8 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
rc = dp_link_process_request(dp->link);
if (!rc) {
sink_request = dp->link->sink_request;
- DRM_DEBUG_DP("hpd_state=%d sink_request=%d\n", dp->hpd_state, sink_request);
+ drm_dbg_dp(dp->drm_dev, "hpd_state=%d sink_request=%d\n",
+ dp->hpd_state, sink_request);
if (sink_request & DS_PORT_STATUS_CHANGED)
rc = dp_display_handle_port_ststus_changed(dp);
else
@@ -533,7 +560,6 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
{
struct dp_usbpd *hpd = dp->usbpd;
u32 state;
- u32 tout = DP_TIMEOUT_5_SECOND;
int ret;
if (!hpd)
@@ -542,7 +568,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
mutex_lock(&dp->event_mutex);
state = dp->hpd_state;
- DRM_DEBUG_DP("Before, type=%d hpd_state=%d\n",
+ drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
dp->dp_display.connector_type, state);
if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
@@ -550,7 +576,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
return 0;
}
- if (state == ST_CONNECT_PENDING || state == ST_CONNECTED) {
+ if (state == ST_MAINLINK_READY || state == ST_CONNECTED) {
mutex_unlock(&dp->event_mutex);
return 0;
}
@@ -562,30 +588,21 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
return 0;
}
- dp->hpd_state = ST_CONNECT_PENDING;
-
ret = dp_display_usbpd_configure_cb(&dp->pdev->dev);
if (ret) { /* link train failed */
dp->hpd_state = ST_DISCONNECTED;
} else {
- /* start sentinel checking in case of missing uevent */
- dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout);
+ dp->hpd_state = ST_MAINLINK_READY;
}
/* enable HDP irq_hpd/replug interrupt */
dp_catalog_hpd_config_intr(dp->catalog,
DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, true);
- DRM_DEBUG_DP("After, type=%d hpd_state=%d\n",
+ drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
dp->dp_display.connector_type, state);
mutex_unlock(&dp->event_mutex);
- /*
- * add fail safe mode outside event_mutex scope
- * to avoid potiential circular lock with drm thread
- */
- dp_panel_add_fail_safe_mode(dp->dp_display.connector);
-
/* uevent will complete connection part */
return 0;
};
@@ -593,23 +610,6 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
static int dp_display_enable(struct dp_display_private *dp, u32 data);
static int dp_display_disable(struct dp_display_private *dp, u32 data);
-static int dp_connect_pending_timeout(struct dp_display_private *dp, u32 data)
-{
- u32 state;
-
- mutex_lock(&dp->event_mutex);
-
- state = dp->hpd_state;
- if (state == ST_CONNECT_PENDING) {
- dp->hpd_state = ST_CONNECTED;
- DRM_DEBUG_DP("type=%d\n", dp->dp_display.connector_type);
- }
-
- mutex_unlock(&dp->event_mutex);
-
- return 0;
-}
-
static void dp_display_handle_plugged_change(struct msm_dp *dp_display,
bool plugged)
{
@@ -636,7 +636,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
state = dp->hpd_state;
- DRM_DEBUG_DP("Before, type=%d hpd_state=%d\n",
+ drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
dp->dp_display.connector_type, state);
/* disable irq_hpd/replug interrupts */
@@ -651,24 +651,21 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
if (dp->link->sink_count == 0) {
dp_display_host_phy_exit(dp);
}
+ dp_display_notify_disconnect(&dp->pdev->dev);
mutex_unlock(&dp->event_mutex);
return 0;
- }
-
- if (state == ST_DISCONNECT_PENDING) {
+ } else if (state == ST_DISCONNECT_PENDING) {
mutex_unlock(&dp->event_mutex);
return 0;
- }
-
- if (state == ST_CONNECT_PENDING) {
- /* wait until CONNECTED */
- dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 1); /* delay = 1 */
+ } else if (state == ST_MAINLINK_READY) {
+ dp_ctrl_off_link(dp->ctrl);
+ dp_display_host_phy_exit(dp);
+ dp->hpd_state = ST_DISCONNECTED;
+ dp_display_notify_disconnect(&dp->pdev->dev);
mutex_unlock(&dp->event_mutex);
return 0;
}
- dp->hpd_state = ST_DISCONNECT_PENDING;
-
/* disable HPD plug interrupts */
dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false);
@@ -676,18 +673,22 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
* We don't need separate work for disconnect as
* connect/attention interrupts are disabled
*/
- dp_display_usbpd_disconnect_cb(&dp->pdev->dev);
+ dp_display_notify_disconnect(&dp->pdev->dev);
- /* start sentinel checking in case of missing uevent */
- dp_add_event(dp, EV_DISCONNECT_PENDING_TIMEOUT, 0, DP_TIMEOUT_5_SECOND);
+ if (state == ST_DISPLAY_OFF) {
+ dp->hpd_state = ST_DISCONNECTED;
+ } else {
+ dp->hpd_state = ST_DISCONNECT_PENDING;
+ }
/* signal the disconnect event early to ensure proper teardown */
dp_display_handle_plugged_change(&dp->dp_display, false);
/* enable HDP plug interrupt to prepare for next plugin */
- dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, true);
+ if (!dp->dp_display.is_edp)
+ dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, true);
- DRM_DEBUG_DP("After, type=%d hpd_state=%d\n",
+ drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
dp->dp_display.connector_type, state);
/* uevent will complete disconnection part */
@@ -695,23 +696,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
return 0;
}
-static int dp_disconnect_pending_timeout(struct dp_display_private *dp, u32 data)
-{
- u32 state;
-
- mutex_lock(&dp->event_mutex);
-
- state = dp->hpd_state;
- if (state == ST_DISCONNECT_PENDING) {
- dp->hpd_state = ST_DISCONNECTED;
- DRM_DEBUG_DP("type=%d\n", dp->dp_display.connector_type);
- }
-
- mutex_unlock(&dp->event_mutex);
-
- return 0;
-}
-
static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
{
u32 state;
@@ -720,7 +704,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
/* irq_hpd can happen at either connected or disconnected state */
state = dp->hpd_state;
- DRM_DEBUG_DP("Before, type=%d hpd_state=%d\n",
+ drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
dp->dp_display.connector_type, state);
if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
@@ -728,14 +712,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
return 0;
}
- if (state == ST_CONNECT_PENDING) {
- /* wait until ST_CONNECTED */
- dp_add_event(dp, EV_IRQ_HPD_INT, 0, 1); /* delay = 1 */
- mutex_unlock(&dp->event_mutex);
- return 0;
- }
-
- if (state == ST_CONNECT_PENDING || state == ST_DISCONNECT_PENDING) {
+ if (state == ST_MAINLINK_READY || state == ST_DISCONNECT_PENDING) {
/* wait until ST_CONNECTED */
dp_add_event(dp, EV_IRQ_HPD_INT, 0, 1); /* delay = 1 */
mutex_unlock(&dp->event_mutex);
@@ -744,7 +721,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
dp_display_usbpd_attention_cb(&dp->pdev->dev);
- DRM_DEBUG_DP("After, type=%d hpd_state=%d\n",
+ drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
dp->dp_display.connector_type, state);
mutex_unlock(&dp->event_mutex);
@@ -806,7 +783,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
goto error;
}
- dp->aux = dp_aux_get(dev, dp->catalog);
+ dp->aux = dp_aux_get(dev, dp->catalog, dp->dp_display.is_edp);
if (IS_ERR(dp->aux)) {
rc = PTR_ERR(dp->aux);
DRM_ERROR("failed to initialize aux, rc = %d\n", rc);
@@ -851,6 +828,10 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
goto error_ctrl;
}
+ /* populate wide_bus_en to differernt layers */
+ dp->ctrl->wide_bus_en = dp->wide_bus_en;
+ dp->catalog->wide_bus_en = dp->wide_bus_en;
+
return rc;
error_ctrl:
@@ -885,9 +866,9 @@ static int dp_display_enable(struct dp_display_private *dp, u32 data)
int rc = 0;
struct msm_dp *dp_display = &dp->dp_display;
- DRM_DEBUG_DP("sink_count=%d\n", dp->link->sink_count);
+ drm_dbg_dp(dp->drm_dev, "sink_count=%d\n", dp->link->sink_count);
if (dp_display->power_on) {
- DRM_DEBUG_DP("Link already setup, return\n");
+ drm_dbg_dp(dp->drm_dev, "Link already setup, return\n");
return 0;
}
@@ -952,7 +933,7 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data)
dp_display->power_on = false;
- DRM_DEBUG_DP("sink count: %d\n", dp->link->sink_count);
+ drm_dbg_dp(dp->drm_dev, "sink count: %d\n", dp->link->sink_count);
return 0;
}
@@ -974,18 +955,42 @@ int dp_display_set_plugged_cb(struct msm_dp *dp_display,
return 0;
}
-int dp_display_validate_mode(struct msm_dp *dp, u32 mode_pclk_khz)
+/**
+ * dp_bridge_mode_valid - callback to determine if specified mode is valid
+ * @bridge: Pointer to drm bridge structure
+ * @info: display info
+ * @mode: Pointer to drm mode structure
+ * Returns: Validity status for specified mode
+ */
+enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
{
const u32 num_components = 3, default_bpp = 24;
struct dp_display_private *dp_display;
struct dp_link_info *link_info;
u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0;
+ struct msm_dp *dp;
+ int mode_pclk_khz = mode->clock;
+
+ dp = to_dp_bridge(bridge)->dp_display;
if (!dp || !mode_pclk_khz || !dp->connector) {
DRM_ERROR("invalid params\n");
return -EINVAL;
}
+ /*
+ * The eDP controller currently does not have a reliable way of
+ * enabling panel power to read sink capabilities. So, we rely
+ * on the panel driver to populate only supported modes for now.
+ */
+ if (dp->is_edp)
+ return MODE_OK;
+
+ if (mode->clock > DP_MAX_PIXEL_CLK_KHZ)
+ return MODE_BAD;
+
dp_display = container_of(dp, struct dp_display_private, dp_display);
link_info = &dp_display->panel->link_info;
@@ -1005,11 +1010,9 @@ int dp_display_validate_mode(struct msm_dp *dp, u32 mode_pclk_khz)
return MODE_OK;
}
-int dp_display_get_modes(struct msm_dp *dp,
- struct dp_display_mode *dp_mode)
+int dp_display_get_modes(struct msm_dp *dp)
{
struct dp_display_private *dp_display;
- int ret = 0;
if (!dp) {
DRM_ERROR("invalid params\n");
@@ -1018,11 +1021,8 @@ int dp_display_get_modes(struct msm_dp *dp,
dp_display = container_of(dp, struct dp_display_private, dp_display);
- ret = dp_panel_get_modes(dp_display->panel,
- dp->connector, dp_mode);
- if (dp_mode->drm_mode.clock)
- dp->max_pclk_khz = dp_mode->drm_mode.clock;
- return ret;
+ return dp_panel_get_modes(dp_display->panel,
+ dp->connector);
}
bool dp_display_check_video_test(struct msm_dp *dp)
@@ -1080,6 +1080,13 @@ static void dp_display_config_hpd(struct dp_display_private *dp)
dp_display_host_init(dp);
dp_catalog_ctrl_hpd_config(dp->catalog);
+ /* Enable plug and unplug interrupts only for external DisplayPort */
+ if (!dp->dp_display.is_edp)
+ dp_catalog_hpd_config_intr(dp->catalog,
+ DP_DP_HPD_PLUG_INT_MASK |
+ DP_DP_HPD_UNPLUG_INT_MASK,
+ true);
+
/* Enable interrupt first time
* we are leaving dp clocks on during disconnect
* and never disable interrupt
@@ -1099,12 +1106,17 @@ static int hpd_event_thread(void *data)
while (1) {
if (timeout_mode) {
wait_event_timeout(dp_priv->event_q,
- (dp_priv->event_pndx == dp_priv->event_gndx),
- EVENT_TIMEOUT);
+ (dp_priv->event_pndx == dp_priv->event_gndx) ||
+ kthread_should_stop(), EVENT_TIMEOUT);
} else {
wait_event_interruptible(dp_priv->event_q,
- (dp_priv->event_pndx != dp_priv->event_gndx));
+ (dp_priv->event_pndx != dp_priv->event_gndx) ||
+ kthread_should_stop());
}
+
+ if (kthread_should_stop())
+ break;
+
spin_lock_irqsave(&dp_priv->event_lock, flag);
todo = &dp_priv->event_list[dp_priv->event_gndx];
if (todo->delay) {
@@ -1158,14 +1170,6 @@ static int hpd_event_thread(void *data)
dp_display_send_hpd_notification(dp_priv,
todo->data);
break;
- case EV_CONNECT_PENDING_TIMEOUT:
- dp_connect_pending_timeout(dp_priv,
- todo->data);
- break;
- case EV_DISCONNECT_PENDING_TIMEOUT:
- dp_disconnect_pending_timeout(dp_priv,
- todo->data);
- break;
default:
break;
}
@@ -1174,12 +1178,17 @@ static int hpd_event_thread(void *data)
return 0;
}
-static void dp_hpd_event_setup(struct dp_display_private *dp_priv)
+static int dp_hpd_event_thread_start(struct dp_display_private *dp_priv)
{
- init_waitqueue_head(&dp_priv->event_q);
- spin_lock_init(&dp_priv->event_lock);
+ /* set event q to empty */
+ dp_priv->event_gndx = 0;
+ dp_priv->event_pndx = 0;
- kthread_run(hpd_event_thread, dp_priv, "dp_hpd_handler");
+ dp_priv->ev_tsk = kthread_run(hpd_event_thread, dp_priv, "dp_hpd_handler");
+ if (IS_ERR(dp_priv->ev_tsk))
+ return PTR_ERR(dp_priv->ev_tsk);
+
+ return 0;
}
static irqreturn_t dp_display_irq_handler(int irq, void *dev_id)
@@ -1196,15 +1205,13 @@ static irqreturn_t dp_display_irq_handler(int irq, void *dev_id)
hpd_isr_status = dp_catalog_hpd_get_intr_status(dp->catalog);
if (hpd_isr_status & 0x0F) {
- DRM_DEBUG_DP("type=%d isr=0x%x\n",
+ drm_dbg_dp(dp->drm_dev, "type=%d isr=0x%x\n",
dp->dp_display.connector_type, hpd_isr_status);
/* hpd related interrupts */
if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK)
dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0);
if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) {
- /* stop sentinel connect pending checking */
- dp_del_event(dp, EV_CONNECT_PENDING_TIMEOUT);
dp_add_event(dp, EV_IRQ_HPD_INT, 0, 0);
}
@@ -1239,10 +1246,9 @@ int dp_display_request_irq(struct msm_dp *dp_display)
dp = container_of(dp_display, struct dp_display_private, dp_display);
dp->irq = irq_of_parse_and_map(dp->pdev->dev.of_node, 0);
- if (dp->irq < 0) {
- rc = dp->irq;
- DRM_ERROR("failed to get irq: %d\n", rc);
- return rc;
+ if (!dp->irq) {
+ DRM_ERROR("failed to get irq\n");
+ return -EINVAL;
}
rc = devm_request_irq(&dp->pdev->dev, dp->irq,
@@ -1302,6 +1308,9 @@ static int dp_display_probe(struct platform_device *pdev)
dp->pdev = pdev;
dp->name = "drm_dp";
dp->dp_display.connector_type = desc->connector_type;
+ dp->wide_bus_en = desc->wide_bus_en;
+ dp->dp_display.is_edp =
+ (dp->dp_display.connector_type == DRM_MODE_CONNECTOR_eDP);
rc = dp_init_sub_modules(dp);
if (rc) {
@@ -1309,7 +1318,10 @@ static int dp_display_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}
+ /* setup event q */
mutex_init(&dp->event_mutex);
+ init_waitqueue_head(&dp->event_q);
+ spin_lock_init(&dp->event_lock);
/* Store DP audio handle inside DP display */
dp->dp_display.dp_audio = dp->audio;
@@ -1350,7 +1362,8 @@ static int dp_pm_resume(struct device *dev)
mutex_lock(&dp->event_mutex);
- DRM_DEBUG_DP("Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n",
+ drm_dbg_dp(dp->drm_dev,
+ "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n",
dp->dp_display.connector_type, dp->core_initialized,
dp->phy_initialized, dp_display->power_on);
@@ -1363,6 +1376,12 @@ static int dp_pm_resume(struct device *dev)
dp_catalog_ctrl_hpd_config(dp->catalog);
+ if (!dp->dp_display.is_edp)
+ dp_catalog_hpd_config_intr(dp->catalog,
+ DP_DP_HPD_PLUG_INT_MASK |
+ DP_DP_HPD_UNPLUG_INT_MASK,
+ true);
+
if (dp_catalog_link_is_connected(dp->catalog)) {
/*
* set sink to normal operation mode -- D0
@@ -1391,8 +1410,8 @@ static int dp_pm_resume(struct device *dev)
dp_display_handle_plugged_change(dp_display, false);
}
- DRM_DEBUG_DP("After, type=%d sink_count=%d is_connected=%d \
- core_inited=%d phy_inited=%d power_on=%d\n",
+ drm_dbg_dp(dp->drm_dev,
+ "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d power=%d\n",
dp->dp_display.connector_type, dp->link->sink_count,
dp->dp_display.is_connected, dp->core_initialized,
dp->phy_initialized, dp_display->power_on);
@@ -1412,7 +1431,8 @@ static int dp_pm_suspend(struct device *dev)
mutex_lock(&dp->event_mutex);
- DRM_DEBUG_DP("Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n",
+ drm_dbg_dp(dp->drm_dev,
+ "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n",
dp->dp_display.connector_type, dp->core_initialized,
dp->phy_initialized, dp_display->power_on);
@@ -1427,7 +1447,8 @@ static int dp_pm_suspend(struct device *dev)
dp->hpd_state = ST_SUSPENDED;
- DRM_DEBUG_DP("After, type=%d core_inited=%d phy_inited=%d power_on=%d\n",
+ drm_dbg_dp(dp->drm_dev,
+ "After, type=%d core_inited=%d phy_inited=%d power_on=%d\n",
dp->dp_display.connector_type, dp->core_initialized,
dp->phy_initialized, dp_display->power_on);
@@ -1489,9 +1510,17 @@ void msm_dp_irq_postinstall(struct msm_dp *dp_display)
dp = container_of(dp_display, struct dp_display_private, dp_display);
- dp_hpd_event_setup(dp);
+ if (!dp_display->is_edp)
+ dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 100);
+}
+
+bool msm_dp_wide_bus_available(const struct msm_dp *dp_display)
+{
+ struct dp_display_private *dp;
- dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 100);
+ dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+ return dp->wide_bus_en;
}
void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor)
@@ -1513,6 +1542,64 @@ void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor)
}
}
+static int dp_display_get_next_bridge(struct msm_dp *dp)
+{
+ int rc;
+ struct dp_display_private *dp_priv;
+ struct device_node *aux_bus;
+ struct device *dev;
+
+ dp_priv = container_of(dp, struct dp_display_private, dp_display);
+ dev = &dp_priv->pdev->dev;
+ aux_bus = of_get_child_by_name(dev->of_node, "aux-bus");
+
+ if (aux_bus && dp->is_edp) {
+ dp_display_host_init(dp_priv);
+ dp_catalog_ctrl_hpd_config(dp_priv->catalog);
+ dp_display_host_phy_init(dp_priv);
+ enable_irq(dp_priv->irq);
+
+ /*
+ * The code below assumes that the panel will finish probing
+ * by the time devm_of_dp_aux_populate_ep_devices() returns.
+ * This isn't a great assumption since it will fail if the
+ * panel driver is probed asynchronously but is the best we
+ * can do without a bigger driver reorganization.
+ */
+ rc = devm_of_dp_aux_populate_ep_devices(dp_priv->aux);
+ of_node_put(aux_bus);
+ if (rc)
+ goto error;
+ } else if (dp->is_edp) {
+ DRM_ERROR("eDP aux_bus not found\n");
+ return -ENODEV;
+ }
+
+ /*
+ * External bridges are mandatory for eDP interfaces: one has to
+ * provide at least an eDP panel (which gets wrapped into panel-bridge).
+ *
+ * For DisplayPort interfaces external bridges are optional, so
+ * silently ignore an error if one is not present (-ENODEV).
+ */
+ rc = dp_parser_find_next_bridge(dp_priv->parser);
+ if (!dp->is_edp && rc == -ENODEV)
+ return 0;
+
+ if (!rc) {
+ dp->next_bridge = dp_priv->parser->next_bridge;
+ return 0;
+ }
+
+error:
+ if (dp->is_edp) {
+ disable_irq(dp_priv->irq);
+ dp_display_host_phy_exit(dp_priv);
+ dp_display_host_deinit(dp_priv);
+ }
+ return rc;
+}
+
int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder)
{
@@ -1536,20 +1623,11 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
dp_display->encoder = encoder;
- dp_display->connector = dp_drm_connector_init(dp_display);
- if (IS_ERR(dp_display->connector)) {
- ret = PTR_ERR(dp_display->connector);
- DRM_DEV_ERROR(dev->dev,
- "failed to create dp connector: %d\n", ret);
- dp_display->connector = NULL;
+ ret = dp_display_get_next_bridge(dp_display);
+ if (ret)
return ret;
- }
-
- dp_priv->panel->connector = dp_display->connector;
-
- priv->connectors[priv->num_connectors++] = dp_display->connector;
- dp_display->bridge = msm_dp_bridge_init(dp_display, dev, encoder);
+ dp_display->bridge = dp_bridge_init(dp_display, dev, encoder);
if (IS_ERR(dp_display->bridge)) {
ret = PTR_ERR(dp_display->bridge);
DRM_DEV_ERROR(dev->dev,
@@ -1560,11 +1638,24 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
priv->bridges[priv->num_bridges++] = dp_display->bridge;
+ dp_display->connector = dp_drm_connector_init(dp_display);
+ if (IS_ERR(dp_display->connector)) {
+ ret = PTR_ERR(dp_display->connector);
+ DRM_DEV_ERROR(dev->dev,
+ "failed to create dp connector: %d\n", ret);
+ dp_display->connector = NULL;
+ return ret;
+ }
+
+ dp_priv->panel->connector = dp_display->connector;
+
return 0;
}
-int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
+void dp_bridge_enable(struct drm_bridge *drm_bridge)
{
+ struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
+ struct msm_dp *dp = dp_bridge->dp_display;
int rc = 0;
struct dp_display_private *dp_display;
u32 state;
@@ -1572,26 +1663,32 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
dp_display = container_of(dp, struct dp_display_private, dp_display);
if (!dp_display->dp_mode.drm_mode.clock) {
DRM_ERROR("invalid params\n");
- return -EINVAL;
+ return;
}
+ if (dp->is_edp)
+ dp_hpd_plug_handle(dp_display, 0);
+
mutex_lock(&dp_display->event_mutex);
- /* stop sentinel checking */
- dp_del_event(dp_display, EV_CONNECT_PENDING_TIMEOUT);
+ state = dp_display->hpd_state;
+ if (state != ST_DISPLAY_OFF && state != ST_MAINLINK_READY) {
+ mutex_unlock(&dp_display->event_mutex);
+ return;
+ }
rc = dp_display_set_mode(dp, &dp_display->dp_mode);
if (rc) {
DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc);
mutex_unlock(&dp_display->event_mutex);
- return rc;
+ return;
}
rc = dp_display_prepare(dp);
if (rc) {
DRM_ERROR("DP display prepare failed, rc=%d\n", rc);
mutex_unlock(&dp_display->event_mutex);
- return rc;
+ return;
}
state = dp_display->hpd_state;
@@ -1615,34 +1712,41 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
/* completed connection */
dp_display->hpd_state = ST_CONNECTED;
+ drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type);
mutex_unlock(&dp_display->event_mutex);
-
- return rc;
}
-int msm_dp_display_pre_disable(struct msm_dp *dp, struct drm_encoder *encoder)
+void dp_bridge_disable(struct drm_bridge *drm_bridge)
{
+ struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
+ struct msm_dp *dp = dp_bridge->dp_display;
struct dp_display_private *dp_display;
dp_display = container_of(dp, struct dp_display_private, dp_display);
dp_ctrl_push_idle(dp_display->ctrl);
-
- return 0;
}
-int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder)
+void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
{
+ struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
+ struct msm_dp *dp = dp_bridge->dp_display;
int rc = 0;
u32 state;
struct dp_display_private *dp_display;
dp_display = container_of(dp, struct dp_display_private, dp_display);
+ if (dp->is_edp)
+ dp_hpd_unplug_handle(dp_display, 0);
+
mutex_lock(&dp_display->event_mutex);
- /* stop sentinel checking */
- dp_del_event(dp_display, EV_DISCONNECT_PENDING_TIMEOUT);
+ state = dp_display->hpd_state;
+ if (state != ST_DISCONNECT_PENDING && state != ST_CONNECTED) {
+ mutex_unlock(&dp_display->event_mutex);
+ return;
+ }
dp_display_disable(dp_display, 0);
@@ -1658,14 +1762,16 @@ int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder)
dp_display->hpd_state = ST_DISPLAY_OFF;
}
+ drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type);
mutex_unlock(&dp_display->event_mutex);
- return rc;
}
-void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- const struct drm_display_mode *adjusted_mode)
+void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
{
+ struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
+ struct msm_dp *dp = dp_bridge->dp_display;
struct dp_display_private *dp_display;
dp_display = container_of(dp, struct dp_display_private, dp_display);
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index 7af2b186d2d9..4f9fe4d7610b 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -21,10 +21,11 @@ struct msm_dp {
bool audio_enabled;
bool power_on;
unsigned int connector_type;
+ bool is_edp;
hdmi_codec_plugged_cb plugged_cb;
- u32 max_pclk_khz;
+ bool wide_bus_en;
u32 max_dp_lanes;
struct dp_audio *dp_audio;
@@ -32,9 +33,7 @@ struct msm_dp {
int dp_display_set_plugged_cb(struct msm_dp *dp_display,
hdmi_codec_plugged_cb fn, struct device *codec_dev);
-int dp_display_validate_mode(struct msm_dp *dp_display, u32 mode_pclk_khz);
-int dp_display_get_modes(struct msm_dp *dp_display,
- struct dp_display_mode *dp_mode);
+int dp_display_get_modes(struct msm_dp *dp_display);
int dp_display_request_irq(struct msm_dp *dp_display);
bool dp_display_check_video_test(struct msm_dp *dp_display);
int dp_display_get_test_bpp(struct msm_dp *dp_display);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 80f59cf99089..62d58b9c4647 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -6,40 +6,25 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
#include <drm/drm_crtc.h>
#include "msm_drv.h"
#include "msm_kms.h"
#include "dp_drm.h"
-
-struct msm_dp_bridge {
- struct drm_bridge bridge;
- struct msm_dp *dp_display;
-};
-
-#define to_dp_display(x) container_of((x), struct msm_dp_bridge, bridge)
-
-struct dp_connector {
- struct drm_connector base;
- struct msm_dp *dp_display;
-};
-#define to_dp_connector(x) container_of(x, struct dp_connector, base)
-
/**
- * dp_connector_detect - callback to determine if connector is connected
- * @conn: Pointer to drm connector structure
- * @force: Force detect setting from drm framework
- * Returns: Connector 'is connected' status
+ * dp_bridge_detect - callback to determine if connector is connected
+ * @bridge: Pointer to drm bridge structure
+ * Returns: Bridge's 'is connected' status
*/
-static enum drm_connector_status dp_connector_detect(struct drm_connector *conn,
- bool force)
+static enum drm_connector_status dp_bridge_detect(struct drm_bridge *bridge)
{
struct msm_dp *dp;
- dp = to_dp_connector(conn)->dp_display;
+ dp = to_dp_bridge(bridge)->dp_display;
- DRM_DEBUG_DP("is_connected = %s\n",
+ drm_dbg_dp(dp->drm_dev, "is_connected = %s\n",
(dp->is_connected) ? "true" : "false");
return (dp->is_connected) ? connector_status_connected :
@@ -47,173 +32,45 @@ static enum drm_connector_status dp_connector_detect(struct drm_connector *conn,
}
/**
- * dp_connector_get_modes - callback to add drm modes via drm_mode_probed_add()
+ * dp_bridge_get_modes - callback to add drm modes via drm_mode_probed_add()
+ * @bridge: Poiner to drm bridge
* @connector: Pointer to drm connector structure
* Returns: Number of modes added
*/
-static int dp_connector_get_modes(struct drm_connector *connector)
+static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector)
{
int rc = 0;
struct msm_dp *dp;
- struct dp_display_mode *dp_mode = NULL;
- struct drm_display_mode *m, drm_mode;
if (!connector)
return 0;
- dp = to_dp_connector(connector)->dp_display;
-
- dp_mode = kzalloc(sizeof(*dp_mode), GFP_KERNEL);
- if (!dp_mode)
- return 0;
+ dp = to_dp_bridge(bridge)->dp_display;
/* pluggable case assumes EDID is read when HPD */
if (dp->is_connected) {
- /*
- *The get_modes() function might return one mode that is stored
- * in dp_mode when compliance test is in progress. If not, the
- * return value is equal to the total number of modes supported
- * by the sink
- */
- rc = dp_display_get_modes(dp, dp_mode);
+ rc = dp_display_get_modes(dp);
if (rc <= 0) {
DRM_ERROR("failed to get DP sink modes, rc=%d\n", rc);
- kfree(dp_mode);
return rc;
}
- if (dp_mode->drm_mode.clock) { /* valid DP mode */
- memset(&drm_mode, 0x0, sizeof(drm_mode));
- drm_mode_copy(&drm_mode, &dp_mode->drm_mode);
- m = drm_mode_duplicate(connector->dev, &drm_mode);
- if (!m) {
- DRM_ERROR("failed to add mode %ux%u\n",
- drm_mode.hdisplay,
- drm_mode.vdisplay);
- kfree(dp_mode);
- return 0;
- }
- drm_mode_probed_add(connector, m);
- }
} else {
- DRM_DEBUG_DP("No sink connected\n");
+ drm_dbg_dp(connector->dev, "No sink connected\n");
}
- kfree(dp_mode);
return rc;
}
-/**
- * dp_connector_mode_valid - callback to determine if specified mode is valid
- * @connector: Pointer to drm connector structure
- * @mode: Pointer to drm mode structure
- * Returns: Validity status for specified mode
- */
-static enum drm_mode_status dp_connector_mode_valid(
- struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- struct msm_dp *dp_disp;
-
- dp_disp = to_dp_connector(connector)->dp_display;
-
- if ((dp_disp->max_pclk_khz <= 0) ||
- (dp_disp->max_pclk_khz > DP_MAX_PIXEL_CLK_KHZ) ||
- (mode->clock > dp_disp->max_pclk_khz))
- return MODE_BAD;
-
- return dp_display_validate_mode(dp_disp, mode->clock);
-}
-
-static const struct drm_connector_funcs dp_connector_funcs = {
- .detect = dp_connector_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-static const struct drm_connector_helper_funcs dp_connector_helper_funcs = {
- .get_modes = dp_connector_get_modes,
- .mode_valid = dp_connector_mode_valid,
-};
-
-/* connector initialization */
-struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display)
-{
- struct drm_connector *connector = NULL;
- struct dp_connector *dp_connector;
- int ret;
-
- dp_connector = devm_kzalloc(dp_display->drm_dev->dev,
- sizeof(*dp_connector),
- GFP_KERNEL);
- if (!dp_connector)
- return ERR_PTR(-ENOMEM);
-
- dp_connector->dp_display = dp_display;
-
- connector = &dp_connector->base;
-
- ret = drm_connector_init(dp_display->drm_dev, connector,
- &dp_connector_funcs,
- dp_display->connector_type);
- if (ret)
- return ERR_PTR(ret);
-
- drm_connector_helper_add(connector, &dp_connector_helper_funcs);
-
- /*
- * Enable HPD to let hpd event is handled when cable is connected.
- */
- connector->polled = DRM_CONNECTOR_POLL_HPD;
-
- drm_connector_attach_encoder(connector, dp_display->encoder);
-
- return connector;
-}
-
-static void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
- const struct drm_display_mode *mode,
- const struct drm_display_mode *adjusted_mode)
-{
- struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge);
- struct msm_dp *dp_display = dp_bridge->dp_display;
-
- msm_dp_display_mode_set(dp_display, drm_bridge->encoder, mode, adjusted_mode);
-}
-
-static void dp_bridge_enable(struct drm_bridge *drm_bridge)
-{
- struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge);
- struct msm_dp *dp_display = dp_bridge->dp_display;
-
- msm_dp_display_enable(dp_display, drm_bridge->encoder);
-}
-
-static void dp_bridge_disable(struct drm_bridge *drm_bridge)
-{
- struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge);
- struct msm_dp *dp_display = dp_bridge->dp_display;
-
- msm_dp_display_pre_disable(dp_display, drm_bridge->encoder);
-}
-
-static void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
-{
- struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge);
- struct msm_dp *dp_display = dp_bridge->dp_display;
-
- msm_dp_display_disable(dp_display, drm_bridge->encoder);
-}
-
static const struct drm_bridge_funcs dp_bridge_ops = {
.enable = dp_bridge_enable,
.disable = dp_bridge_disable,
.post_disable = dp_bridge_post_disable,
.mode_set = dp_bridge_mode_set,
+ .mode_valid = dp_bridge_mode_valid,
+ .get_modes = dp_bridge_get_modes,
+ .detect = dp_bridge_detect,
};
-struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
+struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
struct drm_encoder *encoder)
{
int rc;
@@ -228,11 +85,33 @@ struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, struct drm_devi
bridge = &dp_bridge->bridge;
bridge->funcs = &dp_bridge_ops;
- bridge->encoder = encoder;
+ bridge->type = dp_display->connector_type;
+
+ /*
+ * Many ops only make sense for DP. Why?
+ * - Detect/HPD are used by DRM to know if a display is _physically_
+ * there, not whether the display is powered on / finished initting.
+ * On eDP we assume the display is always there because you can't
+ * know until power is applied. If we don't implement the ops DRM will
+ * assume our display is always there.
+ * - Currently eDP mode reading is driven by the panel driver. This
+ * allows the panel driver to properly power itself on to read the
+ * modes.
+ */
+ if (!dp_display->is_edp) {
+ bridge->ops =
+ DRM_BRIDGE_OP_DETECT |
+ DRM_BRIDGE_OP_HPD |
+ DRM_BRIDGE_OP_MODES;
+ }
+
+ drm_bridge_add(bridge);
rc = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (rc) {
DRM_ERROR("failed to attach bridge, rc=%d\n", rc);
+ drm_bridge_remove(bridge);
+
return ERR_PTR(rc);
}
@@ -249,3 +128,17 @@ struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, struct drm_devi
return bridge;
}
+
+/* connector initialization */
+struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display)
+{
+ struct drm_connector *connector = NULL;
+
+ connector = drm_bridge_connector_init(dp_display->drm_dev, dp_display->encoder);
+ if (IS_ERR(connector))
+ return connector;
+
+ drm_connector_attach_encoder(connector, dp_display->encoder);
+
+ return connector;
+}
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index c27bfceefdf0..f4b1ed1e24f7 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -7,12 +7,30 @@
#define _DP_DRM_H_
#include <linux/types.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_bridge.h>
#include "msm_drv.h"
#include "dp_display.h"
+struct msm_dp_bridge {
+ struct drm_bridge bridge;
+ struct msm_dp *dp_display;
+};
+
+#define to_dp_bridge(x) container_of((x), struct msm_dp_bridge, bridge)
+
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display);
+struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
+ struct drm_encoder *encoder);
+
+void dp_bridge_enable(struct drm_bridge *drm_bridge);
+void dp_bridge_disable(struct drm_bridge *drm_bridge);
+void dp_bridge_post_disable(struct drm_bridge *drm_bridge);
+enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode);
+void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode);
#endif /* _DP_DRM_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index d4d31e5bda07..36f0af02749f 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -36,6 +36,7 @@ struct dp_link_request {
struct dp_link_private {
u32 prev_sink_count;
struct device *dev;
+ struct drm_device *drm_dev;
struct drm_dp_aux *aux;
struct dp_link dp_link;
@@ -128,14 +129,14 @@ static int dp_link_parse_audio_channel_period(struct dp_link_private *link)
goto exit;
req->test_audio_period_ch_1 = ret;
- DRM_DEBUG_DP("test_audio_period_ch_1 = 0x%x\n", ret);
+ drm_dbg_dp(link->drm_dev, "test_audio_period_ch_1 = 0x%x\n", ret);
ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH2);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_2 = ret;
- DRM_DEBUG_DP("test_audio_period_ch_2 = 0x%x\n", ret);
+ drm_dbg_dp(link->drm_dev, "test_audio_period_ch_2 = 0x%x\n", ret);
/* TEST_AUDIO_PERIOD_CH_3 (Byte 0x275) */
ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH3);
@@ -143,42 +144,42 @@ static int dp_link_parse_audio_channel_period(struct dp_link_private *link)
goto exit;
req->test_audio_period_ch_3 = ret;
- DRM_DEBUG_DP("test_audio_period_ch_3 = 0x%x\n", ret);
+ drm_dbg_dp(link->drm_dev, "test_audio_period_ch_3 = 0x%x\n", ret);
ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH4);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_4 = ret;
- DRM_DEBUG_DP("test_audio_period_ch_4 = 0x%x\n", ret);
+ drm_dbg_dp(link->drm_dev, "test_audio_period_ch_4 = 0x%x\n", ret);
ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH5);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_5 = ret;
- DRM_DEBUG_DP("test_audio_period_ch_5 = 0x%x\n", ret);
+ drm_dbg_dp(link->drm_dev, "test_audio_period_ch_5 = 0x%x\n", ret);
ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH6);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_6 = ret;
- DRM_DEBUG_DP("test_audio_period_ch_6 = 0x%x\n", ret);
+ drm_dbg_dp(link->drm_dev, "test_audio_period_ch_6 = 0x%x\n", ret);
ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH7);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_7 = ret;
- DRM_DEBUG_DP("test_audio_period_ch_7 = 0x%x\n", ret);
+ drm_dbg_dp(link->drm_dev, "test_audio_period_ch_7 = 0x%x\n", ret);
ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH8);
if (ret == -EINVAL)
goto exit;
req->test_audio_period_ch_8 = ret;
- DRM_DEBUG_DP("test_audio_period_ch_8 = 0x%x\n", ret);
+ drm_dbg_dp(link->drm_dev, "test_audio_period_ch_8 = 0x%x\n", ret);
exit:
return ret;
}
@@ -205,7 +206,7 @@ static int dp_link_parse_audio_pattern_type(struct dp_link_private *link)
}
link->dp_link.test_audio.test_audio_pattern_type = data;
- DRM_DEBUG_DP("audio pattern type = 0x%x\n", data);
+ drm_dbg_dp(link->drm_dev, "audio pattern type = 0x%x\n", data);
exit:
return ret;
}
@@ -246,8 +247,9 @@ static int dp_link_parse_audio_mode(struct dp_link_private *link)
link->dp_link.test_audio.test_audio_sampling_rate = sampling_rate;
link->dp_link.test_audio.test_audio_channel_count = channel_count;
- DRM_DEBUG_DP("sampling_rate = 0x%x, channel_count = 0x%x\n",
- sampling_rate, channel_count);
+ drm_dbg_dp(link->drm_dev,
+ "sampling_rate = 0x%x, channel_count = 0x%x\n",
+ sampling_rate, channel_count);
exit:
return ret;
}
@@ -486,7 +488,8 @@ static int dp_link_parse_video_pattern_params(struct dp_link_private *link)
return ret;
}
- DRM_DEBUG_DP("link video pattern = 0x%x\n"
+ drm_dbg_dp(link->drm_dev,
+ "link video pattern = 0x%x\n"
"link dynamic range = 0x%x\n"
"link bit depth = 0x%x\n"
"TEST_H_TOTAL = %d, TEST_V_TOTAL = %d\n"
@@ -543,7 +546,8 @@ static int dp_link_parse_link_training_params(struct dp_link_private *link)
}
link->request.test_link_rate = bp;
- DRM_DEBUG_DP("link rate = 0x%x\n", link->request.test_link_rate);
+ drm_dbg_dp(link->drm_dev, "link rate = 0x%x\n",
+ link->request.test_link_rate);
rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_LANE_COUNT, &bp);
if (rlen < 0) {
@@ -558,7 +562,8 @@ static int dp_link_parse_link_training_params(struct dp_link_private *link)
}
link->request.test_lane_count = bp;
- DRM_DEBUG_DP("lane count = 0x%x\n", link->request.test_lane_count);
+ drm_dbg_dp(link->drm_dev, "lane count = 0x%x\n",
+ link->request.test_lane_count);
return 0;
}
@@ -583,7 +588,7 @@ static int dp_link_parse_phy_test_params(struct dp_link_private *link)
link->dp_link.phy_params.phy_test_pattern_sel = data & 0x07;
- DRM_DEBUG_DP("phy_test_pattern_sel = 0x%x\n", data);
+ drm_dbg_dp(link->drm_dev, "phy_test_pattern_sel = 0x%x\n", data);
switch (data) {
case DP_PHY_TEST_PATTERN_SEL_MASK:
@@ -639,10 +644,10 @@ static int dp_link_parse_request(struct dp_link_private *link)
return rlen;
}
- DRM_DEBUG_DP("device service irq vector = 0x%x\n", data);
+ drm_dbg_dp(link->drm_dev, "device service irq vector = 0x%x\n", data);
if (!(data & DP_AUTOMATED_TEST_REQUEST)) {
- DRM_DEBUG_DP("no test requested\n");
+ drm_dbg_dp(link->drm_dev, "no test requested\n");
return 0;
}
@@ -657,11 +662,11 @@ static int dp_link_parse_request(struct dp_link_private *link)
}
if (!data || (data == DP_TEST_LINK_FAUX_PATTERN)) {
- DRM_DEBUG_DP("link 0x%x not supported\n", data);
+ drm_dbg_dp(link->drm_dev, "link 0x%x not supported\n", data);
goto end;
}
- DRM_DEBUG_DP("Test:(0x%x) requested\n", data);
+ drm_dbg_dp(link->drm_dev, "Test:(0x%x) requested\n", data);
link->request.test_requested = data;
if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) {
ret = dp_link_parse_phy_test_params(link);
@@ -732,8 +737,8 @@ static int dp_link_parse_sink_count(struct dp_link *dp_link)
link->dp_link.sink_count =
DP_GET_SINK_COUNT(link->dp_link.sink_count);
- DRM_DEBUG_DP("sink_count = 0x%x, cp_ready = 0x%x\n",
- link->dp_link.sink_count, cp_ready);
+ drm_dbg_dp(link->drm_dev, "sink_count = 0x%x, cp_ready = 0x%x\n",
+ link->dp_link.sink_count, cp_ready);
return 0;
}
@@ -774,7 +779,8 @@ static int dp_link_process_link_training_request(struct dp_link_private *link)
if (link->request.test_requested != DP_TEST_LINK_TRAINING)
return -EINVAL;
- DRM_DEBUG_DP("Test:0x%x link rate = 0x%x, lane count = 0x%x\n",
+ drm_dbg_dp(link->drm_dev,
+ "Test:0x%x link rate = 0x%x, lane count = 0x%x\n",
DP_TEST_LINK_TRAINING,
link->request.test_link_rate,
link->request.test_lane_count);
@@ -852,13 +858,13 @@ bool dp_link_send_edid_checksum(struct dp_link *dp_link, u8 checksum)
static void dp_link_parse_vx_px(struct dp_link_private *link)
{
- DRM_DEBUG_DP("vx: 0=%d, 1=%d, 2=%d, 3=%d\n",
+ drm_dbg_dp(link->drm_dev, "vx: 0=%d, 1=%d, 2=%d, 3=%d\n",
drm_dp_get_adjust_request_voltage(link->link_status, 0),
drm_dp_get_adjust_request_voltage(link->link_status, 1),
drm_dp_get_adjust_request_voltage(link->link_status, 2),
drm_dp_get_adjust_request_voltage(link->link_status, 3));
- DRM_DEBUG_DP("px: 0=%d, 1=%d, 2=%d, 3=%d\n",
+ drm_dbg_dp(link->drm_dev, "px: 0=%d, 1=%d, 2=%d, 3=%d\n",
drm_dp_get_adjust_request_pre_emphasis(link->link_status, 0),
drm_dp_get_adjust_request_pre_emphasis(link->link_status, 1),
drm_dp_get_adjust_request_pre_emphasis(link->link_status, 2),
@@ -868,7 +874,8 @@ static void dp_link_parse_vx_px(struct dp_link_private *link)
* Update the voltage and pre-emphasis levels as per DPCD request
* vector.
*/
- DRM_DEBUG_DP("Current: v_level = 0x%x, p_level = 0x%x\n",
+ drm_dbg_dp(link->drm_dev,
+ "Current: v_level = 0x%x, p_level = 0x%x\n",
link->dp_link.phy_params.v_level,
link->dp_link.phy_params.p_level);
link->dp_link.phy_params.v_level =
@@ -878,7 +885,8 @@ static void dp_link_parse_vx_px(struct dp_link_private *link)
link->dp_link.phy_params.p_level >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;
- DRM_DEBUG_DP("Requested: v_level = 0x%x, p_level = 0x%x\n",
+ drm_dbg_dp(link->drm_dev,
+ "Requested: v_level = 0x%x, p_level = 0x%x\n",
link->dp_link.phy_params.v_level,
link->dp_link.phy_params.p_level);
}
@@ -895,7 +903,7 @@ static int dp_link_process_phy_test_pattern_request(
struct dp_link_private *link)
{
if (!(link->request.test_requested & DP_TEST_LINK_PHY_TEST_PATTERN)) {
- DRM_DEBUG_DP("no phy test\n");
+ drm_dbg_dp(link->drm_dev, "no phy test\n");
return -EINVAL;
}
@@ -907,11 +915,13 @@ static int dp_link_process_phy_test_pattern_request(
return -EINVAL;
}
- DRM_DEBUG_DP("Current: rate = 0x%x, lane count = 0x%x\n",
+ drm_dbg_dp(link->drm_dev,
+ "Current: rate = 0x%x, lane count = 0x%x\n",
link->dp_link.link_params.rate,
link->dp_link.link_params.num_lanes);
- DRM_DEBUG_DP("Requested: rate = 0x%x, lane count = 0x%x\n",
+ drm_dbg_dp(link->drm_dev,
+ "Requested: rate = 0x%x, lane count = 0x%x\n",
link->request.test_link_rate,
link->request.test_lane_count);
@@ -942,17 +952,18 @@ static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
*/
static int dp_link_process_link_status_update(struct dp_link_private *link)
{
- bool channel_eq_done = drm_dp_channel_eq_ok(link->link_status,
- link->dp_link.link_params.num_lanes);
+ bool channel_eq_done = drm_dp_channel_eq_ok(link->link_status,
+ link->dp_link.link_params.num_lanes);
- bool clock_recovery_done = drm_dp_clock_recovery_ok(link->link_status,
- link->dp_link.link_params.num_lanes);
+ bool clock_recovery_done = drm_dp_clock_recovery_ok(link->link_status,
+ link->dp_link.link_params.num_lanes);
- DRM_DEBUG_DP("channel_eq_done = %d, clock_recovery_done = %d\n",
+ drm_dbg_dp(link->drm_dev,
+ "channel_eq_done = %d, clock_recovery_done = %d\n",
channel_eq_done, clock_recovery_done);
- if (channel_eq_done && clock_recovery_done)
- return -EINVAL;
+ if (channel_eq_done && clock_recovery_done)
+ return -EINVAL;
return 0;
@@ -1058,7 +1069,8 @@ int dp_link_process_request(struct dp_link *dp_link)
}
}
- DRM_DEBUG_DP("sink request=%#x", dp_link->sink_request);
+ drm_dbg_dp(link->drm_dev, "sink request=%#x",
+ dp_link->sink_request);
return ret;
}
@@ -1090,18 +1102,22 @@ int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status)
{
int i;
int v_max = 0, p_max = 0;
+ struct dp_link_private *link;
if (!dp_link) {
DRM_ERROR("invalid input\n");
return -EINVAL;
}
+ link = container_of(dp_link, struct dp_link_private, dp_link);
+
/* use the max level across lanes */
for (i = 0; i < dp_link->link_params.num_lanes; i++) {
u8 data_v = drm_dp_get_adjust_request_voltage(link_status, i);
u8 data_p = drm_dp_get_adjust_request_pre_emphasis(link_status,
i);
- DRM_DEBUG_DP("lane=%d req_vol_swing=%d req_pre_emphasis=%d\n",
+ drm_dbg_dp(link->drm_dev,
+ "lane=%d req_vol_swing=%d req_pre_emphasis=%d\n",
i, data_v, data_p);
if (v_max < data_v)
v_max = data_v;
@@ -1117,14 +1133,16 @@ int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status)
* the allowable range.
*/
if (dp_link->phy_params.v_level > DP_TRAIN_VOLTAGE_SWING_MAX) {
- DRM_DEBUG_DP("Requested vSwingLevel=%d, change to %d\n",
+ drm_dbg_dp(link->drm_dev,
+ "Requested vSwingLevel=%d, change to %d\n",
dp_link->phy_params.v_level,
DP_TRAIN_VOLTAGE_SWING_MAX);
dp_link->phy_params.v_level = DP_TRAIN_VOLTAGE_SWING_MAX;
}
if (dp_link->phy_params.p_level > DP_TRAIN_PRE_EMPHASIS_MAX) {
- DRM_DEBUG_DP("Requested preEmphasisLevel=%d, change to %d\n",
+ drm_dbg_dp(link->drm_dev,
+ "Requested preEmphasisLevel=%d, change to %d\n",
dp_link->phy_params.p_level,
DP_TRAIN_PRE_EMPHASIS_MAX);
dp_link->phy_params.p_level = DP_TRAIN_PRE_EMPHASIS_MAX;
@@ -1133,13 +1151,14 @@ int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status)
if ((dp_link->phy_params.p_level > DP_TRAIN_PRE_EMPHASIS_LVL_1)
&& (dp_link->phy_params.v_level ==
DP_TRAIN_VOLTAGE_SWING_LVL_2)) {
- DRM_DEBUG_DP("Requested preEmphasisLevel=%d, change to %d\n",
+ drm_dbg_dp(link->drm_dev,
+ "Requested preEmphasisLevel=%d, change to %d\n",
dp_link->phy_params.p_level,
DP_TRAIN_PRE_EMPHASIS_LVL_1);
dp_link->phy_params.p_level = DP_TRAIN_PRE_EMPHASIS_LVL_1;
}
- DRM_DEBUG_DP("adjusted: v_level=%d, p_level=%d\n",
+ drm_dbg_dp(link->drm_dev, "adjusted: v_level=%d, p_level=%d\n",
dp_link->phy_params.v_level, dp_link->phy_params.p_level);
return 0;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 26c3653c99ec..5149cebc93f6 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -11,6 +11,7 @@
struct dp_panel_private {
struct device *dev;
+ struct drm_device *drm_dev;
struct dp_panel dp_panel;
struct drm_dp_aux *aux;
struct dp_link *link;
@@ -50,7 +51,8 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
/* check for EXTENDED_RECEIVER_CAPABILITY_FIELD_PRESENT */
if (temp & BIT(7)) {
- DRM_DEBUG_DP("using EXTENDED_RECEIVER_CAPABILITY_FIELD\n");
+ drm_dbg_dp(panel->drm_dev,
+ "using EXTENDED_RECEIVER_CAPABILITY_FIELD\n");
offset = DPRX_EXTENDED_DPCD_FIELD;
}
@@ -80,9 +82,9 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
if (link_info->rate >= (drm_dp_bw_code_to_link_rate(DP_LINK_BW_5_4)))
link_info->rate = drm_dp_bw_code_to_link_rate(DP_LINK_BW_5_4);
- DRM_DEBUG_DP("version: %d.%d\n", major, minor);
- DRM_DEBUG_DP("link_rate=%d\n", link_info->rate);
- DRM_DEBUG_DP("lane_count=%d\n", link_info->num_lanes);
+ 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);
if (drm_dp_enhanced_frame_cap(dpcd))
link_info->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;
@@ -151,15 +153,6 @@ static int dp_panel_update_modes(struct drm_connector *connector,
return rc;
}
-void dp_panel_add_fail_safe_mode(struct drm_connector *connector)
-{
- /* fail safe edid */
- mutex_lock(&connector->dev->mode_config.mutex);
- if (drm_add_modes_noedid(connector, 640, 480))
- drm_set_preferred_mode(connector, 640, 480);
- mutex_unlock(&connector->dev->mode_config.mutex);
-}
-
int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
struct drm_connector *connector)
{
@@ -215,12 +208,11 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
rc = -ETIMEDOUT;
goto end;
}
-
- dp_panel_add_fail_safe_mode(connector);
}
if (panel->aux_cfg_update_done) {
- DRM_DEBUG_DP("read DPCD with updated AUX config\n");
+ drm_dbg_dp(panel->drm_dev,
+ "read DPCD with updated AUX config\n");
rc = dp_panel_read_dpcd(dp_panel);
bw_code = drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate);
if (rc || !is_link_rate_valid(bw_code) ||
@@ -259,7 +251,7 @@ u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel,
}
int dp_panel_get_modes(struct dp_panel *dp_panel,
- struct drm_connector *connector, struct dp_display_mode *mode)
+ struct drm_connector *connector)
{
if (!dp_panel) {
DRM_ERROR("invalid input\n");
@@ -334,7 +326,8 @@ void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable)
catalog = panel->catalog;
if (!panel->panel_on) {
- DRM_DEBUG_DP("DP panel not enabled, handle TPG on next on\n");
+ drm_dbg_dp(panel->drm_dev,
+ "DP panel not enabled, handle TPG on next on\n");
return;
}
@@ -343,7 +336,7 @@ void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable)
return;
}
- DRM_DEBUG_DP("%s: calling catalog tpg_enable\n", __func__);
+ drm_dbg_dp(panel->drm_dev, "calling catalog tpg_enable\n");
dp_catalog_panel_tpg_enable(catalog, &panel->dp_panel.dp_mode.drm_mode);
}
@@ -369,12 +362,12 @@ int dp_panel_timing_cfg(struct dp_panel *dp_panel)
catalog = panel->catalog;
drm_mode = &panel->dp_panel.dp_mode.drm_mode;
- DRM_DEBUG_DP("width=%d hporch= %d %d %d\n",
+ drm_dbg_dp(panel->drm_dev, "width=%d hporch= %d %d %d\n",
drm_mode->hdisplay, drm_mode->htotal - drm_mode->hsync_end,
drm_mode->hsync_start - drm_mode->hdisplay,
drm_mode->hsync_end - drm_mode->hsync_start);
- DRM_DEBUG_DP("height=%d vporch= %d %d %d\n",
+ drm_dbg_dp(panel->drm_dev, "height=%d vporch= %d %d %d\n",
drm_mode->vdisplay, drm_mode->vtotal - drm_mode->vsync_end,
drm_mode->vsync_start - drm_mode->vdisplay,
drm_mode->vsync_end - drm_mode->vsync_start);
@@ -418,30 +411,37 @@ int dp_panel_timing_cfg(struct dp_panel *dp_panel)
int dp_panel_init_panel_info(struct dp_panel *dp_panel)
{
struct drm_display_mode *drm_mode;
+ struct dp_panel_private *panel;
drm_mode = &dp_panel->dp_mode.drm_mode;
+ panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
/*
* print resolution info as this is a result
* of user initiated action of cable connection
*/
- DRM_DEBUG_DP("SET NEW RESOLUTION:\n");
- DRM_DEBUG_DP("%dx%d@%dfps\n", drm_mode->hdisplay,
- drm_mode->vdisplay, drm_mode_vrefresh(drm_mode));
- DRM_DEBUG_DP("h_porches(back|front|width) = (%d|%d|%d)\n",
+ drm_dbg_dp(panel->drm_dev, "SET NEW RESOLUTION:\n");
+ drm_dbg_dp(panel->drm_dev, "%dx%d@%dfps\n",
+ drm_mode->hdisplay, drm_mode->vdisplay, drm_mode_vrefresh(drm_mode));
+ drm_dbg_dp(panel->drm_dev,
+ "h_porches(back|front|width) = (%d|%d|%d)\n",
drm_mode->htotal - drm_mode->hsync_end,
drm_mode->hsync_start - drm_mode->hdisplay,
drm_mode->hsync_end - drm_mode->hsync_start);
- DRM_DEBUG_DP("v_porches(back|front|width) = (%d|%d|%d)\n",
+ drm_dbg_dp(panel->drm_dev,
+ "v_porches(back|front|width) = (%d|%d|%d)\n",
drm_mode->vtotal - drm_mode->vsync_end,
drm_mode->vsync_start - drm_mode->vdisplay,
drm_mode->vsync_end - drm_mode->vsync_start);
- DRM_DEBUG_DP("pixel clock (KHz)=(%d)\n", drm_mode->clock);
- DRM_DEBUG_DP("bpp = %d\n", dp_panel->dp_mode.bpp);
+ drm_dbg_dp(panel->drm_dev, "pixel clock (KHz)=(%d)\n",
+ drm_mode->clock);
+ drm_dbg_dp(panel->drm_dev, "bpp = %d\n", dp_panel->dp_mode.bpp);
dp_panel->dp_mode.bpp = max_t(u32, 18,
- min_t(u32, dp_panel->dp_mode.bpp, 30));
- DRM_DEBUG_DP("updated bpp = %d\n", dp_panel->dp_mode.bpp);
+ min_t(u32, dp_panel->dp_mode.bpp, 30));
+ drm_dbg_dp(panel->drm_dev, "updated bpp = %d\n",
+ dp_panel->dp_mode.bpp);
return 0;
}
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index 99739ea679a7..d861197ac1c8 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -49,7 +49,6 @@ struct dp_panel {
bool video_test;
u32 vic;
- u32 max_pclk_khz;
u32 max_dp_lanes;
u32 max_bw_code;
@@ -59,13 +58,12 @@ int dp_panel_init_panel_info(struct dp_panel *dp_panel);
int dp_panel_deinit(struct dp_panel *dp_panel);
int dp_panel_timing_cfg(struct dp_panel *dp_panel);
void dp_panel_dump_regs(struct dp_panel *dp_panel);
-void dp_panel_add_fail_safe_mode(struct drm_connector *connector);
int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
struct drm_connector *connector);
u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel, u32 mode_max_bpp,
u32 mode_pclk_khz);
int dp_panel_get_modes(struct dp_panel *dp_panel,
- struct drm_connector *connector, struct dp_display_mode *mode);
+ struct drm_connector *connector);
void dp_panel_handle_sink_request(struct dp_panel *dp_panel);
void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable);
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c
index 6088d70f22e5..57ae14a0e181 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.c
+++ b/drivers/gpu/drm/msm/dp/dp_parser.c
@@ -258,12 +258,10 @@ static int dp_parser_clock(struct dp_parser *parser)
}
}
- DRM_DEBUG_DP("clock parsing successful\n");
-
return 0;
}
-static int dp_parser_find_next_bridge(struct dp_parser *parser)
+int dp_parser_find_next_bridge(struct dp_parser *parser)
{
struct device *dev = &parser->pdev->dev;
struct drm_bridge *bridge;
@@ -277,7 +275,7 @@ static int dp_parser_find_next_bridge(struct dp_parser *parser)
return 0;
}
-static int dp_parser_parse(struct dp_parser *parser, int connector_type)
+static int dp_parser_parse(struct dp_parser *parser)
{
int rc = 0;
@@ -298,25 +296,6 @@ static int dp_parser_parse(struct dp_parser *parser, int connector_type)
if (rc)
return rc;
- /*
- * External bridges are mandatory for eDP interfaces: one has to
- * provide at least an eDP panel (which gets wrapped into panel-bridge).
- *
- * For DisplayPort interfaces external bridges are optional, so
- * silently ignore an error if one is not present (-ENODEV).
- */
- rc = dp_parser_find_next_bridge(parser);
- if (rc == -ENODEV) {
- if (connector_type == DRM_MODE_CONNECTOR_eDP) {
- DRM_ERROR("eDP: next bridge is not present\n");
- return rc;
- }
- } else if (rc) {
- if (rc != -EPROBE_DEFER)
- DRM_ERROR("DP: error parsing next bridge: %d\n", rc);
- return rc;
- }
-
/* Map the corresponding regulator information according to
* version. Currently, since we only have one supported platform,
* mapping the regulator directly.
diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h
index d371bae1c968..3a4d7972c069 100644
--- a/drivers/gpu/drm/msm/dp/dp_parser.h
+++ b/drivers/gpu/drm/msm/dp/dp_parser.h
@@ -125,7 +125,7 @@ struct dp_parser {
u32 max_dp_lanes;
struct drm_bridge *next_bridge;
- int (*parse)(struct dp_parser *parser, int connector_type);
+ int (*parse)(struct dp_parser *parser);
};
/**
@@ -141,4 +141,16 @@ struct dp_parser {
*/
struct dp_parser *dp_parser_get(struct platform_device *pdev);
+/**
+ * dp_parser_find_next_bridge() - find an additional bridge to DP
+ *
+ * @parser: dp_parser data from client
+ *
+ * This function is used to find any additional bridge attached to
+ * the DP controller. The eDP interface requires a panel bridge.
+ *
+ * Return: 0 if able to get the bridge, otherwise negative errno for failure.
+ */
+int dp_parser_find_next_bridge(struct dp_parser *parser);
+
#endif
diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c
index b48b45e92bfa..d9e011775ad8 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.c
+++ b/drivers/gpu/drm/msm/dp/dp_power.c
@@ -16,6 +16,7 @@ struct dp_power_private {
struct dp_parser *parser;
struct platform_device *pdev;
struct device *dev;
+ struct drm_device *drm_dev;
struct clk *link_clk_src;
struct clk *pixel_provider;
struct clk *link_provider;
@@ -208,7 +209,12 @@ static int dp_power_clk_set_rate(struct dp_power_private *power,
int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
{
- DRM_DEBUG_DP("core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
+ struct dp_power_private *power;
+
+ power = container_of(dp_power, struct dp_power_private, dp_power);
+
+ drm_dbg_dp(power->drm_dev,
+ "core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
dp_power->core_clks_on, dp_power->link_clks_on, dp_power->stream_clks_on);
if (pm_type == DP_CORE_PM)
@@ -240,22 +246,26 @@ int dp_power_clk_enable(struct dp_power *dp_power,
if (enable) {
if (pm_type == DP_CORE_PM && dp_power->core_clks_on) {
- DRM_DEBUG_DP("core clks already enabled\n");
+ drm_dbg_dp(power->drm_dev,
+ "core clks already enabled\n");
return 0;
}
if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) {
- DRM_DEBUG_DP("links clks already enabled\n");
+ drm_dbg_dp(power->drm_dev,
+ "links clks already enabled\n");
return 0;
}
if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) {
- DRM_DEBUG_DP("pixel clks already enabled\n");
+ drm_dbg_dp(power->drm_dev,
+ "pixel clks already enabled\n");
return 0;
}
if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
- DRM_DEBUG_DP("Enable core clks before link clks\n");
+ drm_dbg_dp(power->drm_dev,
+ "Enable core clks before link clks\n");
rc = dp_power_clk_set_rate(power, DP_CORE_PM, enable);
if (rc) {
@@ -282,10 +292,11 @@ int dp_power_clk_enable(struct dp_power *dp_power,
else
dp_power->link_clks_on = enable;
- DRM_DEBUG_DP("%s clocks for %s\n",
+ drm_dbg_dp(power->drm_dev, "%s clocks for %s\n",
enable ? "enable" : "disable",
dp_parser_pm_name(pm_type));
- DRM_DEBUG_DP("strem_clks:%s link_clks:%s core_clks:%s\n",
+ drm_dbg_dp(power->drm_dev,
+ "strem_clks:%s link_clks:%s core_clks:%s\n",
dp_power->stream_clks_on ? "on" : "off",
dp_power->link_clks_on ? "on" : "off",
dp_power->core_clks_on ? "on" : "off");