From f9994c6cff72c203d15bf6175baa6b555ad3429b Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Sun, 1 May 2016 15:23:31 +0200 Subject: [PATCH 3/3] drm/displayid: Parse type 1 detailed timings This adds a parser for DisplayID tag 0x03. Probed modelines are printed out to drm debug log. https://bugs.freedesktop.org/show_bug.cgi?id=95207 --- drivers/gpu/drm/drm_edid.c | 49 +++++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_displayid.h | 29 +++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 6ec0d04..d1367ce 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4244,6 +4244,55 @@ static int drm_parse_display_id(struct drm_connector *connector, drm_mode_put_tile_group(connector->dev, tg); } break; + + case DATA_BLOCK_TYPE_1_DETAILED_TIMING: { + struct displayid_type1_timings_block *tblock = (struct displayid_type1_timings_block *)block; + int i; + + for (i = 0; (i + 1) * sizeof(struct displayid_type1_timings) <= block->num_bytes; i++) { + struct displayid_type1_timings *timings = &(tblock->timings[i]); + u16 hblank_start, width, hblank_end, hsync_start, hsync_end, htotal; + u16 vblank_start, height, vblank_end, vsync_start, vsync_end, vtotal; + u32 dclk; + u16 refresh; + + /* DisplayID fields are 0 based but should be interpreted as 1-based. + * For example hsync_width value can be read as 0-65,535 pixels but + * interpreted as 1-65,536. So, to get the right value add 1. */ + hblank_start = timings->hactive; + width = timings->hactive + 1; + hblank_end = hblank_start + timings->hblank + 1; + hsync_start = hblank_start + timings->hsync_offset + 1; + hsync_end = hsync_start + timings->hsync_width + 1; + htotal = hblank_end; + vblank_start = timings->vactive; + height = timings->vactive + 1; + vblank_end = vblank_start + timings->vblank + 1; + vsync_start = vblank_start + timings->vsync_offset + 1; + vsync_end = vsync_start + timings->vsync_width + 1; + vtotal = vblank_end; + dclk = ((u32) timings->lsb_dclk | ((u32) timings->msb_dclk << 16)) * 10L; + refresh = ((dclk * 1000L) / htotal) / vtotal; + + DRM_DEBUG_KMS(" Modeline \"%dx%d@%d\" %u %d %d %d %d %d %d %d %d %shsync %svsync\n", + width, height, refresh, dclk, + width, hsync_start, hsync_end, hblank_end, + height, vsync_start, vsync_end, vblank_end, + timings->hsync_polarity ? "+" : "-", timings->vsync_polarity ? "+" : "-"); + DRM_DEBUG_KMS(" pixel clock %d kHz, preferred = %d, interlaced = %d, aspect_ratio = %d, stereo_3d_support = %d\n", + dclk, timings->preferred, timings->interlaced, timings->aspect_ratio, timings->stereo_3d_support); + DRM_DEBUG_KMS(" hactive = %d, hblank = %d, hsync_offset = %d, hsync_width = %d\n", + timings->hactive + 1, timings->hblank + 1, timings->hsync_offset + 1, timings->hsync_width + 1); + DRM_DEBUG_KMS(" vactive = %d, vblank = %d, vsync_offset = %d, vsync_width = %d\n", + timings->vactive + 1, timings->vblank + 1, timings->vsync_offset + 1, timings->vsync_width + 1); + DRM_DEBUG_KMS(" hblank_start = %d, width = %d, hblank_end = %d, hsync_start = %d, hsync_end = htotal = %d\n", + hblank_start, width, hblank_end, hsync_start, hsync_end); + DRM_DEBUG_KMS(" vblank_start = %d, height = %d, vblank_end = %d, vsync_start = %d, vsync_end = vtotal = %d\n", + vblank_start, height, vblank_end, vsync_start, vsync_end); + } + } + break; + default: DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag); break; diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h index 042f9fc..6bb4b39 100644 --- a/include/drm/drm_displayid.h +++ b/include/drm/drm_displayid.h @@ -75,4 +75,33 @@ struct displayid_tiled_block { u8 topology_id[8]; } __packed; +/* Type 1 - DTD - 20 bytes */ +struct displayid_type1_timings { + u16 lsb_dclk; + u8 msb_dclk; + + /* timing options - 1 byte */ + u8 aspect_ratio:3; + u8 reserved:1; + u8 interlaced:1; + u8 stereo_3d_support:2; + u8 preferred:1; + + u16 hactive; + u16 hblank; + u16 hsync_offset:15; + u16 hsync_polarity:1; + u16 hsync_width; + u16 vactive; + u16 vblank; + u16 vsync_offset:15; + u16 vsync_polarity:1; + u16 vsync_width; +} __packed; + +struct displayid_type1_timings_block { + struct displayid_block base; + struct displayid_type1_timings timings[]; +} __packed; + #endif -- 2.8.1