Skip to content

Commit f21c8a2

Browse files
Kuogee Hsiehrobclark
authored andcommitted
drm/msm/dp: handle irq_hpd with sink_count = 0 correctly
irq_hpd interrupt should be handled after dongle plugged in and before dongle unplugged. Hence irq_hpd interrupt is enabled at the end of the plugin handle and disabled at the beginning of unplugged handle. Current irq_hpd with sink_count = 0 is wrongly handled same as the dongle unplugged which tears down the mainlink and disables the phy. This patch fixes this problem by only tearing down the mainlink but keeping phy enabled at irq_hpd with sink_count = 0 handle so that next irq_hpd with sink_count =1 can be handled by setup mainlink only. This patch also set dongle into D3 (power off) state at end of handling irq_hpd with sink_count = 0. Changes in v2: -- add ctrl->phy_Power_count Changes in v3: -- del ctrl->phy_Power_count -- add phy_power_off to dp_ctrl_off_link_stream() Changes in v4: -- return immediately if clock disable failed at dp_ctrl_off_link_stream() Changes in v5: -- set dongle to D3 (power off) state at dp_ctrl_off_link_stream() Changes in v6: -- add Fixes tag Fixes: ea9f337 ("drm/msm/dp: reset dp controller only at boot up and pm_resume") Signed-off-by: Kuogee Hsieh <[email protected]> Tested-by: Stephen Boyd <[email protected]> Reviewed-by: Stephen Boyd <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Rob Clark <[email protected]>
1 parent 665a696 commit f21c8a2

File tree

4 files changed

+101
-18
lines changed

4 files changed

+101
-18
lines changed

drivers/gpu/drm/msm/dp/dp_catalog.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -582,10 +582,9 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog)
582582

583583
u32 reftimer = dp_read_aux(catalog, REG_DP_DP_HPD_REFTIMER);
584584

585-
/* enable HPD interrupts */
585+
/* enable HPD plug and unplug interrupts */
586586
dp_catalog_hpd_config_intr(dp_catalog,
587-
DP_DP_HPD_PLUG_INT_MASK | DP_DP_IRQ_HPD_INT_MASK
588-
| DP_DP_HPD_UNPLUG_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, true);
587+
DP_DP_HPD_PLUG_INT_MASK | DP_DP_HPD_UNPLUG_INT_MASK, true);
589588

590589
/* Configure REFTIMER and enable it */
591590
reftimer |= DP_DP_HPD_REFTIMER_ENABLE;

drivers/gpu/drm/msm/dp/dp_ctrl.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,61 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
18091809
return ret;
18101810
}
18111811

1812+
int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
1813+
{
1814+
struct dp_ctrl_private *ctrl;
1815+
struct dp_io *dp_io;
1816+
struct phy *phy;
1817+
int ret;
1818+
1819+
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1820+
dp_io = &ctrl->parser->io;
1821+
phy = dp_io->phy;
1822+
1823+
/* set dongle to D3 (power off) mode */
1824+
dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true);
1825+
1826+
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
1827+
1828+
ret = dp_power_clk_enable(ctrl->power, DP_STREAM_PM, false);
1829+
if (ret) {
1830+
DRM_ERROR("Failed to disable pixel clocks. ret=%d\n", ret);
1831+
return ret;
1832+
}
1833+
1834+
ret = dp_power_clk_enable(ctrl->power, DP_CTRL_PM, false);
1835+
if (ret) {
1836+
DRM_ERROR("Failed to disable link clocks. ret=%d\n", ret);
1837+
return ret;
1838+
}
1839+
1840+
phy_power_off(phy);
1841+
1842+
/* aux channel down, reinit phy */
1843+
phy_exit(phy);
1844+
phy_init(phy);
1845+
1846+
DRM_DEBUG_DP("DP off link/stream done\n");
1847+
return ret;
1848+
}
1849+
1850+
void dp_ctrl_off_phy(struct dp_ctrl *dp_ctrl)
1851+
{
1852+
struct dp_ctrl_private *ctrl;
1853+
struct dp_io *dp_io;
1854+
struct phy *phy;
1855+
1856+
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
1857+
dp_io = &ctrl->parser->io;
1858+
phy = dp_io->phy;
1859+
1860+
dp_catalog_ctrl_reset(ctrl->catalog);
1861+
1862+
phy_exit(phy);
1863+
1864+
DRM_DEBUG_DP("DP off phy done\n");
1865+
}
1866+
18121867
int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
18131868
{
18141869
struct dp_ctrl_private *ctrl;

drivers/gpu/drm/msm/dp/dp_ctrl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset);
2323
void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl);
2424
int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl);
2525
int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl);
26+
int dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl);
27+
void dp_ctrl_off_phy(struct dp_ctrl *dp_ctrl);
2628
int dp_ctrl_off(struct dp_ctrl *dp_ctrl);
2729
void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl);
2830
void dp_ctrl_isr(struct dp_ctrl *dp_ctrl);

drivers/gpu/drm/msm/dp/dp_display.c

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,12 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
346346
dp->dp_display.max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ;
347347
dp->dp_display.max_dp_lanes = dp->parser->max_dp_lanes;
348348

349+
/*
350+
* set sink to normal operation mode -- D0
351+
* before dpcd read
352+
*/
353+
dp_link_psm_config(dp->link, &dp->panel->link_info, false);
354+
349355
dp_link_reset_phy_params_vx_px(dp->link);
350356
rc = dp_ctrl_on_link(dp->ctrl);
351357
if (rc) {
@@ -414,11 +420,6 @@ static int dp_display_usbpd_configure_cb(struct device *dev)
414420

415421
dp_display_host_init(dp, false);
416422

417-
/*
418-
* set sink to normal operation mode -- D0
419-
* before dpcd read
420-
*/
421-
dp_link_psm_config(dp->link, &dp->panel->link_info, false);
422423
rc = dp_display_process_hpd_high(dp);
423424
end:
424425
return rc;
@@ -579,6 +580,10 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
579580
dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout);
580581
}
581582

583+
/* enable HDP irq_hpd/replug interrupt */
584+
dp_catalog_hpd_config_intr(dp->catalog,
585+
DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, true);
586+
582587
mutex_unlock(&dp->event_mutex);
583588

584589
/* uevent will complete connection part */
@@ -628,7 +633,26 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
628633
mutex_lock(&dp->event_mutex);
629634

630635
state = dp->hpd_state;
631-
if (state == ST_DISCONNECT_PENDING || state == ST_DISCONNECTED) {
636+
637+
/* disable irq_hpd/replug interrupts */
638+
dp_catalog_hpd_config_intr(dp->catalog,
639+
DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, false);
640+
641+
/* unplugged, no more irq_hpd handle */
642+
dp_del_event(dp, EV_IRQ_HPD_INT);
643+
644+
if (state == ST_DISCONNECTED) {
645+
/* triggered by irq_hdp with sink_count = 0 */
646+
if (dp->link->sink_count == 0) {
647+
dp_ctrl_off_phy(dp->ctrl);
648+
hpd->hpd_high = 0;
649+
dp->core_initialized = false;
650+
}
651+
mutex_unlock(&dp->event_mutex);
652+
return 0;
653+
}
654+
655+
if (state == ST_DISCONNECT_PENDING) {
632656
mutex_unlock(&dp->event_mutex);
633657
return 0;
634658
}
@@ -642,9 +666,8 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
642666

643667
dp->hpd_state = ST_DISCONNECT_PENDING;
644668

645-
/* disable HPD plug interrupt until disconnect is done */
646-
dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK
647-
| DP_DP_IRQ_HPD_INT_MASK, false);
669+
/* disable HPD plug interrupts */
670+
dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false);
648671

649672
hpd->hpd_high = 0;
650673

@@ -660,8 +683,8 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
660683
/* signal the disconnect event early to ensure proper teardown */
661684
dp_display_handle_plugged_change(g_dp_display, false);
662685

663-
dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK |
664-
DP_DP_IRQ_HPD_INT_MASK, true);
686+
/* enable HDP plug interrupt to prepare for next plugin */
687+
dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, true);
665688

666689
/* uevent will complete disconnection part */
667690
mutex_unlock(&dp->event_mutex);
@@ -692,7 +715,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
692715

693716
/* irq_hpd can happen at either connected or disconnected state */
694717
state = dp->hpd_state;
695-
if (state == ST_DISPLAY_OFF) {
718+
if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) {
696719
mutex_unlock(&dp->event_mutex);
697720
return 0;
698721
}
@@ -910,9 +933,13 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data)
910933

911934
dp_display->audio_enabled = false;
912935

913-
dp_ctrl_off(dp->ctrl);
914-
915-
dp->core_initialized = false;
936+
/* triggered by irq_hpd with sink_count = 0 */
937+
if (dp->link->sink_count == 0) {
938+
dp_ctrl_off_link_stream(dp->ctrl);
939+
} else {
940+
dp_ctrl_off(dp->ctrl);
941+
dp->core_initialized = false;
942+
}
916943

917944
dp_display->power_on = false;
918945

0 commit comments

Comments
 (0)