Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: ea9f337ce81e ("drm/msm/dp: reset dp controller only at boot up and pm_resume")
Signed-off-by: Kuogee Hsieh <khsieh@codeaurora.org>
Tested-by: Stephen Boyd <swboyd@chromium.org>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Link: https://lore.kernel.org/r/1621635930-30161-1-git-send-email-khsieh@codeaurora.org
Signed-off-by: Rob Clark <robdclark@chromium.org>

authored by

Kuogee Hsieh and committed by
Rob Clark
f21c8a27 665a6961

+101 -18
+2 -3
drivers/gpu/drm/msm/dp/dp_catalog.c
··· 582 582 583 583 u32 reftimer = dp_read_aux(catalog, REG_DP_DP_HPD_REFTIMER); 584 584 585 - /* enable HPD interrupts */ 585 + /* enable HPD plug and unplug interrupts */ 586 586 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); 589 588 590 589 /* Configure REFTIMER and enable it */ 591 590 reftimer |= DP_DP_HPD_REFTIMER_ENABLE;
+55
drivers/gpu/drm/msm/dp/dp_ctrl.c
··· 1809 1809 return ret; 1810 1810 } 1811 1811 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 + 1812 1867 int dp_ctrl_off(struct dp_ctrl *dp_ctrl) 1813 1868 { 1814 1869 struct dp_ctrl_private *ctrl;
+2
drivers/gpu/drm/msm/dp/dp_ctrl.h
··· 23 23 void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl); 24 24 int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl); 25 25 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); 26 28 int dp_ctrl_off(struct dp_ctrl *dp_ctrl); 27 29 void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl); 28 30 void dp_ctrl_isr(struct dp_ctrl *dp_ctrl);
+42 -15
drivers/gpu/drm/msm/dp/dp_display.c
··· 346 346 dp->dp_display.max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ; 347 347 dp->dp_display.max_dp_lanes = dp->parser->max_dp_lanes; 348 348 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 + 349 355 dp_link_reset_phy_params_vx_px(dp->link); 350 356 rc = dp_ctrl_on_link(dp->ctrl); 351 357 if (rc) { ··· 420 414 421 415 dp_display_host_init(dp, false); 422 416 423 - /* 424 - * set sink to normal operation mode -- D0 425 - * before dpcd read 426 - */ 427 - dp_link_psm_config(dp->link, &dp->panel->link_info, false); 428 417 rc = dp_display_process_hpd_high(dp); 429 418 end: 430 419 return rc; ··· 580 579 dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout); 581 580 } 582 581 582 + /* enable HDP irq_hpd/replug interrupt */ 583 + dp_catalog_hpd_config_intr(dp->catalog, 584 + DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, true); 585 + 583 586 mutex_unlock(&dp->event_mutex); 584 587 585 588 /* uevent will complete connection part */ ··· 633 628 mutex_lock(&dp->event_mutex); 634 629 635 630 state = dp->hpd_state; 636 - if (state == ST_DISCONNECT_PENDING || state == ST_DISCONNECTED) { 631 + 632 + /* disable irq_hpd/replug interrupts */ 633 + dp_catalog_hpd_config_intr(dp->catalog, 634 + DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, false); 635 + 636 + /* unplugged, no more irq_hpd handle */ 637 + dp_del_event(dp, EV_IRQ_HPD_INT); 638 + 639 + if (state == ST_DISCONNECTED) { 640 + /* triggered by irq_hdp with sink_count = 0 */ 641 + if (dp->link->sink_count == 0) { 642 + dp_ctrl_off_phy(dp->ctrl); 643 + hpd->hpd_high = 0; 644 + dp->core_initialized = false; 645 + } 646 + mutex_unlock(&dp->event_mutex); 647 + return 0; 648 + } 649 + 650 + if (state == ST_DISCONNECT_PENDING) { 637 651 mutex_unlock(&dp->event_mutex); 638 652 return 0; 639 653 } ··· 666 642 667 643 dp->hpd_state = ST_DISCONNECT_PENDING; 668 644 669 - /* disable HPD plug interrupt until disconnect is done */ 670 - dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK 671 - | DP_DP_IRQ_HPD_INT_MASK, false); 645 + /* disable HPD plug interrupts */ 646 + dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false); 672 647 673 648 hpd->hpd_high = 0; 674 649 ··· 683 660 /* signal the disconnect event early to ensure proper teardown */ 684 661 dp_display_handle_plugged_change(g_dp_display, false); 685 662 686 - dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK | 687 - DP_DP_IRQ_HPD_INT_MASK, true); 663 + /* enable HDP plug interrupt to prepare for next plugin */ 664 + dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, true); 688 665 689 666 /* uevent will complete disconnection part */ 690 667 mutex_unlock(&dp->event_mutex); ··· 715 692 716 693 /* irq_hpd can happen at either connected or disconnected state */ 717 694 state = dp->hpd_state; 718 - if (state == ST_DISPLAY_OFF) { 695 + if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { 719 696 mutex_unlock(&dp->event_mutex); 720 697 return 0; 721 698 } ··· 933 910 934 911 dp_display->audio_enabled = false; 935 912 936 - dp_ctrl_off(dp->ctrl); 937 - 938 - dp->core_initialized = false; 913 + /* triggered by irq_hpd with sink_count = 0 */ 914 + if (dp->link->sink_count == 0) { 915 + dp_ctrl_off_link_stream(dp->ctrl); 916 + } else { 917 + dp_ctrl_off(dp->ctrl); 918 + dp->core_initialized = false; 919 + } 939 920 940 921 dp_display->power_on = false; 941 922