Skip to content

Commit

Permalink
Merge branch 'drm-mst-next' of ssh://people.freedesktop.org/~/linux i…
Browse files Browse the repository at this point in the history
…nto 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)
  • Loading branch information
Dave Airlie committed Dec 8, 2014
2 parents b75478d + b0ee9e7 commit d1b8792
Show file tree
Hide file tree
Showing 13 changed files with 593 additions and 39 deletions.
13 changes: 12 additions & 1 deletion Documentation/DocBook/drm.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2412,6 +2412,10 @@ void intel_crt_init(struct drm_device *dev)
!Edrivers/gpu/drm/drm_plane_helper.c
!Pdrivers/gpu/drm/drm_plane_helper.c overview
</sect2>
<sect2>
<title>Tile group</title>
!Pdrivers/gpu/drm/drm_crtc.c Tile group
</sect2>
</sect1>

<!-- Internals: kms properties -->
Expand Down Expand Up @@ -2547,7 +2551,7 @@ void intel_crt_init(struct drm_device *dev)
</tr>
<tr>
<td rowspan="23" valign="top" >DRM</td>
<td rowspan="3" valign="top" >Generic</td>
<td rowspan="4" valign="top" >Generic</td>
<td valign="top" >“EDID”</td>
<td valign="top" >BLOB | IMMUTABLE</td>
<td valign="top" >0</td>
Expand All @@ -2569,6 +2573,13 @@ void intel_crt_init(struct drm_device *dev)
<td valign="top" >Contains topology path to a connector.</td>
</tr>
<tr>
<td valign="top" >“TILE”</td>
<td valign="top" >BLOB | IMMUTABLE</td>
<td valign="top" >0</td>
<td valign="top" >Connector</td>
<td valign="top" >Contains tiling information for a connector.</td>
</tr>
<tr>
<td rowspan="1" valign="top" >Plane</td>
<td valign="top" >“type”</td>
<td valign="top" >ENUM | IMMUTABLE</td>
Expand Down
155 changes: 155 additions & 0 deletions drivers/gpu/drm/drm_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,11 @@ void drm_connector_cleanup(struct drm_connector *connector)
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode, *t;

if (connector->tile_group) {
drm_mode_put_tile_group(dev, connector->tile_group);
connector->tile_group = NULL;
}

list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
drm_mode_remove(connector, mode);

Expand Down Expand Up @@ -1339,6 +1344,11 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
"PATH", 0);
dev->mode_config.path_property = dev_path;

dev->mode_config.tile_property = drm_property_create(dev,
DRM_MODE_PROP_BLOB |
DRM_MODE_PROP_IMMUTABLE,
"TILE", 0);

return 0;
}

Expand Down Expand Up @@ -4082,6 +4092,52 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_mode_connector_set_path_property);

/**
* drm_mode_connector_set_tile_property - set tile property on connector
* @connector: connector to set property on.
*
* This looks up the tile information for a connector, and creates a
* property for userspace to parse if it exists. The property is of
* the form of 8 integers using ':' as a separator.
*
* Returns:
* Zero on success, errno on failure.
*/
int drm_mode_connector_set_tile_property(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
int ret, size;
char tile[256];

if (connector->tile_blob_ptr)
drm_property_destroy_blob(dev, connector->tile_blob_ptr);

if (!connector->has_tile) {
connector->tile_blob_ptr = NULL;
ret = drm_object_property_set_value(&connector->base,
dev->mode_config.tile_property, 0);
return ret;
}

snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d",
connector->tile_group->id, connector->tile_is_single_monitor,
connector->num_h_tile, connector->num_v_tile,
connector->tile_h_loc, connector->tile_v_loc,
connector->tile_h_size, connector->tile_v_size);
size = strlen(tile) + 1;

connector->tile_blob_ptr = drm_property_create_blob(connector->dev,
size, tile);
if (!connector->tile_blob_ptr)
return -EINVAL;

ret = drm_object_property_set_value(&connector->base,
dev->mode_config.tile_property,
connector->tile_blob_ptr->base.id);
return ret;
}
EXPORT_SYMBOL(drm_mode_connector_set_tile_property);

/**
* drm_mode_connector_update_edid_property - update the edid property of a connector
* @connector: drm connector
Expand Down Expand Up @@ -5152,6 +5208,7 @@ void drm_mode_config_init(struct drm_device *dev)
INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
INIT_LIST_HEAD(&dev->mode_config.plane_list);
idr_init(&dev->mode_config.crtc_idr);
idr_init(&dev->mode_config.tile_idr);

drm_modeset_lock_all(dev);
drm_mode_create_standard_connector_properties(dev);
Expand Down Expand Up @@ -5239,6 +5296,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
crtc->funcs->destroy(crtc);
}

idr_destroy(&dev->mode_config.tile_idr);
idr_destroy(&dev->mode_config.crtc_idr);
drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
}
Expand All @@ -5261,3 +5319,100 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
supported_rotations);
}
EXPORT_SYMBOL(drm_mode_create_rotation_property);

/**
* DOC: Tile group
*
* Tile groups are used to represent tiled monitors with a unique
* integer identifier. Tiled monitors using DisplayID v1.3 have
* a unique 8-byte handle, we store this in a tile group, so we
* have a common identifier for all tiles in a monitor group.
*/
static void drm_tile_group_free(struct kref *kref)
{
struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
struct drm_device *dev = tg->dev;
mutex_lock(&dev->mode_config.idr_mutex);
idr_remove(&dev->mode_config.tile_idr, tg->id);
mutex_unlock(&dev->mode_config.idr_mutex);
kfree(tg);
}

/**
* drm_mode_put_tile_group - drop a reference to a tile group.
* @dev: DRM device
* @tg: tile group to drop reference to.
*
* drop reference to tile group and free if 0.
*/
void drm_mode_put_tile_group(struct drm_device *dev,
struct drm_tile_group *tg)
{
kref_put(&tg->refcount, drm_tile_group_free);
}

/**
* drm_mode_get_tile_group - get a reference to an existing tile group
* @dev: DRM device
* @topology: 8-bytes unique per monitor.
*
* Use the unique bytes to get a reference to an existing tile group.
*
* RETURNS:
* tile group or NULL if not found.
*/
struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
char topology[8])
{
struct drm_tile_group *tg;
int id;
mutex_lock(&dev->mode_config.idr_mutex);
idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
if (!memcmp(tg->group_data, topology, 8)) {
if (!kref_get_unless_zero(&tg->refcount))
tg = NULL;
mutex_unlock(&dev->mode_config.idr_mutex);
return tg;
}
}
mutex_unlock(&dev->mode_config.idr_mutex);
return NULL;
}

/**
* drm_mode_create_tile_group - create a tile group from a displayid description
* @dev: DRM device
* @topology: 8-bytes unique per monitor.
*
* Create a tile group for the unique monitor, and get a unique
* identifier for the tile group.
*
* RETURNS:
* new tile group or error.
*/
struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
char topology[8])
{
struct drm_tile_group *tg;
int ret;

tg = kzalloc(sizeof(*tg), GFP_KERNEL);
if (!tg)
return ERR_PTR(-ENOMEM);

kref_init(&tg->refcount);
memcpy(tg->group_data, topology, 8);
tg->dev = dev;

mutex_lock(&dev->mode_config.idr_mutex);
ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL);
if (ret >= 0) {
tg->id = ret;
} else {
kfree(tg);
tg = ERR_PTR(ret);
}

mutex_unlock(&dev->mode_config.idr_mutex);
return tg;
}
7 changes: 4 additions & 3 deletions drivers/gpu/drm/drm_dp_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,11 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,

/*
* The specification doesn't give any recommendation on how often to
* retry native transactions, so retry 7 times like for I2C-over-AUX
* transactions.
* retry native transactions. We used to retry 7 times like for
* aux i2c transactions but real world devices this wasn't
* sufficient, bump to 32 which makes Dell 4k monitors happier.
*/
for (retry = 0; retry < 7; retry++) {
for (retry = 0; retry < 32; retry++) {

mutex_lock(&aux->hw_mutex);
err = aux->transfer(aux, &msg);
Expand Down
25 changes: 22 additions & 3 deletions drivers/gpu/drm/drm_dp_mst_topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -839,15 +839,18 @@ static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb)

static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt)
{
struct drm_dp_mst_branch *mstb;

switch (old_pdt) {
case DP_PEER_DEVICE_DP_LEGACY_CONV:
case DP_PEER_DEVICE_SST_SINK:
/* remove i2c over sideband */
drm_dp_mst_unregister_i2c_bus(&port->aux);
break;
case DP_PEER_DEVICE_MST_BRANCHING:
drm_dp_put_mst_branch_device(port->mstb);
mstb = port->mstb;
port->mstb = NULL;
drm_dp_put_mst_branch_device(mstb);
break;
}
}
Expand All @@ -858,6 +861,8 @@ static void drm_dp_destroy_port(struct kref *kref)
struct drm_dp_mst_topology_mgr *mgr = port->mgr;
if (!port->input) {
port->vcpi.num_slots = 0;

kfree(port->cached_edid);
if (port->connector)
(*port->mgr->cbs->destroy_connector)(mgr, port->connector);
drm_dp_port_teardown_pdt(port, port->pdt);
Expand Down Expand Up @@ -1097,6 +1102,10 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
char proppath[255];
build_mst_prop_path(port, mstb, proppath, sizeof(proppath));
port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath);

if (port->port_num >= 8) {
port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
}
}

/* put reference to this port */
Expand Down Expand Up @@ -2167,7 +2176,8 @@ EXPORT_SYMBOL(drm_dp_mst_hpd_irq);
* This returns the current connection state for a port. It validates the
* port pointer still exists so the caller doesn't require a reference
*/
enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
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)
{
enum drm_connector_status status = connector_status_disconnected;

Expand All @@ -2186,6 +2196,10 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr

case DP_PEER_DEVICE_SST_SINK:
status = connector_status_connected;
/* for logical ports - cache the EDID */
if (port->port_num >= 8 && !port->cached_edid) {
port->cached_edid = drm_get_edid(connector, &port->aux.ddc);
}
break;
case DP_PEER_DEVICE_DP_LEGACY_CONV:
if (port->ldps)
Expand Down Expand Up @@ -2217,7 +2231,12 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
if (!port)
return NULL;

edid = drm_get_edid(connector, &port->aux.ddc);
if (port->cached_edid)
edid = drm_edid_duplicate(port->cached_edid);
else
edid = drm_get_edid(connector, &port->aux.ddc);

drm_mode_connector_set_tile_property(connector);
drm_dp_put_port(port);
return edid;
}
Expand Down
Loading

0 comments on commit d1b8792

Please sign in to comment.