diff options
Diffstat (limited to 'drivers/gpu/drm/drm_edid.c')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 115 |
1 files changed, 96 insertions, 19 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9e62bbedb5ad..95d6f4b6967c 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c | |||
@@ -968,6 +968,9 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) | |||
968 | u8 csum = 0; | 968 | u8 csum = 0; |
969 | struct edid *edid = (struct edid *)raw_edid; | 969 | struct edid *edid = (struct edid *)raw_edid; |
970 | 970 | ||
971 | if (WARN_ON(!raw_edid)) | ||
972 | return false; | ||
973 | |||
971 | if (edid_fixup > 8 || edid_fixup < 0) | 974 | if (edid_fixup > 8 || edid_fixup < 0) |
972 | edid_fixup = 6; | 975 | edid_fixup = 6; |
973 | 976 | ||
@@ -1010,15 +1013,15 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) | |||
1010 | break; | 1013 | break; |
1011 | } | 1014 | } |
1012 | 1015 | ||
1013 | return 1; | 1016 | return true; |
1014 | 1017 | ||
1015 | bad: | 1018 | bad: |
1016 | if (raw_edid && print_bad_edid) { | 1019 | if (print_bad_edid) { |
1017 | printk(KERN_ERR "Raw EDID:\n"); | 1020 | printk(KERN_ERR "Raw EDID:\n"); |
1018 | print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1, | 1021 | print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1, |
1019 | raw_edid, EDID_LENGTH, false); | 1022 | raw_edid, EDID_LENGTH, false); |
1020 | } | 1023 | } |
1021 | return 0; | 1024 | return false; |
1022 | } | 1025 | } |
1023 | EXPORT_SYMBOL(drm_edid_block_valid); | 1026 | EXPORT_SYMBOL(drm_edid_block_valid); |
1024 | 1027 | ||
@@ -1706,11 +1709,11 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, | |||
1706 | return NULL; | 1709 | return NULL; |
1707 | 1710 | ||
1708 | if (pt->misc & DRM_EDID_PT_STEREO) { | 1711 | if (pt->misc & DRM_EDID_PT_STEREO) { |
1709 | printk(KERN_WARNING "stereo mode not supported\n"); | 1712 | DRM_DEBUG_KMS("stereo mode not supported\n"); |
1710 | return NULL; | 1713 | return NULL; |
1711 | } | 1714 | } |
1712 | if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { | 1715 | if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { |
1713 | printk(KERN_WARNING "composite sync not supported\n"); | 1716 | DRM_DEBUG_KMS("composite sync not supported\n"); |
1714 | } | 1717 | } |
1715 | 1718 | ||
1716 | /* it is incorrect if hsync/vsync width is zero */ | 1719 | /* it is incorrect if hsync/vsync width is zero */ |
@@ -2321,6 +2324,31 @@ u8 *drm_find_cea_extension(struct edid *edid) | |||
2321 | } | 2324 | } |
2322 | EXPORT_SYMBOL(drm_find_cea_extension); | 2325 | EXPORT_SYMBOL(drm_find_cea_extension); |
2323 | 2326 | ||
2327 | /* | ||
2328 | * Calculate the alternate clock for the CEA mode | ||
2329 | * (60Hz vs. 59.94Hz etc.) | ||
2330 | */ | ||
2331 | static unsigned int | ||
2332 | cea_mode_alternate_clock(const struct drm_display_mode *cea_mode) | ||
2333 | { | ||
2334 | unsigned int clock = cea_mode->clock; | ||
2335 | |||
2336 | if (cea_mode->vrefresh % 6 != 0) | ||
2337 | return clock; | ||
2338 | |||
2339 | /* | ||
2340 | * edid_cea_modes contains the 59.94Hz | ||
2341 | * variant for 240 and 480 line modes, | ||
2342 | * and the 60Hz variant otherwise. | ||
2343 | */ | ||
2344 | if (cea_mode->vdisplay == 240 || cea_mode->vdisplay == 480) | ||
2345 | clock = clock * 1001 / 1000; | ||
2346 | else | ||
2347 | clock = DIV_ROUND_UP(clock * 1000, 1001); | ||
2348 | |||
2349 | return clock; | ||
2350 | } | ||
2351 | |||
2324 | /** | 2352 | /** |
2325 | * drm_match_cea_mode - look for a CEA mode matching given mode | 2353 | * drm_match_cea_mode - look for a CEA mode matching given mode |
2326 | * @to_match: display mode | 2354 | * @to_match: display mode |
@@ -2339,21 +2367,9 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) | |||
2339 | const struct drm_display_mode *cea_mode = &edid_cea_modes[mode]; | 2367 | const struct drm_display_mode *cea_mode = &edid_cea_modes[mode]; |
2340 | unsigned int clock1, clock2; | 2368 | unsigned int clock1, clock2; |
2341 | 2369 | ||
2342 | clock1 = clock2 = cea_mode->clock; | ||
2343 | |||
2344 | /* Check both 60Hz and 59.94Hz */ | 2370 | /* Check both 60Hz and 59.94Hz */ |
2345 | if (cea_mode->vrefresh % 6 == 0) { | 2371 | clock1 = cea_mode->clock; |
2346 | /* | 2372 | clock2 = cea_mode_alternate_clock(cea_mode); |
2347 | * edid_cea_modes contains the 59.94Hz | ||
2348 | * variant for 240 and 480 line modes, | ||
2349 | * and the 60Hz variant otherwise. | ||
2350 | */ | ||
2351 | if (cea_mode->vdisplay == 240 || | ||
2352 | cea_mode->vdisplay == 480) | ||
2353 | clock1 = clock1 * 1001 / 1000; | ||
2354 | else | ||
2355 | clock2 = DIV_ROUND_UP(clock2 * 1000, 1001); | ||
2356 | } | ||
2357 | 2373 | ||
2358 | if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || | 2374 | if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || |
2359 | KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && | 2375 | KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && |
@@ -2364,6 +2380,66 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) | |||
2364 | } | 2380 | } |
2365 | EXPORT_SYMBOL(drm_match_cea_mode); | 2381 | EXPORT_SYMBOL(drm_match_cea_mode); |
2366 | 2382 | ||
2383 | static int | ||
2384 | add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) | ||
2385 | { | ||
2386 | struct drm_device *dev = connector->dev; | ||
2387 | struct drm_display_mode *mode, *tmp; | ||
2388 | LIST_HEAD(list); | ||
2389 | int modes = 0; | ||
2390 | |||
2391 | /* Don't add CEA modes if the CEA extension block is missing */ | ||
2392 | if (!drm_find_cea_extension(edid)) | ||
2393 | return 0; | ||
2394 | |||
2395 | /* | ||
2396 | * Go through all probed modes and create a new mode | ||
2397 | * with the alternate clock for certain CEA modes. | ||
2398 | */ | ||
2399 | list_for_each_entry(mode, &connector->probed_modes, head) { | ||
2400 | const struct drm_display_mode *cea_mode; | ||
2401 | struct drm_display_mode *newmode; | ||
2402 | u8 cea_mode_idx = drm_match_cea_mode(mode) - 1; | ||
2403 | unsigned int clock1, clock2; | ||
2404 | |||
2405 | if (cea_mode_idx >= ARRAY_SIZE(edid_cea_modes)) | ||
2406 | continue; | ||
2407 | |||
2408 | cea_mode = &edid_cea_modes[cea_mode_idx]; | ||
2409 | |||
2410 | clock1 = cea_mode->clock; | ||
2411 | clock2 = cea_mode_alternate_clock(cea_mode); | ||
2412 | |||
2413 | if (clock1 == clock2) | ||
2414 | continue; | ||
2415 | |||
2416 | if (mode->clock != clock1 && mode->clock != clock2) | ||
2417 | continue; | ||
2418 | |||
2419 | newmode = drm_mode_duplicate(dev, cea_mode); | ||
2420 | if (!newmode) | ||
2421 | continue; | ||
2422 | |||
2423 | /* | ||
2424 | * The current mode could be either variant. Make | ||
2425 | * sure to pick the "other" clock for the new mode. | ||
2426 | */ | ||
2427 | if (mode->clock != clock1) | ||
2428 | newmode->clock = clock1; | ||
2429 | else | ||
2430 | newmode->clock = clock2; | ||
2431 | |||
2432 | list_add_tail(&newmode->head, &list); | ||
2433 | } | ||
2434 | |||
2435 | list_for_each_entry_safe(mode, tmp, &list, head) { | ||
2436 | list_del(&mode->head); | ||
2437 | drm_mode_probed_add(connector, mode); | ||
2438 | modes++; | ||
2439 | } | ||
2440 | |||
2441 | return modes; | ||
2442 | } | ||
2367 | 2443 | ||
2368 | static int | 2444 | static int |
2369 | do_cea_modes (struct drm_connector *connector, u8 *db, u8 len) | 2445 | do_cea_modes (struct drm_connector *connector, u8 *db, u8 len) |
@@ -2946,6 +3022,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) | |||
2946 | if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) | 3022 | if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) |
2947 | num_modes += add_inferred_modes(connector, edid); | 3023 | num_modes += add_inferred_modes(connector, edid); |
2948 | num_modes += add_cea_modes(connector, edid); | 3024 | num_modes += add_cea_modes(connector, edid); |
3025 | num_modes += add_alternate_cea_modes(connector, edid); | ||
2949 | 3026 | ||
2950 | if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) | 3027 | if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) |
2951 | edid_fixup_preferred(connector, quirks); | 3028 | edid_fixup_preferred(connector, quirks); |