The CEA spec has a bunch of very peculiar modes. For backwards compatibility it specifies a bunch of modes that are suitable to display old SD TV content. But these modes have such low pixel clocks that pixels need to be doubled to reach the minimal clock of the HDMI interface. Paulo Zanoni already started to fix this up by properly marking these modes as double-clocked and sending the correct avi infoframe as required by CEA. The problem left is that the CEA spec specifies these modes with timings as they get transmitted, but because the double-clocking is just to make the HDMI phy happy, the TV actually drops every 2nd pixel. So e.g. a 1440x576 mode in our CEA mode list is actually a 720x576 mode. In a way this is similar to the interlaced stuff, where the frame that logically gets send out is not the same that actually goes through the wire. To be consistent with how we handle interlaced modes, we want only half the horizontal timings of what the CEA tables list (which then also properly tells userspace how big the scanned-out framebuffer actually is). To avoid digressing from the CEA table, fix up the horizontal timings in the cea parsing code and not in the table. Wrt the pixel clock I've opted to keep it as-is - in interlaced modes we also specify the pixelclock on the wire. Furthermore this makes checking for bandwidth constraints simpler. Similarly to interlaced modes it could be useful to add a doubleclock flag to drm_mode_set_crtcinfo to specify whether we want double clocked mode timings specified in doubled-up pixels or not. But because only the intel driver bothers atm to correctly implement these modes I've figured adding dead code for potential future use is not worth it. Because the mode names are used in userspace tools, these need to be adjusted, too. But I've left the comments as-is to make comparing with the CEA spec easier. Note also that this completely breaks these modes on intel, but that will be fixed in the next patch to correctly handle double-clocked modes. v2: Fix English fail in the commit message Signed-Off-by: Daniel Vetter <daniel.vetter at ffwll.ch> --- drivers/gpu/drm/drm_edid.c | 19 +++++++++++++++++++ drivers/gpu/drm/drm_edid_modes.h | 30 +++++++++++++++--------------- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 608bddf..9e22b61 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1467,6 +1467,25 @@ do_cea_modes (struct drm_connector *connector, u8 *db, u8 len) struct drm_display_mode *newmode; newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]); + + /* + * CEA specifies horizontal timings for double-clocked + * modes in doubled pixels. In drm, we want actual + * pixels (for consistency with other modes where a + * framebuffer pixel is not equal to a scanned-out + * pixel, e.g. interlaced modes). + * + * To keep the table in-sync with the CEA spec, adjust + * horizontal timings here. + */ + if (newmode->flags & DRM_MODE_FLAG_DBLCLK) { + newmode->hdisplay /= 2; + newmode->hsync_start /= 2; + newmode->hsync_end /= 2; + newmode->htotal /= 2; + newmode->hskew /= 2; + } + if (newmode) { drm_mode_probed_add(connector, newmode); modes++; diff --git a/drivers/gpu/drm/drm_edid_modes.h b/drivers/gpu/drm/drm_edid_modes.h index ff98a7e..9226cbe 100644 --- a/drivers/gpu/drm/drm_edid_modes.h +++ b/drivers/gpu/drm/drm_edid_modes.h @@ -511,22 +511,22 @@ static const struct drm_display_mode edid_cea_modes[] = { DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 6 - 1440x480i at 60Hz */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 7 - 1440x480i at 60Hz */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 8 - 1440x240 at 60Hz */ - { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + { DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK) }, /* 9 - 1440x240 at 60Hz */ - { DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + { DRM_MODE("720x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK) }, @@ -578,17 +578,17 @@ static const struct drm_display_mode edid_cea_modes[] = { DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 21 - 1440x576i at 50Hz */ - { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 22 - 1440x576i at 50Hz */ - { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 23 - 1440x288 at 50Hz */ - { DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + { DRM_MODE("720x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK) }, @@ -678,12 +678,12 @@ static const struct drm_display_mode edid_cea_modes[] = { 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 44 - 1440x576i at 100Hz */ - { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK) }, /* 45 - 1440x576i at 100Hz */ - { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK) }, @@ -705,12 +705,12 @@ static const struct drm_display_mode edid_cea_modes[] = { 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 50 - 1440x480i at 120Hz */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 51 - 1440x480i at 120Hz */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, @@ -723,12 +723,12 @@ static const struct drm_display_mode edid_cea_modes[] = { 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 54 - 1440x576i at 200Hz */ - { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 55 - 1440x576i at 200Hz */ - { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, @@ -741,12 +741,12 @@ static const struct drm_display_mode edid_cea_modes[] = { 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 58 - 1440x480i at 240 */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 59 - 1440x480i at 240 */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, -- 1.7.9