30,15 → 30,11 |
#include <types.h> |
#include <list.h> |
|
#include <linux/idr.h> |
#include <linux/i2c.h> |
#include <linux/i2c-algo-bit.h> |
#include "drmP.h" |
#include "drm_edid.h" |
|
|
|
|
/* |
* TODO: |
* - support EDID 1.4 (incl. CE blocks) |
67,7 → 63,13 |
#define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5) |
/* use +hsync +vsync for detailed mode */ |
#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) |
/* define the number of Extension EDID block */ |
#define MAX_EDID_EXT_NUM 4 |
|
#define LEVEL_DMT 0 |
#define LEVEL_GTF 1 |
#define LEVEL_CVT 2 |
|
static struct edid_quirk { |
char *vendor; |
int product_id; |
244,6 → 246,263 |
preferred_mode->type |= DRM_MODE_TYPE_PREFERRED; |
} |
|
/* |
* Add the Autogenerated from the DMT spec. |
* This table is copied from xfree86/modes/xf86EdidModes.c. |
* But the mode with Reduced blank feature is deleted. |
*/ |
static struct drm_display_mode drm_dmt_modes[] = { |
/* 640x350@85Hz */ |
{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672, |
736, 832, 0, 350, 382, 385, 445, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
/* 640x400@85Hz */ |
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672, |
736, 832, 0, 400, 401, 404, 445, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 720x400@85Hz */ |
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756, |
828, 936, 0, 400, 401, 404, 446, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 640x480@60Hz */ |
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, |
752, 800, 0, 480, 489, 492, 525, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
/* 640x480@72Hz */ |
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664, |
704, 832, 0, 480, 489, 492, 520, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
/* 640x480@75Hz */ |
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656, |
720, 840, 0, 480, 481, 484, 500, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
/* 640x480@85Hz */ |
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696, |
752, 832, 0, 480, 481, 484, 509, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
/* 800x600@56Hz */ |
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824, |
896, 1024, 0, 600, 601, 603, 625, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 800x600@60Hz */ |
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, |
968, 1056, 0, 600, 601, 605, 628, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 800x600@72Hz */ |
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856, |
976, 1040, 0, 600, 637, 643, 666, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 800x600@75Hz */ |
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816, |
896, 1056, 0, 600, 601, 604, 625, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 800x600@85Hz */ |
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832, |
896, 1048, 0, 600, 601, 604, 631, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 848x480@60Hz */ |
{ DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864, |
976, 1088, 0, 480, 486, 494, 517, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1024x768@43Hz, interlace */ |
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032, |
1208, 1264, 0, 768, 768, 772, 817, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | |
DRM_MODE_FLAG_INTERLACE) }, |
/* 1024x768@60Hz */ |
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, |
1184, 1344, 0, 768, 771, 777, 806, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
/* 1024x768@70Hz */ |
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048, |
1184, 1328, 0, 768, 771, 777, 806, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
/* 1024x768@75Hz */ |
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040, |
1136, 1312, 0, 768, 769, 772, 800, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1024x768@85Hz */ |
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072, |
1072, 1376, 0, 768, 769, 772, 808, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1152x864@75Hz */ |
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216, |
1344, 1600, 0, 864, 865, 868, 900, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1280x768@60Hz */ |
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344, |
1472, 1664, 0, 768, 771, 778, 798, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1280x768@75Hz */ |
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360, |
1488, 1696, 0, 768, 771, 778, 805, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
/* 1280x768@85Hz */ |
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360, |
1496, 1712, 0, 768, 771, 778, 809, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1280x800@60Hz */ |
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352, |
1480, 1680, 0, 800, 803, 809, 831, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) }, |
/* 1280x800@75Hz */ |
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360, |
1488, 1696, 0, 800, 803, 809, 838, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1280x800@85Hz */ |
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360, |
1496, 1712, 0, 800, 803, 809, 843, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1280x960@60Hz */ |
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376, |
1488, 1800, 0, 960, 961, 964, 1000, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1280x960@85Hz */ |
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344, |
1504, 1728, 0, 960, 961, 964, 1011, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1280x1024@60Hz */ |
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328, |
1440, 1688, 0, 1024, 1025, 1028, 1066, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1280x1024@75Hz */ |
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296, |
1440, 1688, 0, 1024, 1025, 1028, 1066, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1280x1024@85Hz */ |
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344, |
1504, 1728, 0, 1024, 1025, 1028, 1072, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1360x768@60Hz */ |
{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424, |
1536, 1792, 0, 768, 771, 777, 795, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1440x1050@60Hz */ |
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488, |
1632, 1864, 0, 1050, 1053, 1057, 1089, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1440x1050@75Hz */ |
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504, |
1648, 1896, 0, 1050, 1053, 1057, 1099, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1440x1050@85Hz */ |
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504, |
1656, 1912, 0, 1050, 1053, 1057, 1105, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1440x900@60Hz */ |
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520, |
1672, 1904, 0, 900, 903, 909, 934, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1440x900@75Hz */ |
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536, |
1688, 1936, 0, 900, 903, 909, 942, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1440x900@85Hz */ |
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544, |
1696, 1952, 0, 900, 903, 909, 948, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1600x1200@60Hz */ |
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664, |
1856, 2160, 0, 1200, 1201, 1204, 1250, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1600x1200@65Hz */ |
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664, |
1856, 2160, 0, 1200, 1201, 1204, 1250, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1600x1200@70Hz */ |
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664, |
1856, 2160, 0, 1200, 1201, 1204, 1250, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1600x1200@75Hz */ |
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 2025000, 1600, 1664, |
1856, 2160, 0, 1200, 1201, 1204, 1250, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1600x1200@85Hz */ |
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664, |
1856, 2160, 0, 1200, 1201, 1204, 1250, 0, |
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1680x1050@60Hz */ |
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784, |
1960, 2240, 0, 1050, 1053, 1059, 1089, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1680x1050@75Hz */ |
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800, |
1976, 2272, 0, 1050, 1053, 1059, 1099, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1680x1050@85Hz */ |
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808, |
1984, 2288, 0, 1050, 1053, 1059, 1105, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1792x1344@60Hz */ |
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920, |
2120, 2448, 0, 1344, 1345, 1348, 1394, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1729x1344@75Hz */ |
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888, |
2104, 2456, 0, 1344, 1345, 1348, 1417, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1853x1392@60Hz */ |
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952, |
2176, 2528, 0, 1392, 1393, 1396, 1439, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1856x1392@75Hz */ |
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984, |
2208, 2560, 0, 1392, 1395, 1399, 1500, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1920x1200@60Hz */ |
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056, |
2256, 2592, 0, 1200, 1203, 1209, 1245, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1920x1200@75Hz */ |
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056, |
2264, 2608, 0, 1200, 1203, 1209, 1255, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1920x1200@85Hz */ |
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064, |
2272, 2624, 0, 1200, 1203, 1209, 1262, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1920x1440@60Hz */ |
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048, |
2256, 2600, 0, 1440, 1441, 1444, 1500, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 1920x1440@75Hz */ |
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064, |
2288, 2640, 0, 1440, 1441, 1444, 1500, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 2560x1600@60Hz */ |
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752, |
3032, 3504, 0, 1600, 1603, 1609, 1658, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 2560x1600@75HZ */ |
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768, |
3048, 3536, 0, 1600, 1603, 1609, 1672, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
/* 2560x1600@85HZ */ |
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768, |
3048, 3536, 0, 1600, 1603, 1609, 1682, 0, |
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, |
}; |
|
static struct drm_display_mode *drm_find_dmt(struct drm_device *dev, |
int hsize, int vsize, int fresh) |
{ |
int i, count; |
struct drm_display_mode *ptr, *mode; |
|
count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); |
mode = NULL; |
for (i = 0; i < count; i++) { |
ptr = &drm_dmt_modes[i]; |
if (hsize == ptr->hdisplay && |
vsize == ptr->vdisplay && |
fresh == drm_mode_vrefresh(ptr)) { |
/* get the expected default mode */ |
mode = drm_mode_duplicate(dev, ptr); |
break; |
} |
} |
return mode; |
} |
/** |
* drm_mode_std - convert standard mode info (width, height, refresh) into mode |
* @t: standard timing params |
255,16 → 514,22 |
* generation code. |
*/ |
struct drm_display_mode *drm_mode_std(struct drm_device *dev, |
struct std_timing *t) |
struct std_timing *t, |
int timing_level) |
{ |
struct drm_display_mode *mode; |
int hsize = t->hsize * 8 + 248, vsize; |
int hsize, vsize; |
int vrefresh_rate; |
unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK) |
>> EDID_TIMING_ASPECT_SHIFT; |
unsigned vfreq = (t->vfreq_aspect & EDID_TIMING_VFREQ_MASK) |
>> EDID_TIMING_VFREQ_SHIFT; |
|
mode = drm_mode_create(dev); |
if (!mode) |
return NULL; |
/* According to the EDID spec, the hdisplay = hsize * 8 + 248 */ |
hsize = t->hsize * 8 + 248; |
/* vrefresh_rate = vfreq + 60 */ |
vrefresh_rate = vfreq + 60; |
/* the vdisplay is calculated based on the aspect ratio */ |
|
if (aspect_ratio == 0) |
vsize = (hsize * 10) / 16; |
274,9 → 539,30 |
vsize = (hsize * 4) / 5; |
else |
vsize = (hsize * 9) / 16; |
/* HDTV hack */ |
if (hsize == 1360 && vsize == 765 && vrefresh_rate == 60) { |
mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); |
mode->hdisplay = 1366; |
mode->vsync_start = mode->vsync_start - 1; |
mode->vsync_end = mode->vsync_end - 1; |
return mode; |
} |
mode = NULL; |
/* check whether it can be found in default mode table */ |
mode = drm_find_dmt(dev, hsize, vsize, vrefresh_rate); |
if (mode) |
return mode; |
|
drm_mode_set_name(mode); |
|
switch (timing_level) { |
case LEVEL_DMT: |
break; |
case LEVEL_GTF: |
mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); |
break; |
case LEVEL_CVT: |
mode = drm_cvt_mode(dev, hsize, vsize, vrefresh_rate, 0, 0); |
break; |
} |
return mode; |
} |
|
458,6 → 744,19 |
|
return modes; |
} |
/** |
* stanard_timing_level - get std. timing level(CVT/GTF/DMT) |
* @edid: EDID block to scan |
*/ |
static int standard_timing_level(struct edid *edid) |
{ |
if (edid->revision >= 2) { |
if (edid->revision >= 4 && (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)) |
return LEVEL_CVT; |
return LEVEL_GTF; |
} |
return LEVEL_DMT; |
} |
|
/** |
* add_standard_modes - get std. modes from EDID and add them |
470,7 → 769,10 |
{ |
struct drm_device *dev = connector->dev; |
int i, modes = 0; |
int timing_level; |
|
timing_level = standard_timing_level(edid); |
|
for (i = 0; i < EDID_STD_TIMINGS; i++) { |
struct std_timing *t = &edid->standard_timings[i]; |
struct drm_display_mode *newmode; |
479,7 → 781,8 |
if (t->hsize == 1 && t->vfreq_aspect == 1) |
continue; |
|
newmode = drm_mode_std(dev, &edid->standard_timings[i]); |
newmode = drm_mode_std(dev, &edid->standard_timings[i], |
timing_level); |
if (newmode) { |
drm_mode_probed_add(connector, newmode); |
modes++; |
503,18 → 806,50 |
{ |
struct drm_device *dev = connector->dev; |
int i, j, modes = 0; |
int timing_level; |
|
timing_level = standard_timing_level(edid); |
|
for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { |
struct detailed_timing *timing = &edid->detailed_timings[i]; |
struct detailed_non_pixel *data = &timing->data.other_data; |
struct drm_display_mode *newmode; |
|
/* EDID up to and including 1.2 may put monitor info here */ |
if (edid->version == 1 && edid->revision < 3) |
continue; |
/* X server check is version 1.1 or higher */ |
if (edid->version == 1 && edid->revision >= 1 && |
!timing->pixel_clock) { |
/* 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; |
|
/* Detailed mode timing */ |
if (timing->pixel_clock) { |
std = &data->data.timings[j]; |
newmode = drm_mode_std(dev, std, |
timing_level); |
if (newmode) { |
drm_mode_probed_add(connector, newmode); |
modes++; |
} |
} |
break; |
default: |
break; |
} |
} else { |
newmode = drm_mode_detailed(dev, edid, timing, quirks); |
if (!newmode) |
continue; |
525,7 → 860,91 |
drm_mode_probed_add(connector, newmode); |
|
modes++; |
} |
} |
|
return modes; |
} |
/** |
* add_detailed_mode_eedid - get detailed mode info from addtional timing |
* EDID block |
* @connector: attached connector |
* @edid: EDID block to scan(It is only to get addtional timing EDID block) |
* @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_eedid(struct drm_connector *connector, |
struct edid *edid, u32 quirks) |
{ |
struct drm_device *dev = connector->dev; |
int i, j, modes = 0; |
char *edid_ext = NULL; |
struct detailed_timing *timing; |
struct detailed_non_pixel *data; |
struct drm_display_mode *newmode; |
int edid_ext_num; |
int start_offset, end_offset; |
int timing_level; |
|
if (edid->version == 1 && edid->revision < 3) { |
/* If the EDID version is less than 1.3, there is no |
* extension EDID. |
*/ |
return 0; |
} |
if (!edid->extensions) { |
/* if there is no extension EDID, it is unnecessary to |
* parse the E-EDID to get detailed info |
*/ |
return 0; |
} |
|
/* Chose real EDID extension number */ |
edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ? |
MAX_EDID_EXT_NUM : edid->extensions; |
|
/* Find CEA extension */ |
for (i = 0; i < edid_ext_num; i++) { |
edid_ext = (char *)edid + EDID_LENGTH * (i + 1); |
/* This block is CEA extension */ |
if (edid_ext[0] == 0x02) |
break; |
} |
|
if (i == edid_ext_num) { |
/* if there is no additional timing EDID block, return */ |
return 0; |
} |
|
/* Get the start offset of detailed timing block */ |
start_offset = edid_ext[2]; |
if (start_offset == 0) { |
/* If the start_offset is zero, it means that neither detailed |
* info nor data block exist. In such case it is also |
* unnecessary to parse the detailed timing info. |
*/ |
return 0; |
} |
|
timing_level = standard_timing_level(edid); |
end_offset = EDID_LENGTH; |
end_offset -= sizeof(struct detailed_timing); |
for (i = start_offset; i < end_offset; |
i += sizeof(struct detailed_timing)) { |
timing = (struct detailed_timing *)(edid_ext + i); |
data = &timing->data.other_data; |
/* 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 */ |
548,7 → 967,7 |
struct drm_display_mode *newmode; |
|
std = &data->data.timings[j]; |
newmode = drm_mode_std(dev, std); |
newmode = drm_mode_std(dev, std, timing_level); |
if (newmode) { |
drm_mode_probed_add(connector, newmode); |
modes++; |
608,8 → 1027,6 |
|
ret = drm_do_probe_ddc_edid(adapter, buf, len); |
if (ret != 0) { |
// dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n", |
// drm_get_connector_name(connector)); |
goto end; |
} |
if (!edid_is_valid((struct edid *)buf)) { |
621,7 → 1038,6 |
return ret; |
} |
|
#define MAX_EDID_EXT_NUM 4 |
/** |
* drm_get_edid - get EDID data, if available |
* @connector: connector we're probing |
774,6 → 1190,7 |
num_modes += add_established_modes(connector, edid); |
num_modes += add_standard_modes(connector, edid); |
num_modes += add_detailed_info(connector, edid, quirks); |
num_modes += add_detailed_info_eedid(connector, edid, quirks); |
|
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) |
edid_fixup_preferred(connector, quirks); |
799,3 → 1216,49 |
return num_modes; |
} |
EXPORT_SYMBOL(drm_add_edid_modes); |
|
/** |
* drm_add_modes_noedid - add modes for the connectors without EDID |
* @connector: connector we're probing |
* @hdisplay: the horizontal display limit |
* @vdisplay: the vertical display limit |
* |
* Add the specified modes to the connector's mode list. Only when the |
* hdisplay/vdisplay is not beyond the given limit, it will be added. |
* |
* Return number of modes added or 0 if we couldn't find any. |
*/ |
int drm_add_modes_noedid(struct drm_connector *connector, |
int hdisplay, int vdisplay) |
{ |
int i, count, num_modes = 0; |
struct drm_display_mode *mode, *ptr; |
struct drm_device *dev = connector->dev; |
|
count = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); |
if (hdisplay < 0) |
hdisplay = 0; |
if (vdisplay < 0) |
vdisplay = 0; |
|
for (i = 0; i < count; i++) { |
ptr = &drm_dmt_modes[i]; |
if (hdisplay && vdisplay) { |
/* |
* Only when two are valid, they will be used to check |
* whether the mode should be added to the mode list of |
* the connector. |
*/ |
if (ptr->hdisplay > hdisplay || |
ptr->vdisplay > vdisplay) |
continue; |
} |
mode = drm_mode_duplicate(dev, ptr); |
if (mode) { |
drm_mode_probed_add(connector, mode); |
num_modes++; |
} |
} |
return num_modes; |
} |
EXPORT_SYMBOL(drm_add_modes_noedid); |