diff mbox

[09/11] i915: add DP 1.2 MST support (v0.6)

Message ID 1401940898-2825-10-git-send-email-airlied@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dave Airlie June 5, 2014, 4:01 a.m. UTC
From: Dave Airlie <airlied@redhat.com>

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

TODO:
possibly further state checker fixes
HDMI screaming IRQ needs fixing.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/i915/Makefile         |   1 +
 drivers/gpu/drm/i915/i915_dma.c       |  10 +
 drivers/gpu/drm/i915/i915_drv.c       |  13 +-
 drivers/gpu/drm/i915/i915_drv.h       |   9 +
 drivers/gpu/drm/i915/i915_irq.c       |   6 +-
 drivers/gpu/drm/i915/intel_ddi.c      |  85 +++++-
 drivers/gpu/drm/i915/intel_display.c  |  40 ++-
 drivers/gpu/drm/i915/intel_dp.c       | 234 ++++++++++++++-
 drivers/gpu/drm/i915/intel_dp_mst.c   | 535 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_drv.h      |  45 ++-
 drivers/gpu/drm/i915/intel_fbdev.c    |   5 +
 drivers/gpu/drm/i915/intel_opregion.c |   1 +
 12 files changed, 945 insertions(+), 39 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/intel_dp_mst.c

Comments

Paulo Zanoni July 22, 2014, 8:02 p.m. UTC | #1
2014-06-05 1:01 GMT-03:00 Dave Airlie <airlied@gmail.com>:
> From: Dave Airlie <airlied@redhat.com>
>
> This adds DP 1.2 MST support on Haswell systems.

Hi

It looks like drm-intel-nightly now includes this patch. It actually
includes v7, but I couldn't find it on my mail dirs.

Just by booting the machine with this patch, I get:

[   11.013593] ------------[ cut here ]------------
[   11.013627] WARNING: CPU: 1 PID: 389 at
drivers/gpu/drm/i915/intel_fbdev.c:383
intel_fb_initial_config+0x3ca/0x660 [i915]()
[   11.013629] Modules linked in: i2c_designware_platform i915(+)
i2c_designware_core i2c_algo_bit drm_kms_helper drm sg sd_mod ahci
ehci_pci libahci ehci_hcd e1000e xhci_hcd sdhci_acpi sdhci
[   11.013651] CPU: 1 PID: 389 Comm: udevd Not tainted
3.16.0-rc6.1407221626+ #673
[   11.013654] Hardware name: Intel Corporation Shark Bay Client
platform/WhiteTip Mountain 1, BIOS HSWLPTU1.86C.0137.R00.1403031632
03/03/2014
[   11.013656]  0000000000000009 ffff88009d14b790 ffffffff816b6a61
0000000000000000
[   11.013662]  ffff88009d14b7c8 ffffffff81075d88 ffff8801483db10b
ffff880148279400
[   11.013667]  ffff88009d0caf00 0000000000000003 0000000000000003
ffff88009d14b7d8
[   11.013672] Call Trace:
[   11.013680]  [<ffffffff816b6a61>] dump_stack+0x4d/0x66
[   11.013686]  [<ffffffff81075d88>] warn_slowpath_common+0x78/0xa0
[   11.013690]  [<ffffffff81075e65>] warn_slowpath_null+0x15/0x20
[   11.013714]  [<ffffffffa01a8e5a>] intel_fb_initial_config+0x3ca/0x660 [i915]
[   11.013724]  [<ffffffffa012ebef>] drm_setup_crtcs+0x17f/0x830
[drm_kms_helper]
[   11.013729]  [<ffffffff810c47fd>] ? trace_hardirqs_on_caller+0x15d/0x200
[   11.013736]  [<ffffffffa012f58a>]
drm_fb_helper_initial_config+0x19a/0x4d0 [drm_kms_helper]
[   11.013740]  [<ffffffff810c47fd>] ? trace_hardirqs_on_caller+0x15d/0x200
[   11.013762]  [<ffffffffa01a9c4a>] intel_fbdev_initial_config+0x1a/0x20 [i915]
[   11.013789]  [<ffffffffa01ce0eb>] i915_driver_load+0x111b/0x1130 [i915]
[   11.013803]  [<ffffffffa00c4615>] drm_dev_register+0xa5/0x100 [drm]
[   11.013815]  [<ffffffffa00c7108>] drm_get_pci_dev+0x88/0x1f0 [drm]
[   11.013834]  [<ffffffffa013e586>] i915_pci_probe+0x36/0x50 [i915]
[   11.013839]  [<ffffffff8133e12d>] local_pci_probe+0x3d/0xa0
[   11.013843]  [<ffffffff8133f385>] ? pci_match_device+0xe5/0x110
[   11.013847]  [<ffffffff8133f4b9>] pci_device_probe+0xc9/0x120
[   11.013853]  [<ffffffff813f65e9>] driver_probe_device+0x89/0x250
[   11.013857]  [<ffffffff813f687b>] __driver_attach+0x8b/0x90
[   11.013879]  [<ffffffff813f67f0>] ? __device_attach+0x40/0x40
[   11.013883]  [<ffffffff813f4723>] bus_for_each_dev+0x63/0xa0
[   11.013888]  [<ffffffff813f6139>] driver_attach+0x19/0x20
[   11.013892]  [<ffffffff813f5db8>] bus_add_driver+0x178/0x230
[   11.013896]  [<ffffffff813f6fcf>] driver_register+0x5f/0xf0
[   11.013899]  [<ffffffff8133da48>] __pci_register_driver+0x58/0x60
[   11.013911]  [<ffffffffa00c736a>] drm_pci_init+0xfa/0x130 [drm]
[   11.013915]  [<ffffffff810c48ad>] ? trace_hardirqs_on+0xd/0x10
[   11.013918]  [<ffffffffa0222000>] ? 0xffffffffa0221fff
[   11.013937]  [<ffffffffa0222089>] i915_init+0x89/0x90 [i915]
[   11.013942]  [<ffffffff810002d8>] do_one_initcall+0x98/0x1f0
[   11.013947]  [<ffffffff811920b2>] ? __vunmap+0xa2/0x100
[   11.013952]  [<ffffffff810f904a>] load_module+0x1bea/0x22d0
[   11.013956]  [<ffffffff810f5ab0>] ? symbol_put_addr+0x40/0x40
[   11.013960]  [<ffffffff810f5df9>] ? copy_module_from_fd.isra.49+0x119/0x170
[   11.013965]  [<ffffffff810f9876>] SyS_finit_module+0x76/0x80
[   11.013970]  [<ffffffff816c0bd2>] system_call_fastpath+0x16/0x1b
[   11.013973] ---[ end trace e4d35cd76b2fc39f ]---

This is the WARN that makes the code print
[drm:intel_fb_initial_config] connector HDMI-A-2 has no encoder or
crtc, skipping


Then, if I do a normal S3 suspend/resume cycle with the desktop
enabled and everything running, I get:

[   32.431306] ------------[ cut here ]------------
[   32.431341] WARNING: CPU: 2 PID: 3200 at
drivers/gpu/drm/i915/intel_pm.c:4979
intel_suspend_gt_powersave+0x49/0x50 [i915]()
[   32.431370] Modules linked in: fuse intel_rapl x86_pkg_temp_thermal
intel_powerclamp serio_raw i2c_i801 i2c_designware_platform
i2c_designware_core i915 i2c_algo_bit drm_kms_helper drm mei_me mei sg
sd_mod ehci_pci ehci_hcd ahci libahci e1000e xhci_hcd sdhci_acpi sdhci
[   32.431373] CPU: 2 PID: 3200 Comm: kworker/u16:14 Tainted: G
W     3.16.0-rc6.1407221626+ #673
[   32.431375] Hardware name: Intel Corporation Shark Bay Client
platform/WhiteTip Mountain 1, BIOS HSWLPTU1.86C.0137.R00.1403031632
03/03/2014
[   32.431379] Workqueue: events_unbound async_run_entry_fn
[   32.431383]  0000000000000009 ffff88009d1f3be8 ffffffff816b6a61
0000000000000000
[   32.431386]  ffff88009d1f3c20 ffffffff81075d88 ffff880148610000
0000000000000000
[   32.431390]  ffff880148610000 ffff88009d86e758 ffffffff81a5d47a
ffff88009d1f3c30
[   32.431390] Call Trace:
[   32.431396]  [<ffffffff816b6a61>] dump_stack+0x4d/0x66
[   32.431399]  [<ffffffff81075d88>] warn_slowpath_common+0x78/0xa0
[   32.431402]  [<ffffffff81075e65>] warn_slowpath_null+0x15/0x20
[   32.431413]  [<ffffffffa015a359>] intel_suspend_gt_powersave+0x49/0x50 [i915]
[   32.431422]  [<ffffffffa014c096>] i915_drm_freeze+0x96/0x190 [i915]
[   32.431430]  [<ffffffffa014c21a>] i915_pm_suspend+0x2a/0x50 [i915]
[   32.431434]  [<ffffffff8133ee01>] pci_pm_suspend+0x71/0x160
[   32.431437]  [<ffffffff8133ed90>] ? pci_pm_freeze+0xe0/0xe0
[   32.431440]  [<ffffffff8140071a>] dpm_run_callback+0x3a/0x130
[   32.431443]  [<ffffffff81401e00>] __device_suspend+0xf0/0x2f0
[   32.431445]  [<ffffffff8140201a>] async_suspend+0x1a/0xa0
[   32.431448]  [<ffffffff810a0224>] async_run_entry_fn+0x34/0x120
[   32.431451]  [<ffffffff8109306f>] process_one_work+0x1cf/0x550
[   32.431454]  [<ffffffff8109300f>] ? process_one_work+0x16f/0x550
[   32.431457]  [<ffffffff81093923>] worker_thread+0x63/0x540
[   32.431461]  [<ffffffff810938c0>] ? create_and_start_worker+0x50/0x50
[   32.431464]  [<ffffffff81099ef0>] kthread+0x100/0x120
[   32.431467]  [<ffffffff81099df0>] ? kthread_create_on_node+0x230/0x230
[   32.431470]  [<ffffffff816c0b2c>] ret_from_fork+0x7c/0xb0
[   32.431472]  [<ffffffff81099df0>] ? kthread_create_on_node+0x230/0x230
[   32.431474] ---[ end trace 466388920de060e0 ]---

This is the warn caused by "WARN_ON(intel_irqs_enabled(dev_priv));".


Also, if I run intel-gpu-tools/tests/pm-rpm, which disables all the
screens before trying to suspend, I still get the following backtrace:

[  548.769561] [drm:intel_runtime_resume] Device resumed
[  548.769716] [drm:intel_display_power_get] enabling always-on
[  548.769718] [drm:intel_display_power_get] enabling display
[  548.769735] [drm:hsw_set_power_well] Enabling power well
[  548.770519] [drm] Enabling RC6 states: RC6 on, RC6p off, RC6pp off
[  548.770540] [drm:gen6_enable_rps] Overclocking supported. Max:
1000MHz, Overclock max: 1000MHz
[  548.770670] ------------[ cut here ]------------
[  548.770696] WARNING: CPU: 2 PID: 3186 at
drivers/gpu/drm/i915/intel_pm.c:4979
intel_suspend_gt_powersave+0x49/0x50 [i915]()
[  548.770729] Modules linked in: fuse intel_rapl x86_pkg_temp_thermal
intel_powerclamp serio_raw i2c_i801 mei_me mei i2c_designware_platform
i915 i2c_designware_core i2c_algo_bit drm_kms_helper drm sg sd_mod
ahci ehci_pci libahci ehci_hcd e1000e xhci_hcd sdhci_acpi sdhci
[  548.770734] CPU: 2 PID: 3186 Comm: kworker/u16:13 Tainted: G
W     3.16.0-rc6.1407221626+ #673
[  548.770736] Hardware name: Intel Corporation Shark Bay Client
platform/WhiteTip Mountain 1, BIOS HSWLPTU1.86C.0137.R00.1403031632
03/03/2014
[  548.770743] Workqueue: events_unbound async_run_entry_fn
[  548.770751]  0000000000000009 ffff88009b5c7be8 ffffffff816b6a61
0000000000000000
[  548.770757]  ffff88009b5c7c20 ffffffff81075d88 ffff88009d470000
0000000000000000
[  548.770762]  ffff88009d470000 ffff88009d6bc758 ffffffff81a5d47a
ffff88009b5c7c30
[  548.770764] Call Trace:
[  548.770773]  [<ffffffff816b6a61>] dump_stack+0x4d/0x66
[  548.770778]  [<ffffffff81075d88>] warn_slowpath_common+0x78/0xa0
[  548.770781]  [<ffffffff81075e65>] warn_slowpath_null+0x15/0x20
[  548.770795]  [<ffffffffa014c359>] intel_suspend_gt_powersave+0x49/0x50 [i915]
[  548.770804]  [<ffffffffa013e096>] i915_drm_freeze+0x96/0x190 [i915]
[  548.770814]  [<ffffffffa013e21a>] i915_pm_suspend+0x2a/0x50 [i915]
[  548.770818]  [<ffffffff8133ee01>] pci_pm_suspend+0x71/0x160
[  548.770821]  [<ffffffff8133ed90>] ? pci_pm_freeze+0xe0/0xe0
[  548.770825]  [<ffffffff8140071a>] dpm_run_callback+0x3a/0x130
[  548.770828]  [<ffffffff81401e00>] __device_suspend+0xf0/0x2f0
[  548.770831]  [<ffffffff8140201a>] async_suspend+0x1a/0xa0
[  548.770833]  [<ffffffff810a0224>] async_run_entry_fn+0x34/0x120
[  548.770837]  [<ffffffff8109306f>] process_one_work+0x1cf/0x550
[  548.770841]  [<ffffffff8109300f>] ? process_one_work+0x16f/0x550
[  548.770844]  [<ffffffff81093923>] worker_thread+0x63/0x540
[  548.770848]  [<ffffffff810938c0>] ? create_and_start_worker+0x50/0x50
[  548.770852]  [<ffffffff81099ef0>] kthread+0x100/0x120
[  548.770855]  [<ffffffff81099df0>] ? kthread_create_on_node+0x230/0x230
[  548.770859]  [<ffffffff816c0b2c>] ret_from_fork+0x7c/0xb0
[  548.770861]  [<ffffffff81099df0>] ? kthread_create_on_node+0x230/0x230
[  548.770863] ---[ end trace e4d35cd76b2fc3a0 ]---
[  548.774490] [drm:intel_display_power_put] disabling display
[  548.774493] [drm:hsw_set_power_well] Requesting to disable the power well
[  548.774494] [drm:intel_display_power_put] disabling always-on
[  548.796952] PM: suspend of devices complete after 54.240 msecs

If I revert both "drm/i915: mst topology dumper in debugfs (v0.2)" and
"drm/i915: add DP 1.2 MST support (v0.7)", then the WARNs go away.

My machine is a HSW ULT, and it has an eDP panel and an HDMI monitor attached.

Thanks,
Paulo

>
> 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
>
> TODO:
> possibly further state checker fixes
> HDMI screaming IRQ needs fixing.
>
> Signed-off-by: Dave Airlie <airlied@redhat.com>
> ---
>  drivers/gpu/drm/i915/Makefile         |   1 +
>  drivers/gpu/drm/i915/i915_dma.c       |  10 +
>  drivers/gpu/drm/i915/i915_drv.c       |  13 +-
>  drivers/gpu/drm/i915/i915_drv.h       |   9 +
>  drivers/gpu/drm/i915/i915_irq.c       |   6 +-
>  drivers/gpu/drm/i915/intel_ddi.c      |  85 +++++-
>  drivers/gpu/drm/i915/intel_display.c  |  40 ++-
>  drivers/gpu/drm/i915/intel_dp.c       | 234 ++++++++++++++-
>  drivers/gpu/drm/i915/intel_dp_mst.c   | 535 ++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_drv.h      |  45 ++-
>  drivers/gpu/drm/i915/intel_fbdev.c    |   5 +
>  drivers/gpu/drm/i915/intel_opregion.c |   1 +
>  12 files changed, 945 insertions(+), 39 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/intel_dp_mst.c
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 7b2f3be..03b7525 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -59,6 +59,7 @@ i915-y += dvo_ch7017.o \
>           intel_crt.o \
>           intel_ddi.o \
>           intel_dp.o \
> +         intel_dp_mst.o \
>           intel_dsi_cmd.o \
>           intel_dsi.o \
>           intel_dsi_pll.o \
> diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> index 4e70de6..3bf2f1f 100644
> --- a/drivers/gpu/drm/i915/i915_dma.c
> +++ b/drivers/gpu/drm/i915/i915_dma.c
> @@ -1676,6 +1676,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
>                 goto out_mtrrfree;
>         }
>
> +       dev_priv->dp_wq = alloc_ordered_workqueue("i915-dp", 0);
> +       if (dev_priv->dp_wq == NULL) {
> +               DRM_ERROR("Failed to create our dp workqueue.\n");
> +               ret = -ENOMEM;
> +               goto out_freewq;
> +       }
> +
>         intel_irq_init(dev);
>         intel_uncore_sanitize(dev);
>
> @@ -1751,6 +1758,8 @@ out_gem_unload:
>         intel_teardown_gmbus(dev);
>         intel_teardown_mchbar(dev);
>         pm_qos_remove_request(&dev_priv->pm_qos);
> +       destroy_workqueue(dev_priv->dp_wq);
> +out_freewq:
>         destroy_workqueue(dev_priv->wq);
>  out_mtrrfree:
>         arch_phys_wc_del(dev_priv->gtt.mtrr);
> @@ -1855,6 +1864,7 @@ int i915_driver_unload(struct drm_device *dev)
>         intel_teardown_gmbus(dev);
>         intel_teardown_mchbar(dev);
>
> +       destroy_workqueue(dev_priv->dp_wq);
>         destroy_workqueue(dev_priv->wq);
>         pm_qos_remove_request(&dev_priv->pm_qos);
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 5b5b82c..051cf97 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -524,7 +524,6 @@ static int i915_drm_freeze(struct drm_device *dev)
>                         return error;
>                 }
>
> -               drm_irq_uninstall(dev);
>                 dev_priv->enable_hotplug_processing = false;
>
>                 intel_disable_gt_powersave(dev);
> @@ -539,6 +538,9 @@ static int i915_drm_freeze(struct drm_device *dev)
>                 }
>                 drm_modeset_unlock_all(dev);
>
> +               intel_dp_mst_suspend(dev);
> +               drm_irq_uninstall(dev);
> +
>                 intel_modeset_suspend_hw(dev);
>         }
>
> @@ -642,6 +644,15 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
>
>                 intel_modeset_init_hw(dev);
>
> +               {
> +                       unsigned long irqflags;
> +                       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
> +                       if (dev_priv->display.hpd_irq_setup)
> +                               dev_priv->display.hpd_irq_setup(dev);
> +                       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
> +               }
> +
> +               intel_dp_mst_resume(dev);
>                 drm_modeset_lock_all(dev);
>                 intel_modeset_setup_hw_state(dev, true);
>                 drm_modeset_unlock_all(dev);
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 5fd5bf3..1f3e929 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1556,6 +1556,15 @@ struct drm_i915_private {
>         u32 short_hpd_port_mask;
>         struct work_struct dig_port_work;
>
> +       /*
> +        * if we get a HPD irq from DP and a HPD irq from non-DP
> +        * the non-DP HPD could block the workqueue on a mode config
> +        * mutex getting, that userspace may have taken. However
> +        * userspace is waiting on the DP workqueue to run which is
> +        * blocked behind the non-DP one.
> +        */
> +       struct workqueue_struct *dp_wq;
> +
>         /* Old dri1 support infrastructure, beware the dragons ya fools entering
>          * here! */
>         struct i915_dri1_state dri1;
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index e3554d9..4e8f826 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1700,7 +1700,7 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
>          * deadlock.
>          */
>         if (queue_dig)
> -               schedule_work(&dev_priv->dig_port_work);
> +               queue_work(dev_priv->dp_wq, &dev_priv->dig_port_work);
>         if (queue_hp)
>                 schedule_work(&dev_priv->hotplug_work);
>  }
> @@ -4566,7 +4566,9 @@ void intel_hpd_init(struct drm_device *dev)
>         list_for_each_entry(connector, &mode_config->connector_list, head) {
>                 struct intel_connector *intel_connector = to_intel_connector(connector);
>                 connector->polled = intel_connector->polled;
> -               if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
> +               if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
> +                       connector->polled = DRM_CONNECTOR_POLL_HPD;
> +               if (intel_connector->mst_port)
>                         connector->polled = DRM_CONNECTOR_POLL_HPD;
>         }
>
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 2733a3d..2d8192a 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)
>         struct drm_encoder *encoder = &intel_encoder->base;
>         int type = intel_encoder->type;
>
> -       if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP ||
> +       if (type == INTEL_OUTPUT_DP_MST) {
> +               struct intel_digital_port *intel_dig_port = enc_to_mst(encoder)->primary;
> +               return intel_dig_port->port;
> +       } else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP ||
>             type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) {
>                 struct intel_digital_port *intel_dig_port =
>                         enc_to_dig_port(encoder);
> @@ -630,8 +633,8 @@ static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
>         return (refclk * n * 100) / (p * r);
>  }
>
> -static void intel_ddi_clock_get(struct intel_encoder *encoder,
> -                               struct intel_crtc_config *pipe_config)
> +void intel_ddi_clock_get(struct intel_encoder *encoder,
> +                        struct intel_crtc_config *pipe_config)
>  {
>         struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
>         enum port port = intel_ddi_get_encoder_port(encoder);
> @@ -785,7 +788,15 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
>
>         intel_ddi_put_crtc_pll(crtc);
>
> -       if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
> +       if (type == INTEL_OUTPUT_DP_MST) {
> +               struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
> +               intel_crtc->ddi_pll_sel = link_bw_to_pll_sel(intel_mst->primary->dp.link_bw);
> +               if (intel_crtc->ddi_pll_sel == -1) {
> +                       DRM_ERROR("Link bandwidth %d unsupported\n",
> +                                 intel_mst->primary->dp.link_bw);
> +                       return false;
> +               }
> +       } else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
>                 struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
>
>                 intel_crtc->ddi_pll_sel = link_bw_to_pll_sel(intel_dp->link_bw);
> @@ -943,8 +954,7 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
>         int type = intel_encoder->type;
>         uint32_t temp;
>
> -       if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
> -
> +       if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) {
>                 temp = TRANS_MSA_SYNC_CLK;
>                 switch (intel_crtc->config.pipe_bpp) {
>                 case 18:
> @@ -966,6 +976,21 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
>         }
>  }
>
> +void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state)
> +{
> +       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +       struct drm_device *dev = crtc->dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
> +       uint32_t temp;
> +       temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
> +       if (state == true)
> +               temp |= TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
> +       else
> +               temp &= ~TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
> +       I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp);
> +}
> +
>  void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
>  {
>         struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> @@ -1043,7 +1068,19 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
>                    type == INTEL_OUTPUT_EDP) {
>                 struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
>
> -               temp |= TRANS_DDI_MODE_SELECT_DP_SST;
> +               if (intel_dp->is_mst) {
> +                       temp |= TRANS_DDI_MODE_SELECT_DP_MST;
> +               } else
> +                       temp |= TRANS_DDI_MODE_SELECT_DP_SST;
> +
> +               temp |= DDI_PORT_WIDTH(intel_dp->lane_count);
> +       } else if (type == INTEL_OUTPUT_DP_MST) {
> +               struct intel_dp *intel_dp = &enc_to_mst(encoder)->primary->dp;
> +
> +               if (intel_dp->is_mst) {
> +                       temp |= TRANS_DDI_MODE_SELECT_DP_MST;
> +               } else
> +                       temp |= TRANS_DDI_MODE_SELECT_DP_SST;
>
>                 temp |= DDI_PORT_WIDTH(intel_dp->lane_count);
>         } else {
> @@ -1060,7 +1097,7 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
>         uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
>         uint32_t val = I915_READ(reg);
>
> -       val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK);
> +       val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
>         val |= TRANS_DDI_PORT_NONE;
>         I915_WRITE(reg, val);
>  }
> @@ -1099,8 +1136,11 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
>         case TRANS_DDI_MODE_SELECT_DP_SST:
>                 if (type == DRM_MODE_CONNECTOR_eDP)
>                         return true;
> -       case TRANS_DDI_MODE_SELECT_DP_MST:
>                 return (type == DRM_MODE_CONNECTOR_DisplayPort);
> +       case TRANS_DDI_MODE_SELECT_DP_MST:
> +               /* if the transcoder is in MST state then
> +                * connector isn't connected */
> +               return false;
>
>         case TRANS_DDI_MODE_SELECT_FDI:
>                 return (type == DRM_MODE_CONNECTOR_VGA);
> @@ -1152,6 +1192,9 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
>
>                         if ((tmp & TRANS_DDI_PORT_MASK)
>                             == TRANS_DDI_SELECT_PORT(port)) {
> +                               if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == TRANS_DDI_MODE_SELECT_DP_MST)
> +                                       return false;
> +
>                                 *pipe = i;
>                                 return true;
>                         }
> @@ -1478,10 +1521,15 @@ void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder)
>                         intel_wait_ddi_buf_idle(dev_priv, port);
>         }
>
> -       val = DP_TP_CTL_ENABLE | DP_TP_CTL_MODE_SST |
> +       val = DP_TP_CTL_ENABLE |
>               DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE;
> -       if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
> -               val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
> +       if (intel_dp->is_mst)
> +               val |= DP_TP_CTL_MODE_MST;
> +       else {
> +               val |= DP_TP_CTL_MODE_SST;
> +               if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
> +                       val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
> +       }
>         I915_WRITE(DP_TP_CTL(port), val);
>         POSTING_READ(DP_TP_CTL(port));
>
> @@ -1520,11 +1568,16 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc)
>
>  static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder)
>  {
> -       struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
> -       int type = intel_encoder->type;
> +       struct intel_digital_port *intel_dig_port = enc_to_dig_port(&intel_encoder->base);
> +       int type = intel_dig_port->base.type;
> +
> +       if (type != INTEL_OUTPUT_DISPLAYPORT &&
> +           type != INTEL_OUTPUT_EDP &&
> +           type != INTEL_OUTPUT_UNKNOWN) {
> +               return;
> +       }
>
> -       if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP)
> -               intel_dp_check_link_status(intel_dp);
> +       intel_dp_hot_plug(intel_encoder);
>  }
>
>  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 cef64b8..85db1c2 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -68,6 +68,14 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc);
>  static void intel_set_pipe_csc(struct drm_crtc *crtc);
>  static void vlv_prepare_pll(struct intel_crtc *crtc);
>
> +static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
> +{
> +       if (!connector->mst_port)
> +               return connector->encoder;
> +       else
> +               return &connector->mst_port->mst_encoders[pipe]->base;
> +}
> +
>  typedef struct {
>         int     min, max;
>  } intel_range_t;
> @@ -4105,6 +4113,9 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
>         if (intel_crtc->config.has_pch_encoder)
>                 lpt_pch_enable(crtc);
>
> +       if (intel_crtc->config.dp_encoder_is_mst)
> +               intel_ddi_set_vc_payload_alloc(crtc, true);
> +
>         for_each_encoder_on_crtc(dev, crtc, encoder) {
>                 encoder->enable(encoder);
>                 intel_opregion_notify_encoder(encoder, true);
> @@ -4155,6 +4166,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
>
>         intel_disable_pipe(dev_priv, pipe);
>
> +       if (intel_crtc->config.dp_encoder_is_mst)
> +               intel_ddi_set_vc_payload_alloc(crtc, false);
> +
>         ironlake_pfit_disable(intel_crtc);
>
>         for_each_encoder_on_crtc(dev, crtc, encoder)
> @@ -4316,6 +4330,9 @@ intel_display_port_power_domain(struct intel_encoder *intel_encoder)
>         case INTEL_OUTPUT_EDP:
>                 intel_dig_port = enc_to_dig_port(&intel_encoder->base);
>                 return port_to_power_domain(intel_dig_port->port);
> +       case INTEL_OUTPUT_DP_MST:
> +               intel_dig_port = enc_to_mst(&intel_encoder->base)->primary;
> +               return port_to_power_domain(intel_dig_port->port);
>         case INTEL_OUTPUT_ANALOG:
>                 return POWER_DOMAIN_PORT_CRT;
>         case INTEL_OUTPUT_DSI:
> @@ -4936,6 +4953,10 @@ static void intel_connector_check_state(struct intel_connector *connector)
>                               connector->base.base.id,
>                               connector->base.name);
>
> +               /* there is no real hw state for MST connectors */
> +               if (connector->mst_port)
> +                       return;
> +
>                 WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
>                      "wrong connector dpms state\n");
>                 WARN(connector->base.encoder != &encoder->base,
> @@ -10080,6 +10101,14 @@ check_encoder_state(struct drm_device *dev)
>                         if (connector->base.dpms != DRM_MODE_DPMS_OFF)
>                                 active = true;
>                 }
> +               /*
> +                * for MST connectors if we unplug the connector is gone
> +                * away but the encoder is still connected to a crtc
> +                * until a modeset happens in response to the hotplug.
> +                */
> +               if (!enabled && encoder->base.encoder_type == DRM_MODE_ENCODER_DPMST)
> +                       continue;
> +
>                 WARN(!!encoder->base.crtc != enabled,
>                      "encoder's enabled state mismatch "
>                      "(expected %i, found %i)\n",
> @@ -10617,7 +10646,7 @@ intel_modeset_stage_output_state(struct drm_device *dev,
>                  * for them. */
>                 for (ro = 0; ro < set->num_connectors; ro++) {
>                         if (set->connectors[ro] == &connector->base) {
> -                               connector->new_encoder = connector->encoder;
> +                               connector->new_encoder = intel_find_encoder(connector, to_intel_crtc(set->crtc)->pipe);
>                                 break;
>                         }
>                 }
> @@ -10663,7 +10692,7 @@ intel_modeset_stage_output_state(struct drm_device *dev,
>                                          new_crtc)) {
>                         return -EINVAL;
>                 }
> -               connector->encoder->new_crtc = to_intel_crtc(new_crtc);
> +               connector->new_encoder->new_crtc = to_intel_crtc(new_crtc);
>
>                 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
>                         connector->base.base.id,
> @@ -10697,7 +10726,12 @@ intel_modeset_stage_output_state(struct drm_device *dev,
>                 }
>         }
>         /* Now we've also updated encoder->new_crtc for all encoders. */
> -
> +       list_for_each_entry(connector, &dev->mode_config.connector_list,
> +                           base.head) {
> +               if (connector->new_encoder)
> +                       if (connector->new_encoder != connector->encoder)
> +                               connector->encoder = connector->new_encoder;
> +       }
>         for_each_intel_crtc(dev, crtc) {
>                 crtc->new_enabled = false;
>
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 4603e5f..c500f63 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);
>  static bool _edp_panel_vdd_on(struct intel_dp *intel_dp);
>  static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
>
> -static int
> +int
>  intel_dp_max_link_bw(struct intel_dp *intel_dp)
>  {
>         int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
> @@ -723,8 +723,9 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector)
>  {
>         struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base);
>
> -       sysfs_remove_link(&intel_connector->base.kdev->kobj,
> -                         intel_dp->aux.ddc.dev.kobj.name);
> +       if (!intel_connector->mst_port)
> +               sysfs_remove_link(&intel_connector->base.kdev->kobj,
> +                                 intel_dp->aux.ddc.dev.kobj.name);
>         intel_connector_unregister(intel_connector);
>  }
>
> @@ -3175,6 +3176,33 @@ intel_dp_probe_oui(struct intel_dp *intel_dp)
>         edp_panel_vdd_off(intel_dp, false);
>  }
>
> +static bool
> +intel_dp_probe_mst(struct intel_dp *intel_dp)
> +{
> +       u8 buf[1];
> +
> +       if (!intel_dp->can_mst)
> +               return false;
> +
> +       if (intel_dp->dpcd[DP_DPCD_REV] < 0x12)
> +               return false;
> +
> +       _edp_panel_vdd_on(intel_dp);
> +       if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_MSTM_CAP, buf, 1)) {
> +               if (buf[0] & DP_MST_CAP) {
> +                       DRM_DEBUG_KMS("Sink is MST capable\n");
> +                       intel_dp->is_mst = true;
> +               } else {
> +                       DRM_DEBUG_KMS("Sink is not MST capable\n");
> +                       intel_dp->is_mst = false;
> +               }
> +       }
> +       edp_panel_vdd_off(intel_dp, false);
> +
> +       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
> +       return intel_dp->is_mst;
> +}
> +
>  int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
>  {
>         struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> @@ -3212,6 +3240,20 @@ intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector)
>                                        sink_irq_vector, 1) == 1;
>  }
>
> +static bool
> +intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *sink_irq_vector)
> +{
> +       int ret;
> +
> +       ret = intel_dp_dpcd_read_wake(&intel_dp->aux,
> +                                            DP_SINK_COUNT_ESI,
> +                                            sink_irq_vector, 14);
> +       if (ret != 14)
> +               return false;
> +
> +       return true;
> +}
> +
>  static void
>  intel_dp_handle_test_request(struct intel_dp *intel_dp)
>  {
> @@ -3219,6 +3261,63 @@ intel_dp_handle_test_request(struct intel_dp *intel_dp)
>         drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, DP_TEST_NAK);
>  }
>
> +static int
> +intel_dp_check_mst_status(struct intel_dp *intel_dp)
> +{
> +       bool bret;
> +
> +       if (intel_dp->is_mst) {
> +               u8 esi[16] = { 0 };
> +               int ret = 0;
> +               int retry;
> +               bool handled;
> +               bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
> +       go_again:
> +               if (bret == true) {
> +
> +                       /* check link status - esi[10] = 0x200c */
> +                       if (intel_dp->active_mst_links && !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) {
> +                               DRM_DEBUG_KMS("channel EQ not ok, retraining\n");
> +                               intel_dp_start_link_train(intel_dp);
> +                               intel_dp_complete_link_train(intel_dp);
> +                               intel_dp_stop_link_train(intel_dp);
> +                       }
> +
> +                       DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]);
> +                       ret = drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled);
> +
> +                       if (handled) {
> +                               for (retry = 0; retry < 3; retry++) {
> +                                       int wret;
> +                                       wret = drm_dp_dpcd_write(&intel_dp->aux,
> +                                                                DP_SINK_COUNT_ESI+1,
> +                                                                &esi[1], 3);
> +                                       if (wret == 3) {
> +                                               break;
> +                                       }
> +                               }
> +
> +                               bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
> +                               if (bret == true) {
> +                                       DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]);
> +                                       goto go_again;
> +                               }
> +                       } else
> +                               ret = 0;
> +
> +                       return ret;
> +               } else {
> +                       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +                       DRM_DEBUG_KMS("failed to get ESI - device may have failed\n");
> +                       intel_dp->is_mst = false;
> +                       drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
> +                       /* send a hotplug event */
> +                       drm_kms_helper_hotplug_event(intel_dig_port->base.base.dev);
> +               }
> +       }
> +       return -EINVAL;
> +}
> +
>  /*
>   * According to DP spec
>   * 5.1.2:
> @@ -3227,7 +3326,6 @@ intel_dp_handle_test_request(struct intel_dp *intel_dp)
>   *  3. Use Link Training from 2.5.3.3 and 3.5.1.3
>   *  4. Check link status on receipt of hot-plug interrupt
>   */
> -
>  void
>  intel_dp_check_link_status(struct intel_dp *intel_dp)
>  {
> @@ -3447,6 +3545,7 @@ intel_dp_detect(struct drm_connector *connector, bool force)
>         enum drm_connector_status status;
>         enum intel_display_power_domain power_domain;
>         struct edid *edid = NULL;
> +       bool ret;
>
>         intel_runtime_pm_get(dev_priv);
>
> @@ -3456,6 +3555,14 @@ intel_dp_detect(struct drm_connector *connector, bool force)
>         DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
>                       connector->base.id, connector->name);
>
> +       if (intel_dp->is_mst) {
> +               /* MST devices are disconnected from a monitor POV */
> +               if (intel_encoder->type != INTEL_OUTPUT_EDP)
> +                       intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
> +               status = connector_status_disconnected;
> +               goto out;
> +       }
> +
>         intel_dp->has_audio = false;
>
>         if (HAS_PCH_SPLIT(dev))
> @@ -3468,6 +3575,16 @@ intel_dp_detect(struct drm_connector *connector, bool force)
>
>         intel_dp_probe_oui(intel_dp);
>
> +       ret = intel_dp_probe_mst(intel_dp);
> +       if (ret) {
> +               /* if we are in MST mode then this connector
> +                  won't appear connected or have anything with EDID on it */
> +               if (intel_encoder->type != INTEL_OUTPUT_EDP)
> +                       intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
> +               status = connector_status_disconnected;
> +               goto out;
> +       }
> +
>         if (intel_dp->force_audio != HDMI_AUDIO_AUTO) {
>                 intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON);
>         } else {
> @@ -3663,6 +3780,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
>         struct drm_device *dev = intel_dp_to_dev(intel_dp);
>
>         drm_dp_aux_unregister(&intel_dp->aux);
> +       intel_dp_mst_encoder_cleanup(intel_dig_port);
>         drm_encoder_cleanup(encoder);
>         if (is_edp(intel_dp)) {
>                 cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
> @@ -3691,28 +3809,62 @@ static const struct drm_encoder_funcs intel_dp_enc_funcs = {
>         .destroy = intel_dp_encoder_destroy,
>  };
>
> -static void
> +void
>  intel_dp_hot_plug(struct intel_encoder *intel_encoder)
>  {
> -       struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
> -
> -       intel_dp_check_link_status(intel_dp);
> +       return;
>  }
>
>  bool
>  intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
>  {
>         struct intel_dp *intel_dp = &intel_dig_port->dp;
> +       struct drm_device *dev = intel_dig_port->base.base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       int ret;
> +       if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
> +               intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
>
> -       if (long_hpd)
> -               return true;
> +       DRM_DEBUG_KMS("got hpd irq on port %d - %s\n", intel_dig_port->port,
> +                     long_hpd ? "long" : "short");
>
> -       /*
> -        * we'll check the link status via the normal hot plug path later -
> -        * but for short hpds we should check it now
> -        */
> -       intel_dp_check_link_status(intel_dp);
> +       if (long_hpd) {
> +               if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
> +                       goto mst_fail;
> +
> +               if (!intel_dp_get_dpcd(intel_dp)) {
> +                       goto mst_fail;
> +               }
> +
> +               intel_dp_probe_oui(intel_dp);
> +
> +               if (!intel_dp_probe_mst(intel_dp))
> +                       goto mst_fail;
> +
> +       } else {
> +               if (intel_dp->is_mst) {
> +                       ret = intel_dp_check_mst_status(intel_dp);
> +                       if (ret == -EINVAL)
> +                               goto mst_fail;
> +               }
> +
> +               if (!intel_dp->is_mst) {
> +                       /*
> +                        * we'll check the link status via the normal hot plug path later -
> +                        * but for short hpds we should check it now
> +                        */
> +                       intel_dp_check_link_status(intel_dp);
> +               }
> +       }
>         return false;
> +mst_fail:
> +       /* if we were in MST mode, and device is not there get out of MST mode */
> +       if (intel_dp->is_mst) {
> +               DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n", intel_dp->is_mst, intel_dp->mst_mgr.mst_state);
> +               intel_dp->is_mst = false;
> +               drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
> +       }
> +       return true;
>  }
>
>  /* Return which DP Port should be selected for Transcoder DP control */
> @@ -3763,7 +3915,7 @@ bool intel_dp_is_edp(struct drm_device *dev, enum port port)
>         return false;
>  }
>
> -static void
> +void
>  intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
>  {
>         struct intel_connector *intel_connector = to_intel_connector(connector);
> @@ -4259,6 +4411,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>
>         intel_dp->psr_setup_done = false;
>
> +       /* init MST on ports that can support it */
> +       if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
> +               if (port == PORT_B || port == PORT_C || port == PORT_D) {
> +                       intel_dp_mst_encoder_init(intel_dig_port, intel_connector->base.base.id);
> +               }
> +       }
> +
>         if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) {
>                 drm_dp_aux_unregister(&intel_dp->aux);
>                 if (is_edp(intel_dp)) {
> @@ -4356,3 +4515,46 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
>                 kfree(intel_connector);
>         }
>  }
> +
> +void intel_dp_mst_suspend(struct drm_device *dev)
> +{
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       int i;
> +
> +       /* disable MST */
> +       for (i = 0; i < I915_MAX_PORTS; i++) {
> +               struct intel_digital_port *intel_dig_port = dev_priv->hpd_irq_port[i];
> +               if (!intel_dig_port)
> +                       continue;
> +
> +               if (intel_dig_port->base.type == INTEL_OUTPUT_DISPLAYPORT) {
> +                       if (!intel_dig_port->dp.can_mst)
> +                               continue;
> +                       if (intel_dig_port->dp.is_mst)
> +                               drm_dp_mst_topology_mgr_suspend(&intel_dig_port->dp.mst_mgr);
> +               }
> +       }
> +}
> +
> +void intel_dp_mst_resume(struct drm_device *dev)
> +{
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       int i;
> +
> +       for (i = 0; i < I915_MAX_PORTS; i++) {
> +               struct intel_digital_port *intel_dig_port = dev_priv->hpd_irq_port[i];
> +               if (!intel_dig_port)
> +                       continue;
> +               if (intel_dig_port->base.type == INTEL_OUTPUT_DISPLAYPORT) {
> +                       int ret;
> +
> +                       if (!intel_dig_port->dp.can_mst)
> +                               continue;
> +
> +                       ret = drm_dp_mst_topology_mgr_resume(&intel_dig_port->dp.mst_mgr);
> +                       if (ret != 0) {
> +                               intel_dp_check_mst_status(&intel_dig_port->dp);
> +                       }
> +               }
> +       }
> +}
> 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 0000000..a7db741
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> @@ -0,0 +1,535 @@
> +/*
> + * Copyright © 2008 Intel Corporation
> + *             2014 Red Hat Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#include <drm/drmP.h>
> +#include "i915_drv.h"
> +#include "intel_drv.h"
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_edid.h>
> +
> +bool
> +intel_dp_mst_compute_config(struct intel_encoder *encoder,
> +                           struct intel_crtc_config *pipe_config)
> +{
> +       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
> +       struct intel_digital_port *intel_dig_port = intel_mst->primary;
> +       struct intel_dp *intel_dp = &intel_dig_port->dp;
> +       struct drm_device *dev = encoder->base.dev;
> +       int bpp;
> +       int lane_count, slots;
> +       struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
> +       struct intel_connector *found = NULL, *intel_connector;
> +       int mst_pbn;
> +
> +       pipe_config->dp_encoder_is_mst = true;
> +       pipe_config->has_pch_encoder = false;
> +       pipe_config->has_dp_encoder = true;
> +       bpp = 24;
> +       /*
> +        * for MST we always configure max link bw - the spec doesn't
> +        * seem to suggest we should do otherwise.
> +        */
> +       lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
> +       intel_dp->link_bw = intel_dp_max_link_bw(intel_dp);
> +       intel_dp->lane_count = lane_count;
> +
> +       pipe_config->pipe_bpp = 24;
> +       pipe_config->port_clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
> +
> +       list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head) {
> +               if (intel_connector->new_encoder == encoder) {
> +                       found = intel_connector;
> +                       break;
> +               }
> +       }
> +
> +       if (!found) {
> +               DRM_ERROR("can't find connector\n");
> +               return false;
> +       }
> +
> +       mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp);
> +
> +       pipe_config->pbn = mst_pbn;
> +       slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, mst_pbn);
> +
> +       intel_link_compute_m_n(bpp, lane_count,
> +                              adjusted_mode->crtc_clock,
> +                              pipe_config->port_clock,
> +                              &pipe_config->dp_m_n);
> +
> +       pipe_config->dp_m_n.tu = slots;
> +       return true;
> +
> +}
> +
> +static void intel_mst_disable_dp(struct intel_encoder *encoder)
> +{
> +       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
> +       struct intel_digital_port *intel_dig_port = intel_mst->primary;
> +       struct intel_dp *intel_dp = &intel_dig_port->dp;
> +       int ret;
> +
> +       DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
> +
> +       drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, intel_mst->port);
> +
> +       ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
> +       if (ret) {
> +               DRM_ERROR("failed to update payload %d\n", ret);
> +       }
> +}
> +
> +static void intel_mst_post_disable_dp(struct intel_encoder *encoder)
> +{
> +       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
> +       struct intel_digital_port *intel_dig_port = intel_mst->primary;
> +       struct intel_dp *intel_dp = &intel_dig_port->dp;
> +
> +       DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
> +
> +       /* this can fail */
> +       drm_dp_check_act_status(&intel_dp->mst_mgr);
> +       /* and this can also fail */
> +       drm_dp_update_payload_part2(&intel_dp->mst_mgr);
> +
> +       drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, intel_mst->port);
> +
> +       intel_dp->active_mst_links--;
> +       intel_mst->port = NULL;
> +       if (intel_dp->active_mst_links == 0) {
> +               intel_dig_port->base.post_disable(&intel_dig_port->base);
> +               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
> +       }
> +}
> +
> +static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
> +{
> +       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
> +       struct intel_digital_port *intel_dig_port = intel_mst->primary;
> +       struct intel_dp *intel_dp = &intel_dig_port->dp;
> +       struct drm_device *dev = encoder->base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       enum port port = intel_dig_port->port;
> +       int ret;
> +       uint32_t temp;
> +       struct intel_connector *found = NULL, *intel_connector;
> +       int slots;
> +       struct drm_crtc *crtc = encoder->base.crtc;
> +       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +
> +       list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head) {
> +               if (intel_connector->new_encoder == encoder) {
> +                       found = intel_connector;
> +                       break;
> +               }
> +       }
> +
> +       if (!found) {
> +               DRM_ERROR("can't find connector\n");
> +               return;
> +       }
> +
> +       DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
> +       intel_mst->port = found->port;
> +
> +       if (intel_dp->active_mst_links == 0) {
> +               enum port port = intel_ddi_get_encoder_port(encoder);
> +
> +               I915_WRITE(PORT_CLK_SEL(port), intel_crtc->ddi_pll_sel);
> +
> +               intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
> +
> +               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> +
> +
> +               intel_dp_start_link_train(intel_dp);
> +               intel_dp_complete_link_train(intel_dp);
> +               intel_dp_stop_link_train(intel_dp);
> +       }
> +
> +       ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
> +                                      intel_mst->port, intel_crtc->config.pbn, &slots);
> +       if (ret == false) {
> +               DRM_ERROR("failed to allocate vcpi\n");
> +               return;
> +       }
> +
> +
> +       intel_dp->active_mst_links++;
> +       temp = I915_READ(DP_TP_STATUS(port));
> +       I915_WRITE(DP_TP_STATUS(port), temp);
> +
> +       ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
> +}
> +
> +static void intel_mst_enable_dp(struct intel_encoder *encoder)
> +{
> +       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
> +       struct intel_digital_port *intel_dig_port = intel_mst->primary;
> +       struct intel_dp *intel_dp = &intel_dig_port->dp;
> +       struct drm_device *dev = intel_dig_port->base.base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       enum port port = intel_dig_port->port;
> +       int ret;
> +
> +       DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
> +
> +       if (wait_for((I915_READ(DP_TP_STATUS(port)) & DP_TP_STATUS_ACT_SENT),
> +                    1))
> +               DRM_ERROR("Timed out waiting for ACT sent\n");
> +
> +       ret = drm_dp_check_act_status(&intel_dp->mst_mgr);
> +
> +       ret = drm_dp_update_payload_part2(&intel_dp->mst_mgr);
> +}
> +
> +static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
> +                                     enum pipe *pipe)
> +{
> +       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
> +       *pipe = intel_mst->pipe;
> +       if (intel_mst->port)
> +               return true;
> +       return false;
> +}
> +
> +static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
> +                                       struct intel_crtc_config *pipe_config)
> +{
> +       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
> +       struct intel_digital_port *intel_dig_port = intel_mst->primary;
> +       struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
> +       struct drm_device *dev = encoder->base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
> +       u32 temp, flags = 0;
> +
> +       pipe_config->has_dp_encoder = true;
> +
> +       temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
> +       if (temp & TRANS_DDI_PHSYNC)
> +               flags |= DRM_MODE_FLAG_PHSYNC;
> +       else
> +               flags |= DRM_MODE_FLAG_NHSYNC;
> +       if (temp & TRANS_DDI_PVSYNC)
> +               flags |= DRM_MODE_FLAG_PVSYNC;
> +       else
> +               flags |= DRM_MODE_FLAG_NVSYNC;
> +
> +       switch (temp & TRANS_DDI_BPC_MASK) {
> +       case TRANS_DDI_BPC_6:
> +               pipe_config->pipe_bpp = 18;
> +               break;
> +       case TRANS_DDI_BPC_8:
> +               pipe_config->pipe_bpp = 24;
> +               break;
> +       case TRANS_DDI_BPC_10:
> +               pipe_config->pipe_bpp = 30;
> +               break;
> +       case TRANS_DDI_BPC_12:
> +               pipe_config->pipe_bpp = 36;
> +               break;
> +       default:
> +               break;
> +       }
> +       pipe_config->adjusted_mode.flags |= flags;
> +       intel_dp_get_m_n(crtc, pipe_config);
> +
> +       intel_ddi_clock_get(&intel_dig_port->base, pipe_config);
> +}
> +
> +static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
> +{
> +       struct intel_connector *intel_connector = to_intel_connector(connector);
> +       struct intel_dp *intel_dp = intel_connector->mst_port;
> +       struct edid *edid;
> +       int ret;
> +
> +       edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port);
> +       if (!edid)
> +               return 0;
> +
> +       ret = intel_connector_update_modes(connector, edid);
> +       kfree(edid);
> +
> +       return ret;
> +}
> +
> +static enum drm_connector_status
> +intel_mst_port_dp_detect(struct drm_connector *connector)
> +{
> +       struct intel_connector *intel_connector = to_intel_connector(connector);
> +       struct intel_dp *intel_dp = intel_connector->mst_port;
> +
> +       return drm_dp_mst_detect_port(&intel_dp->mst_mgr, intel_connector->port);
> +}
> +
> +static enum drm_connector_status
> +intel_dp_mst_detect(struct drm_connector *connector, bool force)
> +{
> +       enum drm_connector_status status;
> +       status = intel_mst_port_dp_detect(connector);
> +       return status;
> +}
> +
> +static int
> +intel_dp_mst_set_property(struct drm_connector *connector,
> +                         struct drm_property *property,
> +                         uint64_t val)
> +{
> +       return 0;
> +}
> +
> +static void
> +intel_dp_mst_connector_destroy(struct drm_connector *connector)
> +{
> +       struct intel_connector *intel_connector = to_intel_connector(connector);
> +
> +       if (!IS_ERR_OR_NULL(intel_connector->edid))
> +               kfree(intel_connector->edid);
> +
> +       drm_connector_cleanup(connector);
> +       kfree(connector);
> +}
> +
> +static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
> +       .dpms = intel_connector_dpms,
> +       .detect = intel_dp_mst_detect,
> +       .fill_modes = drm_helper_probe_single_connector_modes,
> +       .set_property = intel_dp_mst_set_property,
> +       .destroy = intel_dp_mst_connector_destroy,
> +};
> +
> +static int intel_dp_mst_get_modes(struct drm_connector *connector)
> +{
> +       return intel_dp_mst_get_ddc_modes(connector);
> +}
> +
> +static enum drm_mode_status
> +intel_dp_mst_mode_valid(struct drm_connector *connector,
> +                       struct drm_display_mode *mode)
> +{
> +       /* TODO - validate mode against available PBN for link */
> +       if (mode->clock < 10000)
> +               return MODE_CLOCK_LOW;
> +
> +       if (mode->flags & DRM_MODE_FLAG_DBLCLK)
> +               return MODE_H_ILLEGAL;
> +
> +       return MODE_OK;
> +}
> +
> +struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connector)
> +{
> +       struct intel_connector *intel_connector = to_intel_connector(connector);
> +       struct intel_dp *intel_dp = intel_connector->mst_port;
> +       return &intel_dp->mst_encoders[0]->base.base;
> +}
> +
> +static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = {
> +       .get_modes = intel_dp_mst_get_modes,
> +       .mode_valid = intel_dp_mst_mode_valid,
> +       .best_encoder = intel_mst_best_encoder,
> +};
> +
> +void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder)
> +{
> +       struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
> +
> +       drm_encoder_cleanup(encoder);
> +       kfree(intel_mst);
> +}
> +
> +static const struct drm_encoder_funcs intel_dp_mst_enc_funcs = {
> +       .destroy = intel_dp_mst_encoder_destroy,
> +};
> +
> +static bool intel_dp_mst_get_hw_state(struct intel_connector *connector)
> +{
> +       if (connector->encoder) {
> +               enum pipe pipe;
> +               if (!connector->encoder->get_hw_state(connector->encoder, &pipe))
> +                       return false;
> +               return true;
> +       }
> +       return false;
> +}
> +
> +static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, char *pathprop)
> +{
> +       struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr);
> +       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +       struct drm_device *dev = intel_dig_port->base.base.dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       struct intel_connector *intel_connector;
> +       struct drm_connector *connector;
> +       int i;
> +
> +       intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL);
> +       if (!intel_connector)
> +               return NULL;
> +
> +       connector = &intel_connector->base;
> +       drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort);
> +       drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs);
> +
> +       intel_connector->unregister = intel_connector_unregister;
> +       intel_connector->get_hw_state = intel_dp_mst_get_hw_state;
> +       intel_connector->mst_port = intel_dp;
> +       intel_connector->port = port;
> +
> +       for (i = PIPE_A; i <= PIPE_C; i++) {
> +               drm_mode_connector_attach_encoder(&intel_connector->base,
> +                                                 &intel_dp->mst_encoders[i]->base.base);
> +       }
> +       intel_dp_add_properties(intel_dp, connector);
> +
> +       drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
> +       drm_mode_connector_set_path_property(connector, pathprop);
> +       drm_reinit_primary_mode_group(dev);
> +       mutex_lock(&dev->mode_config.mutex);
> +       drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, connector);
> +       mutex_unlock(&dev->mode_config.mutex);
> +       drm_sysfs_connector_add(&intel_connector->base);
> +       return connector;
> +}
> +
> +static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
> +                                          struct drm_connector *connector)
> +{
> +       struct intel_connector *intel_connector = to_intel_connector(connector);
> +       struct drm_device *dev = connector->dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
> +       /* need to nuke the connector */
> +       mutex_lock(&dev->mode_config.mutex);
> +       intel_connector_dpms(connector, DRM_MODE_DPMS_OFF);
> +       mutex_unlock(&dev->mode_config.mutex);
> +
> +       intel_connector->unregister(intel_connector);
> +
> +       mutex_lock(&dev->mode_config.mutex);
> +       drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, connector);
> +       drm_connector_cleanup(connector);
> +       mutex_unlock(&dev->mode_config.mutex);
> +
> +       drm_reinit_primary_mode_group(dev);
> +
> +       kfree(intel_connector);
> +       DRM_DEBUG_KMS("\n");
> +}
> +
> +static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
> +{
> +       struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr);
> +       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +       struct drm_device *dev = intel_dig_port->base.base.dev;
> +
> +       drm_kms_helper_hotplug_event(dev);
> +}
> +
> +struct drm_dp_mst_topology_cbs mst_cbs = {
> +       .add_connector = intel_dp_add_mst_connector,
> +       .destroy_connector = intel_dp_destroy_mst_connector,
> +       .hotplug = intel_dp_mst_hotplug,
> +};
> +
> +static struct intel_dp_mst_encoder *
> +intel_dp_create_fake_mst_encoder(struct intel_digital_port *intel_dig_port, enum pipe pipe)
> +{
> +       struct intel_dp_mst_encoder *intel_mst;
> +       struct intel_encoder *intel_encoder;
> +       struct drm_device *dev = intel_dig_port->base.base.dev;
> +
> +       intel_mst = kzalloc(sizeof(*intel_mst), GFP_KERNEL);
> +
> +       if (!intel_mst)
> +               return NULL;
> +
> +       intel_mst->pipe = pipe;
> +       intel_encoder = &intel_mst->base;
> +       intel_mst->primary = intel_dig_port;
> +
> +       drm_encoder_init(dev, &intel_encoder->base, &intel_dp_mst_enc_funcs,
> +                        DRM_MODE_ENCODER_DPMST);
> +
> +       intel_encoder->type = INTEL_OUTPUT_DP_MST;
> +       intel_encoder->crtc_mask = 0x7;
> +       intel_encoder->cloneable = 0;
> +
> +       intel_encoder->compute_config = intel_dp_mst_compute_config;
> +       intel_encoder->disable = intel_mst_disable_dp;
> +       intel_encoder->post_disable = intel_mst_post_disable_dp;
> +       intel_encoder->pre_enable = intel_mst_pre_enable_dp;
> +       intel_encoder->enable = intel_mst_enable_dp;
> +       intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state;
> +       intel_encoder->get_config = intel_dp_mst_enc_get_config;
> +
> +       return intel_mst;
> +
> +}
> +
> +static bool
> +intel_dp_create_fake_mst_encoders(struct intel_digital_port *intel_dig_port)
> +{
> +       int i;
> +       struct intel_dp *intel_dp = &intel_dig_port->dp;
> +
> +       for (i = PIPE_A; i <= PIPE_C; i++)
> +               intel_dp->mst_encoders[i] = intel_dp_create_fake_mst_encoder(intel_dig_port, i);
> +       return true;
> +}
> +
> +int
> +intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_base_id)
> +{
> +       struct intel_dp *intel_dp = &intel_dig_port->dp;
> +       struct drm_device *dev = intel_dig_port->base.base.dev;
> +       int ret;
> +
> +       intel_dp->can_mst = true;
> +       intel_dp->mst_mgr.cbs = &mst_cbs;
> +
> +       /* create encoders */
> +       intel_dp_create_fake_mst_encoders(intel_dig_port);
> +       ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev->dev, &intel_dp->aux, 16, 3, conn_base_id);
> +       if (ret) {
> +               intel_dp->can_mst = false;
> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +void
> +intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port)
> +{
> +       struct intel_dp *intel_dp = &intel_dig_port->dp;
> +
> +       if (!intel_dp->can_mst)
> +               return;
> +
> +       drm_dp_mst_topology_mgr_destroy(&intel_dp->mst_mgr);
> +       /* encoders will get killed by normal cleanup */
> +}
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index da6c440..1edb38a 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -32,7 +32,7 @@
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_fb_helper.h>
> -#include <drm/drm_dp_helper.h>
> +#include <drm/drm_dp_mst_helper.h>
>
>  /**
>   * _wait_for - magic (register) wait macro
> @@ -100,6 +100,7 @@
>  #define INTEL_OUTPUT_EDP 8
>  #define INTEL_OUTPUT_DSI 9
>  #define INTEL_OUTPUT_UNKNOWN 10
> +#define INTEL_OUTPUT_DP_MST 11
>
>  #define INTEL_DVO_CHIP_NONE 0
>  #define INTEL_DVO_CHIP_LVDS 1
> @@ -207,6 +208,10 @@ struct intel_connector {
>         /* since POLL and HPD connectors may use the same HPD line keep the native
>            state of connector->polled in case hotplug storm detection changes it */
>         u8 polled;
> +
> +       void *port; /* store this opaque as its illegal to dereference it */
> +
> +       struct intel_dp *mst_port;
>  };
>
>  typedef struct dpll {
> @@ -347,6 +352,9 @@ struct intel_crtc_config {
>         bool ips_enabled;
>
>         bool double_wide;
> +
> +       bool dp_encoder_is_mst;
> +       int pbn;
>  };
>
>  struct intel_pipe_wm {
> @@ -498,6 +506,7 @@ struct intel_hdmi {
>                                struct drm_display_mode *adjusted_mode);
>  };
>
> +struct intel_dp_mst_encoder;
>  #define DP_MAX_DOWNSTREAM_PORTS                0x10
>
>  /**
> @@ -538,8 +547,17 @@ struct intel_dp {
>         unsigned long last_backlight_off;
>         bool psr_setup_done;
>         bool use_tps3;
> +       bool can_mst; /* this port supports mst */
> +       bool is_mst;
> +       int active_mst_links;
> +       /* connector directly attached - won't be use for modeset in mst world */
>         struct intel_connector *attached_connector;
>
> +       /* mst connector list */
> +       struct intel_connector *mst_connectors;
> +       struct intel_dp_mst_encoder *mst_encoders[I915_MAX_PIPES];
> +       struct drm_dp_mst_topology_mgr mst_mgr;
> +
>         uint32_t (*get_aux_clock_divider)(struct intel_dp *dp, int index);
>         /*
>          * This function returns the value we have to program the AUX_CTL
> @@ -566,6 +584,13 @@ struct intel_digital_port {
>         bool (*hpd_pulse)(struct intel_digital_port *, bool);
>  };
>
> +struct intel_dp_mst_encoder {
> +       struct intel_encoder base;
> +       enum pipe pipe;
> +       struct intel_digital_port *primary;
> +       void *port; /* store this opaque as its illegal to dereference it */
> +};
> +
>  static inline int
>  vlv_dport_to_channel(struct intel_digital_port *dport)
>  {
> @@ -650,6 +675,12 @@ enc_to_dig_port(struct drm_encoder *encoder)
>         return container_of(encoder, struct intel_digital_port, base.base);
>  }
>
> +static inline struct intel_dp_mst_encoder *
> +enc_to_mst(struct drm_encoder *encoder)
> +{
> +       return container_of(encoder, struct intel_dp_mst_encoder, base.base);
> +}
> +
>  static inline struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
>  {
>         return &enc_to_dig_port(encoder)->dp;
> @@ -715,6 +746,9 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
>                           struct intel_crtc_config *pipe_config);
>
>  void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder);
> +void intel_ddi_clock_get(struct intel_encoder *encoder,
> +                        struct intel_crtc_config *pipe_config);
> +void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
>
>  /* intel_display.c */
>  const char *intel_output_name(int output);
> @@ -834,6 +868,15 @@ void intel_edp_psr_update(struct drm_device *dev);
>  void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate);
>  bool intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd);
>
> +int intel_dp_handle_hpd_irq(struct intel_digital_port *digport, bool long_hpd);
> +void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector);
> +void intel_dp_mst_suspend(struct drm_device *dev);
> +void intel_dp_mst_resume(struct drm_device *dev);
> +int intel_dp_max_link_bw(struct intel_dp *intel_dp);
> +void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
> +/* intel_dp_mst.c */
> +int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
> +void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);
>  /* intel_dsi.c */
>  bool intel_dsi_init(struct drm_device *dev);
>
> diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
> index e2d4161..1949350 100644
> --- a/drivers/gpu/drm/i915/intel_fbdev.c
> +++ b/drivers/gpu/drm/i915/intel_fbdev.c
> @@ -349,6 +349,11 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
>                 }
>
>                 encoder = connector->encoder;
> +               if (!encoder) {
> +                       struct drm_connector_helper_funcs *connector_funcs;
> +                       connector_funcs = connector->helper_private;
> +                       encoder = connector_funcs->best_encoder(connector);
> +               }
>                 if (!encoder || WARN_ON(!encoder->crtc)) {
>                         DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
>                                       connector->name);
> diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
> index b812e9d..27d4570 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,
>         case INTEL_OUTPUT_UNKNOWN:
>         case INTEL_OUTPUT_DISPLAYPORT:
>         case INTEL_OUTPUT_HDMI:
> +       case INTEL_OUTPUT_DP_MST:
>                 type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL;
>                 break;
>         case INTEL_OUTPUT_EDP:
> --
> 1.9.3
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Dave Airlie July 23, 2014, 4:32 a.m. UTC | #2
On 23 July 2014 06:02, Paulo Zanoni <przanoni@gmail.com> wrote:
> 2014-06-05 1:01 GMT-03:00 Dave Airlie <airlied@gmail.com>:
>> From: Dave Airlie <airlied@redhat.com>
>>
>> This adds DP 1.2 MST support on Haswell systems.
>
> Hi
>
> It looks like drm-intel-nightly now includes this patch. It actually
> includes v7, but I couldn't find it on my mail dirs.
>
> Just by booting the machine with this patch, I get:
>

There are two patches in my drm-i915-next branch

They should remove the offending bits for the fbdev and powersave warning.

Dave.
Daniel Vetter July 29, 2014, 10:46 a.m. UTC | #3
On Wed, Jul 23, 2014 at 6:32 AM, Dave Airlie <airlied@gmail.com> wrote:
> On 23 July 2014 06:02, Paulo Zanoni <przanoni@gmail.com> wrote:
>> 2014-06-05 1:01 GMT-03:00 Dave Airlie <airlied@gmail.com>:
>>> From: Dave Airlie <airlied@redhat.com>
>>>
>>> This adds DP 1.2 MST support on Haswell systems.
>>
>> Hi
>>
>> It looks like drm-intel-nightly now includes this patch. It actually
>> includes v7, but I couldn't find it on my mail dirs.
>>
>> Just by booting the machine with this patch, I get:
>>
>
> There are two patches in my drm-i915-next branch
>
> They should remove the offending bits for the fbdev and powersave warning.

Paulo, can you please test these two patches?
-Daniel
Dave Airlie July 29, 2014, 10:50 a.m. UTC | #4
On 29 July 2014 20:46, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Wed, Jul 23, 2014 at 6:32 AM, Dave Airlie <airlied@gmail.com> wrote:
>> On 23 July 2014 06:02, Paulo Zanoni <przanoni@gmail.com> wrote:
>>> 2014-06-05 1:01 GMT-03:00 Dave Airlie <airlied@gmail.com>:
>>>> From: Dave Airlie <airlied@redhat.com>
>>>>
>>>> This adds DP 1.2 MST support on Haswell systems.
>>>
>>> Hi
>>>
>>> It looks like drm-intel-nightly now includes this patch. It actually
>>> includes v7, but I couldn't find it on my mail dirs.
>>>
>>> Just by booting the machine with this patch, I get:
>>>
>>
>> There are two patches in my drm-i915-next branch
>>
>> They should remove the offending bits for the fbdev and powersave warning.
>
> Paulo, can you please test these two patches?
>
Oh he did already, didn't I push them? I must have forgotten.

Dave.
Daniel Vetter July 29, 2014, 11 a.m. UTC | #5
On Tue, Jul 29, 2014 at 12:50 PM, Dave Airlie <airlied@gmail.com> wrote:
> On 29 July 2014 20:46, Daniel Vetter <daniel@ffwll.ch> wrote:
>> On Wed, Jul 23, 2014 at 6:32 AM, Dave Airlie <airlied@gmail.com> wrote:
>>> On 23 July 2014 06:02, Paulo Zanoni <przanoni@gmail.com> wrote:
>>>> 2014-06-05 1:01 GMT-03:00 Dave Airlie <airlied@gmail.com>:
>>>>> From: Dave Airlie <airlied@redhat.com>
>>>>>
>>>>> This adds DP 1.2 MST support on Haswell systems.
>>>>
>>>> Hi
>>>>
>>>> It looks like drm-intel-nightly now includes this patch. It actually
>>>> includes v7, but I couldn't find it on my mail dirs.
>>>>
>>>> Just by booting the machine with this patch, I get:
>>>>
>>>
>>> There are two patches in my drm-i915-next branch
>>>
>>> They should remove the offending bits for the fbdev and powersave warning.
>>
>> Paulo, can you please test these two patches?
>>
> Oh he did already, didn't I push them? I must have forgotten.

Oh, I guess I've missed that since it didn't go over the m-l ;-) It's
there already.
-Daniel
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 7b2f3be..03b7525 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -59,6 +59,7 @@  i915-y += dvo_ch7017.o \
 	  intel_crt.o \
 	  intel_ddi.o \
 	  intel_dp.o \
+	  intel_dp_mst.o \
 	  intel_dsi_cmd.o \
 	  intel_dsi.o \
 	  intel_dsi_pll.o \
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 4e70de6..3bf2f1f 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1676,6 +1676,13 @@  int i915_driver_load(struct drm_device *dev, unsigned long flags)
 		goto out_mtrrfree;
 	}
 
+	dev_priv->dp_wq = alloc_ordered_workqueue("i915-dp", 0);
+	if (dev_priv->dp_wq == NULL) {
+		DRM_ERROR("Failed to create our dp workqueue.\n");
+		ret = -ENOMEM;
+		goto out_freewq;
+	}
+
 	intel_irq_init(dev);
 	intel_uncore_sanitize(dev);
 
@@ -1751,6 +1758,8 @@  out_gem_unload:
 	intel_teardown_gmbus(dev);
 	intel_teardown_mchbar(dev);
 	pm_qos_remove_request(&dev_priv->pm_qos);
+	destroy_workqueue(dev_priv->dp_wq);
+out_freewq:
 	destroy_workqueue(dev_priv->wq);
 out_mtrrfree:
 	arch_phys_wc_del(dev_priv->gtt.mtrr);
@@ -1855,6 +1864,7 @@  int i915_driver_unload(struct drm_device *dev)
 	intel_teardown_gmbus(dev);
 	intel_teardown_mchbar(dev);
 
+	destroy_workqueue(dev_priv->dp_wq);
 	destroy_workqueue(dev_priv->wq);
 	pm_qos_remove_request(&dev_priv->pm_qos);
 
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 5b5b82c..051cf97 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -524,7 +524,6 @@  static int i915_drm_freeze(struct drm_device *dev)
 			return error;
 		}
 
-		drm_irq_uninstall(dev);
 		dev_priv->enable_hotplug_processing = false;
 
 		intel_disable_gt_powersave(dev);
@@ -539,6 +538,9 @@  static int i915_drm_freeze(struct drm_device *dev)
 		}
 		drm_modeset_unlock_all(dev);
 
+		intel_dp_mst_suspend(dev);
+		drm_irq_uninstall(dev);
+
 		intel_modeset_suspend_hw(dev);
 	}
 
@@ -642,6 +644,15 @@  static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
 
 		intel_modeset_init_hw(dev);
 
+		{
+			unsigned long irqflags;
+			spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+			if (dev_priv->display.hpd_irq_setup)
+				dev_priv->display.hpd_irq_setup(dev);
+			spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+		}
+
+		intel_dp_mst_resume(dev);
 		drm_modeset_lock_all(dev);
 		intel_modeset_setup_hw_state(dev, true);
 		drm_modeset_unlock_all(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 5fd5bf3..1f3e929 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1556,6 +1556,15 @@  struct drm_i915_private {
 	u32 short_hpd_port_mask;
 	struct work_struct dig_port_work;
 
+	/*
+	 * if we get a HPD irq from DP and a HPD irq from non-DP
+	 * the non-DP HPD could block the workqueue on a mode config
+	 * mutex getting, that userspace may have taken. However
+	 * userspace is waiting on the DP workqueue to run which is
+	 * blocked behind the non-DP one.
+	 */
+	struct workqueue_struct *dp_wq;
+
 	/* Old dri1 support infrastructure, beware the dragons ya fools entering
 	 * here! */
 	struct i915_dri1_state dri1;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index e3554d9..4e8f826 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1700,7 +1700,7 @@  static inline void intel_hpd_irq_handler(struct drm_device *dev,
 	 * deadlock.
 	 */
 	if (queue_dig)
-		schedule_work(&dev_priv->dig_port_work);
+		queue_work(dev_priv->dp_wq, &dev_priv->dig_port_work);
 	if (queue_hp)
 		schedule_work(&dev_priv->hotplug_work);
 }
@@ -4566,7 +4566,9 @@  void intel_hpd_init(struct drm_device *dev)
 	list_for_each_entry(connector, &mode_config->connector_list, head) {
 		struct intel_connector *intel_connector = to_intel_connector(connector);
 		connector->polled = intel_connector->polled;
-		if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
+		if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
+			connector->polled = DRM_CONNECTOR_POLL_HPD;
+		if (intel_connector->mst_port)
 			connector->polled = DRM_CONNECTOR_POLL_HPD;
 	}
 
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 2733a3d..2d8192a 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)
 	struct drm_encoder *encoder = &intel_encoder->base;
 	int type = intel_encoder->type;
 
-	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP ||
+	if (type == INTEL_OUTPUT_DP_MST) {
+		struct intel_digital_port *intel_dig_port = enc_to_mst(encoder)->primary;
+		return intel_dig_port->port;
+	} else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP ||
 	    type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) {
 		struct intel_digital_port *intel_dig_port =
 			enc_to_dig_port(encoder);
@@ -630,8 +633,8 @@  static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
 	return (refclk * n * 100) / (p * r);
 }
 
-static void intel_ddi_clock_get(struct intel_encoder *encoder,
-				struct intel_crtc_config *pipe_config)
+void intel_ddi_clock_get(struct intel_encoder *encoder,
+			 struct intel_crtc_config *pipe_config)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
 	enum port port = intel_ddi_get_encoder_port(encoder);
@@ -785,7 +788,15 @@  bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
 
 	intel_ddi_put_crtc_pll(crtc);
 
-	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
+	if (type == INTEL_OUTPUT_DP_MST) {
+		struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
+		intel_crtc->ddi_pll_sel = link_bw_to_pll_sel(intel_mst->primary->dp.link_bw);
+		if (intel_crtc->ddi_pll_sel == -1) {
+			DRM_ERROR("Link bandwidth %d unsupported\n",
+				  intel_mst->primary->dp.link_bw);
+			return false;
+		}
+	} else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
 		intel_crtc->ddi_pll_sel = link_bw_to_pll_sel(intel_dp->link_bw);
@@ -943,8 +954,7 @@  void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
 	int type = intel_encoder->type;
 	uint32_t temp;
 
-	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
-
+	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) {
 		temp = TRANS_MSA_SYNC_CLK;
 		switch (intel_crtc->config.pipe_bpp) {
 		case 18:
@@ -966,6 +976,21 @@  void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
 	}
 }
 
+void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+	uint32_t temp;
+	temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+	if (state == true)
+		temp |= TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
+	else
+		temp &= ~TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
+	I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp);
+}
+
 void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -1043,7 +1068,19 @@  void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
 		   type == INTEL_OUTPUT_EDP) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
-		temp |= TRANS_DDI_MODE_SELECT_DP_SST;
+		if (intel_dp->is_mst) {
+			temp |= TRANS_DDI_MODE_SELECT_DP_MST;
+		} else
+			temp |= TRANS_DDI_MODE_SELECT_DP_SST;
+
+		temp |= DDI_PORT_WIDTH(intel_dp->lane_count);
+	} else if (type == INTEL_OUTPUT_DP_MST) {
+		struct intel_dp *intel_dp = &enc_to_mst(encoder)->primary->dp;
+
+		if (intel_dp->is_mst) {
+			temp |= TRANS_DDI_MODE_SELECT_DP_MST;
+		} else
+			temp |= TRANS_DDI_MODE_SELECT_DP_SST;
 
 		temp |= DDI_PORT_WIDTH(intel_dp->lane_count);
 	} else {
@@ -1060,7 +1097,7 @@  void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
 	uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
 	uint32_t val = I915_READ(reg);
 
-	val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK);
+	val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
 	val |= TRANS_DDI_PORT_NONE;
 	I915_WRITE(reg, val);
 }
@@ -1099,8 +1136,11 @@  bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
 	case TRANS_DDI_MODE_SELECT_DP_SST:
 		if (type == DRM_MODE_CONNECTOR_eDP)
 			return true;
-	case TRANS_DDI_MODE_SELECT_DP_MST:
 		return (type == DRM_MODE_CONNECTOR_DisplayPort);
+	case TRANS_DDI_MODE_SELECT_DP_MST:
+		/* if the transcoder is in MST state then
+		 * connector isn't connected */
+		return false;
 
 	case TRANS_DDI_MODE_SELECT_FDI:
 		return (type == DRM_MODE_CONNECTOR_VGA);
@@ -1152,6 +1192,9 @@  bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
 
 			if ((tmp & TRANS_DDI_PORT_MASK)
 			    == TRANS_DDI_SELECT_PORT(port)) {
+				if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == TRANS_DDI_MODE_SELECT_DP_MST)
+					return false;
+
 				*pipe = i;
 				return true;
 			}
@@ -1478,10 +1521,15 @@  void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder)
 			intel_wait_ddi_buf_idle(dev_priv, port);
 	}
 
-	val = DP_TP_CTL_ENABLE | DP_TP_CTL_MODE_SST |
+	val = DP_TP_CTL_ENABLE |
 	      DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE;
-	if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
-		val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
+	if (intel_dp->is_mst)
+		val |= DP_TP_CTL_MODE_MST;
+	else {
+		val |= DP_TP_CTL_MODE_SST;
+		if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
+			val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
+	}
 	I915_WRITE(DP_TP_CTL(port), val);
 	POSTING_READ(DP_TP_CTL(port));
 
@@ -1520,11 +1568,16 @@  void intel_ddi_fdi_disable(struct drm_crtc *crtc)
 
 static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder)
 {
-	struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
-	int type = intel_encoder->type;
+	struct intel_digital_port *intel_dig_port = enc_to_dig_port(&intel_encoder->base);
+	int type = intel_dig_port->base.type;
+
+	if (type != INTEL_OUTPUT_DISPLAYPORT &&
+	    type != INTEL_OUTPUT_EDP &&
+	    type != INTEL_OUTPUT_UNKNOWN) {
+		return;
+	}
 
-	if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP)
-		intel_dp_check_link_status(intel_dp);
+	intel_dp_hot_plug(intel_encoder);
 }
 
 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 cef64b8..85db1c2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -68,6 +68,14 @@  static void haswell_set_pipeconf(struct drm_crtc *crtc);
 static void intel_set_pipe_csc(struct drm_crtc *crtc);
 static void vlv_prepare_pll(struct intel_crtc *crtc);
 
+static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
+{
+	if (!connector->mst_port)
+		return connector->encoder;
+	else
+		return &connector->mst_port->mst_encoders[pipe]->base;
+}
+
 typedef struct {
 	int	min, max;
 } intel_range_t;
@@ -4105,6 +4113,9 @@  static void haswell_crtc_enable(struct drm_crtc *crtc)
 	if (intel_crtc->config.has_pch_encoder)
 		lpt_pch_enable(crtc);
 
+	if (intel_crtc->config.dp_encoder_is_mst)
+		intel_ddi_set_vc_payload_alloc(crtc, true);
+
 	for_each_encoder_on_crtc(dev, crtc, encoder) {
 		encoder->enable(encoder);
 		intel_opregion_notify_encoder(encoder, true);
@@ -4155,6 +4166,9 @@  static void ironlake_crtc_disable(struct drm_crtc *crtc)
 
 	intel_disable_pipe(dev_priv, pipe);
 
+	if (intel_crtc->config.dp_encoder_is_mst)
+		intel_ddi_set_vc_payload_alloc(crtc, false);
+
 	ironlake_pfit_disable(intel_crtc);
 
 	for_each_encoder_on_crtc(dev, crtc, encoder)
@@ -4316,6 +4330,9 @@  intel_display_port_power_domain(struct intel_encoder *intel_encoder)
 	case INTEL_OUTPUT_EDP:
 		intel_dig_port = enc_to_dig_port(&intel_encoder->base);
 		return port_to_power_domain(intel_dig_port->port);
+	case INTEL_OUTPUT_DP_MST:
+		intel_dig_port = enc_to_mst(&intel_encoder->base)->primary;
+		return port_to_power_domain(intel_dig_port->port);
 	case INTEL_OUTPUT_ANALOG:
 		return POWER_DOMAIN_PORT_CRT;
 	case INTEL_OUTPUT_DSI:
@@ -4936,6 +4953,10 @@  static void intel_connector_check_state(struct intel_connector *connector)
 			      connector->base.base.id,
 			      connector->base.name);
 
+		/* there is no real hw state for MST connectors */
+		if (connector->mst_port)
+			return;
+
 		WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
 		     "wrong connector dpms state\n");
 		WARN(connector->base.encoder != &encoder->base,
@@ -10080,6 +10101,14 @@  check_encoder_state(struct drm_device *dev)
 			if (connector->base.dpms != DRM_MODE_DPMS_OFF)
 				active = true;
 		}
+		/*
+		 * for MST connectors if we unplug the connector is gone
+		 * away but the encoder is still connected to a crtc
+		 * until a modeset happens in response to the hotplug.
+		 */
+		if (!enabled && encoder->base.encoder_type == DRM_MODE_ENCODER_DPMST)
+			continue;
+
 		WARN(!!encoder->base.crtc != enabled,
 		     "encoder's enabled state mismatch "
 		     "(expected %i, found %i)\n",
@@ -10617,7 +10646,7 @@  intel_modeset_stage_output_state(struct drm_device *dev,
 		 * for them. */
 		for (ro = 0; ro < set->num_connectors; ro++) {
 			if (set->connectors[ro] == &connector->base) {
-				connector->new_encoder = connector->encoder;
+				connector->new_encoder = intel_find_encoder(connector, to_intel_crtc(set->crtc)->pipe);
 				break;
 			}
 		}
@@ -10663,7 +10692,7 @@  intel_modeset_stage_output_state(struct drm_device *dev,
 					 new_crtc)) {
 			return -EINVAL;
 		}
-		connector->encoder->new_crtc = to_intel_crtc(new_crtc);
+		connector->new_encoder->new_crtc = to_intel_crtc(new_crtc);
 
 		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
 			connector->base.base.id,
@@ -10697,7 +10726,12 @@  intel_modeset_stage_output_state(struct drm_device *dev,
 		}
 	}
 	/* Now we've also updated encoder->new_crtc for all encoders. */
-
+	list_for_each_entry(connector, &dev->mode_config.connector_list,
+			    base.head) {
+		if (connector->new_encoder)
+			if (connector->new_encoder != connector->encoder)
+				connector->encoder = connector->new_encoder;
+	}
 	for_each_intel_crtc(dev, crtc) {
 		crtc->new_enabled = false;
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 4603e5f..c500f63 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);
 static bool _edp_panel_vdd_on(struct intel_dp *intel_dp);
 static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
 
-static int
+int
 intel_dp_max_link_bw(struct intel_dp *intel_dp)
 {
 	int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
@@ -723,8 +723,9 @@  intel_dp_connector_unregister(struct intel_connector *intel_connector)
 {
 	struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base);
 
-	sysfs_remove_link(&intel_connector->base.kdev->kobj,
-			  intel_dp->aux.ddc.dev.kobj.name);
+	if (!intel_connector->mst_port)
+		sysfs_remove_link(&intel_connector->base.kdev->kobj,
+				  intel_dp->aux.ddc.dev.kobj.name);
 	intel_connector_unregister(intel_connector);
 }
 
@@ -3175,6 +3176,33 @@  intel_dp_probe_oui(struct intel_dp *intel_dp)
 	edp_panel_vdd_off(intel_dp, false);
 }
 
+static bool
+intel_dp_probe_mst(struct intel_dp *intel_dp)
+{
+	u8 buf[1];
+
+	if (!intel_dp->can_mst)
+		return false;
+
+	if (intel_dp->dpcd[DP_DPCD_REV] < 0x12)
+		return false;
+
+	_edp_panel_vdd_on(intel_dp);
+	if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_MSTM_CAP, buf, 1)) {
+		if (buf[0] & DP_MST_CAP) {
+			DRM_DEBUG_KMS("Sink is MST capable\n");
+			intel_dp->is_mst = true;
+		} else {
+			DRM_DEBUG_KMS("Sink is not MST capable\n");
+			intel_dp->is_mst = false;
+		}
+	}
+	edp_panel_vdd_off(intel_dp, false);
+
+	drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
+	return intel_dp->is_mst;
+}
+
 int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
@@ -3212,6 +3240,20 @@  intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector)
 				       sink_irq_vector, 1) == 1;
 }
 
+static bool
+intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *sink_irq_vector)
+{
+	int ret;
+
+	ret = intel_dp_dpcd_read_wake(&intel_dp->aux,
+					     DP_SINK_COUNT_ESI,
+					     sink_irq_vector, 14);
+	if (ret != 14)
+		return false;
+
+	return true;
+}
+
 static void
 intel_dp_handle_test_request(struct intel_dp *intel_dp)
 {
@@ -3219,6 +3261,63 @@  intel_dp_handle_test_request(struct intel_dp *intel_dp)
 	drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, DP_TEST_NAK);
 }
 
+static int
+intel_dp_check_mst_status(struct intel_dp *intel_dp)
+{
+	bool bret;
+
+	if (intel_dp->is_mst) {
+		u8 esi[16] = { 0 };
+		int ret = 0;
+		int retry;
+		bool handled;
+		bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
+	go_again:
+		if (bret == true) {
+
+			/* check link status - esi[10] = 0x200c */
+			if (intel_dp->active_mst_links && !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) {
+				DRM_DEBUG_KMS("channel EQ not ok, retraining\n");
+				intel_dp_start_link_train(intel_dp);
+				intel_dp_complete_link_train(intel_dp);
+				intel_dp_stop_link_train(intel_dp);
+			}
+
+			DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+			ret = drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled);
+
+			if (handled) {
+				for (retry = 0; retry < 3; retry++) {
+					int wret;
+					wret = drm_dp_dpcd_write(&intel_dp->aux,
+								 DP_SINK_COUNT_ESI+1,
+								 &esi[1], 3);
+					if (wret == 3) {
+						break;
+					}
+				}
+
+				bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
+				if (bret == true) {
+					DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+					goto go_again;
+				}
+			} else
+				ret = 0;
+
+			return ret;
+		} else {
+			struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+			DRM_DEBUG_KMS("failed to get ESI - device may have failed\n");
+			intel_dp->is_mst = false;
+			drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
+			/* send a hotplug event */
+			drm_kms_helper_hotplug_event(intel_dig_port->base.base.dev);
+		}
+	}
+	return -EINVAL;
+}
+
 /*
  * According to DP spec
  * 5.1.2:
@@ -3227,7 +3326,6 @@  intel_dp_handle_test_request(struct intel_dp *intel_dp)
  *  3. Use Link Training from 2.5.3.3 and 3.5.1.3
  *  4. Check link status on receipt of hot-plug interrupt
  */
-
 void
 intel_dp_check_link_status(struct intel_dp *intel_dp)
 {
@@ -3447,6 +3545,7 @@  intel_dp_detect(struct drm_connector *connector, bool force)
 	enum drm_connector_status status;
 	enum intel_display_power_domain power_domain;
 	struct edid *edid = NULL;
+	bool ret;
 
 	intel_runtime_pm_get(dev_priv);
 
@@ -3456,6 +3555,14 @@  intel_dp_detect(struct drm_connector *connector, bool force)
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
 		      connector->base.id, connector->name);
 
+	if (intel_dp->is_mst) {
+		/* MST devices are disconnected from a monitor POV */
+		if (intel_encoder->type != INTEL_OUTPUT_EDP)
+			intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
+		status = connector_status_disconnected;
+		goto out;
+	}
+
 	intel_dp->has_audio = false;
 
 	if (HAS_PCH_SPLIT(dev))
@@ -3468,6 +3575,16 @@  intel_dp_detect(struct drm_connector *connector, bool force)
 
 	intel_dp_probe_oui(intel_dp);
 
+	ret = intel_dp_probe_mst(intel_dp);
+	if (ret) {
+		/* if we are in MST mode then this connector
+		   won't appear connected or have anything with EDID on it */
+		if (intel_encoder->type != INTEL_OUTPUT_EDP)
+			intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
+		status = connector_status_disconnected;
+		goto out;
+	}
+
 	if (intel_dp->force_audio != HDMI_AUDIO_AUTO) {
 		intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON);
 	} else {
@@ -3663,6 +3780,7 @@  void intel_dp_encoder_destroy(struct drm_encoder *encoder)
 	struct drm_device *dev = intel_dp_to_dev(intel_dp);
 
 	drm_dp_aux_unregister(&intel_dp->aux);
+	intel_dp_mst_encoder_cleanup(intel_dig_port);
 	drm_encoder_cleanup(encoder);
 	if (is_edp(intel_dp)) {
 		cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
@@ -3691,28 +3809,62 @@  static const struct drm_encoder_funcs intel_dp_enc_funcs = {
 	.destroy = intel_dp_encoder_destroy,
 };
 
-static void
+void
 intel_dp_hot_plug(struct intel_encoder *intel_encoder)
 {
-	struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
-
-	intel_dp_check_link_status(intel_dp);
+	return;
 }
 
 bool
 intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 {
 	struct intel_dp *intel_dp = &intel_dig_port->dp;
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+	if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
+		intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
 
-	if (long_hpd)
-		return true;
+	DRM_DEBUG_KMS("got hpd irq on port %d - %s\n", intel_dig_port->port,
+		      long_hpd ? "long" : "short");
 
-	/*
-	 * we'll check the link status via the normal hot plug path later -
-	 * but for short hpds we should check it now
-	 */
-	intel_dp_check_link_status(intel_dp);
+	if (long_hpd) {
+		if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
+			goto mst_fail;
+
+		if (!intel_dp_get_dpcd(intel_dp)) {
+			goto mst_fail;
+		}
+
+		intel_dp_probe_oui(intel_dp);
+
+		if (!intel_dp_probe_mst(intel_dp))
+			goto mst_fail;
+
+	} else {
+		if (intel_dp->is_mst) {
+			ret = intel_dp_check_mst_status(intel_dp);
+			if (ret == -EINVAL)
+				goto mst_fail;
+		}
+
+		if (!intel_dp->is_mst) {
+			/*
+			 * we'll check the link status via the normal hot plug path later -
+			 * but for short hpds we should check it now
+			 */
+			intel_dp_check_link_status(intel_dp);
+		}
+	}
 	return false;
+mst_fail:
+	/* if we were in MST mode, and device is not there get out of MST mode */
+	if (intel_dp->is_mst) {
+		DRM_DEBUG_KMS("MST device may have disappeared %d vs %d\n", intel_dp->is_mst, intel_dp->mst_mgr.mst_state);
+		intel_dp->is_mst = false;
+		drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
+	}
+	return true;
 }
 
 /* Return which DP Port should be selected for Transcoder DP control */
@@ -3763,7 +3915,7 @@  bool intel_dp_is_edp(struct drm_device *dev, enum port port)
 	return false;
 }
 
-static void
+void
 intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
 {
 	struct intel_connector *intel_connector = to_intel_connector(connector);
@@ -4259,6 +4411,13 @@  intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 
 	intel_dp->psr_setup_done = false;
 
+	/* init MST on ports that can support it */
+	if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+		if (port == PORT_B || port == PORT_C || port == PORT_D) {
+			intel_dp_mst_encoder_init(intel_dig_port, intel_connector->base.base.id);
+		}
+	}
+
 	if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) {
 		drm_dp_aux_unregister(&intel_dp->aux);
 		if (is_edp(intel_dp)) {
@@ -4356,3 +4515,46 @@  intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
 		kfree(intel_connector);
 	}
 }
+
+void intel_dp_mst_suspend(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int i;
+
+	/* disable MST */
+	for (i = 0; i < I915_MAX_PORTS; i++) {
+		struct intel_digital_port *intel_dig_port = dev_priv->hpd_irq_port[i];
+		if (!intel_dig_port)
+			continue;
+
+		if (intel_dig_port->base.type == INTEL_OUTPUT_DISPLAYPORT) {
+			if (!intel_dig_port->dp.can_mst)
+				continue;
+			if (intel_dig_port->dp.is_mst)
+				drm_dp_mst_topology_mgr_suspend(&intel_dig_port->dp.mst_mgr);
+		}
+	}
+}
+
+void intel_dp_mst_resume(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int i;
+
+	for (i = 0; i < I915_MAX_PORTS; i++) {
+		struct intel_digital_port *intel_dig_port = dev_priv->hpd_irq_port[i];
+		if (!intel_dig_port)
+			continue;
+		if (intel_dig_port->base.type == INTEL_OUTPUT_DISPLAYPORT) {
+			int ret;
+
+			if (!intel_dig_port->dp.can_mst)
+				continue;
+
+			ret = drm_dp_mst_topology_mgr_resume(&intel_dig_port->dp.mst_mgr);
+			if (ret != 0) {
+				intel_dp_check_mst_status(&intel_dig_port->dp);
+			}
+		}
+	}
+}
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 0000000..a7db741
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -0,0 +1,535 @@ 
+/*
+ * Copyright © 2008 Intel Corporation
+ *             2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include <drm/drmP.h>
+#include "i915_drv.h"
+#include "intel_drv.h"
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+
+bool
+intel_dp_mst_compute_config(struct intel_encoder *encoder,
+			    struct intel_crtc_config *pipe_config)
+{
+	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+	struct intel_digital_port *intel_dig_port = intel_mst->primary;
+	struct intel_dp *intel_dp = &intel_dig_port->dp;
+	struct drm_device *dev = encoder->base.dev;
+	int bpp;
+	int lane_count, slots;
+	struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+	struct intel_connector *found = NULL, *intel_connector;
+	int mst_pbn;
+
+	pipe_config->dp_encoder_is_mst = true;
+	pipe_config->has_pch_encoder = false;
+	pipe_config->has_dp_encoder = true;
+	bpp = 24;
+	/*
+	 * for MST we always configure max link bw - the spec doesn't
+	 * seem to suggest we should do otherwise.
+	 */
+	lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
+	intel_dp->link_bw = intel_dp_max_link_bw(intel_dp);
+	intel_dp->lane_count = lane_count;
+
+	pipe_config->pipe_bpp = 24;
+	pipe_config->port_clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
+
+	list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head) {
+		if (intel_connector->new_encoder == encoder) {
+			found = intel_connector;
+			break;
+		}
+	}
+
+	if (!found) {
+		DRM_ERROR("can't find connector\n");
+		return false;
+	}
+
+	mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp);
+
+	pipe_config->pbn = mst_pbn;
+	slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, mst_pbn);
+
+	intel_link_compute_m_n(bpp, lane_count,
+			       adjusted_mode->crtc_clock,
+			       pipe_config->port_clock,
+			       &pipe_config->dp_m_n);
+
+	pipe_config->dp_m_n.tu = slots;
+	return true;
+
+}
+
+static void intel_mst_disable_dp(struct intel_encoder *encoder)
+{
+	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+	struct intel_digital_port *intel_dig_port = intel_mst->primary;
+	struct intel_dp *intel_dp = &intel_dig_port->dp;
+	int ret;
+
+	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
+
+	drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, intel_mst->port);
+
+	ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
+	if (ret) {
+		DRM_ERROR("failed to update payload %d\n", ret);
+	}
+}
+
+static void intel_mst_post_disable_dp(struct intel_encoder *encoder)
+{
+	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+	struct intel_digital_port *intel_dig_port = intel_mst->primary;
+	struct intel_dp *intel_dp = &intel_dig_port->dp;
+
+	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
+
+	/* this can fail */
+	drm_dp_check_act_status(&intel_dp->mst_mgr);
+	/* and this can also fail */
+	drm_dp_update_payload_part2(&intel_dp->mst_mgr);
+
+	drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, intel_mst->port);
+
+	intel_dp->active_mst_links--;
+	intel_mst->port = NULL;
+	if (intel_dp->active_mst_links == 0) {
+		intel_dig_port->base.post_disable(&intel_dig_port->base);
+		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+	}
+}
+
+static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
+{
+	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+	struct intel_digital_port *intel_dig_port = intel_mst->primary;
+	struct intel_dp *intel_dp = &intel_dig_port->dp;
+	struct drm_device *dev = encoder->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	enum port port = intel_dig_port->port;
+	int ret;
+	uint32_t temp;
+	struct intel_connector *found = NULL, *intel_connector;
+	int slots;
+	struct drm_crtc *crtc = encoder->base.crtc;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head) {
+		if (intel_connector->new_encoder == encoder) {
+			found = intel_connector;
+			break;
+		}
+	}
+
+	if (!found) {
+		DRM_ERROR("can't find connector\n");
+		return;
+	}
+
+	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
+	intel_mst->port = found->port;
+
+	if (intel_dp->active_mst_links == 0) {
+		enum port port = intel_ddi_get_encoder_port(encoder);
+
+		I915_WRITE(PORT_CLK_SEL(port), intel_crtc->ddi_pll_sel);
+
+		intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
+
+		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+
+
+		intel_dp_start_link_train(intel_dp);
+		intel_dp_complete_link_train(intel_dp);
+		intel_dp_stop_link_train(intel_dp);
+	}
+
+	ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
+				       intel_mst->port, intel_crtc->config.pbn, &slots);
+	if (ret == false) {
+		DRM_ERROR("failed to allocate vcpi\n");
+		return;
+	}
+
+
+	intel_dp->active_mst_links++;
+	temp = I915_READ(DP_TP_STATUS(port));
+	I915_WRITE(DP_TP_STATUS(port), temp);
+
+	ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
+}
+
+static void intel_mst_enable_dp(struct intel_encoder *encoder)
+{
+	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+	struct intel_digital_port *intel_dig_port = intel_mst->primary;
+	struct intel_dp *intel_dp = &intel_dig_port->dp;
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	enum port port = intel_dig_port->port;
+	int ret;
+
+	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
+
+	if (wait_for((I915_READ(DP_TP_STATUS(port)) & DP_TP_STATUS_ACT_SENT),
+		     1))
+		DRM_ERROR("Timed out waiting for ACT sent\n");
+
+	ret = drm_dp_check_act_status(&intel_dp->mst_mgr);
+
+	ret = drm_dp_update_payload_part2(&intel_dp->mst_mgr);
+}
+
+static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
+				      enum pipe *pipe)
+{
+	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+	*pipe = intel_mst->pipe;
+	if (intel_mst->port)
+		return true;
+	return false;
+}
+
+static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
+					struct intel_crtc_config *pipe_config)
+{
+	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
+	struct intel_digital_port *intel_dig_port = intel_mst->primary;
+	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+	struct drm_device *dev = encoder->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+	u32 temp, flags = 0;
+
+	pipe_config->has_dp_encoder = true;
+
+	temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+	if (temp & TRANS_DDI_PHSYNC)
+		flags |= DRM_MODE_FLAG_PHSYNC;
+	else
+		flags |= DRM_MODE_FLAG_NHSYNC;
+	if (temp & TRANS_DDI_PVSYNC)
+		flags |= DRM_MODE_FLAG_PVSYNC;
+	else
+		flags |= DRM_MODE_FLAG_NVSYNC;
+
+	switch (temp & TRANS_DDI_BPC_MASK) {
+	case TRANS_DDI_BPC_6:
+		pipe_config->pipe_bpp = 18;
+		break;
+	case TRANS_DDI_BPC_8:
+		pipe_config->pipe_bpp = 24;
+		break;
+	case TRANS_DDI_BPC_10:
+		pipe_config->pipe_bpp = 30;
+		break;
+	case TRANS_DDI_BPC_12:
+		pipe_config->pipe_bpp = 36;
+		break;
+	default:
+		break;
+	}
+	pipe_config->adjusted_mode.flags |= flags;
+	intel_dp_get_m_n(crtc, pipe_config);
+
+	intel_ddi_clock_get(&intel_dig_port->base, pipe_config);
+}
+
+static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector)
+{
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_dp *intel_dp = intel_connector->mst_port;
+	struct edid *edid;
+	int ret;
+
+	edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port);
+	if (!edid)
+		return 0;
+
+	ret = intel_connector_update_modes(connector, edid);
+	kfree(edid);
+
+	return ret;
+}
+
+static enum drm_connector_status
+intel_mst_port_dp_detect(struct drm_connector *connector)
+{
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_dp *intel_dp = intel_connector->mst_port;
+
+	return drm_dp_mst_detect_port(&intel_dp->mst_mgr, intel_connector->port);
+}
+
+static enum drm_connector_status
+intel_dp_mst_detect(struct drm_connector *connector, bool force)
+{
+	enum drm_connector_status status;
+	status = intel_mst_port_dp_detect(connector);
+	return status;
+}
+
+static int
+intel_dp_mst_set_property(struct drm_connector *connector,
+			  struct drm_property *property,
+			  uint64_t val)
+{
+	return 0;
+}
+
+static void
+intel_dp_mst_connector_destroy(struct drm_connector *connector)
+{
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+
+	if (!IS_ERR_OR_NULL(intel_connector->edid))
+		kfree(intel_connector->edid);
+
+	drm_connector_cleanup(connector);
+	kfree(connector);
+}
+
+static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
+	.dpms = intel_connector_dpms,
+	.detect = intel_dp_mst_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.set_property = intel_dp_mst_set_property,
+	.destroy = intel_dp_mst_connector_destroy,
+};
+
+static int intel_dp_mst_get_modes(struct drm_connector *connector)
+{
+	return intel_dp_mst_get_ddc_modes(connector);
+}
+
+static enum drm_mode_status
+intel_dp_mst_mode_valid(struct drm_connector *connector,
+			struct drm_display_mode *mode)
+{
+	/* TODO - validate mode against available PBN for link */
+	if (mode->clock < 10000)
+		return MODE_CLOCK_LOW;
+
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		return MODE_H_ILLEGAL;
+
+	return MODE_OK;
+}
+
+struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connector)
+{
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_dp *intel_dp = intel_connector->mst_port;
+	return &intel_dp->mst_encoders[0]->base.base;
+}
+
+static const struct drm_connector_helper_funcs intel_dp_mst_connector_helper_funcs = {
+	.get_modes = intel_dp_mst_get_modes,
+	.mode_valid = intel_dp_mst_mode_valid,
+	.best_encoder = intel_mst_best_encoder,
+};
+
+void intel_dp_mst_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder);
+
+	drm_encoder_cleanup(encoder);
+	kfree(intel_mst);
+}
+
+static const struct drm_encoder_funcs intel_dp_mst_enc_funcs = {
+	.destroy = intel_dp_mst_encoder_destroy,
+};
+
+static bool intel_dp_mst_get_hw_state(struct intel_connector *connector)
+{
+	if (connector->encoder) {
+		enum pipe pipe;
+		if (!connector->encoder->get_hw_state(connector->encoder, &pipe))
+			return false;
+		return true;
+	}
+	return false;
+}
+
+static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, char *pathprop)
+{
+	struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_connector *intel_connector;
+	struct drm_connector *connector;
+	int i;
+
+	intel_connector = kzalloc(sizeof(*intel_connector), GFP_KERNEL);
+	if (!intel_connector)
+		return NULL;
+
+	connector = &intel_connector->base;
+	drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, DRM_MODE_CONNECTOR_DisplayPort);
+	drm_connector_helper_add(connector, &intel_dp_mst_connector_helper_funcs);
+
+	intel_connector->unregister = intel_connector_unregister;
+	intel_connector->get_hw_state = intel_dp_mst_get_hw_state;
+	intel_connector->mst_port = intel_dp;
+	intel_connector->port = port;
+
+	for (i = PIPE_A; i <= PIPE_C; i++) {
+		drm_mode_connector_attach_encoder(&intel_connector->base,
+						  &intel_dp->mst_encoders[i]->base.base);
+	}
+	intel_dp_add_properties(intel_dp, connector);
+
+	drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
+	drm_mode_connector_set_path_property(connector, pathprop);
+	drm_reinit_primary_mode_group(dev);
+	mutex_lock(&dev->mode_config.mutex);
+	drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, connector);
+	mutex_unlock(&dev->mode_config.mutex);
+	drm_sysfs_connector_add(&intel_connector->base);
+	return connector;
+}
+
+static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
+					   struct drm_connector *connector)
+{
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct drm_device *dev = connector->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	/* need to nuke the connector */
+	mutex_lock(&dev->mode_config.mutex);
+	intel_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+	mutex_unlock(&dev->mode_config.mutex);
+
+	intel_connector->unregister(intel_connector);
+
+	mutex_lock(&dev->mode_config.mutex);
+	drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, connector);
+	drm_connector_cleanup(connector);
+	mutex_unlock(&dev->mode_config.mutex);
+
+	drm_reinit_primary_mode_group(dev);
+
+	kfree(intel_connector);
+	DRM_DEBUG_KMS("\n");
+}
+
+static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
+{
+	struct intel_dp *intel_dp = container_of(mgr, struct intel_dp, mst_mgr);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+
+	drm_kms_helper_hotplug_event(dev);
+}
+
+struct drm_dp_mst_topology_cbs mst_cbs = {
+	.add_connector = intel_dp_add_mst_connector,
+	.destroy_connector = intel_dp_destroy_mst_connector,
+	.hotplug = intel_dp_mst_hotplug,
+};
+
+static struct intel_dp_mst_encoder *
+intel_dp_create_fake_mst_encoder(struct intel_digital_port *intel_dig_port, enum pipe pipe)
+{
+	struct intel_dp_mst_encoder *intel_mst;
+	struct intel_encoder *intel_encoder;
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+
+	intel_mst = kzalloc(sizeof(*intel_mst), GFP_KERNEL);
+
+	if (!intel_mst)
+		return NULL;
+
+	intel_mst->pipe = pipe;
+	intel_encoder = &intel_mst->base;
+	intel_mst->primary = intel_dig_port;
+
+	drm_encoder_init(dev, &intel_encoder->base, &intel_dp_mst_enc_funcs,
+			 DRM_MODE_ENCODER_DPMST);
+
+	intel_encoder->type = INTEL_OUTPUT_DP_MST;
+	intel_encoder->crtc_mask = 0x7;
+	intel_encoder->cloneable = 0;
+
+	intel_encoder->compute_config = intel_dp_mst_compute_config;
+	intel_encoder->disable = intel_mst_disable_dp;
+	intel_encoder->post_disable = intel_mst_post_disable_dp;
+	intel_encoder->pre_enable = intel_mst_pre_enable_dp;
+	intel_encoder->enable = intel_mst_enable_dp;
+	intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state;
+	intel_encoder->get_config = intel_dp_mst_enc_get_config;
+
+	return intel_mst;
+
+}
+
+static bool
+intel_dp_create_fake_mst_encoders(struct intel_digital_port *intel_dig_port)
+{
+	int i;
+	struct intel_dp *intel_dp = &intel_dig_port->dp;
+
+	for (i = PIPE_A; i <= PIPE_C; i++)
+		intel_dp->mst_encoders[i] = intel_dp_create_fake_mst_encoder(intel_dig_port, i);
+	return true;
+}
+
+int
+intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_base_id)
+{
+	struct intel_dp *intel_dp = &intel_dig_port->dp;
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	int ret;
+
+	intel_dp->can_mst = true;
+	intel_dp->mst_mgr.cbs = &mst_cbs;
+
+	/* create encoders */
+	intel_dp_create_fake_mst_encoders(intel_dig_port);
+	ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev->dev, &intel_dp->aux, 16, 3, conn_base_id);
+	if (ret) {
+		intel_dp->can_mst = false;
+		return ret;
+	}
+	return 0;
+}
+
+void
+intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port)
+{
+	struct intel_dp *intel_dp = &intel_dig_port->dp;
+
+	if (!intel_dp->can_mst)
+		return;
+
+	drm_dp_mst_topology_mgr_destroy(&intel_dp->mst_mgr);
+	/* encoders will get killed by normal cleanup */
+}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index da6c440..1edb38a 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -32,7 +32,7 @@ 
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
-#include <drm/drm_dp_helper.h>
+#include <drm/drm_dp_mst_helper.h>
 
 /**
  * _wait_for - magic (register) wait macro
@@ -100,6 +100,7 @@ 
 #define INTEL_OUTPUT_EDP 8
 #define INTEL_OUTPUT_DSI 9
 #define INTEL_OUTPUT_UNKNOWN 10
+#define INTEL_OUTPUT_DP_MST 11
 
 #define INTEL_DVO_CHIP_NONE 0
 #define INTEL_DVO_CHIP_LVDS 1
@@ -207,6 +208,10 @@  struct intel_connector {
 	/* since POLL and HPD connectors may use the same HPD line keep the native
 	   state of connector->polled in case hotplug storm detection changes it */
 	u8 polled;
+
+	void *port; /* store this opaque as its illegal to dereference it */
+
+	struct intel_dp *mst_port;
 };
 
 typedef struct dpll {
@@ -347,6 +352,9 @@  struct intel_crtc_config {
 	bool ips_enabled;
 
 	bool double_wide;
+
+	bool dp_encoder_is_mst;
+	int pbn;
 };
 
 struct intel_pipe_wm {
@@ -498,6 +506,7 @@  struct intel_hdmi {
 			       struct drm_display_mode *adjusted_mode);
 };
 
+struct intel_dp_mst_encoder;
 #define DP_MAX_DOWNSTREAM_PORTS		0x10
 
 /**
@@ -538,8 +547,17 @@  struct intel_dp {
 	unsigned long last_backlight_off;
 	bool psr_setup_done;
 	bool use_tps3;
+	bool can_mst; /* this port supports mst */
+	bool is_mst;
+	int active_mst_links;
+	/* connector directly attached - won't be use for modeset in mst world */
 	struct intel_connector *attached_connector;
 
+	/* mst connector list */
+	struct intel_connector *mst_connectors;
+	struct intel_dp_mst_encoder *mst_encoders[I915_MAX_PIPES];
+	struct drm_dp_mst_topology_mgr mst_mgr;
+
 	uint32_t (*get_aux_clock_divider)(struct intel_dp *dp, int index);
 	/*
 	 * This function returns the value we have to program the AUX_CTL
@@ -566,6 +584,13 @@  struct intel_digital_port {
 	bool (*hpd_pulse)(struct intel_digital_port *, bool);
 };
 
+struct intel_dp_mst_encoder {
+	struct intel_encoder base;
+	enum pipe pipe;
+	struct intel_digital_port *primary;
+	void *port; /* store this opaque as its illegal to dereference it */
+};
+
 static inline int
 vlv_dport_to_channel(struct intel_digital_port *dport)
 {
@@ -650,6 +675,12 @@  enc_to_dig_port(struct drm_encoder *encoder)
 	return container_of(encoder, struct intel_digital_port, base.base);
 }
 
+static inline struct intel_dp_mst_encoder *
+enc_to_mst(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct intel_dp_mst_encoder, base.base);
+}
+
 static inline struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
 {
 	return &enc_to_dig_port(encoder)->dp;
@@ -715,6 +746,9 @@  void intel_ddi_get_config(struct intel_encoder *encoder,
 			  struct intel_crtc_config *pipe_config);
 
 void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder);
+void intel_ddi_clock_get(struct intel_encoder *encoder,
+			 struct intel_crtc_config *pipe_config);
+void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 
 /* intel_display.c */
 const char *intel_output_name(int output);
@@ -834,6 +868,15 @@  void intel_edp_psr_update(struct drm_device *dev);
 void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate);
 bool intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd);
 
+int intel_dp_handle_hpd_irq(struct intel_digital_port *digport, bool long_hpd);
+void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector);
+void intel_dp_mst_suspend(struct drm_device *dev);
+void intel_dp_mst_resume(struct drm_device *dev);
+int intel_dp_max_link_bw(struct intel_dp *intel_dp);
+void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
+/* intel_dp_mst.c */
+int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
+void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);
 /* intel_dsi.c */
 bool intel_dsi_init(struct drm_device *dev);
 
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index e2d4161..1949350 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -349,6 +349,11 @@  static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 		}
 
 		encoder = connector->encoder;
+		if (!encoder) {
+			struct drm_connector_helper_funcs *connector_funcs;
+			connector_funcs = connector->helper_private;
+			encoder = connector_funcs->best_encoder(connector);
+		}
 		if (!encoder || WARN_ON(!encoder->crtc)) {
 			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
 				      connector->name);
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index b812e9d..27d4570 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,
 	case INTEL_OUTPUT_UNKNOWN:
 	case INTEL_OUTPUT_DISPLAYPORT:
 	case INTEL_OUTPUT_HDMI:
+	case INTEL_OUTPUT_DP_MST:
 		type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL;
 		break;
 	case INTEL_OUTPUT_EDP: