diff options
author | Dave Airlie <airlied@redhat.com> | 2014-05-02 00:02:48 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-07-21 21:20:26 -0400 |
commit | 0e32b39ceed665bfa4a77a4bc307b6652b991632 (patch) | |
tree | 7d94f2fdb7d3c1e8c920193b0a067a0487f27a34 | |
parent | d05410f9a450df8848196ce87f1c9ef14ff89cb5 (diff) |
drm/i915: add DP 1.2 MST support (v0.7)
This adds DP 1.2 MST support on Haswell systems.
Notes:
a) this reworks irq handling for DP MST ports, so that we can
avoid the mode config locking in the current hpd handlers, as
we need to process up/down msgs at a better time.
Changes since v0.1:
use PORT_PCH_HOTPLUG to detect short vs long pulses
add a workqueue to deal with digital events as they can get blocked on the
main workqueue beyong mode_config mutex
fix a bunch of modeset checker warnings
acks irqs in the driver
cleanup the MST encoders
Changes since v0.2:
check irq status again in work handler
move around bring up and tear down to fix DPMS on/off
use path properties.
Changes since v0.3:
updates for mst apis
more state checker fixes
irq handling improvements
fbcon handling support
improved reference counting of link - fixes redocking.
Changes since v0.4:
handle gpu reset hpd reinit without oopsing
check link status on HPD irqs
fix suspend/resume
Changes since v0.5:
use proper functions to get max link/lane counts
fix another checker backtrace - due to connectors disappearing.
set output type in more places fro, unknown->displayport
don't talk to devices if no HPD asserted
check mst on short irqs only
check link status properly
rebase onto prepping irq changes.
drop unsued force_act
Changes since v0.6:
cleanup unused struct entry.
[airlied: fix some sparse warnings].
Reviewed-by: Todd Previte <tprevite@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/i915/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ddi.c | 75 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 40 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 234 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp_mst.c | 534 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_fbdev.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_opregion.c | 1 |
12 files changed, 934 insertions, 38 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index cad1683d8bb5..91bd167e1cb7 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile | |||
@@ -59,6 +59,7 @@ i915-y += dvo_ch7017.o \ | |||
59 | intel_crt.o \ | 59 | intel_crt.o \ |
60 | intel_ddi.o \ | 60 | intel_ddi.o \ |
61 | intel_dp.o \ | 61 | intel_dp.o \ |
62 | intel_dp_mst.o \ | ||
62 | intel_dsi_cmd.o \ | 63 | intel_dsi_cmd.o \ |
63 | intel_dsi.o \ | 64 | intel_dsi.o \ |
64 | intel_dsi_pll.o \ | 65 | intel_dsi_pll.o \ |
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 6df6506db919..d335c46ec6bc 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -1717,6 +1717,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
1717 | goto out_mtrrfree; | 1717 | goto out_mtrrfree; |
1718 | } | 1718 | } |
1719 | 1719 | ||
1720 | dev_priv->dp_wq = alloc_ordered_workqueue("i915-dp", 0); | ||
1721 | if (dev_priv->dp_wq == NULL) { | ||
1722 | DRM_ERROR("Failed to create our dp workqueue.\n"); | ||
1723 | ret = -ENOMEM; | ||
1724 | goto out_freewq; | ||
1725 | } | ||
1726 | |||
1720 | intel_irq_init(dev); | 1727 | intel_irq_init(dev); |
1721 | intel_uncore_sanitize(dev); | 1728 | intel_uncore_sanitize(dev); |
1722 | 1729 | ||
@@ -1792,6 +1799,8 @@ out_gem_unload: | |||
1792 | intel_teardown_gmbus(dev); | 1799 | intel_teardown_gmbus(dev); |
1793 | intel_teardown_mchbar(dev); | 1800 | intel_teardown_mchbar(dev); |
1794 | pm_qos_remove_request(&dev_priv->pm_qos); | 1801 | pm_qos_remove_request(&dev_priv->pm_qos); |
1802 | destroy_workqueue(dev_priv->dp_wq); | ||
1803 | out_freewq: | ||
1795 | destroy_workqueue(dev_priv->wq); | 1804 | destroy_workqueue(dev_priv->wq); |
1796 | out_mtrrfree: | 1805 | out_mtrrfree: |
1797 | arch_phys_wc_del(dev_priv->gtt.mtrr); | 1806 | arch_phys_wc_del(dev_priv->gtt.mtrr); |
@@ -1892,6 +1901,7 @@ int i915_driver_unload(struct drm_device *dev) | |||
1892 | intel_teardown_gmbus(dev); | 1901 | intel_teardown_gmbus(dev); |
1893 | intel_teardown_mchbar(dev); | 1902 | intel_teardown_mchbar(dev); |
1894 | 1903 | ||
1904 | destroy_workqueue(dev_priv->dp_wq); | ||
1895 | destroy_workqueue(dev_priv->wq); | 1905 | destroy_workqueue(dev_priv->wq); |
1896 | pm_qos_remove_request(&dev_priv->pm_qos); | 1906 | pm_qos_remove_request(&dev_priv->pm_qos); |
1897 | 1907 | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 83cb43a24768..a361bb9bc243 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -518,7 +518,6 @@ static int i915_drm_freeze(struct drm_device *dev) | |||
518 | 518 | ||
519 | flush_delayed_work(&dev_priv->rps.delayed_resume_work); | 519 | flush_delayed_work(&dev_priv->rps.delayed_resume_work); |
520 | 520 | ||
521 | intel_runtime_pm_disable_interrupts(dev); | ||
522 | 521 | ||
523 | intel_suspend_gt_powersave(dev); | 522 | intel_suspend_gt_powersave(dev); |
524 | 523 | ||
@@ -532,6 +531,9 @@ static int i915_drm_freeze(struct drm_device *dev) | |||
532 | } | 531 | } |
533 | drm_modeset_unlock_all(dev); | 532 | drm_modeset_unlock_all(dev); |
534 | 533 | ||
534 | intel_dp_mst_suspend(dev); | ||
535 | intel_runtime_pm_disable_interrupts(dev); | ||
536 | |||
535 | intel_modeset_suspend_hw(dev); | 537 | intel_modeset_suspend_hw(dev); |
536 | } | 538 | } |
537 | 539 | ||
@@ -646,6 +648,15 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) | |||
646 | 648 | ||
647 | intel_modeset_init_hw(dev); | 649 | intel_modeset_init_hw(dev); |
648 | 650 | ||
651 | { | ||
652 | unsigned long irqflags; | ||
653 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); | ||
654 | if (dev_priv->display.hpd_irq_setup) | ||
655 | dev_priv->display.hpd_irq_setup(dev); | ||
656 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); | ||
657 | } | ||
658 | |||
659 | intel_dp_mst_resume(dev); | ||
649 | drm_modeset_lock_all(dev); | 660 | drm_modeset_lock_all(dev); |
650 | intel_modeset_setup_hw_state(dev, true); | 661 | intel_modeset_setup_hw_state(dev, true); |
651 | drm_modeset_unlock_all(dev); | 662 | drm_modeset_unlock_all(dev); |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2dc3a922a3c8..7db16bee2997 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -1595,6 +1595,15 @@ struct drm_i915_private { | |||
1595 | u32 short_hpd_port_mask; | 1595 | u32 short_hpd_port_mask; |
1596 | struct work_struct dig_port_work; | 1596 | struct work_struct dig_port_work; |
1597 | 1597 | ||
1598 | /* | ||
1599 | * if we get a HPD irq from DP and a HPD irq from non-DP | ||
1600 | * the non-DP HPD could block the workqueue on a mode config | ||
1601 | * mutex getting, that userspace may have taken. However | ||
1602 | * userspace is waiting on the DP workqueue to run which is | ||
1603 | * blocked behind the non-DP one. | ||
1604 | */ | ||
1605 | struct workqueue_struct *dp_wq; | ||
1606 | |||
1598 | /* Old dri1 support infrastructure, beware the dragons ya fools entering | 1607 | /* Old dri1 support infrastructure, beware the dragons ya fools entering |
1599 | * here! */ | 1608 | * here! */ |
1600 | struct i915_dri1_state dri1; | 1609 | struct i915_dri1_state dri1; |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 12d77b5368c4..07e1a409e488 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -1846,7 +1846,7 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev, | |||
1846 | * deadlock. | 1846 | * deadlock. |
1847 | */ | 1847 | */ |
1848 | if (queue_dig) | 1848 | if (queue_dig) |
1849 | schedule_work(&dev_priv->dig_port_work); | 1849 | queue_work(dev_priv->dp_wq, &dev_priv->dig_port_work); |
1850 | if (queue_hp) | 1850 | if (queue_hp) |
1851 | schedule_work(&dev_priv->hotplug_work); | 1851 | schedule_work(&dev_priv->hotplug_work); |
1852 | } | 1852 | } |
@@ -4739,7 +4739,9 @@ void intel_hpd_init(struct drm_device *dev) | |||
4739 | list_for_each_entry(connector, &mode_config->connector_list, head) { | 4739 | list_for_each_entry(connector, &mode_config->connector_list, head) { |
4740 | struct intel_connector *intel_connector = to_intel_connector(connector); | 4740 | struct intel_connector *intel_connector = to_intel_connector(connector); |
4741 | connector->polled = intel_connector->polled; | 4741 | connector->polled = intel_connector->polled; |
4742 | if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) | 4742 | if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) |
4743 | connector->polled = DRM_CONNECTOR_POLL_HPD; | ||
4744 | if (intel_connector->mst_port) | ||
4743 | connector->polled = DRM_CONNECTOR_POLL_HPD; | 4745 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
4744 | } | 4746 | } |
4745 | 4747 | ||
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 1aec4257e296..9b1542f1cf01 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c | |||
@@ -116,7 +116,10 @@ enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) | |||
116 | struct drm_encoder *encoder = &intel_encoder->base; | 116 | struct drm_encoder *encoder = &intel_encoder->base; |
117 | int type = intel_encoder->type; | 117 | int type = intel_encoder->type; |
118 | 118 | ||
119 | if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || | 119 | if (type == INTEL_OUTPUT_DP_MST) { |
120 | struct intel_digital_port *intel_dig_port = enc_to_mst(encoder)->primary; | ||
121 | return intel_dig_port->port; | ||
122 | } else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || | ||
120 | type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) { | 123 | type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) { |
121 | struct intel_digital_port *intel_dig_port = | 124 | struct intel_digital_port *intel_dig_port = |
122 | enc_to_dig_port(encoder); | 125 | enc_to_dig_port(encoder); |
@@ -584,8 +587,8 @@ static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, | |||
584 | return (refclk * n * 100) / (p * r); | 587 | return (refclk * n * 100) / (p * r); |
585 | } | 588 | } |
586 | 589 | ||
587 | static void intel_ddi_clock_get(struct intel_encoder *encoder, | 590 | void intel_ddi_clock_get(struct intel_encoder *encoder, |
588 | struct intel_crtc_config *pipe_config) | 591 | struct intel_crtc_config *pipe_config) |
589 | { | 592 | { |
590 | struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; | 593 | struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; |
591 | int link_clock = 0; | 594 | int link_clock = 0; |
@@ -755,8 +758,7 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) | |||
755 | int type = intel_encoder->type; | 758 | int type = intel_encoder->type; |
756 | uint32_t temp; | 759 | uint32_t temp; |
757 | 760 | ||
758 | if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { | 761 | if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) { |
759 | |||
760 | temp = TRANS_MSA_SYNC_CLK; | 762 | temp = TRANS_MSA_SYNC_CLK; |
761 | switch (intel_crtc->config.pipe_bpp) { | 763 | switch (intel_crtc->config.pipe_bpp) { |
762 | case 18: | 764 | case 18: |
@@ -778,6 +780,21 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) | |||
778 | } | 780 | } |
779 | } | 781 | } |
780 | 782 | ||
783 | void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state) | ||
784 | { | ||
785 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
786 | struct drm_device *dev = crtc->dev; | ||
787 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
788 | enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; | ||
789 | uint32_t temp; | ||
790 | temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); | ||
791 | if (state == true) | ||
792 | temp |= TRANS_DDI_DP_VC_PAYLOAD_ALLOC; | ||
793 | else | ||
794 | temp &= ~TRANS_DDI_DP_VC_PAYLOAD_ALLOC; | ||
795 | I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp); | ||
796 | } | ||
797 | |||
781 | void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) | 798 | void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) |
782 | { | 799 | { |
783 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | 800 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
@@ -857,7 +874,19 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) | |||
857 | type == INTEL_OUTPUT_EDP) { | 874 | type == INTEL_OUTPUT_EDP) { |
858 | struct intel_dp *intel_dp = enc_to_intel_dp(encoder); | 875 | struct intel_dp *intel_dp = enc_to_intel_dp(encoder); |
859 | 876 | ||
860 | temp |= TRANS_DDI_MODE_SELECT_DP_SST; | 877 | if (intel_dp->is_mst) { |
878 | temp |= TRANS_DDI_MODE_SELECT_DP_MST; | ||
879 | } else | ||
880 | temp |= TRANS_DDI_MODE_SELECT_DP_SST; | ||
881 | |||
882 | temp |= DDI_PORT_WIDTH(intel_dp->lane_count); | ||
883 | } else if (type == INTEL_OUTPUT_DP_MST) { | ||
884 | struct intel_dp *intel_dp = &enc_to_mst(encoder)->primary->dp; | ||
885 | |||
886 | if (intel_dp->is_mst) { | ||
887 | temp |= TRANS_DDI_MODE_SELECT_DP_MST; | ||
888 | } else | ||
889 | temp |= TRANS_DDI_MODE_SELECT_DP_SST; | ||
861 | 890 | ||
862 | temp |= DDI_PORT_WIDTH(intel_dp->lane_count); | 891 | temp |= DDI_PORT_WIDTH(intel_dp->lane_count); |
863 | } else { | 892 | } else { |
@@ -874,7 +903,7 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, | |||
874 | uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); | 903 | uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); |
875 | uint32_t val = I915_READ(reg); | 904 | uint32_t val = I915_READ(reg); |
876 | 905 | ||
877 | val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK); | 906 | val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC); |
878 | val |= TRANS_DDI_PORT_NONE; | 907 | val |= TRANS_DDI_PORT_NONE; |
879 | I915_WRITE(reg, val); | 908 | I915_WRITE(reg, val); |
880 | } | 909 | } |
@@ -913,8 +942,11 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) | |||
913 | case TRANS_DDI_MODE_SELECT_DP_SST: | 942 | case TRANS_DDI_MODE_SELECT_DP_SST: |
914 | if (type == DRM_MODE_CONNECTOR_eDP) | 943 | if (type == DRM_MODE_CONNECTOR_eDP) |
915 | return true; | 944 | return true; |
916 | case TRANS_DDI_MODE_SELECT_DP_MST: | ||
917 | return (type == DRM_MODE_CONNECTOR_DisplayPort); | 945 | return (type == DRM_MODE_CONNECTOR_DisplayPort); |
946 | case TRANS_DDI_MODE_SELECT_DP_MST: | ||
947 | /* if the transcoder is in MST state then | ||
948 | * connector isn't connected */ | ||
949 | return false; | ||
918 | 950 | ||
919 | case TRANS_DDI_MODE_SELECT_FDI: | 951 | case TRANS_DDI_MODE_SELECT_FDI: |
920 | return (type == DRM_MODE_CONNECTOR_VGA); | 952 | return (type == DRM_MODE_CONNECTOR_VGA); |
@@ -966,6 +998,9 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, | |||
966 | 998 | ||
967 | if ((tmp & TRANS_DDI_PORT_MASK) | 999 | if ((tmp & TRANS_DDI_PORT_MASK) |
968 | == TRANS_DDI_SELECT_PORT(port)) { | 1000 | == TRANS_DDI_SELECT_PORT(port)) { |
1001 | if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == TRANS_DDI_MODE_SELECT_DP_MST) | ||
1002 | return false; | ||
1003 | |||
969 | *pipe = i; | 1004 | *pipe = i; |
970 | return true; | 1005 | return true; |
971 | } | 1006 | } |
@@ -1272,10 +1307,15 @@ void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) | |||
1272 | intel_wait_ddi_buf_idle(dev_priv, port); | 1307 | intel_wait_ddi_buf_idle(dev_priv, port); |
1273 | } | 1308 | } |
1274 | 1309 | ||
1275 | val = DP_TP_CTL_ENABLE | DP_TP_CTL_MODE_SST | | 1310 | val = DP_TP_CTL_ENABLE | |
1276 | DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE; | 1311 | DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE; |
1277 | if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) | 1312 | if (intel_dp->is_mst) |
1278 | val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE; | 1313 | val |= DP_TP_CTL_MODE_MST; |
1314 | else { | ||
1315 | val |= DP_TP_CTL_MODE_SST; | ||
1316 | if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) | ||
1317 | val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE; | ||
1318 | } | ||
1279 | I915_WRITE(DP_TP_CTL(port), val); | 1319 | I915_WRITE(DP_TP_CTL(port), val); |
1280 | POSTING_READ(DP_TP_CTL(port)); | 1320 | POSTING_READ(DP_TP_CTL(port)); |
1281 | 1321 | ||
@@ -1314,11 +1354,16 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc) | |||
1314 | 1354 | ||
1315 | static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) | 1355 | static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) |
1316 | { | 1356 | { |
1317 | struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); | 1357 | struct intel_digital_port *intel_dig_port = enc_to_dig_port(&intel_encoder->base); |
1318 | int type = intel_encoder->type; | 1358 | int type = intel_dig_port->base.type; |
1359 | |||
1360 | if (type != INTEL_OUTPUT_DISPLAYPORT && | ||
1361 | type != INTEL_OUTPUT_EDP && | ||
1362 | type != INTEL_OUTPUT_UNKNOWN) { | ||
1363 | return; | ||
1364 | } | ||
1319 | 1365 | ||
1320 | if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) | 1366 | intel_dp_hot_plug(intel_encoder); |
1321 | intel_dp_check_link_status(intel_dp); | ||
1322 | } | 1367 | } |
1323 | 1368 | ||
1324 | void intel_ddi_get_config(struct intel_encoder *encoder, | 1369 | void intel_ddi_get_config(struct intel_encoder *encoder, |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 421ea71b2e58..7b542b477a4e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -101,6 +101,14 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc); | |||
101 | static void intel_set_pipe_csc(struct drm_crtc *crtc); | 101 | static void intel_set_pipe_csc(struct drm_crtc *crtc); |
102 | static void vlv_prepare_pll(struct intel_crtc *crtc); | 102 | static void vlv_prepare_pll(struct intel_crtc *crtc); |
103 | 103 | ||
104 | static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) | ||
105 | { | ||
106 | if (!connector->mst_port) | ||
107 | return connector->encoder; | ||
108 | else | ||
109 | return &connector->mst_port->mst_encoders[pipe]->base; | ||
110 | } | ||
111 | |||
104 | typedef struct { | 112 | typedef struct { |
105 | int min, max; | 113 | int min, max; |
106 | } intel_range_t; | 114 | } intel_range_t; |
@@ -4130,6 +4138,9 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) | |||
4130 | if (intel_crtc->config.has_pch_encoder) | 4138 | if (intel_crtc->config.has_pch_encoder) |
4131 | lpt_pch_enable(crtc); | 4139 | lpt_pch_enable(crtc); |
4132 | 4140 | ||
4141 | if (intel_crtc->config.dp_encoder_is_mst) | ||
4142 | intel_ddi_set_vc_payload_alloc(crtc, true); | ||
4143 | |||
4133 | for_each_encoder_on_crtc(dev, crtc, encoder) { | 4144 | for_each_encoder_on_crtc(dev, crtc, encoder) { |
4134 | encoder->enable(encoder); | 4145 | encoder->enable(encoder); |
4135 | intel_opregion_notify_encoder(encoder, true); | 4146 | intel_opregion_notify_encoder(encoder, true); |
@@ -4178,6 +4189,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) | |||
4178 | 4189 | ||
4179 | intel_disable_pipe(dev_priv, pipe); | 4190 | intel_disable_pipe(dev_priv, pipe); |
4180 | 4191 | ||
4192 | if (intel_crtc->config.dp_encoder_is_mst) | ||
4193 | intel_ddi_set_vc_payload_alloc(crtc, false); | ||
4194 | |||
4181 | ironlake_pfit_disable(intel_crtc); | 4195 | ironlake_pfit_disable(intel_crtc); |
4182 | 4196 | ||
4183 | for_each_encoder_on_crtc(dev, crtc, encoder) | 4197 | for_each_encoder_on_crtc(dev, crtc, encoder) |
@@ -4336,6 +4350,9 @@ intel_display_port_power_domain(struct intel_encoder *intel_encoder) | |||
4336 | case INTEL_OUTPUT_EDP: | 4350 | case INTEL_OUTPUT_EDP: |
4337 | intel_dig_port = enc_to_dig_port(&intel_encoder->base); | 4351 | intel_dig_port = enc_to_dig_port(&intel_encoder->base); |
4338 | return port_to_power_domain(intel_dig_port->port); | 4352 | return port_to_power_domain(intel_dig_port->port); |
4353 | case INTEL_OUTPUT_DP_MST: | ||
4354 | intel_dig_port = enc_to_mst(&intel_encoder->base)->primary; | ||
4355 | return port_to_power_domain(intel_dig_port->port); | ||
4339 | case INTEL_OUTPUT_ANALOG: | 4356 | case INTEL_OUTPUT_ANALOG: |
4340 | return POWER_DOMAIN_PORT_CRT; | 4357 | return POWER_DOMAIN_PORT_CRT; |
4341 | case INTEL_OUTPUT_DSI: | 4358 | case INTEL_OUTPUT_DSI: |
@@ -5004,6 +5021,10 @@ static void intel_connector_check_state(struct intel_connector *connector) | |||
5004 | connector->base.base.id, | 5021 | connector->base.base.id, |
5005 | connector->base.name); | 5022 | connector->base.name); |
5006 | 5023 | ||
5024 | /* there is no real hw state for MST connectors */ | ||
5025 | if (connector->mst_port) | ||
5026 | return; | ||
5027 | |||
5007 | WARN(connector->base.dpms == DRM_MODE_DPMS_OFF, | 5028 | WARN(connector->base.dpms == DRM_MODE_DPMS_OFF, |
5008 | "wrong connector dpms state\n"); | 5029 | "wrong connector dpms state\n"); |
5009 | WARN(connector->base.encoder != &encoder->base, | 5030 | WARN(connector->base.encoder != &encoder->base, |
@@ -10524,6 +10545,14 @@ check_encoder_state(struct drm_device *dev) | |||
10524 | if (connector->base.dpms != DRM_MODE_DPMS_OFF) | 10545 | if (connector->base.dpms != DRM_MODE_DPMS_OFF) |
10525 | active = true; | 10546 | active = true; |
10526 | } | 10547 | } |
10548 | /* | ||
10549 | * for MST connectors if we unplug the connector is gone | ||
10550 | * away but the encoder is still connected to a crtc | ||
10551 | * until a modeset happens in response to the hotplug. | ||
10552 | */ | ||
10553 | if (!enabled && encoder->base.encoder_type == DRM_MODE_ENCODER_DPMST) | ||
10554 | continue; | ||
10555 | |||
10527 | WARN(!!encoder->base.crtc != enabled, | 10556 | WARN(!!encoder->base.crtc != enabled, |
10528 | "encoder's enabled state mismatch " | 10557 | "encoder's enabled state mismatch " |
10529 | "(expected %i, found %i)\n", | 10558 | "(expected %i, found %i)\n", |
@@ -11069,7 +11098,7 @@ intel_modeset_stage_output_state(struct drm_device *dev, | |||
11069 | * for them. */ | 11098 | * for them. */ |
11070 | for (ro = 0; ro < set->num_connectors; ro++) { | 11099 | for (ro = 0; ro < set->num_connectors; ro++) { |
11071 | if (set->connectors[ro] == &connector->base) { | 11100 | if (set->connectors[ro] == &connector->base) { |
11072 | connector->new_encoder = connector->encoder; | 11101 | connector->new_encoder = intel_find_encoder(connector, to_intel_crtc(set->crtc)->pipe); |
11073 | break; | 11102 | break; |
11074 | } | 11103 | } |
11075 | } | 11104 | } |
@@ -11115,7 +11144,7 @@ intel_modeset_stage_output_state(struct drm_device *dev, | |||
11115 | new_crtc)) { | 11144 | new_crtc)) { |
11116 | return -EINVAL; | 11145 | return -EINVAL; |
11117 | } | 11146 | } |
11118 | connector->encoder->new_crtc = to_intel_crtc(new_crtc); | 11147 | connector->new_encoder->new_crtc = to_intel_crtc(new_crtc); |
11119 | 11148 | ||
11120 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", | 11149 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", |
11121 | connector->base.base.id, | 11150 | connector->base.base.id, |
@@ -11149,7 +11178,12 @@ intel_modeset_stage_output_state(struct drm_device *dev, | |||
11149 | } | 11178 | } |
11150 | } | 11179 | } |
11151 | /* Now we've also updated encoder->new_crtc for all encoders. */ | 11180 | /* Now we've also updated encoder->new_crtc for all encoders. */ |
11152 | 11181 | list_for_each_entry(connector, &dev->mode_config.connector_list, | |
11182 | base.head) { | ||
11183 | if (connector->new_encoder) | ||
11184 | if (connector->new_encoder != connector->encoder) | ||
11185 | connector->encoder = connector->new_encoder; | ||
11186 | } | ||
11153 | for_each_intel_crtc(dev, crtc) { | 11187 | for_each_intel_crtc(dev, crtc) { |
11154 | crtc->new_enabled = false; | 11188 | crtc->new_enabled = false; |
11155 | 11189 | ||
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 30816b3b0742..e7a7953da6d1 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -112,7 +112,7 @@ static void intel_dp_link_down(struct intel_dp *intel_dp); | |||
112 | static bool _edp_panel_vdd_on(struct intel_dp *intel_dp); | 112 | static bool _edp_panel_vdd_on(struct intel_dp *intel_dp); |
113 | static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); | 113 | static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); |
114 | 114 | ||
115 | static int | 115 | int |
116 | intel_dp_max_link_bw(struct intel_dp *intel_dp) | 116 | intel_dp_max_link_bw(struct intel_dp *intel_dp) |
117 | { | 117 | { |
118 | int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE]; | 118 | int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE]; |
@@ -740,8 +740,9 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector) | |||
740 | { | 740 | { |
741 | struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base); | 741 | struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base); |
742 | 742 | ||
743 | sysfs_remove_link(&intel_connector->base.kdev->kobj, | 743 | if (!intel_connector->mst_port) |
744 | intel_dp->aux.ddc.dev.kobj.name); | 744 | sysfs_remove_link(&intel_connector->base.kdev->kobj, |
745 | intel_dp->aux.ddc.dev.kobj.name); | ||
745 | intel_connector_unregister(intel_connector); | 746 | intel_connector_unregister(intel_connector); |
746 | } | 747 | } |
747 | 748 | ||
@@ -3309,6 +3310,33 @@ intel_dp_probe_oui(struct intel_dp *intel_dp) | |||
3309 | edp_panel_vdd_off(intel_dp, false); | 3310 | edp_panel_vdd_off(intel_dp, false); |
3310 | } | 3311 | } |
3311 | 3312 | ||
3313 | static bool | ||
3314 | intel_dp_probe_mst(struct intel_dp *intel_dp) | ||
3315 | { | ||
3316 | u8 buf[1]; | ||
3317 | |||
3318 | if (!intel_dp->can_mst) | ||
3319 | return false; | ||
3320 | |||
3321 | if (intel_dp->dpcd[DP_DPCD_REV] < 0x12) | ||
3322 | return false; | ||
3323 | |||
3324 | _edp_panel_vdd_on(intel_dp); | ||
3325 | if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_MSTM_CAP, buf, 1)) { | ||
3326 | if (buf[0] & DP_MST_CAP) { | ||
3327 | DRM_DEBUG_KMS("Sink is MST capable\n"); | ||
3328 | intel_dp->is_mst = true; | ||
3329 | } else { | ||
3330 | DRM_DEBUG_KMS("Sink is not MST capable\n"); | ||
3331 | intel_dp->is_mst = false; | ||
3332 | } | ||
3333 | } | ||
3334 | edp_panel_vdd_off(intel_dp, false); | ||
3335 | |||
3336 | drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst); | ||
3337 | return intel_dp->is_mst; | ||
3338 | } | ||
3339 | |||
3312 | int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) | 3340 | int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) |
3313 | { | 3341 | { |
3314 | struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | 3342 | struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); |
@@ -3346,6 +3374,20 @@ intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector) | |||
3346 | sink_irq_vector, 1) == 1; | 3374 | sink_irq_vector, 1) == 1; |
3347 | } | 3375 | } |
3348 | 3376 | ||
3377 | static bool | ||
3378 | intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *sink_irq_vector) | ||
3379 | { | ||
3380 | int ret; | ||
3381 | |||
3382 | ret = intel_dp_dpcd_read_wake(&intel_dp->aux, | ||
3383 | DP_SINK_COUNT_ESI, | ||
3384 | sink_irq_vector, 14); | ||
3385 | if (ret != 14) | ||
3386 | return false; | ||
3387 | |||
3388 | return true; | ||
3389 | } | ||
3390 | |||
3349 | static void | 3391 | static void |
3350 | intel_dp_handle_test_request(struct intel_dp *intel_dp) | 3392 | intel_dp_handle_test_request(struct intel_dp *intel_dp) |
3351 | { | 3393 | { |
@@ -3353,6 +3395,63 @@ intel_dp_handle_test_request(struct intel_dp *intel_dp) | |||
3353 | drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, DP_TEST_NAK); | 3395 | drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, DP_TEST_NAK); |
3354 | } | 3396 | } |
3355 | 3397 | ||
3398 | static int | ||
3399 | intel_dp_check_mst_status(struct intel_dp *intel_dp) | ||
3400 | { | ||
3401 | bool bret; | ||
3402 | |||
3403 | if (intel_dp->is_mst) { | ||
3404 | u8 esi[16] = { 0 }; | ||
3405 | int ret = 0; | ||
3406 | int retry; | ||
3407 | bool handled; | ||
3408 | bret = intel_dp_get_sink_irq_esi(intel_dp, esi); | ||
3409 | go_again: | ||
3410 | if (bret == true) { | ||
3411 | |||
3412 | /* check link status - esi[10] = 0x200c */ | ||
3413 | if (intel_dp->active_mst_links && !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) { | ||
3414 | DRM_DEBUG_KMS("channel EQ not ok, retraining\n"); | ||
3415 | intel_dp_start_link_train(intel_dp); | ||
3416 | intel_dp_complete_link_train(intel_dp); | ||
3417 | intel_dp_stop_link_train(intel_dp); | ||
3418 | } | ||
3419 | |||
3420 | DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]); | ||
3421 | ret = drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled); | ||
3422 | |||
3423 | if (handled) { | ||
3424 | for (retry = 0; retry < 3; retry++) { | ||
3425 | int wret; | ||
3426 | wret = drm_dp_dpcd_write(&intel_dp->aux, | ||
3427 | DP_SINK_COUNT_ESI+1, | ||
3428 | &esi[1], 3); | ||
3429 | if (wret == 3) { | ||
3430 | break; | ||
3431 | } | ||
3432 | } | ||
3433 | |||
3434 | bret = intel_dp_get_sink_irq_esi(intel_dp, esi); | ||
3435 | if (bret == true) { | ||
3436 | DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]); | ||
3437 | goto go_again; | ||
3438 | } | ||
3439 | } else | ||
3440 | ret = 0; | ||
3441 | |||
3442 | return ret; | ||
3443 | } else { | ||
3444 | struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | ||
3445 | DRM_DEBUG_KMS("failed to get ESI - device may have failed\n"); | ||
3446 | intel_dp->is_mst = false; | ||
3447 | drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst); | ||
3448 | /* send a hotplug event */ | ||
3449 | drm_kms_helper_hotplug_event(intel_dig_port->base.base.dev); | ||
3450 | } | ||
3451 | } | ||
3452 | return -EINVAL; | ||
3453 | } | ||
3454 | |||
3356 | /* | 3455 | /* |
3357 | * According to DP spec | 3456 | * According to DP spec |
3358 | * 5.1.2: | 3457 | * 5.1.2: |
@@ -3361,7 +3460,6 @@ intel_dp_handle_test_request(struct intel_dp *intel_dp) | |||
3361 | * 3. Use Link Training from 2.5.3.3 and 3.5.1.3 | 3460 | * 3. Use Link Training from 2.5.3.3 and 3.5.1.3 |
3362 | * 4. Check link status on receipt of hot-plug interrupt | 3461 | * 4. Check link status on receipt of hot-plug interrupt |
3363 | */ | 3462 | */ |
3364 | |||
3365 | void | 3463 | void |
3366 | intel_dp_check_link_status(struct intel_dp *intel_dp) | 3464 | intel_dp_check_link_status(struct intel_dp *intel_dp) |
3367 | { | 3465 | { |
@@ -3581,6 +3679,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) | |||
3581 | enum drm_connector_status status; | 3679 | enum drm_connector_status status; |
3582 | enum intel_display_power_domain power_domain; | 3680 | enum intel_display_power_domain power_domain; |
3583 | struct edid *edid = NULL; | 3681 | struct edid *edid = NULL; |
3682 | bool ret; | ||
3584 | 3683 | ||
3585 | intel_runtime_pm_get(dev_priv); | 3684 | intel_runtime_pm_get(dev_priv); |
3586 | 3685 | ||
@@ -3590,6 +3689,14 @@ intel_dp_detect(struct drm_connector *connector, bool force) | |||
3590 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", | 3689 | DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", |
3591 | connector->base.id, connector->name); | 3690 | connector->base.id, connector->name); |
3592 | 3691 | ||
3692 | if (intel_dp->is_mst) { | ||
3693 | /* MST devices are disconnected from a monitor POV */ | ||
3694 | if (intel_encoder->type != INTEL_OUTPUT_EDP) | ||
3695 | intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; | ||
3696 | status = connector_status_disconnected; | ||
3697 | goto out; | ||
3698 | } | ||
3699 | |||
3593 | intel_dp->has_audio = false; | 3700 | intel_dp->has_audio = false; |
3594 | 3701 | ||
3595 | if (HAS_PCH_SPLIT(dev)) | 3702 | if (HAS_PCH_SPLIT(dev)) |
@@ -3602,6 +3709,16 @@ intel_dp_detect(struct drm_connector *connector, bool force) | |||
3602 | 3709 | ||
3603 | intel_dp_probe_oui(intel_dp); | 3710 | intel_dp_probe_oui(intel_dp); |
3604 | 3711 | ||
3712 | ret = intel_dp_probe_mst(intel_dp); | ||
3713 | if (ret) { | ||
3714 | /* if we are in MST mode then this connector | ||
3715 | won't appear connected or have anything with EDID on it */ | ||
3716 | if (intel_encoder->type != INTEL_OUTPUT_EDP) | ||
3717 | intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; | ||
3718 | status = connector_status_disconnected; | ||
3719 | goto out; | ||
3720 | } | ||
3721 | |||
3605 | if (intel_dp->force_audio != HDMI_AUDIO_AUTO) { | 3722 | if (intel_dp->force_audio != HDMI_AUDIO_AUTO) { |
3606 | intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON); | 3723 | intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON); |
3607 | } else { | 3724 | } else { |
@@ -3797,6 +3914,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) | |||
3797 | struct drm_device *dev = intel_dp_to_dev(intel_dp); | 3914 | struct drm_device *dev = intel_dp_to_dev(intel_dp); |
3798 | 3915 | ||
3799 | drm_dp_aux_unregister(&intel_dp->aux); | 3916 | drm_dp_aux_unregister(&intel_dp->aux); |
3917 | intel_dp_mst_encoder_cleanup(intel_dig_port); | ||
3800 | drm_encoder_cleanup(encoder); | 3918 | drm_encoder_cleanup(encoder); |
3801 | if (is_edp(intel_dp)) { | 3919 | if (is_edp(intel_dp)) { |
3802 | cancel_delayed_work_sync(&intel_dp->panel_vdd_work); | 3920 | cancel_delayed_work_sync(&intel_dp->panel_vdd_work); |
@@ -3825,28 +3943,62 @@ static const struct drm_encoder_funcs intel_dp_enc_funcs = { | |||
3825 | .destroy = intel_dp_encoder_destroy, | 3943 | .destroy = intel_dp_encoder_destroy, |
3826 | }; | 3944 | }; |
3827 | 3945 | ||
3828 | static void | 3946 | void |
3829 | intel_dp_hot_plug(struct intel_encoder *intel_encoder) | 3947 | intel_dp_hot_plug(struct intel_encoder *intel_encoder) |
3830 | { | 3948 | { |
3831 | struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); | 3949 | return; |
3832 | |||
3833 | intel_dp_check_link_status(intel_dp); | ||
3834 | } | 3950 | } |
3835 | 3951 | ||
3836 | bool | 3952 | bool |
3837 | intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) | 3953 | intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) |
3838 | { | 3954 | { |
3839 | struct intel_dp *intel_dp = &intel_dig_port->dp; | 3955 | struct intel_dp *intel_dp = &intel_dig_port->dp; |
3956 | struct drm_device *dev = intel_dig_port->base.base.dev; | ||
3957 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
3958 | int ret; | ||
3959 | if (intel_dig_port->base.type != INTEL_OUTPUT_EDP) | ||
3960 | intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT; | ||
3840 | 3961 | ||
3841 | if (long_hpd) | 3962 | DRM_DEBUG_KMS("got hpd irq on port %d - %s\n", intel_dig_port->port, |
3842 | return true; | 3963 | long_hpd ? "long" : "short"); |
3843 | 3964 | ||
3844 | /* | 3965 | if (long_hpd) { |
3845 | * we'll check the link status via the normal hot plug path later - | 3966 | if (!ibx_digital_port_connected(dev_priv, intel_dig_port)) |
3846 | * but for short hpds we should check it now | 3967 | goto mst_fail; |
3847 | */ | 3968 | |
3848 | intel_dp_check_link_status(intel_dp); | 3969 | if (!intel_dp_get_dpcd(intel_dp)) { |
3970 | goto mst_fail; | ||
3971 | } | ||
3972 | |||
3973 | intel_dp_probe_oui(intel_dp); | ||
3974 | |||
3975 | if (!intel_dp_probe_mst(intel_dp)) | ||
3976 | goto mst_fail; | ||
3977 | |||
3978 | } else { | ||
3979 | if (intel_dp->is_mst) { | ||
3980 | ret = intel_dp_check_mst_status(intel_dp); | ||
3981 | if (ret == -EINVAL) | ||
3982 | goto mst_fail; | ||
3983 | } | ||
3984 | |||
3985 | if (!intel_dp->is_mst) { | ||
3986 | /* | ||
3987 | * we'll check the link status via the normal hot plug path later - | ||
3988 | * but for short hpds we should check it now | ||
3989 | */ | ||
3990 | intel_dp_check_link_status(intel_dp); | ||
3991 | } | ||
3992 | } | ||
3849 | return false; | 3993 | return false; |
3994 | mst_fail: | ||
3995 | /* if we were in MST mode, and device is not there get out of MST mode */ | ||
3996 | if (intel_dp->is_mst) { | ||
3997 | DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n", intel_dp->is_mst, intel_dp->mst_mgr.mst_state); | ||
3998 | intel_dp->is_mst = false; | ||
3999 | drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst); | ||
4000 | } | ||
4001 | return true; | ||
3850 | } | 4002 | } |
3851 | 4003 | ||
3852 | /* Return which DP Port should be selected for Transcoder DP control */ | 4004 | /* Return which DP Port should be selected for Transcoder DP control */ |
@@ -3897,7 +4049,7 @@ bool intel_dp_is_edp(struct drm_device *dev, enum port port) | |||
3897 | return false; | 4049 | return false; |
3898 | } | 4050 | } |
3899 | 4051 | ||
3900 | static void | 4052 | void |
3901 | intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector) | 4053 | intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector) |
3902 | { | 4054 | { |
3903 | struct intel_connector *intel_connector = to_intel_connector(connector); | 4055 | struct intel_connector *intel_connector = to_intel_connector(connector); |
@@ -4391,6 +4543,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, | |||
4391 | 4543 | ||
4392 | intel_dp_aux_init(intel_dp, intel_connector); | 4544 | intel_dp_aux_init(intel_dp, intel_connector); |
4393 | 4545 | ||
4546 | /* init MST on ports that can support it */ | ||
4547 | if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { | ||
4548 | if (port == PORT_B || port == PORT_C || port == PORT_D) { | ||
4549 | intel_dp_mst_encoder_init(intel_dig_port, intel_connector->base.base.id); | ||
4550 | } | ||
4551 | } | ||
4552 | |||
4394 | if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) { | 4553 | if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) { |
4395 | drm_dp_aux_unregister(&intel_dp->aux); | 4554 | drm_dp_aux_unregister(&intel_dp->aux); |
4396 | if (is_edp(intel_dp)) { | 4555 | if (is_edp(intel_dp)) { |
@@ -4487,3 +4646,46 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) | |||
4487 | kfree(intel_connector); | 4646 | kfree(intel_connector); |
4488 | } | 4647 | } |
4489 | } | 4648 | } |
4649 | |||
4650 | void intel_dp_mst_suspend(struct drm_device *dev) | ||
4651 | { | ||
4652 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
4653 | int i; | ||
4654 | |||
4655 | /* disable MST */ | ||
4656 | for (i = 0; i < I915_MAX_PORTS; i++) { | ||
4657 | struct intel_digital_port *intel_dig_port = dev_priv->hpd_irq_port[i]; | ||
4658 | if (!intel_dig_port) | ||
4659 | continue; | ||
4660 | |||
4661 | if (intel_dig_port->base.type == INTEL_OUTPUT_DISPLAYPORT) { | ||
4662 | if (!intel_dig_port->dp.can_mst) | ||
4663 | continue; | ||
4664 | if (intel_dig_port->dp.is_mst) | ||
4665 | drm_dp_mst_topology_mgr_suspend(&intel_dig_port->dp.mst_mgr); | ||
4666 | } | ||
4667 | } | ||
4668 | } | ||
4669 | |||
4670 | void intel_dp_mst_resume(struct drm_device *dev) | ||
4671 | { | ||
4672 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
4673 | int i; | ||
4674 | |||
4675 | for (i = 0; i < I915_MAX_PORTS; i++) { | ||
4676 | struct intel_digital_port *intel_dig_port = dev_priv->hpd_irq_port[i]; | ||
4677 | if (!intel_dig_port) | ||
4678 | continue; | ||
4679 | if (intel_dig_port->base.type == INTEL_OUTPUT_DISPLAYPORT) { | ||
4680 | int ret; | ||
4681 | |||
4682 | if (!intel_dig_port->dp.can_mst) | ||
4683 | continue; | ||
4684 | |||
4685 | ret = drm_dp_mst_topology_mgr_resume(&intel_dig_port->dp.mst_mgr); | ||
4686 | if (ret != 0) { | ||
4687 | intel_dp_check_mst_status(&intel_dig_port->dp); | ||
4688 | } | ||
4689 | } | ||
4690 | } | ||
4691 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c new file mode 100644 index 000000000000..ec48d562c7fc --- /dev/null +++ b/drivers/gpu/drm/i915/intel_dp_mst.c | |||
@@ -0,0 +1,534 @@ | |||
1 | /* | ||
2 | * Copyright © 2008 Intel Corporation | ||
3 | * 2014 Red Hat Inc. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the "Software"), | ||
7 | * to deal in the Software without restriction, including without limitation | ||
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
10 | * Software is furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice (including the next | ||
13 | * paragraph) shall be included in all copies or substantial portions of the | ||
14 | * Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
22 | * IN THE SOFTWARE. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <drm/drmP.h> | ||
27 | #include "i915_drv.h" | ||
28 | #include "intel_drv.h" | ||
29 | #include <drm/drm_crtc_helper.h> | ||
30 | #include <drm/drm_edid.h> | ||
31 | |||
32 | static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, | ||
33 | struct intel_crtc_config *pipe_config) | ||
34 | { | ||
35 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | ||
36 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | ||
37 | struct intel_dp *intel_dp = &intel_dig_port->dp; | ||
38 | struct drm_device *dev = encoder->base.dev; | ||
39 | int bpp; | ||
40 | int lane_count, slots; | ||
41 | struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; | ||
42 | struct intel_connector *found = NULL, *intel_connector; | ||
43 | int mst_pbn; | ||
44 | |||
45 | pipe_config->dp_encoder_is_mst = true; | ||
46 | pipe_config->has_pch_encoder = false; | ||
47 | pipe_config->has_dp_encoder = true; | ||
48 | bpp = 24; | ||
49 | /* | ||
50 | * for MST we always configure max link bw - the spec doesn't | ||
51 | * seem to suggest we should do otherwise. | ||
52 | */ | ||
53 | lane_count = drm_dp_max_lane_count(intel_dp->dpcd); | ||
54 | intel_dp->link_bw = intel_dp_max_link_bw(intel_dp); | ||
55 | intel_dp->lane_count = lane_count; | ||
56 | |||
57 | pipe_config->pipe_bpp = 24; | ||
58 | pipe_config->port_clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); | ||
59 | |||
60 | list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head) { | ||
61 | if (intel_connector->new_encoder == encoder) { | ||
62 | found = intel_connector; | ||
63 | break; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | if (!found) { | ||
68 | DRM_ERROR("can't find connector\n"); | ||
69 | return false; | ||
70 | } | ||
71 | |||
72 | mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp); | ||
73 | |||
74 | pipe_config->pbn = mst_pbn; | ||
75 | slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, mst_pbn); | ||
76 | |||
77 | intel_link_compute_m_n(bpp, lane_count, | ||
78 | adjusted_mode->crtc_clock, | ||
79 | pipe_config->port_clock, | ||
80 | &pipe_config->dp_m_n); | ||
81 | |||
82 | pipe_config->dp_m_n.tu = slots; | ||
83 | return true; | ||
84 | |||
85 | } | ||
86 | |||
87 | static void intel_mst_disable_dp(struct intel_encoder *encoder) | ||
88 | { | ||
89 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | ||
90 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | ||
91 | struct intel_dp *intel_dp = &intel_dig_port->dp; | ||
92 | int ret; | ||
93 | |||
94 | DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links); | ||
95 | |||
96 | drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, intel_mst->port); | ||
97 | |||
98 | ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); | ||
99 | if (ret) { | ||
100 | DRM_ERROR("failed to update payload %d\n", ret); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | static void intel_mst_post_disable_dp(struct intel_encoder *encoder) | ||
105 | { | ||
106 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | ||
107 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | ||
108 | struct intel_dp *intel_dp = &intel_dig_port->dp; | ||
109 | |||
110 | DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links); | ||
111 | |||
112 | /* this can fail */ | ||
113 | drm_dp_check_act_status(&intel_dp->mst_mgr); | ||
114 | /* and this can also fail */ | ||
115 | drm_dp_update_payload_part2(&intel_dp->mst_mgr); | ||
116 | |||
117 | drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, intel_mst->port); | ||
118 | |||
119 | intel_dp->active_mst_links--; | ||
120 | intel_mst->port = NULL; | ||
121 | if (intel_dp->active_mst_links == 0) { | ||
122 | intel_dig_port->base.post_disable(&intel_dig_port->base); | ||
123 | intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static void intel_mst_pre_enable_dp(struct intel_encoder *encoder) | ||
128 | { | ||
129 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | ||
130 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | ||
131 | struct intel_dp *intel_dp = &intel_dig_port->dp; | ||
132 | struct drm_device *dev = encoder->base.dev; | ||
133 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
134 | enum port port = intel_dig_port->port; | ||
135 | int ret; | ||
136 | uint32_t temp; | ||
137 | struct intel_connector *found = NULL, *intel_connector; | ||
138 | int slots; | ||
139 | struct drm_crtc *crtc = encoder->base.crtc; | ||
140 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
141 | |||
142 | list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head) { | ||
143 | if (intel_connector->new_encoder == encoder) { | ||
144 | found = intel_connector; | ||
145 | break; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | if (!found) { | ||
150 | DRM_ERROR("can't find connector\n"); | ||
151 | return; | ||
152 | } | ||
153 | |||
154 | DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links); | ||
155 | intel_mst->port = found->port; | ||
156 | |||
157 | if (intel_dp->active_mst_links == 0) { | ||
158 | enum port port = intel_ddi_get_encoder_port(encoder); | ||
159 | |||
160 | I915_WRITE(PORT_CLK_SEL(port), intel_crtc->config.ddi_pll_sel); | ||
161 | |||
162 | intel_ddi_init_dp_buf_reg(&intel_dig_port->base); | ||
163 | |||
164 | intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); | ||
165 | |||
166 | |||
167 | intel_dp_start_link_train(intel_dp); | ||
168 | intel_dp_complete_link_train(intel_dp); | ||
169 | intel_dp_stop_link_train(intel_dp); | ||
170 | } | ||
171 | |||
172 | ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr, | ||
173 | intel_mst->port, intel_crtc->config.pbn, &slots); | ||
174 | if (ret == false) { | ||
175 | DRM_ERROR("failed to allocate vcpi\n"); | ||
176 | return; | ||
177 | } | ||
178 | |||
179 | |||
180 | intel_dp->active_mst_links++; | ||
181 | temp = I915_READ(DP_TP_STATUS(port)); | ||
182 | I915_WRITE(DP_TP_STATUS(port), temp); | ||
183 | |||
184 | ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); | ||
185 | } | ||
186 | |||
187 | static void intel_mst_enable_dp(struct intel_encoder *encoder) | ||
188 | { | ||
189 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | ||
190 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | ||
191 | struct intel_dp *intel_dp = &intel_dig_port->dp; | ||
192 | struct drm_device *dev = intel_dig_port->base.base.dev; | ||
193 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
194 | enum port port = intel_dig_port->port; | ||
195 | int ret; | ||
196 | |||
197 | DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links); | ||
198 | |||
199 | if (wait_for((I915_READ(DP_TP_STATUS(port)) & DP_TP_STATUS_ACT_SENT), | ||
200 | 1)) | ||
201 | DRM_ERROR("Timed out waiting for ACT sent\n"); | ||
202 | |||
203 | ret = drm_dp_check_act_status(&intel_dp->mst_mgr); | ||
204 | |||
205 | ret = drm_dp_update_payload_part2(&intel_dp->mst_mgr); | ||
206 | } | ||
207 | |||
208 | static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder, | ||
209 | enum pipe *pipe) | ||
210 | { | ||
211 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | ||
212 | *pipe = intel_mst->pipe; | ||
213 | if (intel_mst->port) | ||
214 | return true; | ||
215 | return false; | ||
216 | } | ||
217 | |||
218 | static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder, | ||
219 | struct intel_crtc_config *pipe_config) | ||
220 | { | ||
221 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); | ||
222 | struct intel_digital_port *intel_dig_port = intel_mst->primary; | ||
223 | struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); | ||
224 | struct drm_device *dev = encoder->base.dev; | ||
225 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
226 | enum transcoder cpu_transcoder = crtc->config.cpu_transcoder; | ||
227 | u32 temp, flags = 0; | ||
228 | |||
229 | pipe_config->has_dp_encoder = true; | ||
230 | |||
231 | temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); | ||
232 | if (temp & TRANS_DDI_PHSYNC) | ||
233 | flags |= DRM_MODE_FLAG_PHSYNC; | ||
234 | else | ||
235 | flags |= DRM_MODE_FLAG_NHSYNC; | ||
236 | if (temp & TRANS_DDI_PVSYNC) | ||
237 | flags |= DRM_MODE_FLAG_PVSYNC; | ||
238 | else | ||
239 | flags |= DRM_MODE_FLAG_NVSYNC; | ||
240 | |||
241 | switch (temp & TRANS_DDI_BPC_MASK) { | ||
242 | case TRANS_DDI_BPC_6: | ||
243 | pipe_config->pipe_bpp = 18; | ||
244 | break; | ||
245 | case TRANS_DDI_BPC_8: | ||
246 | pipe_config->pipe_bpp = 24; | ||
247 | break; | ||
248 | case TRANS_DDI_BPC_10: | ||
249 | pipe_config->pipe_bpp = 30; | ||
250 | break; | ||
251 | case TRANS_DDI_BPC_12: | ||
252 | pipe_config->pipe_bpp = 36; | ||
253 | break; | ||
254 | default: | ||
255 | break; | ||
256 | } | ||
257 | pipe_config->adjusted_mode.flags |= flags; | ||
258 | intel_dp_get_m_n(crtc, pipe_config); | ||
259 | |||
260 | intel_ddi_clock_get(&intel_dig_port->base, pipe_config); | ||
261 | } | ||
262 | |||
263 | static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector) | ||
264 | { | ||
265 | struct intel_connector *intel_connector = to_intel_connector(connector); | ||
266 | struct intel_dp *intel_dp = intel_connector->mst_port; | ||
267 | struct edid *edid; | ||
268 | int ret; | ||
269 | |||
270 | edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port); | ||
271 | if (!edid) | ||
272 | return 0; | ||
273 | |||
274 | ret = intel_connector_update_modes(connector, edid); | ||
275 | kfree(edid); | ||
276 | |||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | static enum drm_connector_status | ||
281 | intel_mst_port_dp_detect(struct drm_connector *connector) | ||
282 | { | ||
283 | struct intel_connector *intel_connector = to_intel_connector(connector); | ||
284 | struct intel_dp *intel_dp = intel_connector->mst_port; | ||
285 | |||
286 | return drm_dp_mst_detect_port(&intel_dp->mst_mgr, intel_connector->port); | ||
287 | } | ||
288 | |||
289 | static enum drm_connector_status | ||
290 | intel_dp_mst_detect(struct drm_connector *connector, bool force) | ||
291 | { | ||
292 | enum drm_connector_status status; | ||
293 | status = intel_mst_port_dp_detect(connector); | ||
294 | return status; | ||
295 | } | ||
296 | |||
297 | static int | ||
298 | intel_dp_mst_set_property(struct drm_connector *connector, | ||
299 | struct drm_property *property, | ||
300 | uint64_t val) | ||
301 | { | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static void | ||
306 | intel_dp_mst_connector_destroy(struct drm_connector *connector) | ||
307 | { | ||
308 | struct intel_connector *intel_connector = to_intel_connector(connector); | ||
309 | |||
310 | if (!IS_ERR_OR_NULL(intel_connector->edid)) | ||
311 | kfree(intel_connector->edid); | ||
312 | |||
313 | drm_connector_cleanup(connector); | ||
314 | kfree(connector); | ||
315 | } | ||
316 | |||
317 | static const struct drm_connector_funcs intel_dp_mst_connector_funcs = { | ||
318 | .dpms = intel_connector_dpms, | ||
319 | .detect = intel_dp_mst_detect, | ||
320 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
321 | .set_property = intel_dp_mst_set_property, | ||
322 | .destroy = intel_dp_mst_connector_destroy, | ||
323 | }; | ||
324 | |||
325 | static int intel_dp_mst_get_modes(struct drm_connector *connector) | ||
326 | { | ||
327 | return intel_dp_mst_get_ddc_modes(connector); | ||
328 | } | ||
329 | |||
330 | static enum drm_mode_status | ||
331 | intel_dp_mst_mode_valid(struct drm_connector *connector, | ||
332 | struct drm_display_mode *mode) | ||
333 | { | ||
334 | /* TODO - validate mode against available PBN for link */ | ||
335 | if (mode->clock < 10000) | ||
336 | return MODE_CLOCK_LOW; | ||
337 | |||
338 | if (mode->flags & DRM_MODE_FLAG_DBLCLK) | ||
339 | return MODE_H_ILLEGAL; | ||
340 | |||
341 | return MODE_OK; | ||
342 | } | ||
343 | |||
344 | static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connector) | ||
345 | { | ||
346 | struct intel_connector *intel_connector = to_intel_connector(connector); | ||
347 | struct intel_dp *intel_dp = intel_connector->mst_port; | ||
348 | return &intel_dp->mst_encoders[0]->base.base; | ||
349 | } | ||
350 | |||
351 | static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = { | ||
352 | .get_modes = intel_dp_mst_get_modes, | ||
353 | .mode_valid = intel_dp_mst_mode_valid, | ||
354 | .best_encoder = intel_mst_best_encoder, | ||
355 | }; | ||
356 | |||
357 | static void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder) | ||
358 | { | ||
359 | struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); | ||
360 | |||
361 | drm_encoder_cleanup(encoder); | ||
362 | kfree(intel_mst); | ||
363 | } | ||
364 | |||
365 | static const struct drm_encoder_funcs intel_dp_mst_enc_funcs = { | ||
366 | .destroy = intel_dp_mst_encoder_destroy, | ||
367 | }; | ||
368 | |||
369 | static bool intel_dp_mst_get_hw_state(struct intel_connector *connector) | ||
370 | { | ||
371 | if (connector->encoder) { | ||
372 | enum pipe pipe; | ||
373 | if (!connector->encoder->get_hw_state(connector->encoder, &pipe)) | ||
374 | return false; | ||
375 | return true; | ||
376 | } | ||
377 | return false; | ||
378 | } | ||
379 | |||
380 | static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, char *pathprop) | ||
381 | { | ||
382 | struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr); | ||
383 | struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | ||
384 | struct drm_device *dev = intel_dig_port->base.base.dev; | ||
385 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
386 | struct intel_connector *intel_connector; | ||
387 | struct drm_connector *connector; | ||
388 | int i; | ||
389 | |||
390 | intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL); | ||
391 | if (!intel_connector) | ||
392 | return NULL; | ||
393 | |||
394 | connector = &intel_connector->base; | ||
395 | drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort); | ||
396 | drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs); | ||
397 | |||
398 | intel_connector->unregister = intel_connector_unregister; | ||
399 | intel_connector->get_hw_state = intel_dp_mst_get_hw_state; | ||
400 | intel_connector->mst_port = intel_dp; | ||
401 | intel_connector->port = port; | ||
402 | |||
403 | for (i = PIPE_A; i <= PIPE_C; i++) { | ||
404 | drm_mode_connector_attach_encoder(&intel_connector->base, | ||
405 | &intel_dp->mst_encoders[i]->base.base); | ||
406 | } | ||
407 | intel_dp_add_properties(intel_dp, connector); | ||
408 | |||
409 | drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); | ||
410 | drm_mode_connector_set_path_property(connector, pathprop); | ||
411 | drm_reinit_primary_mode_group(dev); | ||
412 | mutex_lock(&dev->mode_config.mutex); | ||
413 | drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, connector); | ||
414 | mutex_unlock(&dev->mode_config.mutex); | ||
415 | drm_connector_register(&intel_connector->base); | ||
416 | return connector; | ||
417 | } | ||
418 | |||
419 | static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, | ||
420 | struct drm_connector *connector) | ||
421 | { | ||
422 | struct intel_connector *intel_connector = to_intel_connector(connector); | ||
423 | struct drm_device *dev = connector->dev; | ||
424 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
425 | /* need to nuke the connector */ | ||
426 | mutex_lock(&dev->mode_config.mutex); | ||
427 | intel_connector_dpms(connector, DRM_MODE_DPMS_OFF); | ||
428 | mutex_unlock(&dev->mode_config.mutex); | ||
429 | |||
430 | intel_connector->unregister(intel_connector); | ||
431 | |||
432 | mutex_lock(&dev->mode_config.mutex); | ||
433 | drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, connector); | ||
434 | drm_connector_cleanup(connector); | ||
435 | mutex_unlock(&dev->mode_config.mutex); | ||
436 | |||
437 | drm_reinit_primary_mode_group(dev); | ||
438 | |||
439 | kfree(intel_connector); | ||
440 | DRM_DEBUG_KMS("\n"); | ||
441 | } | ||
442 | |||
443 | static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) | ||
444 | { | ||
445 | struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr); | ||
446 | struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); | ||
447 | struct drm_device *dev = intel_dig_port->base.base.dev; | ||
448 | |||
449 | drm_kms_helper_hotplug_event(dev); | ||
450 | } | ||
451 | |||
452 | static struct drm_dp_mst_topology_cbs mst_cbs = { | ||
453 | .add_connector = intel_dp_add_mst_connector, | ||
454 | .destroy_connector = intel_dp_destroy_mst_connector, | ||
455 | .hotplug = intel_dp_mst_hotplug, | ||
456 | }; | ||
457 | |||
458 | static struct intel_dp_mst_encoder * | ||
459 | intel_dp_create_fake_mst_encoder(struct intel_digital_port *intel_dig_port, enum pipe pipe) | ||
460 | { | ||
461 | struct intel_dp_mst_encoder *intel_mst; | ||
462 | struct intel_encoder *intel_encoder; | ||
463 | struct drm_device *dev = intel_dig_port->base.base.dev; | ||
464 | |||
465 | intel_mst = kzalloc(sizeof(*intel_mst), GFP_KERNEL); | ||
466 | |||
467 | if (!intel_mst) | ||
468 | return NULL; | ||
469 | |||
470 | intel_mst->pipe = pipe; | ||
471 | intel_encoder = &intel_mst->base; | ||
472 | intel_mst->primary = intel_dig_port; | ||
473 | |||
474 | drm_encoder_init(dev, &intel_encoder->base, &intel_dp_mst_enc_funcs, | ||
475 | DRM_MODE_ENCODER_DPMST); | ||
476 | |||
477 | intel_encoder->type = INTEL_OUTPUT_DP_MST; | ||
478 | intel_encoder->crtc_mask = 0x7; | ||
479 | intel_encoder->cloneable = 0; | ||
480 | |||
481 | intel_encoder->compute_config = intel_dp_mst_compute_config; | ||
482 | intel_encoder->disable = intel_mst_disable_dp; | ||
483 | intel_encoder->post_disable = intel_mst_post_disable_dp; | ||
484 | intel_encoder->pre_enable = intel_mst_pre_enable_dp; | ||
485 | intel_encoder->enable = intel_mst_enable_dp; | ||
486 | intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state; | ||
487 | intel_encoder->get_config = intel_dp_mst_enc_get_config; | ||
488 | |||
489 | return intel_mst; | ||
490 | |||
491 | } | ||
492 | |||
493 | static bool | ||
494 | intel_dp_create_fake_mst_encoders(struct intel_digital_port *intel_dig_port) | ||
495 | { | ||
496 | int i; | ||
497 | struct intel_dp *intel_dp = &intel_dig_port->dp; | ||
498 | |||
499 | for (i = PIPE_A; i <= PIPE_C; i++) | ||
500 | intel_dp->mst_encoders[i] = intel_dp_create_fake_mst_encoder(intel_dig_port, i); | ||
501 | return true; | ||
502 | } | ||
503 | |||
504 | int | ||
505 | intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_base_id) | ||
506 | { | ||
507 | struct intel_dp *intel_dp = &intel_dig_port->dp; | ||
508 | struct drm_device *dev = intel_dig_port->base.base.dev; | ||
509 | int ret; | ||
510 | |||
511 | intel_dp->can_mst = true; | ||
512 | intel_dp->mst_mgr.cbs = &mst_cbs; | ||
513 | |||
514 | /* create encoders */ | ||
515 | intel_dp_create_fake_mst_encoders(intel_dig_port); | ||
516 | ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev->dev, &intel_dp->aux, 16, 3, conn_base_id); | ||
517 | if (ret) { | ||
518 | intel_dp->can_mst = false; | ||
519 | return ret; | ||
520 | } | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | void | ||
525 | intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port) | ||
526 | { | ||
527 | struct intel_dp *intel_dp = &intel_dig_port->dp; | ||
528 | |||
529 | if (!intel_dp->can_mst) | ||
530 | return; | ||
531 | |||
532 | drm_dp_mst_topology_mgr_destroy(&intel_dp->mst_mgr); | ||
533 | /* encoders will get killed by normal cleanup */ | ||
534 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 40086e1a4ee3..1dfd1e518551 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <drm/drm_crtc.h> | 32 | #include <drm/drm_crtc.h> |
33 | #include <drm/drm_crtc_helper.h> | 33 | #include <drm/drm_crtc_helper.h> |
34 | #include <drm/drm_fb_helper.h> | 34 | #include <drm/drm_fb_helper.h> |
35 | #include <drm/drm_dp_helper.h> | 35 | #include <drm/drm_dp_mst_helper.h> |
36 | 36 | ||
37 | /** | 37 | /** |
38 | * _wait_for - magic (register) wait macro | 38 | * _wait_for - magic (register) wait macro |
@@ -100,6 +100,7 @@ | |||
100 | #define INTEL_OUTPUT_EDP 8 | 100 | #define INTEL_OUTPUT_EDP 8 |
101 | #define INTEL_OUTPUT_DSI 9 | 101 | #define INTEL_OUTPUT_DSI 9 |
102 | #define INTEL_OUTPUT_UNKNOWN 10 | 102 | #define INTEL_OUTPUT_UNKNOWN 10 |
103 | #define INTEL_OUTPUT_DP_MST 11 | ||
103 | 104 | ||
104 | #define INTEL_DVO_CHIP_NONE 0 | 105 | #define INTEL_DVO_CHIP_NONE 0 |
105 | #define INTEL_DVO_CHIP_LVDS 1 | 106 | #define INTEL_DVO_CHIP_LVDS 1 |
@@ -207,6 +208,10 @@ struct intel_connector { | |||
207 | /* since POLL and HPD connectors may use the same HPD line keep the native | 208 | /* since POLL and HPD connectors may use the same HPD line keep the native |
208 | state of connector->polled in case hotplug storm detection changes it */ | 209 | state of connector->polled in case hotplug storm detection changes it */ |
209 | u8 polled; | 210 | u8 polled; |
211 | |||
212 | void *port; /* store this opaque as its illegal to dereference it */ | ||
213 | |||
214 | struct intel_dp *mst_port; | ||
210 | }; | 215 | }; |
211 | 216 | ||
212 | typedef struct dpll { | 217 | typedef struct dpll { |
@@ -351,6 +356,9 @@ struct intel_crtc_config { | |||
351 | bool ips_enabled; | 356 | bool ips_enabled; |
352 | 357 | ||
353 | bool double_wide; | 358 | bool double_wide; |
359 | |||
360 | bool dp_encoder_is_mst; | ||
361 | int pbn; | ||
354 | }; | 362 | }; |
355 | 363 | ||
356 | struct intel_pipe_wm { | 364 | struct intel_pipe_wm { |
@@ -506,6 +514,7 @@ struct intel_hdmi { | |||
506 | struct drm_display_mode *adjusted_mode); | 514 | struct drm_display_mode *adjusted_mode); |
507 | }; | 515 | }; |
508 | 516 | ||
517 | struct intel_dp_mst_encoder; | ||
509 | #define DP_MAX_DOWNSTREAM_PORTS 0x10 | 518 | #define DP_MAX_DOWNSTREAM_PORTS 0x10 |
510 | 519 | ||
511 | /** | 520 | /** |
@@ -545,8 +554,16 @@ struct intel_dp { | |||
545 | unsigned long last_power_on; | 554 | unsigned long last_power_on; |
546 | unsigned long last_backlight_off; | 555 | unsigned long last_backlight_off; |
547 | bool use_tps3; | 556 | bool use_tps3; |
557 | bool can_mst; /* this port supports mst */ | ||
558 | bool is_mst; | ||
559 | int active_mst_links; | ||
560 | /* connector directly attached - won't be use for modeset in mst world */ | ||
548 | struct intel_connector *attached_connector; | 561 | struct intel_connector *attached_connector; |
549 | 562 | ||
563 | /* mst connector list */ | ||
564 | struct intel_dp_mst_encoder *mst_encoders[I915_MAX_PIPES]; | ||
565 | struct drm_dp_mst_topology_mgr mst_mgr; | ||
566 | |||
550 | uint32_t (*get_aux_clock_divider)(struct intel_dp *dp, int index); | 567 | uint32_t (*get_aux_clock_divider)(struct intel_dp *dp, int index); |
551 | /* | 568 | /* |
552 | * This function returns the value we have to program the AUX_CTL | 569 | * This function returns the value we have to program the AUX_CTL |
@@ -573,6 +590,13 @@ struct intel_digital_port { | |||
573 | bool (*hpd_pulse)(struct intel_digital_port *, bool); | 590 | bool (*hpd_pulse)(struct intel_digital_port *, bool); |
574 | }; | 591 | }; |
575 | 592 | ||
593 | struct intel_dp_mst_encoder { | ||
594 | struct intel_encoder base; | ||
595 | enum pipe pipe; | ||
596 | struct intel_digital_port *primary; | ||
597 | void *port; /* store this opaque as its illegal to dereference it */ | ||
598 | }; | ||
599 | |||
576 | static inline int | 600 | static inline int |
577 | vlv_dport_to_channel(struct intel_digital_port *dport) | 601 | vlv_dport_to_channel(struct intel_digital_port *dport) |
578 | { | 602 | { |
@@ -657,6 +681,12 @@ enc_to_dig_port(struct drm_encoder *encoder) | |||
657 | return container_of(encoder, struct intel_digital_port, base.base); | 681 | return container_of(encoder, struct intel_digital_port, base.base); |
658 | } | 682 | } |
659 | 683 | ||
684 | static inline struct intel_dp_mst_encoder * | ||
685 | enc_to_mst(struct drm_encoder *encoder) | ||
686 | { | ||
687 | return container_of(encoder, struct intel_dp_mst_encoder, base.base); | ||
688 | } | ||
689 | |||
660 | static inline struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) | 690 | static inline struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) |
661 | { | 691 | { |
662 | return &enc_to_dig_port(encoder)->dp; | 692 | return &enc_to_dig_port(encoder)->dp; |
@@ -719,6 +749,9 @@ void intel_ddi_get_config(struct intel_encoder *encoder, | |||
719 | struct intel_crtc_config *pipe_config); | 749 | struct intel_crtc_config *pipe_config); |
720 | 750 | ||
721 | void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder); | 751 | void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder); |
752 | void intel_ddi_clock_get(struct intel_encoder *encoder, | ||
753 | struct intel_crtc_config *pipe_config); | ||
754 | void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state); | ||
722 | 755 | ||
723 | /* intel_display.c */ | 756 | /* intel_display.c */ |
724 | const char *intel_output_name(int output); | 757 | const char *intel_output_name(int output); |
@@ -871,6 +904,15 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate); | |||
871 | void intel_edp_psr_exit(struct drm_device *dev); | 904 | void intel_edp_psr_exit(struct drm_device *dev); |
872 | void intel_edp_psr_init(struct drm_device *dev); | 905 | void intel_edp_psr_init(struct drm_device *dev); |
873 | 906 | ||
907 | int intel_dp_handle_hpd_irq(struct intel_digital_port *digport, bool long_hpd); | ||
908 | void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector); | ||
909 | void intel_dp_mst_suspend(struct drm_device *dev); | ||
910 | void intel_dp_mst_resume(struct drm_device *dev); | ||
911 | int intel_dp_max_link_bw(struct intel_dp *intel_dp); | ||
912 | void intel_dp_hot_plug(struct intel_encoder *intel_encoder); | ||
913 | /* intel_dp_mst.c */ | ||
914 | int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); | ||
915 | void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port); | ||
874 | /* intel_dsi.c */ | 916 | /* intel_dsi.c */ |
875 | void intel_dsi_init(struct drm_device *dev); | 917 | void intel_dsi_init(struct drm_device *dev); |
876 | 918 | ||
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index f475414671d8..7cdb8861bb7c 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c | |||
@@ -375,6 +375,11 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
375 | } | 375 | } |
376 | 376 | ||
377 | encoder = connector->encoder; | 377 | encoder = connector->encoder; |
378 | if (!encoder) { | ||
379 | struct drm_connector_helper_funcs *connector_funcs; | ||
380 | connector_funcs = connector->helper_private; | ||
381 | encoder = connector_funcs->best_encoder(connector); | ||
382 | } | ||
378 | if (!encoder || WARN_ON(!encoder->crtc)) { | 383 | if (!encoder || WARN_ON(!encoder->crtc)) { |
379 | DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", | 384 | DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", |
380 | connector->name); | 385 | connector->name); |
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 2e2c71fcc9ed..d37934b6338e 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c | |||
@@ -352,6 +352,7 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, | |||
352 | case INTEL_OUTPUT_UNKNOWN: | 352 | case INTEL_OUTPUT_UNKNOWN: |
353 | case INTEL_OUTPUT_DISPLAYPORT: | 353 | case INTEL_OUTPUT_DISPLAYPORT: |
354 | case INTEL_OUTPUT_HDMI: | 354 | case INTEL_OUTPUT_HDMI: |
355 | case INTEL_OUTPUT_DP_MST: | ||
355 | type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL; | 356 | type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL; |
356 | break; | 357 | break; |
357 | case INTEL_OUTPUT_EDP: | 358 | case INTEL_OUTPUT_EDP: |