diff options
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 119 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_modes.c | 81 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 4 |
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 | ||
69 | static struct edid_quirk { | 70 | static 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 | ||
717 | static void | ||
718 | find_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 */ | ||
726 | static int | ||
727 | drm_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 | |||
734 | static int | ||
735 | drm_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 | |||
742 | static int | ||
743 | drm_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 | |||
750 | static int | ||
751 | drm_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 | |||
758 | static int | ||
759 | drm_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 | */ | ||
770 | static 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 | */ |
736 | static struct drm_display_mode * | 802 | static struct drm_display_mode * |
737 | drm_mode_std(struct drm_connector *connector, struct std_timing *t, | 803 | drm_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 | */ | ||
1049 | static 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) | |||
1066 | static int add_standard_modes(struct drm_connector *connector, struct edid *edid) | 1137 | static 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 | */ | ||
1146 | static bool | 1212 | static bool |
1147 | mode_in_range(struct drm_display_mode *mode, struct edid *edid, | 1213 | mode_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, | |||
276 | EXPORT_SYMBOL(drm_cvt_mode); | 276 | EXPORT_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 | */ |
303 | struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, int hdisplay, | 297 | struct drm_display_mode * |
304 | int vdisplay, int vrefresh, | 298 | drm_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 | } |
459 | EXPORT_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 | */ | ||
492 | struct drm_display_mode * | ||
493 | drm_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 | } | ||
473 | EXPORT_SYMBOL(drm_gtf_mode); | 499 | EXPORT_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, | |||
797 | extern struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, | 797 | extern 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); |
800 | extern 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); | ||
800 | extern int drm_add_modes_noedid(struct drm_connector *connector, | 804 | extern int drm_add_modes_noedid(struct drm_connector *connector, |
801 | int hdisplay, int vdisplay); | 805 | int hdisplay, int vdisplay); |
802 | 806 | ||