diff options
author | Dave Airlie <airlied@redhat.com> | 2014-12-08 18:58:51 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-12-08 18:58:51 -0500 |
commit | d1b8792b636f83804add26ec1ac90a686be19e49 (patch) | |
tree | dd12f04f8e18574f134a66bd8ceb93fbf5109606 | |
parent | b75478d1c7e4758abcf15c8494d70d4dc4dcb553 (diff) | |
parent | b0ee9e7fa5b461a91f24d1d03b10c6bf162c86f9 (diff) |
Merge branch 'drm-mst-next' of ssh://people.freedesktop.org/~/linux into drm-next
Merge mst tiling patches and MST fixes
* 'drm-mst-next' of ssh://people.freedesktop.org/~/linux:
drm/fb: add support for tiled monitor configurations. (v2)
drm/tile: expose the tile property to userspace (v3)
drm/connector: store tile information from displayid (v3)
drm/mst: cached EDID for logical ports (v2)
drm: add tile_group support. (v3)
drm/displayid: add displayid defines and edid extension (v2)
drm/dp-mst: Remove branches before dropping the reference
drm/fb_helper: move deferred fb checking into restore mode (v2)
drm/dp: retry AUX transactions 32 times (v1.1)
-rw-r--r-- | Documentation/DocBook/drm.tmpl | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 155 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_dp_helper.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_dp_mst_topology.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 144 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 134 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp_mst.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_fbdev.c | 24 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 38 | ||||
-rw-r--r-- | include/drm/drm_displayid.h | 76 | ||||
-rw-r--r-- | include/drm/drm_dp_mst_helper.h | 4 | ||||
-rw-r--r-- | include/drm/drm_edid.h | 2 | ||||
-rw-r--r-- | include/drm/drm_fb_helper.h | 6 |
13 files changed, 593 insertions, 39 deletions
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 56e2a9b65c68..60c1063d4178 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl | |||
@@ -2412,6 +2412,10 @@ void intel_crt_init(struct drm_device *dev) | |||
2412 | !Edrivers/gpu/drm/drm_plane_helper.c | 2412 | !Edrivers/gpu/drm/drm_plane_helper.c |
2413 | !Pdrivers/gpu/drm/drm_plane_helper.c overview | 2413 | !Pdrivers/gpu/drm/drm_plane_helper.c overview |
2414 | </sect2> | 2414 | </sect2> |
2415 | <sect2> | ||
2416 | <title>Tile group</title> | ||
2417 | !Pdrivers/gpu/drm/drm_crtc.c Tile group | ||
2418 | </sect2> | ||
2415 | </sect1> | 2419 | </sect1> |
2416 | 2420 | ||
2417 | <!-- Internals: kms properties --> | 2421 | <!-- Internals: kms properties --> |
@@ -2547,7 +2551,7 @@ void intel_crt_init(struct drm_device *dev) | |||
2547 | </tr> | 2551 | </tr> |
2548 | <tr> | 2552 | <tr> |
2549 | <td rowspan="23" valign="top" >DRM</td> | 2553 | <td rowspan="23" valign="top" >DRM</td> |
2550 | <td rowspan="3" valign="top" >Generic</td> | 2554 | <td rowspan="4" valign="top" >Generic</td> |
2551 | <td valign="top" >“EDID”</td> | 2555 | <td valign="top" >“EDID”</td> |
2552 | <td valign="top" >BLOB | IMMUTABLE</td> | 2556 | <td valign="top" >BLOB | IMMUTABLE</td> |
2553 | <td valign="top" >0</td> | 2557 | <td valign="top" >0</td> |
@@ -2569,6 +2573,13 @@ void intel_crt_init(struct drm_device *dev) | |||
2569 | <td valign="top" >Contains topology path to a connector.</td> | 2573 | <td valign="top" >Contains topology path to a connector.</td> |
2570 | </tr> | 2574 | </tr> |
2571 | <tr> | 2575 | <tr> |
2576 | <td valign="top" >“TILE”</td> | ||
2577 | <td valign="top" >BLOB | IMMUTABLE</td> | ||
2578 | <td valign="top" >0</td> | ||
2579 | <td valign="top" >Connector</td> | ||
2580 | <td valign="top" >Contains tiling information for a connector.</td> | ||
2581 | </tr> | ||
2582 | <tr> | ||
2572 | <td rowspan="1" valign="top" >Plane</td> | 2583 | <td rowspan="1" valign="top" >Plane</td> |
2573 | <td valign="top" >“type”</td> | 2584 | <td valign="top" >“type”</td> |
2574 | <td valign="top" >ENUM | IMMUTABLE</td> | 2585 | <td valign="top" >ENUM | IMMUTABLE</td> |
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index de79283eaea7..4a44f894f631 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -908,6 +908,11 @@ void drm_connector_cleanup(struct drm_connector *connector) | |||
908 | struct drm_device *dev = connector->dev; | 908 | struct drm_device *dev = connector->dev; |
909 | struct drm_display_mode *mode, *t; | 909 | struct drm_display_mode *mode, *t; |
910 | 910 | ||
911 | if (connector->tile_group) { | ||
912 | drm_mode_put_tile_group(dev, connector->tile_group); | ||
913 | connector->tile_group = NULL; | ||
914 | } | ||
915 | |||
911 | list_for_each_entry_safe(mode, t, &connector->probed_modes, head) | 916 | list_for_each_entry_safe(mode, t, &connector->probed_modes, head) |
912 | drm_mode_remove(connector, mode); | 917 | drm_mode_remove(connector, mode); |
913 | 918 | ||
@@ -1339,6 +1344,11 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) | |||
1339 | "PATH", 0); | 1344 | "PATH", 0); |
1340 | dev->mode_config.path_property = dev_path; | 1345 | dev->mode_config.path_property = dev_path; |
1341 | 1346 | ||
1347 | dev->mode_config.tile_property = drm_property_create(dev, | ||
1348 | DRM_MODE_PROP_BLOB | | ||
1349 | DRM_MODE_PROP_IMMUTABLE, | ||
1350 | "TILE", 0); | ||
1351 | |||
1342 | return 0; | 1352 | return 0; |
1343 | } | 1353 | } |
1344 | 1354 | ||
@@ -4083,6 +4093,52 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector, | |||
4083 | EXPORT_SYMBOL(drm_mode_connector_set_path_property); | 4093 | EXPORT_SYMBOL(drm_mode_connector_set_path_property); |
4084 | 4094 | ||
4085 | /** | 4095 | /** |
4096 | * drm_mode_connector_set_tile_property - set tile property on connector | ||
4097 | * @connector: connector to set property on. | ||
4098 | * | ||
4099 | * This looks up the tile information for a connector, and creates a | ||
4100 | * property for userspace to parse if it exists. The property is of | ||
4101 | * the form of 8 integers using ':' as a separator. | ||
4102 | * | ||
4103 | * Returns: | ||
4104 | * Zero on success, errno on failure. | ||
4105 | */ | ||
4106 | int drm_mode_connector_set_tile_property(struct drm_connector *connector) | ||
4107 | { | ||
4108 | struct drm_device *dev = connector->dev; | ||
4109 | int ret, size; | ||
4110 | char tile[256]; | ||
4111 | |||
4112 | if (connector->tile_blob_ptr) | ||
4113 | drm_property_destroy_blob(dev, connector->tile_blob_ptr); | ||
4114 | |||
4115 | if (!connector->has_tile) { | ||
4116 | connector->tile_blob_ptr = NULL; | ||
4117 | ret = drm_object_property_set_value(&connector->base, | ||
4118 | dev->mode_config.tile_property, 0); | ||
4119 | return ret; | ||
4120 | } | ||
4121 | |||
4122 | snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", | ||
4123 | connector->tile_group->id, connector->tile_is_single_monitor, | ||
4124 | connector->num_h_tile, connector->num_v_tile, | ||
4125 | connector->tile_h_loc, connector->tile_v_loc, | ||
4126 | connector->tile_h_size, connector->tile_v_size); | ||
4127 | size = strlen(tile) + 1; | ||
4128 | |||
4129 | connector->tile_blob_ptr = drm_property_create_blob(connector->dev, | ||
4130 | size, tile); | ||
4131 | if (!connector->tile_blob_ptr) | ||
4132 | return -EINVAL; | ||
4133 | |||
4134 | ret = drm_object_property_set_value(&connector->base, | ||
4135 | dev->mode_config.tile_property, | ||
4136 | connector->tile_blob_ptr->base.id); | ||
4137 | return ret; | ||
4138 | } | ||
4139 | EXPORT_SYMBOL(drm_mode_connector_set_tile_property); | ||
4140 | |||
4141 | /** | ||
4086 | * drm_mode_connector_update_edid_property - update the edid property of a connector | 4142 | * drm_mode_connector_update_edid_property - update the edid property of a connector |
4087 | * @connector: drm connector | 4143 | * @connector: drm connector |
4088 | * @edid: new value of the edid property | 4144 | * @edid: new value of the edid property |
@@ -5152,6 +5208,7 @@ void drm_mode_config_init(struct drm_device *dev) | |||
5152 | INIT_LIST_HEAD(&dev->mode_config.property_blob_list); | 5208 | INIT_LIST_HEAD(&dev->mode_config.property_blob_list); |
5153 | INIT_LIST_HEAD(&dev->mode_config.plane_list); | 5209 | INIT_LIST_HEAD(&dev->mode_config.plane_list); |
5154 | idr_init(&dev->mode_config.crtc_idr); | 5210 | idr_init(&dev->mode_config.crtc_idr); |
5211 | idr_init(&dev->mode_config.tile_idr); | ||
5155 | 5212 | ||
5156 | drm_modeset_lock_all(dev); | 5213 | drm_modeset_lock_all(dev); |
5157 | drm_mode_create_standard_connector_properties(dev); | 5214 | drm_mode_create_standard_connector_properties(dev); |
@@ -5239,6 +5296,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
5239 | crtc->funcs->destroy(crtc); | 5296 | crtc->funcs->destroy(crtc); |
5240 | } | 5297 | } |
5241 | 5298 | ||
5299 | idr_destroy(&dev->mode_config.tile_idr); | ||
5242 | idr_destroy(&dev->mode_config.crtc_idr); | 5300 | idr_destroy(&dev->mode_config.crtc_idr); |
5243 | drm_modeset_lock_fini(&dev->mode_config.connection_mutex); | 5301 | drm_modeset_lock_fini(&dev->mode_config.connection_mutex); |
5244 | } | 5302 | } |
@@ -5261,3 +5319,100 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev, | |||
5261 | supported_rotations); | 5319 | supported_rotations); |
5262 | } | 5320 | } |
5263 | EXPORT_SYMBOL(drm_mode_create_rotation_property); | 5321 | EXPORT_SYMBOL(drm_mode_create_rotation_property); |
5322 | |||
5323 | /** | ||
5324 | * DOC: Tile group | ||
5325 | * | ||
5326 | * Tile groups are used to represent tiled monitors with a unique | ||
5327 | * integer identifier. Tiled monitors using DisplayID v1.3 have | ||
5328 | * a unique 8-byte handle, we store this in a tile group, so we | ||
5329 | * have a common identifier for all tiles in a monitor group. | ||
5330 | */ | ||
5331 | static void drm_tile_group_free(struct kref *kref) | ||
5332 | { | ||
5333 | struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); | ||
5334 | struct drm_device *dev = tg->dev; | ||
5335 | mutex_lock(&dev->mode_config.idr_mutex); | ||
5336 | idr_remove(&dev->mode_config.tile_idr, tg->id); | ||
5337 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
5338 | kfree(tg); | ||
5339 | } | ||
5340 | |||
5341 | /** | ||
5342 | * drm_mode_put_tile_group - drop a reference to a tile group. | ||
5343 | * @dev: DRM device | ||
5344 | * @tg: tile group to drop reference to. | ||
5345 | * | ||
5346 | * drop reference to tile group and free if 0. | ||
5347 | */ | ||
5348 | void drm_mode_put_tile_group(struct drm_device *dev, | ||
5349 | struct drm_tile_group *tg) | ||
5350 | { | ||
5351 | kref_put(&tg->refcount, drm_tile_group_free); | ||
5352 | } | ||
5353 | |||
5354 | /** | ||
5355 | * drm_mode_get_tile_group - get a reference to an existing tile group | ||
5356 | * @dev: DRM device | ||
5357 | * @topology: 8-bytes unique per monitor. | ||
5358 | * | ||
5359 | * Use the unique bytes to get a reference to an existing tile group. | ||
5360 | * | ||
5361 | * RETURNS: | ||
5362 | * tile group or NULL if not found. | ||
5363 | */ | ||
5364 | struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, | ||
5365 | char topology[8]) | ||
5366 | { | ||
5367 | struct drm_tile_group *tg; | ||
5368 | int id; | ||
5369 | mutex_lock(&dev->mode_config.idr_mutex); | ||
5370 | idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { | ||
5371 | if (!memcmp(tg->group_data, topology, 8)) { | ||
5372 | if (!kref_get_unless_zero(&tg->refcount)) | ||
5373 | tg = NULL; | ||
5374 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
5375 | return tg; | ||
5376 | } | ||
5377 | } | ||
5378 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
5379 | return NULL; | ||
5380 | } | ||
5381 | |||
5382 | /** | ||
5383 | * drm_mode_create_tile_group - create a tile group from a displayid description | ||
5384 | * @dev: DRM device | ||
5385 | * @topology: 8-bytes unique per monitor. | ||
5386 | * | ||
5387 | * Create a tile group for the unique monitor, and get a unique | ||
5388 | * identifier for the tile group. | ||
5389 | * | ||
5390 | * RETURNS: | ||
5391 | * new tile group or error. | ||
5392 | */ | ||
5393 | struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, | ||
5394 | char topology[8]) | ||
5395 | { | ||
5396 | struct drm_tile_group *tg; | ||
5397 | int ret; | ||
5398 | |||
5399 | tg = kzalloc(sizeof(*tg), GFP_KERNEL); | ||
5400 | if (!tg) | ||
5401 | return ERR_PTR(-ENOMEM); | ||
5402 | |||
5403 | kref_init(&tg->refcount); | ||
5404 | memcpy(tg->group_data, topology, 8); | ||
5405 | tg->dev = dev; | ||
5406 | |||
5407 | mutex_lock(&dev->mode_config.idr_mutex); | ||
5408 | ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); | ||
5409 | if (ret >= 0) { | ||
5410 | tg->id = ret; | ||
5411 | } else { | ||
5412 | kfree(tg); | ||
5413 | tg = ERR_PTR(ret); | ||
5414 | } | ||
5415 | |||
5416 | mutex_unlock(&dev->mode_config.idr_mutex); | ||
5417 | return tg; | ||
5418 | } | ||
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 959e2074b0d4..79968e39c8d0 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c | |||
@@ -186,10 +186,11 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, | |||
186 | 186 | ||
187 | /* | 187 | /* |
188 | * The specification doesn't give any recommendation on how often to | 188 | * The specification doesn't give any recommendation on how often to |
189 | * retry native transactions, so retry 7 times like for I2C-over-AUX | 189 | * retry native transactions. We used to retry 7 times like for |
190 | * transactions. | 190 | * aux i2c transactions but real world devices this wasn't |
191 | * sufficient, bump to 32 which makes Dell 4k monitors happier. | ||
191 | */ | 192 | */ |
192 | for (retry = 0; retry < 7; retry++) { | 193 | for (retry = 0; retry < 32; retry++) { |
193 | 194 | ||
194 | mutex_lock(&aux->hw_mutex); | 195 | mutex_lock(&aux->hw_mutex); |
195 | err = aux->transfer(aux, &msg); | 196 | err = aux->transfer(aux, &msg); |
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 5682d7e9f1ec..9a5b68717ec8 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c | |||
@@ -839,6 +839,8 @@ static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb) | |||
839 | 839 | ||
840 | static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) | 840 | static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) |
841 | { | 841 | { |
842 | struct drm_dp_mst_branch *mstb; | ||
843 | |||
842 | switch (old_pdt) { | 844 | switch (old_pdt) { |
843 | case DP_PEER_DEVICE_DP_LEGACY_CONV: | 845 | case DP_PEER_DEVICE_DP_LEGACY_CONV: |
844 | case DP_PEER_DEVICE_SST_SINK: | 846 | case DP_PEER_DEVICE_SST_SINK: |
@@ -846,8 +848,9 @@ static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) | |||
846 | drm_dp_mst_unregister_i2c_bus(&port->aux); | 848 | drm_dp_mst_unregister_i2c_bus(&port->aux); |
847 | break; | 849 | break; |
848 | case DP_PEER_DEVICE_MST_BRANCHING: | 850 | case DP_PEER_DEVICE_MST_BRANCHING: |
849 | drm_dp_put_mst_branch_device(port->mstb); | 851 | mstb = port->mstb; |
850 | port->mstb = NULL; | 852 | port->mstb = NULL; |
853 | drm_dp_put_mst_branch_device(mstb); | ||
851 | break; | 854 | break; |
852 | } | 855 | } |
853 | } | 856 | } |
@@ -858,6 +861,8 @@ static void drm_dp_destroy_port(struct kref *kref) | |||
858 | struct drm_dp_mst_topology_mgr *mgr = port->mgr; | 861 | struct drm_dp_mst_topology_mgr *mgr = port->mgr; |
859 | if (!port->input) { | 862 | if (!port->input) { |
860 | port->vcpi.num_slots = 0; | 863 | port->vcpi.num_slots = 0; |
864 | |||
865 | kfree(port->cached_edid); | ||
861 | if (port->connector) | 866 | if (port->connector) |
862 | (*port->mgr->cbs->destroy_connector)(mgr, port->connector); | 867 | (*port->mgr->cbs->destroy_connector)(mgr, port->connector); |
863 | drm_dp_port_teardown_pdt(port, port->pdt); | 868 | drm_dp_port_teardown_pdt(port, port->pdt); |
@@ -1097,6 +1102,10 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, | |||
1097 | char proppath[255]; | 1102 | char proppath[255]; |
1098 | build_mst_prop_path(port, mstb, proppath, sizeof(proppath)); | 1103 | build_mst_prop_path(port, mstb, proppath, sizeof(proppath)); |
1099 | port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath); | 1104 | port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath); |
1105 | |||
1106 | if (port->port_num >= 8) { | ||
1107 | port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); | ||
1108 | } | ||
1100 | } | 1109 | } |
1101 | 1110 | ||
1102 | /* put reference to this port */ | 1111 | /* put reference to this port */ |
@@ -2167,7 +2176,8 @@ EXPORT_SYMBOL(drm_dp_mst_hpd_irq); | |||
2167 | * This returns the current connection state for a port. It validates the | 2176 | * This returns the current connection state for a port. It validates the |
2168 | * port pointer still exists so the caller doesn't require a reference | 2177 | * port pointer still exists so the caller doesn't require a reference |
2169 | */ | 2178 | */ |
2170 | enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) | 2179 | enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, |
2180 | struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) | ||
2171 | { | 2181 | { |
2172 | enum drm_connector_status status = connector_status_disconnected; | 2182 | enum drm_connector_status status = connector_status_disconnected; |
2173 | 2183 | ||
@@ -2186,6 +2196,10 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr | |||
2186 | 2196 | ||
2187 | case DP_PEER_DEVICE_SST_SINK: | 2197 | case DP_PEER_DEVICE_SST_SINK: |
2188 | status = connector_status_connected; | 2198 | status = connector_status_connected; |
2199 | /* for logical ports - cache the EDID */ | ||
2200 | if (port->port_num >= 8 && !port->cached_edid) { | ||
2201 | port->cached_edid = drm_get_edid(connector, &port->aux.ddc); | ||
2202 | } | ||
2189 | break; | 2203 | break; |
2190 | case DP_PEER_DEVICE_DP_LEGACY_CONV: | 2204 | case DP_PEER_DEVICE_DP_LEGACY_CONV: |
2191 | if (port->ldps) | 2205 | if (port->ldps) |
@@ -2217,7 +2231,12 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ | |||
2217 | if (!port) | 2231 | if (!port) |
2218 | return NULL; | 2232 | return NULL; |
2219 | 2233 | ||
2220 | edid = drm_get_edid(connector, &port->aux.ddc); | 2234 | if (port->cached_edid) |
2235 | edid = drm_edid_duplicate(port->cached_edid); | ||
2236 | else | ||
2237 | edid = drm_get_edid(connector, &port->aux.ddc); | ||
2238 | |||
2239 | drm_mode_connector_set_tile_property(connector); | ||
2221 | drm_dp_put_port(port); | 2240 | drm_dp_put_port(port); |
2222 | return edid; | 2241 | return edid; |
2223 | } | 2242 | } |
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a7b5a71856a7..72fd8820e186 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <drm/drmP.h> | 35 | #include <drm/drmP.h> |
36 | #include <drm/drm_edid.h> | 36 | #include <drm/drm_edid.h> |
37 | #include <drm/drm_displayid.h> | ||
37 | 38 | ||
38 | #define version_greater(edid, maj, min) \ | 39 | #define version_greater(edid, maj, min) \ |
39 | (((edid)->version > (maj)) || \ | 40 | (((edid)->version > (maj)) || \ |
@@ -1014,6 +1015,8 @@ module_param_named(edid_fixup, edid_fixup, int, 0400); | |||
1014 | MODULE_PARM_DESC(edid_fixup, | 1015 | MODULE_PARM_DESC(edid_fixup, |
1015 | "Minimum number of valid EDID header bytes (0-8, default 6)"); | 1016 | "Minimum number of valid EDID header bytes (0-8, default 6)"); |
1016 | 1017 | ||
1018 | static void drm_get_displayid(struct drm_connector *connector, | ||
1019 | struct edid *edid); | ||
1017 | /** | 1020 | /** |
1018 | * drm_edid_block_valid - Sanity check the EDID block (base or extension) | 1021 | * drm_edid_block_valid - Sanity check the EDID block (base or extension) |
1019 | * @raw_edid: pointer to raw EDID block | 1022 | * @raw_edid: pointer to raw EDID block |
@@ -1308,10 +1311,15 @@ EXPORT_SYMBOL(drm_probe_ddc); | |||
1308 | struct edid *drm_get_edid(struct drm_connector *connector, | 1311 | struct edid *drm_get_edid(struct drm_connector *connector, |
1309 | struct i2c_adapter *adapter) | 1312 | struct i2c_adapter *adapter) |
1310 | { | 1313 | { |
1314 | struct edid *edid; | ||
1315 | |||
1311 | if (!drm_probe_ddc(adapter)) | 1316 | if (!drm_probe_ddc(adapter)) |
1312 | return NULL; | 1317 | return NULL; |
1313 | 1318 | ||
1314 | return drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); | 1319 | edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); |
1320 | if (edid) | ||
1321 | drm_get_displayid(connector, edid); | ||
1322 | return edid; | ||
1315 | } | 1323 | } |
1316 | EXPORT_SYMBOL(drm_get_edid); | 1324 | EXPORT_SYMBOL(drm_get_edid); |
1317 | 1325 | ||
@@ -2406,7 +2414,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, | |||
2406 | /* | 2414 | /* |
2407 | * Search EDID for CEA extension block. | 2415 | * Search EDID for CEA extension block. |
2408 | */ | 2416 | */ |
2409 | static u8 *drm_find_cea_extension(struct edid *edid) | 2417 | static u8 *drm_find_edid_extension(struct edid *edid, int ext_id) |
2410 | { | 2418 | { |
2411 | u8 *edid_ext = NULL; | 2419 | u8 *edid_ext = NULL; |
2412 | int i; | 2420 | int i; |
@@ -2418,7 +2426,7 @@ static u8 *drm_find_cea_extension(struct edid *edid) | |||
2418 | /* Find CEA extension */ | 2426 | /* Find CEA extension */ |
2419 | for (i = 0; i < edid->extensions; i++) { | 2427 | for (i = 0; i < edid->extensions; i++) { |
2420 | edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); | 2428 | edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); |
2421 | if (edid_ext[0] == CEA_EXT) | 2429 | if (edid_ext[0] == ext_id) |
2422 | break; | 2430 | break; |
2423 | } | 2431 | } |
2424 | 2432 | ||
@@ -2428,6 +2436,16 @@ static u8 *drm_find_cea_extension(struct edid *edid) | |||
2428 | return edid_ext; | 2436 | return edid_ext; |
2429 | } | 2437 | } |
2430 | 2438 | ||
2439 | static u8 *drm_find_cea_extension(struct edid *edid) | ||
2440 | { | ||
2441 | return drm_find_edid_extension(edid, CEA_EXT); | ||
2442 | } | ||
2443 | |||
2444 | static u8 *drm_find_displayid_extension(struct edid *edid) | ||
2445 | { | ||
2446 | return drm_find_edid_extension(edid, DISPLAYID_EXT); | ||
2447 | } | ||
2448 | |||
2431 | /* | 2449 | /* |
2432 | * Calculate the alternate clock for the CEA mode | 2450 | * Calculate the alternate clock for the CEA mode |
2433 | * (60Hz vs. 59.94Hz etc.) | 2451 | * (60Hz vs. 59.94Hz etc.) |
@@ -3888,3 +3906,123 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, | |||
3888 | return 0; | 3906 | return 0; |
3889 | } | 3907 | } |
3890 | EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode); | 3908 | EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode); |
3909 | |||
3910 | static int drm_parse_display_id(struct drm_connector *connector, | ||
3911 | u8 *displayid, int length, | ||
3912 | bool is_edid_extension) | ||
3913 | { | ||
3914 | /* if this is an EDID extension the first byte will be 0x70 */ | ||
3915 | int idx = 0; | ||
3916 | struct displayid_hdr *base; | ||
3917 | struct displayid_block *block; | ||
3918 | u8 csum = 0; | ||
3919 | int i; | ||
3920 | |||
3921 | if (is_edid_extension) | ||
3922 | idx = 1; | ||
3923 | |||
3924 | base = (struct displayid_hdr *)&displayid[idx]; | ||
3925 | |||
3926 | DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n", | ||
3927 | base->rev, base->bytes, base->prod_id, base->ext_count); | ||
3928 | |||
3929 | if (base->bytes + 5 > length - idx) | ||
3930 | return -EINVAL; | ||
3931 | |||
3932 | for (i = idx; i <= base->bytes + 5; i++) { | ||
3933 | csum += displayid[i]; | ||
3934 | } | ||
3935 | if (csum) { | ||
3936 | DRM_ERROR("DisplayID checksum invalid, remainder is %d\n", csum); | ||
3937 | return -EINVAL; | ||
3938 | } | ||
3939 | |||
3940 | block = (struct displayid_block *)&displayid[idx + 4]; | ||
3941 | DRM_DEBUG_KMS("block id %d, rev %d, len %d\n", | ||
3942 | block->tag, block->rev, block->num_bytes); | ||
3943 | |||
3944 | switch (block->tag) { | ||
3945 | case DATA_BLOCK_TILED_DISPLAY: { | ||
3946 | struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block; | ||
3947 | |||
3948 | u16 w, h; | ||
3949 | u8 tile_v_loc, tile_h_loc; | ||
3950 | u8 num_v_tile, num_h_tile; | ||
3951 | struct drm_tile_group *tg; | ||
3952 | |||
3953 | w = tile->tile_size[0] | tile->tile_size[1] << 8; | ||
3954 | h = tile->tile_size[2] | tile->tile_size[3] << 8; | ||
3955 | |||
3956 | num_v_tile = (tile->topo[0] & 0xf) | (tile->topo[2] & 0x30); | ||
3957 | num_h_tile = (tile->topo[0] >> 4) | ((tile->topo[2] >> 2) & 0x30); | ||
3958 | tile_v_loc = (tile->topo[1] & 0xf) | ((tile->topo[2] & 0x3) << 4); | ||
3959 | tile_h_loc = (tile->topo[1] >> 4) | (((tile->topo[2] >> 2) & 0x3) << 4); | ||
3960 | |||
3961 | connector->has_tile = true; | ||
3962 | if (tile->tile_cap & 0x80) | ||
3963 | connector->tile_is_single_monitor = true; | ||
3964 | |||
3965 | connector->num_h_tile = num_h_tile + 1; | ||
3966 | connector->num_v_tile = num_v_tile + 1; | ||
3967 | connector->tile_h_loc = tile_h_loc; | ||
3968 | connector->tile_v_loc = tile_v_loc; | ||
3969 | connector->tile_h_size = w + 1; | ||
3970 | connector->tile_v_size = h + 1; | ||
3971 | |||
3972 | DRM_DEBUG_KMS("tile cap 0x%x\n", tile->tile_cap); | ||
3973 | DRM_DEBUG_KMS("tile_size %d x %d\n", w + 1, h + 1); | ||
3974 | DRM_DEBUG_KMS("topo num tiles %dx%d, location %dx%d\n", | ||
3975 | num_h_tile + 1, num_v_tile + 1, tile_h_loc, tile_v_loc); | ||
3976 | DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]); | ||
3977 | |||
3978 | tg = drm_mode_get_tile_group(connector->dev, tile->topology_id); | ||
3979 | if (!tg) { | ||
3980 | tg = drm_mode_create_tile_group(connector->dev, tile->topology_id); | ||
3981 | } | ||
3982 | if (!tg) | ||
3983 | return -ENOMEM; | ||
3984 | |||
3985 | if (connector->tile_group != tg) { | ||
3986 | /* if we haven't got a pointer, | ||
3987 | take the reference, drop ref to old tile group */ | ||
3988 | if (connector->tile_group) { | ||
3989 | drm_mode_put_tile_group(connector->dev, connector->tile_group); | ||
3990 | } | ||
3991 | connector->tile_group = tg; | ||
3992 | } else | ||
3993 | /* if same tile group, then release the ref we just took. */ | ||
3994 | drm_mode_put_tile_group(connector->dev, tg); | ||
3995 | } | ||
3996 | break; | ||
3997 | default: | ||
3998 | printk("unknown displayid tag %d\n", block->tag); | ||
3999 | break; | ||
4000 | } | ||
4001 | return 0; | ||
4002 | } | ||
4003 | |||
4004 | static void drm_get_displayid(struct drm_connector *connector, | ||
4005 | struct edid *edid) | ||
4006 | { | ||
4007 | void *displayid = NULL; | ||
4008 | int ret; | ||
4009 | connector->has_tile = false; | ||
4010 | displayid = drm_find_displayid_extension(edid); | ||
4011 | if (!displayid) { | ||
4012 | /* drop reference to any tile group we had */ | ||
4013 | goto out_drop_ref; | ||
4014 | } | ||
4015 | |||
4016 | ret = drm_parse_display_id(connector, displayid, EDID_LENGTH, true); | ||
4017 | if (ret < 0) | ||
4018 | goto out_drop_ref; | ||
4019 | if (!connector->has_tile) | ||
4020 | goto out_drop_ref; | ||
4021 | return; | ||
4022 | out_drop_ref: | ||
4023 | if (connector->tile_group) { | ||
4024 | drm_mode_put_tile_group(connector->dev, connector->tile_group); | ||
4025 | connector->tile_group = NULL; | ||
4026 | } | ||
4027 | return; | ||
4028 | } | ||
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 09d47e9ba026..52ce26d6b4fb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -347,9 +347,18 @@ bool drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) | |||
347 | { | 347 | { |
348 | struct drm_device *dev = fb_helper->dev; | 348 | struct drm_device *dev = fb_helper->dev; |
349 | bool ret; | 349 | bool ret; |
350 | bool do_delayed = false; | ||
351 | |||
350 | drm_modeset_lock_all(dev); | 352 | drm_modeset_lock_all(dev); |
351 | ret = restore_fbdev_mode(fb_helper); | 353 | ret = restore_fbdev_mode(fb_helper); |
354 | |||
355 | do_delayed = fb_helper->delayed_hotplug; | ||
356 | if (do_delayed) | ||
357 | fb_helper->delayed_hotplug = false; | ||
352 | drm_modeset_unlock_all(dev); | 358 | drm_modeset_unlock_all(dev); |
359 | |||
360 | if (do_delayed) | ||
361 | drm_fb_helper_hotplug_event(fb_helper); | ||
353 | return ret; | 362 | return ret; |
354 | } | 363 | } |
355 | EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked); | 364 | EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked); |
@@ -888,10 +897,6 @@ int drm_fb_helper_set_par(struct fb_info *info) | |||
888 | 897 | ||
889 | drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); | 898 | drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); |
890 | 899 | ||
891 | if (fb_helper->delayed_hotplug) { | ||
892 | fb_helper->delayed_hotplug = false; | ||
893 | drm_fb_helper_hotplug_event(fb_helper); | ||
894 | } | ||
895 | return 0; | 900 | return 0; |
896 | } | 901 | } |
897 | EXPORT_SYMBOL(drm_fb_helper_set_par); | 902 | EXPORT_SYMBOL(drm_fb_helper_set_par); |
@@ -995,19 +1000,21 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, | |||
995 | crtc_count = 0; | 1000 | crtc_count = 0; |
996 | for (i = 0; i < fb_helper->crtc_count; i++) { | 1001 | for (i = 0; i < fb_helper->crtc_count; i++) { |
997 | struct drm_display_mode *desired_mode; | 1002 | struct drm_display_mode *desired_mode; |
1003 | int x, y; | ||
998 | desired_mode = fb_helper->crtc_info[i].desired_mode; | 1004 | desired_mode = fb_helper->crtc_info[i].desired_mode; |
999 | 1005 | x = fb_helper->crtc_info[i].x; | |
1006 | y = fb_helper->crtc_info[i].y; | ||
1000 | if (desired_mode) { | 1007 | if (desired_mode) { |
1001 | if (gamma_size == 0) | 1008 | if (gamma_size == 0) |
1002 | gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; | 1009 | gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; |
1003 | if (desired_mode->hdisplay < sizes.fb_width) | 1010 | if (desired_mode->hdisplay + x < sizes.fb_width) |
1004 | sizes.fb_width = desired_mode->hdisplay; | 1011 | sizes.fb_width = desired_mode->hdisplay + x; |
1005 | if (desired_mode->vdisplay < sizes.fb_height) | 1012 | if (desired_mode->vdisplay + y < sizes.fb_height) |
1006 | sizes.fb_height = desired_mode->vdisplay; | 1013 | sizes.fb_height = desired_mode->vdisplay + y; |
1007 | if (desired_mode->hdisplay > sizes.surface_width) | 1014 | if (desired_mode->hdisplay + x > sizes.surface_width) |
1008 | sizes.surface_width = desired_mode->hdisplay; | 1015 | sizes.surface_width = desired_mode->hdisplay + x; |
1009 | if (desired_mode->vdisplay > sizes.surface_height) | 1016 | if (desired_mode->vdisplay + y > sizes.surface_height) |
1010 | sizes.surface_height = desired_mode->vdisplay; | 1017 | sizes.surface_height = desired_mode->vdisplay + y; |
1011 | crtc_count++; | 1018 | crtc_count++; |
1012 | } | 1019 | } |
1013 | } | 1020 | } |
@@ -1307,6 +1314,7 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper, | |||
1307 | 1314 | ||
1308 | static bool drm_target_cloned(struct drm_fb_helper *fb_helper, | 1315 | static bool drm_target_cloned(struct drm_fb_helper *fb_helper, |
1309 | struct drm_display_mode **modes, | 1316 | struct drm_display_mode **modes, |
1317 | struct drm_fb_offset *offsets, | ||
1310 | bool *enabled, int width, int height) | 1318 | bool *enabled, int width, int height) |
1311 | { | 1319 | { |
1312 | int count, i, j; | 1320 | int count, i, j; |
@@ -1378,27 +1386,88 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper, | |||
1378 | return false; | 1386 | return false; |
1379 | } | 1387 | } |
1380 | 1388 | ||
1389 | static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper, | ||
1390 | struct drm_display_mode **modes, | ||
1391 | struct drm_fb_offset *offsets, | ||
1392 | int idx, | ||
1393 | int h_idx, int v_idx) | ||
1394 | { | ||
1395 | struct drm_fb_helper_connector *fb_helper_conn; | ||
1396 | int i; | ||
1397 | int hoffset = 0, voffset = 0; | ||
1398 | |||
1399 | for (i = 0; i < fb_helper->connector_count; i++) { | ||
1400 | fb_helper_conn = fb_helper->connector_info[i]; | ||
1401 | if (!fb_helper_conn->connector->has_tile) | ||
1402 | continue; | ||
1403 | |||
1404 | if (!modes[i] && (h_idx || v_idx)) { | ||
1405 | DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i, | ||
1406 | fb_helper_conn->connector->base.id); | ||
1407 | continue; | ||
1408 | } | ||
1409 | if (fb_helper_conn->connector->tile_h_loc < h_idx) | ||
1410 | hoffset += modes[i]->hdisplay; | ||
1411 | |||
1412 | if (fb_helper_conn->connector->tile_v_loc < v_idx) | ||
1413 | voffset += modes[i]->vdisplay; | ||
1414 | } | ||
1415 | offsets[idx].x = hoffset; | ||
1416 | offsets[idx].y = voffset; | ||
1417 | DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx); | ||
1418 | return 0; | ||
1419 | } | ||
1420 | |||
1381 | static bool drm_target_preferred(struct drm_fb_helper *fb_helper, | 1421 | static bool drm_target_preferred(struct drm_fb_helper *fb_helper, |
1382 | struct drm_display_mode **modes, | 1422 | struct drm_display_mode **modes, |
1423 | struct drm_fb_offset *offsets, | ||
1383 | bool *enabled, int width, int height) | 1424 | bool *enabled, int width, int height) |
1384 | { | 1425 | { |
1385 | struct drm_fb_helper_connector *fb_helper_conn; | 1426 | struct drm_fb_helper_connector *fb_helper_conn; |
1386 | int i; | 1427 | int i; |
1387 | 1428 | uint64_t conn_configured = 0, mask; | |
1429 | int tile_pass = 0; | ||
1430 | mask = (1 << fb_helper->connector_count) - 1; | ||
1431 | retry: | ||
1388 | for (i = 0; i < fb_helper->connector_count; i++) { | 1432 | for (i = 0; i < fb_helper->connector_count; i++) { |
1389 | fb_helper_conn = fb_helper->connector_info[i]; | 1433 | fb_helper_conn = fb_helper->connector_info[i]; |
1390 | 1434 | ||
1391 | if (enabled[i] == false) | 1435 | if (conn_configured & (1 << i)) |
1392 | continue; | 1436 | continue; |
1393 | 1437 | ||
1438 | if (enabled[i] == false) { | ||
1439 | conn_configured |= (1 << i); | ||
1440 | continue; | ||
1441 | } | ||
1442 | |||
1443 | /* first pass over all the untiled connectors */ | ||
1444 | if (tile_pass == 0 && fb_helper_conn->connector->has_tile) | ||
1445 | continue; | ||
1446 | |||
1447 | if (tile_pass == 1) { | ||
1448 | if (fb_helper_conn->connector->tile_h_loc != 0 || | ||
1449 | fb_helper_conn->connector->tile_v_loc != 0) | ||
1450 | continue; | ||
1451 | |||
1452 | } else { | ||
1453 | if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 && | ||
1454 | fb_helper_conn->connector->tile_v_loc != tile_pass - 1) | ||
1455 | /* if this tile_pass doesn't cover any of the tiles - keep going */ | ||
1456 | continue; | ||
1457 | |||
1458 | /* find the tile offsets for this pass - need | ||
1459 | to find all tiles left and above */ | ||
1460 | drm_get_tile_offsets(fb_helper, modes, offsets, | ||
1461 | i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc); | ||
1462 | } | ||
1394 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", | 1463 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", |
1395 | fb_helper_conn->connector->base.id); | 1464 | fb_helper_conn->connector->base.id); |
1396 | 1465 | ||
1397 | /* got for command line mode first */ | 1466 | /* got for command line mode first */ |
1398 | modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); | 1467 | modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); |
1399 | if (!modes[i]) { | 1468 | if (!modes[i]) { |
1400 | DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", | 1469 | DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n", |
1401 | fb_helper_conn->connector->base.id); | 1470 | fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0); |
1402 | modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); | 1471 | modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); |
1403 | } | 1472 | } |
1404 | /* No preferred modes, pick one off the list */ | 1473 | /* No preferred modes, pick one off the list */ |
@@ -1408,6 +1477,12 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper, | |||
1408 | } | 1477 | } |
1409 | DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : | 1478 | DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : |
1410 | "none"); | 1479 | "none"); |
1480 | conn_configured |= (1 << i); | ||
1481 | } | ||
1482 | |||
1483 | if ((conn_configured & mask) != mask) { | ||
1484 | tile_pass++; | ||
1485 | goto retry; | ||
1411 | } | 1486 | } |
1412 | return true; | 1487 | return true; |
1413 | } | 1488 | } |
@@ -1497,6 +1572,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
1497 | struct drm_device *dev = fb_helper->dev; | 1572 | struct drm_device *dev = fb_helper->dev; |
1498 | struct drm_fb_helper_crtc **crtcs; | 1573 | struct drm_fb_helper_crtc **crtcs; |
1499 | struct drm_display_mode **modes; | 1574 | struct drm_display_mode **modes; |
1575 | struct drm_fb_offset *offsets; | ||
1500 | struct drm_mode_set *modeset; | 1576 | struct drm_mode_set *modeset; |
1501 | bool *enabled; | 1577 | bool *enabled; |
1502 | int width, height; | 1578 | int width, height; |
@@ -1511,9 +1587,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
1511 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); | 1587 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); |
1512 | modes = kcalloc(dev->mode_config.num_connector, | 1588 | modes = kcalloc(dev->mode_config.num_connector, |
1513 | sizeof(struct drm_display_mode *), GFP_KERNEL); | 1589 | sizeof(struct drm_display_mode *), GFP_KERNEL); |
1590 | offsets = kcalloc(dev->mode_config.num_connector, | ||
1591 | sizeof(struct drm_fb_offset), GFP_KERNEL); | ||
1514 | enabled = kcalloc(dev->mode_config.num_connector, | 1592 | enabled = kcalloc(dev->mode_config.num_connector, |
1515 | sizeof(bool), GFP_KERNEL); | 1593 | sizeof(bool), GFP_KERNEL); |
1516 | if (!crtcs || !modes || !enabled) { | 1594 | if (!crtcs || !modes || !enabled || !offsets) { |
1517 | DRM_ERROR("Memory allocation failed\n"); | 1595 | DRM_ERROR("Memory allocation failed\n"); |
1518 | goto out; | 1596 | goto out; |
1519 | } | 1597 | } |
@@ -1523,14 +1601,16 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
1523 | 1601 | ||
1524 | if (!(fb_helper->funcs->initial_config && | 1602 | if (!(fb_helper->funcs->initial_config && |
1525 | fb_helper->funcs->initial_config(fb_helper, crtcs, modes, | 1603 | fb_helper->funcs->initial_config(fb_helper, crtcs, modes, |
1604 | offsets, | ||
1526 | enabled, width, height))) { | 1605 | enabled, width, height))) { |
1527 | memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); | 1606 | memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); |
1528 | memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); | 1607 | memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); |
1608 | memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0])); | ||
1529 | 1609 | ||
1530 | if (!drm_target_cloned(fb_helper, | 1610 | if (!drm_target_cloned(fb_helper, modes, offsets, |
1531 | modes, enabled, width, height) && | 1611 | enabled, width, height) && |
1532 | !drm_target_preferred(fb_helper, | 1612 | !drm_target_preferred(fb_helper, modes, offsets, |
1533 | modes, enabled, width, height)) | 1613 | enabled, width, height)) |
1534 | DRM_ERROR("Unable to find initial modes\n"); | 1614 | DRM_ERROR("Unable to find initial modes\n"); |
1535 | 1615 | ||
1536 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", | 1616 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", |
@@ -1550,18 +1630,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
1550 | for (i = 0; i < fb_helper->connector_count; i++) { | 1630 | for (i = 0; i < fb_helper->connector_count; i++) { |
1551 | struct drm_display_mode *mode = modes[i]; | 1631 | struct drm_display_mode *mode = modes[i]; |
1552 | struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; | 1632 | struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; |
1633 | struct drm_fb_offset *offset = &offsets[i]; | ||
1553 | modeset = &fb_crtc->mode_set; | 1634 | modeset = &fb_crtc->mode_set; |
1554 | 1635 | ||
1555 | if (mode && fb_crtc) { | 1636 | if (mode && fb_crtc) { |
1556 | DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", | 1637 | DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n", |
1557 | mode->name, fb_crtc->mode_set.crtc->base.id); | 1638 | mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y); |
1558 | fb_crtc->desired_mode = mode; | 1639 | fb_crtc->desired_mode = mode; |
1640 | fb_crtc->x = offset->x; | ||
1641 | fb_crtc->y = offset->y; | ||
1559 | if (modeset->mode) | 1642 | if (modeset->mode) |
1560 | drm_mode_destroy(dev, modeset->mode); | 1643 | drm_mode_destroy(dev, modeset->mode); |
1561 | modeset->mode = drm_mode_duplicate(dev, | 1644 | modeset->mode = drm_mode_duplicate(dev, |
1562 | fb_crtc->desired_mode); | 1645 | fb_crtc->desired_mode); |
1563 | modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; | 1646 | modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; |
1564 | modeset->fb = fb_helper->fb; | 1647 | modeset->fb = fb_helper->fb; |
1648 | modeset->x = offset->x; | ||
1649 | modeset->y = offset->y; | ||
1565 | } | 1650 | } |
1566 | } | 1651 | } |
1567 | 1652 | ||
@@ -1578,6 +1663,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
1578 | out: | 1663 | out: |
1579 | kfree(crtcs); | 1664 | kfree(crtcs); |
1580 | kfree(modes); | 1665 | kfree(modes); |
1666 | kfree(offsets); | ||
1581 | kfree(enabled); | 1667 | kfree(enabled); |
1582 | } | 1668 | } |
1583 | 1669 | ||
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index bfe359506377..7f8c6a66680a 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c | |||
@@ -283,7 +283,7 @@ intel_dp_mst_detect(struct drm_connector *connector, bool force) | |||
283 | struct intel_connector *intel_connector = to_intel_connector(connector); | 283 | struct intel_connector *intel_connector = to_intel_connector(connector); |
284 | struct intel_dp *intel_dp = intel_connector->mst_port; | 284 | struct intel_dp *intel_dp = intel_connector->mst_port; |
285 | 285 | ||
286 | return drm_dp_mst_detect_port(&intel_dp->mst_mgr, intel_connector->port); | 286 | return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, intel_connector->port); |
287 | } | 287 | } |
288 | 288 | ||
289 | static int | 289 | static int |
@@ -414,6 +414,8 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo | |||
414 | intel_dp_add_properties(intel_dp, connector); | 414 | intel_dp_add_properties(intel_dp, connector); |
415 | 415 | ||
416 | drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); | 416 | drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); |
417 | drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); | ||
418 | |||
417 | drm_mode_connector_set_path_property(connector, pathprop); | 419 | drm_mode_connector_set_path_property(connector, pathprop); |
418 | drm_reinit_primary_mode_group(dev); | 420 | drm_reinit_primary_mode_group(dev); |
419 | mutex_lock(&dev->mode_config.mutex); | 421 | mutex_lock(&dev->mode_config.mutex); |
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index f2183b554cbc..850cf7d6578c 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c | |||
@@ -324,6 +324,7 @@ intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc) | |||
324 | static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | 324 | static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, |
325 | struct drm_fb_helper_crtc **crtcs, | 325 | struct drm_fb_helper_crtc **crtcs, |
326 | struct drm_display_mode **modes, | 326 | struct drm_display_mode **modes, |
327 | struct drm_fb_offset *offsets, | ||
327 | bool *enabled, int width, int height) | 328 | bool *enabled, int width, int height) |
328 | { | 329 | { |
329 | struct drm_device *dev = fb_helper->dev; | 330 | struct drm_device *dev = fb_helper->dev; |
@@ -332,6 +333,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
332 | bool fallback = true; | 333 | bool fallback = true; |
333 | int num_connectors_enabled = 0; | 334 | int num_connectors_enabled = 0; |
334 | int num_connectors_detected = 0; | 335 | int num_connectors_detected = 0; |
336 | uint64_t conn_configured = 0, mask; | ||
337 | int pass = 0; | ||
335 | 338 | ||
336 | save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), | 339 | save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), |
337 | GFP_KERNEL); | 340 | GFP_KERNEL); |
@@ -339,7 +342,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
339 | return false; | 342 | return false; |
340 | 343 | ||
341 | memcpy(save_enabled, enabled, dev->mode_config.num_connector); | 344 | memcpy(save_enabled, enabled, dev->mode_config.num_connector); |
342 | 345 | mask = (1 << fb_helper->connector_count) - 1; | |
346 | retry: | ||
343 | for (i = 0; i < fb_helper->connector_count; i++) { | 347 | for (i = 0; i < fb_helper->connector_count; i++) { |
344 | struct drm_fb_helper_connector *fb_conn; | 348 | struct drm_fb_helper_connector *fb_conn; |
345 | struct drm_connector *connector; | 349 | struct drm_connector *connector; |
@@ -349,12 +353,19 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
349 | fb_conn = fb_helper->connector_info[i]; | 353 | fb_conn = fb_helper->connector_info[i]; |
350 | connector = fb_conn->connector; | 354 | connector = fb_conn->connector; |
351 | 355 | ||
356 | if (conn_configured & (1 << i)) | ||
357 | continue; | ||
358 | |||
359 | if (pass == 0 && !connector->has_tile) | ||
360 | continue; | ||
361 | |||
352 | if (connector->status == connector_status_connected) | 362 | if (connector->status == connector_status_connected) |
353 | num_connectors_detected++; | 363 | num_connectors_detected++; |
354 | 364 | ||
355 | if (!enabled[i]) { | 365 | if (!enabled[i]) { |
356 | DRM_DEBUG_KMS("connector %s not enabled, skipping\n", | 366 | DRM_DEBUG_KMS("connector %s not enabled, skipping\n", |
357 | connector->name); | 367 | connector->name); |
368 | conn_configured |= (1 << i); | ||
358 | continue; | 369 | continue; |
359 | } | 370 | } |
360 | 371 | ||
@@ -373,6 +384,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
373 | DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", | 384 | DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", |
374 | connector->name); | 385 | connector->name); |
375 | enabled[i] = false; | 386 | enabled[i] = false; |
387 | conn_configured |= (1 << i); | ||
376 | continue; | 388 | continue; |
377 | } | 389 | } |
378 | 390 | ||
@@ -400,8 +412,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
400 | 412 | ||
401 | /* try for preferred next */ | 413 | /* try for preferred next */ |
402 | if (!modes[i]) { | 414 | if (!modes[i]) { |
403 | DRM_DEBUG_KMS("looking for preferred mode on connector %s\n", | 415 | DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n", |
404 | connector->name); | 416 | connector->name, connector->has_tile); |
405 | modes[i] = drm_has_preferred_mode(fb_conn, width, | 417 | modes[i] = drm_has_preferred_mode(fb_conn, width, |
406 | height); | 418 | height); |
407 | } | 419 | } |
@@ -444,6 +456,12 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
444 | modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :""); | 456 | modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :""); |
445 | 457 | ||
446 | fallback = false; | 458 | fallback = false; |
459 | conn_configured |= (1 << i); | ||
460 | } | ||
461 | |||
462 | if ((conn_configured & mask) != mask) { | ||
463 | pass++; | ||
464 | goto retry; | ||
447 | } | 465 | } |
448 | 466 | ||
449 | /* | 467 | /* |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index dd2c16e43333..b86329813ad3 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -137,6 +137,14 @@ struct drm_display_info { | |||
137 | u8 cea_rev; | 137 | u8 cea_rev; |
138 | }; | 138 | }; |
139 | 139 | ||
140 | /* data corresponds to displayid vend/prod/serial */ | ||
141 | struct drm_tile_group { | ||
142 | struct kref refcount; | ||
143 | struct drm_device *dev; | ||
144 | int id; | ||
145 | u8 group_data[8]; | ||
146 | }; | ||
147 | |||
140 | struct drm_framebuffer_funcs { | 148 | struct drm_framebuffer_funcs { |
141 | /* note: use drm_framebuffer_remove() */ | 149 | /* note: use drm_framebuffer_remove() */ |
142 | void (*destroy)(struct drm_framebuffer *framebuffer); | 150 | void (*destroy)(struct drm_framebuffer *framebuffer); |
@@ -599,6 +607,15 @@ struct drm_encoder { | |||
599 | * @bad_edid_counter: track sinks that give us an EDID with invalid checksum | 607 | * @bad_edid_counter: track sinks that give us an EDID with invalid checksum |
600 | * @debugfs_entry: debugfs directory for this connector | 608 | * @debugfs_entry: debugfs directory for this connector |
601 | * @state: current atomic state for this connector | 609 | * @state: current atomic state for this connector |
610 | * @has_tile: is this connector connected to a tiled monitor | ||
611 | * @tile_group: tile group for the connected monitor | ||
612 | * @tile_is_single_monitor: whether the tile is one monitor housing | ||
613 | * @num_h_tile: number of horizontal tiles in the tile group | ||
614 | * @num_v_tile: number of vertical tiles in the tile group | ||
615 | * @tile_h_loc: horizontal location of this tile | ||
616 | * @tile_v_loc: vertical location of this tile | ||
617 | * @tile_h_size: horizontal size of this tile. | ||
618 | * @tile_v_size: vertical size of this tile. | ||
602 | * | 619 | * |
603 | * Each connector may be connected to one or more CRTCs, or may be clonable by | 620 | * Each connector may be connected to one or more CRTCs, or may be clonable by |
604 | * another connector if they can share a CRTC. Each connector also has a specific | 621 | * another connector if they can share a CRTC. Each connector also has a specific |
@@ -634,6 +651,8 @@ struct drm_connector { | |||
634 | 651 | ||
635 | struct drm_property_blob *path_blob_ptr; | 652 | struct drm_property_blob *path_blob_ptr; |
636 | 653 | ||
654 | struct drm_property_blob *tile_blob_ptr; | ||
655 | |||
637 | uint8_t polled; /* DRM_CONNECTOR_POLL_* */ | 656 | uint8_t polled; /* DRM_CONNECTOR_POLL_* */ |
638 | 657 | ||
639 | /* requested DPMS state */ | 658 | /* requested DPMS state */ |
@@ -661,6 +680,15 @@ struct drm_connector { | |||
661 | struct dentry *debugfs_entry; | 680 | struct dentry *debugfs_entry; |
662 | 681 | ||
663 | struct drm_connector_state *state; | 682 | struct drm_connector_state *state; |
683 | |||
684 | /* DisplayID bits */ | ||
685 | bool has_tile; | ||
686 | struct drm_tile_group *tile_group; | ||
687 | bool tile_is_single_monitor; | ||
688 | |||
689 | uint8_t num_h_tile, num_v_tile; | ||
690 | uint8_t tile_h_loc, tile_v_loc; | ||
691 | uint16_t tile_h_size, tile_v_size; | ||
664 | }; | 692 | }; |
665 | 693 | ||
666 | /** | 694 | /** |
@@ -978,6 +1006,7 @@ struct drm_mode_config { | |||
978 | struct drm_modeset_acquire_ctx *acquire_ctx; /* for legacy _lock_all() / _unlock_all() */ | 1006 | struct drm_modeset_acquire_ctx *acquire_ctx; /* for legacy _lock_all() / _unlock_all() */ |
979 | struct mutex idr_mutex; /* for IDR management */ | 1007 | struct mutex idr_mutex; /* for IDR management */ |
980 | struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ | 1008 | struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ |
1009 | struct idr tile_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ | ||
981 | /* this is limited to one for now */ | 1010 | /* this is limited to one for now */ |
982 | 1011 | ||
983 | struct mutex fb_lock; /* proctects global and per-file fb lists */ | 1012 | struct mutex fb_lock; /* proctects global and per-file fb lists */ |
@@ -1021,6 +1050,7 @@ struct drm_mode_config { | |||
1021 | struct drm_property *edid_property; | 1050 | struct drm_property *edid_property; |
1022 | struct drm_property *dpms_property; | 1051 | struct drm_property *dpms_property; |
1023 | struct drm_property *path_property; | 1052 | struct drm_property *path_property; |
1053 | struct drm_property *tile_property; | ||
1024 | struct drm_property *plane_type_property; | 1054 | struct drm_property *plane_type_property; |
1025 | struct drm_property *rotation_property; | 1055 | struct drm_property *rotation_property; |
1026 | 1056 | ||
@@ -1190,6 +1220,7 @@ extern void drm_mode_config_cleanup(struct drm_device *dev); | |||
1190 | 1220 | ||
1191 | extern int drm_mode_connector_set_path_property(struct drm_connector *connector, | 1221 | extern int drm_mode_connector_set_path_property(struct drm_connector *connector, |
1192 | const char *path); | 1222 | const char *path); |
1223 | int drm_mode_connector_set_tile_property(struct drm_connector *connector); | ||
1193 | extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, | 1224 | extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, |
1194 | const struct edid *edid); | 1225 | const struct edid *edid); |
1195 | 1226 | ||
@@ -1326,6 +1357,13 @@ extern void drm_set_preferred_mode(struct drm_connector *connector, | |||
1326 | extern int drm_edid_header_is_valid(const u8 *raw_edid); | 1357 | extern int drm_edid_header_is_valid(const u8 *raw_edid); |
1327 | extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid); | 1358 | extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid); |
1328 | extern bool drm_edid_is_valid(struct edid *edid); | 1359 | extern bool drm_edid_is_valid(struct edid *edid); |
1360 | |||
1361 | extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, | ||
1362 | char topology[8]); | ||
1363 | extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, | ||
1364 | char topology[8]); | ||
1365 | extern void drm_mode_put_tile_group(struct drm_device *dev, | ||
1366 | struct drm_tile_group *tg); | ||
1329 | struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, | 1367 | struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, |
1330 | int hsize, int vsize, int fresh, | 1368 | int hsize, int vsize, int fresh, |
1331 | bool rb); | 1369 | bool rb); |
diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h new file mode 100644 index 000000000000..623b4e98e748 --- /dev/null +++ b/include/drm/drm_displayid.h | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * Copyright © 2014 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | #ifndef DRM_DISPLAYID_H | ||
23 | #define DRM_DISPLAYID_H | ||
24 | |||
25 | #define DATA_BLOCK_PRODUCT_ID 0x00 | ||
26 | #define DATA_BLOCK_DISPLAY_PARAMETERS 0x01 | ||
27 | #define DATA_BLOCK_COLOR_CHARACTERISTICS 0x02 | ||
28 | #define DATA_BLOCK_TYPE_1_DETAILED_TIMING 0x03 | ||
29 | #define DATA_BLOCK_TYPE_2_DETAILED_TIMING 0x04 | ||
30 | #define DATA_BLOCK_TYPE_3_SHORT_TIMING 0x05 | ||
31 | #define DATA_BLOCK_TYPE_4_DMT_TIMING 0x06 | ||
32 | #define DATA_BLOCK_VESA_TIMING 0x07 | ||
33 | #define DATA_BLOCK_CEA_TIMING 0x08 | ||
34 | #define DATA_BLOCK_VIDEO_TIMING_RANGE 0x09 | ||
35 | #define DATA_BLOCK_PRODUCT_SERIAL_NUMBER 0x0a | ||
36 | #define DATA_BLOCK_GP_ASCII_STRING 0x0b | ||
37 | #define DATA_BLOCK_DISPLAY_DEVICE_DATA 0x0c | ||
38 | #define DATA_BLOCK_INTERFACE_POWER_SEQUENCING 0x0d | ||
39 | #define DATA_BLOCK_TRANSFER_CHARACTERISTICS 0x0e | ||
40 | #define DATA_BLOCK_DISPLAY_INTERFACE 0x0f | ||
41 | #define DATA_BLOCK_STEREO_DISPLAY_INTERFACE 0x10 | ||
42 | #define DATA_BLOCK_TILED_DISPLAY 0x12 | ||
43 | |||
44 | #define DATA_BLOCK_VENDOR_SPECIFIC 0x7f | ||
45 | |||
46 | #define PRODUCT_TYPE_EXTENSION 0 | ||
47 | #define PRODUCT_TYPE_TEST 1 | ||
48 | #define PRODUCT_TYPE_PANEL 2 | ||
49 | #define PRODUCT_TYPE_MONITOR 3 | ||
50 | #define PRODUCT_TYPE_TV 4 | ||
51 | #define PRODUCT_TYPE_REPEATER 5 | ||
52 | #define PRODUCT_TYPE_DIRECT_DRIVE 6 | ||
53 | |||
54 | struct displayid_hdr { | ||
55 | u8 rev; | ||
56 | u8 bytes; | ||
57 | u8 prod_id; | ||
58 | u8 ext_count; | ||
59 | } __packed; | ||
60 | |||
61 | struct displayid_block { | ||
62 | u8 tag; | ||
63 | u8 rev; | ||
64 | u8 num_bytes; | ||
65 | } __packed; | ||
66 | |||
67 | struct displayid_tiled_block { | ||
68 | struct displayid_block base; | ||
69 | u8 tile_cap; | ||
70 | u8 topo[3]; | ||
71 | u8 tile_size[4]; | ||
72 | u8 tile_pixel_bezel[5]; | ||
73 | u8 topology_id[8]; | ||
74 | } __packed; | ||
75 | |||
76 | #endif | ||
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index cec6383bbdb8..00c1da927245 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h | |||
@@ -92,6 +92,8 @@ struct drm_dp_mst_port { | |||
92 | struct drm_dp_vcpi vcpi; | 92 | struct drm_dp_vcpi vcpi; |
93 | struct drm_connector *connector; | 93 | struct drm_connector *connector; |
94 | struct drm_dp_mst_topology_mgr *mgr; | 94 | struct drm_dp_mst_topology_mgr *mgr; |
95 | |||
96 | struct edid *cached_edid; /* for DP logical ports - make tiling work */ | ||
95 | }; | 97 | }; |
96 | 98 | ||
97 | /** | 99 | /** |
@@ -474,7 +476,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms | |||
474 | int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled); | 476 | int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled); |
475 | 477 | ||
476 | 478 | ||
477 | enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); | 479 | enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); |
478 | 480 | ||
479 | struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); | 481 | struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); |
480 | 482 | ||
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index d59240ffb1f7..87d85e81d3a7 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h | |||
@@ -27,12 +27,14 @@ | |||
27 | 27 | ||
28 | #define EDID_LENGTH 128 | 28 | #define EDID_LENGTH 128 |
29 | #define DDC_ADDR 0x50 | 29 | #define DDC_ADDR 0x50 |
30 | #define DDC_ADDR2 0x52 /* E-DDC 1.2 - where DisplayID can hide */ | ||
30 | 31 | ||
31 | #define CEA_EXT 0x02 | 32 | #define CEA_EXT 0x02 |
32 | #define VTB_EXT 0x10 | 33 | #define VTB_EXT 0x10 |
33 | #define DI_EXT 0x40 | 34 | #define DI_EXT 0x40 |
34 | #define LS_EXT 0x50 | 35 | #define LS_EXT 0x50 |
35 | #define MI_EXT 0x60 | 36 | #define MI_EXT 0x60 |
37 | #define DISPLAYID_EXT 0x70 | ||
36 | 38 | ||
37 | struct est_timings { | 39 | struct est_timings { |
38 | u8 t1; | 40 | u8 t1; |
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index f4ad254e3488..b597068103aa 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h | |||
@@ -34,9 +34,14 @@ struct drm_fb_helper; | |||
34 | 34 | ||
35 | #include <linux/kgdb.h> | 35 | #include <linux/kgdb.h> |
36 | 36 | ||
37 | struct drm_fb_offset { | ||
38 | int x, y; | ||
39 | }; | ||
40 | |||
37 | struct drm_fb_helper_crtc { | 41 | struct drm_fb_helper_crtc { |
38 | struct drm_mode_set mode_set; | 42 | struct drm_mode_set mode_set; |
39 | struct drm_display_mode *desired_mode; | 43 | struct drm_display_mode *desired_mode; |
44 | int x, y; | ||
40 | }; | 45 | }; |
41 | 46 | ||
42 | struct drm_fb_helper_surface_size { | 47 | struct drm_fb_helper_surface_size { |
@@ -72,6 +77,7 @@ struct drm_fb_helper_funcs { | |||
72 | bool (*initial_config)(struct drm_fb_helper *fb_helper, | 77 | bool (*initial_config)(struct drm_fb_helper *fb_helper, |
73 | struct drm_fb_helper_crtc **crtcs, | 78 | struct drm_fb_helper_crtc **crtcs, |
74 | struct drm_display_mode **modes, | 79 | struct drm_display_mode **modes, |
80 | struct drm_fb_offset *offsets, | ||
75 | bool *enabled, int width, int height); | 81 | bool *enabled, int width, int height); |
76 | }; | 82 | }; |
77 | 83 | ||