mirror of https://gitee.com/openkylin/linux.git
drm/edid: add displayid detailed 1 timings to the modelist. (v1.1)
The tiled 5K Dell monitor appears to be hiding it's tiled mode inside the displayid timings block, this patch parses this blocks and adds the modes to the modelist. v1.1: add missing __packed. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=95207 Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
c97291774c
commit
a39ed680bd
|
@ -3924,6 +3924,110 @@ static int validate_displayid(u8 *displayid, int length, int idx)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev,
|
||||||
|
struct displayid_detailed_timings_1 *timings)
|
||||||
|
{
|
||||||
|
struct drm_display_mode *mode;
|
||||||
|
unsigned pixel_clock = (timings->pixel_clock[0] |
|
||||||
|
(timings->pixel_clock[1] << 8) |
|
||||||
|
(timings->pixel_clock[2] << 16));
|
||||||
|
unsigned hactive = (timings->hactive[0] | timings->hactive[1] << 8) + 1;
|
||||||
|
unsigned hblank = (timings->hblank[0] | timings->hblank[1] << 8) + 1;
|
||||||
|
unsigned hsync = (timings->hsync[0] | (timings->hsync[1] & 0x7f) << 8) + 1;
|
||||||
|
unsigned hsync_width = (timings->hsw[0] | timings->hsw[1] << 8) + 1;
|
||||||
|
unsigned vactive = (timings->vactive[0] | timings->vactive[1] << 8) + 1;
|
||||||
|
unsigned vblank = (timings->vblank[0] | timings->vblank[1] << 8) + 1;
|
||||||
|
unsigned vsync = (timings->vsync[0] | (timings->vsync[1] & 0x7f) << 8) + 1;
|
||||||
|
unsigned vsync_width = (timings->vsw[0] | timings->vsw[1] << 8) + 1;
|
||||||
|
bool hsync_positive = (timings->hsync[1] >> 7) & 0x1;
|
||||||
|
bool vsync_positive = (timings->vsync[1] >> 7) & 0x1;
|
||||||
|
mode = drm_mode_create(dev);
|
||||||
|
if (!mode)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
mode->clock = pixel_clock * 10;
|
||||||
|
mode->hdisplay = hactive;
|
||||||
|
mode->hsync_start = mode->hdisplay + hsync;
|
||||||
|
mode->hsync_end = mode->hsync_start + hsync_width;
|
||||||
|
mode->htotal = mode->hdisplay + hblank;
|
||||||
|
|
||||||
|
mode->vdisplay = vactive;
|
||||||
|
mode->vsync_start = mode->vdisplay + vsync;
|
||||||
|
mode->vsync_end = mode->vsync_start + vsync_width;
|
||||||
|
mode->vtotal = mode->vdisplay + vblank;
|
||||||
|
|
||||||
|
mode->flags = 0;
|
||||||
|
mode->flags |= hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
|
||||||
|
mode->flags |= vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
|
||||||
|
mode->type = DRM_MODE_TYPE_DRIVER;
|
||||||
|
|
||||||
|
if (timings->flags & 0x80)
|
||||||
|
mode->type |= DRM_MODE_TYPE_PREFERRED;
|
||||||
|
mode->vrefresh = drm_mode_vrefresh(mode);
|
||||||
|
drm_mode_set_name(mode);
|
||||||
|
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_displayid_detailed_1_modes(struct drm_connector *connector,
|
||||||
|
struct displayid_block *block)
|
||||||
|
{
|
||||||
|
struct displayid_detailed_timing_block *det = (struct displayid_detailed_timing_block *)block;
|
||||||
|
int i;
|
||||||
|
int num_timings;
|
||||||
|
struct drm_display_mode *newmode;
|
||||||
|
int num_modes = 0;
|
||||||
|
/* blocks must be multiple of 20 bytes length */
|
||||||
|
if (block->num_bytes % 20)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
num_timings = block->num_bytes / 20;
|
||||||
|
for (i = 0; i < num_timings; i++) {
|
||||||
|
struct displayid_detailed_timings_1 *timings = &det->timings[i];
|
||||||
|
|
||||||
|
newmode = drm_mode_displayid_detailed(connector->dev, timings);
|
||||||
|
if (!newmode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
drm_mode_probed_add(connector, newmode);
|
||||||
|
num_modes++;
|
||||||
|
}
|
||||||
|
return num_modes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_displayid_detailed_modes(struct drm_connector *connector,
|
||||||
|
struct edid *edid)
|
||||||
|
{
|
||||||
|
u8 *displayid;
|
||||||
|
int ret;
|
||||||
|
int idx = 1;
|
||||||
|
int length = EDID_LENGTH;
|
||||||
|
struct displayid_block *block;
|
||||||
|
int num_modes = 0;
|
||||||
|
|
||||||
|
displayid = drm_find_displayid_extension(edid);
|
||||||
|
if (!displayid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = validate_displayid(displayid, length, idx);
|
||||||
|
if (ret)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
idx += sizeof(struct displayid_hdr);
|
||||||
|
while (block = (struct displayid_block *)&displayid[idx],
|
||||||
|
idx + sizeof(struct displayid_block) <= length &&
|
||||||
|
idx + sizeof(struct displayid_block) + block->num_bytes <= length &&
|
||||||
|
block->num_bytes > 0) {
|
||||||
|
idx += block->num_bytes + sizeof(struct displayid_block);
|
||||||
|
switch (block->tag) {
|
||||||
|
case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
|
||||||
|
num_modes += add_displayid_detailed_1_modes(connector, block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num_modes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_add_edid_modes - add modes from EDID data, if available
|
* drm_add_edid_modes - add modes from EDID data, if available
|
||||||
* @connector: connector we're probing
|
* @connector: connector we're probing
|
||||||
|
@ -3969,6 +4073,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
||||||
num_modes += add_established_modes(connector, edid);
|
num_modes += add_established_modes(connector, edid);
|
||||||
num_modes += add_cea_modes(connector, edid);
|
num_modes += add_cea_modes(connector, edid);
|
||||||
num_modes += add_alternate_cea_modes(connector, edid);
|
num_modes += add_alternate_cea_modes(connector, edid);
|
||||||
|
num_modes += add_displayid_detailed_modes(connector, edid);
|
||||||
if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
|
if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
|
||||||
num_modes += add_inferred_modes(connector, edid);
|
num_modes += add_inferred_modes(connector, edid);
|
||||||
|
|
||||||
|
@ -4260,6 +4365,9 @@ static int drm_parse_display_id(struct drm_connector *connector,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
break;
|
break;
|
||||||
|
case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
|
||||||
|
/* handled in mode gathering code. */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag);
|
DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -73,4 +73,21 @@ struct displayid_tiled_block {
|
||||||
u8 topology_id[8];
|
u8 topology_id[8];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct displayid_detailed_timings_1 {
|
||||||
|
u8 pixel_clock[3];
|
||||||
|
u8 flags;
|
||||||
|
u8 hactive[2];
|
||||||
|
u8 hblank[2];
|
||||||
|
u8 hsync[2];
|
||||||
|
u8 hsw[2];
|
||||||
|
u8 vactive[2];
|
||||||
|
u8 vblank[2];
|
||||||
|
u8 vsync[2];
|
||||||
|
u8 vsw[2];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct displayid_detailed_timing_block {
|
||||||
|
struct displayid_block base;
|
||||||
|
struct displayid_detailed_timings_1 timings[0];
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue