|
@@ -33,6 +33,11 @@
|
|
|
#include <linux/i2c-algo-bit.h>
|
|
|
#include "drmP.h"
|
|
|
#include "drm_edid.h"
|
|
|
+#include "drm_edid_modes.h"
|
|
|
+
|
|
|
+#define version_greater(edid, maj, min) \
|
|
|
+ (((edid)->version > (maj)) || \
|
|
|
+ ((edid)->version == (maj) && (edid)->revision > (min)))
|
|
|
|
|
|
#define EDID_EST_TIMINGS 16
|
|
|
#define EDID_STD_TIMINGS 8
|
|
@@ -62,6 +67,13 @@
|
|
|
/* use +hsync +vsync for detailed mode */
|
|
|
#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6)
|
|
|
|
|
|
+struct detailed_mode_closure {
|
|
|
+ struct drm_connector *connector;
|
|
|
+ struct edid *edid;
|
|
|
+ bool preferred;
|
|
|
+ u32 quirks;
|
|
|
+ int modes;
|
|
|
+};
|
|
|
|
|
|
#define LEVEL_DMT 0
|
|
|
#define LEVEL_GTF 1
|
|
@@ -375,7 +387,6 @@ static u32 edid_get_quirks(struct edid *edid)
|
|
|
#define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay)
|
|
|
#define MODE_REFRESH_DIFF(m,r) (abs((m)->vrefresh - target_refresh))
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
* edid_fixup_preferred - set preferred modes based on quirk list
|
|
|
* @connector: has mode list to fix up
|
|
@@ -422,245 +433,6 @@ static void edid_fixup_preferred(struct drm_connector *connector,
|
|
|
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,
|
|
|
- 1168, 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, 202500, 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 const int drm_num_dmt_modes =
|
|
|
- sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
|
|
|
-
|
|
|
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
|
|
|
int hsize, int vsize, int fresh)
|
|
|
{
|
|
@@ -684,6 +456,46 @@ EXPORT_SYMBOL(drm_mode_find_dmt);
|
|
|
|
|
|
typedef void detailed_cb(struct detailed_timing *timing, void *closure);
|
|
|
|
|
|
+static void
|
|
|
+cea_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure)
|
|
|
+{
|
|
|
+ int i, n = 0;
|
|
|
+ u8 rev = ext[0x01], d = ext[0x02];
|
|
|
+ u8 *det_base = ext + d;
|
|
|
+
|
|
|
+ switch (rev) {
|
|
|
+ case 0:
|
|
|
+ /* can't happen */
|
|
|
+ return;
|
|
|
+ case 1:
|
|
|
+ /* have to infer how many blocks we have, check pixel clock */
|
|
|
+ for (i = 0; i < 6; i++)
|
|
|
+ if (det_base[18*i] || det_base[18*i+1])
|
|
|
+ n++;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ /* explicit count */
|
|
|
+ n = min(ext[0x03] & 0x0f, 6);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++)
|
|
|
+ cb((struct detailed_timing *)(det_base + 18 * i), closure);
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+vtb_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure)
|
|
|
+{
|
|
|
+ unsigned int i, n = min((int)ext[0x02], 6);
|
|
|
+ u8 *det_base = ext + 5;
|
|
|
+
|
|
|
+ if (ext[0x01] != 1)
|
|
|
+ return; /* unknown version */
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++)
|
|
|
+ cb((struct detailed_timing *)(det_base + 18 * i), closure);
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure)
|
|
|
{
|
|
@@ -696,7 +508,19 @@ drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure)
|
|
|
for (i = 0; i < EDID_DETAILED_TIMINGS; i++)
|
|
|
cb(&(edid->detailed_timings[i]), closure);
|
|
|
|
|
|
- /* XXX extension block walk */
|
|
|
+ for (i = 1; i <= raw_edid[0x7e]; i++) {
|
|
|
+ u8 *ext = raw_edid + (i * EDID_LENGTH);
|
|
|
+ switch (*ext) {
|
|
|
+ case CEA_EXT:
|
|
|
+ cea_for_each_detailed_block(ext, cb, closure);
|
|
|
+ break;
|
|
|
+ case VTB_EXT:
|
|
|
+ vtb_for_each_detailed_block(ext, cb, closure);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -1047,117 +871,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
|
|
|
return mode;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Detailed mode info for the EDID "established modes" data to use.
|
|
|
- */
|
|
|
-static struct drm_display_mode edid_est_modes[] = {
|
|
|
- { 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@60Hz */
|
|
|
- { 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@56Hz */
|
|
|
- { 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@75Hz */
|
|
|
- { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
|
|
|
- 704, 832, 0, 480, 489, 491, 520, 0,
|
|
|
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
|
|
|
- { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
|
|
|
- 768, 864, 0, 480, 483, 486, 525, 0,
|
|
|
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
|
|
|
- { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
|
|
|
- 752, 800, 0, 480, 490, 492, 525, 0,
|
|
|
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
|
|
|
- { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
|
|
|
- 846, 900, 0, 400, 421, 423, 449, 0,
|
|
|
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
|
|
|
- { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
|
|
|
- 846, 900, 0, 400, 412, 414, 449, 0,
|
|
|
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
|
|
|
- { 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@75Hz */
|
|
|
- { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
|
|
|
- 1136, 1312, 0, 768, 769, 772, 800, 0,
|
|
|
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
|
|
|
- { 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@70Hz */
|
|
|
- { 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@60Hz */
|
|
|
- { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
|
|
|
- 1208, 1264, 0, 768, 768, 776, 817, 0,
|
|
|
- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
|
|
|
- { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
|
|
|
- 928, 1152, 0, 624, 625, 628, 667, 0,
|
|
|
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@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@75Hz */
|
|
|
- { 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@72Hz */
|
|
|
- { 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) }, /* 1152x864@75Hz */
|
|
|
-};
|
|
|
-
|
|
|
-/**
|
|
|
- * add_established_modes - get est. modes from EDID and add them
|
|
|
- * @edid: EDID block to scan
|
|
|
- *
|
|
|
- * Each EDID block contains a bitmap of the supported "established modes" list
|
|
|
- * (defined above). Tease them out and add them to the global modes list.
|
|
|
- */
|
|
|
-static int add_established_modes(struct drm_connector *connector, struct edid *edid)
|
|
|
-{
|
|
|
- struct drm_device *dev = connector->dev;
|
|
|
- unsigned long est_bits = edid->established_timings.t1 |
|
|
|
- (edid->established_timings.t2 << 8) |
|
|
|
- ((edid->established_timings.mfg_rsvd & 0x80) << 9);
|
|
|
- int i, modes = 0;
|
|
|
-
|
|
|
- for (i = 0; i <= EDID_EST_TIMINGS; i++)
|
|
|
- if (est_bits & (1<<i)) {
|
|
|
- struct drm_display_mode *newmode;
|
|
|
- newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
|
|
|
- if (newmode) {
|
|
|
- drm_mode_probed_add(connector, newmode);
|
|
|
- modes++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return modes;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * add_standard_modes - get std. modes from EDID and add them
|
|
|
- * @edid: EDID block to scan
|
|
|
- *
|
|
|
- * Standard modes can be calculated using the CVT standard. Grab them from
|
|
|
- * @edid, calculate them, and add them to the list.
|
|
|
- */
|
|
|
-static int add_standard_modes(struct drm_connector *connector, struct edid *edid)
|
|
|
-{
|
|
|
- int i, modes = 0;
|
|
|
-
|
|
|
- for (i = 0; i < EDID_STD_TIMINGS; i++) {
|
|
|
- struct drm_display_mode *newmode;
|
|
|
-
|
|
|
- newmode = drm_mode_std(connector, edid,
|
|
|
- &edid->standard_timings[i],
|
|
|
- edid->revision);
|
|
|
- if (newmode) {
|
|
|
- drm_mode_probed_add(connector, newmode);
|
|
|
- modes++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return modes;
|
|
|
-}
|
|
|
-
|
|
|
static bool
|
|
|
mode_is_rb(struct drm_display_mode *mode)
|
|
|
{
|
|
@@ -1267,113 +980,33 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
|
|
|
return modes;
|
|
|
}
|
|
|
|
|
|
-static int drm_cvt_modes(struct drm_connector *connector,
|
|
|
- struct detailed_timing *timing)
|
|
|
+static void
|
|
|
+do_inferred_modes(struct detailed_timing *timing, void *c)
|
|
|
{
|
|
|
- int i, j, modes = 0;
|
|
|
- struct drm_display_mode *newmode;
|
|
|
- struct drm_device *dev = connector->dev;
|
|
|
- struct cvt_timing *cvt;
|
|
|
- const int rates[] = { 60, 85, 75, 60, 50 };
|
|
|
- const u8 empty[3] = { 0, 0, 0 };
|
|
|
-
|
|
|
- for (i = 0; i < 4; i++) {
|
|
|
- int uninitialized_var(width), height;
|
|
|
- cvt = &(timing->data.other_data.data.cvt[i]);
|
|
|
+ struct detailed_mode_closure *closure = c;
|
|
|
+ struct detailed_non_pixel *data = &timing->data.other_data;
|
|
|
+ int gtf = (closure->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
|
|
|
|
|
|
- if (!memcmp(cvt->code, empty, 3))
|
|
|
- continue;
|
|
|
+ if (gtf && data->type == EDID_DETAIL_MONITOR_RANGE)
|
|
|
+ closure->modes += drm_gtf_modes_for_range(closure->connector,
|
|
|
+ closure->edid,
|
|
|
+ timing);
|
|
|
+}
|
|
|
|
|
|
- height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2;
|
|
|
- switch (cvt->code[1] & 0x0c) {
|
|
|
- case 0x00:
|
|
|
- width = height * 4 / 3;
|
|
|
- break;
|
|
|
- case 0x04:
|
|
|
- width = height * 16 / 9;
|
|
|
- break;
|
|
|
- case 0x08:
|
|
|
- width = height * 16 / 10;
|
|
|
- break;
|
|
|
- case 0x0c:
|
|
|
- width = height * 15 / 9;
|
|
|
- break;
|
|
|
- }
|
|
|
+static int
|
|
|
+add_inferred_modes(struct drm_connector *connector, struct edid *edid)
|
|
|
+{
|
|
|
+ struct detailed_mode_closure closure = {
|
|
|
+ connector, edid, 0, 0, 0
|
|
|
+ };
|
|
|
|
|
|
- for (j = 1; j < 5; j++) {
|
|
|
- if (cvt->code[2] & (1 << j)) {
|
|
|
- newmode = drm_cvt_mode(dev, width, height,
|
|
|
- rates[j], j == 0,
|
|
|
- false, false);
|
|
|
- if (newmode) {
|
|
|
- drm_mode_probed_add(connector, newmode);
|
|
|
- modes++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ if (version_greater(edid, 1, 0))
|
|
|
+ drm_for_each_detailed_block((u8 *)edid, do_inferred_modes,
|
|
|
+ &closure);
|
|
|
|
|
|
- return modes;
|
|
|
+ return closure.modes;
|
|
|
}
|
|
|
|
|
|
-static const struct {
|
|
|
- short w;
|
|
|
- short h;
|
|
|
- short r;
|
|
|
- short rb;
|
|
|
-} est3_modes[] = {
|
|
|
- /* byte 6 */
|
|
|
- { 640, 350, 85, 0 },
|
|
|
- { 640, 400, 85, 0 },
|
|
|
- { 720, 400, 85, 0 },
|
|
|
- { 640, 480, 85, 0 },
|
|
|
- { 848, 480, 60, 0 },
|
|
|
- { 800, 600, 85, 0 },
|
|
|
- { 1024, 768, 85, 0 },
|
|
|
- { 1152, 864, 75, 0 },
|
|
|
- /* byte 7 */
|
|
|
- { 1280, 768, 60, 1 },
|
|
|
- { 1280, 768, 60, 0 },
|
|
|
- { 1280, 768, 75, 0 },
|
|
|
- { 1280, 768, 85, 0 },
|
|
|
- { 1280, 960, 60, 0 },
|
|
|
- { 1280, 960, 85, 0 },
|
|
|
- { 1280, 1024, 60, 0 },
|
|
|
- { 1280, 1024, 85, 0 },
|
|
|
- /* byte 8 */
|
|
|
- { 1360, 768, 60, 0 },
|
|
|
- { 1440, 900, 60, 1 },
|
|
|
- { 1440, 900, 60, 0 },
|
|
|
- { 1440, 900, 75, 0 },
|
|
|
- { 1440, 900, 85, 0 },
|
|
|
- { 1400, 1050, 60, 1 },
|
|
|
- { 1400, 1050, 60, 0 },
|
|
|
- { 1400, 1050, 75, 0 },
|
|
|
- /* byte 9 */
|
|
|
- { 1400, 1050, 85, 0 },
|
|
|
- { 1680, 1050, 60, 1 },
|
|
|
- { 1680, 1050, 60, 0 },
|
|
|
- { 1680, 1050, 75, 0 },
|
|
|
- { 1680, 1050, 85, 0 },
|
|
|
- { 1600, 1200, 60, 0 },
|
|
|
- { 1600, 1200, 65, 0 },
|
|
|
- { 1600, 1200, 70, 0 },
|
|
|
- /* byte 10 */
|
|
|
- { 1600, 1200, 75, 0 },
|
|
|
- { 1600, 1200, 85, 0 },
|
|
|
- { 1792, 1344, 60, 0 },
|
|
|
- { 1792, 1344, 85, 0 },
|
|
|
- { 1856, 1392, 60, 0 },
|
|
|
- { 1856, 1392, 75, 0 },
|
|
|
- { 1920, 1200, 60, 1 },
|
|
|
- { 1920, 1200, 60, 0 },
|
|
|
- /* byte 11 */
|
|
|
- { 1920, 1200, 75, 0 },
|
|
|
- { 1920, 1200, 85, 0 },
|
|
|
- { 1920, 1440, 60, 0 },
|
|
|
- { 1920, 1440, 75, 0 },
|
|
|
-};
|
|
|
-
|
|
|
static int
|
|
|
drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
|
|
|
{
|
|
@@ -1403,37 +1036,63 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
|
|
|
return modes;
|
|
|
}
|
|
|
|
|
|
-static int add_detailed_modes(struct drm_connector *connector,
|
|
|
- struct detailed_timing *timing,
|
|
|
- struct edid *edid, u32 quirks, int preferred)
|
|
|
+static void
|
|
|
+do_established_modes(struct detailed_timing *timing, void *c)
|
|
|
{
|
|
|
- int i, modes = 0;
|
|
|
+ struct detailed_mode_closure *closure = c;
|
|
|
struct detailed_non_pixel *data = &timing->data.other_data;
|
|
|
- int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
|
|
|
- struct drm_display_mode *newmode;
|
|
|
- struct drm_device *dev = connector->dev;
|
|
|
|
|
|
- if (timing->pixel_clock) {
|
|
|
- newmode = drm_mode_detailed(dev, edid, timing, quirks);
|
|
|
- if (!newmode)
|
|
|
- return 0;
|
|
|
+ if (data->type == EDID_DETAIL_EST_TIMINGS)
|
|
|
+ closure->modes += drm_est3_modes(closure->connector, timing);
|
|
|
+}
|
|
|
|
|
|
- if (preferred)
|
|
|
- newmode->type |= DRM_MODE_TYPE_PREFERRED;
|
|
|
+/**
|
|
|
+ * add_established_modes - get est. modes from EDID and add them
|
|
|
+ * @edid: EDID block to scan
|
|
|
+ *
|
|
|
+ * Each EDID block contains a bitmap of the supported "established modes" list
|
|
|
+ * (defined above). Tease them out and add them to the global modes list.
|
|
|
+ */
|
|
|
+static int
|
|
|
+add_established_modes(struct drm_connector *connector, struct edid *edid)
|
|
|
+{
|
|
|
+ struct drm_device *dev = connector->dev;
|
|
|
+ unsigned long est_bits = edid->established_timings.t1 |
|
|
|
+ (edid->established_timings.t2 << 8) |
|
|
|
+ ((edid->established_timings.mfg_rsvd & 0x80) << 9);
|
|
|
+ int i, modes = 0;
|
|
|
+ struct detailed_mode_closure closure = {
|
|
|
+ connector, edid, 0, 0, 0
|
|
|
+ };
|
|
|
|
|
|
- drm_mode_probed_add(connector, newmode);
|
|
|
- return 1;
|
|
|
+ for (i = 0; i <= EDID_EST_TIMINGS; i++) {
|
|
|
+ if (est_bits & (1<<i)) {
|
|
|
+ struct drm_display_mode *newmode;
|
|
|
+ newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
|
|
|
+ if (newmode) {
|
|
|
+ drm_mode_probed_add(connector, newmode);
|
|
|
+ modes++;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- /* other timing types */
|
|
|
- switch (data->type) {
|
|
|
- case EDID_DETAIL_MONITOR_RANGE:
|
|
|
- if (gtf)
|
|
|
- modes += drm_gtf_modes_for_range(connector, edid,
|
|
|
- timing);
|
|
|
- break;
|
|
|
- case EDID_DETAIL_STD_MODES:
|
|
|
- /* Six modes per detailed section */
|
|
|
+ if (version_greater(edid, 1, 0))
|
|
|
+ drm_for_each_detailed_block((u8 *)edid,
|
|
|
+ do_established_modes, &closure);
|
|
|
+
|
|
|
+ return modes + closure.modes;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+do_standard_modes(struct detailed_timing *timing, void *c)
|
|
|
+{
|
|
|
+ struct detailed_mode_closure *closure = c;
|
|
|
+ struct detailed_non_pixel *data = &timing->data.other_data;
|
|
|
+ struct drm_connector *connector = closure->connector;
|
|
|
+ struct edid *edid = closure->edid;
|
|
|
+
|
|
|
+ if (data->type == EDID_DETAIL_STD_MODES) {
|
|
|
+ int i;
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
struct std_timing *std;
|
|
|
struct drm_display_mode *newmode;
|
|
@@ -1443,108 +1102,169 @@ static int add_detailed_modes(struct drm_connector *connector,
|
|
|
edid->revision);
|
|
|
if (newmode) {
|
|
|
drm_mode_probed_add(connector, newmode);
|
|
|
- modes++;
|
|
|
+ closure->modes++;
|
|
|
}
|
|
|
}
|
|
|
- break;
|
|
|
- case EDID_DETAIL_CVT_3BYTE:
|
|
|
- modes += drm_cvt_modes(connector, timing);
|
|
|
- break;
|
|
|
- case EDID_DETAIL_EST_TIMINGS:
|
|
|
- modes += drm_est3_modes(connector, timing);
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
}
|
|
|
-
|
|
|
- return modes;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * add_detailed_info - get detailed mode info from EDID data
|
|
|
- * @connector: attached connector
|
|
|
+ * add_standard_modes - get std. modes from EDID and add them
|
|
|
* @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.
|
|
|
+ * Standard modes can be calculated using the appropriate standard (DMT,
|
|
|
+ * GTF or CVT. Grab them from @edid and add them to the list.
|
|
|
*/
|
|
|
-static int add_detailed_info(struct drm_connector *connector,
|
|
|
- struct edid *edid, u32 quirks)
|
|
|
+static int
|
|
|
+add_standard_modes(struct drm_connector *connector, struct edid *edid)
|
|
|
{
|
|
|
int i, modes = 0;
|
|
|
+ struct detailed_mode_closure closure = {
|
|
|
+ connector, edid, 0, 0, 0
|
|
|
+ };
|
|
|
+
|
|
|
+ for (i = 0; i < EDID_STD_TIMINGS; i++) {
|
|
|
+ struct drm_display_mode *newmode;
|
|
|
+
|
|
|
+ newmode = drm_mode_std(connector, edid,
|
|
|
+ &edid->standard_timings[i],
|
|
|
+ edid->revision);
|
|
|
+ if (newmode) {
|
|
|
+ drm_mode_probed_add(connector, newmode);
|
|
|
+ modes++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (version_greater(edid, 1, 0))
|
|
|
+ drm_for_each_detailed_block((u8 *)edid, do_standard_modes,
|
|
|
+ &closure);
|
|
|
+
|
|
|
+ /* XXX should also look for standard codes in VTB blocks */
|
|
|
+
|
|
|
+ return modes + closure.modes;
|
|
|
+}
|
|
|
|
|
|
- for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
|
|
|
- struct detailed_timing *timing = &edid->detailed_timings[i];
|
|
|
- int preferred = (i == 0);
|
|
|
+static int drm_cvt_modes(struct drm_connector *connector,
|
|
|
+ struct detailed_timing *timing)
|
|
|
+{
|
|
|
+ int i, j, modes = 0;
|
|
|
+ struct drm_display_mode *newmode;
|
|
|
+ struct drm_device *dev = connector->dev;
|
|
|
+ struct cvt_timing *cvt;
|
|
|
+ const int rates[] = { 60, 85, 75, 60, 50 };
|
|
|
+ const u8 empty[3] = { 0, 0, 0 };
|
|
|
|
|
|
- if (preferred && edid->version == 1 && edid->revision < 4)
|
|
|
- preferred = (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
|
|
|
+ for (i = 0; i < 4; i++) {
|
|
|
+ int uninitialized_var(width), height;
|
|
|
+ cvt = &(timing->data.other_data.data.cvt[i]);
|
|
|
|
|
|
- /* In 1.0, only timings are allowed */
|
|
|
- if (!timing->pixel_clock && edid->version == 1 &&
|
|
|
- edid->revision == 0)
|
|
|
+ if (!memcmp(cvt->code, empty, 3))
|
|
|
continue;
|
|
|
|
|
|
- modes += add_detailed_modes(connector, timing, edid, quirks,
|
|
|
- preferred);
|
|
|
+ height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 4) + 1) * 2;
|
|
|
+ switch (cvt->code[1] & 0x0c) {
|
|
|
+ case 0x00:
|
|
|
+ width = height * 4 / 3;
|
|
|
+ break;
|
|
|
+ case 0x04:
|
|
|
+ width = height * 16 / 9;
|
|
|
+ break;
|
|
|
+ case 0x08:
|
|
|
+ width = height * 16 / 10;
|
|
|
+ break;
|
|
|
+ case 0x0c:
|
|
|
+ width = height * 15 / 9;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (j = 1; j < 5; j++) {
|
|
|
+ if (cvt->code[2] & (1 << j)) {
|
|
|
+ newmode = drm_cvt_mode(dev, width, height,
|
|
|
+ rates[j], j == 0,
|
|
|
+ false, false);
|
|
|
+ if (newmode) {
|
|
|
+ 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)
|
|
|
+static void
|
|
|
+do_cvt_mode(struct detailed_timing *timing, void *c)
|
|
|
{
|
|
|
- int i, modes = 0;
|
|
|
- char *edid_ext = NULL;
|
|
|
- struct detailed_timing *timing;
|
|
|
- int start_offset, end_offset;
|
|
|
+ struct detailed_mode_closure *closure = c;
|
|
|
+ struct detailed_non_pixel *data = &timing->data.other_data;
|
|
|
|
|
|
- if (edid->version == 1 && edid->revision < 3)
|
|
|
- return 0;
|
|
|
- if (!edid->extensions)
|
|
|
- return 0;
|
|
|
+ if (data->type == EDID_DETAIL_CVT_3BYTE)
|
|
|
+ closure->modes += drm_cvt_modes(closure->connector, timing);
|
|
|
+}
|
|
|
|
|
|
- /* Find CEA extension */
|
|
|
- for (i = 0; i < edid->extensions; i++) {
|
|
|
- edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
|
|
|
- if (edid_ext[0] == 0x02)
|
|
|
- break;
|
|
|
- }
|
|
|
+static int
|
|
|
+add_cvt_modes(struct drm_connector *connector, struct edid *edid)
|
|
|
+{
|
|
|
+ struct detailed_mode_closure closure = {
|
|
|
+ connector, edid, 0, 0, 0
|
|
|
+ };
|
|
|
|
|
|
- if (i == edid->extensions)
|
|
|
- return 0;
|
|
|
+ if (version_greater(edid, 1, 2))
|
|
|
+ drm_for_each_detailed_block((u8 *)edid, do_cvt_mode, &closure);
|
|
|
|
|
|
- /* 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;
|
|
|
- }
|
|
|
+ /* XXX should also look for CVT codes in VTB blocks */
|
|
|
|
|
|
- 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);
|
|
|
- modes += add_detailed_modes(connector, timing, edid, quirks, 0);
|
|
|
+ return closure.modes;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+do_detailed_mode(struct detailed_timing *timing, void *c)
|
|
|
+{
|
|
|
+ struct detailed_mode_closure *closure = c;
|
|
|
+ struct drm_display_mode *newmode;
|
|
|
+
|
|
|
+ if (timing->pixel_clock) {
|
|
|
+ newmode = drm_mode_detailed(closure->connector->dev,
|
|
|
+ closure->edid, timing,
|
|
|
+ closure->quirks);
|
|
|
+ if (!newmode)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (closure->preferred)
|
|
|
+ newmode->type |= DRM_MODE_TYPE_PREFERRED;
|
|
|
+
|
|
|
+ drm_mode_probed_add(closure->connector, newmode);
|
|
|
+ closure->modes++;
|
|
|
+ closure->preferred = 0;
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- return modes;
|
|
|
+/*
|
|
|
+ * add_detailed_modes - Add modes from detailed timings
|
|
|
+ * @connector: attached connector
|
|
|
+ * @edid: EDID block to scan
|
|
|
+ * @quirks: quirks to apply
|
|
|
+ */
|
|
|
+static int
|
|
|
+add_detailed_modes(struct drm_connector *connector, struct edid *edid,
|
|
|
+ u32 quirks)
|
|
|
+{
|
|
|
+ struct detailed_mode_closure closure = {
|
|
|
+ connector,
|
|
|
+ edid,
|
|
|
+ 1,
|
|
|
+ quirks,
|
|
|
+ 0
|
|
|
+ };
|
|
|
+
|
|
|
+ if (closure.preferred && !version_greater(edid, 1, 3))
|
|
|
+ closure.preferred =
|
|
|
+ (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
|
|
|
+
|
|
|
+ drm_for_each_detailed_block((u8 *)edid, do_detailed_mode, &closure);
|
|
|
+
|
|
|
+ return closure.modes;
|
|
|
}
|
|
|
|
|
|
#define HDMI_IDENTIFIER 0x000C03
|
|
@@ -1640,35 +1360,21 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
|
|
|
* - established timing codes
|
|
|
* - modes inferred from GTF or CVT range information
|
|
|
*
|
|
|
- * We don't quite implement this yet, but we're close.
|
|
|
+ * We get this pretty much right.
|
|
|
*
|
|
|
* XXX order for additional mode types in extension blocks?
|
|
|
*/
|
|
|
- num_modes += add_detailed_info(connector, edid, quirks);
|
|
|
- num_modes += add_detailed_info_eedid(connector, edid, quirks);
|
|
|
+ num_modes += add_detailed_modes(connector, edid, quirks);
|
|
|
+ num_modes += add_cvt_modes(connector, edid);
|
|
|
num_modes += add_standard_modes(connector, edid);
|
|
|
num_modes += add_established_modes(connector, edid);
|
|
|
+ num_modes += add_inferred_modes(connector, edid);
|
|
|
|
|
|
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
|
|
|
edid_fixup_preferred(connector, quirks);
|
|
|
|
|
|
- connector->display_info.serration_vsync = (edid->input & DRM_EDID_INPUT_SERRATION_VSYNC) ? 1 : 0;
|
|
|
- connector->display_info.sync_on_green = (edid->input & DRM_EDID_INPUT_SYNC_ON_GREEN) ? 1 : 0;
|
|
|
- connector->display_info.composite_sync = (edid->input & DRM_EDID_INPUT_COMPOSITE_SYNC) ? 1 : 0;
|
|
|
- connector->display_info.separate_syncs = (edid->input & DRM_EDID_INPUT_SEPARATE_SYNCS) ? 1 : 0;
|
|
|
- connector->display_info.blank_to_black = (edid->input & DRM_EDID_INPUT_BLANK_TO_BLACK) ? 1 : 0;
|
|
|
- connector->display_info.video_level = (edid->input & DRM_EDID_INPUT_VIDEO_LEVEL) >> 5;
|
|
|
- connector->display_info.digital = (edid->input & DRM_EDID_INPUT_DIGITAL) ? 1 : 0;
|
|
|
connector->display_info.width_mm = edid->width_cm * 10;
|
|
|
connector->display_info.height_mm = edid->height_cm * 10;
|
|
|
- connector->display_info.gamma = edid->gamma;
|
|
|
- connector->display_info.gtf_supported = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) ? 1 : 0;
|
|
|
- connector->display_info.standard_color = (edid->features & DRM_EDID_FEATURE_STANDARD_COLOR) ? 1 : 0;
|
|
|
- connector->display_info.display_type = (edid->features & DRM_EDID_FEATURE_DISPLAY_TYPE) >> 3;
|
|
|
- connector->display_info.active_off_supported = (edid->features & DRM_EDID_FEATURE_PM_ACTIVE_OFF) ? 1 : 0;
|
|
|
- connector->display_info.suspend_supported = (edid->features & DRM_EDID_FEATURE_PM_SUSPEND) ? 1 : 0;
|
|
|
- connector->display_info.standby_supported = (edid->features & DRM_EDID_FEATURE_PM_STANDBY) ? 1 : 0;
|
|
|
- connector->display_info.gamma = edid->gamma;
|
|
|
|
|
|
return num_modes;
|
|
|
}
|