DisplayPort MST v0.3
Subsystems (4)
Dave Airlie
maintainerHi,
A repost of the current state of the displayport MST support for i915, mainly targetted the Lenovo docks.
Major changes since last posting:
add a path blob property for userspace to use to track topology provide reference counting, locking and lookups for branch and port structs. some DocBook!
fix i915 problems with DPMS - ordering of link bring up.
aux channel locking - this should be pushed down I think into the aux helpers,
TODO:
fbcon support:
fix non 4 lane 5.4Ghz.
fix more of state checker harder.
Dave.
Dave Airlie
maintainerPATCH 1/10 drm/dp_helper: add defines for DP 1.2 and MST support.
From: Dave Airlie <[email protected]>
This just adds the defines from the DP 1.2 spec, which we will use later.
--- include/drm/drm_dp_helper.h | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+)
include/drm/drm_dp_helper.h +78 -0
@@ -37,6 +37,7 @@* eDP: Embedded DisplayPort version 1 * DPI: DisplayPort Interoperability Guideline v1.1a * 1.2: DisplayPort 1.2 +* MST: Multistream Transport - part of DP 1.2a * * 1.2 formally includes both eDP and DPI definitions. */
@@ -103,9 +104,14 @@#define DP_TRAINING_AUX_RD_INTERVAL 0x00e/* XXX 1.2? */ /* Multiple stream transport */ +#define DP_FAUX_CAP 0x020/* 1.2 */ +# define DP_FAUX_CAP_1 (1 << 0) +#define DP_MSTM_CAP 0x021/* 1.2 */ # define DP_MST_CAP (1 << 0) +#define DP_GUID 0x030/* 1.2 */ +#define DP_PSR_SUPPORT 0x070/* XXX 1.2? */ # define DP_PSR_IS_SUPPORTED 1#define DP_PSR_CAPS 0x071/* XXX 1.2? */
@@ -221,6 +227,16 @@# define DP_PSR_CRC_VERIFICATION (1 << 2)# define DP_PSR_FRAME_CAPTURE (1 << 3) +#define DP_ADAPTER_CTRL 0x1a0 +# define DP_ADAPTER_CTRL_FORCE_LOAD_SENSE (1 << 0) + +#define DP_BRANCH_DEVICE_CTRL 0x1a1 +# define DP_BRANCH_DEVICE_IRQ_HPD (1 << 0) + +#define DP_PAYLOAD_ALLOCATE_SET 0x1c0 +#define DP_PAYLOAD_ALLOCATE_START_TIME_SLOT 0x1c1 +#define DP_PAYLOAD_ALLOCATE_TIME_SLOT_COUNT 0x1c2 +#define DP_SINK_COUNT 0x200/* prior to 1.2 bit 7 was reserved mbz */ # define DP_GET_SINK_COUNT (x) ((((x) & 0x80) >> 1) | ((x) & 0x3f))
@@ -230,6 +246,9 @@# define DP_REMOTE_CONTROL_COMMAND_PENDING (1 << 0)# define DP_AUTOMATED_TEST_REQUEST (1 << 1)# define DP_CP_IRQ (1 << 2) +# define DP_MCCS_IRQ (1 << 3) +# define DP_DOWN_REP_MSG_RDY (1 << 4)/* DP MST */ +# define DP_UP_REQ_MSG_RDY (1 << 5)/* DP MST */ # define DP_SINK_SPECIFIC_IRQ (1 << 6)#define DP_LANE0_1_STATUS 0x202
@@ -294,6 +313,13 @@#define DP_TEST_SINK 0x270#define DP_TEST_SINK_START (1 << 0) +#define DP_PAYLOAD_TABLE_UPDATE_STATUS 0x2c0/* 1.2 MST */ +# define DP_PAYLOAD_TABLE_UPDATED (1 << 0) +# define DP_PAYLOAD_ACT_HANDLED (1 << 1) + +#define DP_VC_PAYLOAD_ID_SLOT_1 0x2c1/* 1.2 MST */ +/* up to ID_SLOT_63 at 0x2ff */ +#define DP_SOURCE_OUI 0x300#define DP_SINK_OUI 0x400#define DP_BRANCH_OUI 0x500
@@ -303,6 +329,21 @@# define DP_SET_POWER_D3 0x2# define DP_SET_POWER_MASK 0x3 +#define DP_SIDEBAND_MSG_DOWN_REQ_BASE 0x1000/* 1.2 MST */ +#define DP_SIDEBAND_MSG_UP_REP_BASE 0x1200/* 1.2 MST */ +#define DP_SIDEBAND_MSG_DOWN_REP_BASE 0x1400/* 1.2 MST */ +#define DP_SIDEBAND_MSG_UP_REQ_BASE 0x1600/* 1.2 MST */ + +#define DP_SINK_COUNT_ESI 0x2002/* 1.2 */ +/* 0-5 sink count */ +# define DP_SINK_COUNT_CP_READY (1 << 6) + +#define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 0x2003/* 1.2 */ + +#define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 0x2004/* 1.2 */ + +#define DP_LINK_SERVICE_IRQ_VECTOR_ESI0 0x2005/* 1.2 */ +#define DP_PSR_ERROR_STATUS 0x2006/* XXX 1.2? */ # define DP_PSR_LINK_CRC_ERROR (1 << 0)# define DP_PSR_RFB_STORAGE_ERROR (1 << 1)
@@ -319,6 +360,43 @@# define DP_PSR_SINK_INTERNAL_ERROR 7# define DP_PSR_SINK_STATE_MASK 0x07 +/* DP 1.2 Sideband message defines */ +/* peer device type - DP 1.2a Table 2-92 */ +#define DP_PEER_DEVICE_NONE 0x0 +#define DP_PEER_DEVICE_SOURCE_OR_SST 0x1 +#define DP_PEER_DEVICE_MST_BRANCHING 0x2 +#define DP_PEER_DEVICE_SST_SINK 0x3 +#define DP_PEER_DEVICE_DP_LEGACY_CONV 0x4 + +/* DP 1.2 MST sideband request names DP 1.2a Table 2-80 */ +#define DP_LINK_ADDRESS 0x01 +#define DP_CONNECTION_STATUS_NOTIFY 0x02 +#define DP_ENUM_PATH_RESOURCES 0x10 +#define DP_ALLOCATE_PAYLOAD 0x11 +#define DP_QUERY_PAYLOAD 0x12 +#define DP_RESOURCE_STATUS_NOTIFY 0x13 +#define DP_CLEAR_PAYLOAD_ID_TABLE 0x14 +#define DP_REMOTE_DPCD_READ 0x20 +#define DP_REMOTE_DPCD_WRITE 0x21 +#define DP_REMOTE_I2C_READ 0x22 +#define DP_REMOTE_I2C_WRITE 0x23 +#define DP_POWER_UP_PHY 0x24 +#define DP_POWER_DOWN_PHY 0x25 +#define DP_SINK_EVENT_NOTIFY 0x30 +#define DP_QUERY_STREAM_ENC_STATUS 0x38 + +/* DP 1.2 MST sideband nak reasons - table 2.84 */ +#define DP_NAK_WRITE_FAILURE 0x01 +#define DP_NAK_INVALID_READ 0x02 +#define DP_NAK_CRC_FAILURE 0x03 +#define DP_NAK_BAD_PARAM 0x04 +#define DP_NAK_DEFER 0x05 +#define DP_NAK_LINK_FAILURE 0x06 +#define DP_NAK_NO_RESOURCES 0x07 +#define DP_NAK_DPCD_FAIL 0x08 +#define DP_NAK_I2C_NAK 0x09 +#define DP_NAK_ALLOCATE_FAIL 0x0a +#define MODE_I2C_START 1#define MODE_I2C_WRITE 2#define MODE_I2C_READ 4
Signature · 1 line
1.9.0
Re: [PATCH 01/10] drm/dp_helper: add defines for DP 1.2 and MST support.
Quoted 23 lines · Dave Airlie
From: Dave Airlie <[email protected]>
This just adds the defines from the DP 1.2 spec, which we will use later.
Signed-off-by Dave Airlie <[email protected]>--- include/drm/drm_dp_helper.h | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+)include/drm/drm_dp_helper.h +1
-0@@ -37,6 +37,7 @@* eDP: Embedded DisplayPort version 1 * DPI: DisplayPort Interoperability Guideline v1.1a * 1.2: DisplayPort 1.2 +* MST: Multistream Transport - part of DP 1.2a * * 1.2 formally includes both eDP and DPI definitions. */
[.....]
Quoted 3 lines
include/drm/drm_dp_helper.h +3
-0+# define DP_MCCS_IRQ (1 << 3) +# define DP_DOWN_REP_MSG_RDY (1 << 4)/* DP MST */ +# define DP_UP_REQ_MSG_RDY (1 << 5)/* DP MST */
[.....]
Quoted 2 lines
+#define
DP_PAYLOAD_TABLE_UPDATE_STATUS0x2c0/* 1.2 MST */
Hi Dave Airlie,
What is the difference between 'DP MST' and '1.2 MST'? If there is no difference, would you use the same comment as below?
+# define DP_DOWN_REP_MSG_RDY (1 << 4) /* 1.2 MST */
+# define DP_UP_REQ_MSG_RDY (1 << 5) /* 1.2 MST */
Best regards,
Jingoo Han
[.....]
Dave Airlie
maintainerPATCH 2/10 drm: add DP MST encoder type
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
This adds an encoder type for DP MST encoders.
--- drivers/gpu/drm/drm_crtc.c | 1 + include/uapi/drm/drm_mode.h | 1 + 2 files changed, 2 insertions(+)
drivers/gpu/drm/drm_crtc.c +1 -0
@@ -227,6 +227,7 @@ static const struct drm_prop_enum_list drm_encoder_enum_list[] = { DRM_MODE_ENCODER_TVDAC, "TV" }, { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, { DRM_MODE_ENCODER_DSI, "DSI" }, + { DRM_MODE_ENCODER_DPMST, "DP MST" }, }; static const struct drm_prop_enum_list drm_subpixel_enum_list[] =
include/uapi/drm/drm_mode.h +1 -0
@@ -181,6 +181,7 @@ struct drm_mode_get_plane_res {#define DRM_MODE_ENCODER_TVDAC 4#define DRM_MODE_ENCODER_VIRTUAL 5#define DRM_MODE_ENCODER_DSI 6 +#define DRM_MODE_ENCODER_DPMST 7struct drm_mode_get_encoder {__u32 encoder_id;
Signature · 1 line
1.9.0
Dave Airlie
maintainerPATCH 3/10 drm/i915: add some registers need for displayport MST support.
In reply to Dave AirlieFrom: 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
@@ -5386,6 +5386,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 */
@@ -5395,6 +5396,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)
@@ -5409,8 +5411,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.0
Dave Airlie
maintainerPATCH 4/10 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
@@ -1421,6 +1421,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
@@ -916,6 +916,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.0
Re: [PATCH 04/10] drm/crtc: add interface to reinitialise the legacy mode group
Quoted 36 lines · Dave Airlie
From: Dave Airlie <[email protected]>
This can be called to update things after dynamic connectors/encoders are created/deleted.
Signed-off-by Dave Airlie <[email protected]>--- 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@@ -1421,6 +1421,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 +0
-0
include/drm/drm_crtc.h extern const char *drm_get_tv_select_name(int val); · line 919
Quoted 4 lines
include/drm/drm_crtc.h +1
-0@@ -916,6 +916,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);
There was a patch series once to remove all usage of extern from prototypes. Was there an official decision against that which I missed, or did it just fall off the table?
Thierry
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 04/10] drm/crtc: add interface to reinitialise the legacy mode group
Quoted 37 lines · Thierry Reding
Quoted 36 lines · Dave Airlie
From: Dave Airlie <[email protected]>
This can be called to update things after dynamic connectors/encoders are created/deleted.
Signed-off-by Dave Airlie <[email protected]>--- 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@@ -1421,6 +1421,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 +0
-0@@ -916,6 +916,7 @@ extern const char *drm_get_tv_select_name(int val);
Quoted 8 lines
include/drm/drm_crtc.h extern const char *drm_get_tv_select_name(int val); · line 919
Quoted 4 lines
include/drm/drm_crtc.h +1
-0extern 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);There was a patch series once to remove all usage of extern from prototypes. Was there an official decision against that which I missed, or did it just fall off the table?
Iirc I've done that for radeon or so and we decided that it's a bikeshed. tbh I don't care, but in i915 I tend to rip them out since redundant. -Daniel
Signature · 3 lines
Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch
Dave Airlie
maintainerPATCH 5/10 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
@@ -1165,6 +1165,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)
@@ -1179,6 +1180,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 ; }
@@ -3637,6 +3644,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
@@ -500,6 +500,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 */
@@ -774,6 +776,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 */
@@ -926,6 +929,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); extern int drm_object_property_set_value(struct drm_mode_object *obj,
Signature · 1 line
1.9.0
Re: [PATCH 05/10] drm: add a path blob property
Quoted 10 lines · Dave Airlie
From: 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.
Signed-off-by Dave Airlie <[email protected]>--- drivers/gpu/drm/drm_crtc.c | 26 ++++++++++++++++++++++++++ include/drm/drm_crtc.h | 5 +++++ 2 files changed, 31 insertions(+)
The documentation for this property is missing. =)
Quoted 1 line
drivers/gpu/drm/drm_crtc.c +0
-0
[...]
drivers/gpu/drm/drm_crtc.c done: · line 3648
Quoted 2 lines
drivers/gpu/drm/drm_crtc.c +2
-0+int drm_mode_connector_set_path_property (struct drm_connector *connector, +char *path)
"const char *path"?
drivers/gpu/drm/drm_crtc.c done: · line 3652
Quoted 4 lines
drivers/gpu/drm/drm_crtc.c +4
-0+{ +struct drm_device *dev = connector->dev; +int ret, size; + size =strlen (path) +1 ;
At the risk of sounding pedantic: strlen() returns size_t, not int. But I see that drm_property_create_blob() uses int as the type for the length argument, so there's an inconsistency either way. I'll go prepare a patch to fix that inconsistency and see if anybody else is equally pedantic and willing to apply it.
Thierry
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Dave Airlie
maintainerPATCH 6/10 drm/helper: add Displayport multi-stream helper (v0.3)
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.
TODO:
misc features
--- Documentation/DocBook/drm.tmpl | 6 + drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_dp_mst_topology.c | 2536 +++++++++++++++++++++++++++++++++ include/drm/drm_dp_mst_helper.h | 503 +++++++ 4 files changed, 3046 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_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_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 +2536 -0
2,536 lines not on this page · raw message
include/drm/drm_dp_mst_helper.h new file +503 -0
444 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 6 lines
1.9.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
Part of the diff is not shown here. View the raw message.
Dave Airlie
maintainerPATCH 7/10 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 | 20 +++++++++++++------- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 14 insertions(+), 7 deletions(-)
drivers/gpu/drm/i915/intel_ddi.c +13 -7
@@ -364,6 +364,18 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)DRM_ERROR ("FDI link training failed!\n" ); } +void intel_ddi_mode_set_dp (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 void intel_ddi_mode_set (struct intel_encoder *encoder) {struct intel_crtc *crtc =to_intel_crtc (encoder->base.crtc);
@@ -378,13 +390,7 @@ static void intel_ddi_mode_set(struct intel_encoder *encoder) crtc->eld_vld = false;if (type ==INTEL_OUTPUT_DISPLAYPORT || type ==INTEL_OUTPUT_EDP ) {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); - +intel_ddi_mode_set_dp (encoder);if (intel_dp->has_audio) {DRM_DEBUG_DRIVER ("DP audio on pipe %c on DDI\n" ,pipe_name (crtc->pipe));
drivers/gpu/drm/i915/intel_drv.h +1 -0
@@ -683,6 +683,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_mode_set_dp (struct intel_encoder *encoder);/* intel_display.c */ const char *intel_output_name (int output);
Signature · 1 line
1.9.0
Dave Airlie
maintainerPATCH 8/10 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
@@ -2279,13 +2279,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
@@ -1016,6 +1016,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 &&
@@ -1046,6 +1048,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
@@ -4600,20 +4600,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.0
Dave Airlie
maintainerPATCH 9/10 i915: add DP 1.2 MST support (v0.3)
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.
b) it introduces a new MST output type.
c) it really annoys the state checker, as the connector that is connected at the start, goes into disconnected, and its encoder it active, and things blow up, need to look into how to solve that.
d) the intel userspace driver needs changes to use this, -modesetting should work okay.
e) it might contain a race condition big enough to eat you.
f) its hardcoded to 4 lanes 5.4Ghz. - TODO.
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.3
check irq status again in work handler
move around bring up and tear down to fix DPMS on/off use path properties.
TODO:
further state checker fixes
--- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_dma.c | 10 + drivers/gpu/drm/i915/i915_drv.h | 14 + drivers/gpu/drm/i915/i915_irq.c | 106 ++++++- drivers/gpu/drm/i915/intel_ddi.c | 111 +++++-- drivers/gpu/drm/i915/intel_display.c | 59 +++- drivers/gpu/drm/i915/intel_dp.c | 213 +++++++++++++- drivers/gpu/drm/i915/intel_dp_mst.c | 530 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 42 ++- drivers/gpu/drm/i915/intel_opregion.c | 1 + 10 files changed, 1041 insertions(+), 46 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_dp_mst.c
drivers/gpu/drm/i915/Makefile +1 -0
@@ -52,6 +52,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
@@ -1677,6 +1677,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);
@@ -1752,6 +1759,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);
@@ -1856,6 +1865,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.h +14 -0
@@ -1468,6 +1468,18 @@ struct drm_i915_private {struct i915_runtime_pm pm; +struct intel_digital_port *hpd_irq_port[I915_MAX_PORTS ]; +u32 hpd_port; +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;
@@ -1999,6 +2011,8 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,void valleyview_enable_display_irqs (struct drm_i915_private *dev_priv);void valleyview_disable_display_irqs (struct drm_i915_private *dev_priv); +bool intel_hpd_irq_event (struct drm_device *dev, +struct drm_connector *connector);/* i915_gem.c */ int i915_gem_init_ioctl(struct drm_device *dev, void *data,
drivers/gpu/drm/i915/i915_irq.c +102 -4
155 lines not on this page · raw message
drivers/gpu/drm/i915/intel_ddi.c +89 -22
186 lines not on this page · raw message
drivers/gpu/drm/i915/intel_display.c +43 -16
107 lines not on this page · raw message
drivers/gpu/drm/i915/intel_dp.c +210 -3
288 lines not on this page · raw message
drivers/gpu/drm/i915/intel_dp_mst.c new file +530 -0
530 lines not on this page · raw message
drivers/gpu/drm/i915/intel_drv.h +41 -1
104 lines not on this page · raw message
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.0 _______________________________________________ dri-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 09/10] i915: add DP 1.2 MST support (v0.3)
Hi Dave
Quoted 1,363 lines · Dave Airlie
From: 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.b) it introduces a new MST output type.
c) it really annoys the state checker, as the connector that is connected at the start, goes into disconnected, and its encoder it active, and things blow up, need to look into how to solve that.
d) the intel userspace driver needs changes to use this, -modesetting should work okay.
e) it might contain a race condition big enough to eat you.
f) its hardcoded to 4 lanes 5.4Ghz. - TODO.
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.3
check irq status again in work handler
move around bring up and tear down to fix DPMS on/off use path properties.TODO:
further state checker fixesSigned-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.h | 14 + drivers/gpu/drm/i915/i915_irq.c | 106 ++++++- drivers/gpu/drm/i915/intel_ddi.c | 111 +++++-- drivers/gpu/drm/i915/intel_display.c | 59 +++- drivers/gpu/drm/i915/intel_dp.c | 213 +++++++++++++- drivers/gpu/drm/i915/intel_dp_mst.c | 530 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 42 ++- drivers/gpu/drm/i915/intel_opregion.c | 1 + 10 files changed, 1041 insertions(+), 46 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_dp_mst.cdrivers/gpu/drm/i915/Makefile +1
-0@@ -52,6 +52,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@@ -1677,6 +1677,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);@@ -1752,6 +1759,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);@@ -1856,6 +1865,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.h +14
-0@@ -1468,6 +1468,18 @@ struct drm_i915_private {struct i915_runtime_pm pm; +struct intel_digital_port *hpd_irq_port[I915_MAX_PORTS ]; +u32 hpd_port; +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;@@ -1999,6 +2011,8 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,void valleyview_enable_display_irqs (struct drm_i915_private *dev_priv);void valleyview_disable_display_irqs (struct drm_i915_private *dev_priv); +bool intel_hpd_irq_event (struct drm_device *dev, +struct drm_connector *connector);/* i915_gem.c */ int i915_gem_init_ioctl(struct drm_device *dev, void *data,drivers/gpu/drm/i915/i915_irq.c +102
-4@@ -963,8 +963,8 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, &to_intel_crtc(crtc)->config.adjusted_mode); } -static bool intel_hpd_irq_event (struct drm_device *dev, -struct drm_connector *connector) +bool intel_hpd_irq_event (struct drm_device *dev, +struct drm_connector *connector) {enum drm_connector_status old_status;@@ -984,6 +984,71 @@ static bool intel_hpd_irq_event(struct drm_device *dev,return true; } +static int port_to_hotplug_shift (enum port port) +{ +switch (port) { +case PORT_A : +case PORT_E : +default : +return -1 ; +case PORT_B : +return 0 ; +case PORT_C : +return 8 ; +case PORT_D : +return 16 ; + } +} +static void i915_digport_work_func (struct work_struct *work) +{ +struct drm_i915_private *dev_priv = + container_of(work, struct drm_i915_private, dig_port_work); +unsigned long irqflags; +u32 port_bits; +struct intel_digital_port *digport; +int i, ret; +u32 old_bits =0 ; +u32 hotplug_reg, hpshift; +bool long_hpd = false; +spin_lock_irqsave (&dev_priv->irq_lock, irqflags); + port_bits = dev_priv->hpd_port; + dev_priv->hpd_port =0 ; + + hotplug_reg =I915_READ (PCH_PORT_HOTPLUG ); +I915_WRITE (PCH_PORT_HOTPLUG , hotplug_reg); + +spin_unlock_irqrestore (&dev_priv->irq_lock, irqflags); + +for (i =0 ; i <I915_MAX_PORTS ; i++) { +if (port_bits & (1 << i)) { + digport = dev_priv->hpd_irq_port[i]; + + hpshift =port_to_hotplug_shift (i); + +/* if we have no HPD bits for this */ +if (!((hotplug_reg >> hpshift) &PORTB_HOTPLUG_STATUS_MASK )) { +DRM_DEBUG_KMS ("got not regs for port %d %08x\n" , i, hotplug_reg); +continue ; + } + + long_hpd = (hotplug_reg >> hpshift) &PORTB_HOTPLUG_LONG_DETECT ; + + ret =intel_dp_handle_hpd_irq (digport, long_hpd); +if (ret ==1 ) { +/* if we get 1 fallback to old school hpd */ + old_bits |= (1 << digport->base.hpd_pin); + } + } + } + +if (old_bits) { +spin_lock_irqsave (&dev_priv->irq_lock, irqflags); + dev_priv->hpd_event_bits = old_bits; +spin_unlock_irqrestore (&dev_priv->irq_lock, irqflags); +schedule_work (&dev_priv->hotplug_work); + } +} +/* * Handle hotplug events outside the interrupt handler proper. */ @@ -1381,14 +1446,29 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,#define HPD_STORM_DETECT_PERIOD 1000#define HPD_STORM_THRESHOLD 5 +static inline enum port get_port_from_pin (enum hpd_pin pin) +{ +switch (pin) { +case HPD_PORT_B : +return PORT_B ; +case HPD_PORT_C : +return PORT_C ; +case HPD_PORT_D : +return PORT_D ; +default : +return PORT_A ;/* no hpd */ + } +} +static inline void intel_hpd_irq_handler (struct drm_device *dev,u32 hotplug_trigger,const u32 *hpd) {struct drm_i915_private *dev_priv = dev->dev_private;int i; +enum port port;bool storm_detected = false; - +bool queue_dig = false, queue_hp = false;if (!hotplug_trigger)return ;@@ -1397,6 +1477,19 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,spin_lock (&dev_priv->irq_lock);for (i =1 ; i <HPD_NUM_PINS ; i++) { +if (!(hpd[i] & hotplug_trigger)) +continue ; + + port =get_port_from_pin (i); +if (port && dev_priv->hpd_irq_port[port]) { +DRM_DEBUG_DRIVER ("digital hpd port %d\n" , port); + dev_priv->hpd_port |= (1 << port); + hotplug_trigger &= ~hpd[i]; + queue_dig = true; + } + } + +for (i =1 ; i <HPD_NUM_PINS ; i++) {if (hpd[i] & hotplug_trigger && dev_priv->hpd_stats[i].hpd_mark ==HPD_DISABLED ) {@@ -1418,6 +1511,7 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,continue ; dev_priv->hpd_event_bits |= (1 << i); + queue_hp = true;if (!time_in_range (jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies +msecs_to_jiffies (HPD_STORM_DETECT_PERIOD ))) {@@ -1446,7 +1540,10 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,* queue for otherwise the flush_work in the pageflip code will * deadlock. */ -schedule_work (&dev_priv->hotplug_work); +if (queue_dig) +queue_work (dev_priv->dp_wq, &dev_priv->dig_port_work); +if (queue_hp) +schedule_work (&dev_priv->hotplug_work); }static void gmbus_irq_handler (struct drm_device *dev)@@ -4014,6 +4111,7 @@ void intel_irq_init(struct drm_device *dev) {struct drm_i915_private *dev_priv = dev->dev_private; +INIT_WORK (&dev_priv->dig_port_work, i915_digport_work_func);INIT_WORK (&dev_priv->hotplug_work, i915_hotplug_work_func);INIT_WORK (&dev_priv->gpu_error.work, i915_error_work_func);INIT_WORK (&dev_priv->rps.work, gen6_pm_rps_work);drivers/gpu/drm/i915/intel_ddi.c +89
-22@@ -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);@@ -211,6 +214,19 @@ void intel_prepare_ddi(struct drm_device *dev)intel_prepare_ddi_buffers (dev, port); } +void intel_ddi_force_act (struct intel_encoder *encoder,bool state) +{ +struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; +enum port port =intel_ddi_get_encoder_port (encoder); +u32 val; + val =I915_READ (DP_TP_CTL (port)); +if (state == true) + val |=DP_TP_CTL_FORCE_ACT ; +else + val &= ~DP_TP_CTL_FORCE_ACT ; +I915_WRITE (DP_TP_CTL (port), val); +} +static const long hsw_ddi_buf_ctl_values[] = {DDI_BUF_EMP_400MV_0DB_HSW ,DDI_BUF_EMP_400MV_3_5DB_HSW ,@@ -673,8 +689,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);@@ -795,6 +811,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 @@ -814,20 +844,19 @@ 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); -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;@@ -981,8 +1010,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 :@@ -1004,6 +1032,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);@@ -1083,7 +1126,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 {@@ -1100,7 +1155,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); }@@ -1160,6 +1215,11 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,u32 tmp;int i; +if (encoder->type ==INTEL_OUTPUT_DISPLAYPORT ) { +if (enc_to_intel_dp (&encoder->base)->is_mst) +return false; + } + power_domain =intel_display_port_power_domain (encoder);if (!intel_display_power_enabled (dev_priv, power_domain))return false;@@ -1498,10 +1558,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));@@ -1732,6 +1797,8 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->cloneable =0 ; intel_encoder->hot_plug = intel_ddi_hot_plug; + dev_priv->hpd_irq_port[port] = intel_dig_port; +if (init_dp) dp_connector =intel_ddi_init_dp_connector (intel_dig_port);drivers/gpu/drm/i915/intel_display.c +43
-16@@ -56,6 +56,14 @@ static int intel_framebuffer_init(struct drm_device *dev,struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj); +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 ;@@ -3821,6 +3829,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);@@ -3869,6 +3880,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)@@ -4038,6 +4052,23 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc)for ((domain) =0 ; (domain) <POWER_DOMAIN_NUM ; (domain)++) \if ((1 << (domain)) & (mask)) +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 ; + } +} +enum intel_display_power_domain intel_display_port_power_domain (struct intel_encoder *intel_encoder) {@@ -4052,19 +4083,10 @@ 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_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 :@@ -10203,7 +10225,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 ; } }@@ -10249,7 +10271,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,@@ -10283,7 +10305,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; + }list_for_each_entry (crtc, &dev->mode_config.crtc_list, base.head) { crtc->new_enabled = false;drivers/gpu/drm/i915/intel_dp.c +210
-3@@ -701,8 +701,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); }@@ -2892,6 +2893,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);@@ -2929,6 +2957,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,4 ); +if (ret !=4 ) +return false; + +return true; +} +static void intel_dp_handle_test_request (struct intel_dp *intel_dp) {@@ -2944,6 +2986,65 @@ 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 */ +static int +intel_dp_check_mst_status (struct intel_dp *intel_dp) +{ +int send_event =0 ; +bool bret; +if (intel_dp->is_mst) { +u8 esi[4 ] = {0 }; +int ret =0 ; +int retry; + +mutex_lock (&intel_dp->mst_mgr.aux_lock); + bret =intel_dp_get_sink_irq_esi (intel_dp, esi); +mutex_unlock (&intel_dp->mst_mgr.aux_lock); + go_again: +if (bret == true) { +DRM_DEBUG_KMS ("got esi %02x %02x %02x\n" , esi[0 ], esi[1 ], esi[2 ]); +if (esi[1 ] & (DP_UP_REQ_MSG_RDY |DP_DOWN_REP_MSG_RDY )) { + ret =drm_dp_mst_hpd_irq (&intel_dp->mst_mgr, esi[1 ]); +if (ret ==1 ) + send_event =1 ; + }else + ret =0 ; + send_event |= ret; +mutex_lock (&intel_dp->mst_mgr.aux_lock); +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 ; + } + } +mutex_unlock (&intel_dp->mst_mgr.aux_lock); + +mutex_lock (&intel_dp->mst_mgr.aux_lock); + bret =intel_dp_get_sink_irq_esi (intel_dp, esi); +mutex_unlock (&intel_dp->mst_mgr.aux_lock); +if (bret == true) { +DRM_DEBUG_KMS ("got esi2 %02x %02x %02x\n" , esi[0 ], esi[1 ], esi[2 ]); +if (esi[1 ] & (DP_UP_REQ_MSG_RDY |DP_DOWN_REP_MSG_RDY )) { + goto go_again; + } + } + +if (ret ==0 && send_event) +return 1 ; +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_sysfs_hotplug_event (intel_dig_port->base.base.dev); + } + } +return -EINVAL ; +}void intel_dp_check_link_status (struct intel_dp *intel_dp)@@ -3163,6 +3264,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);@@ -3172,6 +3274,12 @@ intel_dp_detect(struct drm_connector *connector, bool force)DRM_DEBUG_KMS ("[CONNECTOR:%d:%s]\n" , connector->base.id,drm_get_connector_name (connector)); +if (intel_dp->is_mst) { +/* MST devices are disconnected from a monitor POV */ + status = connector_status_disconnected; + goto out; + } + intel_dp->has_audio = false;if (HAS_PCH_SPLIT (dev))@@ -3184,6 +3292,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 {@@ -3379,6 +3497,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)struct drm_device *dev =intel_dp_to_dev (intel_dp);drm_dp_aux_unregister_i2c_bus (&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);@@ -3463,7 +3582,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);@@ -3959,6 +4078,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_i2c_bus (&intel_dp->aux);if (is_edp (intel_dp)) {@@ -3989,6 +4115,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,void intel_dp_init (struct drm_device *dev,int output_reg,enum port port) { +struct drm_i915_private *dev_priv = dev->dev_private;struct intel_digital_port *intel_dig_port;struct intel_encoder *intel_encoder;struct drm_encoder *encoder;@@ -4029,6 +4156,10 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_dig_port->port = port; intel_dig_port->dp.output_reg = output_reg; +/* for now only use new IRQ handling for MST capable ports */ +if (intel_dig_port->dp.can_mst) + dev_priv->hpd_irq_port[port] = intel_dig_port; + intel_encoder->type =INTEL_OUTPUT_DISPLAYPORT ; intel_encoder->crtc_mask = (1 <<0 ) | (1 <<1 ) | (1 <<2 ); intel_encoder->cloneable =0 ;@@ -4040,3 +4171,79 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)kfree (intel_connector); } } + +/* +* Handle DP IRQ close to spec recommendations +* Use hw to detect long vs short pulses +* +* If we get a long pulse - we need to read DPCD first +* If we get a short pulse - we need to check link irq/status +* returning 1 causes the old detect to happen for HDMI +*/ +int intel_dp_handle_hpd_irq (struct intel_digital_port *intel_dig_port, +bool hpd_long) +{ +struct intel_dp *intel_dp = &intel_dig_port->dp; +struct drm_device *dev = intel_dig_port->base.base.dev; +struct drm_mode_config *mode_config = &dev->mode_config; +struct drm_connector *connector; +struct intel_connector *intel_connector; +bool changed = false; +int ret; + +if (!intel_dp->output_reg) +return 1 ; + +DRM_DEBUG_KMS ("got hpd irq on port %d - %s\n" , intel_dig_port->port, + hpd_long ?"long" :"short" ); +/* we have to re-read DPCD only on a long irq */ +if (hpd_long) { +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; + } + +if (intel_dp->is_mst) { + ret =intel_dp_check_mst_status (intel_dp); +if (ret == -EINVAL ) +return 1 ; + }else { +intel_dp_check_link_status (intel_dp); +return 1 ; + } + +if (ret ==1 ) { +mutex_lock (&mode_config->mutex); + +/* send the something changed event for the correct port */ +list_for_each_entry (connector, &mode_config->connector_list, head) { + intel_connector =to_intel_connector (connector); +if (!intel_connector->mst_port) +continue ; + +if (intel_connector->mst_port != intel_dp) +continue ; + +if (intel_hpd_irq_event (dev, connector)) + changed = true; + } +mutex_unlock (&mode_config->mutex); +if (changed) +drm_kms_helper_hotplug_event (dev); + } +return 0 ; + +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 ("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); +drm_sysfs_hotplug_event (dev); + } +return 1 ; +}drivers/gpu/drm/i915/intel_dp_mst.c new file +433
-0@@ -0,0 +1,530 @@ +/* +* 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 ; + lane_count =4 ; + intel_dp->link_bw =DP_LINK_BW_5_4 ; + 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_dp_mst_mode_set (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; + +intel_ddi_mode_set_dp (&intel_dig_port->base); +} + +static void intel_mst_disable_dp (struct intel_encoder *encoder) +{ +struct intel_dp_mst_encoder *intel_mst =enc_to_mst (&encoder->base); +struct intel_connector *found =NULL , *intel_connector; +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 ret; + +DRM_DEBUG_KMS ("%d\n" , intel_dp->active_mst_links); +list_for_each_entry (intel_connector, &dev->mode_config.connector_list, base.head) { +if (intel_connector->encoder == encoder) { + found = intel_connector; +break ; + } + } + +if (!found) +return ; + +drm_dp_mst_reset_vcpi_slots (&intel_dp->mst_mgr, found->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; +struct intel_connector *found =NULL , *intel_connector; +struct drm_device *dev = encoder->base.dev; +int ret; +DRM_DEBUG_KMS ("%d\n" , intel_dp->active_mst_links); + +list_for_each_entry (intel_connector, &dev->mode_config.connector_list, base.head) { +if (intel_connector->encoder == encoder) { + found = intel_connector; +break ; + } + } + +if (!found) +return ; + + ret =drm_dp_check_act_status (&intel_dp->mst_mgr); +if (ret) +DRM_ERROR ("failed to check ACT status\n" ); + ret =drm_dp_update_payload_part2 (&intel_dp->mst_mgr); +if (ret) +DRM_ERROR ("failed to update payloads.\n" ); + +drm_dp_mst_deallocate_vcpi (&intel_dp->mst_mgr, found->port); + + intel_dp->active_mst_links--; +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); +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_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, + found->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; +return encoder->connectors_active; +} + +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) +{ +WARN_ON (1 ); +return NULL ; +} + +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) +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 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); +drm_sysfs_connector_add (&intel_connector->base); +return connector; +} + +static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
drivers/gpu/drm/i915/intel_dp_mst.c line 443
Quoted 10 lines
drivers/gpu/drm/i915/intel_dp_mst.c new file +10
-0+ struct drm_connector *connector) +{ +struct intel_connector *intel_connector =to_intel_connector (connector); +struct drm_device *dev = connector->dev; +/* need to nuke the connector */ +mutex_lock (&dev->mode_config.mutex); + intel_connector->unregister (intel_connector); +drm_connector_cleanup (connector); +mutex_unlock (&dev->mode_config.mutex); +drm_reinit_primary_mode_group (dev);
So we leak all dynamically created objects? There's no kfree(intel_connector) here and we cannot add it because drm_mode_object_find() is not ref-counted. So we keep the connector in the mode_group and wait until the final drm_mode_config_cleanup()? But drm_connector_cleanup() already removes the connector from the mode-group, so we eventually leak the object.
I guess you already know that dynamic DRM objects are fragile. Adding new objects is fine, but removing them is troublesome. A quick and easy fix would be to retain destroyed objects in the mode-group but mark them dead. When adding new objects, we can simply reuse them in case we have some left. Not sure, whether that's better than leaking the object, though.
Thanks
David
Quoted 220 lines
drivers/gpu/drm/i915/intel_dp_mst.c new file +87
-0+ +DRM_DEBUG_KMS ("\n" ); +} + +struct drm_dp_mst_topology_cbs mst_cbs = { + .add_connector = intel_dp_add_mst_connector, + .destroy_connector = intel_dp_destroy_mst_connector, +}; + +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->mode_set = intel_dp_mst_mode_set; + 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 +41
-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 {@@ -340,6 +345,9 @@ struct intel_crtc_config {bool ips_enabled;bool double_wide; + +bool dp_encoder_is_mst; +int pbn; };struct intel_pipe_wm {@@ -487,6 +495,7 @@ struct intel_hdmi { struct drm_display_mode *adjusted_mode); }; +struct intel_dp_mst_encoder ;#define DP_MAX_DOWNSTREAM_PORTS 0x10/** @@ -527,8 +536,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 @@ -554,6 +572,12 @@ struct intel_digital_port {struct intel_hdmi hdmi; }; +struct intel_dp_mst_encoder { +struct intel_encoder base; +enum pipe pipe; +struct intel_digital_port *primary; +}; +static inline int vlv_dport_to_channel (struct intel_digital_port *dport) {@@ -621,6 +645,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;@@ -684,6 +714,10 @@ void intel_ddi_get_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config);void intel_ddi_mode_set_dp (struct intel_encoder *encoder); +void intel_ddi_clock_get (struct intel_encoder *encoder, +struct intel_crtc_config *pipe_config); +void intel_ddi_force_act (struct intel_encoder *encoder,bool state); +void intel_ddi_set_vc_payload_alloc (struct drm_crtc *crtc,bool state);/* intel_display.c */ const char *intel_output_name (int output);@@ -800,6 +834,12 @@ void intel_edp_psr_disable(struct intel_dp *intel_dp);void intel_edp_psr_update (struct drm_device *dev);void intel_dp_set_drrs_state (struct drm_device *dev,int refresh_rate); +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); + +/* 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_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.0
Quoted 4 lines
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
Dave Airlie
maintainerRe: [PATCH 09/10] i915: add DP 1.2 MST support (v0.3)
Quoted 8 lines
So we leak all dynamically created objects? There's no
kfree(intel_connector)here and we cannot add it becausedrm_mode_object_find()is not ref-counted. So we keep the connector in themode_groupand wait until the finaldrm_mode_config_cleanup()? Butdrm_connector_cleanup()already removes the connector from the mode-group, so we eventually leak the object.
Seems like freeing it should be fine, it was just an oversight,
Since any objects you get with find are only valid under mode_config.mutex, yes some drivers mess this up, but they should be fixed.
Dave.
Re: [PATCH 09/10] i915: add DP 1.2 MST support (v0.3)
Hi
Quoted 2 lines · Dave Airlie
Since any objects you get with find are only valid under mode_config.mutex, yes some drivers mess this up, but they should be fixed.
Didn't know that we have such a rule. Then it's fine, of course. The page-flip code is what worried me, but drivers ought to cancel that when destroying connectors, anyway.
Thanks
David
Re: [PATCH 09/10] i915: add DP 1.2 MST support (v0.3)
Quoted 9 lines · David Herrmann
Hi
Quoted 2 lines · Dave Airlie
Since any objects you get with find are only valid under mode_config.mutex, yes some drivers mess this up, but they should be fixed.
Didn't know that we have such a rule. Then it's fine, of course. The page-flip code is what worried me, but drivers ought to cancel that when destroying connectors, anyway.
i915 cancels/stalls for any pageflips when we switch off the crtc, so I think we should be fine.
And the above rule is for all modeset objects except framebuffers, since those are separately protected with refcounting and you don't even need the big mode_config mutex to do the idr lookup.
-Daniel
Signature · 3 lines
Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch
Dave Airlie
maintainerPATCH 10/10 i915: mst topology dumper in debugfs
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
use the mst helper code to dump the topology in debugfs.
--- drivers/gpu/drm/i915/i915_debugfs.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
drivers/gpu/drm/i915/i915_debugfs.c +26 -0
@@ -2378,6 +2378,31 @@ 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 ; + +if (!intel_dig_port->dp.is_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;
@@ -3813,6 +3838,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.0
Re: [PATCH 10/10] i915: mst topology dumper in debugfs
On Mon, May 12, 2014 at 04:46:47PM +1000, Dave Airlie wrote:
[...]
drivers/gpu/drm/i915/i915_debugfs.c static const struct drm_info_list i915_debugfs_list[] = { · line 3841
Quoted 5 lines
drivers/gpu/drm/i915/i915_debugfs.c +1
-0@@ -3813,6 +3838,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},
This isn't really specific to this patch, but I've been thinking for a while if perhaps it would be a good idea to try to unify debugfs across drivers to some degree. What I mean by that is try to use common names for files with similar functionality. Off the top of my head I think a couple of drivers expose a list of framebuffers via debugfs, mostly using duplicated code and different file names. Sharing the code would of course be easy, but I think there may be some advantage to keeping the names consistent as well.
Given its generic nature, MST sounds like a good candidate as well.
Thierry
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 10/10] i915: mst topology dumper in debugfs
Quoted 16 lines · Thierry Reding
On Mon, May 12, 2014 at 04:46:47PM +1000, Dave Airlie wrote:
[...]drivers/gpu/drm/i915/i915_debugfs.c static const struct drm_info_list i915_debugfs_list[] = { · line 3841
Quoted 5 lines
drivers/gpu/drm/i915/i915_debugfs.c +1
-0@@ -3813,6 +3838,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},This isn't really specific to this patch, but I've been thinking for a while if perhaps it would be a good idea to try to unify debugfs across drivers to some degree. What I mean by that is try to use common names for files with similar functionality. Off the top of my head I think a couple of drivers expose a list of framebuffers via debugfs, mostly using duplicated code and different file names. Sharing the code would of course be easy, but I think there may be some advantage to keeping the names consistent as well.
Imo our current approach of having seq_file helpers in libraries that drivers can use works well. At least with i915 we often want to add some more driver-private state to dumps (e.g. for framebuffers), so extracting more than what's already extracted is probably hard to do.
But I guess we could add some common files with e.g. just the core framebuffer stuff to all drivers. Not terribly motivated myself though since i915 has it all already ;-)
-Daniel
Signature · 3 lines
Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch
Re: [PATCH 10/10] i915: mst topology dumper in debugfs
Quoted 18 lines · Daniel Vetter
Quoted 16 lines · Thierry Reding
On Mon, May 12, 2014 at 04:46:47PM +1000, Dave Airlie wrote:
[...]drivers/gpu/drm/i915/i915_debugfs.c static const struct drm_info_list i915_debugfs_list[] = { · line 3841
Quoted 5 lines
drivers/gpu/drm/i915/i915_debugfs.c +1
-0@@ -3813,6 +3838,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},This isn't really specific to this patch, but I've been thinking for a while if perhaps it would be a good idea to try to unify debugfs across drivers to some degree. What I mean by that is try to use common names for files with similar functionality. Off the top of my head I think a couple of drivers expose a list of framebuffers via debugfs, mostly using duplicated code and different file names. Sharing the code would of course be easy, but I think there may be some advantage to keeping the names consistent as well.
Quoted 4 lines
Imo our current approach of having
seq_filehelpers in libraries that drivers can use works well. At least with i915 we often want to add some more driver-private state to dumps (e.g. for framebuffers), so extracting more than what's already extracted is probably hard to do.
Good point.
Quoted 3 lines
But I guess we could add some common files with e.g. just the core framebuffer stuff to all drivers. Not terribly motivated myself though since i915 has it all already ;-)
I was thinking it would be convenient if there was some consistency between the debugfs interfaces of the various drivers to make it easier for people to find equivalent information sources. On second thought maybe that's not such a useful idea after all since some of the files may expose similar, but not exactly the same, information, given that some of it may be driver-specific.
Thierry
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Dave Airlie
maintainerQuoted 4 lines · Dave Airlie
Hi,
A repost of the current state of the displayport MST support for i915, mainly targetted the Lenovo docks.
Also in git at
http://cgit.freedesktop.org/~airlied/linux/log/?h=drm-i915-mst-support
Dave.