edid: support decode edid to drm modes

Change-Id: I38f82586d81177a4e6f5c20815af5480b40d2ff8
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
This commit is contained in:
Mark Yao 2017-09-15 15:01:09 +08:00 committed by Kever Yang
parent d807358c86
commit b9e63a962a
3 changed files with 176 additions and 0 deletions

View File

@ -16,6 +16,7 @@
#include <fdtdec.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <drm_modes.h>
int edid_check_info(struct edid1_info *edid_info)
{
@ -136,6 +137,62 @@ static void decode_timing(u8 *buf, struct display_timing *timing)
va + vbl, vborder);
}
/**
* decode_mode() - Decoding an 18-byte detailed timing record
*
* @buf: Pointer to EDID detailed timing record
* @timing: Place to put timing
*/
static void decode_mode(u8 *buf, struct drm_display_mode *mode)
{
uint x_mm, y_mm;
unsigned int ha, hbl, hso, hspw, hborder;
unsigned int va, vbl, vso, vspw, vborder;
struct edid_detailed_timing *t = (struct edid_detailed_timing *)buf;
x_mm = (buf[12] + ((buf[14] & 0xf0) << 4));
y_mm = (buf[13] + ((buf[14] & 0x0f) << 8));
ha = (buf[2] + ((buf[4] & 0xf0) << 4));
hbl = (buf[3] + ((buf[4] & 0x0f) << 8));
hso = (buf[8] + ((buf[11] & 0xc0) << 2));
hspw = (buf[9] + ((buf[11] & 0x30) << 4));
hborder = buf[15];
va = (buf[5] + ((buf[7] & 0xf0) << 4));
vbl = (buf[6] + ((buf[7] & 0x0f) << 8));
vso = ((buf[10] >> 4) + ((buf[11] & 0x0c) << 2));
vspw = ((buf[10] & 0x0f) + ((buf[11] & 0x03) << 4));
vborder = buf[16];
/* Edid contains pixel clock in terms of 10KHz */
mode->clock = (buf[0] + (buf[1] << 8)) * 10;
mode->hdisplay = ha;
mode->hsync_start = ha + hso;
mode->hsync_end = ha + hso + hspw;
mode->htotal = ha + hbl;
mode->vdisplay = va;
mode->vsync_start = va + vso;
mode->vsync_end = va + vso + vspw;
mode->vtotal = va + vbl;
mode->flags = EDID_DETAILED_TIMING_FLAG_HSYNC_POLARITY(*t) ?
DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
mode->flags |= EDID_DETAILED_TIMING_FLAG_VSYNC_POLARITY(*t) ?
DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
if (EDID_DETAILED_TIMING_FLAG_HSYNC_POLARITY(*t))
mode->flags |= DRM_MODE_FLAG_INTERLACE;
debug("Detailed mode clock %u kHz, %d mm x %d mm, flags[%x]\n"
" %04d %04d %04d %04d hborder %d\n"
" %04d %04d %04d %04d vborder %d\n",
mode->clock,
x_mm, y_mm, mode->flags,
mode->hdisplay, mode->hsync_start, mode->hsync_end,
mode->htotal, hborder,
mode->vdisplay, mode->vsync_start, mode->vsync_end,
mode->vtotal, vborder);
}
/**
* Check if HDMI vendor specific data block is present in CEA block
* @param info CEA extension block
@ -169,6 +226,54 @@ static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info)
return false;
}
int edid_get_drm_mode(u8 *buf, int buf_size, struct drm_display_mode *mode,
int *panel_bits_per_colourp)
{
struct edid1_info *edid = (struct edid1_info *)buf;
bool timing_done;
int i;
if (buf_size < sizeof(*edid) || edid_check_info(edid)) {
debug("%s: Invalid buffer\n", __func__);
return -EINVAL;
}
if (!EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(*edid)) {
debug("%s: No preferred timing\n", __func__);
return -ENOENT;
}
/* Look for detailed timing */
timing_done = false;
for (i = 0; i < 4; i++) {
struct edid_monitor_descriptor *desc;
desc = &edid->monitor_details.descriptor[i];
if (desc->zero_flag_1 != 0) {
decode_mode((u8 *)desc, mode);
timing_done = true;
break;
}
}
if (!timing_done)
return -EINVAL;
if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) {
debug("%s: Not a digital display\n", __func__);
return -ENOSYS;
}
if (edid->version != 1 || edid->revision < 4) {
debug("%s: EDID version %d.%d does not have required info\n",
__func__, edid->version, edid->revision);
*panel_bits_per_colourp = -1;
} else {
*panel_bits_per_colourp =
((edid->video_input_definition & 0x70) >> 3) + 4;
}
return 0;
}
int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing,
int *panel_bits_per_colourp)
{
@ -226,6 +331,7 @@ int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing,
return 0;
}
/**
* Snip the tailing whitespace/return of a string.
*

67
include/drm_modes.h Normal file
View File

@ -0,0 +1,67 @@
/*
* (C) Copyright 2008-2016 Fuzhou Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _DRM_MODES_H
#define _DRM_MODES_H
/* Video mode flags */
/* bit compatible with the xorg definitions. */
#define DRM_MODE_FLAG_PHSYNC (1 << 0)
#define DRM_MODE_FLAG_NHSYNC (1 << 1)
#define DRM_MODE_FLAG_PVSYNC (1 << 2)
#define DRM_MODE_FLAG_NVSYNC (1 << 3)
#define DRM_MODE_FLAG_INTERLACE (1 << 4)
#define DRM_MODE_FLAG_DBLSCAN (1 << 5)
#define DRM_MODE_FLAG_CSYNC (1 << 6)
#define DRM_MODE_FLAG_PCSYNC (1 << 7)
#define DRM_MODE_FLAG_NCSYNC (1 << 8)
#define DRM_MODE_FLAG_HSKEW (1 << 9) /* hskew provided */
#define DRM_MODE_FLAG_BCAST (1 << 10)
#define DRM_MODE_FLAG_PIXMUX (1 << 11)
#define DRM_MODE_FLAG_DBLCLK (1 << 12)
#define DRM_MODE_FLAG_CLKDIV2 (1 << 13)
#define DRM_MODE_CONNECTOR_Unknown 0
#define DRM_MODE_CONNECTOR_VGA 1
#define DRM_MODE_CONNECTOR_DVII 2
#define DRM_MODE_CONNECTOR_DVID 3
#define DRM_MODE_CONNECTOR_DVIA 4
#define DRM_MODE_CONNECTOR_Composite 5
#define DRM_MODE_CONNECTOR_SVIDEO 6
#define DRM_MODE_CONNECTOR_LVDS 7
#define DRM_MODE_CONNECTOR_Component 8
#define DRM_MODE_CONNECTOR_9PinDIN 9
#define DRM_MODE_CONNECTOR_DisplayPort 10
#define DRM_MODE_CONNECTOR_HDMIA 11
#define DRM_MODE_CONNECTOR_HDMIB 12
#define DRM_MODE_CONNECTOR_TV 13
#define DRM_MODE_CONNECTOR_eDP 14
#define DRM_MODE_CONNECTOR_VIRTUAL 15
#define DRM_MODE_CONNECTOR_DSI 16
#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 1)
#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 2)
#define DRM_EDID_PT_SEPARATE_SYNC (3 << 3)
#define DRM_EDID_PT_STEREO (1 << 5)
#define DRM_EDID_PT_INTERLACED (1 << 7)
struct drm_display_mode {
/* Proposed mode values */
int clock; /* in kHz */
int hdisplay;
int hsync_start;
int hsync_end;
int htotal;
int vdisplay;
int vsync_start;
int vsync_end;
int vtotal;
int vrefresh;
int vscan;
unsigned int flags;
};
#endif

View File

@ -305,6 +305,7 @@ int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin,
unsigned int *hmax, unsigned int *vmin,
unsigned int *vmax);
struct drm_display_mode;
struct display_timing;
/**
@ -320,5 +321,7 @@ struct display_timing;
*/
int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing,
int *panel_bits_per_colourp);
int edid_get_drm_mode(u8 *buf, int buf_size, struct drm_display_mode *mode,
int *panel_bits_per_colourp);
#endif /* __EDID_H_ */