diff options
author | Thomas Zimmermann <tzimmermann@suse.de> | 2022-06-20 19:21:25 +0300 |
---|---|---|
committer | Thomas Zimmermann <tzimmermann@suse.de> | 2022-06-20 19:21:25 +0300 |
commit | 2b1333b80885b896807ffb6ccf4bc21d29aa65e0 (patch) | |
tree | 51cc2d13d65603383db82c87f01a0aa93bd26010 /drivers/gpu/drm/msm/dp | |
parent | cad564ca557f8d3bb3b1fa965d9a2b3f6490ec69 (diff) | |
parent | 0f95ee9a0c579ebed0309657f6918673927189f2 (diff) | |
download | linux-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.c | 50 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_aux.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_aux.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_catalog.c | 98 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_catalog.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_ctrl.c | 175 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_ctrl.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_debug.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_display.c | 444 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_display.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_drm.c | 215 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_drm.h | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_link.c | 103 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_panel.c | 60 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_panel.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_parser.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_parser.h | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/dp/dp_power.c | 25 |
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"); |