/******************************************************************************* * * Copyright (C) 2015 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * *******************************************************************************/ /******************************************************************************/ /** * * @file xvidc_edid.c * * Contains function definitions related to the Extended Display Identification * Data (EDID) structure which is present in all monitors. All content in this * file is agnostic of communication interface protocol. * * @note None. * * <pre> * MODIFICATION HISTORY: * * Ver Who Date Changes * ----- ---- -------- ----------------------------------------------- * 1.0 als 11/09/14 Initial release. * </pre> * *******************************************************************************/ /******************************* Include Files ********************************/ #include "xvidc_edid.h" /**************************** Function Prototypes *****************************/ static u32 XVidC_EdidIsVideoTimingSupportedPreferredTiming(u8 *EdidRaw, XVidC_VideoTimingMode *VtMode); static u32 XVidC_EdidIsVideoTimingSupportedEstablishedTimings(u8 *EdidRaw, XVidC_VideoTimingMode *VtMode); static u32 XVidC_EdidIsVideoTimingSupportedStandardTimings(u8 *EdidRaw, XVidC_VideoTimingMode *VtMode); static float XVidC_CalculatePower(float Base, u8 Power); static float XVidC_CalculateBinaryFraction(u16 Val, u8 DecPtIndex); /**************************** Function Definitions ****************************/ void XVidC_EdidGetVpiIdManName(u8 *EdidRaw, char ManName[4]) { ManName[0] = 0x40 + ((EdidRaw[XVIDC_EDID_VPI_ID_MAN_NAME0] & XVIDC_EDID_VPI_ID_MAN_NAME0_CHAR0_MASK) >> XVIDC_EDID_VPI_ID_MAN_NAME0_CHAR0_SHIFT); ManName[1] = 0x40 + (((EdidRaw[XVIDC_EDID_VPI_ID_MAN_NAME0] & XVIDC_EDID_VPI_ID_MAN_NAME0_CHAR1_MASK) << XVIDC_EDID_VPI_ID_MAN_NAME0_CHAR1_POS) | (EdidRaw[XVIDC_EDID_VPI_ID_MAN_NAME1] >> XVIDC_EDID_VPI_ID_MAN_NAME1_CHAR1_SHIFT)); ManName[2] = 0x40 + (EdidRaw[XVIDC_EDID_VPI_ID_MAN_NAME1] & XVIDC_EDID_VPI_ID_MAN_NAME1_CHAR2_MASK); ManName[3] = '\0'; } u8 XVidC_EdidGetBDispVidDigBpc(u8 *EdidRaw) { u8 Bpc; switch (((EdidRaw[XVIDC_EDID_BDISP_VID] & XVIDC_EDID_BDISP_VID_DIG_BPC_MASK) >> XVIDC_EDID_BDISP_VID_DIG_BPC_SHIFT)) { case XVIDC_EDID_BDISP_VID_DIG_BPC_6: Bpc = 6; break; case XVIDC_EDID_BDISP_VID_DIG_BPC_8: Bpc = 8; break; case XVIDC_EDID_BDISP_VID_DIG_BPC_10: Bpc = 10; break; case XVIDC_EDID_BDISP_VID_DIG_BPC_12: Bpc = 12; break; case XVIDC_EDID_BDISP_VID_DIG_BPC_14: Bpc = 14; break; case XVIDC_EDID_BDISP_VID_DIG_BPC_16: Bpc = 16; break; default: Bpc = XVIDC_EDID_BDISP_VID_DIG_BPC_UNDEF; break; } return Bpc; } float XVidC_EdidGetCcRedX(u8 *EdidRaw) { return XVidC_CalculateBinaryFraction( (EdidRaw[XVIDC_EDID_CC_REDX_HIGH] << XVIDC_EDID_CC_HIGH_SHIFT) | (EdidRaw[XVIDC_EDID_CC_RG_LOW] >> XVIDC_EDID_CC_RBX_LOW_SHIFT), 9); } float XVidC_EdidGetCcRedY(u8 *EdidRaw) { return XVidC_CalculateBinaryFraction( (EdidRaw[XVIDC_EDID_CC_REDY_HIGH] << XVIDC_EDID_CC_HIGH_SHIFT) | ((EdidRaw[XVIDC_EDID_CC_RG_LOW] & XVIDC_EDID_CC_RBY_LOW_MASK) >> XVIDC_EDID_CC_RBY_LOW_SHIFT), 9); } float XVidC_EdidGetCcGreenX(u8 *EdidRaw) { return XVidC_CalculateBinaryFraction( (EdidRaw[XVIDC_EDID_CC_GREENX_HIGH] << XVIDC_EDID_CC_HIGH_SHIFT) | ((EdidRaw[XVIDC_EDID_CC_RG_LOW] & XVIDC_EDID_CC_GWX_LOW_MASK) >> XVIDC_EDID_CC_GWX_LOW_SHIFT), 9); } float XVidC_EdidGetCcGreenY(u8 *EdidRaw) { return XVidC_CalculateBinaryFraction( (EdidRaw[XVIDC_EDID_CC_GREENY_HIGH] << XVIDC_EDID_CC_HIGH_SHIFT) | (EdidRaw[XVIDC_EDID_CC_RG_LOW] & XVIDC_EDID_CC_GWY_LOW_MASK), 9); } float XVidC_EdidGetCcBlueX(u8 *EdidRaw) { return XVidC_CalculateBinaryFraction( (EdidRaw[XVIDC_EDID_CC_BLUEX_HIGH] << XVIDC_EDID_CC_HIGH_SHIFT) | (EdidRaw[XVIDC_EDID_CC_BW_LOW] >> XVIDC_EDID_CC_RBX_LOW_SHIFT), 9); } float XVidC_EdidGetCcBlueY(u8 *EdidRaw) { return XVidC_CalculateBinaryFraction( (EdidRaw[XVIDC_EDID_CC_BLUEY_HIGH] << XVIDC_EDID_CC_HIGH_SHIFT) | ((EdidRaw[XVIDC_EDID_CC_BW_LOW] & XVIDC_EDID_CC_RBY_LOW_MASK) >> XVIDC_EDID_CC_RBY_LOW_SHIFT), 9); } float XVidC_EdidGetCcWhiteX(u8 *EdidRaw) { return XVidC_CalculateBinaryFraction( (EdidRaw[XVIDC_EDID_CC_WHITEX_HIGH] << XVIDC_EDID_CC_HIGH_SHIFT) | ((EdidRaw[XVIDC_EDID_CC_BW_LOW] & XVIDC_EDID_CC_GWX_LOW_MASK) >> XVIDC_EDID_CC_GWX_LOW_SHIFT), 9); } float XVidC_EdidGetCcWhiteY(u8 *EdidRaw) { return XVidC_CalculateBinaryFraction( (EdidRaw[XVIDC_EDID_CC_WHITEY_HIGH] << XVIDC_EDID_CC_HIGH_SHIFT) | (EdidRaw[XVIDC_EDID_CC_BW_LOW] & XVIDC_EDID_CC_GWY_LOW_MASK), 9); } u16 XVidC_EdidGetStdTimingsV(u8 *EdidRaw, u8 StdTimingsNum) { u16 V; switch (XVidC_EdidGetStdTimingsAr(EdidRaw, StdTimingsNum)) { case XVIDC_EDID_STD_TIMINGS_AR_16_10: V = (10 * XVidC_EdidGetStdTimingsH(EdidRaw, StdTimingsNum)) / 16; break; case XVIDC_EDID_STD_TIMINGS_AR_4_3: V = (3 * XVidC_EdidGetStdTimingsH(EdidRaw, StdTimingsNum)) / 4; break; case XVIDC_EDID_STD_TIMINGS_AR_5_4: V = (4 * XVidC_EdidGetStdTimingsH(EdidRaw, StdTimingsNum)) / 5; break; default: V = (9 * XVidC_EdidGetStdTimingsH(EdidRaw, StdTimingsNum)) / 16; break; } return V; } u32 XVidC_EdidIsVideoTimingSupported(u8 *EdidRaw, XVidC_VideoTimingMode *VtMode) { u32 Status; /* Check if the video mode is the preferred timing. */ Status = XVidC_EdidIsVideoTimingSupportedPreferredTiming(EdidRaw, VtMode); if (Status == XST_SUCCESS) { return Status; } /* Check established timings I, II, and III. */ Status = XVidC_EdidIsVideoTimingSupportedEstablishedTimings(EdidRaw, VtMode); if (Status == XST_SUCCESS) { return Status; } /* Check in standard timings support. */ Status = XVidC_EdidIsVideoTimingSupportedStandardTimings(EdidRaw, VtMode); return Status; } static u32 XVidC_EdidIsVideoTimingSupportedPreferredTiming(u8 *EdidRaw, XVidC_VideoTimingMode *VtMode) { u8 *Ptm; Ptm = &EdidRaw[XVIDC_EDID_PTM]; u32 HActive = (((Ptm[XVIDC_EDID_DTD_PTM_HRES_HBLANK_U4] & XVIDC_EDID_DTD_PTM_XRES_XBLANK_U4_XRES_MASK) >> XVIDC_EDID_DTD_PTM_XRES_XBLANK_U4_XRES_SHIFT) << 8) | Ptm[XVIDC_EDID_DTD_PTM_HRES_LSB]; u32 VActive = (((Ptm[XVIDC_EDID_DTD_PTM_VRES_VBLANK_U4] & XVIDC_EDID_DTD_PTM_XRES_XBLANK_U4_XRES_MASK) >> XVIDC_EDID_DTD_PTM_XRES_XBLANK_U4_XRES_SHIFT) << 8) | Ptm[XVIDC_EDID_DTD_PTM_VRES_LSB]; if (VtMode->Timing.F1VTotal != XVidC_EdidIsDtdPtmInterlaced(EdidRaw)) { return (XST_FAILURE); } else if ((VtMode->Timing.HActive == HActive) && (VtMode->Timing.VActive == VActive)) { return (XST_SUCCESS); } return XST_FAILURE; } static u32 XVidC_EdidIsVideoTimingSupportedEstablishedTimings(u8 *EdidRaw, XVidC_VideoTimingMode *VtMode) { u32 Status = XST_FAILURE; /* First, check established timings I, II, and III. */ if ((VtMode->Timing.HActive == 800) && (VtMode->Timing.VActive == 640) && (VtMode->FrameRate == XVIDC_FR_56HZ) && XVidC_EdidSuppEstTimings800x600_56(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 640) && (VtMode->Timing.VActive == 480) && (VtMode->FrameRate == XVIDC_FR_60HZ) && XVidC_EdidSuppEstTimings640x480_60(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 800) && (VtMode->Timing.VActive == 600) && (VtMode->FrameRate == XVIDC_FR_60HZ) && XVidC_EdidSuppEstTimings800x600_60(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 1024) && (VtMode->Timing.VActive == 768) && (VtMode->FrameRate == XVIDC_FR_60HZ) && XVidC_EdidSuppEstTimings1024x768_60(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 640) && (VtMode->Timing.VActive == 480) && (VtMode->FrameRate == XVIDC_FR_67HZ) && XVidC_EdidSuppEstTimings640x480_67(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 720) && (VtMode->Timing.VActive == 400) && (VtMode->FrameRate == XVIDC_FR_70HZ) && XVidC_EdidSuppEstTimings720x400_70(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 1024) && (VtMode->Timing.VActive == 768) && (VtMode->FrameRate == XVIDC_FR_70HZ) && XVidC_EdidSuppEstTimings1024x768_70(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 640) && (VtMode->Timing.VActive == 480) && (VtMode->FrameRate == XVIDC_FR_72HZ) && XVidC_EdidSuppEstTimings640x480_72(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 800) && (VtMode->Timing.VActive == 600) && (VtMode->FrameRate == XVIDC_FR_72HZ) && XVidC_EdidSuppEstTimings800x600_72(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 640) && (VtMode->Timing.VActive == 480) && (VtMode->FrameRate == XVIDC_FR_75HZ) && XVidC_EdidSuppEstTimings640x480_75(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 800) && (VtMode->Timing.VActive == 600) && (VtMode->FrameRate == XVIDC_FR_75HZ) && XVidC_EdidSuppEstTimings800x600_75(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 832) && (VtMode->Timing.VActive == 624) && (VtMode->FrameRate == XVIDC_FR_75HZ) && XVidC_EdidSuppEstTimings832x624_75(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 1024) && (VtMode->Timing.VActive == 768) && (VtMode->FrameRate == XVIDC_FR_75HZ) && XVidC_EdidSuppEstTimings1024x768_75(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 1152) && (VtMode->Timing.VActive == 870) && (VtMode->FrameRate == XVIDC_FR_75HZ) && XVidC_EdidSuppEstTimings1152x870_75(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 1280) && (VtMode->Timing.VActive == 1024) && (VtMode->FrameRate == XVIDC_FR_75HZ) && XVidC_EdidSuppEstTimings1280x1024_75(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 1024) && (VtMode->Timing.VActive == 768) && (VtMode->FrameRate == XVIDC_FR_87HZ) && XVidC_EdidSuppEstTimings1024x768_87(EdidRaw)) { Status = XST_SUCCESS; } else if ((VtMode->Timing.HActive == 720) && (VtMode->Timing.VActive == 400) && (VtMode->FrameRate == XVIDC_FR_88HZ) && XVidC_EdidSuppEstTimings720x400_88(EdidRaw)) { Status = XST_SUCCESS; } return Status; } static u32 XVidC_EdidIsVideoTimingSupportedStandardTimings(u8 *EdidRaw, XVidC_VideoTimingMode *VtMode) { u8 Index; for (Index = 0; Index < 8; Index++) { if ((VtMode->Timing.HActive == XVidC_EdidGetStdTimingsH(EdidRaw, Index + 1)) && (VtMode->Timing.VActive == XVidC_EdidGetStdTimingsV(EdidRaw, Index + 1)) && (VtMode->FrameRate == (u8)XVidC_EdidGetStdTimingsFrr( EdidRaw, Index + 1))) { return XST_SUCCESS; } } return XST_FAILURE; } /******************************************************************************/ /** * Perform a power operation. * * @param Base is b in the power operation, b^n. * @param Power is n in the power operation, b^n. * * @return Base^Power (Base to the power of Power). * * @note None. * *******************************************************************************/ static float XVidC_CalculatePower(float Base, u8 Power) { u8 Index; float Res = 1.0; for (Index = 0; Index < Power; Index++) { Res *= Base; } return Res; } /******************************************************************************/ /** * Convert a fractional binary number into a decimal number. Binary digits to * the right of the decimal point represent 2^-1 to 2^-(DecPtIndex+1). Binary * digits to the left of the decimal point represent 2^0, 2^1, etc. * * @param Val is the binary representation of the fraction. * @param DecPtIndex is the index of the decimal point in the binary * number. The decimal point is between the binary digits at Val's * indices (DecPtIndex) and (DecPtIndex + 1). * * @return Base^Power (Base to the power of Power). * * @note None. * *******************************************************************************/ static float XVidC_CalculateBinaryFraction(u16 Val, u8 DecPtIndex) { int Index; float Res; for (Index = DecPtIndex, Res = 0; Index >= 0; Index--) { if (((Val >> Index) & 0x1) == 1) { Res += XVidC_CalculatePower( 0.5, DecPtIndex - Index + 1); } } return (Val >> (DecPtIndex + 1)) + Res; }