diff options
-rw-r--r-- | lib/igt_edid.c | 36 | ||||
-rw-r--r-- | lib/igt_edid.h | 50 |
2 files changed, 75 insertions, 11 deletions
diff --git a/lib/igt_edid.c b/lib/igt_edid.c index df5b6611..096668e6 100644 --- a/lib/igt_edid.c +++ b/lib/igt_edid.c @@ -42,6 +42,8 @@ static const char monitor_range_padding[] = { 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; +const uint8_t hdmi_ieee_oui[3] = {0x03, 0x0C, 0x00}; + /* vfreq is in Hz */ static void std_timing_set(struct std_timing *st, int hsize, int vfreq, enum std_timing_aspect aspect) @@ -321,21 +323,23 @@ void cea_sad_init_pcm(struct cea_sad *sad, int channels, */ const struct cea_vsdb *cea_vsdb_get_hdmi_default(size_t *size) { - static char raw[sizeof(struct cea_vsdb) + 4] = {0}; + /* We'll generate a VSDB with 2 extension fields. */ + static char raw[CEA_VSDB_HDMI_MIN_SIZE + 2] = {0}; struct cea_vsdb *vsdb; + struct hdmi_vsdb *hdmi; *size = sizeof(raw); /* Magic incantation. Works better if you orient your screen in the * direction of the VESA headquarters. */ vsdb = (struct cea_vsdb *) raw; - vsdb->ieee_oui[0] = 0x03; - vsdb->ieee_oui[1] = 0x0C; - vsdb->ieee_oui[2] = 0x00; - vsdb->data[0] = 0x10; - vsdb->data[1] = 0x00; - vsdb->data[2] = 0x38; - vsdb->data[3] = 0x2D; + memcpy(vsdb->ieee_oui, hdmi_ieee_oui, sizeof(hdmi_ieee_oui)); + hdmi = &vsdb->data.hdmi; + hdmi->src_phy_addr[0] = 0x10; + hdmi->src_phy_addr[1] = 0x00; + /* 2 VSDB extension fields */ + hdmi->flags1 = 0x38; + hdmi->max_tdms_clock = 0x2D; return vsdb; } @@ -371,6 +375,22 @@ size_t edid_cea_data_block_set_vsdb(struct edid_cea_data_block *block, return sizeof(struct edid_cea_data_block) + vsdb_size; } +size_t edid_cea_data_block_set_hdmi_vsdb(struct edid_cea_data_block *block, + const struct hdmi_vsdb *hdmi, + size_t hdmi_size) +{ + char raw_vsdb[CEA_VSDB_HDMI_MAX_SIZE] = {0}; + struct cea_vsdb *vsdb = (struct cea_vsdb *) raw_vsdb; + + assert(hdmi_size >= HDMI_VSDB_MIN_SIZE && + hdmi_size <= HDMI_VSDB_MAX_SIZE); + memcpy(vsdb->ieee_oui, hdmi_ieee_oui, sizeof(hdmi_ieee_oui)); + memcpy(&vsdb->data.hdmi, hdmi, hdmi_size); + + return edid_cea_data_block_set_vsdb(block, vsdb, + CEA_VSDB_HEADER_SIZE + hdmi_size); +} + size_t edid_cea_data_block_set_speaker_alloc(struct edid_cea_data_block *block, const struct cea_speaker_alloc *speakers) { diff --git a/lib/igt_edid.h b/lib/igt_edid.h index 6fcb50a3..7907baee 100644 --- a/lib/igt_edid.h +++ b/lib/igt_edid.h @@ -191,11 +191,52 @@ struct cea_sad { uint8_t bitrate; } __attribute__((packed)); +enum hdmi_vsdb_flags1 { + HDMI_VSDB_DVI_DUAL = 1 << 0, + HDMI_VSDB_DC_Y444 = 1 << 3, /* supports YCbCr 4:4:4 */ + HDMI_VSDB_DC_30BIT = 1 << 4, /* 30 bits per pixel */ + HDMI_VSDB_DC_36BIT = 1 << 5, /* 36 bits per pixel */ + HDMI_VSDB_DC_48BIT = 1 << 6, /* 48 bits per pixel */ + HDMI_VSDB_SUPPORTS_AI = 1 << 7, /* supports ACP, ISRC1 or ISRC2 packets */ +}; + +enum hdmi_vsdb_flags2 { + HDMI_VSDB_CNC_GRAPHICS = 1 << 0, + HDMI_VSDB_CNC_PHOTO = 1 << 1, + HDMI_VSDB_CNC_CINEMA = 1 << 2, + HDMI_VSDB_CNC_GAME = 1 << 3, + HDMI_VSDB_VIDEO_PRESENT = 1 << 5, + HDMI_VSDB_INTERLACED_LATENCY_PRESENT = 1 << 6, + HDMI_VSDB_LATENCY_PRESENT = 1 << 7, +}; + +/* HDMI's IEEE Registration Identifier */ +extern const uint8_t hdmi_ieee_oui[3]; + +/* HDMI Vendor-Specific Data Block (defined in the HDMI spec) */ +struct hdmi_vsdb { + uint8_t src_phy_addr[2]; /* source physical address */ + + /* Extension fields */ + uint8_t flags1; /* enum hdmi_vsdb_flags1 */ + uint8_t max_tdms_clock; /* multiply by 5MHz */ + uint8_t flags2; /* enum hdmi_vsdb_flags2 */ + char data[]; /* latency, misc, VIC, 3D */ +} __attribute__((packed)); + +#define HDMI_VSDB_MIN_SIZE 2 /* just the source physical address */ +#define HDMI_VSDB_MAX_SIZE 28 +#define CEA_VSDB_HEADER_SIZE 3 /* IEEE OUI */ +#define CEA_VSDB_HDMI_MIN_SIZE (CEA_VSDB_HEADER_SIZE + HDMI_VSDB_MIN_SIZE) +#define CEA_VSDB_HDMI_MAX_SIZE (CEA_VSDB_HEADER_SIZE + HDMI_VSDB_MAX_SIZE) + /* Vendor-Specific Data Block */ struct cea_vsdb { - uint8_t ieee_oui[3]; - char data[]; -}; + uint8_t ieee_oui[3]; /* 24-bit IEEE Registration Identifier, LSB */ + union { + struct hdmi_vsdb hdmi; + } data; +} __attribute__((packed)); enum cea_speaker_alloc_item { CEA_SPEAKER_FRONT_LEFT_RIGHT = 1 << 0, @@ -315,6 +356,9 @@ size_t edid_cea_data_block_set_sad(struct edid_cea_data_block *block, const struct cea_sad *sads, size_t sads_len); size_t edid_cea_data_block_set_vsdb(struct edid_cea_data_block *block, const struct cea_vsdb *vsdb, size_t vsdb_size); +size_t edid_cea_data_block_set_hdmi_vsdb(struct edid_cea_data_block *block, + const struct hdmi_vsdb *hdmi, + size_t hdmi_size); size_t edid_cea_data_block_set_speaker_alloc(struct edid_cea_data_block *block, const struct cea_speaker_alloc *speakers); void edid_ext_set_cea(struct edid_ext *ext, size_t data_blocks_size, |