summaryrefslogtreecommitdiffstats
path: root/edid
diff options
context:
space:
mode:
authorcodeworkx <codeworkx@cyanogenmod.org>2013-02-11 17:29:55 +0000
committercodeworkx <codeworkx@cyanogenmod.org>2013-02-13 18:55:29 +0000
commit222b794ae146b4e0d61958c55a518396e293e6d7 (patch)
tree744f1fc5d63e8669de1018dc7c42c4e863ceae85 /edid
downloaddevice_samsung_omap4-common-222b794ae146b4e0d61958c55a518396e293e6d7.zip
device_samsung_omap4-common-222b794ae146b4e0d61958c55a518396e293e6d7.tar.gz
device_samsung_omap4-common-222b794ae146b4e0d61958c55a518396e293e6d7.tar.bz2
initial commit
sources from http://omapzoom.org
Diffstat (limited to 'edid')
-rw-r--r--edid/Android.mk45
-rw-r--r--edid/cmd/parse_hdmi_edid.c154
-rw-r--r--edid/inc/edid_parser.h113
-rw-r--r--edid/lib/edid_parser.c410
-rw-r--r--edid/lib/edid_parser_priv.h31
5 files changed, 753 insertions, 0 deletions
diff --git a/edid/Android.mk b/edid/Android.mk
new file mode 100644
index 0000000..d1bace0
--- /dev/null
+++ b/edid/Android.mk
@@ -0,0 +1,45 @@
+# Copyright (C) Texas Instruments - http://www.ti.com/
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# AOSP specific
+ifneq ($(TARGET_PRODUCT),full_$(TARGET_BOOTLOADER_BOARD_NAME))
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ lib/edid_parser.c
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := libedid
+
+include $(BUILD_SHARED_LIBRARY)
+
+# ====================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ cmd/parse_hdmi_edid.c
+
+LOCAL_SHARED_LIBRARIES:= \
+ libutils \
+ libedid
+
+LOCAL_MODULE:= parse_hdmi_edid
+LOCAL_MODULE_TAGS:= optional
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/edid/cmd/parse_hdmi_edid.c b/edid/cmd/parse_hdmi_edid.c
new file mode 100644
index 0000000..9f84505
--- /dev/null
+++ b/edid/cmd/parse_hdmi_edid.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <fcntl.h>
+
+#define LOG_TAG "EDID"
+#include <utils/Log.h>
+
+#include <inc/edid_parser.h>
+
+static const char kHdmiEdidPathName[] = "/sys/devices/platform/omapdss/display1/edid";
+
+static void print_s3d_format_info(struct edid_t *edid, const struct hdmi_s3d_format_info_t *info)
+{
+ unsigned int i;
+ if(info == NULL) {
+ return;
+ }
+
+ switch(info->format) {
+ case HDMI_FRAME_PACKING:
+ fprintf(stdout, "--Frame Packing");
+ break;
+ case HDMI_FIELD_ALTERNATIVE:
+ fprintf(stdout, "--Filed Alternative");
+ break;
+ case HDMI_LINE_ALTERNATIVE:
+ fprintf(stdout, "--Line Alternative");
+ break;
+ case HDMI_SIDE_BY_SIDE_FULL:
+ fprintf(stdout, "--Side by Side FULL");
+ break;
+ case HDMI_L_DEPTH:
+ fprintf(stdout, "--L + Depth");
+ break;
+ case HDMI_L_DEPTH_GFX_GFX_DEPTH:
+ fprintf(stdout, "--L + Depth + Graphics + Graphics + Depth");
+ break;
+ case HDMI_TOPBOTTOM:
+ fprintf(stdout, "--Top Bottom");
+ break;
+ case HDMI_SIDE_BY_SIDE_HALF:
+ fprintf(stdout, "--Side by Side HALF");
+ break;
+ default:
+ fprintf(stdout, "--Unkown format");
+ break;
+ }
+ fprintf(stdout, "\n");
+
+ for (i = 0; i < info->num_valid_vic; i++) {
+ const struct svd_t * svd = edid_get_svd_descriptor(edid, info->vic_info[i].vic_pos);
+ fprintf(stdout, "----Mode:%s sub-sampling: ", svd->info.name);
+ switch(info->vic_info[i].subsampling) {
+ case HDMI_SS_HORZANDQUINCUNX:
+ fprintf(stdout, "Horizontal and Quincunx");
+ break;
+ case HDMI_SS_HORIZONTAL:
+ fprintf(stdout, "Horizontal");
+ break;
+ case HDMI_SS_QUINCUNX_ALL:
+ fprintf(stdout, "Quincunx");
+ break;
+ case HDMI_SS_QUINCUNX_OLOR:
+ fprintf(stdout, "Quincunx Odd-Left/Odd-Right");
+ break;
+ case HDMI_SS_QUINCUNX_OLER:
+ fprintf(stdout, "Quincunx Odd-Left/Even-Right");
+ break;
+ case HDMI_SS_QUINCUNX_ELOR:
+ fprintf(stdout, "Quincunx Even-Left/Odd-Right");
+ break;
+ case HDMI_SS_QUINCUNX_ELER:
+ fprintf(stdout, "Quincunx Even-Left/Even-Right");
+ break;
+ case HDMI_SS_VERTICAL:
+ fprintf(stdout, "Vertical");
+ break;
+ case HDMI_SS_NONE:
+ fprintf(stdout, "None");
+ break;
+ default:
+ break;
+ }
+ fprintf(stdout, "\n");
+ }
+
+}
+int main()
+{
+ unsigned int i;
+ struct svd_t *svd_list;
+ unsigned int num_svds;
+
+ int fd = open(kHdmiEdidPathName, O_RDONLY);
+
+ if (!fd) {
+ return 1;
+ }
+
+ uint8_t edid_data[EDID_SIZE];
+ size_t bytes_read = read(fd, edid_data, EDID_SIZE);
+ close(fd);
+
+ if (bytes_read < EDID_SIZE) {
+ fprintf(stderr, "Could not read EDID data\n");
+ return 1;
+ }
+
+ struct edid_t *edid = NULL;
+ if(edid_parser_init(&edid, edid_data)) {
+ fprintf(stderr, "Could not init parser\n");
+ return 1;
+ }
+
+ edid_get_svd_list(edid, &svd_list, &num_svds);
+
+ fprintf(stdout, "EDID Info\n");
+ fprintf(stdout, "[Short Video Descriptors]\n");
+ for (i = 0; i < num_svds; i++) {
+ fprintf(stdout, "----%d: %s [code:%d, native:%d] [xres:%d, yres:%d Hz:%d]\n",
+ i, svd_list[i].info.name, svd_list[i].code, svd_list[i].native,
+ svd_list[i].info.xres, svd_list[i].info.yres, svd_list[i].info.hz);
+ }
+
+ fprintf(stdout, "\n[S3D Optional Formats]\n");
+ print_s3d_format_info(edid, edid_get_s3d_format_info(edid, HDMI_FRAME_PACKING));
+ print_s3d_format_info(edid, edid_get_s3d_format_info(edid, HDMI_FIELD_ALTERNATIVE));
+ print_s3d_format_info(edid, edid_get_s3d_format_info(edid, HDMI_LINE_ALTERNATIVE));
+ print_s3d_format_info(edid, edid_get_s3d_format_info(edid, HDMI_SIDE_BY_SIDE_FULL));
+ print_s3d_format_info(edid, edid_get_s3d_format_info(edid, HDMI_L_DEPTH));
+ print_s3d_format_info(edid, edid_get_s3d_format_info(edid, HDMI_L_DEPTH_GFX_GFX_DEPTH));
+ print_s3d_format_info(edid, edid_get_s3d_format_info(edid, HDMI_TOPBOTTOM));
+ print_s3d_format_info(edid, edid_get_s3d_format_info(edid, HDMI_SIDE_BY_SIDE_HALF));
+
+ edid_parser_deinit(edid);
+
+ return 0;
+}
diff --git a/edid/inc/edid_parser.h b/edid/inc/edid_parser.h
new file mode 100644
index 0000000..9dba5f4
--- /dev/null
+++ b/edid/inc/edid_parser.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _EDID_PARSER_
+#define _EDID_PARSER_
+
+#define EDID_SIZE 256
+#define MAX_VIC_CODES_PER_3D_FORMAT 16
+
+struct edid_t;
+
+enum datablock_id {
+ DATABLOCK_AUDIO = 1,
+ DATABLOCK_VIDEO = 2,
+ DATABLOCK_VENDOR = 3,
+ DATABLOCK_SPEAKERS = 4,
+};
+
+enum hdmi_3d_format {
+ HDMI_FRAME_PACKING = 0,
+ HDMI_FIELD_ALTERNATIVE = 1,
+ HDMI_LINE_ALTERNATIVE = 2,
+ HDMI_SIDE_BY_SIDE_FULL = 3,
+ HDMI_L_DEPTH = 4,
+ HDMI_L_DEPTH_GFX_GFX_DEPTH = 5,
+ HDMI_TOPBOTTOM = 6,
+ HDMI_SIDE_BY_SIDE_HALF = 8,
+};
+
+enum hdmi_3d_format_bits {
+ HDMI_FRAME_PACKING_BIT = 1 << HDMI_FRAME_PACKING,
+ HDMI_FIELD_ALTERNATIVE_BIT = 1 << HDMI_FIELD_ALTERNATIVE,
+ HDMI_LINE_ALTERNATIVE_BIT = 1 << HDMI_LINE_ALTERNATIVE,
+ HDMI_SIDE_BY_SIDE_FULL_BIT = 1 << HDMI_SIDE_BY_SIDE_FULL,
+ HDMI_L_DEPTH_BIT = 1 << HDMI_L_DEPTH ,
+ HDMI_L_DEPTH_GFX_GFX_DEPTH_BIT = 1 << HDMI_L_DEPTH_GFX_GFX_DEPTH,
+ HDMI_TOPBOTTOM_BIT = 1 << HDMI_TOPBOTTOM,
+ HDMI_SIDE_BY_SIDE_HALF_BIT = 1 << HDMI_SIDE_BY_SIDE_HALF,
+ HDMI_SIDE_BY_SIDE_HALF_QUINCUNX_BIT = 1 << 15,
+};
+
+//ALL = both horizontal and quincunx modes are supported
+//HDMI_SS_QUINCUNX_ALL = all quincunx subsampling modes are supported
+//OL = Odd left viewHorizontal sub
+//OR = Odd right view
+//ER = Even left view
+//EL = Even right view
+enum hdmi_3d_subsampling {
+ HDMI_SS_HORZANDQUINCUNX = 0,
+ HDMI_SS_HORIZONTAL = 1,
+ HDMI_SS_QUINCUNX_ALL = 6,
+ HDMI_SS_QUINCUNX_OLOR = 7,
+ HDMI_SS_QUINCUNX_OLER = 8,
+ HDMI_SS_QUINCUNX_ELOR = 9,
+ HDMI_SS_QUINCUNX_ELER = 10,
+ HDMI_SS_VERTICAL = 0xF0000,
+ HDMI_SS_NONE = 0xF0001,
+};
+
+enum hdmi_scan_type {
+ HDMI_SCAN_PROGRESSIVE,
+ HDMI_SCAN_INTERLACED,
+};
+
+struct svd_info_t {
+ uint32_t xres;
+ uint32_t yres;
+ uint32_t hz;
+ enum hdmi_scan_type scan_type;
+ char name[9];
+};
+
+struct svd_t {
+ uint8_t code;
+ bool native;
+ struct svd_info_t info;
+};
+
+struct hdmi_s3d_format_vic_info_t {
+ uint8_t vic_pos;
+ enum hdmi_3d_subsampling subsampling;
+};
+
+struct hdmi_s3d_format_info_t {
+ enum hdmi_3d_format format;
+ unsigned int num_valid_vic;
+ struct hdmi_s3d_format_vic_info_t vic_info[MAX_VIC_CODES_PER_3D_FORMAT];
+};
+
+int edid_parser_init(struct edid_t **edid, const uint8_t *raw_edid_data);
+void edid_parser_deinit(struct edid_t *edid);
+
+bool edid_s3d_capable(struct edid_t *edid);
+bool edid_supports_s3d_format(struct edid_t *edid, enum hdmi_3d_format format);
+const struct hdmi_s3d_format_info_t * edid_get_s3d_format_info(struct edid_t *edid, enum hdmi_3d_format format);
+
+void edid_get_svd_list(struct edid_t *edid, struct svd_t **list, unsigned int *num_elements);
+const struct svd_t *edid_get_svd_descriptor(struct edid_t *edid, uint8_t vic_pos);
+
+#endif //_EDID_PARSER_ \ No newline at end of file
diff --git a/edid/lib/edid_parser.c b/edid/lib/edid_parser.c
new file mode 100644
index 0000000..e08822c
--- /dev/null
+++ b/edid/lib/edid_parser.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <inc/edid_parser.h>
+#include "edid_parser_priv.h"
+
+const struct svd_info_t svd_table[] =
+{
+ {0, 0, 0, HDMI_SCAN_PROGRESSIVE, "reserved"},
+ {640, 480, 60, HDMI_SCAN_PROGRESSIVE, "DMT0659"},
+ {720, 480, 60, HDMI_SCAN_PROGRESSIVE, "480p"},
+ {720, 480, 60, HDMI_SCAN_PROGRESSIVE, "480pH"},
+ {1280, 720, 60, HDMI_SCAN_PROGRESSIVE, "720p"},
+ {1920, 1080, 60, HDMI_SCAN_INTERLACED, "1080i"},
+ {720, 480, 60, HDMI_SCAN_INTERLACED, "480i"},
+ {720, 480, 60, HDMI_SCAN_INTERLACED, "480iH"},
+ {720, 240, 60, HDMI_SCAN_PROGRESSIVE, "240p"},
+ {1280, 720, 60, HDMI_SCAN_PROGRESSIVE, "240pH"},
+ {720, 480, 60, HDMI_SCAN_INTERLACED, "480i4x"},
+ {720, 480, 60, HDMI_SCAN_INTERLACED, "480i4xH"},
+ {720, 240, 60, HDMI_SCAN_PROGRESSIVE, "240p4x"},
+ {720, 240, 60, HDMI_SCAN_PROGRESSIVE, "240p4xH"},
+ {720, 480, 60, HDMI_SCAN_PROGRESSIVE, "480p2x"},
+ {720, 480, 60, HDMI_SCAN_PROGRESSIVE, "480p2xH"},
+ {1920, 1080, 60, HDMI_SCAN_PROGRESSIVE, "1080p"},
+ {720, 576, 50, HDMI_SCAN_PROGRESSIVE, "576p"},
+ {720, 576, 50, HDMI_SCAN_PROGRESSIVE, "576pH"},
+ {1280, 720, 50, HDMI_SCAN_PROGRESSIVE, "720p50"},
+ {1920, 1080, 50, HDMI_SCAN_INTERLACED, "1080i25"},
+ {720, 576, 50, HDMI_SCAN_INTERLACED, "576i"},
+ {720, 576, 50, HDMI_SCAN_INTERLACED, "576iH"},
+ {720, 288, 50, HDMI_SCAN_PROGRESSIVE, "288p"},
+ {720, 288, 50, HDMI_SCAN_PROGRESSIVE, "288pH"},
+ {720, 576, 50, HDMI_SCAN_INTERLACED, "576i4x"},
+ {720, 576, 50, HDMI_SCAN_INTERLACED, "576i4xH"},
+ {720, 288, 50, HDMI_SCAN_PROGRESSIVE, "288p4x"},
+ {720, 288, 50, HDMI_SCAN_PROGRESSIVE, "288p4xH"},
+ {720, 576, 50, HDMI_SCAN_PROGRESSIVE, "576p2x"},
+ {720, 576, 50, HDMI_SCAN_PROGRESSIVE, "576p2xH"},
+ {1920, 1080, 50, HDMI_SCAN_PROGRESSIVE, "1080p50"},
+ {1920, 1080, 24, HDMI_SCAN_PROGRESSIVE, "1080p24"},
+ {1920, 1080, 25, HDMI_SCAN_PROGRESSIVE, "1080p25"},
+ {1920, 1080, 30, HDMI_SCAN_PROGRESSIVE, "1080p30"},
+ {720, 480, 60, HDMI_SCAN_PROGRESSIVE, "480p4x"},
+ {720, 480, 60, HDMI_SCAN_PROGRESSIVE, "480p4xH"},
+ {720, 576, 50, HDMI_SCAN_PROGRESSIVE, "576p4x"},
+ {720, 576, 50, HDMI_SCAN_PROGRESSIVE, "576p4xH"},
+ {1920, 1080, 50, HDMI_SCAN_INTERLACED, "1080i25"},
+ {1920, 1080, 100, HDMI_SCAN_INTERLACED, "1080i50"},
+ {1280, 720, 100, HDMI_SCAN_PROGRESSIVE, "720p100"},
+ {720, 576, 100, HDMI_SCAN_PROGRESSIVE, "576p100"},
+ {720, 576, 100, HDMI_SCAN_PROGRESSIVE, "576p100H"},
+ {720, 576, 100, HDMI_SCAN_INTERLACED, "576i50"},
+ {720, 576, 100, HDMI_SCAN_INTERLACED, "576i50H"},
+ {1920, 1080, 120, HDMI_SCAN_INTERLACED, "1080i60"},
+ {1280, 720, 120, HDMI_SCAN_PROGRESSIVE, "720p120"},
+ {720, 480, 120, HDMI_SCAN_PROGRESSIVE, "480p120"},
+ {720, 480, 120, HDMI_SCAN_PROGRESSIVE, "480p120H"},
+ {720, 480, 120, HDMI_SCAN_INTERLACED, "480i60"},
+ {720, 480, 120, HDMI_SCAN_INTERLACED, "480i60H"},
+ {720, 576, 200, HDMI_SCAN_PROGRESSIVE, "576p200"},
+ {720, 576, 200, HDMI_SCAN_PROGRESSIVE, "576p200H"},
+ {720, 576, 200, HDMI_SCAN_INTERLACED, "576i100"},
+ {720, 576, 200, HDMI_SCAN_INTERLACED, "576i100H"},
+ {720, 480, 240, HDMI_SCAN_PROGRESSIVE, "480p240"},
+ {720, 480, 240, HDMI_SCAN_PROGRESSIVE, "480p240H"},
+ {720, 480, 240, HDMI_SCAN_INTERLACED, "480i120"},
+ {720, 480, 240, HDMI_SCAN_INTERLACED, "480i120H"},
+ {1280, 720, 24, HDMI_SCAN_PROGRESSIVE, "720p24"},
+ {1280, 720, 25, HDMI_SCAN_PROGRESSIVE, "720p25"},
+ {1280, 720, 30, HDMI_SCAN_PROGRESSIVE, "720p30"},
+ {1920, 1080, 120, HDMI_SCAN_PROGRESSIVE, "1080p120"}
+};
+
+const int NUM_SVD_ENTRIES = sizeof(svd_table)/sizeof(svd_table[0]);
+
+static unsigned int count_set_bits(uint16_t value)
+{
+ unsigned int count;
+ for (count = 0; value; count++)
+ value &= value - 1;
+ return count;
+}
+
+static void set_s3d_format_bits(const uint8_t *edid_data, int off, int hdmi_3d_len, uint16_t *s3d_struct_bits)
+{
+ //These are 3D formats signaled through 2D VIC order and 3D_structure-3D_Detail
+ while (hdmi_3d_len > 0) {
+ unsigned int val = edid_data[off++] & 0x0F;
+ *s3d_struct_bits |= 1 << val;
+ //3D Detail_x is included for 3D_Structure_x range 0x8-0xF
+ if ( val >= HDMI_SIDE_BY_SIDE_HALF) {
+ hdmi_3d_len--;
+ off++;
+ }
+ hdmi_3d_len--;
+ }
+}
+
+static void update_s3d_format(struct edid_t *edid, enum hdmi_3d_format format,
+ uint8_t vic_pos, enum hdmi_3d_subsampling subsamp)
+{
+ unsigned int format_ix, vic_pos_ix;
+ if (vic_pos > edid->num_svds) {
+ return;
+ }
+
+ for (format_ix = 0; format_ix < edid->num_s3d_formats; format_ix++) {
+ if (edid->s3d_format_list[format_ix].format == format) {
+ break;
+ }
+ }
+
+ if (format_ix >= edid->num_s3d_formats) {
+ return;
+ }
+
+ //In case this has already been signaled, we'll update the subsampling mode
+ for (vic_pos_ix = 0; vic_pos_ix < edid->s3d_format_list[format_ix].num_valid_vic; vic_pos_ix++) {
+ if (edid->s3d_format_list[format_ix].vic_info[vic_pos_ix].vic_pos == vic_pos) {
+ break;
+ }
+ }
+
+ if (vic_pos_ix >= edid->s3d_format_list[format_ix].num_valid_vic) {
+ vic_pos_ix = edid->s3d_format_list[format_ix].num_valid_vic;
+ edid->s3d_format_list[format_ix].num_valid_vic += 1;
+ }
+
+ edid->s3d_format_list[format_ix].vic_info[vic_pos_ix].vic_pos = vic_pos;
+ edid->s3d_format_list[format_ix].vic_info[vic_pos_ix].subsampling = subsamp;
+}
+
+/* This function was originally written by Mythri pk */
+static int edid_get_datablock_offset(const uint8_t *edid_data, enum datablock_id type, unsigned int *off)
+{
+ uint8_t val;
+ uint8_t ext_length;
+ uint8_t offset;
+
+ //CEA extension signaled? If not, then no datablocks are contained
+ if (edid_data[0x7e] == 0x00) {
+ return 1;
+ }
+
+ //18-byte descriptors only? Otherwise, there are datablocks present
+ ext_length = edid_data[0x82];
+ if (ext_length == 0x4) {
+ return 1;
+ }
+
+ //Start of first extended data block
+ offset = 0x84;
+ while (offset < (0x80 + ext_length)) {
+ val = edid_data[offset];
+ //Upper 3 bits indicate block type
+ if ((val >> 5) == type) {
+ *off = offset;
+ return 0;
+ } else {
+ //lower 5 bits indicate block length
+ offset += (val & 0x1F) + 1;
+ }
+ }
+ return 1;
+}
+
+static void edid_parse_s3d_support(struct edid_t *edid, const uint8_t *edid_data)
+{
+ unsigned int off;
+ unsigned int i, count;
+ uint8_t val;
+ uint8_t s3d_multi_present;
+ uint8_t hdmi_3d_len;
+ uint16_t s3d_struct_all = 0;
+ uint16_t s3d_struct_bits = 0;
+ uint16_t hdmi_vic_pos_bits = 0;
+
+ //memset(edid->s3d_formats, 0, sizeof(edid->s3d_formats));
+
+ //S3D HDMI information is signaled in the Vendor Specific datablock
+ if(edid_get_datablock_offset(edid_data, DATABLOCK_VENDOR, &off))
+ return;
+
+ //Skip header and other non-S3D related fields
+ off += 8;
+ val = edid_data[off++];
+
+ //HDMI_Video_present?
+ if (!(val & 0x20)) {
+ return;
+ }
+
+ //Latency_Fields_Present? Skip
+ if (val & 0x80) {
+ off += 2;
+ }
+
+ //I_Latency_Fields_Present? Skip
+ if (val & 0x40) {
+ off += 2;
+ }
+
+ val = edid_data[off++];
+ //3D_Present?
+ if (!(val & 0x80)) {
+ return;
+ }
+
+ edid->s3d_capable = true;
+
+ s3d_multi_present = (val & 0x60) >> 5;
+
+ //Skip HDMI_XX_LEN
+ val = edid_data[off++];
+ off += (val & 0xE0) >> 5;
+ hdmi_3d_len = (val & 0x1F);
+
+ //3D capabilities signaled through bitmasks
+ //s3d_struct_all has all the 3D formats supported (per bit)
+ //hdmi_vic_mask has which of the corresponding VIC codes the 3D formats apply to
+ //if s3d_multi_present = 1, then the 3D formats apply to all the first 16 VIC codes
+ if (s3d_multi_present == 1 || s3d_multi_present == 2) {
+ s3d_struct_all = (edid_data[off] << 8) | edid_data[off+1];
+ hdmi_vic_pos_bits = 0xFFFF;
+ hdmi_3d_len -= 2;
+ off += 2;
+ }
+
+ if (s3d_multi_present == 2) {
+ hdmi_vic_pos_bits = (edid_data[off] << 8) | edid_data[off+1];
+ hdmi_3d_len -= 2;
+ off += 2;
+ }
+
+ //Bit 15 signals same format as Bit 8 - HDMI_SIDE_BY_SIDE_HALF, they only differ in subsampling options
+ s3d_struct_bits = s3d_struct_all & 0x7FFF;
+ set_s3d_format_bits(edid_data, off, hdmi_3d_len, &s3d_struct_bits);
+
+ edid->num_s3d_formats = count_set_bits(s3d_struct_bits);
+ edid->s3d_format_list = (struct hdmi_s3d_format_info_t *) malloc(edid->num_s3d_formats * sizeof(struct hdmi_s3d_format_info_t));
+
+ count = 0;
+ for (i = 0; i <= HDMI_SIDE_BY_SIDE_HALF; i++) {
+ if (s3d_struct_bits & (1 << i)) {
+ edid->s3d_format_list[count++].format = (enum hdmi_3d_format)i;
+ }
+ }
+
+ for (i = 0; i < edid->num_s3d_formats; i++) {
+ unsigned int j;
+ enum hdmi_3d_subsampling subsampling;
+ if (edid->s3d_format_list[i].format == HDMI_SIDE_BY_SIDE_HALF) {
+ uint16_t bitmask = HDMI_SIDE_BY_SIDE_HALF_QUINCUNX_BIT | HDMI_SIDE_BY_SIDE_HALF_BIT;
+ if ( (s3d_struct_all & bitmask) == bitmask) {
+ subsampling = HDMI_SS_HORZANDQUINCUNX;
+ } else if ((s3d_struct_all & bitmask) == HDMI_SIDE_BY_SIDE_HALF_QUINCUNX_BIT) {
+ subsampling = HDMI_SS_QUINCUNX_ALL;
+ } else if ((s3d_struct_all & bitmask) == HDMI_SIDE_BY_SIDE_HALF_BIT) {
+ subsampling = HDMI_SS_HORIZONTAL;
+ }
+ } else if (edid->s3d_format_list[i].format == HDMI_TOPBOTTOM) {
+ subsampling = HDMI_SS_VERTICAL;
+ } else {
+ subsampling = HDMI_SS_NONE;
+ }
+ count = 0;
+ for (j = 0; j < 16; j++) {
+ if ((s3d_struct_all & (1 << edid->s3d_format_list[i].format)) &&
+ (hdmi_vic_pos_bits & (1 << j))) {
+ edid->s3d_format_list[i].vic_info[count].subsampling = subsampling;
+ edid->s3d_format_list[i].vic_info[count++].vic_pos = j;
+ }
+ }
+ edid->s3d_format_list[i].num_valid_vic = count;
+ }
+
+ //In this case, the 3D formats signaled only apply to the VIC codes signaled per bit
+ //i.e. bit0 = VIC code 0 from the Short video descriptors list
+ while (hdmi_3d_len > 0) {
+ //Upper 4 bits indicate vic position, lower 4 bits are the 3D structure value
+ enum hdmi_3d_subsampling subsampling = HDMI_SS_NONE;
+ uint8_t vic_pos = (edid_data[off] & 0xF0) >> 4;
+ enum hdmi_3d_format format = (enum hdmi_3d_format) (edid_data[off++] & 0x0F);
+ if (format >= HDMI_SIDE_BY_SIDE_HALF) {
+ subsampling = (enum hdmi_3d_subsampling)((edid_data[off++] & 0xF0) >> 4);
+ hdmi_3d_len--;
+ }
+ if (format == HDMI_TOPBOTTOM) {
+ subsampling = HDMI_SS_VERTICAL;
+ }
+ update_s3d_format(edid, format, vic_pos, subsampling);
+ hdmi_3d_len--;
+ }
+}
+
+static void edid_fill_svd_info(uint8_t code, struct svd_info_t *info)
+{
+ if(code > NUM_SVD_ENTRIES)
+ code = 0;
+ memcpy(info, &svd_table[code], sizeof(struct svd_info_t));
+}
+
+static void edid_parse_svds(struct edid_t *edid, const uint8_t *raw_edid_data)
+{
+ unsigned int offset;
+ unsigned int i;
+ if (edid_get_datablock_offset(raw_edid_data, DATABLOCK_VIDEO, &offset)) {
+ edid->num_svds = 0;
+ edid->svd_list = NULL;
+ return ;
+ }
+
+ edid->num_svds = raw_edid_data[offset] & 0x1F;
+ edid->svd_list = (struct svd_t *) malloc(edid->num_svds * sizeof(struct svd_t));
+ for (i = 0; i < edid->num_svds; i++) {
+ struct svd_t *svd = &edid->svd_list[i];
+ svd->code = raw_edid_data[offset + i] & 0x7F;
+ svd->native = (raw_edid_data[offset + i] & 0x80) == 0x80;
+ edid_fill_svd_info(svd->code, &svd->info);
+ }
+}
+
+/*=======================================================*/
+int edid_parser_init(struct edid_t **edid_handle, const uint8_t *raw_edid_data)
+{
+ if(edid_handle == NULL) {
+ return -1;
+ }
+
+ struct edid_t *edid = (struct edid_t *) malloc(sizeof(struct edid_t));
+ if (edid == NULL) {
+ return -1;
+ }
+
+ memset(edid, 0, sizeof(struct edid_t));
+ edid_parse_svds(edid, raw_edid_data);
+ edid_parse_s3d_support(edid, raw_edid_data);
+
+ *edid_handle = edid;
+ return 0;
+}
+
+void edid_parser_deinit(struct edid_t *edid)
+{
+ free(edid->s3d_format_list);
+ free(edid->svd_list);
+ free(edid);
+}
+
+bool edid_s3d_capable(struct edid_t *edid)
+{
+ return edid->s3d_capable;
+}
+
+bool edid_supports_s3d_format(struct edid_t *edid, enum hdmi_3d_format format)
+{
+ unsigned int i;
+ for (i = 0; i < edid->num_s3d_formats; i++) {
+ if (edid->s3d_format_list[i].format == format) {
+ return true;
+ }
+ }
+ return false;
+}
+
+const struct hdmi_s3d_format_info_t * edid_get_s3d_format_info(struct edid_t *edid, enum hdmi_3d_format format)
+{
+ unsigned int i;
+ for (i = 0; i < edid->num_s3d_formats; i++) {
+ if (edid->s3d_format_list[i].format == format) {
+ return &edid->s3d_format_list[i];
+ }
+ }
+ return NULL;
+}
+
+void edid_get_svd_list(struct edid_t *edid, struct svd_t **list, unsigned int *num_elements)
+{
+ if(list == NULL || num_elements == NULL)
+ return;
+
+ *list = edid->svd_list;
+ *num_elements = edid->num_svds;
+}
+
+const struct svd_t *edid_get_svd_descriptor(struct edid_t *edid, uint8_t vic_pos)
+{
+ if(vic_pos > edid->num_svds)
+ return NULL;
+ return &edid->svd_list[vic_pos];
+}
diff --git a/edid/lib/edid_parser_priv.h b/edid/lib/edid_parser_priv.h
new file mode 100644
index 0000000..69ba513
--- /dev/null
+++ b/edid/lib/edid_parser_priv.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Texas Instruments - http://www.ti.com/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+struct hdmi_s3d_format_t {
+ bool supported;
+ struct hdmi_s3d_format_info_t f;
+};
+
+struct edid_t {
+ bool s3d_capable;
+
+ unsigned int num_s3d_formats;
+ struct hdmi_s3d_format_info_t *s3d_format_list;
+
+ unsigned int num_svds;
+ struct svd_t *svd_list;
+};