From fe7553bef8d676d1d8b40666868b33ec39b9df5d Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 8 Jan 2019 16:11:27 -0500 Subject: drm/amdgpu: Don't ignore rc from drm_dp_mst_topology_mgr_resume() drm_dp_mst_topology_mgr_resume() returns whether or not it managed to find the topology in question after a suspend resume cycle, and the driver is supposed to check this value and disable MST accordingly if it's gone-in addition to sending a hotplug in order to notify userspace that something changed during suspend. Currently, amdgpu just makes the mistake of ignoring the return code from drm_dp_mst_topology_mgr_resume() which means that if a topology was removed in suspend, amdgpu never notices and assumes it's still connected which leads to all sorts of problems. So, fix this by actually checking the rc from drm_dp_mst_topology_mgr_resume(). Also, reformat the rest of the function while we're at it to fix the over-indenting. Signed-off-by: Lyude Paul Reviewed-by: Harry Wentland Cc: Jerry Zuo Cc: # v4.15+ Link: https://patchwork.freedesktop.org/patch/msgid/20190108211133.32564-2-lyude@redhat.com --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 32 ++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index a9a28dbc3e24..127b1e8f58e6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -699,22 +699,36 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend) { struct amdgpu_dm_connector *aconnector; struct drm_connector *connector; + struct drm_dp_mst_topology_mgr *mgr; + int ret; + bool need_hotplug = false; drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - aconnector = to_amdgpu_dm_connector(connector); - if (aconnector->dc_link->type == dc_connection_mst_branch && - !aconnector->mst_port) { + list_for_each_entry(connector, &dev->mode_config.connector_list, + head) { + aconnector = to_amdgpu_dm_connector(connector); + if (aconnector->dc_link->type != dc_connection_mst_branch || + aconnector->mst_port) + continue; + + mgr = &aconnector->mst_mgr; - if (suspend) - drm_dp_mst_topology_mgr_suspend(&aconnector->mst_mgr); - else - drm_dp_mst_topology_mgr_resume(&aconnector->mst_mgr); - } + if (suspend) { + drm_dp_mst_topology_mgr_suspend(mgr); + } else { + ret = drm_dp_mst_topology_mgr_resume(mgr); + if (ret < 0) { + drm_dp_mst_topology_mgr_set_mst(mgr, false); + need_hotplug = true; + } + } } drm_modeset_unlock(&dev->mode_config.connection_mutex); + + if (need_hotplug) + drm_kms_helper_hotplug_event(dev); } /** -- cgit 1.4.1 From 2d1af6a11cb9d88e0e3dd10258904c437fe1b315 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 8 Jan 2019 16:11:28 -0500 Subject: drm/amdgpu: Don't fail resume process if resuming atomic state fails This is an ugly one unfortunately. Currently, all DRM drivers supporting atomic modesetting will save the state that userspace had set before suspending, then attempt to restore that state on resume. This probably worked very well at one point, like many other things, until DP MST came into the picture. While it's easy to restore state on normal display connectors that were disconnected during suspend regardless of their state post-resume, this can't really be done with MST because of the fact that setting up a downstream sink requires performing sideband transactions between the source and the MST hub, sending out the ACT packets, etc. Because of this, there isn't really a guarantee that we can restore the atomic state we had before suspend once we've resumed. This sucks pretty bad, but so far I haven't run into any compositors that this actually causes serious issues with. Most compositors will notice the hotplug we send afterwards, and then reprobe state. Since nouveau and i915 also don't fail the suspend/resume process due to failing to restore the atomic state, let's make amdgpu match this behavior. Better to resume the GPU properly, then to stop the process half way because of a potentially unavoidable atomic commit failure. Eventually, we'll have a real fix for this problem on the DRM level. But we've got some more important low-hanging fruit to deal with first. Signed-off-by: Lyude Paul Reviewed-by: Harry Wentland Cc: Jerry Zuo Cc: # v4.15+ Link: https://patchwork.freedesktop.org/patch/msgid/20190108211133.32564-3-lyude@redhat.com --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 127b1e8f58e6..34f35e9a3c46 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -912,7 +912,6 @@ static int dm_resume(void *handle) struct drm_plane_state *new_plane_state; struct dm_plane_state *dm_new_plane_state; enum dc_connection_type new_connection_type = dc_connection_none; - int ret; int i; /* power on hardware */ @@ -985,13 +984,13 @@ static int dm_resume(void *handle) } } - ret = drm_atomic_helper_resume(ddev, dm->cached_state); + drm_atomic_helper_resume(ddev, dm->cached_state); dm->cached_state = NULL; amdgpu_dm_irq_resume_late(adev); - return ret; + return 0; } /** -- cgit 1.4.1 From c235316d935a19deedc2fc48076798c9a56e1a7c Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 8 Jan 2019 16:11:29 -0500 Subject: drm/dp_mst: Add __must_check to drm_dp_mst_topology_mgr_resume() Since I've had to fix two cases of drivers not checking the return code from this function, let's make the compiler complain so this doesn't come up again in the future. Changes since v1: * Remove unneeded __must_check in function declaration - danvet Signed-off-by: Lyude Paul Cc: Jerry Zuo Reviewed-by: Daniel Vetter Reviewed-by: Harry Wentland Link: https://patchwork.freedesktop.org/patch/msgid/20190108211133.32564-4-lyude@redhat.com --- include/drm/drm_dp_mst_helper.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 59f005b419cf..727af08e5ea6 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -616,7 +616,8 @@ void drm_dp_mst_dump_topology(struct seq_file *m, struct drm_dp_mst_topology_mgr *mgr); void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); -int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); +int __must_check +drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr); int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, -- cgit 1.4.1 From 4842379cbe6e851de914a7132f76f4e200b9a98b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:48 +0200 Subject: drm/bridge: tc358767: add bus flags tc358767 driver does not set DRM bus_flags, even if it does configures the polarity settings into its registers. This means that the DPI source can't configure the polarities correctly. Add sync flags accordingly. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-2-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 8e28e738cb52..29a7e33e8ae0 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1195,6 +1195,10 @@ static int tc_bridge_attach(struct drm_bridge *bridge) drm_display_info_set_bus_formats(&tc->connector.display_info, &bus_format, 1); + tc->connector.display_info.bus_flags = + DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_NEGEDGE | + DRM_BUS_FLAG_SYNC_NEGEDGE; drm_connector_attach_encoder(&tc->connector, tc->bridge.encoder); return 0; -- cgit 1.4.1 From adf4109896bbee27fd2ac3b48d22d6a0062fe517 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:49 +0200 Subject: drm/bridge: tc358767: add defines for DP1_SRCCTRL & PHY_2LANE DP1_SRCCTRL register and PHY_2LANE field did not have matching defines. Add these. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-3-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 29a7e33e8ae0..5f0a666db2fd 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -142,6 +142,8 @@ #define DP0_LTLOOPCTRL 0x06d8 #define DP0_SNKLTCTRL 0x06e4 +#define DP1_SRCCTRL 0x07a0 + /* PHY */ #define DP_PHY_CTRL 0x0800 #define DP_PHY_RST BIT(28) /* DP PHY Global Soft Reset */ @@ -150,6 +152,7 @@ #define PHY_M1_RST BIT(12) /* Reset PHY1 Main Channel */ #define PHY_RDY BIT(16) /* PHY Main Channels Ready */ #define PHY_M0_RST BIT(8) /* Reset PHY0 Main Channel */ +#define PHY_2LANE BIT(2) /* PHY Enable 2 lanes */ #define PHY_A0_EN BIT(1) /* PHY Aux Channel0 Enable */ #define PHY_M0_EN BIT(0) /* PHY Main Channel0 Enable */ @@ -564,7 +567,7 @@ static int tc_aux_link_setup(struct tc_data *tc) value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2; tc_write(SYS_PLLPARAM, value); - tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | BIT(2) | PHY_A0_EN); + tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_2LANE | PHY_A0_EN); /* * Initially PLLs are in bypass. Force PLL parameter update, @@ -834,7 +837,7 @@ static int tc_main_link_setup(struct tc_data *tc) DP0_SRCCTRL_LANESKEW | DP0_SRCCTRL_LANES_2 | DP0_SRCCTRL_BW27 | DP0_SRCCTRL_AUTOCORRECT); /* from excel file - DP1_SrcCtrl */ - tc_write(0x07a0, 0x00003083); + tc_write(DP1_SRCCTRL, 0x00003083); rate = clk_get_rate(tc->refclk); switch (rate) { @@ -855,8 +858,9 @@ static int tc_main_link_setup(struct tc_data *tc) } value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2; tc_write(SYS_PLLPARAM, value); + /* Setup Main Link */ - dp_phy_ctrl = BGREN | PWR_SW_EN | BIT(2) | PHY_A0_EN | PHY_M0_EN; + dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_2LANE | PHY_A0_EN | PHY_M0_EN; tc_write(DP_PHY_CTRL, dp_phy_ctrl); msleep(100); -- cgit 1.4.1 From 4d9d54a730434cc068dd3515ba6116697196f77b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:50 +0200 Subject: drm/bridge: tc358767: fix single lane configuration PHY_2LANE bit is always set in DP_PHY_CTRL, breaking 1 lane use. Set PHY_2LANE only when 2 lanes are used. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-4-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 5f0a666db2fd..fee53422c31f 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -543,6 +543,7 @@ static int tc_aux_link_setup(struct tc_data *tc) unsigned long rate; u32 value; int ret; + u32 dp_phy_ctrl; rate = clk_get_rate(tc->refclk); switch (rate) { @@ -567,7 +568,10 @@ static int tc_aux_link_setup(struct tc_data *tc) value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2; tc_write(SYS_PLLPARAM, value); - tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | PHY_2LANE | PHY_A0_EN); + dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN; + if (tc->link.base.num_lanes == 2) + dp_phy_ctrl |= PHY_2LANE; + tc_write(DP_PHY_CTRL, dp_phy_ctrl); /* * Initially PLLs are in bypass. Force PLL parameter update, @@ -860,7 +864,9 @@ static int tc_main_link_setup(struct tc_data *tc) tc_write(SYS_PLLPARAM, value); /* Setup Main Link */ - dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_2LANE | PHY_A0_EN | PHY_M0_EN; + dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN | PHY_M0_EN; + if (tc->link.base.num_lanes == 2) + dp_phy_ctrl |= PHY_2LANE; tc_write(DP_PHY_CTRL, dp_phy_ctrl); msleep(100); -- cgit 1.4.1 From 9a63bd6fe1b5590ffa42ae2ed22ee21363293e31 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:51 +0200 Subject: drm/bridge: tc358767: fix initial DP0/1_SRCCTRL value Initially DP0_SRCCTRL is set to a static value which includes DP0_SRCCTRL_LANES_2 and DP0_SRCCTRL_BW27, even when only 1 lane of 1.62Gbps speed is used. DP1_SRCCTRL is configured to a magic number. This patch changes the configuration as follows: Configure DP0_SRCCTRL by using tc_srcctrl() which provides the correct value. DP1_SRCCTRL needs two bits to be set to the same value as DP0_SRCCTRL: SSCG and BW27. All other bits can be zero. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-5-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index fee53422c31f..ab299f4debfa 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -836,12 +836,11 @@ static int tc_main_link_setup(struct tc_data *tc) if (!tc->mode) return -EINVAL; - /* from excel file - DP0_SrcCtrl */ - tc_write(DP0_SRCCTRL, DP0_SRCCTRL_SCRMBLDIS | DP0_SRCCTRL_EN810B | - DP0_SRCCTRL_LANESKEW | DP0_SRCCTRL_LANES_2 | - DP0_SRCCTRL_BW27 | DP0_SRCCTRL_AUTOCORRECT); - /* from excel file - DP1_SrcCtrl */ - tc_write(DP1_SRCCTRL, 0x00003083); + tc_write(DP0_SRCCTRL, tc_srcctrl(tc)); + /* SSCG and BW27 on DP1 must be set to the same as on DP0 */ + tc_write(DP1_SRCCTRL, + (tc->link.spread ? DP0_SRCCTRL_SSCG : 0) | + ((tc->link.base.rate != 162000) ? DP0_SRCCTRL_BW27 : 0)); rate = clk_get_rate(tc->refclk); switch (rate) { -- cgit 1.4.1 From 51b9e62eb6950c762162ab7eb8390990179be067 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:52 +0200 Subject: drm/bridge: tc358767: reject modes which require too much BW The current driver accepts any videomode with pclk < 154MHz. This is not correct, as with 1 lane and/or 1.62Mbps speed not all videomodes can be supported. Add code to reject modes that require more bandwidth that is available. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-6-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index ab299f4debfa..a1f3dd2afbb1 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1114,10 +1114,20 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, static enum drm_mode_status tc_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct tc_data *tc = connector_to_tc(connector); + u32 req, avail; + u32 bits_per_pixel = 24; + /* DPI interface clock limitation: upto 154 MHz */ if (mode->clock > 154000) return MODE_CLOCK_HIGH; + req = mode->clock * bits_per_pixel / 8; + avail = tc->link.base.num_lanes * tc->link.base.rate; + + if (req > avail) + return MODE_BAD; + return MODE_OK; } -- cgit 1.4.1 From 7923e09c7a766e2d58de7fc395bb84c18e5bc625 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:53 +0200 Subject: drm/bridge: tc358767: fix output H/V syncs The H and V syncs of the DP output are always set to active high. This patch fixes the syncs by configuring them according to the videomode. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-7-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index a1f3dd2afbb1..391547358756 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -98,6 +98,8 @@ #define DP0_STARTVAL 0x064c #define DP0_ACTIVEVAL 0x0650 #define DP0_SYNCVAL 0x0654 +#define SYNCVAL_HS_POL_ACTIVE_LOW (1 << 15) +#define SYNCVAL_VS_POL_ACTIVE_LOW (1 << 31) #define DP0_MISC 0x0658 #define TU_SIZE_RECOMMENDED (63) /* LSCLK cycles per TU */ #define BPC_6 (0 << 5) @@ -726,7 +728,9 @@ static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode) tc_write(DP0_ACTIVEVAL, (mode->vdisplay << 16) | (mode->hdisplay)); - tc_write(DP0_SYNCVAL, (vsync_len << 16) | (hsync_len << 0)); + tc_write(DP0_SYNCVAL, (vsync_len << 16) | (hsync_len << 0) | + ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? SYNCVAL_HS_POL_ACTIVE_LOW : 0) | + ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? SYNCVAL_VS_POL_ACTIVE_LOW : 0)); tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW | DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888); -- cgit 1.4.1 From f8c15790e4d8bdf2d21a5e9d43b5f97983af1222 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jan 2019 13:59:54 +0200 Subject: drm/bridge: tc358767: use DP connector if no panel set tc358767 driver sets the connector type always to eDP. This patch sets the type to DP if there is no panel defined, which implies that there's a DP connector on the board. Signed-off-by: Tomi Valkeinen Reviewed-by: Andrzej Hajda Signed-off-by: Andrzej Hajda Link: https://patchwork.freedesktop.org/patch/msgid/20190103115954.12785-8-tomi.valkeinen@ti.com --- drivers/gpu/drm/bridge/tc358767.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 391547358756..e6403b9549f1 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1209,7 +1209,8 @@ static int tc_bridge_attach(struct drm_bridge *bridge) /* Create eDP connector */ drm_connector_helper_add(&tc->connector, &tc_connector_helper_funcs); ret = drm_connector_init(drm, &tc->connector, &tc_connector_funcs, - DRM_MODE_CONNECTOR_eDP); + tc->panel ? DRM_MODE_CONNECTOR_eDP : + DRM_MODE_CONNECTOR_DisplayPort); if (ret) return ret; -- cgit 1.4.1