diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-09 16:04:31 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-09 16:04:31 -0700 |
commit | 2e17c5a97e231f3cb426f4b7895eab5be5c5442e (patch) | |
tree | 80871817427250200d6931a45ccb4833c4add74a /drivers/gpu/drm/drm_edid.c | |
parent | 5f097cd249f00683442c3e265d6f27d80fc83563 (diff) | |
parent | 774d8e34e46506222bb5e2888e3ef42b2775715f (diff) |
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"Okay this is the big one, I was stalled on the fbdev pull req as I
stupidly let fbdev guys merge a patch I required to fix a warning with
some patches I had, they ended up merging the patch from the wrong
place, but the warning should be fixed. In future I'll just take the
patch myself!
Outside drm:
There are some snd changes for the HDMI audio interactions on haswell,
they've been acked for inclusion via my tree. This relies on the
wound/wait tree from Ingo which is already merged.
Major changes:
AMD finally released the dynamic power management code for all their
GPUs from r600->present day, this is great, off by default for now but
also a huge amount of code, in fact it is most of this pull request.
Since it landed there has been a lot of community testing and Alex has
sent a lot of fixes for any bugs found so far. I suspect radeon might
now be the biggest kernel driver ever :-P p.s. radeon.dpm=1 to enable
dynamic powermanagement for anyone.
New drivers:
Renesas r-car display unit.
Other highlights:
- core: GEM CMA prime support, use new w/w mutexs for TTM
reservations, cursor hotspot, doc updates
- dvo chips: chrontel 7010B support
- i915: Haswell (fbc, ips, vecs, watermarks, audio powerwell),
Valleyview (enabled by default, rc6), lots of pll reworking, 30bpp
support (this time for sure)
- nouveau: async buffer object deletion, context/register init
updates, kernel vp2 engine support, GF117 support, GK110 accel
support (with external nvidia ucode), context cleanups.
- exynos: memory leak fixes, Add S3C64XX SoC series support, device
tree updates, common clock framework support,
- qxl: cursor hotspot support, multi-monitor support, suspend/resume
support
- mgag200: hw cursor support, g200 mode limiting
- shmobile: prime support
- tegra: fixes mostly
I've been banging on this quite a lot due to the size of it, and it
seems to okay on everything I've tested it on."
* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (811 commits)
drm/radeon/dpm: implement vblank_too_short callback for si
drm/radeon/dpm: implement vblank_too_short callback for cayman
drm/radeon/dpm: implement vblank_too_short callback for btc
drm/radeon/dpm: implement vblank_too_short callback for evergreen
drm/radeon/dpm: implement vblank_too_short callback for 7xx
drm/radeon/dpm: add checks against vblank time
drm/radeon/dpm: add helper to calculate vblank time
drm/radeon: remove stray line in old pm code
drm/radeon/dpm: fix display_gap programming on rv7xx
drm/nvc0/gr: fix gpc firmware regression
drm/nouveau: fix minor thinko causing bo moves to not be async on kepler
drm/radeon/dpm: implement force performance level for TN
drm/radeon/dpm: implement force performance level for ON/LN
drm/radeon/dpm: implement force performance level for SI
drm/radeon/dpm: implement force performance level for cayman
drm/radeon/dpm: implement force performance levels for 7xx/eg/btc
drm/radeon/dpm: add infrastructure to force performance levels
drm/radeon: fix surface setup on r1xx
drm/radeon: add support for 3d perf states on older asics
drm/radeon: set default clocks for SI when DPM is disabled
...
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) u8 csum = 0; struct edid *edid = (struct edid *)raw_edid; + if (WARN_ON(!raw_edid)) + return false; + if (edid_fixup > 8 || edid_fixup < 0) edid_fixup = 6; @@ -1010,15 +1013,15 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) break; } - return 1; + return true; bad: - if (raw_edid && print_bad_edid) { + if (print_bad_edid) { printk(KERN_ERR "Raw EDID:\n"); print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1, raw_edid, EDID_LENGTH, false); } - return 0; + return false; } EXPORT_SYMBOL(drm_edid_block_valid); @@ -1706,11 +1709,11 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, return NULL; if (pt->misc & DRM_EDID_PT_STEREO) { - printk(KERN_WARNING "stereo mode not supported\n"); + DRM_DEBUG_KMS("stereo mode not supported\n"); return NULL; } if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { - printk(KERN_WARNING "composite sync not supported\n"); + DRM_DEBUG_KMS("composite sync not supported\n"); } /* it is incorrect if hsync/vsync width is zero */ @@ -2321,6 +2324,31 @@ u8 *drm_find_cea_extension(struct edid *edid) } EXPORT_SYMBOL(drm_find_cea_extension); +/* + * Calculate the alternate clock for the CEA mode + * (60Hz vs. 59.94Hz etc.) + */ +static unsigned int +cea_mode_alternate_clock(const struct drm_display_mode *cea_mode) +{ + unsigned int clock = cea_mode->clock; + + if (cea_mode->vrefresh % 6 != 0) + return clock; + + /* + * edid_cea_modes contains the 59.94Hz + * variant for 240 and 480 line modes, + * and the 60Hz variant otherwise. + */ + if (cea_mode->vdisplay == 240 || cea_mode->vdisplay == 480) + clock = clock * 1001 / 1000; + else + clock = DIV_ROUND_UP(clock * 1000, 1001); + + return clock; +} + /** * drm_match_cea_mode - look for a CEA mode matching given mode * @to_match: display mode @@ -2339,21 +2367,9 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) const struct drm_display_mode *cea_mode = &edid_cea_modes[mode]; unsigned int clock1, clock2; - clock1 = clock2 = cea_mode->clock; - /* Check both 60Hz and 59.94Hz */ - if (cea_mode->vrefresh % 6 == 0) { - /* - * edid_cea_modes contains the 59.94Hz - * variant for 240 and 480 line modes, - * and the 60Hz variant otherwise. - */ - if (cea_mode->vdisplay == 240 || - cea_mode->vdisplay == 480) - clock1 = clock1 * 1001 / 1000; - else - clock2 = DIV_ROUND_UP(clock2 * 1000, 1001); - } + clock1 = cea_mode->clock; + clock2 = cea_mode_alternate_clock(cea_mode); if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && @@ -2364,6 +2380,66 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match) } EXPORT_SYMBOL(drm_match_cea_mode); +static int +add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) +{ + struct drm_device *dev = connector->dev; + struct drm_display_mode *mode, *tmp; + LIST_HEAD(list); + int modes = 0; + + /* Don't add CEA modes if the CEA extension block is missing */ + if (!drm_find_cea_extension(edid)) + return 0; + + /* + * Go through all probed modes and create a new mode + * with the alternate clock for certain CEA modes. + */ + list_for_each_entry(mode, &connector->probed_modes, head) { + const struct drm_display_mode *cea_mode; + struct drm_display_mode *newmode; + u8 cea_mode_idx = drm_match_cea_mode(mode) - 1; + unsigned int clock1, clock2; + + if (cea_mode_idx >= ARRAY_SIZE(edid_cea_modes)) + continue; + + cea_mode = &edid_cea_modes[cea_mode_idx]; + + clock1 = cea_mode->clock; + clock2 = cea_mode_alternate_clock(cea_mode); + + if (clock1 == clock2) + continue; + + if (mode->clock != clock1 && mode->clock != clock2) + continue; + + newmode = drm_mode_duplicate(dev, cea_mode); + if (!newmode) + continue; + + /* + * The current mode could be either variant. Make + * sure to pick the "other" clock for the new mode. + */ + if (mode->clock != clock1) + newmode->clock = clock1; + else + newmode->clock = clock2; + + list_add_tail(&newmode->head, &list); + } + + list_for_each_entry_safe(mode, tmp, &list, head) { + list_del(&mode->head); + drm_mode_probed_add(connector, mode); + modes++; + } + + return modes; +} static int 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) if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) num_modes += add_inferred_modes(connector, edid); num_modes += add_cea_modes(connector, edid); + num_modes += add_alternate_cea_modes(connector, edid); if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) edid_fixup_preferred(connector, quirks); |