aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-12-08 18:58:51 -0500
committerDave Airlie <airlied@redhat.com>2014-12-08 18:58:51 -0500
commitd1b8792b636f83804add26ec1ac90a686be19e49 (patch)
treedd12f04f8e18574f134a66bd8ceb93fbf5109606
parentb75478d1c7e4758abcf15c8494d70d4dc4dcb553 (diff)
parentb0ee9e7fa5b461a91f24d1d03b10c6bf162c86f9 (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.tmpl13
-rw-r--r--drivers/gpu/drm/drm_crtc.c155
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c7
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c25
-rw-r--r--drivers/gpu/drm/drm_edid.c144
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c134
-rw-r--r--drivers/gpu/drm/i915/intel_dp_mst.c4
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c24
-rw-r--r--include/drm/drm_crtc.h38
-rw-r--r--include/drm/drm_displayid.h76
-rw-r--r--include/drm/drm_dp_mst_helper.h4
-rw-r--r--include/drm/drm_edid.h2
-rw-r--r--include/drm/drm_fb_helper.h6
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,
4083EXPORT_SYMBOL(drm_mode_connector_set_path_property); 4093EXPORT_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 */
4106int 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}
4139EXPORT_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}
5263EXPORT_SYMBOL(drm_mode_create_rotation_property); 5321EXPORT_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 */
5331static 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 */
5348void 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 */
5364struct 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 */
5393struct 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
840static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt) 840static 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 */
2170enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) 2179enum 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);
1014MODULE_PARM_DESC(edid_fixup, 1015MODULE_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
1018static 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);
1308struct edid *drm_get_edid(struct drm_connector *connector, 1311struct 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}
1316EXPORT_SYMBOL(drm_get_edid); 1324EXPORT_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 */
2409static u8 *drm_find_cea_extension(struct edid *edid) 2417static 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
2439static u8 *drm_find_cea_extension(struct edid *edid)
2440{
2441 return drm_find_edid_extension(edid, CEA_EXT);
2442}
2443
2444static 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}
3890EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode); 3908EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode);
3909
3910static 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
4004static 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;
4022out_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}
355EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked); 364EXPORT_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}
897EXPORT_SYMBOL(drm_fb_helper_set_par); 902EXPORT_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
1308static bool drm_target_cloned(struct drm_fb_helper *fb_helper, 1315static 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
1389static 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
1381static bool drm_target_preferred(struct drm_fb_helper *fb_helper, 1421static 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;
1431retry:
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)
1578out: 1663out:
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
289static int 289static 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)
324static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, 324static 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;
346retry:
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 */
141struct drm_tile_group {
142 struct kref refcount;
143 struct drm_device *dev;
144 int id;
145 u8 group_data[8];
146};
147
140struct drm_framebuffer_funcs { 148struct 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
1191extern int drm_mode_connector_set_path_property(struct drm_connector *connector, 1221extern int drm_mode_connector_set_path_property(struct drm_connector *connector,
1192 const char *path); 1222 const char *path);
1223int drm_mode_connector_set_tile_property(struct drm_connector *connector);
1193extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, 1224extern 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,
1326extern int drm_edid_header_is_valid(const u8 *raw_edid); 1357extern int drm_edid_header_is_valid(const u8 *raw_edid);
1327extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid); 1358extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid);
1328extern bool drm_edid_is_valid(struct edid *edid); 1359extern bool drm_edid_is_valid(struct edid *edid);
1360
1361extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
1362 char topology[8]);
1363extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
1364 char topology[8]);
1365extern void drm_mode_put_tile_group(struct drm_device *dev,
1366 struct drm_tile_group *tg);
1329struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, 1367struct 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
54struct displayid_hdr {
55 u8 rev;
56 u8 bytes;
57 u8 prod_id;
58 u8 ext_count;
59} __packed;
60
61struct displayid_block {
62 u8 tag;
63 u8 rev;
64 u8 num_bytes;
65} __packed;
66
67struct 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
474int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled); 476int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled);
475 477
476 478
477enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); 479enum 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
479struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); 481struct 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
37struct est_timings { 39struct 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
37struct drm_fb_offset {
38 int x, y;
39};
40
37struct drm_fb_helper_crtc { 41struct 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
42struct drm_fb_helper_surface_size { 47struct 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