Skip to content

Commit 0e32b39

Browse files
committed
drm/i915: add DP 1.2 MST support (v0.7)
This adds DP 1.2 MST support on Haswell systems. Notes: a) this reworks irq handling for DP MST ports, so that we can avoid the mode config locking in the current hpd handlers, as we need to process up/down msgs at a better time. Changes since v0.1: use PORT_PCH_HOTPLUG to detect short vs long pulses add a workqueue to deal with digital events as they can get blocked on the main workqueue beyong mode_config mutex fix a bunch of modeset checker warnings acks irqs in the driver cleanup the MST encoders Changes since v0.2: check irq status again in work handler move around bring up and tear down to fix DPMS on/off use path properties. Changes since v0.3: updates for mst apis more state checker fixes irq handling improvements fbcon handling support improved reference counting of link - fixes redocking. Changes since v0.4: handle gpu reset hpd reinit without oopsing check link status on HPD irqs fix suspend/resume Changes since v0.5: use proper functions to get max link/lane counts fix another checker backtrace - due to connectors disappearing. set output type in more places fro, unknown->displayport don't talk to devices if no HPD asserted check mst on short irqs only check link status properly rebase onto prepping irq changes. drop unsued force_act Changes since v0.6: cleanup unused struct entry. [airlied: fix some sparse warnings]. Reviewed-by: Todd Previte <tprevite@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
1 parent d05410f commit 0e32b39

File tree

12 files changed

+934
-38
lines changed

12 files changed

+934
-38
lines changed

drivers/gpu/drm/i915/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ i915-y += dvo_ch7017.o \
5959
intel_crt.o \
6060
intel_ddi.o \
6161
intel_dp.o \
62+
intel_dp_mst.o \
6263
intel_dsi_cmd.o \
6364
intel_dsi.o \
6465
intel_dsi_pll.o \

drivers/gpu/drm/i915/i915_dma.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,6 +1717,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
17171717
goto out_mtrrfree;
17181718
}
17191719

1720+
dev_priv->dp_wq = alloc_ordered_workqueue("i915-dp", 0);
1721+
if (dev_priv->dp_wq == NULL) {
1722+
DRM_ERROR("Failed to create our dp workqueue.\n");
1723+
ret = -ENOMEM;
1724+
goto out_freewq;
1725+
}
1726+
17201727
intel_irq_init(dev);
17211728
intel_uncore_sanitize(dev);
17221729

@@ -1792,6 +1799,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
17921799
intel_teardown_gmbus(dev);
17931800
intel_teardown_mchbar(dev);
17941801
pm_qos_remove_request(&dev_priv->pm_qos);
1802+
destroy_workqueue(dev_priv->dp_wq);
1803+
out_freewq:
17951804
destroy_workqueue(dev_priv->wq);
17961805
out_mtrrfree:
17971806
arch_phys_wc_del(dev_priv->gtt.mtrr);
@@ -1892,6 +1901,7 @@ int i915_driver_unload(struct drm_device *dev)
18921901
intel_teardown_gmbus(dev);
18931902
intel_teardown_mchbar(dev);
18941903

1904+
destroy_workqueue(dev_priv->dp_wq);
18951905
destroy_workqueue(dev_priv->wq);
18961906
pm_qos_remove_request(&dev_priv->pm_qos);
18971907

drivers/gpu/drm/i915/i915_drv.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,6 @@ static int i915_drm_freeze(struct drm_device *dev)
518518

519519
flush_delayed_work(&dev_priv->rps.delayed_resume_work);
520520

521-
intel_runtime_pm_disable_interrupts(dev);
522521

523522
intel_suspend_gt_powersave(dev);
524523

@@ -532,6 +531,9 @@ static int i915_drm_freeze(struct drm_device *dev)
532531
}
533532
drm_modeset_unlock_all(dev);
534533

534+
intel_dp_mst_suspend(dev);
535+
intel_runtime_pm_disable_interrupts(dev);
536+
535537
intel_modeset_suspend_hw(dev);
536538
}
537539

@@ -646,6 +648,15 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
646648

647649
intel_modeset_init_hw(dev);
648650

651+
{
652+
unsigned long irqflags;
653+
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
654+
if (dev_priv->display.hpd_irq_setup)
655+
dev_priv->display.hpd_irq_setup(dev);
656+
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
657+
}
658+
659+
intel_dp_mst_resume(dev);
649660
drm_modeset_lock_all(dev);
650661
intel_modeset_setup_hw_state(dev, true);
651662
drm_modeset_unlock_all(dev);

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,6 +1595,15 @@ struct drm_i915_private {
15951595
u32 short_hpd_port_mask;
15961596
struct work_struct dig_port_work;
15971597

1598+
/*
1599+
* if we get a HPD irq from DP and a HPD irq from non-DP
1600+
* the non-DP HPD could block the workqueue on a mode config
1601+
* mutex getting, that userspace may have taken. However
1602+
* userspace is waiting on the DP workqueue to run which is
1603+
* blocked behind the non-DP one.
1604+
*/
1605+
struct workqueue_struct *dp_wq;
1606+
15981607
/* Old dri1 support infrastructure, beware the dragons ya fools entering
15991608
* here! */
16001609
struct i915_dri1_state dri1;

drivers/gpu/drm/i915/i915_irq.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,7 +1846,7 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
18461846
* deadlock.
18471847
*/
18481848
if (queue_dig)
1849-
schedule_work(&dev_priv->dig_port_work);
1849+
queue_work(dev_priv->dp_wq, &dev_priv->dig_port_work);
18501850
if (queue_hp)
18511851
schedule_work(&dev_priv->hotplug_work);
18521852
}
@@ -4739,7 +4739,9 @@ void intel_hpd_init(struct drm_device *dev)
47394739
list_for_each_entry(connector, &mode_config->connector_list, head) {
47404740
struct intel_connector *intel_connector = to_intel_connector(connector);
47414741
connector->polled = intel_connector->polled;
4742-
if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
4742+
if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
4743+
connector->polled = DRM_CONNECTOR_POLL_HPD;
4744+
if (intel_connector->mst_port)
47434745
connector->polled = DRM_CONNECTOR_POLL_HPD;
47444746
}
47454747

drivers/gpu/drm/i915/intel_ddi.c

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,10 @@ enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder)
116116
struct drm_encoder *encoder = &intel_encoder->base;
117117
int type = intel_encoder->type;
118118

119-
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP ||
119+
if (type == INTEL_OUTPUT_DP_MST) {
120+
struct intel_digital_port *intel_dig_port = enc_to_mst(encoder)->primary;
121+
return intel_dig_port->port;
122+
} else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP ||
120123
type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) {
121124
struct intel_digital_port *intel_dig_port =
122125
enc_to_dig_port(encoder);
@@ -584,8 +587,8 @@ static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
584587
return (refclk * n * 100) / (p * r);
585588
}
586589

587-
static void intel_ddi_clock_get(struct intel_encoder *encoder,
588-
struct intel_crtc_config *pipe_config)
590+
void intel_ddi_clock_get(struct intel_encoder *encoder,
591+
struct intel_crtc_config *pipe_config)
589592
{
590593
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
591594
int link_clock = 0;
@@ -755,8 +758,7 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
755758
int type = intel_encoder->type;
756759
uint32_t temp;
757760

758-
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
759-
761+
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) {
760762
temp = TRANS_MSA_SYNC_CLK;
761763
switch (intel_crtc->config.pipe_bpp) {
762764
case 18:
@@ -778,6 +780,21 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
778780
}
779781
}
780782

783+
void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state)
784+
{
785+
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
786+
struct drm_device *dev = crtc->dev;
787+
struct drm_i915_private *dev_priv = dev->dev_private;
788+
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
789+
uint32_t temp;
790+
temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
791+
if (state == true)
792+
temp |= TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
793+
else
794+
temp &= ~TRANS_DDI_DP_VC_PAYLOAD_ALLOC;
795+
I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp);
796+
}
797+
781798
void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
782799
{
783800
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -857,7 +874,19 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
857874
type == INTEL_OUTPUT_EDP) {
858875
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
859876

860-
temp |= TRANS_DDI_MODE_SELECT_DP_SST;
877+
if (intel_dp->is_mst) {
878+
temp |= TRANS_DDI_MODE_SELECT_DP_MST;
879+
} else
880+
temp |= TRANS_DDI_MODE_SELECT_DP_SST;
881+
882+
temp |= DDI_PORT_WIDTH(intel_dp->lane_count);
883+
} else if (type == INTEL_OUTPUT_DP_MST) {
884+
struct intel_dp *intel_dp = &enc_to_mst(encoder)->primary->dp;
885+
886+
if (intel_dp->is_mst) {
887+
temp |= TRANS_DDI_MODE_SELECT_DP_MST;
888+
} else
889+
temp |= TRANS_DDI_MODE_SELECT_DP_SST;
861890

862891
temp |= DDI_PORT_WIDTH(intel_dp->lane_count);
863892
} else {
@@ -874,7 +903,7 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
874903
uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
875904
uint32_t val = I915_READ(reg);
876905

877-
val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK);
906+
val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC);
878907
val |= TRANS_DDI_PORT_NONE;
879908
I915_WRITE(reg, val);
880909
}
@@ -913,8 +942,11 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
913942
case TRANS_DDI_MODE_SELECT_DP_SST:
914943
if (type == DRM_MODE_CONNECTOR_eDP)
915944
return true;
916-
case TRANS_DDI_MODE_SELECT_DP_MST:
917945
return (type == DRM_MODE_CONNECTOR_DisplayPort);
946+
case TRANS_DDI_MODE_SELECT_DP_MST:
947+
/* if the transcoder is in MST state then
948+
* connector isn't connected */
949+
return false;
918950

919951
case TRANS_DDI_MODE_SELECT_FDI:
920952
return (type == DRM_MODE_CONNECTOR_VGA);
@@ -966,6 +998,9 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
966998

967999
if ((tmp & TRANS_DDI_PORT_MASK)
9681000
== TRANS_DDI_SELECT_PORT(port)) {
1001+
if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == TRANS_DDI_MODE_SELECT_DP_MST)
1002+
return false;
1003+
9691004
*pipe = i;
9701005
return true;
9711006
}
@@ -1272,10 +1307,15 @@ void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder)
12721307
intel_wait_ddi_buf_idle(dev_priv, port);
12731308
}
12741309

1275-
val = DP_TP_CTL_ENABLE | DP_TP_CTL_MODE_SST |
1310+
val = DP_TP_CTL_ENABLE |
12761311
DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE;
1277-
if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
1278-
val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
1312+
if (intel_dp->is_mst)
1313+
val |= DP_TP_CTL_MODE_MST;
1314+
else {
1315+
val |= DP_TP_CTL_MODE_SST;
1316+
if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
1317+
val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE;
1318+
}
12791319
I915_WRITE(DP_TP_CTL(port), val);
12801320
POSTING_READ(DP_TP_CTL(port));
12811321

@@ -1314,11 +1354,16 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc)
13141354

13151355
static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder)
13161356
{
1317-
struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
1318-
int type = intel_encoder->type;
1357+
struct intel_digital_port *intel_dig_port = enc_to_dig_port(&intel_encoder->base);
1358+
int type = intel_dig_port->base.type;
1359+
1360+
if (type != INTEL_OUTPUT_DISPLAYPORT &&
1361+
type != INTEL_OUTPUT_EDP &&
1362+
type != INTEL_OUTPUT_UNKNOWN) {
1363+
return;
1364+
}
13191365

1320-
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP)
1321-
intel_dp_check_link_status(intel_dp);
1366+
intel_dp_hot_plug(intel_encoder);
13221367
}
13231368

13241369
void intel_ddi_get_config(struct intel_encoder *encoder,

drivers/gpu/drm/i915/intel_display.c

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc);
101101
static void intel_set_pipe_csc(struct drm_crtc *crtc);
102102
static void vlv_prepare_pll(struct intel_crtc *crtc);
103103

104+
static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
105+
{
106+
if (!connector->mst_port)
107+
return connector->encoder;
108+
else
109+
return &connector->mst_port->mst_encoders[pipe]->base;
110+
}
111+
104112
typedef struct {
105113
int min, max;
106114
} intel_range_t;
@@ -4130,6 +4138,9 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
41304138
if (intel_crtc->config.has_pch_encoder)
41314139
lpt_pch_enable(crtc);
41324140

4141+
if (intel_crtc->config.dp_encoder_is_mst)
4142+
intel_ddi_set_vc_payload_alloc(crtc, true);
4143+
41334144
for_each_encoder_on_crtc(dev, crtc, encoder) {
41344145
encoder->enable(encoder);
41354146
intel_opregion_notify_encoder(encoder, true);
@@ -4178,6 +4189,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
41784189

41794190
intel_disable_pipe(dev_priv, pipe);
41804191

4192+
if (intel_crtc->config.dp_encoder_is_mst)
4193+
intel_ddi_set_vc_payload_alloc(crtc, false);
4194+
41814195
ironlake_pfit_disable(intel_crtc);
41824196

41834197
for_each_encoder_on_crtc(dev, crtc, encoder)
@@ -4336,6 +4350,9 @@ intel_display_port_power_domain(struct intel_encoder *intel_encoder)
43364350
case INTEL_OUTPUT_EDP:
43374351
intel_dig_port = enc_to_dig_port(&intel_encoder->base);
43384352
return port_to_power_domain(intel_dig_port->port);
4353+
case INTEL_OUTPUT_DP_MST:
4354+
intel_dig_port = enc_to_mst(&intel_encoder->base)->primary;
4355+
return port_to_power_domain(intel_dig_port->port);
43394356
case INTEL_OUTPUT_ANALOG:
43404357
return POWER_DOMAIN_PORT_CRT;
43414358
case INTEL_OUTPUT_DSI:
@@ -5004,6 +5021,10 @@ static void intel_connector_check_state(struct intel_connector *connector)
50045021
connector->base.base.id,
50055022
connector->base.name);
50065023

5024+
/* there is no real hw state for MST connectors */
5025+
if (connector->mst_port)
5026+
return;
5027+
50075028
WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
50085029
"wrong connector dpms state\n");
50095030
WARN(connector->base.encoder != &encoder->base,
@@ -10524,6 +10545,14 @@ check_encoder_state(struct drm_device *dev)
1052410545
if (connector->base.dpms != DRM_MODE_DPMS_OFF)
1052510546
active = true;
1052610547
}
10548+
/*
10549+
* for MST connectors if we unplug the connector is gone
10550+
* away but the encoder is still connected to a crtc
10551+
* until a modeset happens in response to the hotplug.
10552+
*/
10553+
if (!enabled && encoder->base.encoder_type == DRM_MODE_ENCODER_DPMST)
10554+
continue;
10555+
1052710556
WARN(!!encoder->base.crtc != enabled,
1052810557
"encoder's enabled state mismatch "
1052910558
"(expected %i, found %i)\n",
@@ -11069,7 +11098,7 @@ intel_modeset_stage_output_state(struct drm_device *dev,
1106911098
* for them. */
1107011099
for (ro = 0; ro < set->num_connectors; ro++) {
1107111100
if (set->connectors[ro] == &connector->base) {
11072-
connector->new_encoder = connector->encoder;
11101+
connector->new_encoder = intel_find_encoder(connector, to_intel_crtc(set->crtc)->pipe);
1107311102
break;
1107411103
}
1107511104
}
@@ -11115,7 +11144,7 @@ intel_modeset_stage_output_state(struct drm_device *dev,
1111511144
new_crtc)) {
1111611145
return -EINVAL;
1111711146
}
11118-
connector->encoder->new_crtc = to_intel_crtc(new_crtc);
11147+
connector->new_encoder->new_crtc = to_intel_crtc(new_crtc);
1111911148

1112011149
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
1112111150
connector->base.base.id,
@@ -11149,7 +11178,12 @@ intel_modeset_stage_output_state(struct drm_device *dev,
1114911178
}
1115011179
}
1115111180
/* Now we've also updated encoder->new_crtc for all encoders. */
11152-
11181+
list_for_each_entry(connector, &dev->mode_config.connector_list,
11182+
base.head) {
11183+
if (connector->new_encoder)
11184+
if (connector->new_encoder != connector->encoder)
11185+
connector->encoder = connector->new_encoder;
11186+
}
1115311187
for_each_intel_crtc(dev, crtc) {
1115411188
crtc->new_enabled = false;
1115511189

0 commit comments

Comments
 (0)