aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2010-03-29 17:43:30 -0400
committerDave Airlie <airlied@redhat.com>2010-04-05 20:40:25 -0400
commit7a37435008b0ffea2442eb1134ddd4adeea81e19 (patch)
treecb0f68ab38d1a6572a913857c67e782ca34ad99c
parent7ca6adb37918db21d076a489c6c39490fb34264e (diff)
drm/edid: Add secondary GTF curve support
Before CVT-R, some monitors would advertise support for an alternative GTF formula with lower blanking intervals. Correctly identify such monitors, and use the alternative formula when generating modes for them. Note that we only do this for "standard" timing descriptors (tuples of hsize in characters / aspect ratio / vertical refresh). Range-based mode lists still only refer to the primary GTF curve. It would be possible to do better for the latter case, but monitors are required to support the primary curve over the entire advertised range, so all it would win you is a lower pixel clock and therefore possibly better image quality on analog links. Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_edid.c119
-rw-r--r--drivers/gpu/drm/drm_modes.c81
-rw-r--r--include/drm/drm_crtc.h4
3 files changed, 150 insertions, 54 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 6e999bd03935..3924a7bf271a 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -64,7 +64,8 @@
64 64
65#define LEVEL_DMT 0 65#define LEVEL_DMT 0
66#define LEVEL_GTF 1 66#define LEVEL_GTF 1
67#define LEVEL_CVT 2 67#define LEVEL_GTF2 2
68#define LEVEL_CVT 3
68 69
69static struct edid_quirk { 70static struct edid_quirk {
70 char *vendor; 71 char *vendor;
@@ -713,6 +714,71 @@ drm_monitor_supports_rb(struct edid *edid)
713 return ((edid->input & DRM_EDID_INPUT_DIGITAL) != 0); 714 return ((edid->input & DRM_EDID_INPUT_DIGITAL) != 0);
714} 715}
715 716
717static void
718find_gtf2(struct detailed_timing *t, void *data)
719{
720 u8 *r = (u8 *)t;
721 if (r[3] == EDID_DETAIL_MONITOR_RANGE && r[10] == 0x02)
722 *(u8 **)data = r;
723}
724
725/* Secondary GTF curve kicks in above some break frequency */
726static int
727drm_gtf2_hbreak(struct edid *edid)
728{
729 u8 *r = NULL;
730 drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
731 return r ? (r[12] * 2) : 0;
732}
733
734static int
735drm_gtf2_2c(struct edid *edid)
736{
737 u8 *r = NULL;
738 drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
739 return r ? r[13] : 0;
740}
741
742static int
743drm_gtf2_m(struct edid *edid)
744{
745 u8 *r = NULL;
746 drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
747 return r ? (r[15] << 8) + r[14] : 0;
748}
749
750static int
751drm_gtf2_k(struct edid *edid)
752{
753 u8 *r = NULL;
754 drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
755 return r ? r[16] : 0;
756}
757
758static int
759drm_gtf2_2j(struct edid *edid)
760{
761 u8 *r = NULL;
762 drm_for_each_detailed_block((u8 *)edid, find_gtf2, &r);
763 return r ? r[17] : 0;
764}
765
766/**
767 * standard_timing_level - get std. timing level(CVT/GTF/DMT)
768 * @edid: EDID block to scan
769 */
770static int standard_timing_level(struct edid *edid)
771{
772 if (edid->revision >= 2) {
773 if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF))
774 return LEVEL_CVT;
775 if (drm_gtf2_hbreak(edid))
776 return LEVEL_GTF2;
777 return LEVEL_GTF;
778 }
779 return LEVEL_DMT;
780}
781
716/* 782/*
717 * 0 is reserved. The spec says 0x01 fill for unused timings. Some old 783 * 0 is reserved. The spec says 0x01 fill for unused timings. Some old
718 * monitors fill with ascii space (0x20) instead. 784 * monitors fill with ascii space (0x20) instead.
@@ -734,8 +800,8 @@ bad_std_timing(u8 a, u8 b)
734 * and convert them into a real mode using CVT/GTF/DMT. 800 * and convert them into a real mode using CVT/GTF/DMT.
735 */ 801 */
736static struct drm_display_mode * 802static struct drm_display_mode *
737drm_mode_std(struct drm_connector *connector, struct std_timing *t, 803drm_mode_std(struct drm_connector *connector, struct edid *edid,
738 int revision, int timing_level) 804 struct std_timing *t, int revision)
739{ 805{
740 struct drm_device *dev = connector->dev; 806 struct drm_device *dev = connector->dev;
741 struct drm_display_mode *m, *mode = NULL; 807 struct drm_display_mode *m, *mode = NULL;
@@ -745,6 +811,7 @@ drm_mode_std(struct drm_connector *connector, struct std_timing *t,
745 >> EDID_TIMING_ASPECT_SHIFT; 811 >> EDID_TIMING_ASPECT_SHIFT;
746 unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK) 812 unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK)
747 >> EDID_TIMING_VFREQ_SHIFT; 813 >> EDID_TIMING_VFREQ_SHIFT;
814 int timing_level = standard_timing_level(edid);
748 815
749 if (bad_std_timing(t->hsize, t->vfreq_aspect)) 816 if (bad_std_timing(t->hsize, t->vfreq_aspect))
750 return NULL; 817 return NULL;
@@ -806,6 +873,23 @@ drm_mode_std(struct drm_connector *connector, struct std_timing *t,
806 case LEVEL_GTF: 873 case LEVEL_GTF:
807 mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); 874 mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
808 break; 875 break;
876 case LEVEL_GTF2:
877 /*
878 * This is potentially wrong if there's ever a monitor with
879 * more than one ranges section, each claiming a different
880 * secondary GTF curve. Please don't do that.
881 */
882 mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
883 if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) {
884 kfree(mode);
885 mode = drm_gtf_mode_complex(dev, hsize, vsize,
886 vrefresh_rate, 0, 0,
887 drm_gtf2_m(edid),
888 drm_gtf2_2c(edid),
889 drm_gtf2_k(edid),
890 drm_gtf2_2j(edid));
891 }
892 break;
809 case LEVEL_CVT: 893 case LEVEL_CVT:
810 mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0, 894 mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0,
811 false); 895 false);
@@ -1042,19 +1126,6 @@ static int add_established_modes(struct drm_connector *connector, struct edid *e
1042 1126
1043 return modes; 1127 return modes;
1044} 1128}
1045/**
1046 * stanard_timing_level - get std. timing level(CVT/GTF/DMT)
1047 * @edid: EDID block to scan
1048 */
1049static int standard_timing_level(struct edid *edid)
1050{
1051 if (edid->revision >= 2) {
1052 if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF))
1053 return LEVEL_CVT;
1054 return LEVEL_GTF;
1055 }
1056 return LEVEL_DMT;
1057}
1058 1129
1059/** 1130/**
1060 * add_standard_modes - get std. modes from EDID and add them 1131 * add_standard_modes - get std. modes from EDID and add them
@@ -1066,15 +1137,13 @@ static int standard_timing_level(struct edid *edid)
1066static int add_standard_modes(struct drm_connector *connector, struct edid *edid) 1137static int add_standard_modes(struct drm_connector *connector, struct edid *edid)
1067{ 1138{
1068 int i, modes = 0; 1139 int i, modes = 0;
1069 int timing_level;
1070
1071 timing_level = standard_timing_level(edid);
1072 1140
1073 for (i = 0; i < EDID_STD_TIMINGS; i++) { 1141 for (i = 0; i < EDID_STD_TIMINGS; i++) {
1074 struct drm_display_mode *newmode; 1142 struct drm_display_mode *newmode;
1075 1143
1076 newmode = drm_mode_std(connector, &edid->standard_timings[i], 1144 newmode = drm_mode_std(connector, edid,
1077 edid->revision, timing_level); 1145 &edid->standard_timings[i],
1146 edid->revision);
1078 if (newmode) { 1147 if (newmode) {
1079 drm_mode_probed_add(connector, newmode); 1148 drm_mode_probed_add(connector, newmode);
1080 modes++; 1149 modes++;
@@ -1140,9 +1209,6 @@ range_pixel_clock(struct edid *edid, u8 *t)
1140 return t[9] * 10000 + 5001; 1209 return t[9] * 10000 + 5001;
1141} 1210}
1142 1211
1143/*
1144 * XXX fix this for GTF secondary curve formula
1145 */
1146static bool 1212static bool
1147mode_in_range(struct drm_display_mode *mode, struct edid *edid, 1213mode_in_range(struct drm_display_mode *mode, struct edid *edid,
1148 struct detailed_timing *timing) 1214 struct detailed_timing *timing)
@@ -1339,7 +1405,6 @@ static int add_detailed_modes(struct drm_connector *connector,
1339{ 1405{
1340 int i, modes = 0; 1406 int i, modes = 0;
1341 struct detailed_non_pixel *data = &timing->data.other_data; 1407 struct detailed_non_pixel *data = &timing->data.other_data;
1342 int timing_level = standard_timing_level(edid);
1343 int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF); 1408 int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
1344 struct drm_display_mode *newmode; 1409 struct drm_display_mode *newmode;
1345 struct drm_device *dev = connector->dev; 1410 struct drm_device *dev = connector->dev;
@@ -1370,8 +1435,8 @@ static int add_detailed_modes(struct drm_connector *connector,
1370 struct drm_display_mode *newmode; 1435 struct drm_display_mode *newmode;
1371 1436
1372 std = &data->data.timings[i]; 1437 std = &data->data.timings[i];
1373 newmode = drm_mode_std(connector, std, edid->revision, 1438 newmode = drm_mode_std(connector, edid, std,
1374 timing_level); 1439 edid->revision);
1375 if (newmode) { 1440 if (newmode) {
1376 drm_mode_probed_add(connector, newmode); 1441 drm_mode_probed_add(connector, newmode);
1377 modes++; 1442 modes++;
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 76d63394c776..d460b6c472d4 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -276,35 +276,29 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
276EXPORT_SYMBOL(drm_cvt_mode); 276EXPORT_SYMBOL(drm_cvt_mode);
277 277
278/** 278/**
279 * drm_gtf_mode - create the modeline based on GTF algorithm 279 * drm_gtf_mode_complex - create the modeline based on full GTF algorithm
280 * 280 *
281 * @dev :drm device 281 * @dev :drm device
282 * @hdisplay :hdisplay size 282 * @hdisplay :hdisplay size
283 * @vdisplay :vdisplay size 283 * @vdisplay :vdisplay size
284 * @vrefresh :vrefresh rate. 284 * @vrefresh :vrefresh rate.
285 * @interlaced :whether the interlace is supported 285 * @interlaced :whether the interlace is supported
286 * @margins :whether the margin is supported 286 * @margins :desired margin size
287 * @GTF_[MCKJ] :extended GTF formula parameters
287 * 288 *
288 * LOCKING. 289 * LOCKING.
289 * none. 290 * none.
290 * 291 *
291 * return the modeline based on GTF algorithm 292 * return the modeline based on full GTF algorithm.
292 *
293 * This function is to create the modeline based on the GTF algorithm.
294 * Generalized Timing Formula is derived from:
295 * GTF Spreadsheet by Andy Morrish (1/5/97)
296 * available at http://www.vesa.org
297 * 293 *
298 * And it is copied from the file of xserver/hw/xfree86/modes/xf86gtf.c. 294 * GTF feature blocks specify C and J in multiples of 0.5, so we pass them
299 * What I have done is to translate it by using integer calculation. 295 * in here multiplied by two. For a C of 40, pass in 80.
300 * I also refer to the function of fb_get_mode in the file of
301 * drivers/video/fbmon.c
302 */ 296 */
303struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, int hdisplay, 297struct drm_display_mode *
304 int vdisplay, int vrefresh, 298drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay,
305 bool interlaced, int margins) 299 int vrefresh, bool interlaced, int margins,
306{ 300 int GTF_M, int GTF_2C, int GTF_K, int GTF_2J)
307 /* 1) top/bottom margin size (% of height) - default: 1.8, */ 301{ /* 1) top/bottom margin size (% of height) - default: 1.8, */
308#define GTF_MARGIN_PERCENTAGE 18 302#define GTF_MARGIN_PERCENTAGE 18
309 /* 2) character cell horizontal granularity (pixels) - default 8 */ 303 /* 2) character cell horizontal granularity (pixels) - default 8 */
310#define GTF_CELL_GRAN 8 304#define GTF_CELL_GRAN 8
@@ -316,17 +310,9 @@ struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, int hdisplay,
316#define H_SYNC_PERCENT 8 310#define H_SYNC_PERCENT 8
317 /* min time of vsync + back porch (microsec) */ 311 /* min time of vsync + back porch (microsec) */
318#define MIN_VSYNC_PLUS_BP 550 312#define MIN_VSYNC_PLUS_BP 550
319 /* blanking formula gradient */
320#define GTF_M 600
321 /* blanking formula offset */
322#define GTF_C 40
323 /* blanking formula scaling factor */
324#define GTF_K 128
325 /* blanking formula scaling factor */
326#define GTF_J 20
327 /* C' and M' are part of the Blanking Duty Cycle computation */ 313 /* C' and M' are part of the Blanking Duty Cycle computation */
328#define GTF_C_PRIME (((GTF_C - GTF_J) * GTF_K / 256) + GTF_J) 314#define GTF_C_PRIME ((((GTF_2C - GTF_2J) * GTF_K / 256) + GTF_2J) / 2)
329#define GTF_M_PRIME (GTF_K * GTF_M / 256) 315#define GTF_M_PRIME (GTF_K * GTF_M / 256)
330 struct drm_display_mode *drm_mode; 316 struct drm_display_mode *drm_mode;
331 unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd; 317 unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd;
332 int top_margin, bottom_margin; 318 int top_margin, bottom_margin;
@@ -470,7 +456,48 @@ struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, int hdisplay,
470 456
471 return drm_mode; 457 return drm_mode;
472} 458}
459EXPORT_SYMBOL(drm_gtf_mode_complex);
460
461/**
462 * drm_gtf_mode - create the modeline based on GTF algorithm
463 *
464 * @dev :drm device
465 * @hdisplay :hdisplay size
466 * @vdisplay :vdisplay size
467 * @vrefresh :vrefresh rate.
468 * @interlaced :whether the interlace is supported
469 * @margins :whether the margin is supported
470 *
471 * LOCKING.
472 * none.
473 *
474 * return the modeline based on GTF algorithm
475 *
476 * This function is to create the modeline based on the GTF algorithm.
477 * Generalized Timing Formula is derived from:
478 * GTF Spreadsheet by Andy Morrish (1/5/97)
479 * available at http://www.vesa.org
480 *
481 * And it is copied from the file of xserver/hw/xfree86/modes/xf86gtf.c.
482 * What I have done is to translate it by using integer calculation.
483 * I also refer to the function of fb_get_mode in the file of
484 * drivers/video/fbmon.c
485 *
486 * Standard GTF parameters:
487 * M = 600
488 * C = 40
489 * K = 128
490 * J = 20
491 */
492struct drm_display_mode *
493drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
494 bool lace, int margins)
495{
496 return drm_gtf_mode_complex(dev, hdisplay, vdisplay, vrefresh, lace,
497 margins, 600, 40 * 2, 128, 20 * 2);
498}
473EXPORT_SYMBOL(drm_gtf_mode); 499EXPORT_SYMBOL(drm_gtf_mode);
500
474/** 501/**
475 * drm_mode_set_name - set the name on a mode 502 * drm_mode_set_name - set the name on a mode
476 * @mode: name will be set in this mode 503 * @mode: name will be set in this mode
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index f74523a299c9..8eb3630ee67d 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -797,6 +797,10 @@ extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
797extern struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, 797extern struct drm_display_mode *drm_gtf_mode(struct drm_device *dev,
798 int hdisplay, int vdisplay, int vrefresh, 798 int hdisplay, int vdisplay, int vrefresh,
799 bool interlaced, int margins); 799 bool interlaced, int margins);
800extern struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev,
801 int hdisplay, int vdisplay, int vrefresh,
802 bool interlaced, int margins, int GTF_M,
803 int GTF_2C, int GTF_K, int GTF_2J);
800extern int drm_add_modes_noedid(struct drm_connector *connector, 804extern int drm_add_modes_noedid(struct drm_connector *connector,
801 int hdisplay, int vdisplay); 805 int hdisplay, int vdisplay);
802 806