diff options
author | Zhao Yakui <yakui.zhao@intel.com> | 2009-06-22 01:17:10 -0400 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2009-07-15 02:52:02 -0400 |
commit | 5c61259e6c7290082108e93815f7f72f27da14f4 (patch) | |
tree | 5762aa9b05f4233d5d23b4c8d3ca1d91edd550c3 /drivers | |
parent | 26bbdadad356ec02d33657858d91675f3e9aca94 (diff) |
drm/mode: get the modeline for standard timing in EDID by using CVT/GTF
Create the standard timing modeline by using CVT/GFT algorithm while
interpreting the EDID.
In course of interpreting the EDID, the timing level will be obtained,
which is used to determine whether the CVT/GTF algorithm is selected to
generate the modeline for the given hdisplay/vdisplay/vrefresh_rate.
In the UMS mode firstly it will check whether it can be found in
the DMT table. If it can be found, then the modeline is returned. Then the
timing_level is used to choose CVT/GTF.
As there is no DMT table, no modeline is returned when timing level
is DMT. For the other two timing levels, the CVT/GTF will be called to
generate the required standard timing modeline.
[airlied: fixed up conflicts since EDID rework]
Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 70 |
1 files changed, 58 insertions, 12 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 80cc6d06d61b..bbcb2e22675b 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -61,6 +61,10 @@ | |||
61 | /* use +hsync +vsync for detailed mode */ | 61 | /* use +hsync +vsync for detailed mode */ |
62 | #define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) | 62 | #define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) |
63 | 63 | ||
64 | #define LEVEL_DMT 0 | ||
65 | #define LEVEL_GTF 1 | ||
66 | #define LEVEL_CVT 2 | ||
67 | |||
64 | static struct edid_quirk { | 68 | static struct edid_quirk { |
65 | char *vendor; | 69 | char *vendor; |
66 | int product_id; | 70 | int product_id; |
@@ -240,25 +244,31 @@ static void edid_fixup_preferred(struct drm_connector *connector, | |||
240 | /** | 244 | /** |
241 | * drm_mode_std - convert standard mode info (width, height, refresh) into mode | 245 | * drm_mode_std - convert standard mode info (width, height, refresh) into mode |
242 | * @t: standard timing params | 246 | * @t: standard timing params |
247 | * @timing_level: standard timing level | ||
243 | * | 248 | * |
244 | * Take the standard timing params (in this case width, aspect, and refresh) | 249 | * Take the standard timing params (in this case width, aspect, and refresh) |
245 | * and convert them into a real mode using CVT. | 250 | * and convert them into a real mode using CVT/GTF/DMT. |
246 | * | 251 | * |
247 | * Punts for now, but should eventually use the FB layer's CVT based mode | 252 | * Punts for now, but should eventually use the FB layer's CVT based mode |
248 | * generation code. | 253 | * generation code. |
249 | */ | 254 | */ |
250 | struct drm_display_mode *drm_mode_std(struct drm_device *dev, | 255 | struct drm_display_mode *drm_mode_std(struct drm_device *dev, |
251 | struct std_timing *t) | 256 | struct std_timing *t, |
257 | int timing_level) | ||
252 | { | 258 | { |
253 | struct drm_display_mode *mode; | 259 | struct drm_display_mode *mode; |
254 | int hsize = t->hsize * 8 + 248, vsize; | 260 | int hsize, vsize; |
261 | int vrefresh_rate; | ||
255 | unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK) | 262 | unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK) |
256 | >> EDID_TIMING_ASPECT_SHIFT; | 263 | >> EDID_TIMING_ASPECT_SHIFT; |
257 | 264 | unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK) | |
258 | mode = drm_mode_create(dev); | 265 | >> EDID_TIMING_VFREQ_SHIFT; |
259 | if (!mode) | 266 | |
260 | return NULL; | 267 | /* According to the EDID spec, the hdisplay = hsize * 8 + 248 */ |
261 | 268 | hsize = t->hsize * 8 + 248; | |
269 | /* vrefresh_rate = vfreq + 60 */ | ||
270 | vrefresh_rate = vfreq + 60; | ||
271 | /* the vdisplay is calculated based on the aspect ratio */ | ||
262 | if (aspect_ratio == 0) | 272 | if (aspect_ratio == 0) |
263 | vsize = (hsize * 10) / 16; | 273 | vsize = (hsize * 10) / 16; |
264 | else if (aspect_ratio == 1) | 274 | else if (aspect_ratio == 1) |
@@ -268,8 +278,23 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, | |||
268 | else | 278 | else |
269 | vsize = (hsize * 9) / 16; | 279 | vsize = (hsize * 9) / 16; |
270 | 280 | ||
271 | drm_mode_set_name(mode); | 281 | mode = NULL; |
272 | 282 | switch (timing_level) { | |
283 | case LEVEL_DMT: | ||
284 | mode = drm_mode_create(dev); | ||
285 | if (mode) { | ||
286 | mode->hdisplay = hsize; | ||
287 | mode->vdisplay = vsize; | ||
288 | drm_mode_set_name(mode); | ||
289 | } | ||
290 | break; | ||
291 | case LEVEL_GTF: | ||
292 | mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); | ||
293 | break; | ||
294 | case LEVEL_CVT: | ||
295 | mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); | ||
296 | break; | ||
297 | } | ||
273 | return mode; | 298 | return mode; |
274 | } | 299 | } |
275 | 300 | ||
@@ -451,6 +476,19 @@ static int add_established_modes(struct drm_connector *connector, struct edid *e | |||
451 | 476 | ||
452 | return modes; | 477 | return modes; |
453 | } | 478 | } |
479 | /** | ||
480 | * stanard_timing_level - get std. timing level(CVT/GTF/DMT) | ||
481 | * @edid: EDID block to scan | ||
482 | */ | ||
483 | static int standard_timing_level(struct edid *edid) | ||
484 | { | ||
485 | if (edid->revision >= 2) { | ||
486 | if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)) | ||
487 | return LEVEL_CVT; | ||
488 | return LEVEL_GTF; | ||
489 | } | ||
490 | return LEVEL_DMT; | ||
491 | } | ||
454 | 492 | ||
455 | /** | 493 | /** |
456 | * add_standard_modes - get std. modes from EDID and add them | 494 | * add_standard_modes - get std. modes from EDID and add them |
@@ -463,6 +501,9 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid | |||
463 | { | 501 | { |
464 | struct drm_device *dev = connector->dev; | 502 | struct drm_device *dev = connector->dev; |
465 | int i, modes = 0; | 503 | int i, modes = 0; |
504 | int timing_level; | ||
505 | |||
506 | timing_level = standard_timing_level(edid); | ||
466 | 507 | ||
467 | for (i = 0; i < EDID_STD_TIMINGS; i++) { | 508 | for (i = 0; i < EDID_STD_TIMINGS; i++) { |
468 | struct std_timing *t = &edid->standard_timings[i]; | 509 | struct std_timing *t = &edid->standard_timings[i]; |
@@ -472,7 +513,8 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid | |||
472 | if (t->hsize == 1 && t->vfreq_aspect == 1) | 513 | if (t->hsize == 1 && t->vfreq_aspect == 1) |
473 | continue; | 514 | continue; |
474 | 515 | ||
475 | newmode = drm_mode_std(dev, &edid->standard_timings[i]); | 516 | newmode = drm_mode_std(dev, &edid->standard_timings[i], |
517 | timing_level); | ||
476 | if (newmode) { | 518 | if (newmode) { |
477 | drm_mode_probed_add(connector, newmode); | 519 | drm_mode_probed_add(connector, newmode); |
478 | modes++; | 520 | modes++; |
@@ -496,6 +538,9 @@ static int add_detailed_info(struct drm_connector *connector, | |||
496 | { | 538 | { |
497 | struct drm_device *dev = connector->dev; | 539 | struct drm_device *dev = connector->dev; |
498 | int i, j, modes = 0; | 540 | int i, j, modes = 0; |
541 | int timing_level; | ||
542 | |||
543 | timing_level = standard_timing_level(edid); | ||
499 | 544 | ||
500 | for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { | 545 | for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { |
501 | struct detailed_timing *timing = &edid->detailed_timings[i]; | 546 | struct detailed_timing *timing = &edid->detailed_timings[i]; |
@@ -541,7 +586,8 @@ static int add_detailed_info(struct drm_connector *connector, | |||
541 | struct drm_display_mode *newmode; | 586 | struct drm_display_mode *newmode; |
542 | 587 | ||
543 | std = &data->data.timings[j]; | 588 | std = &data->data.timings[j]; |
544 | newmode = drm_mode_std(dev, std); | 589 | newmode = drm_mode_std(dev, std, |
590 | timing_level); | ||
545 | if (newmode) { | 591 | if (newmode) { |
546 | drm_mode_probed_add(connector, newmode); | 592 | drm_mode_probed_add(connector, newmode); |
547 | modes++; | 593 | modes++; |