From 222b794ae146b4e0d61958c55a518396e293e6d7 Mon Sep 17 00:00:00 2001 From: codeworkx Date: Mon, 11 Feb 2013 17:29:55 +0000 Subject: initial commit sources from http://omapzoom.org --- edid/Android.mk | 45 +++++ edid/cmd/parse_hdmi_edid.c | 154 +++++++++++++++++ edid/inc/edid_parser.h | 113 ++++++++++++ edid/lib/edid_parser.c | 410 ++++++++++++++++++++++++++++++++++++++++++++ edid/lib/edid_parser_priv.h | 31 ++++ 5 files changed, 753 insertions(+) create mode 100644 edid/Android.mk create mode 100644 edid/cmd/parse_hdmi_edid.c create mode 100644 edid/inc/edid_parser.h create mode 100644 edid/lib/edid_parser.c create mode 100644 edid/lib/edid_parser_priv.h (limited to 'edid') 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 +#include +#include + +#define LOG_TAG "EDID" +#include + +#include + +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 +#include +#include + +#include +#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; +}; -- cgit v1.1