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)
This commit is contained in:
commit
d1b8792b63
|
@ -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 -->
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -839,6 +839,8 @@ 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:
|
||||
|
@ -846,8 +848,9 @@ static void drm_dp_port_teardown_pdt(struct drm_dp_mst_port *port, int old_pdt)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_displayid.h>
|
||||
|
||||
#define version_greater(edid, maj, min) \
|
||||
(((edid)->version > (maj)) || \
|
||||
|
@ -1014,6 +1015,8 @@ module_param_named(edid_fixup, edid_fixup, int, 0400);
|
|||
MODULE_PARM_DESC(edid_fixup,
|
||||
"Minimum number of valid EDID header bytes (0-8, default 6)");
|
||||
|
||||
static void drm_get_displayid(struct drm_connector *connector,
|
||||
struct edid *edid);
|
||||
/**
|
||||
* drm_edid_block_valid - Sanity check the EDID block (base or extension)
|
||||
* @raw_edid: pointer to raw EDID block
|
||||
|
@ -1308,10 +1311,15 @@ EXPORT_SYMBOL(drm_probe_ddc);
|
|||
struct edid *drm_get_edid(struct drm_connector *connector,
|
||||
struct i2c_adapter *adapter)
|
||||
{
|
||||
struct edid *edid;
|
||||
|
||||
if (!drm_probe_ddc(adapter))
|
||||
return NULL;
|
||||
|
||||
return drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
|
||||
edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
|
||||
if (edid)
|
||||
drm_get_displayid(connector, edid);
|
||||
return edid;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_get_edid);
|
||||
|
||||
|
@ -2406,7 +2414,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
|
|||
/*
|
||||
* Search EDID for CEA extension block.
|
||||
*/
|
||||
static u8 *drm_find_cea_extension(struct edid *edid)
|
||||
static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
|
||||
{
|
||||
u8 *edid_ext = NULL;
|
||||
int i;
|
||||
|
@ -2418,7 +2426,7 @@ static u8 *drm_find_cea_extension(struct edid *edid)
|
|||
/* Find CEA extension */
|
||||
for (i = 0; i < edid->extensions; i++) {
|
||||
edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
|
||||
if (edid_ext[0] == CEA_EXT)
|
||||
if (edid_ext[0] == ext_id)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2428,6 +2436,16 @@ static u8 *drm_find_cea_extension(struct edid *edid)
|
|||
return edid_ext;
|
||||
}
|
||||
|
||||
static u8 *drm_find_cea_extension(struct edid *edid)
|
||||
{
|
||||
return drm_find_edid_extension(edid, CEA_EXT);
|
||||
}
|
||||
|
||||
static u8 *drm_find_displayid_extension(struct edid *edid)
|
||||
{
|
||||
return drm_find_edid_extension(edid, DISPLAYID_EXT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the alternate clock for the CEA mode
|
||||
* (60Hz vs. 59.94Hz etc.)
|
||||
|
@ -3888,3 +3906,123 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
|
|||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode);
|
||||
|
||||
static int drm_parse_display_id(struct drm_connector *connector,
|
||||
u8 *displayid, int length,
|
||||
bool is_edid_extension)
|
||||
{
|
||||
/* if this is an EDID extension the first byte will be 0x70 */
|
||||
int idx = 0;
|
||||
struct displayid_hdr *base;
|
||||
struct displayid_block *block;
|
||||
u8 csum = 0;
|
||||
int i;
|
||||
|
||||
if (is_edid_extension)
|
||||
idx = 1;
|
||||
|
||||
base = (struct displayid_hdr *)&displayid[idx];
|
||||
|
||||
DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",
|
||||
base->rev, base->bytes, base->prod_id, base->ext_count);
|
||||
|
||||
if (base->bytes + 5 > length - idx)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = idx; i <= base->bytes + 5; i++) {
|
||||
csum += displayid[i];
|
||||
}
|
||||
if (csum) {
|
||||
DRM_ERROR("DisplayID checksum invalid, remainder is %d\n", csum);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
block = (struct displayid_block *)&displayid[idx + 4];
|
||||
DRM_DEBUG_KMS("block id %d, rev %d, len %d\n",
|
||||
block->tag, block->rev, block->num_bytes);
|
||||
|
||||
switch (block->tag) {
|
||||
case DATA_BLOCK_TILED_DISPLAY: {
|
||||
struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block;
|
||||
|
||||
u16 w, h;
|
||||
u8 tile_v_loc, tile_h_loc;
|
||||
u8 num_v_tile, num_h_tile;
|
||||
struct drm_tile_group *tg;
|
||||
|
||||
w = tile->tile_size[0] | tile->tile_size[1] << 8;
|
||||
h = tile->tile_size[2] | tile->tile_size[3] << 8;
|
||||
|
||||
num_v_tile = (tile->topo[0] & 0xf) | (tile->topo[2] & 0x30);
|
||||
num_h_tile = (tile->topo[0] >> 4) | ((tile->topo[2] >> 2) & 0x30);
|
||||
tile_v_loc = (tile->topo[1] & 0xf) | ((tile->topo[2] & 0x3) << 4);
|
||||
tile_h_loc = (tile->topo[1] >> 4) | (((tile->topo[2] >> 2) & 0x3) << 4);
|
||||
|
||||
connector->has_tile = true;
|
||||
if (tile->tile_cap & 0x80)
|
||||
connector->tile_is_single_monitor = true;
|
||||
|
||||
connector->num_h_tile = num_h_tile + 1;
|
||||
connector->num_v_tile = num_v_tile + 1;
|
||||
connector->tile_h_loc = tile_h_loc;
|
||||
connector->tile_v_loc = tile_v_loc;
|
||||
connector->tile_h_size = w + 1;
|
||||
connector->tile_v_size = h + 1;
|
||||
|
||||
DRM_DEBUG_KMS("tile cap 0x%x\n", tile->tile_cap);
|
||||
DRM_DEBUG_KMS("tile_size %d x %d\n", w + 1, h + 1);
|
||||
DRM_DEBUG_KMS("topo num tiles %dx%d, location %dx%d\n",
|
||||
num_h_tile + 1, num_v_tile + 1, tile_h_loc, tile_v_loc);
|
||||
DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]);
|
||||
|
||||
tg = drm_mode_get_tile_group(connector->dev, tile->topology_id);
|
||||
if (!tg) {
|
||||
tg = drm_mode_create_tile_group(connector->dev, tile->topology_id);
|
||||
}
|
||||
if (!tg)
|
||||
return -ENOMEM;
|
||||
|
||||
if (connector->tile_group != tg) {
|
||||
/* if we haven't got a pointer,
|
||||
take the reference, drop ref to old tile group */
|
||||
if (connector->tile_group) {
|
||||
drm_mode_put_tile_group(connector->dev, connector->tile_group);
|
||||
}
|
||||
connector->tile_group = tg;
|
||||
} else
|
||||
/* if same tile group, then release the ref we just took. */
|
||||
drm_mode_put_tile_group(connector->dev, tg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk("unknown displayid tag %d\n", block->tag);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drm_get_displayid(struct drm_connector *connector,
|
||||
struct edid *edid)
|
||||
{
|
||||
void *displayid = NULL;
|
||||
int ret;
|
||||
connector->has_tile = false;
|
||||
displayid = drm_find_displayid_extension(edid);
|
||||
if (!displayid) {
|
||||
/* drop reference to any tile group we had */
|
||||
goto out_drop_ref;
|
||||
}
|
||||
|
||||
ret = drm_parse_display_id(connector, displayid, EDID_LENGTH, true);
|
||||
if (ret < 0)
|
||||
goto out_drop_ref;
|
||||
if (!connector->has_tile)
|
||||
goto out_drop_ref;
|
||||
return;
|
||||
out_drop_ref:
|
||||
if (connector->tile_group) {
|
||||
drm_mode_put_tile_group(connector->dev, connector->tile_group);
|
||||
connector->tile_group = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -347,9 +347,18 @@ bool drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
|
|||
{
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
bool ret;
|
||||
bool do_delayed = false;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
ret = restore_fbdev_mode(fb_helper);
|
||||
|
||||
do_delayed = fb_helper->delayed_hotplug;
|
||||
if (do_delayed)
|
||||
fb_helper->delayed_hotplug = false;
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
if (do_delayed)
|
||||
drm_fb_helper_hotplug_event(fb_helper);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
|
||||
|
@ -888,10 +897,6 @@ int drm_fb_helper_set_par(struct fb_info *info)
|
|||
|
||||
drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
|
||||
|
||||
if (fb_helper->delayed_hotplug) {
|
||||
fb_helper->delayed_hotplug = false;
|
||||
drm_fb_helper_hotplug_event(fb_helper);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
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,
|
|||
crtc_count = 0;
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
struct drm_display_mode *desired_mode;
|
||||
int x, y;
|
||||
desired_mode = fb_helper->crtc_info[i].desired_mode;
|
||||
|
||||
x = fb_helper->crtc_info[i].x;
|
||||
y = fb_helper->crtc_info[i].y;
|
||||
if (desired_mode) {
|
||||
if (gamma_size == 0)
|
||||
gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
|
||||
if (desired_mode->hdisplay < sizes.fb_width)
|
||||
sizes.fb_width = desired_mode->hdisplay;
|
||||
if (desired_mode->vdisplay < sizes.fb_height)
|
||||
sizes.fb_height = desired_mode->vdisplay;
|
||||
if (desired_mode->hdisplay > sizes.surface_width)
|
||||
sizes.surface_width = desired_mode->hdisplay;
|
||||
if (desired_mode->vdisplay > sizes.surface_height)
|
||||
sizes.surface_height = desired_mode->vdisplay;
|
||||
if (desired_mode->hdisplay + x < sizes.fb_width)
|
||||
sizes.fb_width = desired_mode->hdisplay + x;
|
||||
if (desired_mode->vdisplay + y < sizes.fb_height)
|
||||
sizes.fb_height = desired_mode->vdisplay + y;
|
||||
if (desired_mode->hdisplay + x > sizes.surface_width)
|
||||
sizes.surface_width = desired_mode->hdisplay + x;
|
||||
if (desired_mode->vdisplay + y > sizes.surface_height)
|
||||
sizes.surface_height = desired_mode->vdisplay + y;
|
||||
crtc_count++;
|
||||
}
|
||||
}
|
||||
|
@ -1307,6 +1314,7 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
|
|||
|
||||
static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
|
||||
struct drm_display_mode **modes,
|
||||
struct drm_fb_offset *offsets,
|
||||
bool *enabled, int width, int height)
|
||||
{
|
||||
int count, i, j;
|
||||
|
@ -1378,27 +1386,88 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
|
|||
return false;
|
||||
}
|
||||
|
||||
static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
|
||||
struct drm_display_mode **modes,
|
||||
struct drm_fb_offset *offsets,
|
||||
int idx,
|
||||
int h_idx, int v_idx)
|
||||
{
|
||||
struct drm_fb_helper_connector *fb_helper_conn;
|
||||
int i;
|
||||
int hoffset = 0, voffset = 0;
|
||||
|
||||
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
fb_helper_conn = fb_helper->connector_info[i];
|
||||
if (!fb_helper_conn->connector->has_tile)
|
||||
continue;
|
||||
|
||||
if (!modes[i] && (h_idx || v_idx)) {
|
||||
DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
|
||||
fb_helper_conn->connector->base.id);
|
||||
continue;
|
||||
}
|
||||
if (fb_helper_conn->connector->tile_h_loc < h_idx)
|
||||
hoffset += modes[i]->hdisplay;
|
||||
|
||||
if (fb_helper_conn->connector->tile_v_loc < v_idx)
|
||||
voffset += modes[i]->vdisplay;
|
||||
}
|
||||
offsets[idx].x = hoffset;
|
||||
offsets[idx].y = voffset;
|
||||
DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
|
||||
struct drm_display_mode **modes,
|
||||
struct drm_fb_offset *offsets,
|
||||
bool *enabled, int width, int height)
|
||||
{
|
||||
struct drm_fb_helper_connector *fb_helper_conn;
|
||||
int i;
|
||||
|
||||
uint64_t conn_configured = 0, mask;
|
||||
int tile_pass = 0;
|
||||
mask = (1 << fb_helper->connector_count) - 1;
|
||||
retry:
|
||||
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
fb_helper_conn = fb_helper->connector_info[i];
|
||||
|
||||
if (enabled[i] == false)
|
||||
if (conn_configured & (1 << i))
|
||||
continue;
|
||||
|
||||
if (enabled[i] == false) {
|
||||
conn_configured |= (1 << i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* first pass over all the untiled connectors */
|
||||
if (tile_pass == 0 && fb_helper_conn->connector->has_tile)
|
||||
continue;
|
||||
|
||||
if (tile_pass == 1) {
|
||||
if (fb_helper_conn->connector->tile_h_loc != 0 ||
|
||||
fb_helper_conn->connector->tile_v_loc != 0)
|
||||
continue;
|
||||
|
||||
} else {
|
||||
if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 &&
|
||||
fb_helper_conn->connector->tile_v_loc != tile_pass - 1)
|
||||
/* if this tile_pass doesn't cover any of the tiles - keep going */
|
||||
continue;
|
||||
|
||||
/* find the tile offsets for this pass - need
|
||||
to find all tiles left and above */
|
||||
drm_get_tile_offsets(fb_helper, modes, offsets,
|
||||
i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc);
|
||||
}
|
||||
DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
|
||||
fb_helper_conn->connector->base.id);
|
||||
|
||||
/* got for command line mode first */
|
||||
modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
|
||||
if (!modes[i]) {
|
||||
DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
|
||||
fb_helper_conn->connector->base.id);
|
||||
DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
|
||||
fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0);
|
||||
modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
|
||||
}
|
||||
/* No preferred modes, pick one off the list */
|
||||
|
@ -1408,6 +1477,12 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
|
|||
}
|
||||
DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
|
||||
"none");
|
||||
conn_configured |= (1 << i);
|
||||
}
|
||||
|
||||
if ((conn_configured & mask) != mask) {
|
||||
tile_pass++;
|
||||
goto retry;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1497,6 +1572,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
|||
struct drm_device *dev = fb_helper->dev;
|
||||
struct drm_fb_helper_crtc **crtcs;
|
||||
struct drm_display_mode **modes;
|
||||
struct drm_fb_offset *offsets;
|
||||
struct drm_mode_set *modeset;
|
||||
bool *enabled;
|
||||
int width, height;
|
||||
|
@ -1511,9 +1587,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
|||
sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
|
||||
modes = kcalloc(dev->mode_config.num_connector,
|
||||
sizeof(struct drm_display_mode *), GFP_KERNEL);
|
||||
offsets = kcalloc(dev->mode_config.num_connector,
|
||||
sizeof(struct drm_fb_offset), GFP_KERNEL);
|
||||
enabled = kcalloc(dev->mode_config.num_connector,
|
||||
sizeof(bool), GFP_KERNEL);
|
||||
if (!crtcs || !modes || !enabled) {
|
||||
if (!crtcs || !modes || !enabled || !offsets) {
|
||||
DRM_ERROR("Memory allocation failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
@ -1523,14 +1601,16 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
|||
|
||||
if (!(fb_helper->funcs->initial_config &&
|
||||
fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
|
||||
offsets,
|
||||
enabled, width, height))) {
|
||||
memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0]));
|
||||
memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0]));
|
||||
memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0]));
|
||||
|
||||
if (!drm_target_cloned(fb_helper,
|
||||
modes, enabled, width, height) &&
|
||||
!drm_target_preferred(fb_helper,
|
||||
modes, enabled, width, height))
|
||||
if (!drm_target_cloned(fb_helper, modes, offsets,
|
||||
enabled, width, height) &&
|
||||
!drm_target_preferred(fb_helper, modes, offsets,
|
||||
enabled, width, height))
|
||||
DRM_ERROR("Unable to find initial modes\n");
|
||||
|
||||
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)
|
|||
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
struct drm_display_mode *mode = modes[i];
|
||||
struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
|
||||
struct drm_fb_offset *offset = &offsets[i];
|
||||
modeset = &fb_crtc->mode_set;
|
||||
|
||||
if (mode && fb_crtc) {
|
||||
DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
|
||||
mode->name, fb_crtc->mode_set.crtc->base.id);
|
||||
DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
|
||||
mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
|
||||
fb_crtc->desired_mode = mode;
|
||||
fb_crtc->x = offset->x;
|
||||
fb_crtc->y = offset->y;
|
||||
if (modeset->mode)
|
||||
drm_mode_destroy(dev, modeset->mode);
|
||||
modeset->mode = drm_mode_duplicate(dev,
|
||||
fb_crtc->desired_mode);
|
||||
modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
|
||||
modeset->fb = fb_helper->fb;
|
||||
modeset->x = offset->x;
|
||||
modeset->y = offset->y;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1578,6 +1663,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
|||
out:
|
||||
kfree(crtcs);
|
||||
kfree(modes);
|
||||
kfree(offsets);
|
||||
kfree(enabled);
|
||||
}
|
||||
|
||||
|
|
|
@ -283,7 +283,7 @@ intel_dp_mst_detect(struct drm_connector *connector, bool force)
|
|||
struct intel_connector *intel_connector = to_intel_connector(connector);
|
||||
struct intel_dp *intel_dp = intel_connector->mst_port;
|
||||
|
||||
return drm_dp_mst_detect_port(&intel_dp->mst_mgr, intel_connector->port);
|
||||
return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, intel_connector->port);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -414,6 +414,8 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
|
|||
intel_dp_add_properties(intel_dp, connector);
|
||||
|
||||
drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
|
||||
drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0);
|
||||
|
||||
drm_mode_connector_set_path_property(connector, pathprop);
|
||||
drm_reinit_primary_mode_group(dev);
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
|
|
@ -324,6 +324,7 @@ intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
|
|||
static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
|
||||
struct drm_fb_helper_crtc **crtcs,
|
||||
struct drm_display_mode **modes,
|
||||
struct drm_fb_offset *offsets,
|
||||
bool *enabled, int width, int height)
|
||||
{
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
|
@ -332,6 +333,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
|
|||
bool fallback = true;
|
||||
int num_connectors_enabled = 0;
|
||||
int num_connectors_detected = 0;
|
||||
uint64_t conn_configured = 0, mask;
|
||||
int pass = 0;
|
||||
|
||||
save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool),
|
||||
GFP_KERNEL);
|
||||
|
@ -339,7 +342,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
|
|||
return false;
|
||||
|
||||
memcpy(save_enabled, enabled, dev->mode_config.num_connector);
|
||||
|
||||
mask = (1 << fb_helper->connector_count) - 1;
|
||||
retry:
|
||||
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
struct drm_fb_helper_connector *fb_conn;
|
||||
struct drm_connector *connector;
|
||||
|
@ -349,12 +353,19 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
|
|||
fb_conn = fb_helper->connector_info[i];
|
||||
connector = fb_conn->connector;
|
||||
|
||||
if (conn_configured & (1 << i))
|
||||
continue;
|
||||
|
||||
if (pass == 0 && !connector->has_tile)
|
||||
continue;
|
||||
|
||||
if (connector->status == connector_status_connected)
|
||||
num_connectors_detected++;
|
||||
|
||||
if (!enabled[i]) {
|
||||
DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
|
||||
connector->name);
|
||||
conn_configured |= (1 << i);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -373,6 +384,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
|
|||
DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
|
||||
connector->name);
|
||||
enabled[i] = false;
|
||||
conn_configured |= (1 << i);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -400,8 +412,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
|
|||
|
||||
/* try for preferred next */
|
||||
if (!modes[i]) {
|
||||
DRM_DEBUG_KMS("looking for preferred mode on connector %s\n",
|
||||
connector->name);
|
||||
DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
|
||||
connector->name, connector->has_tile);
|
||||
modes[i] = drm_has_preferred_mode(fb_conn, width,
|
||||
height);
|
||||
}
|
||||
|
@ -444,6 +456,12 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
|
|||
modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :"");
|
||||
|
||||
fallback = false;
|
||||
conn_configured |= (1 << i);
|
||||
}
|
||||
|
||||
if ((conn_configured & mask) != mask) {
|
||||
pass++;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -137,6 +137,14 @@ struct drm_display_info {
|
|||
u8 cea_rev;
|
||||
};
|
||||
|
||||
/* data corresponds to displayid vend/prod/serial */
|
||||
struct drm_tile_group {
|
||||
struct kref refcount;
|
||||
struct drm_device *dev;
|
||||
int id;
|
||||
u8 group_data[8];
|
||||
};
|
||||
|
||||
struct drm_framebuffer_funcs {
|
||||
/* note: use drm_framebuffer_remove() */
|
||||
void (*destroy)(struct drm_framebuffer *framebuffer);
|
||||
|
@ -599,6 +607,15 @@ struct drm_encoder {
|
|||
* @bad_edid_counter: track sinks that give us an EDID with invalid checksum
|
||||
* @debugfs_entry: debugfs directory for this connector
|
||||
* @state: current atomic state for this connector
|
||||
* @has_tile: is this connector connected to a tiled monitor
|
||||
* @tile_group: tile group for the connected monitor
|
||||
* @tile_is_single_monitor: whether the tile is one monitor housing
|
||||
* @num_h_tile: number of horizontal tiles in the tile group
|
||||
* @num_v_tile: number of vertical tiles in the tile group
|
||||
* @tile_h_loc: horizontal location of this tile
|
||||
* @tile_v_loc: vertical location of this tile
|
||||
* @tile_h_size: horizontal size of this tile.
|
||||
* @tile_v_size: vertical size of this tile.
|
||||
*
|
||||
* Each connector may be connected to one or more CRTCs, or may be clonable by
|
||||
* another connector if they can share a CRTC. Each connector also has a specific
|
||||
|
@ -634,6 +651,8 @@ struct drm_connector {
|
|||
|
||||
struct drm_property_blob *path_blob_ptr;
|
||||
|
||||
struct drm_property_blob *tile_blob_ptr;
|
||||
|
||||
uint8_t polled; /* DRM_CONNECTOR_POLL_* */
|
||||
|
||||
/* requested DPMS state */
|
||||
|
@ -661,6 +680,15 @@ struct drm_connector {
|
|||
struct dentry *debugfs_entry;
|
||||
|
||||
struct drm_connector_state *state;
|
||||
|
||||
/* DisplayID bits */
|
||||
bool has_tile;
|
||||
struct drm_tile_group *tile_group;
|
||||
bool tile_is_single_monitor;
|
||||
|
||||
uint8_t num_h_tile, num_v_tile;
|
||||
uint8_t tile_h_loc, tile_v_loc;
|
||||
uint16_t tile_h_size, tile_v_size;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -978,6 +1006,7 @@ struct drm_mode_config {
|
|||
struct drm_modeset_acquire_ctx *acquire_ctx; /* for legacy _lock_all() / _unlock_all() */
|
||||
struct mutex idr_mutex; /* for IDR management */
|
||||
struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
|
||||
struct idr tile_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
|
||||
/* this is limited to one for now */
|
||||
|
||||
struct mutex fb_lock; /* proctects global and per-file fb lists */
|
||||
|
@ -1021,6 +1050,7 @@ struct drm_mode_config {
|
|||
struct drm_property *edid_property;
|
||||
struct drm_property *dpms_property;
|
||||
struct drm_property *path_property;
|
||||
struct drm_property *tile_property;
|
||||
struct drm_property *plane_type_property;
|
||||
struct drm_property *rotation_property;
|
||||
|
||||
|
@ -1190,6 +1220,7 @@ extern void drm_mode_config_cleanup(struct drm_device *dev);
|
|||
|
||||
extern int drm_mode_connector_set_path_property(struct drm_connector *connector,
|
||||
const char *path);
|
||||
int drm_mode_connector_set_tile_property(struct drm_connector *connector);
|
||||
extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
|
||||
const struct edid *edid);
|
||||
|
||||
|
@ -1326,6 +1357,13 @@ extern void drm_set_preferred_mode(struct drm_connector *connector,
|
|||
extern int drm_edid_header_is_valid(const u8 *raw_edid);
|
||||
extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid);
|
||||
extern bool drm_edid_is_valid(struct edid *edid);
|
||||
|
||||
extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
|
||||
char topology[8]);
|
||||
extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
|
||||
char topology[8]);
|
||||
extern void drm_mode_put_tile_group(struct drm_device *dev,
|
||||
struct drm_tile_group *tg);
|
||||
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
|
||||
int hsize, int vsize, int fresh,
|
||||
bool rb);
|
||||
|
|
76
include/drm/drm_displayid.h
Normal file
76
include/drm/drm_displayid.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright © 2014 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef DRM_DISPLAYID_H
|
||||
#define DRM_DISPLAYID_H
|
||||
|
||||
#define DATA_BLOCK_PRODUCT_ID 0x00
|
||||
#define DATA_BLOCK_DISPLAY_PARAMETERS 0x01
|
||||
#define DATA_BLOCK_COLOR_CHARACTERISTICS 0x02
|
||||
#define DATA_BLOCK_TYPE_1_DETAILED_TIMING 0x03
|
||||
#define DATA_BLOCK_TYPE_2_DETAILED_TIMING 0x04
|
||||
#define DATA_BLOCK_TYPE_3_SHORT_TIMING 0x05
|
||||
#define DATA_BLOCK_TYPE_4_DMT_TIMING 0x06
|
||||
#define DATA_BLOCK_VESA_TIMING 0x07
|
||||
#define DATA_BLOCK_CEA_TIMING 0x08
|
||||
#define DATA_BLOCK_VIDEO_TIMING_RANGE 0x09
|
||||
#define DATA_BLOCK_PRODUCT_SERIAL_NUMBER 0x0a
|
||||
#define DATA_BLOCK_GP_ASCII_STRING 0x0b
|
||||
#define DATA_BLOCK_DISPLAY_DEVICE_DATA 0x0c
|
||||
#define DATA_BLOCK_INTERFACE_POWER_SEQUENCING 0x0d
|
||||
#define DATA_BLOCK_TRANSFER_CHARACTERISTICS 0x0e
|
||||
#define DATA_BLOCK_DISPLAY_INTERFACE 0x0f
|
||||
#define DATA_BLOCK_STEREO_DISPLAY_INTERFACE 0x10
|
||||
#define DATA_BLOCK_TILED_DISPLAY 0x12
|
||||
|
||||
#define DATA_BLOCK_VENDOR_SPECIFIC 0x7f
|
||||
|
||||
#define PRODUCT_TYPE_EXTENSION 0
|
||||
#define PRODUCT_TYPE_TEST 1
|
||||
#define PRODUCT_TYPE_PANEL 2
|
||||
#define PRODUCT_TYPE_MONITOR 3
|
||||
#define PRODUCT_TYPE_TV 4
|
||||
#define PRODUCT_TYPE_REPEATER 5
|
||||
#define PRODUCT_TYPE_DIRECT_DRIVE 6
|
||||
|
||||
struct displayid_hdr {
|
||||
u8 rev;
|
||||
u8 bytes;
|
||||
u8 prod_id;
|
||||
u8 ext_count;
|
||||
} __packed;
|
||||
|
||||
struct displayid_block {
|
||||
u8 tag;
|
||||
u8 rev;
|
||||
u8 num_bytes;
|
||||
} __packed;
|
||||
|
||||
struct displayid_tiled_block {
|
||||
struct displayid_block base;
|
||||
u8 tile_cap;
|
||||
u8 topo[3];
|
||||
u8 tile_size[4];
|
||||
u8 tile_pixel_bezel[5];
|
||||
u8 topology_id[8];
|
||||
} __packed;
|
||||
|
||||
#endif
|
|
@ -92,6 +92,8 @@ struct drm_dp_mst_port {
|
|||
struct drm_dp_vcpi vcpi;
|
||||
struct drm_connector *connector;
|
||||
struct drm_dp_mst_topology_mgr *mgr;
|
||||
|
||||
struct edid *cached_edid; /* for DP logical ports - make tiling work */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -474,7 +476,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
|
|||
int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
|
||||
|
||||
|
|
|
@ -27,12 +27,14 @@
|
|||
|
||||
#define EDID_LENGTH 128
|
||||
#define DDC_ADDR 0x50
|
||||
#define DDC_ADDR2 0x52 /* E-DDC 1.2 - where DisplayID can hide */
|
||||
|
||||
#define CEA_EXT 0x02
|
||||
#define VTB_EXT 0x10
|
||||
#define DI_EXT 0x40
|
||||
#define LS_EXT 0x50
|
||||
#define MI_EXT 0x60
|
||||
#define DISPLAYID_EXT 0x70
|
||||
|
||||
struct est_timings {
|
||||
u8 t1;
|
||||
|
|
|
@ -34,9 +34,14 @@ struct drm_fb_helper;
|
|||
|
||||
#include <linux/kgdb.h>
|
||||
|
||||
struct drm_fb_offset {
|
||||
int x, y;
|
||||
};
|
||||
|
||||
struct drm_fb_helper_crtc {
|
||||
struct drm_mode_set mode_set;
|
||||
struct drm_display_mode *desired_mode;
|
||||
int x, y;
|
||||
};
|
||||
|
||||
struct drm_fb_helper_surface_size {
|
||||
|
@ -72,6 +77,7 @@ struct drm_fb_helper_funcs {
|
|||
bool (*initial_config)(struct drm_fb_helper *fb_helper,
|
||||
struct drm_fb_helper_crtc **crtcs,
|
||||
struct drm_display_mode **modes,
|
||||
struct drm_fb_offset *offsets,
|
||||
bool *enabled, int width, int height);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue