drm/i915 mst support
Subsystems (4)
Dave Airlie
maintainerAnother round of the MST support for i915 haswell.
This relies on the aux locking and i915 irq rework patches I posted already.
this also splits out some more i915 rework into earlier patches.
The main fix is not talking to devices if HPD isn't asserted, at least on the dock I have it will reply to DPCD without HPD being asserted but it just confuses everyone.
Otherwise it contains a bunch of stability fixes, and avoids the worst backtraces of i915 state tracker, which is fine when hw is involved but MST doesn't really fit so well with it, esp when you hot unplug some hardware, and the state tracker expects it to remain in the same state until userspace catches up, (note the hw is gone!).
All available on:git://people.freedesktop.org/~airlied/linux drm-i915-mst-support
Dave.
Dave Airlie
maintainerPATCH 1/11 drm/i915: add some registers need for displayport MST support.
From: Dave Airlie <[email protected]>
These are just from the Haswell spec.
--- drivers/gpu/drm/i915/i915_reg.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/i915_reg.h +9 -2
@@ -5736,6 +5736,7 @@ enum punit_power_well {#define TRANS_DDI_EDP_INPUT_A_ONOFF (4<<12)#define TRANS_DDI_EDP_INPUT_B_ONOFF (5<<12)#define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12) +#define TRANS_DDI_DP_VC_PAYLOAD_ALLOC (1<<8)#define TRANS_DDI_BFI_ENABLE (1<<4)/* DisplayPort Transport Control */
@@ -5745,6 +5746,7 @@ enum punit_power_well {#define DP_TP_CTL_ENABLE (1<<31)#define DP_TP_CTL_MODE_SST (0<<27)#define DP_TP_CTL_MODE_MST (1<<27) +#define DP_TP_CTL_FORCE_ACT (1<<25)#define DP_TP_CTL_ENHANCED_FRAME_ENABLE (1<<18)#define DP_TP_CTL_FDI_AUTOTRAIN (1<<15)#define DP_TP_CTL_LINK_TRAIN_MASK (7<<8)
@@ -5759,8 +5761,13 @@ enum punit_power_well {#define DP_TP_STATUS_A 0x64044#define DP_TP_STATUS_B 0x64144#define DP_TP_STATUS (port) _PORT(port, DP_TP_STATUS_A, DP_TP_STATUS_B) -#define DP_TP_STATUS_IDLE_DONE (1<<25) -#define DP_TP_STATUS_AUTOTRAIN_DONE (1<<12) +#define DP_TP_STATUS_IDLE_DONE (1<<25) +#define DP_TP_STATUS_ACT_SENT (1<<24) +#define DP_TP_STATUS_MODE_STATUS_MST (1<<23) +#define DP_TP_STATUS_AUTOTRAIN_DONE (1<<12) +#define DP_TP_STATUS_PAYLOAD_MAPPING_VC2 (3 << 8) +#define DP_TP_STATUS_PAYLOAD_MAPPING_VC1 (3 << 4) +#define DP_TP_STATUS_PAYLOAD_MAPPING_VC0 (3 << 0)/* DDI Buffer Control */ #define DDI_BUF_CTL_A 0x64000
Signature · 1 line
1.9.3
Dave Airlie
maintainerPATCH 2/11 drm/crtc: add interface to reinitialise the legacy mode group
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
This can be called to update things after dynamic connectors/encoders are created/deleted.
--- drivers/gpu/drm/drm_crtc.c | 9 +++++++++ include/drm/drm_crtc.h | 1 + 2 files changed, 10 insertions(+)
drivers/gpu/drm/drm_crtc.c +9 -0
@@ -1430,6 +1430,15 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, }EXPORT_SYMBOL (drm_mode_group_init_legacy_group); +void drm_reinit_primary_mode_group (struct drm_device *dev) +{ +drm_modeset_lock_all (dev); +drm_mode_group_destroy (&dev->primary->mode_group); +drm_mode_group_init_legacy_group (dev, &dev->primary->mode_group); +drm_modeset_unlock_all (dev); +} +EXPORT_SYMBOL (drm_reinit_primary_mode_group); +/** * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo * @out: drm_mode_modeinfo struct to return to the user
include/drm/drm_crtc.h +1 -0
@@ -931,6 +931,7 @@ extern const char *drm_get_tv_select_name(int val);extern void drm_fb_release (struct drm_file *file_priv);extern int drm_mode_group_init_legacy_group (struct drm_device *dev,struct drm_mode_group *group);extern void drm_mode_group_destroy (struct drm_mode_group *group); +extern void drm_reinit_primary_mode_group (struct drm_device *dev);extern bool drm_probe_ddc (struct i2c_adapter *adapter);extern struct edid *drm_get_edid (struct drm_connector *connector,struct i2c_adapter *adapter);
Signature · 1 line
1.9.3
Dave Airlie
maintainerPATCH 3/11 drm/fb_helper: allow adding/removing connectors later
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
This is required to get fbcon probing to work on new connectors, callers should acquire the mode config lock before calling these.
--- drivers/gpu/drm/drm_fb_helper.c | 53 +++++++++++++++++++++++++++++++++++++++++ include/drm/drm_fb_helper.h | 4 ++++ 2 files changed, 57 insertions(+)
drivers/gpu/drm/drm_fb_helper.c +53 -0
@@ -105,6 +105,58 @@ fail: }EXPORT_SYMBOL (drm_fb_helper_single_add_all_connectors); +int drm_fb_helper_add_one_connector (struct drm_fb_helper *fb_helper,struct drm_connector *connector) +{ +struct drm_fb_helper_connector **temp; +struct drm_fb_helper_connector *fb_helper_connector; + +WARN_ON (!mutex_is_locked (&fb_helper->dev->mode_config.mutex)); +if (fb_helper->connector_count +1 > fb_helper->connector_info_alloc_count) { + temp =krealloc (fb_helper->connector_info,sizeof (struct drm_fb_helper_connector ) * (fb_helper->connector_count +1 ),GFP_KERNEL ); +if (!temp) +return -ENOMEM ; + + fb_helper->connector_info_alloc_count = fb_helper->connector_count +1 ; + fb_helper->connector_info = temp; + } + + + fb_helper_connector =kzalloc (sizeof (struct drm_fb_helper_connector ),GFP_KERNEL ); +if (!fb_helper_connector) +return -ENOMEM ; + + fb_helper_connector->connector = connector; + fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; +return 0 ; +} +EXPORT_SYMBOL (drm_fb_helper_add_one_connector); + +int drm_fb_helper_remove_one_connector (struct drm_fb_helper *fb_helper, +struct drm_connector *connector) +{ +struct drm_fb_helper_connector *fb_helper_connector; +int i, j; + +WARN_ON (!mutex_is_locked (&fb_helper->dev->mode_config.mutex)); + +for (i =0 ; i < fb_helper->connector_count; i++) { +if (fb_helper->connector_info[i]->connector == connector) +break ; + } + +if (i == fb_helper->connector_count) +return -EINVAL ; + fb_helper_connector = fb_helper->connector_info[i]; + +for (j = i +1 ; j < fb_helper->connector_count; j++) { + fb_helper->connector_info[j -1 ] = fb_helper->connector_info[j]; + } + fb_helper->connector_count--; +kfree (fb_helper_connector); +return 0 ; +} +EXPORT_SYMBOL (drm_fb_helper_remove_one_connector); +static int drm_fb_helper_parse_command_line (struct drm_fb_helper *fb_helper) {struct drm_fb_helper_connector *fb_helper_conn;
@@ -543,6 +595,7 @@ int drm_fb_helper_init(struct drm_device *dev,kfree (fb_helper->crtc_info);return -ENOMEM ; } + fb_helper->connector_info_alloc_count = dev->mode_config.num_connector; fb_helper->connector_count =0 ;for (i =0 ; i < crtc_count; i++) {
include/drm/drm_fb_helper.h +4 -0
@@ -86,6 +86,7 @@ struct drm_fb_helper {int crtc_count;struct drm_fb_helper_crtc *crtc_info;int connector_count; +int connector_info_alloc_count;struct drm_fb_helper_connector **connector_info;struct drm_fb_helper_funcs *funcs;struct fb_info *fbdev;
@@ -128,4 +129,7 @@ struct drm_display_mode * drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, int width, int height); +int drm_fb_helper_add_one_connector (struct drm_fb_helper *fb_helper,struct drm_connector *connector); +int drm_fb_helper_remove_one_connector (struct drm_fb_helper *fb_helper, +struct drm_connector *connector);#endif
Signature · 1 line
1.9.3
Dave Airlie
maintainerPATCH 4/11 drm: add a path blob property
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
This property will be used by the MST code to provide userspace with a path to parse so it can recognise connectors around hotplugs.
--- drivers/gpu/drm/drm_crtc.c | 26 ++++++++++++++++++++++++++ include/drm/drm_crtc.h | 5 +++++ 2 files changed, 31 insertions(+)
drivers/gpu/drm/drm_crtc.c +26 -0
@@ -1174,6 +1174,7 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) {struct drm_property *edid;struct drm_property *dpms; +struct drm_property *dev_path;/* * Standard properties (apply to all connectors)
@@ -1188,6 +1189,12 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) ARRAY_SIZE(drm_dpms_enum_list)); dev->mode_config.dpms_property = dpms; + dev_path =drm_property_create (dev, +DRM_MODE_PROP_BLOB | +DRM_MODE_PROP_IMMUTABLE , +"PATH" ,0 ); + dev->mode_config.path_property = dev_path; +return 0 ; }
@@ -3665,6 +3672,25 @@ done:return ret; } +int drm_mode_connector_set_path_property (struct drm_connector *connector, +char *path) +{ +struct drm_device *dev = connector->dev; +int ret, size; + size =strlen (path) +1 ; + + connector->path_blob_ptr =drm_property_create_blob (connector->dev, + size, path); +if (!connector->path_blob_ptr) +return -EINVAL ; + + ret =drm_object_property_set_value (&connector->base, + dev->mode_config.path_property, + connector->path_blob_ptr->base.id); +return ret; +} +EXPORT_SYMBOL (drm_mode_connector_set_path_property); +/** * drm_mode_connector_update_edid_property - update the edid property of a connector * @connector: drm connector
include/drm/drm_crtc.h +5 -0
@@ -515,6 +515,8 @@ struct drm_connector {struct drm_property_blob *edid_blob_ptr;struct drm_object_properties properties; +struct drm_property_blob *path_blob_ptr; +uint8_t polled;/* DRM_CONNECTOR_POLL_* */ /* requested DPMS state */
@@ -790,6 +792,7 @@ struct drm_mode_config {struct list_head property_blob_list;struct drm_property *edid_property;struct drm_property *dpms_property; +struct drm_property *path_property;struct drm_property *plane_type_property;/* DVI-I properties */
@@ -941,6 +944,8 @@ extern void drm_mode_config_init(struct drm_device *dev);extern void drm_mode_config_reset (struct drm_device *dev);extern void drm_mode_config_cleanup (struct drm_device *dev); +extern int drm_mode_connector_set_path_property (struct drm_connector *connector, +char *path);extern int drm_mode_connector_update_edid_property (struct drm_connector *connector,struct edid *edid);
Signature · 1 line
1.9.3
Dave Airlie
maintainerPATCH 5/11 drm/helper: add Displayport multi-stream helper (v0.6)
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
This is the initial import of the helper for displayport multistream.
It consists of a topology manager, init/destroy/set mst state
It supports DP 1.2 MST sideband msg protocol handler - via hpd irqs
connector detect and edid retrieval interface.
It supports i2c device over DP 1.2 sideband msg protocol (EDID reads only)
bandwidth manager API via vcpi allocation and payload updating, along with a helper to check the ACT status.
Objects:
MST topology manager - one per toplevel MST capable GPU port - not sure if this should be higher level again MST branch unit - one instance per plugged branching unit - one at top of hierarchy - others hanging from ports MST port - one port per port reported by branching units, can have MST units hanging from them as well.
Changes since initial posting:
a) add a mutex responsbile for the queues, it locks the sideband and msg slots, and msgs to transmit state
b) add worker to handle connection state change events, for MST device chaining and hotplug
c) add a payload spinlock
d) add path sideband msg support
e) fixup enum path resources transmit
f) reduce max dpcd msg to 16, as per DP1.2 spec.
g) separate tx queue kicking from irq processing and move irq acking back to drivers.
Changes since v0.2:
a) reorganise code,
b) drop ACT forcing code
c) add connector naming interface using path property
d) add topology dumper helper
e) proper reference counting and lookup for ports and mstbs.
f) move tx kicking into a workq
g) add aux locking - this should be redone
h) split teardown into two parts
i) start working on documentation on interface.
Changes since v0.3:
a) vc payload locking and tracking fixes
b) add hotplug callback into driver - replaces crazy return 1 scheme
c) txmsg + mst branch device refcount fixes
d) don't bail on mst shutdown if device is gone
e) change irq handler to take all 4 bytes of SINK_COUNT + ESI vectors
f) make DP payload updates timeout longer - observed on docking station redock
g) add more info to debugfs dumper
Changes since v0.4:
a) suspend/resume support
b) more debugging in debugfs
Changes since v0.5:
a) use byte * to avoid unnecessary stack usage
b) fix num_sdp_streams interpretation.
c) init payload state for unplug events
d) remove lenovo dock sink count hack
e) drop aux lock - post rebase
f) call hotplug on port destroy
TODO:
misc features
--- Documentation/DocBook/drm.tmpl | 6 + drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_dp_mst_topology.c | 2712 +++++++++++++++++++++++++++++++++ include/drm/drm_dp_mst_helper.h | 509 +++++++ 4 files changed, 3228 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_dp_mst_topology.c create mode 100644 include/drm/drm_dp_mst_helper.h
Documentation/DocBook/drm.tmpl +6 -0
@@ -2296,6 +2296,12 @@ void intel_crt_init(struct drm_device *dev) !Edrivers/gpu/drm/drm_dp_helper.c </sect2> <sect2> + <title>Display Port MST Helper Functions Reference</title> +!Pdrivers/gpu/drm/drm_dp_mst_topology.c dp mst helper +!Iinclude/drm/drm_dp_mst_helper.h +!Edrivers/gpu/drm/drm_dp_mst_topology.c + </sect2> + <sect2> <title>EDID Helper Functions Reference</title> !Edrivers/gpu/drm/drm_edid.c </sect2>
drivers/gpu/drm/Makefile +1 -1
@@ -23,7 +23,7 @@ drm-$(CONFIG_DRM_PANEL) += drm_panel.o drm-usb-y := drm_usb.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ - drm_plane_helper.o + drm_plane_helper.o drm_dp_mst_topology.o drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o drm_kms_helper-$(CONFIG_DRM_KMS_FB_HELPER) += drm_fb_helper.o drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
drivers/gpu/drm/drm_dp_mst_topology.c new file +2712 -0
2,712 lines not on this page · raw message
include/drm/drm_dp_mst_helper.h new file +509 -0
268 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 6 lines
1.9.3 _______________________________________________ Intel-gfx mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Part of the diff is not shown here. View the raw message.
Dave Airlie
maintainerPATCH 6/11 i915: split some DP modesetting code into a separate function
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
this is just prep work for mst support.
--- drivers/gpu/drm/i915/intel_ddi.c | 18 +++++++++++++----- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 14 insertions(+), 5 deletions(-)
drivers/gpu/drm/i915/intel_ddi.c +13 -5
@@ -364,6 +364,18 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)DRM_ERROR ("FDI link training failed!\n" ); } +void intel_ddi_init_dp_buf_reg (struct intel_encoder *encoder) +{ +struct intel_dp *intel_dp =enc_to_intel_dp (&encoder->base); +struct intel_digital_port *intel_dig_port = +enc_to_dig_port (&encoder->base); + + intel_dp->DP = intel_dig_port->saved_port_bits | +DDI_BUF_CTL_ENABLE |DDI_BUF_EMP_400MV_0DB_HSW ; + intel_dp->DP |=DDI_PORT_WIDTH (intel_dp->lane_count); + +} +static struct intel_encoder *intel_ddi_get_crtc_encoder (struct drm_crtc *crtc) {
@@ -1266,12 +1278,8 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)if (type ==INTEL_OUTPUT_DISPLAYPORT || type ==INTEL_OUTPUT_EDP ) {struct intel_dp *intel_dp =enc_to_intel_dp (encoder); -struct intel_digital_port *intel_dig_port = -enc_to_dig_port (encoder); - intel_dp->DP = intel_dig_port->saved_port_bits | -DDI_BUF_CTL_ENABLE |DDI_BUF_EMP_400MV_0DB_HSW ; - intel_dp->DP |=DDI_PORT_WIDTH (intel_dp->lane_count); +intel_ddi_init_dp_buf_reg (intel_encoder);intel_dp_sink_dpms (intel_dp,DRM_MODE_DPMS_ON );intel_dp_start_link_train (intel_dp);
drivers/gpu/drm/i915/intel_drv.h +1 -0
@@ -714,6 +714,7 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc);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);/* intel_display.c */ const char *intel_output_name (int output);
Signature · 1 line
1.9.3
Dave Airlie
maintainerPATCH 7/11 drm/i915: check connector->encoder before using it.
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
DP MST will need connectors that aren't connected to specific encoders, add some checks in advance to avoid oopses.
--- drivers/gpu/drm/i915/i915_debugfs.c | 16 +++++++++------- drivers/gpu/drm/i915/i915_irq.c | 4 ++++ drivers/gpu/drm/i915/intel_display.c | 25 ++++++++++++++----------- 3 files changed, 27 insertions(+), 18 deletions(-)
drivers/gpu/drm/i915/i915_debugfs.c +9 -7
@@ -2285,13 +2285,15 @@ static void intel_connector_info(struct seq_file *m,seq_printf (m,"\tCEA rev: %d\n" , connector->display_info.cea_rev); } -if (intel_encoder->type ==INTEL_OUTPUT_DISPLAYPORT || - intel_encoder->type ==INTEL_OUTPUT_EDP ) -intel_dp_info (m, intel_connector); -else if (intel_encoder->type ==INTEL_OUTPUT_HDMI ) -intel_hdmi_info (m, intel_connector); -else if (intel_encoder->type ==INTEL_OUTPUT_LVDS ) -intel_lvds_info (m, intel_connector); +if (intel_encoder) { +if (intel_encoder->type ==INTEL_OUTPUT_DISPLAYPORT || + intel_encoder->type ==INTEL_OUTPUT_EDP ) +intel_dp_info (m, intel_connector); +else if (intel_encoder->type ==INTEL_OUTPUT_HDMI ) +intel_hdmi_info (m, intel_connector); +else if (intel_encoder->type ==INTEL_OUTPUT_LVDS ) +intel_lvds_info (m, intel_connector); + }seq_printf (m,"\tmodes:\n" );list_for_each_entry (mode, &connector->modes, head)
drivers/gpu/drm/i915/i915_irq.c +4 -0
@@ -1175,6 +1175,8 @@ static void i915_hotplug_work_func(struct work_struct *work) dev_priv->hpd_event_bits =0 ;list_for_each_entry (connector, &mode_config->connector_list, head) { intel_connector =to_intel_connector (connector); +if (!intel_connector->encoder) +continue ; intel_encoder = intel_connector->encoder; if (intel_encoder->hpd_pin > HPD_NONE && dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_MARK_DISABLED &&
@@ -1205,6 +1207,8 @@ static void i915_hotplug_work_func(struct work_struct *work)list_for_each_entry (connector, &mode_config->connector_list, head) { intel_connector =to_intel_connector (connector); +if (!intel_connector->encoder) +continue ; intel_encoder = intel_connector->encoder;if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {if (intel_encoder->hot_plug)
drivers/gpu/drm/i915/intel_display.c +14 -11
@@ -4935,20 +4935,23 @@ static void intel_connector_check_state(struct intel_connector *connector) "wrong connector dpms state\n");WARN (connector->base.encoder != &encoder->base,"active connector not linked to encoder\n" ); -WARN (!encoder->connectors_active, -"encoder->connectors_active not set\n" ); - encoder_enabled = encoder->get_hw_state (encoder, &pipe); -WARN (!encoder_enabled,"encoder not enabled\n" ); -if (WARN_ON (!encoder->base.crtc)) -return ; +if (encoder) { +WARN (!encoder->connectors_active, +"encoder->connectors_active not set\n" ); + + encoder_enabled = encoder->get_hw_state (encoder, &pipe); +WARN (!encoder_enabled,"encoder not enabled\n" ); +if (WARN_ON (!encoder->base.crtc)) +return ; - crtc = encoder->base.crtc; + crtc = encoder->base.crtc; -WARN (!crtc->enabled,"crtc not enabled\n" ); -WARN (!to_intel_crtc (crtc)->active,"crtc not active\n" ); -WARN (pipe !=to_intel_crtc (crtc)->pipe, -"encoder active on the wrong pipe\n" ); +WARN (!crtc->enabled,"crtc not enabled\n" ); +WARN (!to_intel_crtc (crtc)->active,"crtc not active\n" ); +WARN (pipe !=to_intel_crtc (crtc)->pipe, +"encoder active on the wrong pipe\n" ); + } } }
Signature · 1 line
1.9.3
Dave Airlie
maintainerPATCH 8/11 drm/i915: split some conversion functions out into separate functions.
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
for MST I need to reuse these, so split them out early.
--- drivers/gpu/drm/i915/intel_ddi.c | 27 ++++++++++++++++----------- drivers/gpu/drm/i915/intel_display.c | 31 ++++++++++++++++++------------- 2 files changed, 34 insertions(+), 24 deletions(-)
drivers/gpu/drm/i915/intel_ddi.c +16 -11
@@ -752,6 +752,20 @@ intel_ddi_calculate_wrpll(int clock /* in Hz */, *r2_out = best.r2; } +static int link_bw_to_pll_sel (int link_bw) +{ +switch (link_bw) { +case DP_LINK_BW_1_62 : +return PORT_CLK_SEL_LCPLL_810 ; +case DP_LINK_BW_2_7 : +return PORT_CLK_SEL_LCPLL_1350 ; +case DP_LINK_BW_5_4 : +return PORT_CLK_SEL_LCPLL_2700 ; +default : +return -1 ; + } +} +/* * Tries to find a PLL for the CRTC. If it finds, it increases the refcount and * stores it in intel_crtc->ddi_pll_sel, so other mode sets won't be able to
@@ -774,17 +788,8 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)if (type ==INTEL_OUTPUT_DISPLAYPORT || type ==INTEL_OUTPUT_EDP ) {struct intel_dp *intel_dp =enc_to_intel_dp (encoder); -switch (intel_dp->link_bw) { -case DP_LINK_BW_1_62 : - intel_crtc->ddi_pll_sel =PORT_CLK_SEL_LCPLL_810 ; -break ; -case DP_LINK_BW_2_7 : - intel_crtc->ddi_pll_sel =PORT_CLK_SEL_LCPLL_1350 ; -break ; -case DP_LINK_BW_5_4 : - intel_crtc->ddi_pll_sel =PORT_CLK_SEL_LCPLL_2700 ; -break ; -default : + intel_crtc->ddi_pll_sel =link_bw_to_pll_sel (intel_dp->link_bw); +if (intel_crtc->ddi_pll_sel ==-1 ) {DRM_ERROR ("Link bandwidth %d unsupported\n" , intel_dp->link_bw);return false;
drivers/gpu/drm/i915/intel_display.c +18 -13
@@ -4280,6 +4280,23 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc)I915_WRITE (BCLRPAT (crtc->pipe),0 ); } +static enum intel_display_power_domain port_to_power_domain (enum port port) +{ +switch (port) { +case PORT_A : +return POWER_DOMAIN_PORT_DDI_A_4_LANES ; +case PORT_B : +return POWER_DOMAIN_PORT_DDI_B_4_LANES ; +case PORT_C : +return POWER_DOMAIN_PORT_DDI_C_4_LANES ; +case PORT_D : +return POWER_DOMAIN_PORT_DDI_D_4_LANES ; +default : +WARN_ON_ONCE (1 ); +return POWER_DOMAIN_PORT_OTHER ; + } +} +#define for_each_power_domain (domain, mask) \ for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \ if ((1 << (domain)) & (mask))
@@ -4298,19 +4315,7 @@ intel_display_port_power_domain(struct intel_encoder *intel_encoder)case INTEL_OUTPUT_HDMI :case INTEL_OUTPUT_EDP : intel_dig_port =enc_to_dig_port (&intel_encoder->base); -switch (intel_dig_port->port) { -case PORT_A : -return POWER_DOMAIN_PORT_DDI_A_4_LANES ; -case PORT_B : -return POWER_DOMAIN_PORT_DDI_B_4_LANES ; -case PORT_C : -return POWER_DOMAIN_PORT_DDI_C_4_LANES ; -case PORT_D : -return POWER_DOMAIN_PORT_DDI_D_4_LANES ; -default : -WARN_ON_ONCE (1 ); -return POWER_DOMAIN_PORT_OTHER ; - } +return port_to_power_domain (intel_dig_port->port);case INTEL_OUTPUT_ANALOG :return POWER_DOMAIN_PORT_CRT ;case INTEL_OUTPUT_DSI :
Signature · 1 line
1.9.3
Dave Airlie
maintainerPATCH 9/11 i915: add DP 1.2 MST support (v0.6)
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
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.
--- 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
drivers/gpu/drm/i915/Makefile +1 -0
@@ -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 \
drivers/gpu/drm/i915/i915_dma.c +10 -0
@@ -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);
drivers/gpu/drm/i915/i915_drv.c +12 -1
@@ -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);
drivers/gpu/drm/i915/i915_drv.h +9 -0
@@ -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;
drivers/gpu/drm/i915/i915_irq.c +4 -2
@@ -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 ; }
drivers/gpu/drm/i915/intel_ddi.c +69 -16
154 lines not on this page · raw message
drivers/gpu/drm/i915/intel_display.c +37 -3
@@ -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;
drivers/gpu/drm/i915/intel_dp.c +218 -16
326 lines not on this page · raw message
drivers/gpu/drm/i915/intel_dp_mst.c new file +535 -0
535 lines not on this page · raw message
drivers/gpu/drm/i915/intel_drv.h +44 -1
107 lines not on this page · raw message
drivers/gpu/drm/i915/intel_fbdev.c +5 -0
@@ -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);
drivers/gpu/drm/i915/intel_opregion.c +1 -0
@@ -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 :
Signature · 6 lines
1.9.3 _______________________________________________ Intel-gfx mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [PATCH 09/11] i915: add DP 1.2 MST support (v0.6)
2014-06-05 1:01 GMT-03:00 Dave Airlie <[email protected]>:
Quoted 3 lines
From: Dave Airlie <[email protected]>
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
Quoted 1,508 lines
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:
usePORT_PCH_HOTPLUGto detect short vs long pulses
add a workqueue to deal with digital events as they can get blocked on the main workqueue beyongmode_configmutex
fix a bunch of modeset checker warnings
acks irqs in the driver
cleanup the MST encodersChanges 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/resumeChanges 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->displayportdon't talk to devices if no HPD asserted
check mst on short irqs only
check link status properly
rebase onto prepping irq changes.
drop unsuedforce_actTODO:
possibly further state checker fixes
HDMI screaming IRQ needs fixing.Signed-off-by Dave Airlie <[email protected]>--- 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.cdrivers/gpu/drm/i915/Makefile +1
-0@@ -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 \drivers/gpu/drm/i915/i915_dma.c +10
-0@@ -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);drivers/gpu/drm/i915/i915_drv.c +12
-1@@ -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);drivers/gpu/drm/i915/i915_drv.h +9
-0@@ -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;drivers/gpu/drm/i915/i915_irq.c +4
-2@@ -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 ; }drivers/gpu/drm/i915/intel_ddi.c +69
-16@@ -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,drivers/gpu/drm/i915/intel_display.c +37
-3@@ -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;drivers/gpu/drm/i915/intel_dp.c +218
-16@@ -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); + } + } + } +}drivers/gpu/drm/i915/intel_dp_mst.c new file +535
-0@@ -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 */ +}drivers/gpu/drm/i915/intel_drv.h +44
-1@@ -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);drivers/gpu/drm/i915/intel_fbdev.c +5
-0@@ -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);drivers/gpu/drm/i915/intel_opregion.c +1
-1@@ -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
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 5 lines
Paulo Zanoni _______________________________________________ Intel-gfx mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Dave Airlie
maintainerRe: [PATCH 09/11] i915: add DP 1.2 MST support (v0.6)
Quoted 12 lines · Paulo Zanoni
2014-06-05 1:01 GMT-03:00 Dave Airlie <[email protected]>:
Quoted 3 lines
From: Dave Airlie <[email protected]>
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.
Re: [Intel-gfx] [PATCH 09/11] i915: add DP 1.2 MST support (v0.6)
Quoted 11 lines · Dave Airlie
Quoted 10 lines · Paulo Zanoni
2014-06-05 1:01 GMT-03:00 Dave Airlie <[email protected]>:
Quoted 3 lines
From: Dave Airlie <[email protected]>
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.
Quoted 6 lines
Quoted 2 lines
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
Signature · 3 lines
Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch
Dave Airlie
maintainerRe: [PATCH 09/11] i915: add DP 1.2 MST support (v0.6)
Quoted 12 lines · Daniel Vetter
Quoted 11 lines · Dave Airlie
Quoted 10 lines · Paulo Zanoni
2014-06-05 1:01 GMT-03:00 Dave Airlie <[email protected]>:
Quoted 3 lines
From: Dave Airlie <[email protected]>
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.
Quoted 9 lines
Quoted 6 lines
Quoted 2 lines
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.
Re: [Intel-gfx] [PATCH 09/11] i915: add DP 1.2 MST support (v0.6)
Quoted 16 lines · Dave Airlie
Quoted 15 lines · Daniel Vetter
Quoted 14 lines · Dave Airlie
Quoted 12 lines · Paulo Zanoni
2014-06-05 1:01 GMT-03:00 Dave Airlie <[email protected]>:
Quoted 3 lines
From: Dave Airlie <[email protected]>
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:
Quoted 7 lines
Quoted 6 lines
Quoted 3 lines
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
Signature · 3 lines
Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch
Dave Airlie
maintainerPATCH 10/11 i915: mst topology dumper in debugfs (v0.2)
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
use the mst helper code to dump the topology in debugfs.
v0.2: drop is_mst check - as we want to dump other info
--- drivers/gpu/drm/i915/i915_debugfs.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
drivers/gpu/drm/i915/i915_debugfs.c +23 -0
@@ -2379,6 +2379,28 @@ struct pipe_crc_info {enum pipe pipe; }; +static int i915_dp_mst_info (struct seq_file *m,void *unused) +{ +struct drm_info_node *node = (struct drm_info_node *) m->private; +struct drm_device *dev = node->minor->dev; +struct drm_encoder *encoder; +struct intel_encoder *intel_encoder; +struct intel_digital_port *intel_dig_port; +drm_modeset_lock_all (dev); +list_for_each_entry (encoder, &dev->mode_config.encoder_list, head) { + intel_encoder =to_intel_encoder (encoder); +if (intel_encoder->type !=INTEL_OUTPUT_DISPLAYPORT ) +continue ; + intel_dig_port =enc_to_dig_port (encoder); +if (!intel_dig_port->dp.can_mst) +continue ; + +drm_dp_mst_dump_topology (m, &intel_dig_port->dp.mst_mgr); + } +drm_modeset_unlock_all (dev); +return 0 ; +} +static int i915_pipe_crc_open (struct inode *inode,struct file *filep) {struct pipe_crc_info *info = inode->i_private;
@@ -3819,6 +3841,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_pc8_status", i915_pc8_status, 0}, {"i915_power_domain_info", i915_power_domain_info, 0}, {"i915_display_info", i915_display_info, 0}, + {"i915_dp_mst_info", i915_dp_mst_info, 0}, };#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
Signature · 1 line
1.9.3
Dave Airlie
maintainerPATCH 11/11 HACK: i915: avoid with fbdev init warning doesn't seem to matter
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
--- drivers/gpu/drm/i915/intel_dp_mst.c | 10 ++++++++++ drivers/gpu/drm/i915/intel_fbdev.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/intel_dp_mst.c +10 -0
@@ -346,6 +346,16 @@ 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; +int i; + +/* try and pick the enabled one if there is one - +stops intel_fbdev getting confused */ +for (i =0 ; i <I915_MAX_PIPES ; i++) { +struct intel_dp_mst_encoder *mst_enc = intel_dp->mst_encoders[i]; +if (mst_enc->base.base.crtc) { +return &intel_dp->mst_encoders[i]->base.base; + } + }return &intel_dp->mst_encoders[0 ]->base.base; }
drivers/gpu/drm/i915/intel_fbdev.c +1 -1
@@ -354,7 +354,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, connector_funcs = connector->helper_private; encoder = connector_funcs->best_encoder (connector); } -if (!encoder ||WARN_ON (!encoder->crtc)) { +if (!encoder || !encoder->crtc) {DRM_DEBUG_KMS ("connector %s has no encoder or crtc, skipping\n" , connector->name); enabled[i] = false;
Signature · 1 line
1.9.3