Commit fc2ec956 authored by Ma Ling's avatar Ma Ling Committed by Adam Jackson

EDID: CEA extension support

Reviewed-by: Adam Jackson's avatarAdam Jackson <ajax@redhat.com>
parent fab74d10
......@@ -544,6 +544,36 @@ configureMonitorSection (int screennum)
return ptr;
}
/* Initialize Configure Monitor from Detailed Timing Block */
static void handle_detailed_input(struct detailed_monitor_section *det_mon,
void *data)
{
XF86ConfMonitorPtr ptr = (XF86ConfMonitorPtr) data;
switch (det_mon->type) {
case DS_NAME:
ptr->mon_modelname = realloc(ptr->mon_modelname,
strlen((char*)(det_mon->section.name)) +
1);
strcpy(ptr->mon_modelname,
(char*)(det_mon->section.name));
break;
case DS_RANGES:
ptr->mon_hsync[ptr->mon_n_hsync].lo =
det_mon->section.ranges.min_h;
ptr->mon_hsync[ptr->mon_n_hsync].hi =
det_mon->section.ranges.max_h;
ptr->mon_n_vrefresh = 1;
ptr->mon_vrefresh[ptr->mon_n_hsync].lo =
det_mon->section.ranges.min_v;
ptr->mon_vrefresh[ptr->mon_n_hsync].hi =
det_mon->section.ranges.max_v;
ptr->mon_n_hsync++;
default:
break;
}
}
static XF86ConfMonitorPtr
configureDDCMonitorSection (int screennum)
{
......@@ -590,30 +620,8 @@ configureDDCMonitorSection (int screennum)
}
#endif /* def CONFIGURE_DISPLAYSIZE */
for (i=0;i<4;i++) {
switch (ConfiguredMonitor->det_mon[i].type) {
case DS_NAME:
ptr->mon_modelname = realloc(ptr->mon_modelname,
strlen((char*)(ConfiguredMonitor->det_mon[i].section.name))
+ 1);
strcpy(ptr->mon_modelname,
(char*)(ConfiguredMonitor->det_mon[i].section.name));
break;
case DS_RANGES:
ptr->mon_hsync[ptr->mon_n_hsync].lo =
ConfiguredMonitor->det_mon[i].section.ranges.min_h;
ptr->mon_hsync[ptr->mon_n_hsync].hi =
ConfiguredMonitor->det_mon[i].section.ranges.max_h;
ptr->mon_n_vrefresh = 1;
ptr->mon_vrefresh[ptr->mon_n_hsync].lo =
ConfiguredMonitor->det_mon[i].section.ranges.min_v;
ptr->mon_vrefresh[ptr->mon_n_hsync].hi =
ConfiguredMonitor->det_mon[i].section.ranges.max_v;
ptr->mon_n_hsync++;
default:
break;
}
}
xf86ForEachDetailedBlock(ConfiguredMonitor, handle_detailed_input,
ptr);
if (ConfiguredMonitor->features.dpms) {
ptr->mon_option_lst = xf86addNewOption(ptr->mon_option_lst, xstrdup("DPMS"), NULL);
......
......@@ -562,4 +562,101 @@ typedef struct {
extern _X_EXPORT xf86MonPtr ConfiguredMonitor;
#define EXT_TAG 0
#define EXT_REV 1
#define CEA_EXT 0x02
#define VTB_EXT 0x10
#define DI_EXT 0x40
#define LS_EXT 0x50
#define MI_EXT 0x60
#define CEA_EXT_MIN_DATA_OFFSET 4
#define CEA_EXT_MAX_DATA_OFFSET 127
#define CEA_EXT_DET_TIMING_NUM 6
#define IEEE_ID_HDMI 0x000C03
#define CEA_AUDIO_BLK 1
#define CEA_VIDEO_BLK 2
#define CEA_VENDOR_BLK 3
#define CEA_SPEAKER_ALLOC_BLK 4
#define CEA_VESA_DTC_BLK 5
#define VENDOR_SUPPORT_AI(x) ((x) >> 7)
#define VENDOR_SUPPORT_DC_48bit(x) ( ( (x) >> 6) & 0x01)
#define VENDOR_SUPPORT_DC_36bit(x) ( ( (x) >> 5) & 0x01)
#define VENDOR_SUPPORT_DC_30bit(x) ( ( (x) >> 4) & 0x01)
#define VENDOR_SUPPORT_DC_Y444(x) ( ( (x) >> 3) & 0x01)
#define VENDOR_LATENCY_PRESENT(x) ( (x) >> 7)
#define VENDOR_LATENCY_PRESENT_I(x) ( ( (x) >> 6) & 0x01)
#define HDMI_MAX_TMDS_UNIT (5000)
struct cea_video_block {
Uchar video_code;
};
struct cea_audio_block_descriptor {
Uchar audio_code[3];
};
struct cea_audio_block {
struct cea_audio_block_descriptor descriptor[10];
};
struct cea_vendor_block_hdmi {
Uchar portB:4;
Uchar portA:4;
Uchar portD:4;
Uchar portC:4;
Uchar support_flags;
Uchar max_tmds_clock;
Uchar latency_present;
Uchar video_latency;
Uchar audio_latency;
Uchar interlaced_video_latency;
Uchar interlaced_audio_latency;
};
struct cea_vendor_block {
unsigned char ieee_id[3];
union {
struct cea_vendor_block_hdmi hdmi;
/* any other vendor blocks we know about */
};
};
struct cea_speaker_block
{
Uchar FLR:1;
Uchar LFE:1;
Uchar FC:1;
Uchar RLR:1;
Uchar RC:1;
Uchar FLRC:1;
Uchar RLRC:1;
Uchar FLRW:1;
Uchar FLRH:1;
Uchar TC:1;
Uchar FCH:1;
Uchar Resv:5;
Uchar ResvByte;
};
struct cea_data_block {
Uchar len:5;
Uchar tag:3;
union{
struct cea_video_block video;
struct cea_audio_block audio;
struct cea_vendor_block vendor;
struct cea_speaker_block speaker;
}u;
};
struct cea_ext_body {
Uchar tag;
Uchar rev;
Uchar dt_offset;
Uchar flags;
struct cea_data_block data_collection;
};
#endif /* _EDID_H_ */
This diff is collapsed.
This diff is collapsed.
......@@ -73,4 +73,54 @@ FindDMTMode(int hsize, int vsize, int refresh, Bool rb);
extern _X_EXPORT const DisplayModeRec DMTModes[];
/*
* Quirks to work around broken EDID data from various monitors.
*/
typedef enum {
DDC_QUIRK_NONE = 0,
/* First detailed mode is bogus, prefer largest mode at 60hz */
DDC_QUIRK_PREFER_LARGE_60 = 1 << 0,
/* 135MHz clock is too high, drop a bit */
DDC_QUIRK_135_CLOCK_TOO_HIGH = 1 << 1,
/* Prefer the largest mode at 75 Hz */
DDC_QUIRK_PREFER_LARGE_75 = 1 << 2,
/* Convert detailed timing's horizontal from units of cm to mm */
DDC_QUIRK_DETAILED_H_IN_CM = 1 << 3,
/* Convert detailed timing's vertical from units of cm to mm */
DDC_QUIRK_DETAILED_V_IN_CM = 1 << 4,
/* Detailed timing descriptors have bogus size values, so just take the
* maximum size and use that.
*/
DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE = 1 << 5,
/* Monitor forgot to set the first detailed is preferred bit. */
DDC_QUIRK_FIRST_DETAILED_PREFERRED = 1 << 6,
/* use +hsync +vsync for detailed mode */
DDC_QUIRK_DETAILED_SYNC_PP = 1 << 7,
/* Force single-link DVI bandwidth limit */
DDC_QUIRK_DVI_SINGLE_LINK = 1 << 8,
} ddc_quirk_t;
DisplayModePtr xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC);
extern Bool
xf86MonitorIsHDMI(xf86MonPtr mon);
typedef void (* handle_detailed_fn)(struct detailed_monitor_section *,void *);
void xf86ForEachDetailedBlock(xf86MonPtr mon,
handle_detailed_fn,
void *data);
ddc_quirk_t
xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose);
void xf86DetTimingApplyQuirks(struct detailed_monitor_section *det_mon,
ddc_quirk_t quirks, int hsize, int vsize);
typedef void (* handle_video_fn)(struct cea_video_block *, void *);
void xf86ForEachVideoBlock(xf86MonPtr,
handle_video_fn,
void *);
#endif
......@@ -1523,6 +1523,42 @@ GuessRangeFromModes(MonPtr mon, DisplayModePtr mode)
mon->vrefresh[0].lo = 58.0;
}
struct det_monrec_parameter {
MonRec *mon_rec;
int *max_clock;
Bool set_hsync;
Bool set_vrefresh;
enum { sync_config, sync_edid, sync_default } *sync_source;
};
static void handle_detailed_monrec(struct detailed_monitor_section *det_mon,
void *data)
{
enum { sync_config, sync_edid, sync_default };
struct det_monrec_parameter *p;
p = (struct det_monrec_parameter *)data;
if (det_mon->type == DS_RANGES) {
struct monitor_ranges *ranges = &det_mon->section.ranges;
if (p->set_hsync && ranges->max_h) {
p->mon_rec->hsync[p->mon_rec->nHsync].lo = ranges->min_h;
p->mon_rec->hsync[p->mon_rec->nHsync].hi = ranges->max_h;
p->mon_rec->nHsync++;
if (*p->sync_source == sync_default)
*p->sync_source = sync_edid;
}
if (p->set_vrefresh && ranges->max_v) {
p->mon_rec->vrefresh[p->mon_rec->nVrefresh].lo = ranges->min_v;
p->mon_rec->vrefresh[p->mon_rec->nVrefresh].hi = ranges->max_v;
p->mon_rec->nVrefresh++;
if (*p->sync_source == sync_default)
*p->sync_source = sync_edid;
}
if (ranges->max_clock * 1000 > *p->max_clock)
*p->max_clock = ranges->max_clock * 1000;
}
}
void
xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY)
{
......@@ -1601,42 +1637,24 @@ xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY)
edid_monitor = output->MonInfo;
if (edid_monitor)
{
int i;
Bool set_hsync = mon_rec.nHsync == 0;
Bool set_vrefresh = mon_rec.nVrefresh == 0;
struct disp_features *features = &edid_monitor->features;
if (edid_monitor)
{
struct det_monrec_parameter p;
struct disp_features *features = &edid_monitor->features;
/* if display is not continuous-frequency, don't add default modes */
if (!GTF_SUPPORTED(features->msc))
add_default_modes = FALSE;
for (i = 0; i < sizeof (edid_monitor->det_mon) / sizeof (edid_monitor->det_mon[0]); i++)
{
if (edid_monitor->det_mon[i].type == DS_RANGES)
{
struct monitor_ranges *ranges = &edid_monitor->det_mon[i].section.ranges;
if (set_hsync && ranges->max_h)
{
mon_rec.hsync[mon_rec.nHsync].lo = ranges->min_h;
mon_rec.hsync[mon_rec.nHsync].hi = ranges->max_h;
mon_rec.nHsync++;
if (sync_source == sync_default)
sync_source = sync_edid;
}
if (set_vrefresh && ranges->max_v)
{
mon_rec.vrefresh[mon_rec.nVrefresh].lo = ranges->min_v;
mon_rec.vrefresh[mon_rec.nVrefresh].hi = ranges->max_v;
mon_rec.nVrefresh++;
if (sync_source == sync_default)
sync_source = sync_edid;
}
if (ranges->max_clock * 1000 > max_clock)
max_clock = ranges->max_clock * 1000;
}
}
p.mon_rec = &mon_rec;
p.max_clock = &max_clock;
p.set_hsync = mon_rec.nHsync == 0;
p.set_vrefresh = mon_rec.nVrefresh == 0;
p.sync_source = &sync_source;
xf86ForEachDetailedBlock(edid_monitor,
handle_detailed_monrec,
&p);
}
if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK,
......@@ -2900,6 +2918,35 @@ xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len)
#endif
/* Pull out a phyiscal size from a detailed timing if available. */
struct det_phySize_parameter {
xf86OutputPtr output;
ddc_quirk_t quirks;
Bool ret;
};
static void handle_detailed_physical_size(struct detailed_monitor_section
*det_mon, void *data)
{
struct det_phySize_parameter *p;
p = (struct det_phySize_parameter *)data;
if (p->ret == TRUE )
return ;
xf86DetTimingApplyQuirks(det_mon, p->quirks,
p->output->MonInfo->features.hsize,
p->output->MonInfo->features.vsize);
if (det_mon->type == DT &&
det_mon->section.d_timings.h_size != 0 &&
det_mon->section.d_timings.v_size != 0) {
p->output->mm_width = det_mon->section.d_timings.h_size;
p->output->mm_height = det_mon->section.d_timings.v_size;
p->ret = TRUE;
}
}
/**
* Set the EDID information for the specified output
*/
......@@ -2908,7 +2955,6 @@ xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon)
{
ScrnInfoPtr scrn = output->scrn;
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
int i;
#ifdef RANDR_12_INTERFACE
int size;
#endif
......@@ -2943,20 +2989,15 @@ xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon)
xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size);
#endif
if (edid_mon)
{
/* Pull out a phyiscal size from a detailed timing if available. */
for (i = 0; i < 4; i++) {
if (edid_mon->det_mon[i].type == DT &&
edid_mon->det_mon[i].section.d_timings.h_size != 0 &&
edid_mon->det_mon[i].section.d_timings.v_size != 0)
{
output->mm_width = edid_mon->det_mon[i].section.d_timings.h_size;
output->mm_height = edid_mon->det_mon[i].section.d_timings.v_size;
break;
}
}
if (edid_mon) {
struct det_phySize_parameter p;
p.output = output;
p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex,edid_mon, FALSE);
p.ret = FALSE;
xf86ForEachDetailedBlock(edid_mon,
handle_detailed_physical_size, &p);
/* if no mm size is available from a detailed timing, check the max size field */
if ((!output->mm_width || !output->mm_height) &&
(edid_mon->features.hsize && edid_mon->features.vsize))
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment