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:
parent
d807358c86
commit
b9e63a962a
106
common/edid.c
106
common/edid.c
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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_ */
|
||||
|
|
|
|||
Loading…
Reference in New Issue