Commit 9cf00977 authored by Adam Jackson's avatar Adam Jackson Committed by Dave Airlie

drm/edid: Unify detailed block parsing between base and extension blocks

Also fix an embarassing bug in standard timing subblock parsing that
would result in an infinite loop.
Signed-off-by: default avatarAdam Jackson <ajax@redhat.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 9632b41f
...@@ -838,53 +838,41 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid ...@@ -838,53 +838,41 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid
return modes; return modes;
} }
/** static int add_detailed_modes(struct drm_connector *connector,
* add_detailed_modes - get detailed mode info from EDID data struct detailed_timing *timing,
* @connector: attached connector struct edid *edid, u32 quirks, int preferred)
* @edid: EDID block to scan
* @quirks: quirks to apply
*
* Some of the detailed timing sections may contain mode information. Grab
* it and add it to the list.
*/
static int add_detailed_info(struct drm_connector *connector,
struct edid *edid, u32 quirks)
{ {
int i, modes = 0;
struct detailed_non_pixel *data = &timing->data.other_data;
int timing_level = standard_timing_level(edid);
struct drm_display_mode *newmode;
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
int i, j, modes = 0;
int timing_level;
timing_level = standard_timing_level(edid); if (timing->pixel_clock) {
newmode = drm_mode_detailed(dev, edid, timing, quirks);
if (!newmode)
return 0;
for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { if (preferred)
struct detailed_timing *timing = &edid->detailed_timings[i]; newmode->type |= DRM_MODE_TYPE_PREFERRED;
struct detailed_non_pixel *data = &timing->data.other_data;
struct drm_display_mode *newmode;
/* X server check is version 1.1 or higher */ drm_mode_probed_add(connector, newmode);
if (edid->version == 1 && edid->revision >= 1 && return 1;
!timing->pixel_clock) { }
/* Other timing or info */
/* other timing types */
switch (data->type) { switch (data->type) {
case EDID_DETAIL_MONITOR_SERIAL:
break;
case EDID_DETAIL_MONITOR_STRING:
break;
case EDID_DETAIL_MONITOR_RANGE: case EDID_DETAIL_MONITOR_RANGE:
/* Get monitor range data */ /* Get monitor range data */
break; break;
case EDID_DETAIL_MONITOR_NAME:
break;
case EDID_DETAIL_MONITOR_CPDATA:
break;
case EDID_DETAIL_STD_MODES: case EDID_DETAIL_STD_MODES:
for (j = 0; j < 6; i++) { /* Six modes per detailed section */
for (i = 0; i < 6; i++) {
struct std_timing *std; struct std_timing *std;
struct drm_display_mode *newmode; struct drm_display_mode *newmode;
std = &data->data.timings[j]; std = &data->data.timings[i];
newmode = drm_mode_std(dev, std, newmode = drm_mode_std(dev, std, edid->revision,
edid->revision,
timing_level); timing_level);
if (newmode) { if (newmode) {
drm_mode_probed_add(connector, newmode); drm_mode_probed_add(connector, newmode);
...@@ -895,22 +883,40 @@ static int add_detailed_info(struct drm_connector *connector, ...@@ -895,22 +883,40 @@ static int add_detailed_info(struct drm_connector *connector,
default: default:
break; break;
} }
} else {
newmode = drm_mode_detailed(dev, edid, timing, quirks);
if (!newmode)
continue;
/* First detailed mode is preferred */ return modes;
if (i == 0 && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING)) }
newmode->type |= DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, newmode);
modes++; /**
} * add_detailed_info - get detailed mode info from EDID data
* @connector: attached connector
* @edid: EDID block to scan
* @quirks: quirks to apply
*
* Some of the detailed timing sections may contain mode information. Grab
* it and add it to the list.
*/
static int add_detailed_info(struct drm_connector *connector,
struct edid *edid, u32 quirks)
{
int i, modes = 0;
for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
struct detailed_timing *timing = &edid->detailed_timings[i];
int preferred = (i == 0) && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
/* In 1.0, only timings are allowed */
if (!timing->pixel_clock && edid->version == 1 &&
edid->revision == 0)
continue;
modes += add_detailed_modes(connector, timing, edid, quirks,
preferred);
} }
return modes; return modes;
} }
/** /**
* add_detailed_mode_eedid - get detailed mode info from addtional timing * add_detailed_mode_eedid - get detailed mode info from addtional timing
* EDID block * EDID block
...@@ -924,12 +930,9 @@ static int add_detailed_info(struct drm_connector *connector, ...@@ -924,12 +930,9 @@ static int add_detailed_info(struct drm_connector *connector,
static int add_detailed_info_eedid(struct drm_connector *connector, static int add_detailed_info_eedid(struct drm_connector *connector,
struct edid *edid, u32 quirks) struct edid *edid, u32 quirks)
{ {
struct drm_device *dev = connector->dev; int i, modes = 0;
int i, j, modes = 0;
char *edid_ext = NULL; char *edid_ext = NULL;
struct detailed_timing *timing; struct detailed_timing *timing;
struct detailed_non_pixel *data;
struct drm_display_mode *newmode;
int edid_ext_num; int edid_ext_num;
int start_offset, end_offset; int start_offset, end_offset;
int timing_level; int timing_level;
...@@ -980,51 +983,7 @@ static int add_detailed_info_eedid(struct drm_connector *connector, ...@@ -980,51 +983,7 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
for (i = start_offset; i < end_offset; for (i = start_offset; i < end_offset;
i += sizeof(struct detailed_timing)) { i += sizeof(struct detailed_timing)) {
timing = (struct detailed_timing *)(edid_ext + i); timing = (struct detailed_timing *)(edid_ext + i);
data = &timing->data.other_data; modes += add_detailed_modes(connector, timing, edid, quirks, 0);
/* Detailed mode timing */
if (timing->pixel_clock) {
newmode = drm_mode_detailed(dev, edid, timing, quirks);
if (!newmode)
continue;
drm_mode_probed_add(connector, newmode);
modes++;
continue;
}
/* Other timing or info */
switch (data->type) {
case EDID_DETAIL_MONITOR_SERIAL:
break;
case EDID_DETAIL_MONITOR_STRING:
break;
case EDID_DETAIL_MONITOR_RANGE:
/* Get monitor range data */
break;
case EDID_DETAIL_MONITOR_NAME:
break;
case EDID_DETAIL_MONITOR_CPDATA:
break;
case EDID_DETAIL_STD_MODES:
/* Five modes per detailed section */
for (j = 0; j < 5; i++) {
struct std_timing *std;
struct drm_display_mode *newmode;
std = &data->data.timings[j];
newmode = drm_mode_std(dev, std,
edid->revision,
timing_level);
if (newmode) {
drm_mode_probed_add(connector, newmode);
modes++;
}
}
break;
default:
break;
}
} }
return modes; return modes;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment