diff --git a/include/platform/hdmi_if.h b/include/platform/hdmi_if.h new file mode 100644 index 00000000..88cf4f87 --- /dev/null +++ b/include/platform/hdmi_if.h @@ -0,0 +1,745 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +/** + * @addtogroup HDMI + * @{ + * + * @brief Declares standard APIs of basic High-Definition Multimedia Interface (HDMI) capabilities. + * + * You can use this module to access the HDMI and enable the driver to operate an HDMI sink device. + * These capabilities include start and stop tramnsfer on HDMI, setting some attributes, + * and read sink device's EDID data. + * + * @since 1.0 + */ + +/** + * @file hdmi_if.h + * + * @brief Declares the standard HDMI interface functions. + * + * @since 1.0 + */ + +#ifndef HDMI_IF_H +#define HDMI_IF_H + +#include "hdf_platform.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/** + * @brief Indicates that maximum length of an HDMI sink device's EDID is 512 bytes. + * + * @since 1.0 + */ +#define HDMI_EDID_MAX_LEN 512 + +/** + * @brief Enumerates deep color, + * see the section 6.2.4 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiDeepColor { + HDMI_DEEP_COLOR_24BITS = 0, + HDMI_DEEP_COLOR_30BITS = 1, + HDMI_DEEP_COLOR_36BITS = 2, + HDMI_DEEP_COLOR_48BITS = 3, + HDMI_DEEP_COLOR_OFF = 0xff, + HDMI_DEEP_COLOR_BUTT, +}; + +/** + * @brief Enumerates video bit depth + * see the section 6.6 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiVideoBitDepth { + HDMI_VIDEO_BIT_DEPTH_8 = 0, + HDMI_VIDEO_BIT_DEPTH_10 = 1, + HDMI_VIDEO_BIT_DEPTH_12 = 2, + HDMI_VIDEO_BIT_DEPTH_16 = 3, + HDMI_VIDEO_BIT_DEPTH_OFF, +}; + +/** + * @brief Enumerates color space, + * see the section 6 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiColorSpace { + HDMI_COLOR_SPACE_RGB = 0, + HDMI_COLOR_SPACE_YCBCR422 = 1, + HDMI_COLOR_SPACE_YCBCR444 = 2, + HDMI_COLOR_SPACE_YCBCR420 = 3, + HDMI_COLOR_SPACE_BUTT, +}; + +/** + * @brief Enumerates colorimetry, see the section 6.7 of HDMI Specification 1.4 and + * the section 7.2 of HDMI Specification 2.0 for details. + * + * @since 1.0 + */ +enum HdmiColorimetry { + HDMI_COLORIMETRY_NO_DATA = 0, + HDMI_COLORIMETRY_ITU601 = 1, + HDMI_COLORIMETRY_ITU709 = 2, + HDMI_COLORIMETRY_EXTENDED = 3, +}; + +/** + * @brief Enumerates extended colorimetry, see the section 6.7 of HDMI Specification 1.4 and + * the section 7.2 of HDMI Specification 2.0 for details. + * + * @since 1.0 + */ +enum HdmiExtendedColorimetry { + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601 = 0, + HDMI_EXTENDED_COLORIMETRY_XV_YCC_709 = 1, + HDMI_EXTENDED_COLORIMETRY_S_YCC_601 = 2, + HDMI_EXTENDED_COLORIMETRY_OPYCC_601 = 3, + HDMI_EXTENDED_COLORIMETRY_OPRGB = 4, + HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM = 5, + HDMI_EXTENDED_COLORIMETRY_BT2020 = 6, + HDMI_EXTENDED_COLORIMETRY_ADDITIONAL = 7, + HDMI_EXTENDED_COLORIMETRY_BUTT, +}; + +/** + * @brief Enumerates quantization range, see the section 6.6 of HDMI Specification 1.4 and + * the section 7.3 of HDMI Specification 2.0 for details. + * + * @since 1.0 + */ +enum HdmiQuantizationRange { + HDMI_QUANTIZATION_RANGE_DEFAULT = 0, + HDMI_QUANTIZATION_RANGE_LIMITED = 1, + HDMI_QUANTIZATION_RANGE_FULL = 2, + HDMI_QUANTIZATION_RANGE_BUTT, +}; + +/** + * @brief Enumerates YCC quantization range, see the section 6.6 of HDMI Specification 1.4 and + * the section 7.3 of HDMI Specification 2.0 for details. + * + * @since 1.0 + */ +enum HdmiYccQuantizationRange { + HDMI_YCC_QUANTIZATION_RANGE_LIMITED = 0, + HDMI_YCC_QUANTIZATION_RANGE_FULL = 1, + HDMI_YCC_QUANTIZATION_RANGE_BUTT, +}; + +/** + * @brief Enumerates video 3d structure, + * see the section 8.2.3 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiVideo3dStructure { + HDMI_VS_VIDEO_3D_FRAME_PACKING = 0, + HDMI_VS_VIDEO_3D_FIELD_ALTERNATIVE = 1, + HDMI_VS_VIDEO_3D_LINE_ALTERNATIVE = 2, + HDMI_VS_VIDEO_3D_SIDE_BY_SIDE_FULL = 3, + HDMI_VS_VIDEO_3D_L_DEPTH = 4, + HDMI_VS_VIDEO_3D_L_DEPTH_GFX_GFX_DEPTH = 5, + HDMI_VS_VIDEO_3D_TOP_AND_BOTTOM = 6, + HDMI_VS_VIDEO_3D_SIDE_BY_SIDE_HALF = 8, + HDMI_VS_VIDEO_3D_BUTT, +}; + +/** + * @brief Enumerates video timing, + * see the section 8.2.3 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiVideoTiming { + HDMI_VIDEO_TIMING_NONE = 0, + HDMI_VIDEO_TIMING_640X480P60 = 1, + HDMI_VIDEO_TIMING_720X480P60 = 2, + HDMI_VIDEO_TIMING_720X480P120 = 3, + HDMI_VIDEO_TIMING_720X480P240 = 4, + HDMI_VIDEO_TIMING_720X576P50 = 5, + HDMI_VIDEO_TIMING_720X576P100 = 6, + HDMI_VIDEO_TIMING_720X576P200 = 7, + HDMI_VIDEO_TIMING_1280X720P24 = 8, + HDMI_VIDEO_TIMING_1280X720P25 = 9, + HDMI_VIDEO_TIMING_1280X720P30 = 10, + HDMI_VIDEO_TIMING_1280X720P48 = 11, + HDMI_VIDEO_TIMING_1280X720P50 = 12, + HDMI_VIDEO_TIMING_1280X720P60 = 13, + HDMI_VIDEO_TIMING_1280X720P100 = 14, + HDMI_VIDEO_TIMING_1280X720P120 = 15, + HDMI_VIDEO_TIMING_1440X240P60 = 16, + HDMI_VIDEO_TIMING_1440X288P50 = 17, + HDMI_VIDEO_TIMING_1440X480I60 = 18, + HDMI_VIDEO_TIMING_1440X480P60 = 19, + HDMI_VIDEO_TIMING_1440X480I120 = 20, + HDMI_VIDEO_TIMING_1440X480I240 = 21, + HDMI_VIDEO_TIMING_1440X576I50 = 22, + HDMI_VIDEO_TIMING_1440X576P50 = 23, + HDMI_VIDEO_TIMING_1440X576I60 = 24, + HDMI_VIDEO_TIMING_1440X576I100 = 25, + HDMI_VIDEO_TIMING_1440X576I200 = 26, + HDMI_VIDEO_TIMING_2880X288P50 = 27, + HDMI_VIDEO_TIMING_2880X480I60 = 28, + HDMI_VIDEO_TIMING_2880X480P60 = 29, + HDMI_VIDEO_TIMING_2880X240I60 = 30, + HDMI_VIDEO_TIMING_2880X576I50 = 31, + HDMI_VIDEO_TIMING_2880X576P50 = 32, + HDMI_VIDEO_TIMING_1680X720P24 = 33, + HDMI_VIDEO_TIMING_1680X720P25 = 34, + HDMI_VIDEO_TIMING_1680X720P30 = 35, + HDMI_VIDEO_TIMING_1680X720P48 = 36, + HDMI_VIDEO_TIMING_1680X720P50 = 37, + HDMI_VIDEO_TIMING_1680X720P60 = 38, + HDMI_VIDEO_TIMING_1680X720P100 = 39, + HDMI_VIDEO_TIMING_1680X720P120 = 40, + HDMI_VIDEO_TIMING_2560X1080P24 = 41, + HDMI_VIDEO_TIMING_2560X1080P25 = 42, + HDMI_VIDEO_TIMING_2560X1080P30 = 43, + HDMI_VIDEO_TIMING_2560X1080P48 = 44, + HDMI_VIDEO_TIMING_2560X1080P50 = 45, + HDMI_VIDEO_TIMING_2560X1080P60 = 46, + HDMI_VIDEO_TIMING_2560X1080P100 = 47, + HDMI_VIDEO_TIMING_2560X1080P120 = 48, + HDMI_VIDEO_TIMING_1920X1080I60 = 49, + HDMI_VIDEO_TIMING_1920X1080P60 = 50, + HDMI_VIDEO_TIMING_1920X1080I50 = 51, + HDMI_VIDEO_TIMING_1920X1080P50 = 52, + HDMI_VIDEO_TIMING_1920X1080P24 = 53, + HDMI_VIDEO_TIMING_1920X1080P25 = 54, + HDMI_VIDEO_TIMING_1920X1080P30 = 55, + HDMI_VIDEO_TIMING_1920X1080P48 = 56, + HDMI_VIDEO_TIMING_1920X1080I100 = 57, + HDMI_VIDEO_TIMING_1920X1080I120 = 58, + HDMI_VIDEO_TIMING_1920X1080P120 = 59, + HDMI_VIDEO_TIMING_1920X1080P100 = 60, + HDMI_VIDEO_TIMING_3840X2160P24 = 61, + HDMI_VIDEO_TIMING_3840X2160P25 = 62, + HDMI_VIDEO_TIMING_3840X2160P30 = 63, + HDMI_VIDEO_TIMING_3840X2160P48 = 64, + HDMI_VIDEO_TIMING_3840X2160P50 = 65, + HDMI_VIDEO_TIMING_3840X2160P60 = 66, + HDMI_VIDEO_TIMING_3840X2160P100 = 67, + HDMI_VIDEO_TIMING_3840X2160P120 = 68, + HDMI_VIDEO_TIMING_4096X2160P24 = 69, + HDMI_VIDEO_TIMING_4096X2160P25 = 70, + HDMI_VIDEO_TIMING_4096X2160P30 = 71, + HDMI_VIDEO_TIMING_4096X2160P48 = 72, + HDMI_VIDEO_TIMING_4096X2160P50 = 73, + HDMI_VIDEO_TIMING_4096X2160P60 = 74, + HDMI_VIDEO_TIMING_4096X2160P100 = 75, + HDMI_VIDEO_TIMING_4096X2160P120 = 76, + HDMI_VIDEO_TIMING_5120X2160P24 = 77, + HDMI_VIDEO_TIMING_5120X2160P25 = 78, + HDMI_VIDEO_TIMING_5120X2160P30 = 79, + HDMI_VIDEO_TIMING_5120X2160P48 = 80, + HDMI_VIDEO_TIMING_5120X2160P50 = 81, + HDMI_VIDEO_TIMING_5120X2160P60 = 82, + HDMI_VIDEO_TIMING_5120X2160P100 = 83, + HDMI_VIDEO_TIMING_5120X2160P120 = 84, + HDMI_VIDEO_TIMING_7680X4320P24 = 85, + HDMI_VIDEO_TIMING_7680X4320P25 = 86, + HDMI_VIDEO_TIMING_7680X4320P30 = 87, + HDMI_VIDEO_TIMING_7680X4320P48 = 88, + HDMI_VIDEO_TIMING_7680X4320P50 = 89, + HDMI_VIDEO_TIMING_7680X4320P60 = 90, + HDMI_VIDEO_TIMING_7680X4320P100 = 91, + HDMI_VIDEO_TIMING_7680X4320P120 = 92, + HDMI_VIDEO_TIMING_10240X4320P24 = 93, + HDMI_VIDEO_TIMING_10240X4320P25 = 94, + HDMI_VIDEO_TIMING_10240X4320P30 = 95, + HDMI_VIDEO_TIMING_10240X4320P48 = 96, + HDMI_VIDEO_TIMING_10240X4320P50 = 97, + HDMI_VIDEO_TIMING_10240X4320P60 = 98, + HDMI_VIDEO_TIMING_10240X4320P100 = 99, + HDMI_VIDEO_TIMING_10240X4320P120 = 100, + HDMI_VIDEO_TIMING_VESA_DEFINE = 101, + HDMI_VIDEO_TIMING_VESA_800X600_60 = 102, + HDMI_VIDEO_TIMING_VESA_848X480_60 = 103, + HDMI_VIDEO_TIMING_VESA_1024X768_60 = 104, + HDMI_VIDEO_TIMING_VESA_1280X720_60 = 105, + HDMI_VIDEO_TIMING_VESA_1280X768_60 = 106, + HDMI_VIDEO_TIMING_VESA_1280X768_60_RB = 107, + HDMI_VIDEO_TIMING_VESA_1280X800_60 = 108, + HDMI_VIDEO_TIMING_VESA_1280X800_60_RB = 109, + HDMI_VIDEO_TIMING_VESA_1280X960_60 = 110, + HDMI_VIDEO_TIMING_VESA_1280X1024_60 = 111, + HDMI_VIDEO_TIMING_VESA_1360X768_60 = 112, + HDMI_VIDEO_TIMING_VESA_1366X768_60 = 113, + HDMI_VIDEO_TIMING_VESA_1400X1050_60 = 114, + HDMI_VIDEO_TIMING_VESA_1440X900_60 = 115, + HDMI_VIDEO_TIMING_VESA_1440X900_60_RB = 116, + HDMI_VIDEO_TIMING_VESA_1440X1050_60 = 117, + HDMI_VIDEO_TIMING_VESA_1440X1050_60_RB = 118, + HDMI_VIDEO_TIMING_VESA_1600X900_60_RB = 119, + HDMI_VIDEO_TIMING_VESA_1600X1200_60 = 120, + HDMI_VIDEO_TIMING_VESA_1680X1050_60 = 113, + HDMI_VIDEO_TIMING_VESA_1680X1050_60_RB = 114, + HDMI_VIDEO_TIMING_VESA_1792X1344_60 = 115, + HDMI_VIDEO_TIMING_VESA_1856X1392_60 = 116, + HDMI_VIDEO_TIMING_VESA_1920X1080_60 = 117, + HDMI_VIDEO_TIMING_VESA_1920X1200_60 = 118, + HDMI_VIDEO_TIMING_VESA_1920X1200_60_RB = 119, + HDMI_VIDEO_TIMING_VESA_1920X1440_60 = 120, + HDMI_VIDEO_TIMING_VESA_2048X1152_60 = 121, + HDMI_VIDEO_TIMING_VESA_2560X1440_60_RB = 122, + HDMI_VIDEO_TIMING_VESA_2560X1600_60 = 123, + HDMI_VIDEO_TIMING_VESA_2560X1600_60_RB = 124, + HDMI_VIDEO_TIMING_USER_DEFINE = 125, + HDMI_VIDEO_TIMING_USER_1920X2160_30 = 126, + HDMI_VIDEO_TIMING_USER_2560X1440_30 = 127, + HDMI_VIDEO_TIMING_USER_2560X1440_60 = 128, + HDMI_VIDEO_TIMING_USER_1280X720_60 = 129, + HDMI_VIDEO_TIMING_USER_1366X768_60 = 130, + HDMI_VIDEO_TIMING_USER_1600X900_60_RB = 131, + HDMI_VIDEO_TIMING_USER_1920X1080_60 = 132, + HDMI_VIDEO_TIMING_USER_2048X1152_60 = 133, + HDMI_VIDEO_TIMING_BUTT, +}; + +/** + * @brief Enumerates picture aspect ratio, + * see the section 8.2.1 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiPictureAspectRatio { + HDMI_PICTURE_ASPECT_NO_DATA = 0, + HDMI_PICTURE_ASPECT_4_3 = 1, + HDMI_PICTURE_ASPECT_16_9 = 2, + HDMI_PICTURE_ASPECT_64_27 = 3, + HDMI_PICTURE_ASPECT_256_135 = 4, + HDMI_PICTURE_ASPECT_BUTT = 5, +}; + +/** + * @brief Enumerates active format aspect ratio, + * see the section 8.2.1 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiActiveFormatAspectRatio { + HDMI_ACTIVE_FORMAT_ASPECT_16_9_TOP = 2, + HDMI_ACTIVE_FORMAT_ASPECT_14_9_TOP = 3, + HDMI_ACTIVE_FORMAT_ASPECT_16_9_CENTER = 4, + HDMI_ACTIVE_FORMAT_ASPECT_PICTURE = 8, + HDMI_ACTIVE_FORMAT_ASPECT_4_3 = 9, + HDMI_ACTIVE_FORMAT_ASPECT_16_9 = 10, + HDMI_ACTIVE_FORMAT_ASPECT_14_9 = 11, + HDMI_ACTIVE_FORMAT_ASPECT_4_3_SP_14_9 = 13, + HDMI_ACTIVE_FORMAT_ASPECT_16_9_SP_14_9 = 14, + HDMI_ACTIVE_FORMAT_ASPECT_16_9_SP_4_3 = 15, + HDMI_ACTIVE_FORMAT_ASPECT_BUTT, +}; + +/** + * @brief Enumerates Nups(non-uniform picture scaling), + * see the section 8.2.1 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiNups { + HDMI_NUPS_UNKNOWN = 0, /* No Known non-uniform scaling */ + HDMI_NUPS_HORIZONTAL = 1, /* Picture has been scaled horizontally */ + HDMI_NUPS_VERTICAL = 2, /* Picture has been scaled vertically */ + HDMI_NUPS_BOTH = 3, /* Picture has been scaled horizontally and vertically */ +}; + +struct HdmiVideoAttr { + uint32_t tmdsClock; /* unit: KHz */ + uint32_t pixelClock; /* unit: KHz */ + uint32_t pixelRepeat; + enum HdmiColorSpace colorSpace; + enum HdmiColorimetry colorimetry; + enum HdmiExtendedColorimetry extColorimetry; + enum HdmiQuantizationRange quantization; + enum HdmiYccQuantizationRange yccQuantization; + enum HdmiDeepColor deepColor; + enum HdmiVideo3dStructure _3dStruct; + enum HdmiVideoTiming timing; + enum HdmiPictureAspectRatio aspect; + enum HdmiActiveFormatAspectRatio activeAspect; + enum HdmiNups nups; + bool xvycc; +}; + +/** + * @brief Enumerates audio coding type, + * see the section 7 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiAudioCodingType { + HDMI_AUDIO_CODING_TYPE_STREAM = 0, + HDMI_AUDIO_CODING_TYPE_LPCM = 1, + HDMI_AUDIO_CODING_TYPE_AC3 = 2, + HDMI_AUDIO_CODING_TYPE_MPEG1 = 3, + HDMI_AUDIO_CODING_TYPE_MP3 = 4, + HDMI_AUDIO_CODING_TYPE_MPEG2 = 5, + HDMI_AUDIO_CODING_TYPE_AAC_LC = 6, + HDMI_AUDIO_CODING_TYPE_DTS = 7, + HDMI_AUDIO_CODING_TYPE_ATRAC = 8, + HDMI_AUDIO_CODING_TYPE_OBA =9, + HDMI_AUDIO_CODING_TYPE_EAC3 = 10, + HDMI_AUDIO_CODING_TYPE_DTS_HD = 11, + HDMI_AUDIO_CODING_TYPE_MLP = 12, + HDMI_AUDIO_CODING_TYPE_DST = 13, + HDMI_AUDIO_CODING_TYPE_WMA_PRO = 14, + HDMI_AUDIO_CODING_TYPE_CXT = 15, +}; + +/** + * @brief Enumerates audio interface type. + * + * @since 1.0 + */ +enum HdmiAudioInterfaceType { + HDMI_AUDIO_IF_TYPE_I2S = 0, /* Inter-IC Sound */ + HDMI_AUDIO_IF_TYPE_SPDIF = 1, /* Sony/Philips Digital Interface */ + HDMI_AUDIO_IF_TYPE_OTHER, +}; + +/** + * @brief Enumerates audio bit depth, + * see the section 7 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiAudioBitDepth { + HDMI_ADIO_BIT_DEPTH_UNKNOWN, + HDMI_ADIO_BIT_DEPTH_8 = 8, + HDMI_ADIO_BIT_DEPTH_16 = 16, + HDMI_ADIO_BIT_DEPTH_18 = 18, + HDMI_ADIO_BIT_DEPTH_20 = 20, + HDMI_ADIO_BIT_DEPTH_24 = 24, + HDMI_ADIO_BIT_DEPTH_32 = 32, + HDMI_ADIO_BIT_DEPTH_BUTT, +}; + +/** + * @brief Enumerates sample rate used for audio, + * see the section 7.3 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiSampleRate { + HDMI_SAMPLE_RATE_UNKNOWN, + HDMI_SAMPLE_RATE_8K = 8000, + HDMI_SAMPLE_RATE_11K = 11025, + HDMI_SAMPLE_RATE_12K = 12000, + HDMI_SAMPLE_RATE_16K = 16000, + HDMI_SAMPLE_RATE_22K = 22050, + HDMI_SAMPLE_RATE_24K = 24000, + HDMI_SAMPLE_RATE_32K = 32000, + HDMI_SAMPLE_RATE_44K = 44100, + HDMI_SAMPLE_RATE_48K = 48000, + HDMI_SAMPLE_RATE_88K = 88200, + HDMI_SAMPLE_RATE_96K = 96000, + HDMI_SAMPLE_RATE_176K = 176400, + HDMI_SAMPLE_RATE_192K = 192000, + HDMI_SAMPLE_RATE_768K = 768000, + HDMI_SAMPLE_RATE_BUTT, +}; + +/** + * @brief Enumerates audio format channel, + * see the section 7 of HDMI Specification 1.4 for details. + * + * @since 1.0 + */ +enum HdmiAudioFormatChannel { + HDMI_AUDIO_FORMAT_CHANNEL_2 = 2, + HDMI_AUDIO_FORMAT_CHANNEL_3, + HDMI_AUDIO_FORMAT_CHANNEL_4, + HDMI_AUDIO_FORMAT_CHANNEL_5, + HDMI_AUDIO_FORMAT_CHANNEL_6, + HDMI_AUDIO_FORMAT_CHANNEL_7, + HDMI_AUDIO_FORMAT_CHANNEL_8, + HDMI_AUDIO_FORMAT_CHANNEL_BUTT, +}; + +/** + * @brief Defines the audio Attribute struct. + * + * @since 1.0 + */ +struct HdmiAudioAttr { + enum HdmiAudioCodingType codingType; + enum HdmiAudioInterfaceType ifType; + enum HdmiAudioBitDepth bitDepth; + enum HdmiSampleRate sampleRate; + bool downSample; + enum HdmiAudioFormatChannel channels; +}; + +/* Electro-Optical Transfer Function (EOTF) type define. */ +enum HdmiEotfType { + HDMI_DRM_EOTF_SDR_LUMIN = 0, /* Traditional gamma - SDR Luminance Range */ + HDMI_DRM_EOTF_HDR_LUMIN = 1, /* Traditional gamma - HDR Luminance Range */ + HDMI_DRM_EOTF_SMPTE_ST_2048 = 2, /* SMPTE ST 2048 */ + HDMI_DRM_EOTF_HLG = 3, /* Hybrid Log-Gamma (HLG) based on ITU-R BT.2100-0 */ + HDMI_DRM_EOTF_BUTT, +}; + +/** + * @brief Enumerates hdr colormetry, + * see HDMI Specification 2.1 for details. + * + * @since 1.0 + */ +enum HdmiHdrColormetry { + HDMI_HDR_COLORIMETRY_NONE, + HDMI_HDR_COLORIMETRY_ITU_601, + HDMI_HDR_COLORIMETRY_ITU_709, + HDMI_HDR_COLORIMETRY_EXTENDED, + HDMI_HDR_EXTENDED_COLORIMETRY_XV_YCC_601, + HDMI_HDR_EXTENDED_COLORIMETRY_XV_YCC_709, + HDMI_HDR_EXTENDED_COLORIMETRY_S_YCC_601, + HDMI_HDR_EXTENDED_COLORIMETRY_ADOBE_YCC_601, + HDMI_HDR_EXTENDED_COLORIMETRY_ADOBE_RGB, + HDMI_HDR_EXTENDED_COLORIMETRY_2020_CONST_LUMINOUS, /* BT2020 c_ycc */ + HDMI_HDR_EXTENDED_COLORIMETRY_2020_NON_CONST_LUMINOUW +}; + +/** + * @brief Enumerates hdr mode, + * see HDMI Specification 2.1 for details. + * + * @since 1.0 + */ +enum HdmiHdrMode { + HDMI_HDR_MODE_DISABLE, /* HDR & dolby mode disable */ + HDMI_HDR_MODE_DOLBY_NORMAL, /* dolby normal(ycbcr422-12bit) mode enable */ + HDMI_HDR_MODE_DOLBY_TUNNELING, /* dolby tunneling(RGB-8bit) mode enable */ + HDMI_HDR_MODE_CEA_861_3, /* HDR standard mode enable(according to ) */ + HDMI_HDR_MODE_CEA_861_3_AUTHEN, /* HDR authen mode */ + HDMI_HDR_MODE_BUTT +}; + +/** + * @brief Enumerates hdr user mode, + * see HDMI Specification 2.1 for details. + * + * @since 1.0 + */ +enum HdmiHdrUserMode { + HDMI_HDR_USERMODE_SDR, + HDMI_HDR_USERMODE_HDR10, + HDMI_HDR_USERMODE_DOLBY, + HDMI_HDR_USERMODE_BUTT +}; + +/** + * @brief Enumerates static metadata type, + * see the section 6.9 of CTA-861-G for details. + * + * @since 1.0 + */ +enum HdmiStaticMetadataType { + HDMI_DRM_STATIC_METADATA_TYPE_1 = 0, /* Static Metadata Type 1 */ + HDMI_DRM_STATIC_METADATA_BUTT, +}; + +/** + * @brief Enumerates static metadata descriptor1st, + * see the section 6.9 of CTA-861-G for details. + * + * @since 1.0 + */ +struct HdmiStaticMetadataDescriptor1st { + uint16_t displayPrimaries0X; /* display_primaries_x[0], in units of 0.00002 */ + uint16_t displayPrimaries0Y; /* display_primaries_y[0], in units of 0.00002 */ + uint16_t displayPrimaries1X; /* display_primaries_x[1], in units of 0.00002 */ + uint16_t displayPrimaries1Y; /* display_primaries_y[1], in units of 0.00002 */ + uint16_t displayPrimaries2X; /* display_primaries_x[2], in units of 0.00002 */ + uint16_t displayPrimaries2Y; /* display_primaries_y[2], in units of 0.00002 */ + uint16_t whitePointX; /* white_point_x, in units of 0.00002 */ + uint16_t whitePointY; /* white_point_y, in units of 0.00002 */ + uint16_t maxDisplayMasteringLuminance; /* max_display_mastering_luminance, in units of 1 cd/m^2 */ + uint16_t minDisplayMasteringLuminance; /* min_display_mastering_luminance, in units of 0.0001 cd/m^2 */ + uint16_t maxContentLightLevel; /* Maximum Content Light Level, in units of 1 cd/m^2 */ + uint16_t maxFrameAverageLightLevel; /* Maximum Frame-average Light Level, in units of 1 cd/m^2 */ +}; + +union HdmiStaticMetadataDescriptor { + struct HdmiStaticMetadataDescriptor1st type1; +}; + +struct HdmiHdrAttr { + enum HdmiHdrMode mode; + enum HdmiHdrUserMode userMode; + /* The following members are valid, when mode is HDMI_HDR_MODE_CEA_861_3. */ + enum HdmiEotfType eotfType; + enum HdmiStaticMetadataType metadataType; + union HdmiStaticMetadataDescriptor descriptor; + enum HdmiHdrColormetry colorimetry; +}; + +/** + * @brief Opens an HDMI controller with a specified bus number. + * + * Before using the HDMI interface, you can obtain the device handle of the HDMI controller + * by calling {@link HdmiOpen}. This function is used in pair with {@link HdmiClose}. + * + * @param busNum Indicates the bus number. + * + * @return Returns the device handle {@link DevHandle} of the HDMI controller if the operation is successful; + * returns NULL otherwise. + * + * @since 1.0 + */ +DevHandle HdmiOpen(uint16_t busNum); + +/** + * @brief HDMI transmission start. + * + * This function is used in pair with {@link HdmiStop}. + * + * @param handle Indicates the pointer to the device handle of the HDMI controller. + * + * @return Returns 0 if the operation is successful; returns a negative value if the operation fails. + * + * @since 1.0 + */ +int32_t HdmiStart(DevHandle handle); + +/** + * @brief HDMI transmission stop. + * + * This function is used in pair with {@link HdmiStart}. + * + * @param handle Indicates the pointer to the device handle of the HDMI controller. + * + * @return Returns 0 if the operation is successful; returns a negative value if the operation fails. + * + * @since 1.0 + */ +int32_t HdmiStop(DevHandle handle); + +/** + * @brief HDMI Avmute set. + * + * First put the display device into the black screen mute state, waitting for the HDMI output device switch, + * and then send a Clear AVMute signal, so that the display device to boot, so that the switching process of + * the screen will be shielded. + * + * @param handle Indicates the pointer to the device handle of the HDMI controller. + * @param enable Indicates whether to enable avmute. + * + * @return Returns 0 if the operation is successful; returns a negative value if the operation fails. + * + * @since 1.0 + */ +int32_t HdmiAvmuteSet(DevHandle handle, bool enable); + + +/** + * @brief HDMI deep color set. + * + * @param handle Indicates the pointer to the device handle of the HDMI controller. + * @param color Indicates the deep color to be set, see {@link HdmiDeepColor}. + * + * @return Returns 0 if the operation is successful; returns a negative value if the operation fails. + * + * @since 1.0 + */ +int32_t HdmiDeepColorSet(DevHandle handle, enum HdmiDeepColor color); + +/** + * @brief HDMI deep color get. + * + * @param handle Indicates the pointer to the device handle of the HDMI controller. + * @param color Indicates the pointer to the deep color to read, see {@link HdmiDeepColor}. + * + * @return Returns 0 if the operation is successful; returns a negative value if the operation fails. + * + * @since 1.0 + */ +int32_t HdmiDeepColorGet(DevHandle handle, enum HdmiDeepColor *color); + +/** + * @brief HDMI set video attribute. + * + * @param handle Indicates the pointer to the device handle of the HDMI controller. + * @param attr Indicates the pointer to the video attribute to set, see {@link HdmiVideoAttr}. + * + * @return Returns 0 if the operation is successful; returns a negative value if the operation fails. + * + * @since 1.0 + */ +int32_t HdmiSetVideoAttribute(DevHandle handle, struct HdmiVideoAttr *attr); + +/** + * @brief HDMI set audio attribute. + * + * @param handle Indicates the pointer to the device handle of the HDMI controller. + * @param attr Indicates the pointer to the audio attribute to set, see {@link HdmiAudioAttr}. + * + * @return Returns 0 if the operation is successful; returns a negative value if the operation fails. + * + * @since 1.0 + */ +int32_t HdmiSetAudioAttribute(DevHandle handle, struct HdmiAudioAttr *attr); + +/** + * @brief HDMI set hdr attribute. + * + * @param handle Indicates the pointer to the device handle of the HDMI controller. + * @param attr Indicates the pointer to the hdr attribute to set, see {@link HdmiHdrAttr}. + * + * @return Returns 0 if the operation is successful; returns a negative value if the operation fails. + * + * @since 1.0 + */ +int32_t HdmiSetHdrAttribute(DevHandle handle, struct HdmiHdrAttr *attr); + +/** + * @brief HDMI read sink device's raw EDID data. + * + * @param handle Indicates the pointer to the device handle of the HDMI controller. + * @param buffer Indicates the pointer to the data to read. + * @param len Indicates the length of the data to read. + * + * @return Returns the length of the data read if the operation is successful; + * returns a negative value or 0 if the operation fails. + * + * @since 1.0 + */ +int32_t HdmiReadSinkEdid(DevHandle handle, uint8_t *buffer, uint32_t len); + +/** + * @brief Closes an HDMI controller. + * + * After the HDMI interface is used, you can close the HDMI controller by calling {@link HdmiClose}. + * This function is used in pair with {@link HdmiOpen}. + * + * @param handle Indicates the pointer to the device handle of the HDMI controller. + * + * @since 1.0 + */ +void HdmiClose(DevHandle handle); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_IF_H */ diff --git a/support/platform/include/hdmi/hdmi_cec.h b/support/platform/include/hdmi/hdmi_cec.h new file mode 100644 index 00000000..70b8a0f3 --- /dev/null +++ b/support/platform/include/hdmi/hdmi_cec.h @@ -0,0 +1,1712 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_CEC_H +#define HDMI_CEC_H + +#include "hdf_base.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/* + * CEC(Consumer Electronics Control). + * CEC is a protocol that provides high-level control functions between all of the various audiovisual products + * in a user's environment. + */ + +/* + * One Touch Play Feature/Routing Control Feature. + * Used by a new source to indicate that it has started to transmit a stream OR + * used in response to a . + * Param: [Physical Address], 2 bytes. + * Broadcast message. + */ +#define HDMI_CEC_OPCODE_ACTIVE_SOURCE 0x82 + +#define HDMI_CEC_ACTIVE_SOURCE_MSG_PARAM_LEN 2 + +/* + * One Touch Play Feature. + * Sent by a source device to the TV whenever it enters the + * active state(alternatively it may send ). + * Param: None. + */ +#define HDMI_CEC_OPCODE_IMAGE_VIEW_ON 0x04 + +/* + * One Touch Play Feature. + * As , but should also remove any text, menus and PIP windows from the TV's display. + * Param: None. + */ +#define HDMI_CEC_OPCODE_TEXT_VIEW_ON 0x0D + +/* + * Routing Control Feature. + * Used by currently active source to inform the TV that it has no video to be presented to the user, + * or is going into the Standby state as the result of a local user command on the device. + * Param: [Physical Address], 2 bytes. + */ +#define HDMI_CEC_OPCODE_INACTIVE_SOURCE 0x9D + +#define HDMI_CEC_INACTIVE_SOURCE_MSG_PARAM_LEN 2 + +/* + * Routing Control Feature. + * Used by a new device to discover the status of the system. + * Param: None. + * Broadcast message. + */ +#define HDMI_CEC_OPCODE_REQUEST_ACTIVE_SOURCE 0x85 + +/* + * Routing Control Feature. + * Sent By CEC Switch when it is manually switched to inform all other devices on the network that + * the active route below the switch has changed. + * Param: [Original(Physical) Address], 2 bytes. [New(Physical) Address], 2 bytes. + * Broadcast message. + */ +#define HDMI_CEC_OPCODE_ROUTING_CHANGE 0x80 + +#define HDMI_CEC_ROUTING_CHANGE_MSG_PARAM_LEN 4 + +/* + * Routing Control Feature. + * Sent By a CEC Switch to indicate the active route below the switch. + * Param: [Physical Address], 2 bytes. + * Broadcast message. + */ +#define HDMI_CEC_OPCODE_ROUTING_INFORMATION 0x81 + +#define HDMI_CEC_ROUTING_INFORMATIO_MSG_PARAM_LEN 2 + +/* + * Routing Control Feature. + * Used by the TV to request a streaming path from the specified Physical Address. + * Param: [Physical Address], 2 bytes. + * Broadcast message. + */ +#define HDMI_CEC_OPCODE_SET_STREAM_PATH 0x86 + +#define HDMI_CEC_SET_STREAM_PATH_MSG_PARAM_LEN 2 + +/* + * Routing Control Feature. + * Switches one or all devices into the Standby state. + * Can be used as a broadcast message or be addressed to a specific device. + * Param: None. + */ +#define HDMI_CEC_OPCODE_STANDBY 0x36 + +/* + * One Touch Record Feature. + * Request a device stop a recording. + * Param: None. + */ +#define HDMI_CEC_OPCODE_RECORD_OFF 0x0B + +/* + * One Touch Record Feature. + * Attempt to record the specified source. + * Param: [Record Source], 1~8 bytes. + */ +#define HDMI_CEC_OPCODE_RECORD_ON 0x09 + +/* Record Source Type, 1 byte. */ +#define HDMI_CEC_RECORD_SOURCE_TYPE_LEN 1 +enum HdmiCecRecordSourceType { + HDMI_CEC_RECORD_SRC_OWN = 1, + HDMI_CEC_RECORD_SRC_DIGITAL = 2, + HDMI_CEC_RECORD_SRC_ANALOG = 3, + HDMI_CEC_RECORD_SRC_EXT_PLUG = 4, + HDMI_CEC_RECORD_SRC_EXT_PHY_ADDR = 5, +}; + +/* + * Digital Service Identification. 7 bytes. + * [Service Identification Method] 1 bit + * [Digital Broadcast System] 7 bits + * [Service Identification] 6 bytes + */ +#define HDMI_CEC_DIGITAL_SERVICE_ID_LEN 7 +#define HDMI_CEC_SERVICE_ID_METHOD_BY_DIGITAL_IDS 0 +#define HDMI_CEC_SERVICE_ID_METHOD_BY_CHANNEL 1 + +enum HdmiCecDigitalBroadcastSystem { + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN = 0x00, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN = 0x01, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN = 0x02, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS = 0x08, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS = 0x09, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ARIB_T = 0x0A, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE = 0x10, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ATSC_SATELLITE = 0x11, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ATSC_TERRESTRIAL = 0x12, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_DVB_C = 0x18, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_DVB_S = 0x19, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_DVB_S2 = 0x1A, + HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_DVB_T = 0x1B, +}; + +/* + * Service Identification, 6 bytes. + * [ARIB Data] | [ATSC Data] | [DVB Data] | [Channel Data] + * Channel Data, 6 bytes. + * [Channel Identifier] 4 bytes, [Reserved] 2 bytes. + * Channel Identifier, 4 bytes. + * [Channel Number Format] 6 bits. + * [Major Channel Number] 10 bits. + * [Minor Channel Number] 16 bits + */ +#define HDMI_CEC_CHANNEL_NUMBER_FORMAT_1_PART 0x01 +#define HDMI_CEC_CHANNEL_NUMBER_FORMAT_2_PART 0x02 +#define HDMI_CEC_CHANNEL_NUMBER_FORMAT_SHIFT 2 + +struct HdmiCecDigitalServiceAribData { + uint16_t transportId; + uint16_t serviceId; + uint16_t orgNetworkId; +}; + +struct HdmiCecDigitalServiceAtscData { + uint16_t transportId; + uint16_t programNumber; +}; + +struct HdmiCecDigitalServiceDvbData { + uint16_t transportId; + uint16_t serviceId; + uint16_t orgNetworkId; +}; + +#define HDMI_CEC_CHANNEL_IDENTIFIER_LEN 4 +struct HdmiCecChannelIdentifier { + uint8_t format; + uint16_t major; + uint16_t minor; +}; + +#define HDMI_CEC_DIGITAL_SERVICE_ID_METHOD_SHIFT 7 + +struct HdmiCecDigitalServiceId { + uint8_t method; + uint8_t system; + union { + struct HdmiCecDigitalServiceAribData arib; + struct HdmiCecDigitalServiceAtscData atsc; + struct HdmiCecDigitalServiceDvbData dvb; + struct HdmiCecChannelIdentifier channel; + } systemData; +}; + +/* + * Record Source. + * {[Record Source Type]} | {[Record Source Type] [Digital Service Identification]} | + * {[Record Source Type] [Analogue Broadcast Type] [Analogue Frequency] [Broadcast System]} | + * {[Record Source Type] [External Plug]} | {[Record Source Type] [External Physical Address]} + */ +#define HDMI_CEC_ANALOGUE_BROADCAST_TYPE_LEN 1 +#define HDMI_CEC_ANALOGUE_FREQ_LEN 2 +#define HDMI_CEC_BROADCAST_SYSTEM_LEN 1 +#define HDMI_CEC_EXT_PLUG_LEN 1 +#define HDMI_CEC_EXT_PHY_ADDRESS_LEN 2 +#define HDMI_CEC_RECORD_ON_OWN_MSG_PARAM_LEN HDMI_CEC_RECORD_SOURCE_TYPE_LEN +#define HDMI_CEC_RECORD_ON_DIGITAL_MSG_PARAM_LEN (HDMI_CEC_RECORD_SOURCE_TYPE_LEN + HDMI_CEC_DIGITAL_SERVICE_ID_LEN) +#define HDMI_CEC_RECORD_ON_ANALOG_MSG_PARAM_LEN (HDMI_CEC_RECORD_SOURCE_TYPE_LEN + \ + HDMI_CEC_ANALOGUE_BROADCAST_TYPE_LEN + HDMI_CEC_ANALOGUE_FREQ_LEN + HDMI_CEC_BROADCAST_SYSTEM_LEN) +#define HDMI_CEC_RECORD_ON_EXT_PLUG_MSG_PARAM_LEN (HDMI_CEC_RECORD_SOURCE_TYPE_LEN + HDMI_CEC_EXT_PLUG_LEN) +#define HDMI_CEC_RECORD_ON_EXT_PHY_ADDR_MSG_PARAM_LEN (HDMI_CEC_RECORD_SOURCE_TYPE_LEN + HDMI_CEC_EXT_PHY_ADDRESS_LEN) + +struct HdmiCecRecordSource { + uint8_t type; + union { + struct HdmiCecDigitalServiceId id; + struct { + uint8_t anaBcastType; + uint16_t anaFreq; + uint8_t bcstSystem; + } analog; + uint8_t extPlug; + uint16_t extPhyAddr; + } data; +}; + +/* + * One Touch Record Feature. + * Used by a Recording Device to inform the Initiator of the message about its status. + * Param: [Record Status Info], 1 byte. + */ +#define HDMI_CEC_OPCODE_RECORD_STATUS 0x0A + +#define HDMI_CEC_RECORD_STATUS_MSG_PARAM_LEN 1 + +/* Record Status Info */ +enum HdmiCecRecordStatusInfo { + HDMI_CEC_RECORD_STATUS_CUR_SRC = 0x01, + HDMI_CEC_RECORD_STATUS_DIG_SERVICE = 0x02, + HDMI_CEC_RECORD_STATUS_ANA_SERVICE = 0x03, + HDMI_CEC_RECORD_STATUS_EXT_INPUT = 0x04, + HDMI_CEC_RECORD_STATUS_NO_DIG_SERVICE = 0x05, + HDMI_CEC_RECORD_STATUS_NO_ANA_SERVICE = 0x06, + HDMI_CEC_RECORD_STATUS_NO_SERVICE = 0x07, + HDMI_CEC_RECORD_STATUS_INVALID_EXT_PLUG = 0x09, + HDMI_CEC_RECORD_STATUS_INVALID_EXT_PHYS_ADDR = 0x0A, + HDMI_CEC_RECORD_STATUS_UNSUP_CA = 0x0B, + HDMI_CEC_RECORD_STATUS_NO_CA_ENTITLEMENTS = 0x0C, + HDMI_CEC_RECORD_STATUS_NO_COPY_SRC = 0x0D, + HDMI_CEC_RECORD_STATUS_NO_MORE_COPIES = 0x0E, + HDMI_CEC_RECORD_STATUS_NO_MEDIA = 0x10, + HDMI_CEC_RECORD_STATUS_PLAYING = 0x11, + HDMI_CEC_RECORD_STATUS_ALREADY_RECORDING = 0x12, + HDMI_CEC_RECORD_STATUS_MEDIA_PROTECTED = 0x13, + HDMI_CEC_RECORD_STATUS_NO_SRC_SIGNAL = 0x14, + HDMI_CEC_RECORD_STATUS_MEDIA_PROBLEM = 0x15, + HDMI_CEC_RECORD_STATUS_NO_SPACE = 0x16, + HDMI_CEC_RECORD_STATUS_PARENTAL_LOCK = 0x17, + HDMI_CEC_RECORD_STATUS_TERMINATED_OK = 0x1A, + HDMI_CEC_RECORD_STATUS_ALREADY_TERMINATED = 0x1B, + HDMI_CEC_RECORD_STATUS_OTHER = 0x1F, +}; + +/* + * One Touch Record Feature. + * Request by The Recording Device to record the presently displayed source. + */ +#define HDMI_CEC_OPCODE_RECORD_TV_SCREEN 0x0F + +/* + * Timer Programming Feature. + * Used to clear an Analogue timer block of a device. + * Param: see param. + */ +#define HDMI_CEC_OPCODE_CLEAR_ANALOGUE_TIMER 0x33 + +/* + * Timer Programming Feature. + * Used to clear a Digital timer block of a device. + * Param: see param. + */ +#define HDMI_CEC_OPCODE_CLEAR_DIGITAL_TIMER 0x99 + +/* + * Timer Programming Feature. + * Used to clear a External timer block of a device. + * Param: see param. + */ +#define HDMI_CEC_OPCODE_CLEAR_EXTERNAL_TIMER 0xA1 + +/* + * Timer Programming Feature. + * Used to set a single timer block on an Analogue Recording device. + * Param: [Day of Month], 1 byte; [Month of Year], 1 byte; [Start Time], 2 byte; [Duration], 2 byte; + * [Recording Sequence], 1 byte; [Analogue Broadcast Type], 1 byte; [Analogue Frequency], 2 byte; + * [Broadcast System], 1 byte. + */ +#define HDMI_CEC_OPCODE_SET_ANALOGUE_TIMER 0x34 + +/* Analogue Broadcast Type, 1 byte. */ +enum HdmiCecAnalogueBroadcastType { + HDMI_CEC_ANALOGUE_BROADCAST_CABLE = 0, + HDMI_CEC_ANALOGUE_BROADCAST_SATELITE = 1, + HDMI_CEC_ANALOGUE_BROADCAST_TERRESTRIAL = 2, +}; + +/* Recording Sequence, 8 bits. */ +enum HdmiCecRecordingSequence { + HDMI_CEC_RECORDING_SEQ_ONCE_ONLY = 0x00, + HDMI_CEC_RECORDING_SEQ_SUNDAY = 0x01, + HDMI_CEC_RECORDING_SEQ_MONDAY = 0x02, + HDMI_CEC_RECORDING_SEQ_TUESDAY = 0x04, + HDMI_CEC_RECORDING_SEQ_WEDNESDAY = 0x08, + HDMI_CEC_RECORDING_SEQ_THURSDAY = 0x10, + HDMI_CEC_RECORDING_SEQ_FRIDAY = 0x20, + HDMI_CEC_RECORDING_SEQ_SATERDAY = 0x40, +}; + +#define HDMI_CEC_ANALOGUE_TIMER_INFO_LEN 11 +/* Hour and Minute are in BCD format. */ +#define HDMI_CEC_BCD_FORMAT_TIME(time) (((time / 10) << 4) | (time % 10)) + +#define HDMI_CEC_COMM_TIMER_INFO_LEN 7 +struct HdmiCecCommTimerInfo { + uint8_t data; + uint8_t month; + uint8_t startHour; + uint8_t startMinute; + uint8_t durationHour; + uint8_t durationMinute; + uint8_t recordingSeq; +}; + +struct HdmiCecAnalogueTimerInfo { + struct HdmiCecCommTimerInfo commInfo; + uint8_t anaBcastType; + uint16_t anaFreq; + uint8_t bcstSystem; +}; + +/* + * Timer Programming Feature. + * Used to set a single timer block on a Digital Recording device. + * Param: [Day of Month], 1 byte; [Month of Year], 1 byte; [Start Time], 2 byte; [Duration], 2 byte; + * [Recording Sequence], 1 byte; [Digtial Service Identification], 7 byte. + */ +#define HDMI_CEC_OPCODE_SET_DIGITAL_TIMER 0x97 + +#define HDMI_CEC_DIGITAL_TIMER_INFO_LEN 14 +struct HdmiCecDigitalTimerInfo { + struct HdmiCecCommTimerInfo commInfo; + struct HdmiCecDigitalServiceId id; +}; + +/* + * Timer Programming Feature. + * Used to set a single timer block to record from an External device. + * Param: [Day of Month], 1 byte; [Month of Year], 1 byte; [Start Time], 2 byte; [Duration], 2 byte; + * [Recording Sequence], 1 byte; [External Source Specifier], 1 byte; [External Plug], 1 byte; + * [External Physical address], 2 byte. + */ +#define HDMI_CEC_OPCODE_SET_EXTERNAL_TIMER 0xA2 + +#define HDMI_CEC_EXTERNAL_TIMER_INFO_LEN 11 + +/* External Source Specifier */ +#define HDMI_CEC_EXT_PLUG 4 +#define HDMI_CEC_EXT_PHYS_ADDR 5 + +struct HdmiCecExternalTimerInfo { + struct HdmiCecCommTimerInfo commInfo; + uint8_t extSrcSpec; + uint8_t extPlug; + uint16_t extPhyAddr; +}; + +/* + * Timer Programming Feature. + * Used to set the name of a program associate with a timer block. + * Sent directly after sending a or message. + * The name is then associated with that timer block. + * Param: [Program Title String], 1~14 bytes. + */ +#define HDMI_CEC_OPCODE_SET_TIMER_PROGRAM_TITLE 0x67 + +#define HDMI_CEC_PROGRAM_TITLE_STR_MIN_LEN 1 +#define HDMI_CEC_PROGRAM_TITLE_STR_MAX_LEN 14 + +/* + * Timer Programming Feature. + * Used to give the status of a , + * or message. + * Param: [Timer Cleared Status Data], 1 byte. + */ +#define HDMI_CEC_OPCODE_TIMER_CLEARED_STATUS 0x43 + +#define HDMI_CEC_TIMER_CLEARED_STATUS_MSG_PARAM_LEN 1 + +/* Timer Cleared Status Data */ +enum HdmiCecTimerClearedStatus { + HDMI_CEC_TIMER_CLR_STAT_NO_CLEARED_RECORDING = 0x00, + HDMI_CEC_TIMER_CLR_STAT_NO_CLEARED_NO_MATCHING = 0x01, + HDMI_CEC_TIMER_CLR_STAT_NO_CLEARED_NO_INFO = 0x02, + HDMI_CEC_TIMER_CLR_STAT_CLEARED = 0x80, +}; + +/* + * Timer Programming Feature. + * Used to send timer status to the Initiator of a message. + * Param: [Timer Status Data], 1 byte or 3 bytes. + */ +#define HDMI_CEC_OPCODE_TIMER_STATUS 0x35 + +#define HDMI_CEC_TIMER_STATUS_DATA_MIN_LEN 1 +#define HDMI_CEC_TIMER_STATUS_DATA_MAX_LEN 3 + +/* + * Timer Status Data. 1 byte or 3 bytes. + * [Timer overlap warning] 1bit. + * [Media Info] 2 bits. + * [Timer Progremmed Info] 5 bits or 21 bits. + */ +#define HDMI_CEC_TIMER_OVERLAP_WARNING_NO_OVERLAP 0 +#define HDMI_CEC_TIMER_OVERLAP_WARNING_TIMER_BLOCK_OVERLAP 1 + +enum HdmiCecMediaInfo { + HDMI_CEC_MEDIA_PRESENT_NOT_POTECTED = 0, + HDMI_CEC_MEDIA_PRESENT_POTECTED = 1, + HDMI_CEC_MEDIA_NOT_PRESENT = 2, + HDMI_CEC_MEDIA_BUTT, +}; + +/* + * Timer Progremmed Info, 5 bits or 21 bits. + * [Progremmed Indicator], 1 bit. + * {[Progremmed Info], 4 bits. [Duration Available], 2bytes.} | + * {[Not Progremmed Error Info], 4 bits. [Duration Available], 2bytes.} + */ +/* Progremmed Indicator, 1 bit */ +#define HDMI_CEC_PROG_IND_NOT_PROGRAMMED 0 +#define HDMI_CEC_PROG_IND_PROGRAMMED 1 + +/* Progremmed Info, 4 bits */ +enum HdmiCecProgremmedInfo { + HDMI_CEC_PROGRAMMED_INFO_ENOUGH_SPAC = 0x08, + HDMI_CEC_PROGRAMMED_INFO_NOT_ENOUGH_SPAC = 0x09, + HDMI_CEC_PROGRAMMED_INFO_NO_MEDIA_INFO = 0x0A, + HDMI_CEC_PROGRAMMED_INFO_MIGHT_NOT_BE_ENOUGH_SPACE = 0x0B, +}; + +/* Not Progremmed Error Info */ +enum HdmiCecNotProgremmedErrorInfo { + HDMI_CEC_NOT_PROG_ERR_NO_FREE_TIMER = 0x01, + HDMI_CEC_NOT_PROG_ERR_DATE_OUT_OF_RANGE = 0x02, + HDMI_CEC_NOT_PROG_ERR_RECORDING_SEQ_ERROR = 0x03, + HDMI_CEC_NOT_PROG_ERR_INVALID_EXT_PLUG = 0x04, + HDMI_CEC_NOT_PROG_ERR_INVALID_EXT_PHYS_ADDR = 0x05, + HDMI_CEC_NOT_PROG_ERR_CA_UNSUPP = 0x06, + HDMI_CEC_NOT_PROG_ERR_INSUF_CA_ENTITLEMENTS = 0x07, + HDMI_CEC_NOT_PROG_ERR_RESOLUTION_UNSUPP = 0x08, + HDMI_CEC_NOT_PROG_ERR_PARENTAL_LOCK = 0x09, + HDMI_CEC_NOT_PROG_ERR_CLOCK_FAILURE = 0x0A, + HDMI_CEC_NOT_PROG_ERR_DUPLICATE = 0x0E, +}; + +struct HdmiCecTimerProgremmedInfo { + uint8_t indicator; + uint8_t info; /* Progremmed Info/Not Progremmed Error Info */ + uint8_t durationHour; + uint8_t durationMinute; +}; + +struct HdmiCecTimerStatusData { + uint8_t timerOverlap; + uint8_t mediaInfo; + struct HdmiCecTimerProgremmedInfo progInfo; +}; + +/* + * System Information Feature/Vendor Specific Commands Feature. + * Used to indicate the version number of the CEC Specification which was used to design the device, + * in response to a . + * Param: [CEC Version], 1 byte. + */ +#define HDMI_CEC_OPCODE_CEC_VERSION 0x9E + +#define HDMI_CEC_CEC_VERSION_MSG_PARAM_LEN 1 + +/* CEC Version */ +#define HDMI_CEC_VERSION_1_3A 4 +#define HDMI_CEC_VERSION_1_4 5 +#define HDMI_CEC_VERSION_2_0 6 + +/* + * System Information Feature/Vendor Specific Commands Feature. + * Used by a device to enquire which version number of the CEC Specification + * was used to design the Follwer device. + * Param: None. + */ +#define HDMI_CEC_OPCODE_GET_CEC_VERSION 0x9F + +/* + * System Information Feature. + * A request to a device return its Physical Address. + * Param: None. + */ +#define HDMI_CEC_OPCODE_GIVE_PHYSICAL_ADDRESS 0x83 + +/* + * System Information Feature. + * Sent by a device capable of character generation(for OSD and Menus) to a TV in order to + * discover the currently selected Menu language on the TV. + * Param: None. + */ +#define HDMI_CEC_OPCODE_GET_MENU_LANGUAGE 0x91 + +/* + * System Information Feature. + * Used to inform all other devices of the mapping between + * physical and Logical address of the Initiator. + * Param: [Physical Address], 2 bytes. [Device Type], 1 byte. + * Broadcast message. + */ +#define HDMI_CEC_OPCODE_REPORT_PHYSICAL_ADDRESS 0x84 + +#define HDMI_CEC_REPORT_PHYSICAL_ADDRESS_MSG_PARAM_LEN 3 + +/* + * Device Type/Primary Device Type. + * The HDMI 1.4b operand [Device Type] has been extended as [Primary Device Type]. + */ +enum HdmiCecDeviceType { + HDMI_CEC_DEVICE_TYPE_TV = 0, + HDMI_CEC_DEVICE_TYPE_RECORDING_DEVICE = 1, + HDMI_CEC_DEVICE_TYPE_RESERVED = 2, + HDMI_CEC_DEVICE_TYPE_TUNER = 3, + HDMI_CEC_DEVICE_TYPE_PLAYBACK_DEVICE = 4, + HDMI_CEC_DEVICE_TYPE_AUDIO_SYSTEM = 5, + HDMI_CEC_DEVICE_TYPE_PURE_CEC_SWITCH = 6, + HDMI_CEC_DEVICE_TYPE_PROCESSOR = 7, +}; + +/* + * System Information Feature. + * Used by a TV to indicate its currently selected menu language. + * Param: [Language], 3 bytes. + * Broadcast message. + */ +#define HDMI_CEC_OPCODE_SET_MENU_LANGUAGE 0x32 + +#define HDMI_CEC_SET_MENU_LANGUAGE_MSG_PARAM_LEN 3 + +/* + * System Information Feature. + * Used by a device to announce its version, features and device type. + * Param: [CEC Version], 1 byte. [All Device Types], 1 byte. [RC Profile], 1..N bytes. [Device Features], 1..N bytes. + */ +#define HDMI_CEC_OPCODE_REPORT_FEATURES 0xA6 + +#define HDMI_CEC_REPORT_FEATURES_MSG_PARAM_MIN_LEN 4 + +/* All Device Types */ +enum HdmiCecAllDevType { + HDMI_CEC_ALL_DEV_TYPE_CEC_SWITCH = 0x04, + HDMI_CEC_ALL_DEV_TYPE_AUDIO_SYSTEM = 0x08, + HDMI_CEC_ALL_DEV_TYPE_PLAYBACK = 0x10, + HDMI_CEC_ALL_DEV_TYPE_TUNER =0x20, + HDMI_CEC_ALL_DEV_TYPE_RECORD = 0x40, + HDMI_CEC_ALL_DEV_TYPE_TV = 0x80, +}; + +/* + * RC Profile, 1..N bytes. + * [RC Profile 1]; or [RC Profile 1]..[RC Profile N](where N >= 2) + * RC Profile 1, 1 byte. + * [RC Profile Externsion], bit 7 + * if bit6 is 0, [RC Profile TV] in bit5-0; if bit6 is 1, [RC Profile Source] in bit5-0. + */ +#define HDMI_CEC_RC_PROFILE_MAX_NUM 6 +#define HDMI_CEC_RC_PROFILE_EXTERNSION_MARK (1 << 7) +#define HDMI_CEC_RC_PROFILE_TV_OR_SOURCE_MARK (1 << 6) + +/* RC Profile Source, 6 bits. */ +#define HDMI_CEC_RC_PROFILE_SOURCE_ROOT_MENU (1 << 4) +#define HDMI_CEC_RC_PROFILE_SOURCE_SETUP_MENU (1 << 3) +#define HDMI_CEC_RC_PROFILE_SOURCE_CONTENTS_MENU (1 << 2) +#define HDMI_CEC_RC_PROFILE_SOURCE_MEDIA_TOP_MENU (1 << 1) +#define HDMI_CEC_RC_PROFILE_SOURCE_MEDIA_CONTEXT_SENSITIVE_MENU (1 << 0) + +/* + * RC Profile TV, 6 bits. + * [RC Profile ID], Bit3-0. + */ +enum HdmiCecRcProfileId { + HDMI_CEC_RC_PROFILE_NONE = 0x00, + HDMI_CEC_RC_PROFILE_1 = 0x02, + HDMI_CEC_RC_PROFILE_2 = 0x06, + HDMI_CEC_RC_PROFILE_3 = 0x0A, + HDMI_CEC_RC_PROFILE_4 = 0x0E, + HDMI_CEC_RC_PROFILE_BUTT, +}; + +/* + * Device Features, 1..N bytes. + * [Device Features 1], 1 byte. + */ +#define HDMI_CEC_DEVICE_FEATURES_MAX_NUM 6 +#define HDMI_CEC_DEVICE_FEATURES_EXTERNSION_MARK (1 << 7) /* 0 the last; 1 continues. */ +#define HDMI_CEC_DEVICE_FEATURES_TV_SUPP_RECORD_TV_SCREEN (1 << 6) +#define HDMI_CEC_DEVICE_FEATURES_TV_SUPP_SET_OSD_STRING (1 << 5) +#define HDMI_CEC_DEVICE_FEATURES_DECK_SUPP_CONTROL (1 << 4) +#define HDMI_CEC_DEVICE_FEATURES_SRC_SUPP_SET_AUDIO_RATE (1 << 3) +#define HDMI_CEC_DEVICE_FEATURES_SINK_SUPP_ARC_TX (1 << 2) +#define HDMI_CEC_DEVICE_FEATURES_SRC_SUPP_ARC_RX (1 << 1) + +/* + * System Information Feature. + * Used by a device to request another device's features. + * Param: None. + */ +#define HDMI_CEC_OPCODE_GIVE_FEATURES 0xA5 + +/* + * Deck Control Feature. + * Used to control a device's media functions. + * Param: [Deck Control Mode], 1 byte. + */ +#define HDMI_CEC_OPCODE_DECK_CONTROL 0x42 + +#define HDMI_CEC_DECK_CONTROL_MSG_PARAM_LEN 1 + +/* Deck Control Mode */ +enum HdmiCecDeckControlMode { + HDMI_CEC_DECK_CONTROL_MODE_SKIP_FWD = 1, + HDMI_CEC_DECK_CONTROL_MODE_SKIP_REV = 2, + HDMI_CEC_DECK_CONTROL_MODE_STOP = 3, + HDMI_CEC_DECK_CONTROL_MODE_EJECT = 4, +}; + +/* + * Deck Control Feature. + * Used to provide a deck's status to the indicate of the message. + * Param: [Deck Info], 1 byte. + */ +#define HDMI_CEC_OPCODE_DECK_STATUS 0x1B + +#define HDMI_CEC_DECK_STATUS_MSG_PARAM_LEN 1 + +/* Deck Info. Indicate the current status of a tape or disk deck. */ +enum HdmiCecDeckInfo { + HDMI_CEC_DECK_PLAY = 0x11, + HDMI_CEC_DECK_RECORD = 0x12, + HDMI_CEC_DECK_PLAY_REVERSE = 0x13, + HDMI_CEC_DECK_STILL = 0x14, + HDMI_CEC_DECK_SLOW = 0x15, + HDMI_CEC_DECK_SLOW_REVERSE = 0x16, + HDMI_CEC_DECK_FAST_FORWARD = 0x17, + HDMI_CEC_DECK_FAST_REVERSE = 0x18, + HDMI_CEC_DECK_NO_MEDIA = 0x19, + HDMI_CEC_DECK_STOP = 0x1A, + HDMI_CEC_DECK_SKIP_FORWARD = 0x1B, + HDMI_CEC_DECK_SKIP_REVERSE = 0x1C, + HDMI_CEC_DECK_INDEX_SEARCH_FORWARD = 0x1D, + HDMI_CEC_DECK_INDEX_SEARCH_REVERSE = 0x1E, + HDMI_CEC_DECK_OTHER_STATUS = 0x1F, +}; + +/* + * Deck Control Feature. + * Used to request the status of a device, + * regardless of whether or not it is the current active source. + * Param: [Status Request], 1 byte. + */ +#define HDMI_CEC_OPCODE_GIVE_DECK_STATUS 0x1A + +#define HDMI_CEC_GIVE_DECK_STATUS_MSG_PARAM_LEN 1 + +/* Status Request */ +enum HdmiCecStatusRequest { + HDMI_CEC_STATUS_REQUEST_ON = 1, + HDMI_CEC_STATUS_REQUEST_OFF = 2, + HDMI_CEC_STATUS_REQUEST_ONCE = 3, +}; + +/* + * Deck Control Feature. + * Used to control the playback bahavior of a source device. + * Param: [Play Mode], 1 byte. + */ +#define HDMI_CEC_OPCODE_PLAY 0x41 + +#define HDMI_CEC_PLAY_MSG_PARAM_LEN 1 + +/* Play Mode */ +enum HdmiCecPlayMode { + HDMI_CEC_PLAY_MODE_PLAY_FAST_FWD_MIN = 0x05, + HDMI_CEC_PLAY_MODE_PLAY_FAST_FWD_MED = 0x06, + HDMI_CEC_PLAY_MODE_PLAY_FAST_FWD_MAX = 0x07, + HDMI_CEC_PLAY_MODE_PLAY_FAST_REV_MIN = 0x09, + HDMI_CEC_PLAY_MODE_PLAY_FAST_REV_MED = 0x0A, + HDMI_CEC_PLAY_MODE_PLAY_FAST_REV_MAX = 0x0B, + HDMI_CEC_PLAY_MODE_PLAY_SLOW_FWD_MIN = 0x15, + HDMI_CEC_PLAY_MODE_PLAY_SLOW_FWD_MED = 0x16, + HDMI_CEC_PLAY_MODE_PLAY_SLOW_FWD_MAX = 0x17, + HDMI_CEC_PLAY_MODE_PLAY_SLOW_REV_MIN = 0x19, + HDMI_CEC_PLAY_MODE_PLAY_SLOW_REV_MED = 0x1A, + HDMI_CEC_PLAY_MODE_PLAY_SLOW_REV_MAX = 0x1B, + HDMI_CEC_PLAY_MODE_PLAY_REV = 0x20, + HDMI_CEC_PLAY_MODE_PLAY_FWD = 0x24, + HDMI_CEC_PLAY_MODE_PLAY_STILL = 0x25, +}; + +/* + * Tuner Control Feature. + * Used to request the status of a tuner device. + * Param: [Status Request], 1 byte. + */ +#define HDMI_CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS 0x08 + +#define HDMI_CEC_GIVE_TUNER_DEVICE_STATU_MSG_PARAM_LEN 1 + +/* + * Tuner Control Feature. + * Directly selects a Digital TV, Radio or Data Briadcast service. + * Param: [Digital Service Identification], 7 bytes. + */ +#define HDMI_CEC_OPCODE_SELECT_DIGITAL_SERVICE 0x93 + +#define HDMI_CEC_SELECT_DIGITAL_SERVICE_MSG_PARAM_LEN HDMI_CEC_DIGITAL_SERVICE_ID_LEN + +/* + * Tuner Control Feature. + * Used by a tuner device to provide its status to the initiator of + * the message. + * Param: [Tuner Device Info], 5 bytes(analogue service), 8 bytes(digital service). + */ +#define HDMI_CEC_OPCODE_TUNER_DEVICE_STATUS 0x07 + +#define HDMI_CEC_TUNER_DEVICE_STATUS_MSG_ANA_PARAM_LEN 5 +#define HDMI_CEC_TUNER_DEVICE_STATUS_MSG_DIG_PARAM_LEN 8 + +/* + * Tuner Device Info, 5 bytes(analogue service), 8 bytes(digital service). + * [Recording Flag], 1 bit. [Tuner Display Info], 7 bits. + * {[Analogue Broadcast Type], 1 byte. [Analogue Frequency], 2 bytes. [Broadcast System], 1 byte.} | + * {[Digital Service Identification], 7 bytes}. + */ +#define HDMI_CEC_RECORDING_FALG_NOT_USED 0 +#define HDMI_CEC_RECORDING_FALG_USED 1 + +enum HdmiCecTunerDisplayInfo { + HDMI_CEC_TUNER_DISP_DIGITAL = 0, + HDMI_CEC_TUNER_DISP_NOT_DISP = 1, + HDMI_CEC_TUNER_DISP_ANALOGUE = 2, +}; + +struct HdmiCecTunerDeviceInfo { + uint8_t recordingFlag; + uint8_t dispInfo; + bool isAnalogService; + union { + struct HdmiCecDigitalServiceId digital; + struct { + uint8_t anaBcastType; + uint16_t anaFreq; + uint8_t bcstSystem; + } analog; + } data; +}; + +/* + * Tuner Control Feature. + * Used to tune to next lowest service in a tuner's service list. Can used for PIP. + * Param: None. + */ +#define HDMI_CEC_OPCODE_TUNER_STEP_DECREMENT 0x06 + +/* + * Tuner Control Feature. + * Used to tune to next highest service in a tuner's service list. Can used for PIP. + * Param: None. + */ +#define HDMI_CEC_OPCODE_TUNER_STEP_INCREMENT 0x05 + +/* + * Vendor Specific Commands Feature. + * Reports the vendor ID of this device. + * Param: [Vendor ID], 3 bytes. + * Broadcast message. + */ +#define HDMI_CEC_OPCODE_DEVICE_VENDOR_ID 0x87 + +#define HDMI_CEC_DEVICE_VENDOR_ID_MSG_PARAM_LEN 3 + +/* + * Indicates the vendor ID should be disabled. + */ +#define HDMI_CEC_VENDOR_ID_UNKNOWN 0xFFFFFFFF + +/* + * Vendor Specific Commands Feature. + * Requests the Vendor ID from a device. + * Param: None. + */ +#define HDMI_CEC_OPCODE_GIVE_DEVICE_VENDOR_ID 0x8C + +/* + * Vendor Specific Commands Feature. + * Allows vendor specific commands to be sent between two devices. + * Param: [Vendor Specific Data], <= 14 bytes. + */ +#define HDMI_CEC_OPCODE_VENDOR_COMMAND 0x89 + +#define HDMI_CEC_VENDOR_SPECIFIC_DATA_MAX_LEN 14 + +/* + * Vendor Specific Commands Feature. + * Allows vendor specific commands to be sent between two devices or broadcast. + * Param: [Vendor ID], 3 bytes. [Vendor Specific Data], <= 11 bytes. + * Broadcast/Directly addressed message. + */ +#define HDMI_CEC_OPCODE_VENDOR_COMMAND_WITH_ID 0xA0 + +#define HDMI_CEC_VENDOR_ID_LEN 3 +#define HDMI_CEC_VENDOR_SPECIFIC_DATA_WITH_ID_MAX_LEN 11 + +/* + * Vendor Specific Commands Feature. + * Indicates that a remote control button has been depressed. + * Param: [Vendor Specific RC Code], <= 14 bytes. + * Broadcast/Directly addressed message. + */ +#define HDMI_CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN 0x8A + +#define HDMI_CEC_VENDOR_SPECIFIC_RC_CODE_MAX_LEN 14 + +/* + * Vendor Specific Commands Feature. + * Indicates that a remote control button(the last button pressed indicated + * by the Vendor Remote Button Down message) has been released. + * Param: None. + * Broadcast/Directly addressed message. + */ +#define HDMI_CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP 0x8B + +/* + * OSD Display Feature. + * Used to send a text massage to output on a TV. + * OSD(on-screen display). + * Param: [Display Control], 1 byte. [OSD String], 1-13 bits. + */ +#define HDMI_CEC_OPCODE_SET_OSD_STRING 0x64 + +#define HDMI_CEC_DISPLAY_CONTROL_LEN 1 +#define HDMI_CEC_OSD_STRING_MAX_LEN 13 + +/* Display Control */ +enum HdmiCecDisplayControl { + HDMI_CEC_DISPLAY_FOR_DEFAULT_TIME = 0x00, + HDMI_CEC_DISPLAY_UNTIL_CLEARED = 0x40, + HDMI_CEC_DISPLAY_CLEAR_PREVIOUS_MESSAGE = 0x80, + HDMI_CEC_DISPLAY_BUTT, +}; + +/* + * OSD Display Feature. + * Used to request the preferred OSD name of a device for use in menus associated with that device. + * Param: None. + */ +#define HDMI_CEC_OPCODE_GIVE_OSD_NAME 0x46 + +/* + * OSD Display Feature. + * Used to set the preferred OSD name of a device for use in menus associated with that device. + * Param: [OSD Name], 1-14 bytes. + */ +#define HDMI_CEC_OPCODE_SET_OSD_NAME 0x47 + +#define HDMI_CEC_OSD_NAME_MAX_LEN 14 + +/* + * Device Menu Control Feature. + * A request from the TV for a device to show/remove a menu or to + * query if a device is currently showing a menu. + * Param: [Menu Request Type], 1 byte. + */ +#define HDMI_CEC_OPCODE_MENU_REQUEST 0x8D + +#define HDMI_CEC_MENU_REQUEST_MSG_PARAM_LEN 1 + +/* Menu Request Type */ +enum HdmiCecMenuRequestType { + HDMI_CEC_MENU_REQUEST_ACTIVE = 0, + HDMI_CEC_MENU_REQUEST_DEACTIVE = 1, + HDMI_CEC_MENU_REQUEST_QUERY = 2, +}; + +/* + * Device Menu Control Feature. + * Used to indicate to the TV that the device is showing/has removed a menu and + * requests the remote control keys to be passed throuh. + * Param: [Menu State], 1 byte. + */ +#define HDMI_CEC_OPCODE_MENU_STATUS 0x8E + +#define HDMI_CEC_MENU_STATUS_MSG_PARAM_LEN 1 + +/* Menu State */ +#define HDMI_CEC_MENU_STATE_ACTIVE 0 +#define HDMI_CEC_MENU_STATE_DEACTIVE 1 + +/* + * Device Menu Control Feature/Remote Contro Passthrough Feature/System Audio Control Feature. + * Used to indicate that the user pressed a remote control button or switched from + * one remote control button to another. Can also be used as a command that is not directly initiated by the user. + * Param: [UI Command], 1 byte. + * Note that some [UI Command] messages also have further operands. See CEC Table 6 and CEC Table 7. + */ +#define HDMI_CEC_OPCODE_USER_CONTROL_PRESSED 0x44 + +#define HDMI_CEC_UI_COMMAND_LEN 1 + +/* UI Command */ +enum HdmiCecUiCmdType { + HDMI_CEC_UI_CMD_SELECT = 0x00, + HDMI_CEC_UI_CMD_UP = 0x01, + HDMI_CEC_UI_CMD_DOWN = 0x02, + HDMI_CEC_UI_CMD_LEFT = 0x03, + HDMI_CEC_UI_CMD_RIGHT = 0x04, + HDMI_CEC_UI_CMD_RIGHT_UP = 0x05, + HDMI_CEC_UI_CMD_RIGHT_DOWN = 0x06, + HDMI_CEC_UI_CMD_LEFT_UP = 0x07, + HDMI_CEC_UI_CMD_LEFT_DOWN = 0x08, + HDMI_CEC_UI_CMD_DEVICE_ROOT_MENU = 0x09, + HDMI_CEC_UI_CMD_DEVICE_SETUP_MENU = 0x0a, + HDMI_CEC_UI_CMD_CONTENTS_MENU = 0x0b, + HDMI_CEC_UI_CMD_FAVORITE_MENU = 0x0c, + HDMI_CEC_UI_CMD_EXIT = 0x0d, + HDMI_CEC_UI_CMD_MEDIA_TOP_MENU = 0x10, + HDMI_CEC_UI_CMD_MEDIA_CONTEXT_SENSITIVE_MENU = 0x11, + HDMI_CEC_UI_CMD_NUMBER_ENTRY_MODE = 0x1d, + HDMI_CEC_UI_CMD_NUMBER_11 = 0x1e, + HDMI_CEC_UI_CMD_NUMBER_12 = 0x1f, + HDMI_CEC_UI_CMD_NUMBER_0_OR_NUMBER_10 = 0x20, + HDMI_CEC_UI_CMD_NUMBER_1 = 0x21, + HDMI_CEC_UI_CMD_NUMBER_2 = 0x22, + HDMI_CEC_UI_CMD_NUMBER_3 = 0x23, + HDMI_CEC_UI_CMD_NUMBER_4 = 0x24, + HDMI_CEC_UI_CMD_NUMBER_5 = 0x25, + HDMI_CEC_UI_CMD_NUMBER_6 = 0x26, + HDMI_CEC_UI_CMD_NUMBER_7 = 0x27, + HDMI_CEC_UI_CMD_NUMBER_8 = 0x28, + HDMI_CEC_UI_CMD_NUMBER_9 = 0x29, + HDMI_CEC_UI_CMD_DOT = 0x2a, + HDMI_CEC_UI_CMD_ENTER = 0x2b, + HDMI_CEC_UI_CMD_CLEAR = 0x2c, + HDMI_CEC_UI_CMD_NEXT_FAVORITE = 0x2f, + HDMI_CEC_UI_CMD_CHANNEL_UP = 0x30, + HDMI_CEC_UI_CMD_CHANNEL_DOWN = 0x31, + HDMI_CEC_UI_CMD_PREVIOUS_CHANNEL = 0x32, + HDMI_CEC_UI_CMD_SOUND_SELECT = 0x33, + HDMI_CEC_UI_CMD_INPUT_SELECT = 0x34, + HDMI_CEC_UI_CMD_DISPLAY_INFORMATION = 0x35, + HDMI_CEC_UI_CMD_HELP = 0x36, + HDMI_CEC_UI_CMD_PAGE_UP = 0x37, + HDMI_CEC_UI_CMD_PAGE_DOWN = 0x38, + HDMI_CEC_UI_CMD_POWER = 0x40, + HDMI_CEC_UI_CMD_VOLUME_UP = 0x41, + HDMI_CEC_UI_CMD_VOLUME_DOWN = 0x42, + HDMI_CEC_UI_CMD_MUTE = 0x43, + HDMI_CEC_UI_CMD_PLAY = 0x44, + HDMI_CEC_UI_CMD_STOP = 0x45, + HDMI_CEC_UI_CMD_PAUSE = 0x46, + HDMI_CEC_UI_CMD_RECORD = 0x47, + HDMI_CEC_UI_CMD_REWIND = 0x48, + HDMI_CEC_UI_CMD_FAST_FORWARD = 0x49, + HDMI_CEC_UI_CMD_EJECT = 0x4a, + HDMI_CEC_UI_CMD_SKIP_FORWARD = 0x4b, + HDMI_CEC_UI_CMD_SKIP_BACKWARD = 0x4c, + HDMI_CEC_UI_CMD_STOP_RECORD = 0x4d, + HDMI_CEC_UI_CMD_PAUSE_RECORD = 0x4e, + HDMI_CEC_UI_CMD_ANGLE = 0x50, + HDMI_CEC_UI_CMD_SUB_PICTURE = 0x51, + HDMI_CEC_UI_CMD_VIDEO_ON_DEMAND = 0x52, + HDMI_CEC_UI_CMD_ELECTRONIC_PROGRAM_GUIDE = 0x53, + HDMI_CEC_UI_CMD_TIMER_PROGRAMMING = 0x54, + HDMI_CEC_UI_CMD_INITIAL_CONFIGURATION = 0x55, + HDMI_CEC_UI_CMD_SELECT_BROADCAST_TYPE = 0x56, /* Additional Operands: [UI Broadcast Type] */ + HDMI_CEC_UI_CMD_SELECT_SOUND_PRESENTATION = 0x57, /* Additional Operands: [UI Sound Presentation Control] */ + HDMI_CEC_UI_CMD_AUDIO_DESCRIPTION = 0x58, + HDMI_CEC_UI_CMD_INTERNET = 0x59, + HDMI_CEC_UI_CMD_3D_MODE = 0x5a, + HDMI_CEC_UI_CMD_PLAY_FUNCTION = 0x60, /* Additional Operands: [Play Mode] */ + HDMI_CEC_UI_CMD_PAUSE_PLAY_FUNCTION = 0x61, + HDMI_CEC_UI_CMD_RECORD_FUNCTION = 0x62, + HDMI_CEC_UI_CMD_PAUSE_RECORD_FUNCTION = 0x63, + HDMI_CEC_UI_CMD_STOP_FUNCTION = 0x64, + HDMI_CEC_UI_CMD_MUTE_FUNCTION = 0x65, + HDMI_CEC_UI_CMD_RESTORE_VOLUME_FUNCTION = 0x66, + HDMI_CEC_UI_CMD_TUNE_FUNCTION = 0x67, /* Additional Operands: [Channel Identifier] */ + HDMI_CEC_UI_CMD_SELECT_MEDIA_FUNCTION = 0x68, /* Additional Operands: [UI Function Media] */ + HDMI_CEC_UI_CMD_SELECT_AV_INPUT_FUNCTION = 0x69, /* Additional Operands: [UI Function Select A/V Input] */ + HDMI_CEC_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION = 0x6a, /* Additional Operands: [UI Function Select Audio Input] */ + HDMI_CEC_UI_CMD_POWER_TOGGLE_FUNCTION = 0x6b, + HDMI_CEC_UI_CMD_POWER_OFF_FUNCTION = 0x6c, + HDMI_CEC_UI_CMD_POWER_ON_FUNCTION = 0x6d, + HDMI_CEC_UI_CMD_F1_BLUE = 0x71, + HDMI_CEC_UI_CMD_F2_RED = 0x72, + HDMI_CEC_UI_CMD_F3_GREEN = 0x73, + HDMI_CEC_UI_CMD_F4_YELLOW = 0x74, + HDMI_CEC_UI_CMD_F5 = 0x75, + HDMI_CEC_UI_CMD_DATA = 0x76, +}; + +enum HdmiCecUiBroadcastType { + HDMI_CEC_UI_BROADCAST_TYPE_TOGGLE_ALL = 0x00, + HDMI_CEC_UI_BROADCAST_TYPE_TOGGLE_DIG_ANA = 0x01, + HDMI_CEC_UI_BROADCAST_TYPE_ANA = 0x10, + HDMI_CEC_UI_BROADCAST_TYPE_ANA_TERRESTRIAL = 0x20, + HDMI_CEC_UI_BROADCAST_TYPE_ANA_CABLE = 0x30, + HDMI_CEC_UI_BROADCAST_TYPE_ANA_SATELLITE = 0x40, + HDMI_CEC_UI_BROADCAST_TYPE_DIG = 0x50, + HDMI_CEC_UI_BROADCAST_TYPE_DIG_TERRESTRIAL = 0x60, + HDMI_CEC_UI_BROADCAST_TYPE_DIG_CABLE = 0x70, + HDMI_CEC_UI_BROADCAST_TYPE_DIG_SATELLITE = 0x80, + HDMI_CEC_UI_BROADCAST_TYPE_DIG_COM_SATELLITE = 0x90, + HDMI_CEC_UI_BROADCAST_TYPE_DIG_COM_SATELLITE2 = 0x91, + HDMI_CEC_UI_BROADCAST_TYPE_IP = 0xA0, +}; + +/* UI Sound Presentation Control */ +enum HdmiCecUiSoundPresCtl { + HDMI_CEC_UI_SOUND_PRES_CTL_DUAL_MONO = 0x20, + HDMI_CEC_UI_SOUND_PRES_CTL_KARAOKE = 0x30, + HDMI_CEC_UI_SOUND_PRES_CTL_DOWNMIX = 0x80, + HDMI_CEC_UI_SOUND_PRES_CTL_REVERB_PROCESS = 0x90, + HDMI_CEC_UI_SOUND_PRES_CTL_EQUALIZER = 0xA0, + HDMI_CEC_UI_SOUND_PRES_CTL_BASS_STEP_UP = 0xB1, + HDMI_CEC_UI_SOUND_PRES_CTL_BASS_NEUTRAL = 0xB2, + HDMI_CEC_UI_SOUND_PRES_CTL_BASS_STEP_DOWN = 0xB3, + HDMI_CEC_UI_SOUND_PRES_CTL_TREBLE_STEP_UP = 0xC1, + HDMI_CEC_UI_SOUND_PRES_CTL_TREBLE_NEUTRAL = 0xC2, + HDMI_CEC_UI_SOUND_PRES_CTL_TREBLE_STEP_DOWN = 0xC3, +}; + +struct HdmiCecUiCmd { + uint8_t cmdType; + bool hasAddOp; + union { + uint8_t uiBroadcastType; + uint8_t uiSoundPresCtl; + uint8_t playMode; + uint8_t uiFunctionMedia; + uint8_t uiFunctionSelectAvInput; + uint8_t uiFunctionSelectAudioInput; + struct HdmiCecChannelIdentifier channel; + } addOperands; +}; + +/* + * Device Menu Control Feature/Remote Contro Passthrough Feature/System Audio Control Feature. + * Indicates that user released a remote control button(the last one indicated by the + * message). Also used after a command that is not directly initiated by the user. + * Param: None. + */ +#define HDMI_CEC_OPCODE_USER_CONTROL_RELEASED 0x45 + +/* + * Remote Contro Passthrough Feature. + * Used to determine the current power status of a target device. + * Param: None. + */ +#define HDMI_CEC_OPCODE_GIVE_DEVICE_POWER_STATUS 0x8F + +/* + * Remote Contro Passthrough Feature. + * Used to inform a requesting device of the current power status. + * Param: [Power Status], 1 byte. + * Broadcast(Hdmi Spec2.0)/Directly addressed message. + */ +#define HDMI_CEC_OPCODE_REPORT_POWER_STATUS 0x90 + +#define HDMI_CEC_REPORT_POWER_STATUS_MSG_PARA_LEN 1 + +/* Power Status */ +enum HdmiCecPowerStatus { + HDMI_CEC_POWER_STATUS_ON = 0x00, + HDMI_CEC_POWER_STATUS_STANDBY = 0x01, + HDMI_CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON = 0x02, + HDMI_CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY = 0x03, +}; + +/* + * General Protocol Messages. + * Used as a response to indicate that the device does not support the requested message type, + * or that is cannot execute it at the present time. + * Param: [Feature Opcode], 1 byte. [Abort Reason], 1 byte. + */ +#define HDMI_CEC_OPCODE_FEATURE_ABORT 0x00 + +#define HDMI_CEC_FEATURE_ABORT_MSG_PARA_LEN 2 + +/* Abort Reason */ +enum HdmiCecAbortReason { + HDMI_CEC_ABORT_UNRECOGNIZED_OPCODE = 0, + HDMI_CEC_ABORT_NOT_IN_CORRECT_MODE_TO_RESPOND = 1, + HDMI_CEC_ABORT_CANNOT_PROVIDE_SOURCE = 2, + HDMI_CEC_ABORT_INVALID_OPERAND = 3, + HDMI_CEC_ABORT_REFUSED = 4, + HDMI_CEC_ABORT_UNABLE_TO_DETERMINE = 5, +}; + +/* + * General Protocol Messages. + * This message is reversed for testing purposes. + * Param: None. + */ +#define HDMI_CEC_OPCODE_ABORT 0xFF + +/* + * System Audio Control Feature. + * Requests an Amplifier to send its volume and mute status. + * Param: None. + */ +#define HDMI_CEC_OPCODE_GIVE_AUDIO_STATUS 0x71 + +/* + * System Audio Control Feature. + * Requests the status of the System Audio Mode. + * Param: None. + */ +#define HDMI_CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS 0x7D + +/* + * System Audio Control Feature. + * Reports an Amplifier's volume and mute status. + * Param: [Audio Status], 1 byte. + */ +#define HDMI_CEC_OPCODE_REPORT_AUDIO_STATUS 0x7A + +#define HDMI_CEC_REPORT_AUDIO_STATUSMSG_PARAM_LEN 1 + +/* + * Audio Status, 1 byte. + * [Audio Mute Status], Bit 7; [Audio Volume Status], Bits 6-0. + */ +#define HDMI_CEC_AUDIO_MUTE_STATUS_MARK 0x80 +#define HDMI_CEC_AUDIO_MUTE_STATUS_SHIFT 7 +#define HDMI_CEC_AUDIO_VOLUME_STATUS_MARK 0x7F +/* Audio Mute Status */ +#define HDMI_CEC_AUDIO_MUTE_STATUS_OFF 0 +#define HDMI_CEC_AUDIO_MUTE_STATUS_ON 1 +/* Audio Volume Status, 0%~100% */ +#define HDMI_CEC_AUDIO_VOLUME_STATUS_MIN_VAL 0x00 +#define HDMI_CEC_AUDIO_VOLUME_STATUS_MAX_VAL 0x64 +#define HDMI_CEC_AUDIO_VOLUME_STATUS_UNKNOWN 0x7F + +/* + * System Audio Control Feature. + * Report Audio Capability. + * Param: [Short Audio Descriptor], 3 bytes. Up to 4 Short Audio Descriptor identifying supported audio formats. + */ +#define HDMI_CEC_OPCODE_REPORT_SHORT_AUDIO_DESCRIPTOR 0xA3 + +#define HDMI_CEC_SHORT_AUDIO_DESCRIPTOR_LEN 3 +#define HDMI_CEC_MAX_SHORT_AUDIO_DESCRIPTOR_NUM 4 + +/* + * System Audio Control Feature. + * Report Audio Capability. + * Param: [Audio Format ID], 2 bits. [Audio Format Code], 6 bits. Up to 4 Audio Format ID and Audio Format Code. + */ +#define HDMI_CEC_OPCODE_REQUEST_SHORT_AUDIO_DESCRIPTOR 0xA4 + +#define HDMI_CEC_AUDIO_FORMAT_LEN 1 +#define HDMI_CEC_MAX_AUDIO_FORMAT_NUM 4 +#define HDMI_CEC_AUDIO_FORMAT_ID_SHIFT 6 +#define HDMI_CEC_AUDIO_FORMAT_CODE_MARK 0x3F + +/* + * System Audio Control Feature. + * Turns the System Audio Mode On or Off. + * Param: [System Audio Status], 1 byte. + * Broadcast/Directly addressed message. + */ +#define HDMI_CEC_OPCODE_SET_SYSTEM_AUDIO_MODE 0x72 + +#define HDMI_CEC_SYSTEM_AUDIO_STATUS_LEN 1 + +/* System Audio Status */ +#define HDMI_CEC_SYSTEM_AUDIO_STATUS_OFF 0 +#define HDMI_CEC_SYSTEM_AUDIO_STATUS_ON 1 + +/* + * System Audio Control Feature. + * A device implementing System Audio Control and which has volume control + * RC buttons(e.g. TV or STB) requests to use System Audio Mode to the Amplifier. + # Param: [Physical Address], 2 bytes. + */ +#define HDMI_CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST 0x70 + +#define HDMI_CEC_SYSTEM_AUDIO_MODE_REQUEST_PARAM_LEN 2 + +/* + * System Audio Control Feature. + * Reports the current status of the System Audio Mode. + * Param: [System Audio Status], 1 byte. + */ +#define HDMI_CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS 0x7E + +/* + * Audio Rate Control Feature. + * Used to control audio rate from Source Device. + * Param: [Audio Rate], 1 byte. + */ +#define HDMI_CEC_OPCODE_SET_AUDIO_RATE 0x9A + +#define HDMI_CEC_SET_AUDIO_RATE_PARAM_LEN 1 + +/* Audio Rate */ +enum HdmiCecAudioRate { + HDMI_CEC_AUDIO_RATE_OFF = 0, /* Rate Control Off */ + HDMI_CEC_AUDIO_RATE_WIDE_STD = 1, /* Standard Rate: 100% rate */ + HDMI_CEC_AUDIO_RATE_WIDE_FAST = 2, /* Fast Rate: Max 101% rate */ + HDMI_CEC_AUDIO_RATE_WIDE_SLOW = 3, /* Slow Rate: Min 99% rate */ + HDMI_CEC_AUDIO_RATE_NARROW_STD = 4, /* Standard Rate: 100.0% rate */ + HDMI_CEC_AUDIO_RATE_NARROW_FAST = 5, /* Fast Rate: Max 100.1% rate */ + HDMI_CEC_AUDIO_RATE_NARROW_SLOW = 6, /* Slow Rate: Min 99.9% rate */ +}; + +/* + * Audio Return Channel Control Feature. + * Used by an ARC RX device to active the ARC functionality in an ARC TX device. + * Param: None. + */ +#define HDMI_CEC_OPCODE_INITIATE_ARC 0xC0 + +/* + * Audio Return Channel Control Feature. + * Used by an ARC RX device to indicate that its ARC functionality has been actived. + * Param: None. + */ +#define HDMI_CEC_OPCODE_REPORT_ARC_INITIATED 0xC1 + +/* + * Audio Return Channel Control Feature. + * Used by an ARC RX device to indicate that its ARC functionality has been deactived. + * Param: None. + */ +#define HDMI_CEC_OPCODE_REPORT_ARC_TERMINATION 0xC2 + +/* + * Audio Return Channel Control Feature. + * Used by an ARC TX device to request an ARC RX device to + * active the ARC functionality in the ARC TX device. + * Param: None. + */ +#define HDMI_CEC_OPCODE_REQUEST_ARC_INITIATION 0xC3 + +/* + * Audio Return Channel Control Feature. + * Used by an ARC TX device to request an ARC RX device to + * deactive the ARC functionality in the ARC TX device. + * Param: None. + */ +#define HDMI_CEC_OPCODE_REQUEST_ARC_TERMINATION 0xC4 + +/* + * Audio Return Channel Control Feature. + * Used by an ARC TX device to deactive the ARC functionality in the ARC TX device. + * Param: None. + */ +#define HDMI_CEC_OPCODE_TERMINATE_ARC 0xC5 + +/* + * Capability Discovery and Control Feature. + * Used for Capability Discovery and Control. + * Broadcast message. + */ +#define HDMI_CEC_OPCODE_CDC_MESSAGE 0xF8 + +/* + * Dynamic Auto Lispync Feature. + * Used by Amplifier(or other device) to request current latency values. + * Param: [Physical Address], 2 byte. + */ +#define HDMI_CEC_OPCODE_REQUEST_CURRENT_LATENCY 0xA7 + +#define HDMI_CEC_REQUEST_CURRENT_LATENCY_MSG_LEN 2 + +/* + * Dynamic Auto Lispync Feature. + * Used by TV(or other Initiator) to report updates of latency. + * Param: [Physical Address], 2 byte. [Video Latency], 1 byte. [Latency Flags], 1 byte. + * [Audio Output Delay], 1 byte, optional. + */ +#define HDMI_CEC_OPCODE_REPORT_CURRENT_LATENCY 0xA8 + +#define HDMI_CEC_REPORT_CURRENT_LATENCY_MSG_PARAM_MAX_LEN 5 +#define HDMI_CEC_REPORT_CURRENT_LATENCY_MSG_PARAM_MIN_LEN 4 + +/* + * Latency Flags, 1 byte. + * Bit 7..3 reversed; Bit 2 [Low Latency Mode]; Bit 1-0 [Audio Output Compensated]. + */ +#define HDMI_CEC_LOW_LATENCY_MODE_SHIFT 2 +#define HDMI_CEC_NORMAL_LATENCY_MODE 0 +#define HDMI_CEC_LOW_LATENCY_MODE 1 + +#define HDMI_CEC_AUDIO_OUTPUT_COMPENSATED_NA 0 +#define HDMI_CEC_AUDIO_OUTPUT_COMPENSATED_DELAY 1 +#define HDMI_CEC_AUDIO_OUTPUT_COMPENSATED_NO_DELAY 2 +#define HDMI_CEC_AUDIO_OUTPUT_COMPENSATED_PARTIAL_DELAY 3 + +struct HdmiCecLatencyInfo { + uint8_t videoLatency; + uint8_t lowLatencyMode; + uint8_t audioOutputCompensated; + uint8_t audioOutputDelay; +}; + + +/* Broadcast System, 0~31. See hdmi spec1.4, CEC Table 31. */ +enum HdmiCecBroadcastSystem { + HDMI_CEC_BROADCAST_SYSTEM_PAL_BG = 0, + HDMI_CEC_BROADCAST_SYSTEM_SECAM_LQ = 1, + HDMI_CEC_BROADCAST_SYSTEM_PAL_M = 2, + HDMI_CEC_BROADCAST_SYSTEM_NTSC_M = 3, + HDMI_CEC_BROADCAST_SYSTEM_PAL_I = 4, + HDMI_CEC_BROADCAST_SYSTEM_SECAM_DK = 5, + HDMI_CEC_BROADCAST_SYSTEM_SECAM_BG = 6, + HDMI_CEC_BROADCAST_SYSTEM_SECAM_L = 7, + HDMI_CEC_BROADCAST_SYSTEM_PAL_DK = 8, + HDMI_CEC_BROADCAST_SYSTEM_OTHER = 31, +}; + +/* CDC(Capability Discovery and Control) Message */ + +/* + * HDMI Ethernet Channel Feature. + * Used to inquire the state of an HDMI Ethernet Channel. + * Param: [Physical Address], 2 byte. [Physical Address], 2 byte. + */ +#define HDMI_CDC_HEC_INQUIRE_STATE 0x00 + +#define HDMI_CDC_HEC_INQUIRE_STATE_MSG_PARAM_LEN 4 + +/* + * HDMI Ethernet Channel Feature. + * Used to report capabilities and states of a device that supports functionality. + * Param: [Physical Address], 2 bytes. [HEC State], 1 byte. [HEC Support Field], 2 bytes. + * [HEC Activation Field], 2 bytes. + */ +#define HDMI_CDC_HEC_REPORT_STATE 0x01 + +#define HDMI_CDC_HEC_REPORT_STATE_MSG_PARAM_MAX_LEN 5 +#define HDMI_CDC_HEC_REPORT_STATE_MSG_PARAM_MIN_LEN 3 + +/* + * HEC State, 1 byte + * [HEC Functionality State], 2 bits. + * [Host Functionality State], 2 bits. + * [ENC Functionality State], 2 bits. + * [CDC Error Code], 2 bits. + */ +#define HDMI_CDC_HEC_FUNC_STATE_SHIFT 6 +#define HDMI_CDC_HOST_FUNC_STATE_SHIFT 4 +#define HDMI_CDC_ENC_FUNC_STATE_SHIFT 2 + +enum HdmiCdcHecFuncState { + HDMI_CDC_HEC_FUNC_STATE_NOT_SUPPORTED = 0, + HDMI_CDC_HEC_FUNC_STATE_INACTIVE = 1, + HDMI_CDC_HEC_FUNC_STATE_ACTIVE = 2, + HDMI_CDC_HEC_FUNC_STATE_ACTIVATION_FIELD = 3, +}; + +enum HdmiCdcHostFuncState { + HDMI_CDC_HOST_HEC_STATE_NOT_SUPPORTED = 0, + HDMI_CDC_HOST_HEC_STATE_NOT_INACTIVE = 1, + HDMI_CDC_HOST_HEC_STATE_NOT_ACTIVE = 2, +}; + +enum HdmiCdcEncFuncState { + HDMI_CDC_ENC_FUNC_STATE_EXT_CON_NOT_SUPPORTED = 0, + HDMI_CDC_ENC_FUNC_STATE_EXT_CON_INACTIVE = 1, + HDMI_CDC_ENC_FUNC_STATE_EXT_CON_ACTIVE = 2, +}; + +enum HdmiCdcErrCode { + HDMI_CDC_ERR_CODE_NO_ERROR = 0, + HDMI_CDC_ERR_CODE_CAP_UNSUPPORTED = 1, + HDMI_CDC_ERR_CODE_WRONG_STATE = 2, + HDMI_CDC_ERR_CODE_OTHER = 3, +}; + +/* + * HEC Support Field, 2 bytes. + * [HEC Support], Bit 14. {14[HEC Support]}, Bit 13-0. + */ +#define HDMI_CDC_HEC_SUPPORT_MAKR (1 << 14) +#define HDMI_CDC_HEC_NOT_SUPPORT 0 +#define HDMI_CDC_HEC_SUPPORT 1 + +/* + * HEC Activation Field, 2 bytes. + * [HEC Activation], Bit 14. {14[HEC Activation]}, Bit 13-0. + */ +#define HDMI_CDC_HEC_ACTIVATION_MAKR (1 << 14) +#define HDMI_CDC_HEC_INACTIVE 0 +#define HDMI_CDC_HEC_ACTIVE 1 + +struct HdmiCdcHecState { + uint8_t hecFuncState; + uint8_t hostFuncState; + uint8_t encFuncState; + uint8_t cdcErrCode; + bool haveHecField; + uint16_t hecField; +}; + +/* + * HDMI Ethernet Channel Feature. + * Used to active or de-active an HDMI Ethernet Channel to an adjacent device. + * Param: [Physical Address], 2 bytes. [HEC Set State], 1 byte. + */ +#define HDMI_CDC_HEC_SET_STATE_ADJACENT 0x02 + +#define HDMI_CDC_HEC_SET_STATE_ADJACENT_MSG_PARAM_LEN 3 + +/* HEC Set State, 1 byte. */ +#define HDMI_CDC_DEACTIVATE_HEC 0 +#define HDMI_CDC_ACTIVATE_HEC 1 + +/* + * HDMI Ethernet Channel Feature. + * Used to active or de-active an HDMI Ethernet Channel to an adjacent device. + * Param: [Physical Address], 2 bytes. [Physical Address], 2 bytes. [HEC Set State], 1 byte. + * [Physical Address], 2 bytes. [Physical Address], 2 bytes. [Physical Address], 2 bytes. + * The last three [PA] parameters shall not be incorporated if only one HEC shall activated. + */ +#define HDMI_CDC_HEC_SET_STATE 0x03 + +#define HDMI_CDC_HEC_SET_STATE_MSG_MIN_LEN 5 +#define HDMI_CDC_HEC_SET_STATE_MSG_OPTIONAL_PA_MAX_NUM 3 + +struct HemiCdcHecStateInfo { + uint16_t phyAddr1; + uint16_t phyAddr2; + uint8_t hecSetState; + uint16_t phyAddr[HDMI_CDC_HEC_SET_STATE_MSG_OPTIONAL_PA_MAX_NUM]; + uint32_t phyAddrLen; +}; + +/* + * HDMI Ethernet Channel Feature. + * Used to request the deactivation of an HDMI Ethernet Channel. + * Param: [Physical Address], 2 bytes. [Physical Address], 2 bytes. [Physical Address], 2 bytes. + */ +#define HDMI_CDC_HEC_REQUEST_DEACTIVATION 0x04 + +#define HDMI_CDC_HEC_REQUEST_DEACTIVATION_MSG_PHY_ADDR_NUM 3 +#define HDMI_CDC_HEC_REQUEST_DEACTIVATION_MSG_PARAM_LEN 6 + +/* + * HDMI Ethernet Channel Feature. + * Used to keep alive HDMI Ethernet Channels active. + */ +#define HDMI_CDC_HEC_NOTIFY_ALIVE 0x05 + +/* + * HDMI Ethernet Channel Feature. + * Used to discover all HEC capabilities of devices within the HDMI network. + */ +#define HDMI_CDC_HEC_DISCOVER 0x06 + +/* + * CDC HPD Feature. + * Used to substitute physical HPD pin signaling. + * Param: [Input port number], 4 bits. [HPD State], 4 bits. + */ +#define HDMI_CDC_HPD_SET_STATE 0x10 + +#define HDMI_CDC_HPD_SET_STATE_MSG_LEN 1 +#define HDMI_CDC_INPUT_PORT_NUMBER_SHIFT 4 + +enum HdmiCdcHpdState { + HDMI_CDC_HDP_STATE_CP_EDID_DISABLE = 0, + HDMI_CDC_HDP_STATE_CP_EDID_ENABLE = 1, + HDMI_CDC_HDP_STATE_CP_EDID_DISABLE_ENABLE = 2, + HDMI_CDC_HDP_STATE_EDID_DISABLE = 3, + HDMI_CDC_HDP_STATE_EDID_ENABLE = 4, + HDMI_CDC_HDP_STATE_EDID_DISABLE_ENABLE = 5, + HDMI_CDC_HDP_STATE_BUTT, +}; + +/* + * CDC HPD Feature. + * Used to report the state of a device using the CDC HPD signaling. + * Param: [HPD State], 4 bits. [CDC_HPD_Error_Code], 4 bits. + */ +#define CEC_MSG_CDC_HPD_REPORT_STATE 0x11 + +#define HDMI_CDC_HPD_REPORT_STATE_MSG_LEN 1 +#define HDMI_CDC_HPD_STATE_SHIFT 4 + +enum HdmiCdcHpdErrCode { + HDMI_CDC_HPD_NO_ERR = 0, + HDMI_CDC_HPD_ERR_INITIATOR_NOT_CAPABLE = 1, + HDMI_CDC_HPD_ERR_INITIATOR_WRONG_STATE = 2, + HDMI_CDC_HPD_ERR_OTHER = 3, + HDMI_CDC_HPD_NO_ERR_NO_VIDEO_STREAM = 4, + HDMI_CDC_HPD_ERR_BUTT, +}; + +/* + * CEC message frame. + * + * 1 block 1 block 0-14 blocks + * Start_Bit CEC_Header_Block CEC_Opcode_Block CEC_Operand_Blocks + * + * CDC message frame. + * + * 1 block 1 block 2 blocks 1 block 0~11 blocks + * Start_Bit CEC_Header_Block CEC_Opcode_Block(0xF8) Initiator_Phy_Address CDC_Opcode CDC_Parameters + * + * Header Block. + * high 4 bits low 4 bits + * Initiator Logic Address field Destination Logic Address field + * + */ +#define HDMI_CEC_MSG_MAX_LEN 20 /* Make sure it has enough space. */ +#define HDMI_CEC_HEADER_LEN 1 +#define HDMI_CEC_OPCODE_LEN 1 +#define HDMI_CEC_MSG_MIN_LEN (HDMI_CEC_HEADER_LEN + HDMI_CEC_OPCODE_LEN) +#define HDMI_POLLING_MSG_LEN 1 +#define HDMI_CEC_INITIATOR_PHY_ADDRESS_LEN 2 +#define HDMI_CEC_GET_MSG_LEN(len) (HDMI_CEC_HEADER_LEN + HDMI_CEC_OPCODE_LEN + len) +#define HDMI_CDC_OPCODE_LEN 1 +#define HDMI_CDC_GET_MSG_LEN(len) \ + (HDMI_CEC_HEADER_LEN + HDMI_CEC_OPCODE_LEN + HDMI_CEC_INITIATOR_PHY_ADDRESS_LEN + HDMI_CDC_OPCODE_LEN + len) + +#define HDMI_CEC_HEADER_BLOCK_INITIATOR_MARK 0xF0 +#define HDMI_CEC_HEADER_BLOCK_DESTINATION_MARK 0x0F +#define HDMI_CEC_HEADER_BLOCK_INITIATOR_SHIFT 4 + +#define HDMI_CEC_INVALID_PHY_ADDR 0xFFFF +#define HDMI_CEC_INVALID_LOGICAL_ADDR 0xFF + +enum HdmiCecLogicalAddr { + HDMI_CEC_LOG_ADDR_TV = 0, + HDMI_CEC_LOG_ADDR_RECORDING_DEVICE_1 = 1, + HDMI_CEC_LOG_ADDR_RECORDING_DEVICE_2 = 2, + HDMI_CEC_LOG_ADDR_TUNER_1 = 3, + HDMI_CEC_LOG_ADDR_PLAYBACK_DEVICE_1 = 4, + HDMI_CEC_LOG_ADDR_AUDIO_SYSTEM = 5, + HDMI_CEC_LOG_ADDR_TUNER_2 = 6, + HDMI_CEC_LOG_ADDR_TUNER_3 = 7, + HDMI_CEC_LOG_ADDR_PLAYBACK_DEVICE_2 = 8, + HDMI_CEC_LOG_ADDR_RECORDING_DEVICE_3 = 9, + HDMI_CEC_LOG_ADDR_TUNER_4 = 10, + HDMI_CEC_LOG_ADDR_PLAYBACK_DEVICE_3 = 11, + HDMI_CEC_LOG_ADDR_BACKUP_1 = 12, + HDMI_CEC_LOG_ADDR_BACKUP_2 = 13, + HDMI_CEC_LOG_ADDR_SPECIFIC_USE = 14, + HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST = 15, /* + * Unregistered(as initiator address); + * Broadcast(as destination address). + */ + HDMI_CEC_LOG_ADDR_BUTT, +}; + +enum HdmiCecLogicalAddrMark { + HDMI_CEC_LOG_ADDR_MASK_TV = (1 << HDMI_CEC_LOG_ADDR_TV), + HDMI_CEC_LOG_ADDR_MASK_RECORD = ((1 << HDMI_CEC_LOG_ADDR_RECORDING_DEVICE_1) | + (1 << HDMI_CEC_LOG_ADDR_RECORDING_DEVICE_2) | (1 << HDMI_CEC_LOG_ADDR_RECORDING_DEVICE_3)), + HDMI_CEC_LOG_ADDR_MASK_TUNER = ((1 << HDMI_CEC_LOG_ADDR_TUNER_1) | (1 << HDMI_CEC_LOG_ADDR_TUNER_2) | + (1 << HDMI_CEC_LOG_ADDR_TUNER_3) | (1 << HDMI_CEC_LOG_ADDR_TUNER_4)), + HDMI_CEC_LOG_ADDR_MASK_PLAYBACK = ((1 << HDMI_CEC_LOG_ADDR_PLAYBACK_DEVICE_1) | + (1 << HDMI_CEC_LOG_ADDR_PLAYBACK_DEVICE_2) | (1 << HDMI_CEC_LOG_ADDR_PLAYBACK_DEVICE_3)), + HDMI_CEC_LOG_ADDR_MASK_AUDIOSYSTEM = (1 << HDMI_CEC_LOG_ADDR_AUDIO_SYSTEM), + HDMI_CEC_LOG_ADDR_MASK_BACKUP = ((1 << HDMI_CEC_LOG_ADDR_BACKUP_1) | (1 << HDMI_CEC_LOG_ADDR_BACKUP_2)), + HDMI_CEC_LOG_ADDR_MASK_SPECIFIC = (1 << HDMI_CEC_LOG_ADDR_SPECIFIC_USE), + HDMI_CEC_LOG_ADDR_MASK_UNREGISTERED = (1 << HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST), +}; + +enum HdmiCecLogicalAddrType { + HDMI_CEC_LOG_ADDR_TYPE_TV = 0, + HDMI_CEC_LOG_ADDR_TYPE_RECORD = 1, + HDMI_CEC_LOG_ADDR_TYPE_TUNER = 2, + HDMI_CEC_LOG_ADDR_TYPE_PLAYBACK = 3, + HDMI_CEC_LOG_ADDR_TYPE_AUDIOSYSTEM = 4, + HDMI_CEC_LOG_ADDR_TYPE_SPECIFIC = 5, + HDMI_CEC_LOG_ADDR_TYPE_UNREGISTERED = 6, +}; + +enum HdmiCecMsgType { + HDMI_CEC_MSG_BROADCAST_1_4 = 0x01, + HDMI_CEC_MSG_BROADCAST_2_0 = 0x02, + HDMI_CEC_MSG_BROADCAST = 0x03, + HDMI_CEC_MSG_DIRECTED = 0x04, + HDMI_CEC_MSG_DIRECTED_OR_BROADCAST_1_4 = 0x05, + HDMI_CEC_MSG_DIRECTED_OR_BROADCAST_2_0 = 0x06, + HDMI_CEC_MSG_ALL = 0x07, +}; + +struct HdmiCecMsgLenInfo { + uint8_t opcode; + uint8_t minLen; + uint8_t type; +}; + +#define HDMI_CEC_WAIT_RESPONSE_MSG_MAX_TIME 1000 /* 1s */ +struct HdmiCecMsg { + uint32_t len; + uint8_t data[HDMI_CEC_MSG_MAX_LEN]; + uint8_t rspMsg; + bool response; + uint32_t timeout; /* Indicates the maximum time(in ms) for the peer to reply to a message. */ +}; + +struct HdmiCecInfo { + uint8_t logAddr; + uint8_t logAddrType; + uint16_t logAddrMask; + uint8_t primaryDeviceType; + uint8_t cecVersion; + uint16_t phyAddr; + uint32_t vendorId; + uint32_t flags; + uint8_t osdName[HDMI_CEC_OSD_NAME_MAX_LEN + 1]; + uint8_t osdNameLen; + uint8_t allDeviceType; + uint8_t rcProfile[HDMI_CEC_RC_PROFILE_MAX_NUM]; + uint8_t devFeatures[HDMI_CEC_DEVICE_FEATURES_MAX_NUM]; + bool isWaitingResponse; + uint8_t response; +}; + +struct HdmiCec { + struct HdmiCecInfo info; + void *priv; +}; + +static inline bool HdmiCecIsBroadcastMsg(struct HdmiCecMsg *msg) +{ + if ((msg->data[0] & HDMI_CEC_HEADER_BLOCK_DESTINATION_MARK) == + HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST) { + return true; + } + return false; +} + +static inline uint8_t HdmiCecGetMsgInitiator(struct HdmiCecMsg *msg) +{ + return ((msg->data[0] & HDMI_CEC_HEADER_BLOCK_INITIATOR_MARK) >> HDMI_CEC_HEADER_BLOCK_INITIATOR_SHIFT); +} + +static inline uint8_t HdmiCecGetMsgDestination(struct HdmiCecMsg *msg) +{ + return (msg->data[0] & HDMI_CEC_HEADER_BLOCK_DESTINATION_MARK); +} + +static inline bool HdmiCecLogAddrValid(struct HdmiCec *cec, uint8_t logAddr) +{ + return (cec->info.logAddr & (1 << logAddr)); +} + +static inline bool HdmiCecIsCdcOnlyDevice(struct HdmiCec *cec) +{ + return ((cec->info.logAddr == HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST) && + (cec->info.primaryDeviceType == HDMI_CEC_DEVICE_TYPE_PURE_CEC_SWITCH)); +} + +static inline void HdmiCecFillMsgHeader(struct HdmiCecMsg *destMsg, struct HdmiCecMsg *srcMsg) +{ + destMsg->data[0] = (HdmiCecGetMsgDestination(srcMsg) << HDMI_CEC_HEADER_BLOCK_INITIATOR_SHIFT) | + HdmiCecGetMsgInitiator(srcMsg); +} + +int32_t HdmiCecReceivedMsg(struct HdmiCec *cec, struct HdmiCecMsg *msg); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_CEC_H */ diff --git a/support/platform/include/hdmi/hdmi_common.h b/support/platform/include/hdmi/hdmi_common.h new file mode 100644 index 00000000..1c2fa1fc --- /dev/null +++ b/support/platform/include/hdmi/hdmi_common.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_COMMON_H +#define HDMI_COMMON_H + +#include "hdf_base.h" +#include "hdmi_if.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +#define HDMI_CEA_VIDEO_CODE_MAX 44 +#define HDMI_VESA_VIDEO_CODE_MAX 31 +#define HDMI_VIDEO_4K_CODES_MAX 4 + +#define HDMI_HDMI14_MAX_TMDS_RATE 340000 /* unit: KHz */ +#define HDMI_HDMI20_MAX_TMDS_RATE 600000 /* unit: KHz */ +#define HDMI_MULTIPLE_2P0(x) (2 * x) +#define HDMI_MULTIPLE_1P5(x) (((x) * 3) >> 1) +#define HDMI_MULTIPLE_1P25(x) (((x) * 5) >> 2) +#define HDMI_MULTIPLE_0P5(x) ((x) >> 1) + +enum HdmiTmdsModeType { + HDMI_TMDS_MODE_NULL = 0, + HDMI_TMDS_MODE_DVI = 1, + HDMI_TMDS_MODE_HDMI_1_4 = 2, + HDMI_TMDS_MODE_HDMI_2_0 = 3, + HDMI_TMDS_MODE_AUTO = 4, + HDMI_TMDS_MODE_HDMI_2_1 = 5, + HDMI_TMDS_MODE_BUTT, +}; + +/* + * Video Identification Code (VIC). + * see CTA-861-G, table 3. + */ +enum HdmiVic { + HDMI_VIC_NONE = 0, /* No Video Identification Code Avaiable(Used with AVI Infoframe only) */ + HDMI_VIC_640X480P60_4_3 = 1, + HDMI_VIC_720X480P60_4_3 = 2, + HDMI_VIC_720X480P60_16_9 = 3, + HDMI_VIC_1280X720P60_16_9 = 4, + HDMI_VIC_1920X1080I60_16_9 = 5, + HDMI_VIC_1440X480I60_4_3 = 6, + HDMI_VIC_1440X480I60_16_9 = 7, + HDMI_VIC_1440X240P60_4_3 = 8, + HDMI_VIC_1440X240P60_16_9 = 9, + HDMI_VIC_2880X480I60_4_3 = 10, + HDMI_VIC_2880X480I60_16_9 = 11, + HDMI_VIC_2880X240P60_4_3 = 12, + HDMI_VIC_2880X240P60_16_9 = 13, + HDMI_VIC_1440X480P60_4_3 = 14, + HDMI_VIC_1440X480P60_16_9 = 15, + HDMI_VIC_1920X1080P60_16_9 = 16, + HDMI_VIC_720X576P50_4_3 = 17, + HDMI_VIC_720X576P50_16_9 = 18, + HDMI_VIC_1280X720P50_16_9 = 19, + HDMI_VIC_1920X1080I50_16_9 = 20, + HDMI_VIC_1440X576I50_4_3 = 21, + HDMI_VIC_1440X576I50_16_9 = 22, + HDMI_VIC_1440X288P50_4_3 = 23, + HDMI_VIC_1440X288P50_16_9 = 24, + HDMI_VIC_2880X576I50_4_3 = 25, + HDMI_VIC_2880X576I50_16_9 = 26, + HDMI_VIC_2880X288P50_4_3 = 27, + HDMI_VIC_2880X288P50_16_9 = 28, + HDMI_VIC_1440X576P50_4_3 = 29, + HDMI_VIC_1440X576P50_16_9 = 30, + HDMI_VIC_1920X1080P50_16_9 = 31, + HDMI_VIC_1920X1080P24_16_9 = 32, + HDMI_VIC_1920X1080P25_16_9 = 33, + HDMI_VIC_1920X1080P30_16_9 = 34, + HDMI_VIC_2880X480P60_4_3 = 35, + HDMI_VIC_2880X480P60_16_9 = 36, + HDMI_VIC_2880X576P50_4_3 = 37, + HDMI_VIC_2880X576P50_16_9 = 38, + HDMI_VIC_1920X1080I50_1250_16_9 = 39, + HDMI_VIC_1920X1080I100_16_9 = 40, + HDMI_VIC_1280X720P100_16_9 = 41, + HDMI_VIC_720X576P100_4_3 = 42, + HDMI_VIC_720X576P100_16_9 = 43, + HDMI_VIC_1440X576I100_4_3 = 44, + HDMI_VIC_1440X576I100_16_9 = 45, + HDMI_VIC_1920X1080I120_16_9 = 46, + HDMI_VIC_1280X720P120_16_9 = 47, + HDMI_VIC_720X480P120_4_3 = 48, + HDMI_VIC_720X480P120_16_9 = 49, + HDMI_VIC_1440X480I120_4_3 = 50, + HDMI_VIC_1440X480I120_16_9 = 51, + HDMI_VIC_720X576P200_4_3 = 52, + HDMI_VIC_720X576P200_16_9 = 53, + HDMI_VIC_1440X576I120_4_3 = 54, + HDMI_VIC_1440X576I120_16_9 = 55, + HDMI_VIC_720X480P240_4_3 = 56, + HDMI_VIC_720X480P240_16_9 = 57, + HDMI_VIC_1440X480I240_4_3 = 58, + HDMI_VIC_1440X480I240_16_9 = 59, + HDMI_VIC_1280X720P24_16_9 = 60, + HDMI_VIC_1280X720P25_16_9 = 61, + HDMI_VIC_1280X720P30_16_9 = 62, + HDMI_VIC_1920X1080P120_16_9 = 63, + HDMI_VIC_1920X1080P100_16_9 = 64, + HDMI_VIC_1280X720P24_64_27 = 65, + HDMI_VIC_1280X720P25_64_27 = 66, + HDMI_VIC_1280X720P30_64_27 = 67, + HDMI_VIC_1280X720P50_64_27 = 68, + HDMI_VIC_1280X720P60_64_27 = 69, + HDMI_VIC_1280X720P100_64_27 = 70, + HDMI_VIC_1280X720P120_64_27 = 71, + HDMI_VIC_1920X1080P24_64_27 = 72, + HDMI_VIC_1920X1080P25_64_27 = 73, + HDMI_VIC_1920X1080P30_64_27 = 74, + HDMI_VIC_1920X1080P50_64_27 = 75, + HDMI_VIC_1920X1080P60_64_27 = 76, + HDMI_VIC_1920X1080P100_64_27 = 77, + HDMI_VIC_1920X1080P120_64_27 = 78, + HDMI_VIC_1680X720P24_64_27 = 79, + HDMI_VIC_1680X720P25_64_27 = 80, + HDMI_VIC_1680X720P30_64_27 = 81, + HDMI_VIC_1680X720P50_64_27 = 82, + HDMI_VIC_1680X720P60_64_27 = 83, + HDMI_VIC_1680X720P100_64_27 = 84, + HDMI_VIC_1680X720P120_64_27 = 85, + HDMI_VIC_2560X1080P24_64_27 = 86, + HDMI_VIC_2560X1080P25_64_27 = 87, + HDMI_VIC_2560X1080P30_64_27 = 88, + HDMI_VIC_2560X1080P50_64_27 = 89, + HDMI_VIC_2560X1080P60_64_27 = 90, + HDMI_VIC_2560X1080P100_64_27 = 91, + HDMI_VIC_2560X1080P120_64_27 = 92, + HDMI_VIC_3840X2160P24_16_9 = 93, + HDMI_VIC_3840X2160P25_16_9 = 94, + HDMI_VIC_3840X2160P30_16_9 = 95, + HDMI_VIC_3840X2160P50_16_9 = 96, + HDMI_VIC_3840X2160P60_16_9 = 97, + HDMI_VIC_4096X2160P24_256_135 = 98, + HDMI_VIC_4096X2160P25_256_135 = 99, + HDMI_VIC_4096X2160P30_256_135 = 100, + HDMI_VIC_4096X2160P50_256_135 = 101, + HDMI_VIC_4096X2160P60_256_135 = 102, + HDMI_VIC_3840X2160P24_64_27 = 103, + HDMI_VIC_3840X2160P25_64_27 = 104, + HDMI_VIC_3840X2160P30_64_27 = 105, + HDMI_VIC_3840X2160P50_64_27 = 106, + HDMI_VIC_3840X2160P60_64_27 = 107, + HDMI_VIC_1280X720P48_16_9 = 108, + HDMI_VIC_1280X720P48_64_27 = 109, + HDMI_VIC_1680X720P48_64_27 = 110, + HDMI_VIC_1920X1080P48_16_9 = 111, + HDMI_VIC_1920X1080P48_64_27 = 112, + HDMI_VIC_2560X1080P48_64_27 = 113, + HDMI_VIC_3840X2160P48_16_9 = 114, + HDMI_VIC_4096X2160P48_256_135 = 115, + HDMI_VIC_3840X2160P48_64_27 = 116, + HDMI_VIC_3840X2160P100_16_9 = 117, + HDMI_VIC_3840X2160P120_16_9 = 118, + HDMI_VIC_3840X2160P100_64_27 = 119, + HDMI_VIC_3840X2160P120_64_27 = 120, + HDMI_VIC_5120X2160P24_64_27 = 121, + HDMI_VIC_5120X2160P25_64_27 = 122, + HDMI_VIC_5120X2160P30_64_27 = 123, + HDMI_VIC_5120X2160P48_64_27 = 124, + HDMI_VIC_5120X2160P50_64_27 = 125, + HDMI_VIC_5120X2160P60_64_27 = 126, + HDMI_VIC_5120X2160P100_64_27 = 127, + HDMI_VIC_5120X2160P120_64_27 = 193, + HDMI_VIC_7680X4320P24_16_9 = 194, + HDMI_VIC_7680X4320P25_16_9 = 195, + HDMI_VIC_7680X4320P30_16_9 = 196, + HDMI_VIC_7680X4320P48_16_9 = 197, + HDMI_VIC_7680X4320P50_16_9 = 198, + HDMI_VIC_7680X4320P60_16_9 = 199, + HDMI_VIC_7680X4320P100_16_9 = 200, + HDMI_VIC_7680X4320P120_16_9 = 201, + HDMI_VIC_7680X4320P24_64_27 = 202, + HDMI_VIC_7680X4320P25_164_27 = 203, + HDMI_VIC_7680X4320P30_64_27 = 204, + HDMI_VIC_7680X4320P48_64_27 = 205, + HDMI_VIC_7680X4320P50_64_27 = 206, + HDMI_VIC_7680X4320P60_64_27 = 207, + HDMI_VIC_7680X4320P100_64_27 = 208, + HDMI_VIC_7680X4320P120_64_27 = 209, + HDMI_VIC_10240X4320P24_64_27 = 210, + HDMI_VIC_10240X4320P25_64_27 = 211, + HDMI_VIC_10240X4320P30_64_27 = 212, + HDMI_VIC_10240X4320P48_64_27 = 213, + HDMI_VIC_10240X4320P50_64_27 = 214, + HDMI_VIC_10240X4320P60_64_27 = 215, + HDMI_VIC_10240X4320P100_64_27 = 216, + HDMI_VIC_10240X4320P120_64_27 = 217, + HDMI_VIC_4096X2160P100_256_135 = 218, + HDMI_VIC_4096X2160P120_256_135 = 219, +}; + +enum HdmiVideoFormatType { + HDMI_VIDEO_FORMAT_NULL = 0, + HDMI_VIDEO_FORMAT_PROGRESSIVE = 1, + HDMI_VIDEO_FORMA_INTERLACE = 2, + HDMI_VIDEO_FORMA_BUTT, +}; + +enum HdmiColorDeep { + HDMI_COLOR_DEEP_8BITS = 8, + HDMI_COLOR_DEEP_10BITS = 10, + HDMI_COLOR_DEEP_12BITS = 12, + HDMI_COLOR_DEEP_16BITS = 16, + HDMI_COLOR_DEEP_BUTT, +}; + +enum HdmiPhyModeCfg { + HDMI_PHY_MODE_TMDS = 0, + HDMI_PHY_MODE_FRL = 1, + HDMI_PHY_MODE_TXFFE = 2, + HDMI_PHY_MODE_BUTT, +}; + +enum HdmiHdcpMode { + HDMI_HDCP_MODE_AUTO = 0, + HDMI_HDCP_MODE_1_4 = 1, + HDMI_HDCP_MODE_2_2 = 2, + HDMI_HDCP_MODE_BUTT +}; + +struct HdmiVideoDefInfo { + enum HdmiVic vic; + uint32_t pixclk; + uint32_t rate; + uint32_t hactive; + uint32_t vactive; + uint32_t hblank; + uint32_t vblank; + uint32_t hfront; + uint32_t hsync; + uint32_t hback; + uint32_t vfront; + uint32_t vsync; + uint32_t vback; + enum HdmiPictureAspectRatio aspect; + enum HdmiVideoTiming timing; + enum HdmiVideoFormatType formatType; +}; + +/* see hdmi spec2.0 table 10-2. */ +enum Hdmi4kVic { + HDMI_4K_VIC_3840X2160_30 = 1, + HDMI_4K_VIC_3840X2160_25, + HDMI_4K_VIC_3840X2160_24, + HDMI_4K_VIC_4096X2160_24 +}; + +struct HdmiVideo4kInfo { + enum Hdmi4kVic _4kVic; + enum HdmiVic vic; + uint32_t pixclk; + uint32_t rate; + uint32_t hactive; + uint32_t vactive; + enum HdmiPictureAspectRatio aspect; + enum HdmiVideoTiming timing; + enum HdmiVideoFormatType formatType; +}; + +struct HdmiCommonStatus { + bool hotplug; + bool avmute; + bool sinkPowerOn; + enum HdmiTmdsModeType tmdsMode; +}; + +struct HdmiAudioStatus { + bool mute; + bool enable; + bool downSample; + enum HdmiSampleRate sampleRate; + enum HdmiAudioInterfaceType interface; + enum HdmiAudioBitDepth bitDepth; + enum HdmiAudioFormatChannel channel; + uint32_t refN; + uint32_t regN; + uint32_t refCts; + uint32_t regCts; +}; + +struct HdmiVideoStatus { + bool mute; + bool ycbcr2Rgb; + bool rgb2Ycbcr; + bool ycbcr444422; + bool ycbcr422420; + bool ycbcr420422; + bool ycbcr422444; + bool in420Ydemux; + bool out420Ydemux; + bool vSyncPol; + bool hSyncPol; + bool syncPol; + bool dePol; + bool swapHsCs; + enum HdmiColorSpace inColorSpace; + enum HdmiColorSpace outColorSpace; + enum HdmiVideoBitDepth outBitDepth; + enum HdmiQuantizationRange quantization; +}; + +struct HdmiCommonAttr { + bool enableHdmi; + bool enableVideo; + bool enableAudio; + bool xvyccMode; + bool avi; + bool spd; + bool mpeg; + bool audio; + bool drm; + bool hdcpEnable; + bool vsifDolby; + enum HdmiColorSpace colorSpace; + enum HdmiQuantizationRange quantization; + enum HdmiDeepColor deepColor; + enum HdmiHdcpMode hdcpMode; +}; + +enum HdmiVideoBitDepth HdmiCommonDeepClolorConvertToColorDepth(enum HdmiDeepColor deepColor); +enum HdmiDeepColor HdmiCommonColorDepthConvertToDeepClolor(enum HdmiVideoBitDepth colorDepth); +enum HdmiVic HdmiCommonGetVic(enum HdmiVideoTiming timing, + enum HdmiPictureAspectRatio aspect, bool enable3d); +struct HdmiVideoDefInfo *HdmiCommonGetVideoDefInfo(enum HdmiVideoTiming timing, + enum HdmiPictureAspectRatio aspect, bool enable3d); +struct HdmiVideo4kInfo *HdmiCommonGetVideo4kInfo(uint32_t _4kVic); +enum HdmiVideoTiming HdmiCommonGetVideoTiming(enum HdmiVic vic, enum HdmiPictureAspectRatio aspect); +enum HdmiVideoTiming HdmiCommonGetVideo4kTiming(uint32_t _4kVic); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_COMMON_H */ diff --git a/support/platform/include/hdmi/hdmi_core.h b/support/platform/include/hdmi/hdmi_core.h new file mode 100644 index 00000000..3ea46fdf --- /dev/null +++ b/support/platform/include/hdmi/hdmi_core.h @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_CORE_H +#define HDMI_CORE_H + +#include "hdf_base.h" +#include "hdf_device_desc.h" +#include "hdmi_cec.h" +#include "hdmi_common.h" +#include "hdmi_ddc.h" +#include "hdmi_edid.h" +#include "hdmi_event.h" +#include "hdmi_frl.h" +#include "hdmi_hdcp.h" +#include "hdmi_hdr.h" +#include "hdmi_if.h" +#include "hdmi_infoframe.h" +#include "hdmi_scdc.h" +#include "osal_mutex.h" +#include "platform_core.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +#define HDMI_ONE_BYTE_MARK 0xFF +#define HDMI_ONE_BYTE_SHIFT 8 +#define HDMI_TWO_BYTES_SHIFT 16 + +struct HdmiPhyCfg { + uint32_t pixelClk; + uint32_t tmdsClk; /* TMDS colck, KHz */ + enum HdmiDeepColor deepColor; /* deep color(color depth) */ + enum HdmiPhyModeCfg modeCfg; /* TMDS/FRL/tx_ffe */ + enum HdmiColorSpace colorSpace; + enum HdmiFrlWorkMode rate; /* lane and rate */ + enum HdmiFrlTxffeMode txffe[4]; /* tx_ffe */ +}; + +struct HdmiTmdsConfig { + uint32_t pixelClk; + uint32_t tmdsClk; + enum HdmiPhyModeCfg mode; + enum HdmiDeepColor deepColor; +}; + +struct HdmiCntlr; + +union HdmiCap { + uint32_t data; + struct CapBitsData { + uint32_t scdc : 1; /* bit0: support scdc */ + uint32_t frl : 1; /* bit1: support frl */ + uint32_t hdr : 1; /* bit2: support hdr */ + uint32_t hdcp: 1; /* bit3: support hdcp */ + uint32_t cec : 1; /* bit4: support cec */ + uint32_t hdmi14 : 1; /* bit5: support hdmi1.4 spec */ + uint32_t hdmi20 : 1; /* bit6: support hdmi2.0 spec */ + uint32_t hdmi21 : 1; /* bit7: support hdmi2.1 spec */ + uint32_t hdcp14 : 1; /* bit8: support hdcp1.4 spec */ + uint32_t hdcp22 : 1; /* bit9: support hdcp2.2 spec */ + uint32_t rgb444 : 1; /* bit10: support rgb444 */ + uint32_t ycbcr444 : 1; /* bit11: support ycbcr444 */ + uint32_t ycbcr422 : 1; /* bit12: support ycbcr422 */ + uint32_t ycbcr420 : 1; /* bit13: support ycbcr420 */ + uint32_t deepColor10bits: 1; /* bit14: support deep color 10 bits */ + uint32_t deepColor12bits: 1; /* bit15: support deep color 12 bits */ + uint32_t deepColor16bits: 1; /* bit16: support deep color 16 bits */ + uint32_t scramble : 1; /* bit17: support scramble */ + uint32_t cecRc : 1; /* bit18: support CEC Remote Control */ + uint32_t rev : 13; /* bit21~31: reserved */ + } bits; +}; + +enum HdmiCapMark { + HDMI_CAP_SCDC_MARK = (1 << 0), + HDMI_CAP_FRL_MARK = (1 << 1), + HDMI_CAP_HDR_MARK = (1 << 2), + HDMI_CAP_HDCP_MARK = (1 << 3), + HDMI_CAP_CEC_MARK = (1 << 4), + HDMI_CAP_HDMI14_MARK = (1 << 5), + HDMI_CAP_HDMI20_MARK = (1 << 6), + HDMI_CAP_HDMI21_MARK = (1 << 7), + HDMI_CAP_HDCP14_MARK = (1 << 8), + HDMI_CAP_HDCP22_MARK = (1 << 9), + HDMI_CAP_RGB444_MARK = (1 << 10), + HDMI_CAP_YCBCR444_MARK = (1 << 11), + HDMI_CAP_YCBCR422_MARK = (1 << 12), + HDMI_CAP_YCBCR420_MARK = (1 << 13), + HDMI_CAP_DEEP_COLOR_10BITES_MARK = (1 << 14), + HDMI_CAP_DEEP_COLOR_12BITES_MARK = (1 << 15), + HDMI_CAP_DEEP_COLOR_16BITES_MARK = (1 << 16), + HDMI_CAP_SCRAMBLE_MARK = (1 << 17), +}; + +struct HdmiCntlrCap { + union HdmiCap baseCap; + uint32_t maxTmdsClock; + uint32_t defTmdsClock; /* unit: MHz */ + uint32_t maxFrlRate; + uint32_t videoTiming; + uint32_t quantization; + uint32_t colorSpace; + uint32_t colorimetry; + uint32_t audioIfType; + uint32_t audioBitDepth; + uint32_t audioSampleRate; + uint32_t audioChannels; + uint32_t hdrColorimetry; + uint32_t hdrUserMode; +}; + +struct HdmiHardwareStatus { + struct HdmiCommonStatus commonStatus; + struct HdmiAudioStatus audioStatus; + struct HdmiVideoStatus videoStatus; + struct HdmiInfoframeStatus infoframeStatus; + struct HdmiHdcpStatus hdcpstatus; +}; + +struct HdmiAudioConfigInfo { + bool enable; + bool downSample; + uint32_t tmdsClock; + uint32_t pixelRepeat; + enum HdmiAudioInterfaceType ifType; + enum HdmiAudioBitDepth bitDepth; + enum HdmiSampleRate sampleRate; + enum HdmiAudioFormatChannel channels; +}; + +struct HdmiCntlrOps { + void (*hardWareInit)(struct HdmiCntlr *cntlr); + void (*hardWareStatusGet)(struct HdmiCntlr *cntlr, struct HdmiHardwareStatus *status); + void (*controllerReset)(struct HdmiCntlr *cntlr); + bool (*hotPlugStateGet)(struct HdmiCntlr *cntlr); + bool (*hotPlugInterruptStateGet)(struct HdmiCntlr *cntlr); + void (*lowPowerSet)(struct HdmiCntlr *cntlr, bool enable); + void (*tmdsModeSet)(struct HdmiCntlr *cntlr, enum HdmiTmdsModeType mode); + int32_t (*tmdsConfigSet)(struct HdmiCntlr *cntlr, struct HdmiTmdsConfig mode); + void (*infoframeEnable)(struct HdmiCntlr *cntlr, enum HdmiPacketType infoframeType, bool enable); + int32_t (*infoframeSend)(struct HdmiCntlr *cntlr, enum HdmiPacketType infoframeType, uint8_t *data, uint32_t len); + int32_t (*infoframeDataSet)(struct HdmiCntlr *cntlr, uint32_t type, uint8_t *data, uint32_t len); + int32_t (*cecMsgSend)(struct HdmiCntlr *cntlr, struct HdmiCecMsg *msg); + void (*audioPathEnable)(struct HdmiCntlr *cntlr, bool enable); + void (*audioPathSet)(struct HdmiCntlr *cntlr, struct HdmiAudioConfigInfo *config); + void (*phyOutputEnable)(struct HdmiCntlr *cntlr, bool enable); + void (*phyOutputSet)(struct HdmiCntlr *cntlr, struct HdmiPhyCfg *cfg); + void (*blackDataSet)(struct HdmiCntlr *cntlr, bool enable); + void (*videoMuteEnable)(struct HdmiCntlr *cntlr, bool enable); + void (*videoPathSet)(struct HdmiCntlr *cntlr, struct HdmiVideoAttr *attr); + void (*audioMuteEnable)(struct HdmiCntlr *cntlr, bool enable); + void (*avmuteSet)(struct HdmiCntlr *cntlr, bool enable); + int32_t (*ddcTransfer)(struct HdmiCntlr *cntlr, struct HdmiDdcCfg *ddcCfg); + bool (*scdcSourceScrambleGet)(struct HdmiCntlr *cntlr); + int32_t (*scdcSourceScrambleSet)(struct HdmiCntlr *cntlr, bool enable); + void (*frlSet)(struct HdmiCntlr *cntlr); + int32_t (*frlEnable)(struct HdmiCntlr *cntlr, bool enable); + int32_t (*audioNctsSet)(struct HdmiCntlr *cntlr, struct HdmiFrlAudioNctsConfig *cfg); + void (*frlTrainingConfigSet)(struct HdmiCntlr *cntlr, struct HdmiFrlTrainConfig *cfg); + void (*frlTrainingStart)(struct HdmiCntlr *cntlr); + void (*frlGetTriningRslt)(struct HdmiCntlr *cntlr, struct HdmiFrlTrainRslt *rslt); + void (*hdcpRegInit)(struct HdmiCntlr *cntlr); + int32_t (*hdcpGenerateAksvAndAn)(struct HdmiCntlr *cntlr); + int32_t (*hdcpOptReg)(struct HdmiCntlr *cntlr, enum HdmiHdcpRegOptType type, uint8_t *data, uint32_t len); + void (*hdrTimerSet)(struct HdmiCntlr *cntlr, struct HdmiHdrTimerConfig *config); +}; + +enum HdmiCntlrState { + HDMI_CNTLR_STATE_NONE = 0, + HDMI_CNTLR_STATE_OPEN = (1 << 0), + HDMI_CNTLR_STATE_START = (1 << 1), + HDMI_CNTLR_STATE_STOP = (1 << 2), + HDMI_CNTLR_STATE_CLOSE = (1 << 3), +}; + +struct HdmiDevice { + struct HdmiEdid edid; /* device cap */ + struct HdmiCntlr *cntlr; + void *priv; +}; + +struct HdmiAttr { + struct HdmiCommonAttr commAttr; + struct HdmiAudioAttr audioAttr; + struct HdmiVideoAttr videoAttr; + struct HdmiHdrAttr hdrAttr; +}; + +struct HdmiCntlr { + struct IDeviceIoService service; + struct HdfDeviceObject *hdfDevObj; + struct PlatformDevice device; + struct OsalMutex mutex; + struct PlatformQueue *msgQueue; + struct HdmiCntlrCap cap; + struct HdmiAttr attr; + struct HdmiCntlrOps *ops; + uint32_t deviceIndex; + uint32_t state; /* cntlr state. */ + enum HdmiTmdsModeType tmdsMode; + struct HdmiDevice *hdmi; + struct HdmiInfoframe infoframe; + struct HdmiScdc *scdc; + struct HdmiDdc ddc; + struct HdmiFrl *frl; + struct HdmiHdcp *hdcp; + struct HdmiCec *cec; + struct HdmiEvent event; + struct HdmiHdr *hdr; + void *priv; +}; + +static inline void HdmiCntlrLock(struct HdmiCntlr *cntlr) +{ + if (cntlr != NULL) { + (void)OsalMutexLock(&cntlr->mutex); + } +} + +static inline void HdmiCntlrUnlock(struct HdmiCntlr *cntlr) +{ + if (cntlr != NULL) { + (void)OsalMutexUnlock(&cntlr->mutex); + } +} + +static inline struct HdmiCntlr *HdmiCntlrGetByBusNum(uint16_t num) +{ + struct PlatformDevice *device = PlatformManagerGetDeviceByMagic(PlatformManagerGet(PLATFORM_MODULE_HDMI), num); + + if (device == NULL) { + return NULL; + } + return CONTAINER_OF(device, struct HdmiCntlr, device); +} + +static inline void HdmiCntlrLowPowerSet(struct HdmiCntlr *cntlr, bool enable) +{ + if (cntlr->ops != NULL && cntlr->ops->lowPowerSet != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->lowPowerSet(cntlr, enable); + HdmiCntlrUnlock(cntlr); + } +} + +static inline void HdmiCntlrHardWareInit(struct HdmiCntlr *cntlr) +{ + if (cntlr->ops != NULL && cntlr->ops->hardWareInit != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->hardWareInit(cntlr); + HdmiCntlrUnlock(cntlr); + } +} + +static inline void HdmiCntlrAudioPathEnable(struct HdmiCntlr *cntlr, bool enable) +{ + if (cntlr->ops != NULL && cntlr->ops->audioPathEnable != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->audioPathEnable(cntlr, enable); + HdmiCntlrUnlock(cntlr); + } +} + +static inline void HdmiCntlrAudioPathSet(struct HdmiCntlr *cntlr, struct HdmiAudioConfigInfo *config) +{ + if (cntlr->ops != NULL && cntlr->ops->audioPathSet != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->audioPathSet(cntlr, config); + HdmiCntlrUnlock(cntlr); + } +} + +static inline void HdmiCntlrAudioMuteEnable(struct HdmiCntlr *cntlr, bool enable) +{ + if (cntlr->ops != NULL && cntlr->ops->audioMuteEnable != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->audioMuteEnable(cntlr, enable); + HdmiCntlrUnlock(cntlr); + } +} + +static inline void HdmiCntlrVideoPathSet(struct HdmiCntlr *cntlr, struct HdmiVideoAttr *attr) +{ + if (cntlr->ops != NULL && cntlr->ops->videoPathSet != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->videoPathSet(cntlr, attr); + HdmiCntlrUnlock(cntlr); + } +} + +static inline void HdmiCntlrTmdsModeSet(struct HdmiCntlr *cntlr, enum HdmiTmdsModeType mode) +{ + if (cntlr->ops != NULL && cntlr->ops->tmdsModeSet != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->tmdsModeSet(cntlr, mode); + HdmiCntlrUnlock(cntlr); + } +} + +static inline void HdmiCntlrReset(struct HdmiCntlr *cntlr) +{ + if (cntlr->ops != NULL && cntlr->ops->controllerReset != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->controllerReset(cntlr); + HdmiCntlrUnlock(cntlr); + } +} + +static inline void HdmiCntlrBlackDataSet(struct HdmiCntlr *cntlr, bool enable) +{ + if (cntlr->ops != NULL && cntlr->ops->blackDataSet != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->blackDataSet(cntlr, enable); + HdmiCntlrUnlock(cntlr); + } +} + +static inline void HdmiCntlrPhyOutputEnablet(struct HdmiCntlr *cntlr, bool enable) +{ + if (cntlr->ops != NULL && cntlr->ops->phyOutputEnable != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->phyOutputEnable(cntlr, enable); + HdmiCntlrUnlock(cntlr); + } +} + +static inline void HdmiCntlrHdrTimerSet(struct HdmiCntlr *cntlr, struct HdmiHdrTimerConfig *config) +{ + if (cntlr->ops != NULL && cntlr->ops->hdrTimerSet != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->hdrTimerSet(cntlr, config); + HdmiCntlrUnlock(cntlr); + } +} + +static inline void HdmiCntlrAvmuteSet(struct HdmiCntlr *cntlr, bool enable) +{ + if (cntlr->ops != NULL && cntlr->ops->avmuteSet != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->avmuteSet(cntlr, enable); + HdmiCntlrUnlock(cntlr); + } +} + +int32_t HdmiCntlrParse(struct HdmiCntlr *cntlr, struct HdfDeviceObject *obj); +int32_t HdmiCntlrAdd(struct HdmiCntlr *cntlr); +void HdmiCntlrRemove(struct HdmiCntlr *cntlr); + +int32_t HdmiCntlrOpen(struct HdmiCntlr *cntlr); +int32_t HdmiCntlrGetSinkEdid(struct HdmiCntlr *cntlr, uint8_t *buffer, uint32_t len); +int32_t HdmiCntlrStart(struct HdmiCntlr *cntlr); +int32_t HdmiCntlrStop(struct HdmiCntlr *cntlr); +int32_t HdmiCntlrDeepColorSet(struct HdmiCntlr *cntlr, enum HdmiDeepColor color); +int32_t HdmiCntlrDeepColorGet(struct HdmiCntlr *cntlr, enum HdmiDeepColor *color); +int32_t HdmiCntlrSetVideoAttribute(struct HdmiCntlr *cntlr, struct HdmiVideoAttr *attr); +int32_t HdmiCntlrSetAudioAttribute(struct HdmiCntlr *cntlr, struct HdmiAudioAttr *attr); +int32_t HdmiCntlrSetHdrAttribute(struct HdmiCntlr *cntlr, struct HdmiHdrAttr *attr); +int32_t HdmiCntlrInfoframeGet(struct HdmiCntlr *cntlr, enum HdmiPacketType type, union HdmiInfoframeInfo *frame); +int32_t HdmiCntlrInfoframeSet(struct HdmiCntlr *cntlr, enum HdmiPacketType type, union HdmiInfoframeInfo *frame); +void HdmiCntlrClose(struct HdmiCntlr *cntlr); + +bool HdmiHpdStatusDelayGet(struct HdmiCntlr *cntlr); +bool HdmiHpdStatusGet(struct HdmiCntlr *cntlr); +int32_t HdmiEventHandle(struct HdmiCntlr *cntlr, enum HdmiEventType event, void *datat); +int32_t HdmiEventMsgHandleDefault(struct PlatformQueue *queue, struct PlatformMsg *msg); + +bool HdmiEdidSupportFrl(struct HdmiDevice *hdmi); +uint8_t HdmiEdidGetMaxFrlRate(struct HdmiDevice *hdmi); +bool HdmiEdidScdcSupport(struct HdmiDevice *hdmi); +int32_t HdmiCntlrAllocDev(struct HdmiCntlr *cntlr); +void HdmiCntlrFreeDev(struct HdmiCntlr *cntlr); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_CORE_H */ diff --git a/support/platform/include/hdmi/hdmi_ddc.h b/support/platform/include/hdmi/hdmi_ddc.h new file mode 100644 index 00000000..cdd9cf60 --- /dev/null +++ b/support/platform/include/hdmi/hdmi_ddc.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_DDC_H +#define HDMI_DDC_H + +#include "hdf_base.h" +#include "osal_mutex.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/* + * DDC(Display Data Channel) + * The DDC channel is used by an HDMI Source to determine the capabilities and characteristics of + * the Sink by reading the E-EDID data structure. + * The DDC is also uesd to exchange point-to-point dynamic data between the Source and the Sink + * using a new DDC address for the HDMI Status and Control Data Channel(SCDC). + * In addition, The DDC is also uesd for HDCP to exchange key selection vector and other information. + */ +#define HDMI_DDC_EDID_DEV_ADDRESS 0xA0 +#define HDMI_DDC_SCDC_DEV_ADDRESS 0xA8 +#define HDMI_DDC_HDCP_DEV_ADDRESS 0x74 + +enum HdmiDdcDeviceType { + HDMI_DDC_DEV_EDID = 0, + HDMI_DDC_DEV_SCDC = 1, + HDMI_DDC_DEV_HDCP = 2, + HDMI_DDC_DEV_BUTT, +}; + +enum HdmiDdcMode { + HDMI_DDC_MODE_READ_SINGLE_NO_ACK = 0, + HDMI_DDC_MODE_READ_SINGLE_ACK = 1, + HDMI_DDC_MODE_READ_MUTIL_NO_ACK = 2, + HDMI_DDC_MODE_READ_MUTIL_ACK = 3, + HDMI_DDC_MODE_READ_SEGMENT_NO_ACK = 4, + HDMI_DDC_MODE_READ_SEGMENT_ACK = 5, + HDMI_DDC_MODE_WRITE_MUTIL_NO_ACK = 6, + HDMI_DDC_MODE_WRITE_MUTIL_ACK = 7, + HDMI_DDC_MODE_BUTT, +}; + +struct HdmiDdcCfg { + enum HdmiDdcDeviceType type; + enum HdmiDdcMode mode; + bool readFlag; + uint32_t devAddr; + uint8_t offset; + uint8_t segment; /* see VESA spec. 1 segment is 256 bytes. */ + uint32_t dataLen; + uint8_t *data; +}; + +struct HdmiDdc { + struct OsalMutex ddcMutex; + bool init; + void *priv; +}; + +int32_t HdmiDdcTransfer(struct HdmiDdc *ddc, struct HdmiDdcCfg *cfg); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_DDC_H */ diff --git a/support/platform/include/hdmi/hdmi_dfm.h b/support/platform/include/hdmi/hdmi_dfm.h new file mode 100644 index 00000000..a22aee86 --- /dev/null +++ b/support/platform/include/hdmi/hdmi_dfm.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_DFM_H +#define HDMI_DFM_H + +#include "hdmi_if.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/* + * DFM(Data Flow Metering). + * During data transmission in FRL mode, there is a lot of bandwidth redundancy (blanking period) or slight bandwidth + * insufficiency (active video). In order for the link to tolerate these fluctuations, source and sink need to use + * buffers. To limit the size of the buffer required, the protocol adds the Data Flow Metering requirement. + */ +#define HDMI_DFM_FRL_CHAR_NUM_PER_CB 502 +#define HDMI_DFM_RS_NUM_PER_CB 8 +/* A FRL Character Block(CB) contains 502 FRL Characters and 8 RS check characters. */ +#define HDMI_DFM_CHAR_NUM_PER_CB (HDMI_DFM_FRL_CHAR_NUM_PER_CB + HDMI_DFM_RS_NUM_PER_CB) + +/* + * A FRL Super Block(SB) contains four FRL Character Blocks. + * Each FRL Super Block is preceded by a group of three or four Start Super Blocks (SSB) or a group of three or + * four Scrambler Reset (SR) characters. + */ +#define HDMI_DFM_FRL_CB_NUM_PER_SB 4 +#define HDMI_DFM_FRL_SB_LEN(lane) (HDMI_DFM_FRL_CB_NUM_PER_SB * HDMI_DFM_CHAR_NUM_PER_CB + lane) + +#define HDMI_DFM_FRL_PIXELCLK_TOLERANCE 5 /* 0.50% */ +#define HDMI_DFM_FRL_BITRATE_TOLERANCE 3 /* 300 */ +#define HDMI_DFM_FRL_AUDIOCLK_TOLERANCE 1 +#define HDMI_DFM_MAGNIFICATION_8 8 +#define HDMI_DFM_FRL_MAX_TB_BORROW 400 +#define HDMI_DFM_RATE_MAGNIFICATION 100000 +#define HDMI_DFM_OVERHEAD_SIZE 300 + +#define HDMI_AUDIO_CHANNEL_ALLOC_TYPE1 1 +#define HDMI_AUDIO_CHANNEL_ALLOC_TYPE2 2 +#define HDMI_AUDIO_CHANNEL_ALLOC_TYPE3 3 + +/* + * Packets per sample. + * This is the number of audio packets required to carry each sample. + * x100. + */ +#define HDMI_AUDIO_AP_SIZE_25 25 +#define HDMI_AUDIO_AP_SIZE_100 100 +#define HDMI_AUDIO_AP_SIZE_200 200 +#define HDMI_AUDIO_AP_SIZE_300 300 +#define HDMI_AUDIO_AP_SIZE_400 400 + +enum HdmiAudioPacketType { + HDMI_AUDIO_SAMPLE_PACKET = 0x02, + HDMI_ONE_BIT_AUDIO_SAMPLE_PACKET = 0x07, + HDMI_DTS_AUDIO_PACKET = 0x08, + HDMI_HBR_AUDIO_PACKET = 0x09, + HDMI_AUDIO_3D_SAMPLE_PACKET = 0x0B, + HDMI_ONE_BIT_AUDIO_3D_SAMPLE_PACKET = 0x0C, + HDMI_MULTI_STREAM_AUDIO_SAMPLE_PACKET = 0x0E, + HDMI_ONE_BIT_MULTI_STREAM_AUDIO_SAMPLE_PACKET = 0x0F, +}; + +enum HdmiDfmPixelFormatMode { + HDMI_DFM_PIXEL_FORMAT_MODE_0 = 0, + HDMI_DFM_PIXEL_FORMAT_MODE_1, + HDMI_DFM_PIXEL_FORMAT_MODE_2, + HDMI_DFM_PIXEL_FORMAT_MODE_3 +}; + +struct HdmiDfmInfo { + bool audioSupport; + bool videoSupport; + bool uncompressSupport; + bool isExtraMode; + bool canbeTrans; + uint32_t htotal; + uint32_t vtotal; + uint32_t bpp; /* Bits per Pixel */ + uint32_t cFrlSb; /* Total FRL Characters Per SuperBlock(include SSB/SR) */ + uint32_t overheadSb; + uint32_t overheadRs; + uint32_t overheadMap; + uint32_t overheadMin; + uint32_t overheadMax; + uint32_t lineMinTime; /* minimum Video Line period */ + uint32_t lineMaxTime; /* maximum Video Line period */ + uint32_t audioAp; /* the number of audio packets required to carry each sample */ + uint32_t audioRap; /* Average Audio Related Packet Rate */ + uint32_t avgAudioPacketsPerLine; /* Average Required Packets per line */ + uint32_t audioPacketsLine; /* Packets per Hblank that must be supportable. */ + uint32_t hblankAudioMin; /* */ + uint32_t cFrlFree; + uint32_t cFrlRcMargin; + uint32_t cFrlRcSavings; + uint32_t activeBytesPerLine; /* Video Bytes per line */ + uint32_t activeTbPerLine; /* Required Characters to carry Active Video per line */ + uint32_t hblankTbPerLine; /* Required Characters to carry H-Blank Video per line */ + uint32_t activeTimeRef; + uint32_t blankTimeRef; + uint32_t activeTimeMin; + uint32_t blankTimeMin; + int32_t tBorrow; + int32_t tbBorrow; + uint32_t cFrlActualPayload; + uint32_t utilization; + int32_t margin; + uint32_t avgTbRate; + uint64_t pixelClk; + uint64_t maxPixelClk; /* maximum legal pixel rate */ + uint64_t minPixelClk; /* minimum legal pixel rate */ + uint64_t maxBitRate; /* FRL max bit rate */ + uint64_t minBitRate; /* FRL min bit rate */ + uint64_t maxFrlCharRate; /* max FRL Character Rate */ + uint64_t minFrlCharRate; /* min FRL Character Rate */ + uint32_t maxFrlCharsPerLine; /* max FRL Characters per line Period */ + uint32_t minFrlCharsPerLine; /* min FRL Characters per line Period */ +}; + +struct HdmiDfmParam { + uint32_t hactive; + uint32_t vactive; + uint32_t hblank; + uint32_t vblank; + uint32_t hsync; + uint32_t hback; + uint32_t hfront; + uint32_t vsync; + uint32_t vback; + uint32_t vfront; + uint32_t vfreq; + uint32_t colorDepth; + uint32_t pixelFormat; /* 1:420, 2:422, 3:RGB444 */ + uint32_t laneNum; + uint32_t bitRate; + uint32_t audioRate; + uint32_t packetType; + uint32_t layout; + uint32_t acat; +}; + +uint32_t HdmiDfmGetPixelFormat(enum HdmiColorSpace colorSpace); +void HdmiDfmFillParam(struct HdmiDfmParam *param, struct HdmiVideoDefInfo *videoInfo, + struct HdmiAudioAttr *audioAttr, enum HdmiColorSpace colorSpace, enum HdmiDeepColor deepColor); +bool HdmiDfmFormatSupport(struct HdmiDfmParam *param); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_DFM_H */ diff --git a/support/platform/include/hdmi/hdmi_dispatch.h b/support/platform/include/hdmi/hdmi_dispatch.h new file mode 100644 index 00000000..c7292369 --- /dev/null +++ b/support/platform/include/hdmi/hdmi_dispatch.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_DISPATCH_H +#define HDMI_DISPATCH_H + +#include "hdf_base.h" + +#ifndef __USER__ +#include "devsvc_manager_clnt.h" +#endif + +#ifdef __USER__ +#include "hdf_io_service_if.h" +#endif + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +#ifndef __USER__ +int32_t HdmiIoDispatch(struct HdfDeviceIoClient *client, int cmd, struct HdfSBuf *data, struct HdfSBuf *reply); +#endif + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_NCTS_H */ diff --git a/support/platform/include/hdmi/hdmi_edid.h b/support/platform/include/hdmi/hdmi_edid.h new file mode 100644 index 00000000..0bc17dfa --- /dev/null +++ b/support/platform/include/hdmi/hdmi_edid.h @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_EDID_H +#define HDMI_EDID_H + +#include "hdf_base.h" +#include "hdmi_ddc.h" +#include "hdmi_if.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/* (EDID)Extended Display Identification Data */ +#define HDMI_EDID_SINGLE_BLOCK_SIZE 128 +#define HDMI_EDID_MAX_BLOCK_NUM 4 +#define HDMI_EDID_TOTAL_SIZE (HDMI_EDID_SINGLE_BLOCK_SIZE * HDMI_EDID_MAX_BLOCK_NUM) +#define HDMI_EDID_MAX_VIC_COUNT 128 + +#define HDMI_EDID_BIT0_MARK 0x01 +#define HDMI_EDID_BIT1_MARK 0x02 +#define HDMI_EDID_BIT2_MARK 0x04 +#define HDMI_EDID_BIT3_MARK 0x08 +#define HDMI_EDID_BIT4_MARK 0x10 +#define HDMI_EDID_BIT5_MARK 0x20 +#define HDMI_EDID_BIT6_MARK 0x40 +#define HDMI_EDID_BIT7_MARK 0x80 +#define HDMI_EDID_UPPER_NIBBLE_MARK 0xf0 +#define HDMI_EDID_LOWER_NIBBLE_MARK 0x0f +#define HDMI_EDID_BITS_OF_ONE_BYTE 8 +#define HDMI_EDID_ONE_BYTE_SHIFT 8 +#define HDMI_EDID_6_BITS_SHIFT 6 +#define HDMI_EDID_NIBBLE_SHIFT 4 +#define HDMI_EDID_2_BITS_SHIFT 2 + +#define HDMI_EDID_CHECK_SUM_MARK 0xff + +/* edid header */ +#define HDMI_EDID_BLOCK_HEADER_FIELD_LEN 8 + +/* edid vendor/product info */ +#define HDMI_EDID_MANUFACRURER_NAME_FIELD_LEN 2 +#define HDMI_EDID_MANUFACRURER_NAME_MAX_LEN 4 +#define HDMI_EDID_MANUFACRURER_NAME_CHAR_MARK 0x1F /* 5 bits */ +#define HDMI_EDID_MANUFACRURER_NAME_CHAR_SHIFT 5 +#define HDMI_EDID_MANUFACRURER_NAME_LOW_INVALID 0 +#define HDMI_EDID_MANUFACRURER_NAME_HIGH_INVALID 27 +#define HDMI_EDID_MANUFACRURER_NAME_SHIFT 8 +#define HDMI_EDID_PRODUCT_CODE_FIELD_LEN 2 +#define HDMI_EDID_PRODUCT_CODE_SHIFT 8 +#define HDMI_EDID_SERIAL_NUMBER_FIELD_LEN 4 +#define HDMI_EDID_SERIAL_NUMBER_SHIFT 8 +#define HDMI_EDID_WEEK_LOW_VALID 1 +#define HDMI_EDID_WEEK_HIGH_VALID 53 +#define HDMI_EDID_YEAR_VALID 0xFF +#define HDMI_EDID_YEAR_BASE 1990 + +struct HdmiEdidVendorInfo { + char mfrName[HDMI_EDID_MANUFACRURER_NAME_MAX_LEN]; + uint16_t productCode; + uint32_t serialNumber; + uint8_t week; + uint8_t year; +}; + +#define HDMI_EDID_VERSION_NUM 1 +#define HDMI_EDID_REVISION_NUM 3 + +/* edid version info */ +struct HdmiEdidVersionInfo { + uint8_t version; + uint8_t revision; +}; + +/* edid basic display parameters and features */ +struct HdmiEdidBasicDispParamInfo { + uint8_t width; /* unit: cm */ + uint8_t height; /* unit: cm */ +}; + +/* edid color characteristics */ +#define HDMI_EDID_COLOR_LOW_BITS_MARK 0x03 +#define HDMI_EDID_COLOR_RED_X_LOW_OFFSET 6 +#define HDMI_EDID_COLOR_RED_Y_LOW_OFFSET 4 +#define HDMI_EDID_COLOR_GREEN_X_LOW_OFFSET 2 +#define HDMI_EDID_COLOR_BLUE_X_LOW_OFFSET 6 +#define HDMI_EDID_COLOR_BLUE_Y_LOW_OFFSET 4 +#define HDMI_EDID_COLOR_WHITE_X_LOW_OFFSET 2 +#define HDMI_EDID_COLOR_HIGH_OFFSET 2 + +struct HdmiEdidColorInfo { + uint16_t redX; + uint16_t redY; + uint16_t greenX; + uint16_t greenY; + uint16_t blueX; + uint16_t blueY; + uint16_t whiteX; + uint16_t whiteY; +}; + +/* edid established timings */ +#define HDMI_EDID_ESTABLISHED_TIMINGS_FIELD_LEN 3 + +enum HdmiEdidEstablishTiming { + HDMI_EDID_ESTABLISHED_TIMING_VESA_800X600_60 = 0, + HDMI_EDID_ESTABLISHED_TIMING_VESA_800X600_56 = 1, + HDMI_EDID_ESTABLISHED_TIMING_VESA_640X480_75 = 2, + HDMI_EDID_ESTABLISHED_TIMING_VESA_640X480_72 = 3, + HDMI_EDID_ESTABLISHED_TIMING_640X480_67 = 4, + HDMI_EDID_ESTABLISHED_TIMING_VGA_640X480_60 = 5, + HDMI_EDID_ESTABLISHED_TIMING_XGA_720X400_88 = 6, + HDMI_EDID_ESTABLISHED_TIMING_VGA_720X400_70 = 7, + HDMI_EDID_ESTABLISHED_TIMING_VESA_1280X1024_75 = 8, + HDMI_EDID_ESTABLISHED_TIMING_VESA_1024X768_75 = 9, + HDMI_EDID_ESTABLISHED_TIMING_VESA_1024X768_70 = 10, + HDMI_EDID_ESTABLISHED_TIMING_VESA_1024X768_60 = 11, + HDMI_EDID_ESTABLISHED_TIMING_1024X768_87 = 12, + HDMI_EDID_ESTABLISHED_TIMING_832X624_75 = 13, + HDMI_EDID_ESTABLISHED_TIMING_VESA_800X600_75 = 14, + HDMI_EDID_ESTABLISHED_TIMING_VESA_800X600_72 = 15, + HDMI_EDID_ESTABLISHED_TIMING_VESA_1152X870_75 = 16, + HDMI_EDID_ESTABLISHED_TIMING_BUTT, +}; + +struct HdmiEdidEstablishedTimingsInfo { + uint32_t estTimingsNum; + uint32_t estTimings[HDMI_EDID_ESTABLISHED_TIMING_BUTT]; +}; + +/* edid standard timing */ +#define HDMI_EDID_STANDARD_TIMING_FIELD_LEN 16 +#define HDMI_EDID_STANDARD_TIMING_COUNT 8 +#define HDMI_EDID_PER_STANDARD_TIMING_BYTE_NUM 2 +#define HDMI_EDID_STANDARD_TIMING_UNUSED_FLAG 0x01 +#define HDMI_EDID_STANDARD_TIMING_HORIZ_PIXEL_BASE 31 +#define HDMI_EDID_STANDARD_TIMING_HORIZ_PIXEL_FACTOR 8 +#define HDMI_EDID_STANDARD_TIMING_REFRESH_RATE_BASE 60 +#define HDMI_EDID_STANDARD_TIMING_REFRESH_RATE_MARK 0x3F + +#define HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_MARK 0xC0 +#define HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_SHIFT 6 + +enum HdmiEdidStdTimingAspectRate { + HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_16_10 = 0, + HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_5_4 = 1, + HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_4_3 = 2, + HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_16_9 = 3, +}; + +struct HdmiEdidStdTimingInfo { + uint32_t horizPixel; + uint32_t vertPixel; + uint32_t refreshRate; +}; + +/* edid detailed timing descriptor */ +#define HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN 18 +#define HDMI_EDID_DETAILED_TIMING_PIXEL_CLK_FIELD_LEN 2 +#define HDMI_EDID_DETAILED_TIMING_PIXEL_CLK_KHZ_FACTOR 10 +#define HDMI_EDID_DETAILED_TIMING_UPPER_4BITS_MARK 0xF0 +#define HDMI_EDID_DETAILED_TIMING_LOWER_4BITS_MARK 0x0F +#define HDMI_EDID_DETAILED_TIMING_HS_OFFSET_MARK 0xC0 +#define HDMI_EDID_DETAILED_TIMING_HS_PULSE_WIDTH_MARK 0x30 +#define HDMI_EDID_DETAILED_TIMING_VS_OFFSET_MARK 0x0C +#define HDMI_EDID_DETAILED_TIMING_VS_PULSE_WIDTH_MARK 0x03 +#define HDMI_EDID_DETAILED_TIMING_STEREO_MARK 0x60 +#define HDMI_EDID_DETAILED_TIMING_STEREO_SEQUENTIAL_R 0x02 +#define HDMI_EDID_DETAILED_TIMING_STEREO_SEQUENTIAL_L 0x04 +#define HDMI_EDID_DETAILED_TIMING_STEREO_INTERLEAVED_2R 0x03 +#define HDMI_EDID_DETAILED_TIMING_STEREO_INTERLEAVED_2L 0x05 +#define HDMI_EDID_DETAILED_TIMING_STEREO_INTERLEAVED_4 0x06 +#define HDMI_EDID_DETAILED_TIMING_STEREO_INTERLEAVED_SBS 0x07 +#define HDMI_EDID_DETAILED_TIMING_SYNC_SIGNAL_TYPE_MARK 0x0E +#define HDMI_EDID_DETAILED_TIMING_SYNC_DCS_WS_0 0x00 +#define HDMI_EDID_DETAILED_TIMING_SYNC_DCS_WS_1 0x01 +#define HDMI_EDID_DETAILED_TIMING_SYNC_DCS_DS_2 0x02 +#define HDMI_EDID_DETAILED_TIMING_SYNC_DCS_DS_3 0x03 +#define HDMI_EDID_DETAILED_TIMING_SYNC_DSS_VN_HN_4 0x04 +#define HDMI_EDID_DETAILED_TIMING_SYNC_DSS_VN_HP_5 0x05 +#define HDMI_EDID_DETAILED_TIMING_SYNC_DSS_VP_HN_6 0x06 +#define HDMI_EDID_DETAILED_TIMING_SYNC_DSS_VP_HP_7 0x07 +#define HDMI_EDID_MAX_DETAILED_TIMING_COUNT 10 + +struct HdmiEdidDetailedTimingBlockInfo { + uint8_t pixelClk[HDMI_EDID_DETAILED_TIMING_PIXEL_CLK_FIELD_LEN]; + uint8_t hActive; + uint8_t hBlanking; + uint8_t hActiveBlanking; + uint8_t vActive; + uint8_t vBlanking; + uint8_t vActiveBlanking; + uint8_t hSyncOffset; + uint8_t hSyncPulseWidth; + uint8_t vsOffesetPulseWidth; + uint8_t hsOffsetVsOffset; + uint8_t hImageSize; + uint8_t vImageSize; + uint8_t hvImageSize; + uint8_t hBorder; + uint8_t vBorder; + uint8_t flags; +}; + +struct HdmiEdidPreferredTimingInfo { + uint32_t pixelClk; /* unit: KHz */ + uint32_t hActive; /* horizontal active area */ + uint32_t hBackBlank; /* horizontal back blank */ + uint32_t hFrontBlank; /* horizontal front blank */ + uint32_t hSyncPluseWidth; /* horizontal sync pluse width */ + uint32_t vActive; /* vertical active area */ + uint32_t vBackBlank; /* vertical back blank */ + uint32_t vFrontBlank; /* vertical front blank */ + uint32_t vSyncPluseWidth; /* vertical sync pluse width */ + uint32_t imageWidth; /* image width */ + uint32_t imageHeight; /* image height */ + bool interlaceFlag; /* interlace flag */ + bool idv; /* flag of data valid signal is needed flip */ + bool ihs; /* flag of horizontal sync pulse is needed flip */ + bool ivs; /* flag of vertical sync pulse is needed flip */ +}; + + +/* edid monitor descriptor */ +#define HDMI_EDID_MONITOR_FLAGS_FIELD_LEN 3 +#define HDMI_EDID_MONITOR_DATA_FIELD_LEN 13 +#define HDMI_EDID_MAX_SINK_NAME_COUNT 14 + +enum HdmiEdidMonitorDataType { + HDMI_EDID_MONITOR_DATA_NAME = 0xFC, + HDMI_EDID_MONITOR_DATA_RANGE_LIMIT = 0xFD, + HDMI_EDID_MONITOR_DATA_STRING = 0xFE, + HDMI_EDID_MONITOR_DATA_SERIAL_NUMBER = 0xFF, +}; + +struct HdmiEdidMonitorBlockInfo { + uint8_t flags[HDMI_EDID_MONITOR_FLAGS_FIELD_LEN]; + uint8_t dataTag; + uint8_t flag; + uint8_t data[HDMI_EDID_MONITOR_DATA_FIELD_LEN]; +}; + +/* edid extension flag and checksum */ +#define HDMI_EDID_EXTENSION_BLOCK_ADDR 0x7E +#define HDMI_EDID_CHECKSUM_ADDR 0x7F + +struct HdmiEdidFirstBlockInfo { + uint8_t header[HDMI_EDID_BLOCK_HEADER_FIELD_LEN]; + uint8_t vendorName[HDMI_EDID_MANUFACRURER_NAME_FIELD_LEN]; + uint8_t productCode[HDMI_EDID_PRODUCT_CODE_FIELD_LEN]; + uint8_t serialNumber[HDMI_EDID_SERIAL_NUMBER_FIELD_LEN]; + uint8_t week; /* + * The designated values for this field range from 1 to 53. If this field is unused, the value + * should be set to 0. If the next field is used for Model Year, then 0xFF should be set. + */ + uint8_t year; /* This value is determined by the actual year of production minus 1990. */ + uint8_t version; + uint8_t revision; + uint8_t videoInput; + uint8_t width; /* unit: cm */ + uint8_t height; /* unit: cm */ + uint8_t gamma; /* Display Transfer Characteristics */ + uint8_t features; + uint8_t redGreenLow; + uint8_t blueWhiteLow; + uint8_t redX; + uint8_t redY; + uint8_t greenX; + uint8_t greenY; + uint8_t blueX; + uint8_t blueY; + uint8_t whiteX; + uint8_t whiteY; + uint8_t estTimings[HDMI_EDID_ESTABLISHED_TIMINGS_FIELD_LEN]; + uint8_t stdTiming[HDMI_EDID_STANDARD_TIMING_FIELD_LEN]; + uint8_t detailedTiming1[HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN]; + uint8_t detailedTiming2[HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN]; + uint8_t detailedTiming3[HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN]; + uint8_t detailedTiming4[HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN]; + uint8_t extensionFlag; + uint8_t checksum; +}; + +/* edid extension block */ +#define HDMI_EDID_CTA_EXTENSION_TAG 0x02 +#define HDMI_EDID_CTA_EXTENSION3_REVISION 0x03 +#define HDMI_EDID_EXTENSION_DATA_BLOCK_LEN_MARK 0x1F +#define HDMI_EDID_EXTENSION_DATA_BLOCK_TAG_CODE_MARK 0xE0 +#define HDMI_EDID_EXTENSION_DATA_BLOCK_TAG_CODE_SHIFT 5 +#define HDMI_EDID_EXTENSION_BLOCK_OFFSET 4 +#define HDMI_EDID_EXTENSION_D_INVALID_MIN_VAL 4 + +enum HdmiEdidExtDataBlockType { + HDMI_EDID_NULL_DATA_BLOCK = 0, + HDMI_EDID_AUDIO_DATA_BLOCK = 1, + HDMI_EDID_VIDEO_DATA_BLOCK = 2, + HDMI_EDID_VENDOR_SPECIFIC_DATA_BLOCK = 3, + HDMI_EDID_SPEAKER_ALLOCATION_DATA_BLOCK = 4, + HDMI_EDID_VESA_DTC_DATA_BLOCK = 5, /* VESA Display Transfer Characteristic Data Block */ + HDMI_EDID_USE_EXT_DATA_BLOCK = 7, /* Use Extended Tag */ +}; + +struct HdmiEdidColorSpace { + bool rgb444; + bool ycbcr422; + bool ycbcr444; + bool ycbcr420; +}; + +/* edid extension block: Audio Data Block */ +#define HDMI_EDID_EXTENSION_SHORT_AUDIO_DESCRIPTOR_LEN 3 +#define HDMI_EDID_EXTENSION_MAX_SHORT_AUDIO_DESCRIPTOR_NUM 10 +#define HDMI_EDID_EXTENSION_AUDIO_FORMAT_CODE_MARK 0x78 +#define HDMI_EDID_EXTENSION_AUDIO_FORMAT_CODE_SHIFT 3 +#define HDMI_EDID_EXTENSION_AUDIO_MAX_CHANNEL_MARK 0x07 +#define HDMI_EDID_EXTENSION_AUDIO_MAX_SAMPLE_RATE_NUM 8 +#define HDMI_EDID_EXTENSION_AUDIO_MAX_BIT_DEPTH_NUM 6 +#define HDMI_EDID_EXTENSION_AUDIO_BIT_RATE_FACTOR 8 +#define HDMI_EDID_EXTENSION_AUDIO_CAP_COUNT 16 + + +struct HdmiEdidAudioInfo { + enum HdmiAudioCodingType formatCode; + uint32_t sampleRateNum; + enum HdmiSampleRate sampleRate[HDMI_EDID_EXTENSION_AUDIO_MAX_SAMPLE_RATE_NUM]; + uint32_t bitDepthNum; + enum HdmiAudioBitDepth bitDepth[HDMI_EDID_EXTENSION_AUDIO_MAX_BIT_DEPTH_NUM]; + uint8_t channels; + uint32_t maxBitRate; /* unit: KHz */ +}; + +/* edid extension block: Video Data Block */ +#define HDMI_EDID_EXTENSION_VIC_NATIVE_MAX 64 +#define HDMI_EDID_EXTENSION_VIC_LOWER7_MARK 0x7F +#define HDMI_EDID_EXTENSION_MAX_VIC_COUNT 128 +#define HDMI_EDID_EXTENSION_VIC_INVALID_LOW 128 +#define HDMI_EDID_EXTENSION_VIC_INVALID_HIGH 192 + +/* + * Each supported Video Format is represented by a Short Video Descriptor (SVD) containing + * a Video Identification Code (VIC) and, in the case of VICs 1 through 64, a Native Video Format indicator. + */ +struct HdmiEdidVideoInfo { + uint32_t vicNum; + uint32_t vic[HDMI_EDID_EXTENSION_MAX_VIC_COUNT]; + uint32_t nativeFormat; +}; + +/* edid extension block: (VSDB)Vendor-Specific Data Block */ +#define HDMI_EDID_EXTENSION_VSDB_LEN 3 +#define HDMI_EDID_EXTENSION_VSDB_IEEE_1ST 0x03 +#define HDMI_EDID_EXTENSION_VSDB_IEEE_2ND 0x0C +#define HDMI_EDID_EXTENSION_VSDB_IEEE_3RD 0x00 +#define HDMI_EDID_EXTENSION_VSDB_CEC_INVALID_ADDR 0xF +#define HDMI_EDID_EXTENSION_MAX_HDMI14_TMDS_RATE 340 /* unit: Mcsc */ +#define HDMI_EDID_EXTENSION_TMDS_FACTOR 5 /* unit: MHz */ +#define HDMI_EDID_EXTENSION_VSDB_3D_LEN_MARK 0x1F +#define HDMI_EDID_EXTENSION_VSDB_VIC_LEN_MARK 0xE0 +#define HDMI_EDID_EXTENSION_VSDB_VIC_LEN_SHIFT 5 +#define HDMI_EDID_EXTENSION_VSDB_3D_MULTI_PRESENT_MARK 0x60 +#define HDMI_EDID_EXTENSION_VSDB_3D_MULTI_PRESENT_SHIFT 5 +#define HDMI_EDID_EXTENSION_VSDB_3D_STR_INVALID_MARK 0x03 + +struct HdmiEdidVsdbCecAddr { + bool addrValid; + uint8_t phyAddrA; + uint8_t phyAddrB; + uint8_t phyAddrC; + uint8_t phyAddrD; +}; + +struct HdmiEdidDeepColor { + bool dcY444; + bool dc30bit; + bool dc36bit; + bool dc48bit; +}; + +struct HdmiEdidExtVsdbInfo { + struct HdmiEdidVsdbCecAddr cecAddr; + struct HdmiEdidDeepColor deepColor; + bool supportAi; + bool supportDviDual; + bool latencyFieldsPresent; + bool iLatencyFieldsPresent; + bool hdmiVideoPresent; + uint8_t videoLatency; + uint8_t audioLatency; + uint8_t interlacedVideoLatency; + uint8_t interlacedAudioLatency; + bool _3dPresent; + bool _3dMultiPresent; + bool support3dType[HDMI_VS_VIDEO_3D_BUTT]; +}; + +/* edid extension block: (HF-VSDB)HDMI Forum Vendor-Specific Data Block */ +#define HDMI_EDID_EXTENSION_HFVSDB_IEEE_1ST 0xD8 +#define HDMI_EDID_EXTENSION_HFVSDB_IEEE_2ND 0x5D +#define HDMI_EDID_EXTENSION_HFVSDB_IEEE_3RD 0xC4 +#define HDMI_EDID_EXTENSION_HFVSDB_VERSION 0x01 +#define HDMI_EDID_EXTENSION_HFVSDB_MIN_INVALID_LEN 7 +#define HDMI_EDID_EXTENSION_HFVSDB_MAX_INVALID_LEN 31 + +/* deep color Y420(4:2:0) */ +struct HdmiEdidExtHfVsdbDeepColor { + bool dc30bit; + bool dc36bit; + bool dc48bit; +}; + +/* dsc(Display Stream Compression ) */ +struct HdmiEdidExtHfVsdbDscInfo { + bool dsc1p2; + bool dscNative420; + bool dscAllBpp; + bool dsc10bpc; + bool dsc20bpc; + bool dsc16bpc; + uint8_t dscMaxSlices; + uint8_t dscMaxFrlRate; + uint8_t dscTotalChunkKBytes; +}; + +struct HdmiEdidExtHfVsdbInfo { + bool scdcPresent; + bool rrCapable; /* read request cap. */ + bool lte340McscScramble; + bool independentView; + bool dualView; + bool _3dOsdDisparity; + struct HdmiEdidExtHfVsdbDeepColor dc; + /* hdmi 2.1 */ + uint8_t maxFrlRate; + bool fapaStartLocation; + bool allm; + bool fva; + bool cnmVrr; + bool cinemaVrr; + bool mDelta; + uint8_t vrrMin; + uint16_t vrrMax; + struct HdmiEdidExtHfVsdbDscInfo dscInfo; +}; + +/* edid extension block: Speaker Allocation Data Block */ +#define HDMI_EDID_EXTENSION_SADB_MIN_INVALID_LEN 2 + +enum HdmiEdidAudioSpeaker { + HDMI_EDID_AUDIO_SPEAKER_FL_FR = 0, + HDMI_EDID_AUDIO_SPEAKER_LFE = 1, + HDMI_EDID_AUDIO_SPEAKER_FC = 2, + HDMI_EDID_AUDIO_SPEAKER_BL_BR = 3, + HDMI_EDID_AUDIO_SPEAKER_BC = 4, + HDMI_EDID_AUDIO_SPEAKER_FLC_FRC = 5, + HDMI_EDID_AUDIO_SPEAKER_RLC_RRC = 6, + HDMI_EDID_AUDIO_SPEAKER_FLW_FRW = 7, + HDMI_EDID_AUDIO_SPEAKER_TPFL_TPFH = 8, + HDMI_EDID_AUDIO_SPEAKER_TPC = 9, + HDMI_EDID_AUDIO_SPEAKER_TPFC = 10, + HDMI_EDID_AUDIO_SPEAKER_BUTT, +}; + +/* + * If the Tag Code is 7 (Use Extended Tag) then the second byte of the data block contains the Extended + * Tag Code, which indicates the actual type of the data block. + */ +enum HdmiEdidExtExtenedDataBlockType { + HDMI_EDID_EXT_VCDB = 0, /* Video Capability Data Block */ + HDMI_EDID_EXT_VSVDB = 1, /* Vendor-Specific Video Data Block */ + HDMI_EDID_EXT_VESA_DDDB = 2, /* VESA Display Device Data Block */ + HDMI_EDID_EXT_VESA_VTBE = 3, /* VESA Video Timing Block Extension */ + HDMI_EDID_EXT_CDB = 5, /* Colorimetry Data Block */ + HDMI_EDID_EXT_HDR_SMDB = 6, /* HDR Static Metadata Data Block */ + HDMI_EDID_EXT_HDR_DMDB = 7, /* HDR Dynamic Metadata Data Block */ + HDMI_EDID_EXT_VFPDB = 13, /* Video Format Preference Data Block */ + HDMI_EDID_EXT_YCBCR420_VDB = 14, /* YCBCR 4:2:0 Video Data Block */ + HDMI_EDID_EXT_YCBCR420_CMDB = 15, /* YCBCR 4:2:0 Capability Map Data Block */ + HDMI_EDID_EXT_VSADB = 17, /* Vendor-Specific Audio Data Block */ + HDMI_EDID_EXT_RCDB = 19, /* Room Configuration Data Block */ + HDMI_EDID_EXT_SLDB = 20, /* Speaker Location Data Block */ + HDMI_EDID_EXT_INFOFRAME_DB = 32, /* InfoFrame Data Block (includes one or more Short InfoFrame Descriptors) */ + HDMI_EDID_EXT_BUTT, +}; + +/* edid extension block: Colorimetry Data Block */ +#define HDMI_EDID_CDB_LEN 3 + +struct HdmiEdidColorimetry { + bool xvYcc601; + bool xvYcc709; + bool sYcc601; + bool opYcc601; + bool opRgb; + bool bt2020cYcc; + bool bt2020Ycc; + bool bt2020Rgb; + bool dciP3; + uint8_t md; +}; + +/* edid extension block: Vendor-Specific Video Data Block */ +#define HDMI_EDID_VSVDB_DOLBY_OUI 0x00D046 +#define HDMI_EDID_VSVDB_DOLBY_VERSION_0 0x00 +#define HDMI_EDID_VSVDB_DOLBY_VERSION_1 0x01 +#define HDMI_EDID_VSVDB_DOLBY_VERSION_0_LEN 27 +#define HDMI_EDID_VSVDB_DOLBY_VERSION_1_LEN 14 +#define HDMI_EDID_VSVDB_DOLBY_LOWER_2BIT_MARK 0x03 +#define HDMI_EDID_VSVDB_DOLBY_LOWER_3BIT_MARK 0x07 +#define HDMI_EDID_VSVDB_DOLBY_LOWER_7BIT_MARK 0x7F +#define HDMI_EDID_VSVDB_DOLBY_VERSION_MARK 0xE0 +#define HDMI_EDID_VSVDB_DOLBY_VERSION_SHIFT 5 +#define HDMI_EDID_VSVDB_DOLBY_DM_VER_MARK 0x1C +#define HDMI_EDID_VSVDB_DOLBY_DM_VER_SHIFT 2 + + +struct HdmiEdidVsvdbDolbyCap { + uint32_t oui; + uint8_t version; + bool yuv422; + bool b2160p60; /* capable of processing a max timing 3840X2160p60. */ + bool globalDimming; + uint16_t redX; + uint16_t redY; + uint16_t greenX; + uint16_t greenY; + uint16_t blueX; + uint16_t blueY; + uint16_t whiteX; /* only version0 support */ + uint16_t whiteY; /* only version0 support */ + uint16_t minLuminance; + uint16_t maxLuminance; + uint8_t dMajorVer; /* only version0 support */ + uint8_t dMinorVer; /* only version0 support */ + bool colorimetry; /* only version1 support */ + uint8_t dmVer; /* only version1 support */ +}; + +/* edid extension block: Video Capability Data Block */ +#define HDMI_EDID_VCDB_LEN 2 + +struct HdmiEdidVideoCapability { + bool qy; /* Quantization Range(Applies to YCC only) */ + bool qs; /* Quantization Range Selectable(Applies to RGB only) */ +}; + +/* edid extension block: HDR Static Metadata Data Block */ +#define HDMI_EDID_HDR_SMDB_MIN_LEN 3 + +/* EOTF(Electro-Optical Transfer Functions) */ +struct HdmiEdidHdrSmdbEotf { + bool sdr; /* Traditional gamma - SDR Luminance Range */ + bool hdr; /* Traditional gamma - HDR Luminance Range */ + bool smpteSt2048; /* SMPTE ST 2084 */ + bool hlg; /* Hybrid Log-Gamma (HLG) based on Recommendation ITU-R BT.2100-0 */ +}; + +struct HdmiEdidHdrCap { + struct HdmiEdidHdrSmdbEotf eotf; + bool smType1; /* Static Metadata Type 1 */ + uint8_t maxLuminancedata; /* Desired Content Max Luminance data */ + uint8_t maxFrameAverageLuminanceData; /* Desired Content Max Frame-average Luminance data */ + uint8_t minLuminanceData; /* Desired Content Min Luminance data */ +}; + +/* edid extension block: YCBCR 4:2:0 Capability Map Data Block */ +struct HdmiEdidYcbcr420Cap { + uint32_t onlySupportY420VicNum; + uint32_t onlySupportY420Format[HDMI_EDID_EXTENSION_MAX_VIC_COUNT]; + uint32_t SupportY420VicNum; + uint32_t SupportY420Format[HDMI_EDID_EXTENSION_MAX_VIC_COUNT]; +}; + +/* sink device cap */ +struct HdmiSinkDeviceCapability { + uint8_t extBlockNum; + struct HdmiEdidVendorInfo vendorInfo; + struct HdmiEdidVersionInfo verInfo; + char sinkDeviceName[HDMI_EDID_MAX_SINK_NAME_COUNT]; + struct HdmiEdidBasicDispParamInfo disp; + struct HdmiEdidEstablishedTimingsInfo establishedTimingsInfo; + struct HdmiEdidStdTimingInfo stdTimingsInfo[HDMI_EDID_STANDARD_TIMING_COUNT]; + struct HdmiEdidColorInfo colorInfo; + struct HdmiEdidColorSpace colorSpace; + uint32_t preTimingCnt; + struct HdmiEdidPreferredTimingInfo preTimingInfo[HDMI_EDID_MAX_DETAILED_TIMING_COUNT]; + uint32_t audioInfoCnt; + struct HdmiEdidAudioInfo audioInfo[HDMI_EDID_EXTENSION_AUDIO_CAP_COUNT]; + struct HdmiEdidVideoInfo videoInfo; + uint32_t maxTmdsClk; + bool supportHdmi14; + bool supportHdmi20; + bool supportAudio; + struct HdmiEdidExtVsdbInfo vsdbInfo; + struct HdmiEdidExtHfVsdbInfo hfVsdbInfo; + bool supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_BUTT]; + struct HdmiEdidColorimetry colorimetry; + struct HdmiEdidVideoCapability videoCap; + struct HdmiEdidYcbcr420Cap y420Cap; + struct HdmiEdidHdrCap hdrCap; + struct HdmiEdidVsvdbDolbyCap dolbyCap; +}; + +/* + * EDID(Extended Display Identification Data). + * The Source read the Sink's EDID in order to discover the Sink's configuration and/or capabilities. + */ +struct HdmiEdid { + bool edidPhase; + uint32_t rawLen; + uint8_t raw[HDMI_EDID_TOTAL_SIZE]; + struct HdmiSinkDeviceCapability sinkCap; +}; + +typedef int32_t (*HdmiEdidPhaseFunc)(struct HdmiEdid *edid); + +int32_t HdmiEdidReset(struct HdmiEdid *edid); +int32_t HdmiEdidPhase(struct HdmiEdid *edid); +int32_t HdmiEdidGetRaw(struct HdmiEdid *edid, uint8_t *raw, uint32_t len); +int32_t HdmiEdidRawDataRead(struct HdmiEdid *edid, struct HdmiDdc *ddc); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_EDID_H */ diff --git a/support/platform/include/hdmi/hdmi_event.h b/support/platform/include/hdmi/hdmi_event.h new file mode 100644 index 00000000..5a88a454 --- /dev/null +++ b/support/platform/include/hdmi/hdmi_event.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_EVENT_H +#define HDMI_EVENT_H + +#include "hdf_base.h" +#include "platform_core.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/* HPD(hot plug detect) */ +#define HDMI_READ_HPD_STATUS_DELAY 110 /* ms */ + +enum HdmiEventType { + HDMI_EVENT_HOTPLUG = 0, + HDMI_EVENT_HOTUNPLUG = 1, + HDMI_EVENT_DETECT_SINK = 2, + HDMI_EVENT_CEC_MSG = 3, + HDMI_EVENT_HDCP_MSG = 4, + HDMI_EVENT_ZERO_DRMIF_TIMEOUT = 5, + HDMI_EVENT_SWITCH_TO_HDRMODE_TIMEOUT = 6, + HDMI_EVENT_BUTT, +}; + +struct HdmiEventMsg { + struct PlatformMsg msg; + void *priv; +}; + +struct HdmiEvent { + bool plugged; + bool hpdDetected; +}; + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_EVENT_H */ diff --git a/support/platform/include/hdmi/hdmi_frl.h b/support/platform/include/hdmi/hdmi_frl.h new file mode 100644 index 00000000..4d034629 --- /dev/null +++ b/support/platform/include/hdmi/hdmi_frl.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_FRL_H +#define HDMI_FRL_H + +#include "hdf_base.h" +#include "osal_time.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/* FRL(Fix Rate Link) */ +enum HdmiFrlMode { + HDMI_FRL_MODE_TMDS = 0, + HDMI_FRL_MODE_FRL = 1, + HDMI_FRL_MODE_BUTT, +}; + +#define HDMI_FRL_3_LANES 3 +#define HDMI_FRL_4_LANES 4 + +enum HdmiFrlWorkMode { + HDMI_FRL_WORK_MODE_NONE = 0, + HDMI_FRL_WORK_MODE_3L3G = 1, /* 3 lanes, 3Gbps per lane */ + HDMI_FRL_WORK_MODE_3L6G = 2, /* 3 lanes, 6Gbps per lane */ + HDMI_FRL_WORK_MODE_4L6G = 3, /* 4 lanes, 6Gbps per lane */ + HDMI_FRL_WORK_MODE_4L8G = 4, /* 4 lanes, 8Gbps per lane */ + HDMI_FRL_WORK_MODE_4L10G = 5, /* 4 lanes, 10Gbps per lane */ + HDMI_FRL_WORK_MODE_4L12G = 6, /* 4 lanes, 12Gbps per lane */ + HDMI_FRL_WORK_MODE_BUTT, +}; + +enum HdmiFrlBitRate { + HDMI_FRL_BIT_RATE_3 = 3, + HDMI_FRL_BIT_RATE_6 = 6, + HDMI_FRL_BIT_RATE_8 = 8, + HDMI_FRL_BIT_RATE_10 = 10, + HDMI_FRL_BIT_RATE_12 = 12, + HDMI_FRL_BIT_RATE_BUTT, +}; + +enum HdmiFrlTrainPattern { + HDMI_FRL_TRAIN_PATTERN_NULL = 0, + HDMI_FRL_TRAIN_PATTERN_LP1 = 1, + HDMI_FRL_TRAIN_PATTERN_LP2 = 2, + HDMI_FRL_TRAIN_PATTERN_LP3 = 3, + HDMI_FRL_TRAIN_PATTERN_LP4 = 4, + HDMI_FRL_TRAIN_PATTERN_LP5 = 5, + HDMI_FRL_TRAIN_PATTERN_LP6 = 6, + HDMI_FRL_TRAIN_PATTERN_LP7 = 7, + HDMI_FRL_TRAIN_PATTERN_LP8 = 8, + HDMI_FRL_TRAIN_PATTERN_REV = 9, + HDMI_FRL_TRAIN_PATTERN_0E = 14, + HDMI_FRL_TRAIN_PATTERN_0F = 15, + HDMI_FRL_TRAIN_PATTERN_BUTT, +}; + +enum HdmiFrlTrainStatus { + HDMI_FRL_TRAIN_STATUS_NULL = 0, + HDMI_FRL_TRAIN_STATUS_FAIL = 1, + HDMI_FRL_TRAIN_STATUS_SUCC = 2, + HDMI_FRL_TRAIN_STATUS_BUSY = 3, + HDMI_FRL_TRAIN_STATUS_BUTT, +}; + +enum HdmiFrlTrainingFailReason { + HDMI_FRL_TRAIN_FAIL_NORMAL, + HDMI_FRL_TRAIN_FAIL_FLT_TIMEOUT, + HDMI_FRL_TRAIN_FAIL_FLT_STEP_TIMEOUT, + HDMI_FRL_TRAIN_FAIL_RATE_CHANGE, + HDMI_FRL_TRAIN_FAIL_FFE_CHANGE, + HDMI_FRL_TRAIN_FAIL_BUTT +}; + +enum HdmiFrlTrainStep { + HDMI_FRL_TRAIN_STEP_READR_CHECK = 0, + HDMI_FRL_TRAIN_STEP_TRAIN_START = 1, + HDMI_FRL_TRAIN_STEP_RESULT_CHECK = 2, + HDMI_FRL_TRAIN_STEP_RATE_CHANGE = 3, + HDMI_FRL_TRAIN_STEP_RESULT_HANDLE = 4, + HDMI_FRL_TRAIN_STEP_RETRAIN_CHECK = 5, + HDMI_FRL_TRAIN_STEP_TRAIN_STOP = 6, + HDMI_FRL_TRAIN_STEP_BUTT, +}; + +enum HdmiFrlRateSelect { + HDMI_FRL_RATE_LITTLE = 0, + HDMI_FRL_RATE_BIG = 1, + HDMI_FRL_RATE_BUTT, +}; + +enum HdmiFrlPixelFormatMode { + HDMI_FRL_PIXEL_FORMAT_MODE_0 = 0, + HDMI_FRL_PIXEL_FORMAT_MODE_1 = 1, + HDMI_FRL_PIXEL_FORMAT_MODE_2 = 2, + HDMI_FRL_PIXEL_FORMAT_MODE_3 = 3, +}; + +enum HdmiFrlBypass { + HDMI_FRL_BYPASS_READ_CHECK = 0x01, + HDMI_FRL_BYPASS_RESULT_CHECK = 0x02, + HDMI_FRL_BYPASS_RETRAIN_CHECK = 0x04, +}; + +/* + * Feed Forward Equalizer(FFE) + * Tx terminal will use 0=TxFFE0 FFE in Link Training. If higher rate signal needs to be transmitted, + * Tx will decide higher FFE compensation through Link Training to ensure + * that video and audio data can be completely transmitted to the Sink terminal. + */ +enum HdmiFrlTxffeMode { + HDMI_FRL_TXFFE_MODE_0 = 0, + HDMI_FRL_TXFFE_MODE_1 = 1, + HDMI_FRL_TXFFE_MODE_2 = 2, + HDMI_FRL_TXFFE_MODE_3 = 3, + HDMI_FRL_TXFFE_MODE_BUTT, +}; + +enum HdmiFrlStrategyMode { + HDMI_FRL_STRATEGY_MODE_1, + HDMI_FRL_STRATEGY_MODE_2, + HDMI_FRL_STRATEGY_MODE_3, + HDMI_FRL_STRATEGY_MODE_BUTT +}; + +enum HdmiFrlStateMachineRunningState { + HDMI_FRL_STATE_MACHINE_NULL = 0, + HDMI_FRL_STATE_MACHINE_START = 1, + HDMI_FRL_STATE_MACHINE_STOP = 2, +}; + +struct HdmiFrlStateMachineInfo { + bool start; + enum HdmiFrlTrainStep trainingState; + enum HdmiFrlStateMachineRunningState machineState; + uint64_t startTime; /* ms */ + uint32_t waitReadyTime; /* ms */ + uint32_t waitHandleTime; /* ms */ + uint32_t waitRetrainTime; /* ms */ + uint32_t trainTimeout; /* ms */ + uint32_t timeoutCnt; +}; + +struct HdmiFrlInfo { + uint8_t curFrlRate; + uint8_t minFrlRate; + uint8_t maxFrlRate; + uint8_t preFrlRate; + uint32_t trainFailCnt; + uint32_t trainMaxFailTimes; + uint32_t tmdsClock; + enum HdmiFrlMode perMode; + enum HdmiFrlMode mode; + enum HdmiFrlStrategyMode strategy; + enum HdmiFrlRateSelect rateSelect; + bool scdc; + bool ctsMode; + bool start; + bool work; + struct HdmiFrlStateMachineInfo machineInfo; + uint32_t trainingFailCnt; + uint32_t trainingMaxFailTimes; +}; + +struct HdmiFrl { + struct HdmiFrlInfo info; + void *priv; +}; + +struct HdmiFrlAudioNctsConfig { + enum HdmiSampleRate sampleRate; + enum HdmiFrlMode mode; + uint8_t frlRate; + uint32_t pixelClk; + uint32_t n; + uint32_t cts; +}; + +struct HdmiFrlTrainConfig { + bool frlNoTimeout; + uint8_t frlRate; + uint8_t txffe; + uint32_t trainTimeout; +}; + +struct HdmiFrlTrainRslt { + enum HdmiFrlTrainStatus status; + enum HdmiFrlTrainPattern pattern[HDMI_FRL_4_LANES]; + enum HdmiFrlTrainingFailReason failReason; +}; + +void HdmiFrlEnable(struct HdmiFrl *frl, bool enable); +bool HdmiFrlSupport(struct HdmiFrl *frl); +int32_t HdmiFrlModeSelect(struct HdmiFrl *frl); +bool HdmiFrlModeChanged(struct HdmiFrl *frl); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_FRL_H */ diff --git a/support/platform/include/hdmi/hdmi_hdcp.h b/support/platform/include/hdmi/hdmi_hdcp.h new file mode 100644 index 00000000..9a7e743c --- /dev/null +++ b/support/platform/include/hdmi/hdmi_hdcp.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_HDCP_H +#define HDMI_HDCP_H + +#include "hdf_base.h" +#include "osal_mutex.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/* HDCP(High-bandwidth Digital Content Protection) Sysytem. */ + +enum HdmiHdcpPortOffset { + /* HDCP 1.4 Spec */ + HDMI_HDCP_BKSV = 0x00, /* Rd, 5 bytes */ + HDMI_HDCP_RI = 0x08, /* Rd, 2 bytes */ + HDMI_HDCP_PJ = 0x0A, /* Rd, 1 byte */ + HDMI_HDCP_AKSV = 0x10, /* Wr, 5 bytes */ + HDMI_HDCP_AINFO = 0x15, /* Wr, 1 byte */ + HDMI_HDCP_AN = 0x18, /* Wr, 8 bytes */ + HDMI_HDCP_V_H0 = 0x20, /* Rd, 4 bytes */ + HDMI_HDCP_V_H1 = 0x24, /* Rd, 4 bytes */ + HDMI_HDCP_V_H2 = 0x28, /* Rd, 4 bytes */ + HDMI_HDCP_V_H3 = 0x2C, /* Rd, 4 bytes */ + HDMI_HDCP_V_H4 = 0x30, /* Rd, 4 bytes */ + HDMI_HDCP_BCAPS = 0x40, /* Rd, 1 byte */ + HDMI_HDCP_BSTATUS = 0x41, /* Rd, 2 bytes */ + HDMI_HDCP_KSV_FIFO = 0x43, /* Rd, 1 byte */ + + /* HDCP 2.2 Spec */ + HDMI_HDCP_HDCP2VERSION = 0x50, /* Rd, 1 byte */ + HDMI_HDCP_WRITE_MSG = 0x60, /* Wr, 1 byte */ + HDMI_HDCP_RXSTATUS = 0x70, /* Rd, 2 bytes */ + HDMI_HDCP_READ_MSG = 0x80, /* Rd, 1 byte */ +}; + +/* HDCP 2.2 Read/Write Message Id */ +enum HdmiHdcpMsgId { + HDMI_HDCP_MSG_AKE_INIT = 2, /* Write, 12 bytes */ + HDMI_HDCP_MSG_AKE_SEND_CERT = 3, /* Read, 534 bytes */ + HDMI_HDCP_MSG_AKE_NO_STORED_KM = 4, /* Write, 129 bytes */ + HDMI_HDCP_MSG_AKE_STORED_KM = 5, /* Write, 33 bytes */ + HDMI_HDCP_MSG_AKE_SEND_H_PRIME = 7, /* Read, 33 bytes */ + HDMI_HDCP_MSG_AKE_SEND_PAIRING_INFO = 8, /* Read, 17 bytes */ + HDMI_HDCP_MSG_LC_INIT = 9, /* Write, 9 bytes */ + HDMI_HDCP_MSG_LC_SEND_L_PRIME = 10, /* Read, 33 bytes */ + HDMI_HDCP_MSG_SKE_SEND_EKS = 11, /* Write, 25 bytes */ + HDMI_HDCP_MSG_REPEATER_AUTH_SEND_RCVID_LIST = 12, /* Read, 22 + 5 * device_count bytes */ + HDMI_HDCP_MSG_REPEATER_AUTH_SEND_ACK = 15, /* Write, 17 bytes */ + HDMI_HDCP_MSG_REPEATER_AUTH_STREAM_MANAGE = 16, /* Write, 6 + 2 * k bytes */ + HDMI_HDCP_MSG_REPEATER_AUTH_STREAM_READY = 17, /* Read, 33 bytes */ +}; + +enum HdmiHdcpRegOptType { + /* HDCP 1.4 Spec */ + HDMI_HDCP_OPT_WRITE_BKSV = 0x00, + HDMI_HDCP_OPT_WRITE_RI = 0x01, + HDMI_HDCP_OPT_WRITE_PJ = 0x02, + HDMI_HDCP_OPT_WRITE_V_H0 = 0x03, + HDMI_HDCP_OPT_WRITE_V_H1 = 0x04, + HDMI_HDCP_OPT_WRITE_V_H2 = 0x05, + HDMI_HDCP_OPT_WRITE_V_H3 = 0x06, + HDMI_HDCP_OPT_WRITE_V_H4 = 0x07, + HDMI_HDCP_OPT_WRITE_V_H_ALL = 0x08, + HDMI_HDCP_OPT_WRITE_BCAPS = 0x0C, + HDMI_HDCP_OPT_WRITE_BSTATUS = 0x0D, + HDMI_HDCP_OPT_WRITE_KSV_FIFO = 0x0E, + HDMI_HDCP_OPT_RESET_SHA = 0x0F, + HDMI_HDCP_OPT_CHECK_V = 0x10, + HDMI_HDCP_OPT_CHECK_R = 0x11, + HDMI_HDCP_OPT_AUTH_FAIL = 0x12, + HDMI_HDCP_OPT_AUTH_DONE = 0x13, + HDMI_HDCP_OPT_AUTH_CLOSE = 0x14, +}; + +#define HDMI_HDCP_MSG_BKSV_LEN 5 +#define HDMI_HDCP_MSG_RI_LEN 2 +#define HDMI_HDCP_MSG_PJ_LEN 1 +#define HDMI_HDCP_MSG_AKSV_LEN 5 +#define HDMI_HDCP_MSG_AINFO_LEN 1 +#define HDMI_HDCP_MSG_AN_LEN 8 +#define HDMI_HDCP_MSG_PER_VH_LEN 4 +#define HDMI_HDCP_MSG_ALL_VH_LEN 20 +#define HDMI_HDCP_MSG_BCAPS_LEN 1 +#define HDMI_HDCP_MSG_BSTATUS_LEN 2 +#define HDMI_HDCP_MSG_KSV_FIFO_LEN 1 +#define HDMI_HDCP_DEVICE_COUNT_MAX 127 +#define HDMI_HDCP_MSG_KSV_MAX_LEN (5 * HDMI_HDCP_DEVICE_COUNT_MAX) +#define HDMI_HDCP_GET_KSV_LEN(x) (5 * x) + +#define HDMI_HDCP_AKSV_ONE_NUM 20 +#define HDMI_HDCP_BCAPS_REPEATER_MARK 0x40 +#define HDMI_HDCP_BCAPS_KSV_FIFO_READY_MARK 0x20 +#define HDMI_HDCP_DEFAULT_READ_REG_TRY 100 +#define HDMI_HDCP_WAIT_KSV_LIST_TIMES 5000 /* 5s */ +#define HDMI_HDCP_WAIT_KSV_LIST_READ_REG_INTERVAL 20 /* 20ms */ +#define HDMI_HDCP_WAIT_KSV_LIST_READ_REG_CNT \ + (HDMI_HDCP_WAIT_KSV_LIST_TIMES / HDMI_HDCP_WAIT_KSV_LIST_READ_REG_INTERVAL) + +#define HDMI_HDCP_BSTATUS_DEVICE_COUNT_MARK 0x7F +#define HDMI_HDCP_BSTATUS_MAX_DEVS_EXCEEDED_MARK (1 << 7) +#define HDMI_HDCP_BSTATUS_MAX_CASCADE_EXCEEDED_MARK (1 << 11) +#define HDMI_HDCP_BSTATUS_DEPTH_MARK 0x07 +#define HDMI_HDCP_BSTATUS_DEPTH_SHIFT 8 + + +#define HDMI_HDCP_MSG_HDCP2VERSION_LEN 1 +#define HDMI_HDCP_MSG_RXSTATUS_LEN 2 +#define HDMI_HDCP_MSG_AKE_INIT_LEN 12 +#define HDMI_HDCP_MSG_AKE_CERT_LEN 534 +#define HDMI_HDCP_MSG_AKE_NO_STORED_KM_LEN 129 +#define HDMI_HDCP_MSG_AKE_STORED_KM_LEN 33 +#define HDMI_HDCP_MSG_AKE_H_PRIME_LEN 33 +#define HDMI_HDCP_MSG_AKE_PAIRING_INFO 17 +#define HDMI_HDCP_MSG_LC_INIT_LEN 9 +#define HDMI_HDCP_MSG_LC_L_PRIME_LEN 33 +#define HDMI_HDCP_MSG_SKE_EKS_LEN 25 +#define HDMI_HDCP_MSG_AUTH_RCVID_LIST_LEN (22 + 5 * 31) +#define HDMI_HDCP_MSG_REPEATER_AUTH_ACK_LEN 17 +#define HDMI_HDCP_MSG_REPEATER_AUTH_STREAM_MANAGE_LEN (6 + 2 * 31) +#define HDMI_HDCP_MSG_REPEATER_AUTH_STREAM_READY_LEN 33 + +#define HDMI_HDCP_2_2_VERSION 2 +#define HDMI_HDCP_GET_AUTH_RCVID_LIST_LEN(x) (22 + 5 * x) + +struct HdmiHdcpMsg { + /* HDCP 1.4 message */ + uint8_t bksv[HDMI_HDCP_MSG_BKSV_LEN]; + uint8_t ri[HDMI_HDCP_MSG_RI_LEN]; + uint8_t pj; + uint8_t aksv[HDMI_HDCP_MSG_AKSV_LEN]; + uint8_t ainfo; + uint8_t an[HDMI_HDCP_MSG_AN_LEN]; + uint8_t vh[HDMI_HDCP_MSG_ALL_VH_LEN]; + uint8_t bcaps; + uint8_t bstatus[HDMI_HDCP_MSG_BSTATUS_LEN]; + uint8_t ksvList[HDMI_HDCP_MSG_KSV_MAX_LEN]; + uint32_t ksvLen; + + /* HDCP 2.2 Message */ + uint8_t Hdcp2Version; + uint8_t rxStatus[HDMI_HDCP_MSG_RXSTATUS_LEN]; + uint8_t akeInit[HDMI_HDCP_MSG_AKE_INIT_LEN]; + uint8_t akeCert[HDMI_HDCP_MSG_AKE_CERT_LEN]; + uint8_t akeNoStoredKm[HDMI_HDCP_MSG_AKE_NO_STORED_KM_LEN]; + uint8_t akeStoredKm[HDMI_HDCP_MSG_AKE_STORED_KM_LEN]; + uint8_t akeHPrime[HDMI_HDCP_MSG_AKE_H_PRIME_LEN]; + uint8_t akePairingInfo[HDMI_HDCP_MSG_AKE_PAIRING_INFO]; + uint8_t lcInit[HDMI_HDCP_MSG_LC_INIT_LEN]; + uint8_t lcLPrime[HDMI_HDCP_MSG_LC_L_PRIME_LEN]; + uint8_t skeEks[HDMI_HDCP_MSG_SKE_EKS_LEN]; + uint8_t rxIdList[HDMI_HDCP_MSG_AUTH_RCVID_LIST_LEN]; + uint32_t rxIdListLen; + uint8_t authAck[HDMI_HDCP_MSG_REPEATER_AUTH_ACK_LEN]; + uint8_t authStreamManage[HDMI_HDCP_MSG_REPEATER_AUTH_STREAM_MANAGE_LEN]; + uint32_t authStreamManageLen; + uint8_t authStreamReady[HDMI_HDCP_MSG_REPEATER_AUTH_STREAM_READY_LEN]; +}; + +enum HdmiHdcpAuthState { + HDMI_HDCP_AUTH_INACTIVE = 0, + HDMI_HDCP_AUTH_AKSV_INVALID = 1, + HDMI_HDCP_AUTH_DOING = 2, + HDMI_HDCP_AUTH_DONE = 3, + HDMI_HDCP_AUTH_FAIL = 4, +}; + +#define HDMI_HDCP_AUTH_MAX_RETRY_CNT 10 +struct HdmiHdcp { + struct OsalMutex hdcpMutex; + enum HdmiHdcpAuthState state; + uint8_t authRetryCnt; + /* HDCP 1.4 */ + uint8_t aksv[HDMI_HDCP_MSG_AKSV_LEN]; /* need driver to generate */ + uint8_t an[HDMI_HDCP_MSG_AN_LEN]; /* need driver to generate */ + uint8_t bksv[HDMI_HDCP_MSG_BKSV_LEN]; + uint8_t bcaps; + uint8_t ri[HDMI_HDCP_MSG_RI_LEN]; + uint8_t bstatus[HDMI_HDCP_MSG_BSTATUS_LEN]; + uint8_t deviceCount; + uint8_t ksvList[HDMI_HDCP_MSG_KSV_MAX_LEN]; + uint32_t ksvLen; + uint8_t vh[HDMI_HDCP_MSG_ALL_VH_LEN]; + bool aksvValid; + void *priv; +}; + +struct HdmiHdcpStatus { + bool hdcp22; + bool hdcp14; + uint8_t bksv[HDMI_HDCP_MSG_BKSV_LEN]; + uint8_t aksv[HDMI_HDCP_MSG_AKSV_LEN]; +}; + +int32_t HdmiHdcpOpen(struct HdmiHdcp *hdcp); +void HdmiHdcpClose(struct HdmiHdcp *hdcp); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_HDCP_H */ diff --git a/support/platform/include/hdmi/hdmi_hdr.h b/support/platform/include/hdmi/hdmi_hdr.h new file mode 100644 index 00000000..7d8d83ff --- /dev/null +++ b/support/platform/include/hdmi/hdmi_hdr.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_HPR_H +#define HDMI_HPR_H + +#include "hdf_base.h" +#include "hdmi_if.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/* HDR(High Dynamic Range) Sysytem. */ +#define HDMI_ZERO_DRMIF_SEND_TIME 2000 +#define HDMI_HDR_STATE_CHANGE_TIME 500 + +enum HdmiHdrTimerType { + HDMI_HDR_TIMER_ZERO_DRMIF, + HDMI_HDR_TIMER_SDR_TO_HDR10, + HDMI_HDR_TIMER_TYPE_BUTT +}; + +enum HdmiHdrState { + HDMI_HDR_STATE_NONE, /* HDR state change, SDR->HDR10 don't change anything */ + HDMI_HDR_STATE_OE, /* HDR state change, SDR->HDR10 output disable and enable */ + HDMI_HDR_STATE_AVMUTE, /* HDR state change, SDR->HDR10 send avmute */ + HDMI_HDR_STATE_BUTT +}; + +struct HdmiHdrTimerConfig { + enum HdmiHdrTimerType timerType; + bool start; + uint32_t time; +}; + +struct HdmiHdrInfo { + enum HdmiHdrState state; /* Make sure that switch smoothly from non-HDR10 to HDR10. */ + struct HdmiHdrTimerConfig zeroDrmIfTimer; /* Send zero DRM infoframe when the HDR mode from HDR10 to non-HDR10. */ + struct HdmiHdrTimerConfig stateChangeTimer; /* */ +}; + +struct HdmiHdr { + struct HdmiHdrInfo info; + void *priv; +}; + +int32_t HdmiHdrAttrHandle(struct HdmiHdr *hdr, struct HdmiHdrAttr *curAttr); +int32_t HdmiHdrDrmInfoframeStop(struct HdmiHdr *hdr); +int32_t HdmiHdrModeChangeTimeout(struct HdmiHdr *hdr); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_HPR_H */ diff --git a/support/platform/include/hdmi/hdmi_infoframe.h b/support/platform/include/hdmi/hdmi_infoframe.h new file mode 100644 index 00000000..ae2bacc3 --- /dev/null +++ b/support/platform/include/hdmi/hdmi_infoframe.h @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_INFOFRAME_H +#define HDMI_INFOFRAME_H + +#include "hdmi_common.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/* + * An InfoFrame packet carries one InfoFrame. The InfoFrame provided by HDMI is limited to 30 + * bytes plus a checksum byte. HDMI Sources are required, in some cases, to use the AVI InfoFrame and Audio InfoFrame + * and recommended in other cases. Other InfoFrames specified in CEA-861 Spec are optional. + * + * TMDS is used to carry all audio and video data as well as auxiliary data, including AVI(Auxiliary Video information) + * and Audio InfoFrames that describe the active audio and video streams. + * + */ +#define HDMI_INFOFRAME_LEN 32 +#define HDMI_INFOFRAME_PACKET_HEADER_LEN 4 +#define HDMI_AVI_INFOFRAME_LEN 13 +#define HDMI_AUDIO_INFOFRAME_LEN 10 +#define HDMI_DRM_INFOFRAME_LEN 26 +#define HDMI_SPD_INFOFRAME_LEN 25 +#define HDMI_INFOFRAME_CHECKSUM 256 + +enum HdmiPacketType { + HDMI_PACKET_TYPE_NULL = 0x00, /* Null Packet */ + HDMI_PACKET_TYPE_AUDIO_CLOCK_REGENERATION = 0x01, /* Audio Clock Regeneration(N/CTS) */ + HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02, /* Audio Samlpe(L-PCM and IEC 61937 compressed formats) */ + HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03, /* General Control Packet */ + HDMI_PACKET_TYPE_ACP = 0x04, /* ACP(Audio Content Protection Packet) */ + HDMI_PACKET_TYPE_ISRC1 = 0x05, /* ISRC(International Standard Recording Code) */ + HDMI_PACKET_TYPE_ISRC2 = 0x06, + HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07, /* One Bit Audio Sample Packet */ + HDMI_PACKET_TYPE_DST_AUDIO = 0x08, /* DST(Diret Stream Transport) Audio Packet */ + HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09, /* HBR(High Bitrate) Audio Stream Packet */ + HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a, /* gamut metadata packet */ + /* infoframe type */ + HDMI_INFOFRAME_PACKET_TYPE_VS = 0x81, /* Verdor-Specific */ + HDMI_INFOFRAME_PACKET_TYPE_AVI = 0x82, /* Auxiliary Video Information */ + HDMI_INFOFRAME_PACKET_TYPE_SPD = 0x83, /* Source Product Description */ + HDMI_INFOFRAME_PACKET_TYPE_AUDIO = 0x84, /* Audio */ + HDMI_INFOFRAME_PACKET_TYPE_MPEG = 0x85, /* MPEG Source */ + HDMI_INFOFRAME_PACKET_TYPE_GBD = 0x86, /* gamut boundary description */ + HDMI_INFOFRAME_PACKET_TYPE_DRM = 0x87, /* Dynamic Range and Mastering */ + HDMI_PACKET_TYPE_BUTT, +}; + +struct HdmiInfoframeHeader { + enum HdmiPacketType type; + uint8_t verNum; + uint8_t len; +}; + +/* Verdor-Specific infoframe details. */ +#define HDMI_VENDOR_1_4_MAX_3D_METADAT_LEN 20 +#define HDMI_VENDOR_USER_DATA_MAX_LEN 22 +#define HDMI_VENDOR_1_4_FORMAT_MARK 0x07 +#define HDMI_VENDOR_1_4_FORMAT_SHIFT 5 +#define HDMI_VENDOR_3D_STRUCTURE_MARK 0x0f +#define HDMI_VENDOR_3D_STRUCTURE_SHIFT 4 +#define HDMI_VENDOR_3D_EXT_DATA_MARK 0x0f +#define HDMI_VENDOR_3D_EXT_DATA_SHIFT 4 +#define HDMI_VSIF_VERSION 1 + +enum HdmiIeeeOui { + HDMI_IEEE_OUI_1_4 = 0x000c03, + HDMI_IEEE_OUI_2_0 = 0x045dd8, +}; + +enum HdmiVsVideoFormat { + HDMI_VS_VIDEO_FORMAT_NULL = 0, + HDMI_VS_VIDEO_FORMAT_4K = 1, + HDMI_VS_VIDEO_FORMAT_3D = 2, + HDMI_VS_VIDEO_FORMAT_BUTT, +}; + +enum HdmiVs3dExtData { + HDMI_3D_PICTURE_HORIZONTAL_ODD_LEFT_ODD_RIGHT = 0, + HDMI_3D_PICTURE_HORIZONTAL_ODD_LEFT_EVEN_RIGHT = 1, + HDMI_3D_PICTURE_HORIZONTAL_EVEN_LEFT_ODD_RIGHT = 2, + HDMI_3D_PICTURE_HORIZONTAL_EVEN_LEFT_EVEN_RIGHT = 3, + HDMI_3D_PICTURE_MATRIX_ODD_LEFT_ODD_RIGHT = 4, + HDMI_3D_PICTURE_MATRIX_ODD_LEFT_EVEN_RIGHT = 5, + HDMI_3D_PICTURE_MATRIX_EVEN_LEFT_ODD_RIGHT = 6, + HDMI_3D_PICTURE_MATRIX_EVEN_LEFT_EVEN_RIGHT = 7, + HDMI_3D_PICTURE_BUTT, +}; + +struct HdmiVs14VsifContent { + enum HdmiIeeeOui oui; + enum HdmiVsVideoFormat format; + enum Hdmi4kVic vic; + bool _3dMetaPresent; + enum HdmiVideo3dStructure _3dStruct; + enum HdmiVs3dExtData _3dExtData; + uint8_t _3dMetadataType; + uint8_t _3dMetadataLen; + uint8_t _3dMetadata[HDMI_VENDOR_1_4_MAX_3D_METADAT_LEN]; +}; + +struct HdmiVsUserVsifContent { + enum HdmiIeeeOui oui; + enum HdmiVsVideoFormat format; + enum Hdmi4kVic vic; + bool _3dMetaPresent; + enum HdmiVideo3dStructure _3dStruct; + uint8_t len; + uint8_t data[HDMI_VENDOR_USER_DATA_MAX_LEN]; +}; + +struct HdmiForumVsifContent { + enum HdmiIeeeOui oui; + uint8_t version; + bool _3dValid; + uint8_t _3dFStructure; + bool _3dAdditionalInfoPresent; + bool _3dDisparityDataPresent; + bool _3dMetaPresent; + uint8_t _3dFExtData; + uint8_t _3dDualView; + uint8_t _3dViewDependency; + uint8_t _3dPreferred2dView; + uint8_t _3dDisparityDataVersion; + uint8_t _3dDisparityDataLen; + uint8_t _3dDisparityData[10]; + uint8_t _3dMetadataType; + uint8_t _3dMetadataLen; + uint8_t _3dMetadata[10]; +}; + +struct HdmiVsInfoframe { + enum HdmiPacketType type; + uint8_t verNum; + uint8_t len; + union { + struct HdmiVs14VsifContent _14Vsif; + struct HdmiVsUserVsifContent userVsif; + struct HdmiForumVsifContent forumVsif; + } vsifContent; +}; + +/* AVI infoframe details. */ +#define HDMI_AVI_COLOR_SPACE_MARK 0x03 +#define HDMI_AVI_SCAN_MODE_MARK 0x03 +#define HDMI_AVI_COLOR_SPACE_SHIFT 5 +#define HDMI_AVI_ACTIVE_INFORMATION_SHIFT 4 +#define HDMI_AVI_HORIZONTAL_BAR_SHIFT 3 +#define HDMI_AVI_VERTICAL_BAR_SHIFT 2 + +#define HDMI_AVI_COLORIMETRY_MARK 0x03 +#define HDMI_AVI_PICTURE_ASPECT_RATE_MARK 0x03 +#define HDMI_AVI_ACTIVE_FORMAT_ASPECT_RATE_MARK 0x0f +#define HDMI_AVI_COLORIMETRY_SHIFT 6 +#define HDMI_AVI_PICTURE_ASPECT_RATE_SHIFT 4 + +#define HDMI_AVI_EXT_COLORIMETRY_MARK 0x07 +#define HDMI_AVI_EXT_QUANTIZATION_RANGE_MARK 0x03 +#define HDMI_AVI_NUPS_RANGE_MARK 0x03 +#define HDMI_AVI_IT_CONTENT_SHIFT 7 +#define HDMI_AVI_EXT_COLORIMETRY_SHIFT 4 +#define HDMI_AVI_EXT_QUANTIZATION_RANGE_SHIFT 2 + +#define HDMI_AVI_YCC_QUANTIZATION_RANGE_MARK 0x03 +#define HDMI_AVI_IT_CONTENT_TYPE_MARK 0x03 +#define HDMI_AVI_PIXEL_REPETION_FACTOR_MARK 0x0f +#define HDMI_AVI_YCC_QUANTIZATION_RANGE_SHIFT 6 +#define HDMI_AVI_IT_CONTENT_TYPE_SHIFT 4 + +#define HDMI_AVI_BAR_MODE_MARK 0xff +#define HDMI_AVI_BAR_MODE_SHIFT 8 + +#define HDMI_AVI_VERSION2 2 +#define HDMI_AVI_VERSION3 3 +#define HDMI_AVI_VERSION4 4 +#define HDMI_AVI_Y2_MASK (0x1 << 2) + +enum HdmiScanMode { + HDMI_SCAN_MODE_NO_DATA = 0, + HDMI_SCAN_MODE_OVERSCAN = 1, + HDMI_SCAN_MODE_UNDERSCAN = 2, + HDMI_SCAN_MODE_FUTURE = 3, +}; + +enum HdmiItContentType { + HDMI_IT_CONTENT_TYPE_GRAPHICS = 0, + HDMI_IT_CONTENT_TYPE_PHOTO = 1, + HDMI_IT_CONTENT_TYPE_CINEMA = 2, + HDMI_IT_CONTENT_TYPE_GAME = 3, +}; + +struct HdmiAviInfoframe { + enum HdmiPacketType type; + uint8_t verNum; + uint8_t len; + enum HdmiScanMode scanMode; + bool vertBarInfoPresent; + bool horizBarInfoPresent; + bool activeFormatInformationPresent; + enum HdmiColorSpace colorSpace; + enum HdmiActiveFormatAspectRatio activeAspect; + enum HdmiPictureAspectRatio pictureAspect; + enum HdmiColorimetry colorimetry; + enum HdmiNups nups; + enum HdmiQuantizationRange range; + enum HdmiExtendedColorimetry extColorimetry; + bool itc; /* IT content */ + uint8_t vic; + uint8_t pixelRepetitionFactor; + enum HdmiItContentType itcType; + enum HdmiYccQuantizationRange yccRange; + uint16_t topBar; + uint16_t bottomBar; + uint16_t leftBar; + uint16_t rightBar; +}; + +/* Audio infoframe details. */ +#define HDMI_AUDIO_INFOFRAME_VERSION 1 +#define HDMI_AUDIO_CODING_TYPE_MARK 0x0f +#define HDMI_AUDIO_CHANNEL_COUNT_MARK 0x07 +#define HDMI_AUDIO_CODING_TYPE_SHIFT 4 + +#define HDMI_AUDIO_SAMPLE_FREQUENCY_MARK 0x07 +#define HDMI_AUDIO_SAMPLE_SIZE_MARK 0x03 +#define HDMI_AUDIO_SAMPLE_FREQUENCY_SHIFT 2 + +#define HDMI_AUDIO_CXT_MARK 0x1f + +#define HDMI_AUDIO_LEVEL_SHIFT_VALUE_MARK 0x0f +#define HDMI_AUDIO_LEF_PLAYBACK_LEVEL_MARK 0x03 +#define HDMI_AUDIO_DM_INH_SHIFT 7 +#define HDMI_AUDIO_LEVEL_SHIFT_VALUE_SHIFT 3 + +enum HdmiAudioSampleSize { + HDMI_AUDIO_SAMPLE_SIZE_STREAM = 0, + HDMI_AUDIO_SAMPLE_SIZE_16_BIT = 1, + HDMI_AUDIO_SAMPLE_SIZE_20_BIT = 2, + HDMI_AUDIO_SAMPLE_SIZE_24_BIT = 3, +}; + +enum HdmiAudioSampleFrequency { + HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM = 0, + HDMI_AUDIO_SAMPLE_FREQUENCY_32K = 1, + HDMI_AUDIO_SAMPLE_FREQUENCY_44_1K = 2, + HDMI_AUDIO_SAMPLE_FREQUENCY_48K = 3, + HDMI_AUDIO_SAMPLE_FREQUENCY_88_2K = 4, + HDMI_AUDIO_SAMPLE_FREQUENCY_96K = 5, + HDMI_AUDIO_SAMPLE_FREQUENCY_176_4K = 6, + HDMI_AUDIO_SAMPLE_FREQUENCY_192K = 7, +}; + +enum HdmiAudioCodingExtType { + /* Refer to Audio Coding Type (CT) field in Data Byte 1 */ + HDMI_AUDIO_CODING_EXT_TYPET_CT = 0, + + /* + * The next three CXT values are defined in CEA-861-E only. + * They do not exist in older versions, and in CEA-861-F they are + * defined as 'Not in use'. + */ + HDMI_AUDIO_CODING_EXT_TYPET_HE_AAC = 1, + HDMI_AUDIO_CODING_EXT_TYPET_HE_AAC_V2 = 2, + HDMI_AUDIO_CODING_EXT_TYPET_MPEG_SURROUND = 3, + + HDMI_AUDIO_CODING_EXT_TYPET_MPEG4_HE_AAC = 4, + HDMI_AUDIO_CODING_EXT_TYPET_MPEG4_HE_AAC_V2 = 5, + HDMI_AUDIO_CODING_EXT_TYPET_MPEG4_AAC_LC = 6, + HDMI_AUDIO_CODING_EXT_TYPET_DRA = 7, + HDMI_AUDIO_CODING_EXT_TYPET_MPEG4_HE_AAC_SURROUND = 8, + HDMI_AUDIO_CODING_EXT_TYPET_RESERVED = 9, + HDMI_AUDIO_CODING_EXT_TYPET_MPEG4_AAC_LC_SURROUND = 10, + + HDMI_AUDIO_CODING_EXT_TYPET_MPEGH_3D_AUDIO = 11, + HDMI_AUDIO_CODING_EXT_TYPET_AC4 = 12, + HDMI_AUDIO_CODING_EXT_TYPET_LPCM_3D_AUDIO = 13, + HDMI_AUDIO_CODING_EXT_TYPET_BUTT, +}; + +/* LEF(Low Frequency Effects) playback level. */ +enum HdmiAudioLfePlaybackLevel { + HDMI_AUDIO_LFE_PLAYBACK_NULL = 0, + HDMI_AUDIO_LFE_PLAYBACK_0DB = 1, + HDMI_AUDIO_LFE_PLAYBACK_10DB = 2, + HDMI_AUDIO_LFE_PLAYBAC_BUTT, +}; + +struct HdmiAudioInfoframe { + enum HdmiPacketType type; + uint8_t verNum; + uint8_t len; + uint8_t channelCount; + enum HdmiAudioCodingType codingType; + enum HdmiAudioSampleSize sampleSize; + enum HdmiAudioSampleFrequency sampleFreq; + enum HdmiAudioCodingExtType codingExtType; + uint8_t channelAllocation; + enum HdmiAudioLfePlaybackLevel playBackLevel; + uint8_t levelShiftValue; + bool dmInh; /* Down-mix Inhibit Flag */ +}; + +/* Source Product Description infoframe details. */ +#define HDMI_SPD_VENDOR_NAME_LEN 8 +#define HDMI_SPD_PRODUCT_DESCRIPTION_LEN 16 +#define HDMI_SPD_VERSION 1 + +/* SDI(Source Device Information) */ +enum HdmiSpdSdi { + HDMI_SPD_SDI_NULL = 0, + HDMI_SPD_SDI_DIGITAL_STB = 1, + HDMI_SPD_SDI_DVD_PLAYER = 2, + HDMI_SPD_SDI_D_VHS = 3, + HDMI_SPD_SDI_HDD_VIDEORECORDER = 4, + HDMI_SPD_SDI_DVC = 5, + HDMI_SPD_SDI_DSC = 6, + HDMI_SPD_SDI_VIDEO_CD = 7, + HDMI_SPD_SDI_GAME = 8, + HDMI_SPD_SDI_PC_GENERAL = 9, + HDMI_SPD_SDI_BLU_RAY_DIS = 10, + HDMI_SPD_SDI_SUPER_AUDIO_CD = 11, + HDMI_SPD_SDI_HDDVD = 12, + HDMI_SPD_SDI_PMP = 13, + HDMI_SPD_SDI_BUTT, +}; + +struct HdmiSpdInfoframe { + enum HdmiPacketType type; + uint8_t verNum; + uint8_t len; + char vendorName[HDMI_SPD_VENDOR_NAME_LEN]; + char productDescription[HDMI_SPD_PRODUCT_DESCRIPTION_LEN]; + enum HdmiSpdSdi sdi; +}; + +/* Dynamic Range and Mastering infoframe details. */ +#define HDMI_DRM_METADATA_MARK 0xff +#define HDMI_DRM_METADATA_SHIFT 8 +#define HDMI_DRM_INFOFRAME_VERSION 1 + +struct HdmiDrmInfoframe { + enum HdmiPacketType type; + uint8_t verNum; + uint8_t len; + enum HdmiEotfType eotfType; + enum HdmiStaticMetadataType metadataType; + union HdmiStaticMetadataDescriptor des; +}; + +/* GBD(gamut boundary description) */ +union HdmiGbdHb1{ + struct { + uint8_t affectedGamutSeqNum : 4; /* [0:3] */ + uint8_t gbdProfil : 3; /* [4:5] */ + uint8_t reseverd: 1; /* [6] */ + uint8_t noCrntGbd : 1; /* [7] */ + } bits; + uint8_t val; +}; + +union HdmiGbdHb2{ + struct { + uint8_t currentGamutSeqNum : 4; /* [0:3] */ + uint8_t packetSeq : 2; /* [4:5] */ + uint8_t nextField : 1; /* [7] */ + } bits; + uint8_t val; +}; + +union HdmiGbdRangeData0 { + struct { + uint8_t gbdColorSpace : 3; /* [0:2] */ + uint8_t gbdColorPercision : 2; /* [3:4] */ + uint8_t rsvd: 2; /* [5:6] */ + uint8_t formatFlag : 1; /* [7] */ + } bits; + uint8_t val; +}; + +struct HdmiGbdPacket { + uint8_t hb0; + union HdmiGbdHb1 hb1; + union HdmiGbdHb2 hb2; + union HdmiGbdRangeData0 data0; + uint8_t minRedDataH; + uint8_t midRedData; /* Min_Red_Data_L | Max_Red_Data_H */ + uint8_t maxRedDataL; + uint8_t minGreenDataH; + uint8_t midGreenData; /* Min_Green_Data_L | Max_Green_Data_H */ + uint8_t maxGreenDataL; + uint8_t minBlueDataH; + uint8_t midBlueData; /* Min_Blue_Data_L | Max_Blue_Data_H */ + uint8_t maxBlueDataL; +}; + +union HdmiInfoframeInfo { + struct HdmiInfoframeHeader header; + struct HdmiVsInfoframe vs; + struct HdmiAviInfoframe avi; + struct HdmiAudioInfoframe audio; + struct HdmiSpdInfoframe spd; + struct HdmiDrmInfoframe drm; + struct HdmiGbdPacket gbd; +}; + +/* + * Infoframe: A data structure defined in CEA-861-D that is designed to carry a variety of auxiliary data items + * regarding the audio or video streams or the source device and is carried from Source to Sink across HDMI. + */ +struct HdmiInfoframe { + enum HdmiPacketType infoframeType; + bool hdrSupport; + struct HdmiVsInfoframe vs; + struct HdmiAviInfoframe avi; + struct HdmiAudioInfoframe audio; + struct HdmiSpdInfoframe spd; + struct HdmiDrmInfoframe drm; + struct HdmiGbdPacket gbd; + struct HdmiVsUserVsifContent userVsif; + void *priv; +}; + +struct HdmiInfoframeStatus { + bool vsifEnable; + bool aviEnable; + bool audioEnable; + bool spdEnable; + bool drmEnable; + bool gdbEnable; + uint8_t avi[HDMI_INFOFRAME_LEN]; + uint8_t audio[HDMI_INFOFRAME_LEN]; + uint8_t vsif[HDMI_INFOFRAME_LEN]; + uint8_t spd[HDMI_INFOFRAME_LEN]; + uint8_t drm[HDMI_INFOFRAME_LEN]; + uint8_t gdb[HDMI_INFOFRAME_LEN]; +}; + +int32_t HdmiAudioInfoframeSend(struct HdmiInfoframe *frame, bool enable); +int32_t HdmiAviInfoframeSend(struct HdmiInfoframe *frame, bool enable); +int32_t HdmiDrmInfoframeSend(struct HdmiInfoframe *frame, bool enable); +int32_t HdmiVsInfoframeSend(struct HdmiInfoframe *frame, bool enable, bool dolbyEnable); +int32_t HdmiSpdInfoframeSend(struct HdmiInfoframe *frame, bool enable, + char *vendorName, char *productName, enum HdmiSpdSdi sdi); +int32_t HdmiInfoframeGetInfo(struct HdmiInfoframe *frame, enum HdmiPacketType type, + union HdmiInfoframeInfo *infoframe); +int32_t HdmiInfoframeSetInfo(struct HdmiInfoframe *frame, enum HdmiPacketType type, + union HdmiInfoframeInfo *infoframe); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_INFOFRAME_H */ diff --git a/support/platform/include/hdmi/hdmi_ncts.h b/support/platform/include/hdmi/hdmi_ncts.h new file mode 100644 index 00000000..97923b71 --- /dev/null +++ b/support/platform/include/hdmi/hdmi_ncts.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_NCTS_H +#define HDMI_NCTS_H + +#include "hdf_base.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/* N/CTS(Cycle Time Stamp), see hdmi1.4 spec section 7.2. */ +#define HDMI_NCTS_FACTOR 128 +#define HDMI_NCTS_N_DEFAULT 6144 +#define HDMI_NCTS_TMDS_DEVIATION 20 + +struct HdmiAudioNCts { + uint32_t sampleRate; /* audio sample rate(fs) */ + uint32_t tmdsClock; + uint32_t n; + uint32_t cts; +}; + +uint32_t HdmiGetN(uint32_t sampleRate, uint32_t tmdsClock); +uint32_t HdmiGetCts(uint32_t sampleRate, uint32_t tmdsClock); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_NCTS_H */ diff --git a/support/platform/include/hdmi/hdmi_scdc.h b/support/platform/include/hdmi/hdmi_scdc.h new file mode 100644 index 00000000..532d446c --- /dev/null +++ b/support/platform/include/hdmi/hdmi_scdc.h @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#ifndef HDMI_SCDC_H +#define HDMI_SCDC_H + +#include "hdf_base.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif /* __cplusplus */ + +/* SCDC(Status and Control Data Channel) */ +#define HDMI_SCDC_HDMI20_VERSION 1 +#define HDMI_SCDC_DEFAULT_SCRAMBLE_TIMEOUT 200 /* ms */ + +/* + * SCDCS(Status and Control Data Channel Structure). + * see hdmi2.0 spec table 10-15. + */ +enum HdmiScdcsOffset { + HDMI_SCDCS_OFFSET_SINK_VERSION = 0x01, + HDMI_SCDCS_OFFSET_SOURCE_VERSION = 0x02, + HDMI_SCDCS_OFFSET_UPDATE_0 = 0x10, + HDMI_SCDCS_OFFSET_UPDATE_1 = 0x11, + HDMI_SCDCS_OFFSET_TMDS_CONFIG = 0x20, + HDMI_SCDCS_OFFSET_SCRAMBLER_STATUS = 0x21, + HDMI_SCDCS_OFFSET_CONFIG_0 = 0x30, + HDMI_SCDCS_OFFSET_CONFIG_1 = 0x31, + HDMI_SCDCS_OFFSET_TEST_CONFIG_1 = 0x35, + HDMI_SCDCS_OFFSET_STASTUS_FLAG_0 = 0x40, + HDMI_SCDCS_OFFSET_STASTUS_FLAG_1 = 0x41, + HDMI_SCDCS_OFFSET_STASTUS_FLAG_2 = 0x42, + HDMI_SCDCS_OFFSET_ERR_DET_0_L = 0x50, + HDMI_SCDCS_OFFSET_ERR_DET_0_H = 0x51, + HDMI_SCDCS_OFFSET_ERR_DET_1_L = 0x52, + HDMI_SCDCS_OFFSET_ERR_DET_1_H = 0x53, + HDMI_SCDCS_OFFSET_ERR_DET_2_L = 0x54, + HDMI_SCDCS_OFFSET_ERR_DET_2_H = 0x55, + HDMI_SCDCS_OFFSET_ERR_DET_CHECKSUM = 0x56, + HDMI_SCDCS_OFFSET_TEST_CONFIG_0 = 0xC0, + HDMI_SCDCS_OFFSET_IEEE_OUI_3TH = 0xD0, + HDMI_SCDCS_OFFSET_IEEE_OUI_2ND = 0xD1, + HDMI_SCDCS_OFFSET_IEEE_OUI_1ST = 0xD2, + HDMI_SCDCS_OFFSET_DEVICE_ID_START = 0xD3, + HDMI_SCDCS_OFFSET_DEVICE_ID_END = 0xDD, + HDMI_SCDCS_OFFSET_SPECIFIC_START = 0xDE, + HDMI_SCDCS_OFFSET_SPECIFIC_END = 0xFF, +}; + +/* + * see HDMI2.1 section 10.4.1.3. + * All update flags are readable and writable. + * The purpose of these flags is to provide a mechanism for the sink device to efficiently inform the source device + * that additional source device action may be required. + */ +union HdmiScdcsUpdateFlag0 { + uint8_t data; + struct { + uint8_t statusUpdate : 1; /* The sink shall set this bit when value is changed in the Status Flag register. */ + uint8_t cedUpdate : 1; /* ced(character error detection) register. */ + uint8_t rrTest : 1; /* rr(Read Request) */ + uint8_t srcTestUpdate : 1; + uint8_t frlStart : 1; + uint8_t fltUpdate : 1; + uint8_t rsedUpdate : 1; + uint8_t reserved : 1; + } bits; +}; + +#define HDMI_SCDC_STATUS_UPDATE_MARK (1 << 0) +#define HDMI_SCDC_CED_UPDATE_MARK (1 << 1) +#define HDMI_SCDC_RR_TEST_MARK (1 << 2) +#define HDMI_SCDC_SRC_TEST_UPDATE_MARK (1 << 3) +#define HDMI_SCDC_FRL_START_MARK (1 << 4) +#define HDMI_SCDC_FLT_UPDATE_MARK (1 << 5) +#define HDMI_SCDC_RSED_UPDATE_MARK (1 << 6) + +/* + * see HDMI2.1 section 10.4.1.4. + * All Configuration fields are readable and writable. + */ +union HdmiScdcsTmdsConfig { + uint8_t data; + struct { + uint8_t scramblingEnable : 1; + uint8_t tmdsBitClockRatio: 1; /* + * 0: TMDS_Bit_Period/TMDS_Clock_Period is 1/10; + * 1: TMDS_Bit_Period/TMDS_Clock_Period is 1/40. + */ + uint8_t reserved : 6; + } bits; +}; + +/* + * see HDMI2.1 section 10.4.1.5. + * The Status Flags are all Read Only. + */ +union HdmiScdcsScramblerStatus { + uint8_t data; + struct { + uint8_t scramblingStatus : 1; + uint8_t reserved : 7; + } bits; +}; + +/* + * see hdmi2.0 spec table 10-21. + * All Configuration fields are readable and writable. + */ +union HdmiScdcsConfig0 { + uint8_t data; + struct { + uint8_t rrEnable : 1; /* + * The source set this bit when the source supports Read Request. + * The sink shall reset this bit when SCDC of the sink goes from the disabled to enabled. + */ + uint8_t fltNoRetrain : 1; + uint8_t reserved : 6; + } bits; +}; + +/* + * see HDMI2.1 section 10.4.1.6. + */ +union HdmiScdcsConfig1 { + uint8_t data; + struct { + uint8_t frlRate : 4; /* + * Source select the FRL rate and Lane count by writing into this register. + * This field is written by the Source during the Link Training protocol. + */ + uint8_t ffeLevels : 4; + } bits; +}; + +/* + * see HDMI2.1 section 10.4.1.6. + */ +union HdmiScdcsTestConfig1 { + uint8_t data; + struct { + uint8_t reserved0 : 1; + uint8_t preShootIOnly : 1; + uint8_t deEmphasisOnly : 1; + uint8_t noFfe : 1; + uint8_t reserved1 : 1; + uint8_t fltNoTimeout : 1; + uint8_t dscFrlMax : 1; + uint8_t frlMax : 1; + } bits; +}; + +#define HDMI_SCDC_PRE_SHOOT_ONLY_MARK (1 << 1) +#define HDMI_SCDC_DE_EMPHASIS_ONLY_MARK (1 << 2) +#define HDMI_SCDC_NO_FFE_MARK (1 << 3) +#define HDMI_SCDC_FLT_NO_TIMEOUT_MARK (1 << 5) +#define HDMI_SCDC_DSC_FRL_MAX_MARK (1 << 6) +#define HDMI_SCDC_FRL_MAX_MARK (1 << 7) + +/* + * see HDMI2.1 section 10.4.1.7. + * The Status Flags are all Read Only. + */ +union HdmiScdcsStatusFlag0 { + uint8_t data; + struct { + uint8_t clockDetected : 1; /* This bit shall be set by the sink when the sink detects a valid clock signal. */ + uint8_t ch0Locked : 1; /* + * This bit shall be set by the sink when the sink is successfully decoding + * data on HDMI Channel 0. + */ + uint8_t ch1Locked : 1; /* + * This bit shall be set by the sink when the sink is successfully decoding + * data on HDMI Channel 1. + */ + uint8_t ch2Locked : 1; /* + * This bit shall be set by the sink when the sink is successfully decoding + * data on HDMI Channel 2. + */ + uint8_t ch3Locked : 1; + uint8_t reserved : 1; + uint8_t fltReady : 1; + uint8_t dscDecodeFail : 1; + } bits; +}; + +#define HDMI_SCDC_CLOCK_DETECTED_MARK (1 << 0) +#define HDMI_SCDC_CH0_LOCKED_MARK (1 << 1) +#define HDMI_SCDC_CH1_LOCKED_MARK (1 << 2) +#define HDMI_SCDC_CH2_LOCKED_MARK (1 << 3) +#define HDMI_SCDC_CH3_LOCKED_MARK (1 << 4) +#define HDMI_SCDC_FLT_READY_MARK (1 << 6) +#define HDMI_SCDC_DSC_DECODE_FAIL_MARK (1 << 7) + +/* + * see HDMI2.1 section 10.4.1.7. + * The Status Flags are all Read Only. + */ +union HdmiScdcsStatusFlag1 { + uint8_t data; + struct { + uint8_t ln0LtpReq : 4; + uint8_t ln1LtpReq : 4; + } bits; +}; + +/* + * see HDMI2.1 section 10.4.1.7. + * The Status Flags are all Read Only. + */ +union HdmiScdcsStatusFlag2 { + uint8_t data; + struct { + uint8_t ln2LtpReq : 4; + uint8_t ln3LtpReq : 4; + } bits; +}; + +/* + * see hdmi2.0 spec table 10-23. Offeset 0x50~0x55. + * The Character Error Detection counters are not writable by the source and are cleared on read by the source. + */ +union HdmiScdcsCharacterErrorDetection { + uint16_t data; + struct { + uint16_t chErrCntLower : 8; /* Channel 0/1/2 Erroe Count bits 7->0 */ + uint16_t chErrCntUpper : 7; /* Channel 0/1/2 Erroe Count bits 14->8 */ + uint16_t chValid : 1; /* Channel 0/1/2 valid flag */ + } bits; +}; + +/* + * see hdmi2.0 spec table 10-24. + * The Test Configuration registers are privided to facilitate compliance testing. + */ +union HdmiScdcsTestConfig0 { + uint8_t data; + struct { + uint8_t testReadRequestDelay : 7; + uint8_t testReadRequest : 1; /* Read/Write */ + } bits; +}; + +struct HdmiScdcsRegStatus { + uint8_t sinkVersion; + uint8_t sourceVersion; /* R/W */ + union HdmiScdcsUpdateFlag0 upfate0; /* R/W */ + union HdmiScdcsTmdsConfig tmdsCfg; /* R/W */ + union HdmiScdcsScramblerStatus scramblerStatus; + union HdmiScdcsConfig0 cfg0; /* R/W */ + union HdmiScdcsStatusFlag0 statusFlag0; + union HdmiScdcsCharacterErrorDetection errDet0; + union HdmiScdcsCharacterErrorDetection errDet1; + union HdmiScdcsCharacterErrorDetection errDet2; + uint8_t errDetChecksum; + union HdmiScdcsTestConfig0 testCfg0; /* R/W */ + uint8_t ieeeOui[HDMI_SCDCS_OFFSET_IEEE_OUI_1ST - HDMI_SCDCS_OFFSET_IEEE_OUI_3TH + 1]; + uint8_t deviceId[HDMI_SCDCS_OFFSET_DEVICE_ID_END - HDMI_SCDCS_OFFSET_DEVICE_ID_START + 1]; +}; + +struct HdmiScdcScrambleCap { + bool sinkScramble; + bool sourceScramble; + bool tmdsBitClockRatio40; +}; + +struct HdmiScdcAttribute { + bool sinkReadRequest; + bool srcScramble; + bool sinkScramble; + bool tmdsBitClockRatio40; + uint32_t ScrambleTimeOut; + uint32_t ScrambleInterval; +}; + +struct HdmiScdc { + struct HdmiScdcsRegStatus status; + struct HdmiScdcAttribute attr; + void *priv; +}; + +/* used for frl. */ +enum HdmiScdcOptMsg { + HDMI_SCDC_OPT_SET_SOURCE_VER = 0, + HDMI_SCDC_OPT_GET_SOURCE_VER = 1, + HDMI_SCDC_OPT_GET_SINK_VER = 2, + HDMI_SCDC_OPT_SET_FLT_UPDATE = 3, + HDMI_SCDC_OPT_GET_FLT_UPDATE = 4, + HDMI_SCDC_OPT_SET_FRL_START = 5, + HDMI_SCDC_OPT_GET_FRL_START = 6, + HDMI_SCDC_OPT_SET_CONFIG1 = 7, + HDMI_SCDC_OPT_GET_CONFIG1 = 8, + HDMI_SCDC_OPT_GET_TEST_CONFIG_1 = 9, + HDMI_SCDC_OPT_GET_FLT_READY = 10, + HDMI_SCDC_OPT_GET_LTP_REQ = 11, + HDMI_SCDC_OPT_BUTT, +}; + +int32_t HdmiScdcScrambleSet(struct HdmiScdc *scdc, struct HdmiScdcScrambleCap *scramble); +int32_t HdmiScdcScrambleGet(struct HdmiScdc *scdc, struct HdmiScdcScrambleCap *scramble); +bool HdmiScdcSinkSupport(struct HdmiScdc *scdc); +void HdmiScdcReset(struct HdmiScdc *scdc); +int32_t HdmiScdcOptMsgHandle(struct HdmiScdc *scdc, enum HdmiScdcOptMsg msg, uint8_t *buffer, uint32_t len); +int32_t HdmiScdcFillScrambleCap(struct HdmiScdc *scdc, struct HdmiScdcScrambleCap *scramble, + enum HdmiTmdsModeType *tmdsMode); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif /* __cplusplus */ + +#endif /* HDMI_SCDC_H */ diff --git a/support/platform/src/hdmi/hdmi_cec.c b/support/platform/src/hdmi/hdmi_cec.c new file mode 100644 index 00000000..da013387 --- /dev/null +++ b/support/platform/src/hdmi/hdmi_cec.c @@ -0,0 +1,1649 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdf_log.h" +#include "hdmi_core.h" +#include "securec.h" + +#define HDF_LOG_TAG hdmi_cec_c + +#define HDMI_CEC_PHY_ADDR_PHASE(addr) \ + ((addr) >> 12), ((addr) >> 8) & 0xf, ((addr) >> 4) & 0xf, (addr) & 0xf + +typedef void (*HdmiCecHandleMsgFunc)(struct HdmiCntlr *cntlr, struct HdmiCecMsg *oldMsg, struct HdmiCecMsg *newMsg); + +struct HdmiCecHandleMsgFuncMap { + uint8_t opcode; + HdmiCecHandleMsgFunc func; +}; + +struct HdmiCecMsgLenInfo g_cecMsg[] = { + { HDMI_CEC_OPCODE_ACTIVE_SOURCE, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_ACTIVE_SOURCE_MSG_PARAM_LEN), + HDMI_CEC_MSG_BROADCAST }, + { HDMI_CEC_OPCODE_IMAGE_VIEW_ON, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_TEXT_VIEW_ON, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_INACTIVE_SOURCE, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_INACTIVE_SOURCE_MSG_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_REQUEST_ACTIVE_SOURCE, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_BROADCAST }, + { HDMI_CEC_OPCODE_ROUTING_CHANGE, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_ROUTING_CHANGE_MSG_PARAM_LEN), + HDMI_CEC_MSG_BROADCAST }, + { HDMI_CEC_OPCODE_ROUTING_INFORMATION, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_ROUTING_INFORMATIO_MSG_PARAM_LEN), + HDMI_CEC_MSG_BROADCAST }, + { HDMI_CEC_OPCODE_SET_STREAM_PATH, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SET_STREAM_PATH_MSG_PARAM_LEN), + HDMI_CEC_MSG_BROADCAST }, + { HDMI_CEC_OPCODE_STANDBY, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_RECORD_OFF, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_RECORD_ON, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_SOURCE_TYPE_LEN), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_RECORD_STATUS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_STATUS_MSG_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_RECORD_TV_SCREEN, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_CLEAR_ANALOGUE_TIMER, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_ANALOGUE_TIMER_INFO_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_CLEAR_DIGITAL_TIMER, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_DIGITAL_TIMER_INFO_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_CLEAR_EXTERNAL_TIMER, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_EXTERNAL_TIMER_INFO_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_SET_ANALOGUE_TIMER, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_ANALOGUE_TIMER_INFO_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_SET_DIGITAL_TIMER, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_DIGITAL_TIMER_INFO_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_SET_EXTERNAL_TIMER, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_EXTERNAL_TIMER_INFO_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_SET_TIMER_PROGRAM_TITLE, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_TIMER_CLEARED_STATUS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_TIMER_CLEARED_STATUS_MSG_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_TIMER_STATUS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_TIMER_STATUS_DATA_MIN_LEN), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_CEC_VERSION, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_CEC_VERSION_MSG_PARAM_LEN), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_GET_CEC_VERSION, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_GIVE_PHYSICAL_ADDRESS, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_GET_MENU_LANGUAGE, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_REPORT_PHYSICAL_ADDRESS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_REPORT_PHYSICAL_ADDRESS_MSG_PARAM_LEN), + HDMI_CEC_MSG_BROADCAST }, + { HDMI_CEC_OPCODE_SET_MENU_LANGUAGE, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SET_MENU_LANGUAGE_MSG_PARAM_LEN), + HDMI_CEC_MSG_BROADCAST }, + { HDMI_CEC_OPCODE_REPORT_FEATURES, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_REPORT_FEATURES_MSG_PARAM_MIN_LEN), + HDMI_CEC_MSG_BROADCAST }, + { HDMI_CEC_OPCODE_GIVE_FEATURES, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_DECK_CONTROL, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_DECK_CONTROL_MSG_PARAM_LEN), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_DECK_STATUS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_DECK_STATUS_MSG_PARAM_LEN), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_GIVE_DECK_STATUS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_GIVE_DECK_STATUS_MSG_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_PLAY, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_PLAY_MSG_PARAM_LEN), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_GIVE_TUNER_DEVICE_STATU_MSG_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_SELECT_ANALOGUE_SERVICE, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SELECT_ANALOGUE_SERVICE_MSG_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_SELECT_DIGITAL_SERVICE, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SELECT_DIGITAL_SERVICE_MSG_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_TUNER_DEVICE_STATUS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_TUNER_DEVICE_STATUS_MSG_ANA_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_TUNER_STEP_DECREMENT, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_TUNER_STEP_INCREMENT, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_DEVICE_VENDOR_ID, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_DEVICE_VENDOR_ID_MSG_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_GIVE_DEVICE_VENDOR_ID, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_VENDOR_COMMAND, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_VENDOR_COMMAND_WITH_ID, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_VENDOR_ID_LEN), HDMI_CEC_MSG_ALL }, + { HDMI_CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_ALL }, + { HDMI_CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_ALL }, + { HDMI_CEC_OPCODE_SET_OSD_STRING, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_DISPLAY_CONTROL_LEN), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_GIVE_OSD_NAME, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_SET_OSD_NAME, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_MENU_REQUEST, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_MENU_REQUEST_MSG_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_MENU_STATUS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_MENU_STATUS_MSG_PARAM_LEN), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_USER_CONTROL_PRESSED, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_UI_COMMAND_LEN), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_USER_CONTROL_RELEASED, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_GIVE_DEVICE_POWER_STATUS, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_REPORT_POWER_STATUS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_REPORT_POWER_STATUS_MSG_PARA_LEN), + HDMI_CEC_MSG_DIRECTED_OR_BROADCAST_2_0 }, + { HDMI_CEC_OPCODE_FEATURE_ABORT, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_FEATURE_ABORT_MSG_PARA_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_ABORT, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_GIVE_AUDIO_STATUS, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_REPORT_AUDIO_STATUS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_REPORT_AUDIO_STATUSMSG_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_REPORT_SHORT_AUDIO_DESCRIPTOR, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_REQUEST_SHORT_AUDIO_DESCRIPTOR, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_SET_SYSTEM_AUDIO_MODE, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SYSTEM_AUDIO_STATUS_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SYSTEM_AUDIO_MODE_REQUEST_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SYSTEM_AUDIO_STATUS_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_SET_AUDIO_RATE, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SET_AUDIO_RATE_PARAM_LEN), + HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_INITIATE_ARC, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_REPORT_ARC_INITIATED, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_REPORT_ARC_TERMINATION, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_REQUEST_ARC_INITIATION, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_REQUEST_ARC_TERMINATION, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_TERMINATE_ARC, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_DIRECTED }, + { HDMI_CEC_OPCODE_CDC_MESSAGE, HDMI_CEC_GET_MSG_LEN(0), HDMI_CEC_MSG_BROADCAST }, + { HDMI_CEC_OPCODE_REQUEST_CURRENT_LATENCY, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_REQUEST_CURRENT_LATENCY_MSG_LEN), + HDMI_CEC_MSG_BROADCAST }, + { HDMI_CEC_OPCODE_REPORT_CURRENT_LATENCY, HDMI_CEC_GET_MSG_LEN(HDMI_CEC_REPORT_CURRENT_LATENCY_MSG_PARAM_MIN_LEN), + HDMI_CEC_MSG_BROADCAST } +}; + +static struct HdmiCecMsgLenInfo *HdmiCecGetMsgLenInfo(uint8_t opcode) +{ + uint32_t i, len; + + len = sizeof(g_cecMsg) / sizeof(g_cecMsg[0]); + for (i = 0; i < len; i++) { + if (opcode == g_cecMsg[i].opcode) { + return (&g_cecMsg[i]); + } + } + return NULL; +} + +static bool HdmiCecCheckTimerStatusMsgLen(struct HdmiCecMsg *msg) +{ + uint8_t info = (msg->data[2] & 0xf); /* Progremmed Info or Not Progremmed Error Info. */ + + /* Progremmed Indicator Check. */ + if ((msg->data[2] & 0x10) > 0) { + if ((info == HDMI_CEC_PROGRAMMED_INFO_NOT_ENOUGH_SPAC || + info == HDMI_CEC_PROGRAMMED_INFO_MIGHT_NOT_BE_ENOUGH_SPACE) && + msg->len < HDMI_CEC_GET_MSG_LEN(HDMI_CEC_TIMER_STATUS_DATA_MAX_LEN)) { + HDF_LOGD("check Timer_Status(Indicator) Msg fail."); + return false; + } + } else if (info == HDMI_CEC_NOT_PROG_ERR_DUPLICATE) { + if (msg->len < HDMI_CEC_GET_MSG_LEN(HDMI_CEC_TIMER_STATUS_DATA_MAX_LEN)) { + HDF_LOGD("check Timer_Status Msg fail."); + return false; + } + } + return true; +} + +static bool HdmiCecCheckRecordOnMsgLen(struct HdmiCecMsg *msg) +{ + switch (msg->data[2]) { + case HDMI_CEC_RECORD_SRC_OWN: + break; + case HDMI_CEC_RECORD_SRC_DIGITAL: + if (msg->len < HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_ON_DIGITAL_MSG_PARAM_LEN)) { + HDF_LOGD("check Record_On(DIGITAL) Msg fail."); + return false; + } + break; + case HDMI_CEC_RECORD_SRC_ANALOG: + if (msg->len < HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_ON_ANALOG_MSG_PARAM_LEN)) { + HDF_LOGD("check Record_On(ANALOG) Msg fail."); + return false; + } + break; + case HDMI_CEC_RECORD_SRC_EXT_PLUG: + if (msg->len < HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_ON_EXT_PLUG_MSG_PARAM_LEN)) { + HDF_LOGD("check Record_On(EXT_PLUG) Msg fail."); + return false; + } + break; + case HDMI_CEC_RECORD_SRC_EXT_PHY_ADDR: + if (msg->len < HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_ON_EXT_PHY_ADDR_MSG_PARAM_LEN)) { + HDF_LOGD("check Record_On(EXT_PHY_ADDR) Msg fail."); + return false; + } + break; + default : + break; + } + return true; +} + +static bool HdmiCecCheckSomeSpecialfMsgLen(struct HdmiCecMsg *msg, uint8_t opcode) +{ + bool ret = true; + + switch (opcode) { + case HDMI_CEC_OPCODE_TIMER_STATUS : + ret = HdmiCecCheckTimerStatusMsgLen(msg); + break; + case HDMI_CEC_OPCODE_RECORD_ON : + ret = HdmiCecCheckRecordOnMsgLen(msg); + default : + break; + } + return ret; +} + +static bool HdmiCecCheckMsgLen(struct HdmiCec *cec, struct HdmiCecMsg *msg, uint8_t opcode) +{ + struct HdmiCecMsgLenInfo *info = NULL; + + info = HdmiCecGetMsgLenInfo(opcode); + if (info == NULL) { + HDF_LOGD("have no this cec msg"); + return false; + } + + if (msg->len < info->minLen) { + HDF_LOGD("this cec msg is invalid, opcode = 0x%x, len = %d.", opcode, msg->len); + return false; + } + if (HdmiCecIsBroadcastMsg(msg) == true && + (info->type & HDMI_CEC_MSG_BROADCAST) == 0) { + HDF_LOGD("this cec msg,check broadcast msg fail."); + return false; + } + if (HdmiCecIsBroadcastMsg(msg) == false && + (info->type & HDMI_CEC_MSG_BROADCAST) > 0) { + HDF_LOGD("this cec msg,check directed msg fail."); + return false; + } + if (HdmiCecIsBroadcastMsg(msg) == true && + (info->type & HDMI_CEC_MSG_BROADCAST_1_4) > 0 && + cec->info.cecVersion < HDMI_CEC_VERSION_2_0) { + HDF_LOGD("this cec msg,check broadcast msg version fail."); + return false; + } + return HdmiCecCheckSomeSpecialfMsgLen(msg, opcode); +} + +/* message encoding/decoding functions. */ +void HdmiCecEncodingActiveSourceMsg(struct HdmiCecMsg *msg, uint16_t phyAddr) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_ACTIVE_SOURCE_MSG_PARAM_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_ACTIVE_SOURCE; + msg->data[2] = (phyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (phyAddr & HDMI_ONE_BYTE_MARK); +} + +void HdmiCecEncodingImageViewOnMsg(struct HdmiCecMsg *msg) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_IMAGE_VIEW_ON; +} + +void HdmiCecEncodingTextViewOnMsg(struct HdmiCecMsg *msg) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_TEXT_VIEW_ON; +} + +void HdmiCecEncodingInactiveSourceMsg(struct HdmiCecMsg *msg, uint16_t phyAddr) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_INACTIVE_SOURCE_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_INACTIVE_SOURCE; + msg->data[2] = (phyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (phyAddr & HDMI_ONE_BYTE_MARK); +} + +void HdmiCecEncodingRequestActiveSourceMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_REQUEST_ACTIVE_SOURCE; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_ACTIVE_SOURCE; + } +} + +void HdmiCecEncodingRoutingChangeMsg(struct HdmiCecMsg *msg, uint16_t orgAddr, uint16_t newAddr, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_ROUTING_CHANGE_MSG_PARAM_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_ROUTING_CHANGE; + msg->data[2] = (orgAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (orgAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = (newAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[5] = (newAddr & HDMI_ONE_BYTE_MARK); + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_ROUTING_INFORMATION; + } +} + +void HdmiCecEncodingRoutingInfomationMsg(struct HdmiCecMsg *msg, uint16_t phyAddr) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_ROUTING_INFORMATIO_MSG_PARAM_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_ROUTING_INFORMATION; + msg->data[2] = (phyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (phyAddr & HDMI_ONE_BYTE_MARK); +} + +void HdmiCecEncodingSetStreamPathMsg(struct HdmiCecMsg *msg, uint16_t phyAddr) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SET_STREAM_PATH_MSG_PARAM_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_SET_STREAM_PATH; + msg->data[2] = (phyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (phyAddr & HDMI_ONE_BYTE_MARK); +} + +void HdmiCecEncodingStandbyMsg(struct HdmiCecMsg *msg) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_STANDBY; +} + +void HdmiCecEncodingRecordOffMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_RECORD_OFF; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_RECORD_STATUS; + } +} + +static void HdmiCecEncodingRecordOnOwn(struct HdmiCecMsg *msg) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_SOURCE_TYPE_LEN); + msg->data[1] = HDMI_CEC_OPCODE_RECORD_ON; + msg->data[2] = HDMI_CEC_RECORD_SRC_OWN; +} + +static void HdmiCecEncodingDigitalServiceId(uint8_t *data, uint8_t len, struct HdmiCecDigitalServiceId *digital) +{ + if (len < HDMI_CEC_DIGITAL_SERVICE_ID_LEN) { + return; + } + + data[0] = (digital->method << HDMI_CEC_DIGITAL_SERVICE_ID_METHOD_SHIFT) | (digital->system); + if (digital->method == HDMI_CEC_SERVICE_ID_METHOD_BY_CHANNEL) { + data[1] = (digital->systemData.channel.format << HDMI_CEC_CHANNEL_NUMBER_FORMAT_SHIFT) | + (digital->systemData.channel.major >> HDMI_ONE_BYTE_SHIFT); + data[2] = digital->systemData.channel.major & HDMI_ONE_BYTE_MARK; + data[3] = digital->systemData.channel.minor >> HDMI_ONE_BYTE_SHIFT; + data[4] = digital->systemData.channel.minor & HDMI_ONE_BYTE_MARK; + return; + } + switch (digital->system) { + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN : + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS : + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS : + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ARIB_T : + data[1] = digital->systemData.arib.transportId >> HDMI_ONE_BYTE_SHIFT; + data[2] = digital->systemData.arib.transportId & HDMI_ONE_BYTE_MARK; + data[3] = digital->systemData.arib.serviceId >> HDMI_ONE_BYTE_SHIFT; + data[4] = digital->systemData.arib.serviceId & HDMI_ONE_BYTE_MARK; + data[5] = digital->systemData.arib.orgNetworkId >> HDMI_ONE_BYTE_SHIFT; + data[6] = digital->systemData.arib.orgNetworkId & HDMI_ONE_BYTE_MARK; + break; + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN : + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE : + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ATSC_SATELLITE : + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_ATSC_TERRESTRIAL : + data[1] = digital->systemData.atsc.transportId >> HDMI_ONE_BYTE_SHIFT; + data[2] = digital->systemData.atsc.transportId & HDMI_ONE_BYTE_MARK; + data[3] = digital->systemData.atsc.programNumber >> HDMI_ONE_BYTE_SHIFT; + data[4] = digital->systemData.atsc.programNumber & HDMI_ONE_BYTE_MARK; + break; + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN : + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_DVB_C : + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_DVB_S : + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_DVB_S2 : + case HDMI_CEC_DIG_SERVICE_BCAST_SYSTEM_DVB_T : + data[1] = digital->systemData.dvb.transportId >> HDMI_ONE_BYTE_SHIFT; + data[2] = digital->systemData.dvb.transportId & HDMI_ONE_BYTE_MARK; + data[3] = digital->systemData.dvb.serviceId >> HDMI_ONE_BYTE_SHIFT; + data[4] = digital->systemData.dvb.serviceId & HDMI_ONE_BYTE_MARK; + data[5] = digital->systemData.dvb.orgNetworkId >> HDMI_ONE_BYTE_SHIFT; + data[6] = digital->systemData.dvb.orgNetworkId & HDMI_ONE_BYTE_MARK; + break; + default : + HDF_LOGE("digital system 0x%x is invalid", digital->system); + } +} + +static void HdmiCecEncodingRecordOnDigital(struct HdmiCecMsg *msg, struct HdmiCecDigitalServiceId *digital) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_ON_DIGITAL_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_RECORD_ON; + msg->data[2] = HDMI_CEC_RECORD_SRC_DIGITAL; + HdmiCecEncodingDigitalServiceId(&(msg->data[3]), HDMI_CEC_DIGITAL_SERVICE_ID_LEN, digital); +} + +static void HdmiCecEncodingRecordOnAnalog(struct HdmiCecMsg *msg, + uint8_t anaBcastType, uint16_t anaFreq, uint8_t bcstSystem) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_ON_ANALOG_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_RECORD_ON; + msg->data[2] = HDMI_CEC_RECORD_SRC_ANALOG; + msg->data[3] = anaBcastType; + msg->data[4] = (anaFreq >> HDMI_ONE_BYTE_SHIFT); + msg->data[5] = (anaFreq & HDMI_ONE_BYTE_MARK); + msg->data[6] = bcstSystem; +} + +static void HdmiCecEncodingRecordOnExtPlug(struct HdmiCecMsg *msg, uint8_t extPlug) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_ON_EXT_PLUG_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_RECORD_ON; + msg->data[2] = HDMI_CEC_RECORD_SRC_EXT_PLUG; + msg->data[3] = extPlug; +} + +static void HdmiCecEncodingRecordOnExtPhyAddr(struct HdmiCecMsg *msg, uint16_t extPhyAddr) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_ON_EXT_PHY_ADDR_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_RECORD_ON; + msg->data[2] = HDMI_CEC_RECORD_SRC_EXT_PHY_ADDR; + msg->data[3] = (extPhyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[4] = (extPhyAddr & HDMI_ONE_BYTE_MARK); +} + +void HdmiCecEncodingRecordOnMsg(struct HdmiCecMsg *msg, struct HdmiCecRecordSource *src, bool response) +{ + switch (src->type) { + case HDMI_CEC_RECORD_SRC_OWN : + HdmiCecEncodingRecordOnOwn(msg); + break; + case HDMI_CEC_RECORD_SRC_DIGITAL : + HdmiCecEncodingRecordOnDigital(msg, &(src->data.id)); + break; + case HDMI_CEC_RECORD_SRC_ANALOG : + HdmiCecEncodingRecordOnAnalog(msg, src->data.analog.anaBcastType, + src->data.analog.anaFreq, src->data.analog.bcstSystem); + break; + case HDMI_CEC_RECORD_SRC_EXT_PLUG : + HdmiCecEncodingRecordOnExtPlug(msg, src->data.extPlug); + break; + case HDMI_CEC_RECORD_SRC_EXT_PHY_ADDR : + HdmiCecEncodingRecordOnExtPhyAddr(msg, src->data.extPhyAddr); + break; + default : + HDF_LOGE("cec record on: type %d unknow", src->type); + } + + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_RECORD_STATUS; + } +} + +void HdmiCecEncodingRecordStatusMsg(struct HdmiCecMsg *msg, uint8_t recordStatusInfo) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_RECORD_STATUS_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_RECORD_STATUS; + msg->data[2] = recordStatusInfo; +} + +void HdmiCecEncodingRecordTvScreenMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_RECORD_TV_SCREEN; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_RECORD_ON; + } +} + +static void HdmiCecEncodingCommTimerInfo(uint8_t *data, uint8_t len, struct HdmiCecCommTimerInfo *info) +{ + if (len < HDMI_CEC_COMM_TIMER_INFO_LEN) { + return; + } + data[0] = info->data; + data[1] = info->month; + data[2] = HDMI_CEC_BCD_FORMAT_TIME(info->startHour); + data[3] = HDMI_CEC_BCD_FORMAT_TIME(info->startMinute); + data[4] = HDMI_CEC_BCD_FORMAT_TIME(info->durationHour); + data[5] = HDMI_CEC_BCD_FORMAT_TIME(info->durationMinute); + data[6] = info->recordingSeq; +} + +static void HdmiCecEncodingAnalogueTimerInfo(uint8_t *data, uint8_t len, struct HdmiCecAnalogueTimerInfo *info) +{ + if (len < HDMI_CEC_ANALOGUE_TIMER_INFO_LEN) { + return; + } + HdmiCecEncodingCommTimerInfo(data, HDMI_CEC_COMM_TIMER_INFO_LEN, &(info->commInfo)); + data[7] = info->anaBcastType; + data[8] = (info->anaFreq >> HDMI_ONE_BYTE_SHIFT); + data[9] = (info->anaFreq & HDMI_ONE_BYTE_MARK); + data[10] = info->bcstSystem; +} + +void HdmiCecEncodingClearAnalogueTimerMsg(struct HdmiCecMsg *msg, struct HdmiCecAnalogueTimerInfo *info, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_ANALOGUE_TIMER_INFO_LEN); + msg->data[1] = HDMI_CEC_OPCODE_CLEAR_ANALOGUE_TIMER; + HdmiCecEncodingAnalogueTimerInfo(&(msg->data[2]), HDMI_CEC_ANALOGUE_TIMER_INFO_LEN, info); + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_TIMER_CLEARED_STATUS; + } +} + +static void HdmiCecEncodingDigitalTimerInfo(uint8_t *data, uint8_t len, struct HdmiCecDigitalTimerInfo *info) +{ + if (len < HDMI_CEC_DIGITAL_TIMER_INFO_LEN) { + return; + } + HdmiCecEncodingCommTimerInfo(data, HDMI_CEC_COMM_TIMER_INFO_LEN, &(info->commInfo)); + HdmiCecEncodingDigitalServiceId(&data[7], len - HDMI_CEC_COMM_TIMER_INFO_LEN, &(info->id)); +} + +void HdmiCecEncodingClearDigitalTimerMsg(struct HdmiCecMsg *msg, struct HdmiCecDigitalTimerInfo *info, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_DIGITAL_TIMER_INFO_LEN); + msg->data[1] = HDMI_CEC_OPCODE_CLEAR_DIGITAL_TIMER; + HdmiCecEncodingDigitalTimerInfo(&(msg->data[2]), HDMI_CEC_DIGITAL_TIMER_INFO_LEN, info); + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_TIMER_CLEARED_STATUS; + } +} + +static void HdmiCecEncodingExternalTimerInfo(uint8_t *data, uint8_t len, struct HdmiCecExternalTimerInfo *info) +{ + if (len < HDMI_CEC_EXTERNAL_TIMER_INFO_LEN) { + return; + } + HdmiCecEncodingCommTimerInfo(data, HDMI_CEC_COMM_TIMER_INFO_LEN, &(info->commInfo)); + data[7] = info->extSrcSpec; + data[8] = info->extPlug; + data[9] = (info->extPhyAddr >> HDMI_ONE_BYTE_SHIFT); + data[10] = (info->extPhyAddr & HDMI_ONE_BYTE_MARK); +} + +void HdmiCecEncodingClearExternalTimerMsg(struct HdmiCecMsg *msg, struct HdmiCecExternalTimerInfo *info, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_EXTERNAL_TIMER_INFO_LEN); + msg->data[1] = HDMI_CEC_OPCODE_CLEAR_EXTERNAL_TIMER; + HdmiCecEncodingExternalTimerInfo(&(msg->data[2]), HDMI_CEC_EXTERNAL_TIMER_INFO_LEN, info); + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_TIMER_CLEARED_STATUS; + } +} + +void HdmiCecEncodingSetAnalogueTimerMsg(struct HdmiCecMsg *msg, struct HdmiCecAnalogueTimerInfo *info, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_ANALOGUE_TIMER_INFO_LEN); + msg->data[1] = HDMI_CEC_OPCODE_SET_ANALOGUE_TIMER; + HdmiCecEncodingAnalogueTimerInfo(&(msg->data[2]), HDMI_CEC_ANALOGUE_TIMER_INFO_LEN, info); + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_TIMER_STATUS; + } +} + +void HdmiCecEncodingSetDigitalTimerMsg(struct HdmiCecMsg *msg, struct HdmiCecDigitalTimerInfo *info, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_DIGITAL_TIMER_INFO_LEN); + msg->data[1] = HDMI_CEC_OPCODE_SET_DIGITAL_TIMER; + HdmiCecEncodingDigitalTimerInfo(&(msg->data[2]), HDMI_CEC_DIGITAL_TIMER_INFO_LEN, info); + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_TIMER_STATUS; + } +} + +void HdmiCecEncodingSetExternalTimerMsg(struct HdmiCecMsg *msg, struct HdmiCecExternalTimerInfo *info, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_EXTERNAL_TIMER_INFO_LEN); + msg->data[1] = HDMI_CEC_OPCODE_SET_EXTERNAL_TIMER; + HdmiCecEncodingExternalTimerInfo(&(msg->data[2]), HDMI_CEC_EXTERNAL_TIMER_INFO_LEN, info); + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_TIMER_STATUS; + } +} + +void HdmiCecEncodingSetTimerProgramTitleMsg(struct HdmiCecMsg *msg, uint8_t *title, uint32_t len) +{ + uint32_t length; + + if (title == NULL || len < HDMI_CEC_PROGRAM_TITLE_STR_MIN_LEN) { + HDF_LOGE("encoding set timer program title, input param invalid."); + return; + } + length = ((len <= HDMI_CEC_PROGRAM_TITLE_STR_MAX_LEN) ? len : HDMI_CEC_PROGRAM_TITLE_STR_MAX_LEN); + msg->len = HDMI_CEC_GET_MSG_LEN(length); + msg->data[1] = HDMI_CEC_OPCODE_SET_TIMER_PROGRAM_TITLE; + if (memcpy_s(&(msg->data[2]), (msg->len - 2), title, length) != EOK) { + HDF_LOGE("encoding set timer program title, memcpy_s fail."); + } +} + +void HdmiCecEncodingTimerClearedStatusMsg(struct HdmiCecMsg *msg, uint8_t status) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_TIMER_CLEARED_STATUS_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_TIMER_CLEARED_STATUS; + msg->data[2] = status; +} + +void HdmiCecEncodingTimerStatusMsg(struct HdmiCecMsg *msg, struct HdmiCecTimerStatusData *status) +{ + bool duration = false; + + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_TIMER_STATUS_DATA_MIN_LEN); + msg->data[1] = HDMI_CEC_OPCODE_TIMER_STATUS; + msg->data[2] |= (status->timerOverlap << 7); + msg->data[2] |= (status->mediaInfo << 5); + msg->data[2] |= (status->progInfo.indicator << 4); + msg->data[2] |= (status->progInfo.info); + if (status->progInfo.indicator > 0) { + /* Progremmed Info */ + if (status->progInfo.info == HDMI_CEC_PROGRAMMED_INFO_NOT_ENOUGH_SPAC || + status->progInfo.info == HDMI_CEC_PROGRAMMED_INFO_MIGHT_NOT_BE_ENOUGH_SPACE) { + duration = true; + } + } else { + /* Not Progremmed Error Info */ + if (status->progInfo.info == HDMI_CEC_NOT_PROG_ERR_DUPLICATE) { + duration = true; + } + } + if (duration == true) { + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_TIMER_STATUS_DATA_MAX_LEN); + msg->data[3] = HDMI_CEC_BCD_FORMAT_TIME(status->progInfo.durationHour); + msg->data[4] = HDMI_CEC_BCD_FORMAT_TIME(status->progInfo.durationMinute); + } +} + +void HdmiCecEncodingCecVersionMsg(struct HdmiCecMsg *msg, uint8_t version) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_CEC_VERSION_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_CEC_VERSION; + msg->data[2] = version; +} + +void HdmiCecEncodingGetCecVersionMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_GET_CEC_VERSION; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_CEC_VERSION; + } +} + +void HdmiCecEncodingGetPhyAddressMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_GIVE_PHYSICAL_ADDRESS; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_REPORT_PHYSICAL_ADDRESS; + } +} + +void HdmiCecEncodingGetMenuLanguageMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_GET_MENU_LANGUAGE; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_SET_MENU_LANGUAGE; + } +} + +void HdmiCecEncodingReportPhyAddressMsg(struct HdmiCecMsg *msg, uint16_t phyAddr, uint8_t deviceType) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_REPORT_PHYSICAL_ADDRESS_MSG_PARAM_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_REPORT_PHYSICAL_ADDRESS; + msg->data[2] = (phyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (phyAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = deviceType; +} + +void HdmiCecEncodingSetMenuLanguageMsg(struct HdmiCecMsg *msg, uint8_t *language, uint32_t len) +{ + if (language == NULL || len != HDMI_CEC_SET_MENU_LANGUAGE_MSG_PARAM_LEN) { + HDF_LOGE("encoding set menu language, input param invalid."); + return; + } + + msg->len = HDMI_CEC_GET_MSG_LEN(len); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_SET_MENU_LANGUAGE; + if (memcpy_s(&(msg->data[2]), (msg->len - 2), language, len) != EOK) { + HDF_LOGE("encoding set menu language, memcpy_s fail."); + } +} + +void HdmiCecEncodingReportFeaturesMsg(struct HdmiCecMsg *msg, struct HdmiCecInfo *info) +{ + uint32_t i; + + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_REPORT_FEATURES; + msg->data[2] = info->cecVersion; + msg->len++; + msg->data[3] = info->allDeviceType; + msg->len++; + /* fill RC Profile. */ + for (i = 0; i < HDMI_CEC_RC_PROFILE_MAX_NUM; i++) { + msg->data[msg->len] = info->rcProfile[i]; + msg->len++; + if ((info->rcProfile[i] & HDMI_CEC_RC_PROFILE_EXTERNSION_MARK) == 0) { + break; + } + } + /* fill Device Features. */ + for (i = 0; i < HDMI_CEC_DEVICE_FEATURES_MAX_NUM; i++) { + msg->data[msg->len] = info->devFeatures[i]; + msg->len++; + if ((info->devFeatures[i] & HDMI_CEC_DEVICE_FEATURES_EXTERNSION_MARK) == 0) { + break; + } + } +} + +void HdmiCecEncodingGiveFeaturesMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_GIVE_FEATURES; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_SET_MENU_LANGUAGE; + } +} + + +void HdmiCecEncodingDeckControlMsg(struct HdmiCecMsg *msg, uint8_t mode) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_DECK_CONTROL_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_DECK_CONTROL; + msg->data[2] = mode; +} + +void HdmiCecEncodingDeckStatusMsg(struct HdmiCecMsg *msg, uint8_t info) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_DECK_STATUS_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_DECK_STATUS; + msg->data[2] = info; +} + +void HdmiCecEncodingGiveDeckStatusMsg(struct HdmiCecMsg *msg, uint8_t statusReq, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_GIVE_DECK_STATUS_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_GIVE_DECK_STATUS; + msg->data[2] = statusReq; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_DECK_STATUS; + } +} + +void HdmiCecEncodingPlayMsg(struct HdmiCecMsg *msg, uint8_t playMode) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_PLAY_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_PLAY; + msg->data[2] = playMode; +} + +void HdmiCecEncodingGiveTunerDeviceStatusMsg(struct HdmiCecMsg *msg, uint8_t statusReq, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_GIVE_TUNER_DEVICE_STATU_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS; + msg->data[2] = statusReq; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_TUNER_DEVICE_STATUS; + } +} + +void HdmiCecEncodingSelectAnalogueServiceMsg(struct HdmiCecMsg *msg, + uint8_t anaBcastType, uint16_t anaFreq, uint8_t bcstSystem) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SELECT_ANALOGUE_SERVICE_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_SELECT_ANALOGUE_SERVICE; + msg->data[2] = anaBcastType; + msg->data[3] = (anaFreq >> HDMI_ONE_BYTE_SHIFT); + msg->data[4] = (anaFreq & HDMI_ONE_BYTE_MARK); + msg->data[5] = bcstSystem; +} + +void HdmiCecEncodingSelectDigitalServiceMsg(struct HdmiCecMsg *msg, struct HdmiCecDigitalServiceId *digital) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SELECT_DIGITAL_SERVICE_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_SELECT_DIGITAL_SERVICE; + HdmiCecEncodingDigitalServiceId(&(msg->data[2]), HDMI_CEC_SELECT_DIGITAL_SERVICE_MSG_PARAM_LEN, digital); +} + +void HdmiCecEncodingTunerDeviceStatusMsg(struct HdmiCecMsg *msg, struct HdmiCecTunerDeviceInfo *info) +{ + msg->data[1] = HDMI_CEC_OPCODE_TUNER_DEVICE_STATUS; + msg->data[2] = (info->recordingFlag << 7) | (info->dispInfo); + if (info->isAnalogService == true) { + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_TUNER_DEVICE_STATUS_MSG_ANA_PARAM_LEN); + msg->data[3] = info->data.analog.anaBcastType; + msg->data[4] = (info->data.analog.anaFreq >> HDMI_ONE_BYTE_SHIFT); + msg->data[5] = (info->data.analog.anaFreq & HDMI_ONE_BYTE_MARK); + msg->data[6] = info->data.analog.bcstSystem; + } else { + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_TUNER_DEVICE_STATUS_MSG_DIG_PARAM_LEN); + HdmiCecEncodingDigitalServiceId(&(msg->data[3]), HDMI_CEC_SELECT_DIGITAL_SERVICE_MSG_PARAM_LEN, + &(info->data.digital)); + } +} + +void HdmiCecEncodingTunerStepDecrementMsg(struct HdmiCecMsg *msg) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_TUNER_STEP_DECREMENT; +} + +void HdmiCecEncodingTunerStepIncrementMsg(struct HdmiCecMsg *msg) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_TUNER_STEP_INCREMENT; +} + +void HdmiCecEncodingDeviceVendorIdMsg(struct HdmiCecMsg *msg, uint32_t devVendorId) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_DEVICE_VENDOR_ID_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_DEVICE_VENDOR_ID; + msg->data[2] = (devVendorId >> HDMI_TWO_BYTES_SHIFT) & HDMI_ONE_BYTE_MARK; + msg->data[3] = (devVendorId >> HDMI_ONE_BYTE_SHIFT) & HDMI_ONE_BYTE_MARK; + msg->data[4] = (devVendorId & HDMI_ONE_BYTE_MARK); +} + +void HdmiCecEncodingGiveDeviceVendorIdMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_GIVE_DEVICE_VENDOR_ID; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_DEVICE_VENDOR_ID; + } +} + +void HdmiCecEncodingVendorCommandMsg(struct HdmiCecMsg *msg, uint8_t *data, uint32_t len) +{ + uint32_t length; + + if (data == NULL || len == 0) { + HDF_LOGE("encoding vendor cmd, input param invalid."); + return; + } + length = (len > HDMI_CEC_VENDOR_SPECIFIC_DATA_MAX_LEN) ? HDMI_CEC_VENDOR_SPECIFIC_DATA_MAX_LEN : len; + msg->len = HDMI_CEC_GET_MSG_LEN(length); + msg->data[1] = HDMI_CEC_OPCODE_VENDOR_COMMAND; + if (memcpy_s(&(msg->data[2]), (msg->len - 2), data, length) != EOK) { + HDF_LOGE("encoding vendor cmd, memcpy_s fail."); + } +} + +void HdmiCecEncodingVendorCommandWithIdMsg(struct HdmiCecMsg *msg, uint32_t vendorId, uint8_t *data, uint32_t len) +{ + uint32_t length; + + if (data == NULL || len == 0) { + HDF_LOGE("encoding vendor cmd with id, input param invalid."); + return; + } + length = (len > HDMI_CEC_VENDOR_SPECIFIC_DATA_WITH_ID_MAX_LEN) ? + HDMI_CEC_VENDOR_SPECIFIC_DATA_WITH_ID_MAX_LEN : len; + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_VENDOR_ID_LEN + length); + msg->data[1] = HDMI_CEC_OPCODE_VENDOR_COMMAND_WITH_ID; + msg->data[2] = (vendorId >> HDMI_TWO_BYTES_SHIFT) & HDMI_ONE_BYTE_MARK; + msg->data[3] = (vendorId >> HDMI_ONE_BYTE_SHIFT) & HDMI_ONE_BYTE_MARK; + msg->data[4] = (vendorId & HDMI_ONE_BYTE_MARK); + if (memcpy_s(&(msg->data[5]), (msg->len - 5), data, length) != EOK) { + HDF_LOGE("encoding vendor cmd with id, memcpy_s fail."); + } +} + +void HdmiCecEncodingVendorRemoteButtonDownMsg(struct HdmiCecMsg *msg, uint8_t *rcCode, uint32_t len) +{ + uint32_t length; + + if (rcCode == NULL || len == 0) { + HDF_LOGE("encoding vendor remote button down, input param invalid."); + return; + } + length = (len > HDMI_CEC_VENDOR_SPECIFIC_RC_CODE_MAX_LEN) ? HDMI_CEC_VENDOR_SPECIFIC_RC_CODE_MAX_LEN : len; + msg->len = HDMI_CEC_GET_MSG_LEN(length); + msg->data[1] = HDMI_CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN; + if (memcpy_s(&(msg->data[2]), (msg->len - 2), rcCode, length) != EOK) { + HDF_LOGE("encoding vendor remote button down, memcpy_s fail."); + } +} + +void HdmiCecEncodingVendorRemoteButtonUpMsg(struct HdmiCecMsg *msg) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP; +} + +void HdmiCecEncodingSetOsdStringMsg(struct HdmiCecMsg *msg, uint8_t dispControl, uint8_t *str, uint32_t len) +{ + uint32_t length; + + if (str == NULL || len == 0) { + HDF_LOGE("encoding set OSD string, input param invalid."); + return; + } + length = (len > HDMI_CEC_OSD_STRING_MAX_LEN) ? HDMI_CEC_OSD_STRING_MAX_LEN : len; + msg->len = HDMI_CEC_GET_MSG_LEN(length + HDMI_CEC_DISPLAY_CONTROL_LEN); + msg->data[1] = HDMI_CEC_OPCODE_SET_OSD_STRING; + msg->data[2] = dispControl; + if (memcpy_s(&(msg->data[3]), (msg->len - 3), str, length) != EOK) { + HDF_LOGE("encoding set OSD string, memcpy_s fail."); + } +} + +void HdmiCecEncodingGiveOsdNameMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_GIVE_OSD_NAME; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_SET_OSD_NAME; + } +} + +void HdmiCecEncodingSetOsdNameMsg(struct HdmiCecMsg *msg, uint8_t *name, uint32_t len) +{ + uint32_t length; + + if (name == NULL || len == 0) { + HDF_LOGE("encoding set OSD name, input param invalid."); + return; + } + length = (len > HDMI_CEC_OSD_NAME_MAX_LEN) ? HDMI_CEC_OSD_NAME_MAX_LEN : len; + msg->len = HDMI_CEC_GET_MSG_LEN(length); + msg->data[1] = HDMI_CEC_OPCODE_SET_OSD_NAME; + if (memcpy_s(&(msg->data[2]), (msg->len - 2), name, length) != EOK) { + HDF_LOGE("encoding set OSD name, memcpy_s fail."); + } +} + +void HdmiCecEncodingMenuRequestMsg(struct HdmiCecMsg *msg, uint8_t menuReq, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_MENU_REQUEST_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_MENU_REQUEST; + msg->data[2] = menuReq; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_MENU_STATUS; + } +} + +void HdmiCecEncodingMenuStatusMsg(struct HdmiCecMsg *msg, uint8_t menuStatus) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_MENU_STATUS_MSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_MENU_STATUS; + msg->data[2] = menuStatus; +} + +void HdmiCecEncodingUserControlPrtessedMsg(struct HdmiCecMsg *msg, struct HdmiCecUiCmd *cmd) +{ + if (cmd == NULL) { + return; + } + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_UI_COMMAND_LEN); + msg->data[1] = HDMI_CEC_OPCODE_USER_CONTROL_PRESSED; + msg->data[2] = cmd->cmdType; + if (cmd->hasAddOp == false) { + return; + } + switch (cmd->cmdType) { + case HDMI_CEC_UI_CMD_SELECT_BROADCAST_TYPE : + case HDMI_CEC_UI_CMD_SELECT_SOUND_PRESENTATION : + case HDMI_CEC_UI_CMD_PLAY_FUNCTION : + case HDMI_CEC_UI_CMD_SELECT_MEDIA_FUNCTION : + case HDMI_CEC_UI_CMD_SELECT_AV_INPUT_FUNCTION : + case HDMI_CEC_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION : + (msg->len)++; + /* The additional operand is one byte for all these UI commands */ + msg->data[3] = cmd->addOperands.uiBroadcastType; + break; + case HDMI_CEC_UI_CMD_TUNE_FUNCTION : + msg->len += HDMI_CEC_CHANNEL_IDENTIFIER_LEN; + msg->data[3] = (cmd->addOperands.channel.format << HDMI_CEC_CHANNEL_NUMBER_FORMAT_SHIFT) | + (cmd->addOperands.channel.major >> HDMI_ONE_BYTE_SHIFT); + msg->data[4] = (cmd->addOperands.channel.major & HDMI_ONE_BYTE_MARK); + msg->data[5] = (cmd->addOperands.channel.minor >> HDMI_ONE_BYTE_SHIFT); + msg->data[6] = (cmd->addOperands.channel.minor & HDMI_ONE_BYTE_MARK); + break; + default : + HDF_LOGI("UI type %d have no additional operands.", cmd->cmdType); + break; + } +} + +void HdmiCecEncodingUserControlReleasedMsg(struct HdmiCecMsg *msg) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_USER_CONTROL_RELEASED; +} + +void HdmiCecEncodingGiveDevicePowerStatusMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_GIVE_DEVICE_POWER_STATUS; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_REPORT_POWER_STATUS; + } +} + +void HdmiCecEncodingReportDevicePowerStatusMsg(struct HdmiCecMsg *msg, uint8_t powerStatus) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_REPORT_POWER_STATUS_MSG_PARA_LEN); + msg->data[1] = HDMI_CEC_OPCODE_REPORT_POWER_STATUS; + msg->data[2] = powerStatus; +} + +void HdmiCecEncodingFeatureAbortMsg(struct HdmiCecMsg *msg, uint8_t opcode, uint8_t reason) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_FEATURE_ABORT_MSG_PARA_LEN); + msg->data[1] = HDMI_CEC_OPCODE_FEATURE_ABORT; + msg->data[2] = opcode; + msg->data[3] = reason; +} + +void HdmiCecEncodingAbortMsg(struct HdmiCecMsg *msg) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_ABORT; +} + +void HdmiCecEncodingGiveAudioStatusMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_GIVE_AUDIO_STATUS; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_REPORT_AUDIO_STATUS; + } +} + +void HdmiCecEncodingGiveSystemAudioModeMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS; + } +} + +void HdmiCecEncodingReportAudioStatusMsg(struct HdmiCecMsg *msg, uint8_t audioMuteStatus, uint8_t audioVolumeStatus) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_REPORT_AUDIO_STATUSMSG_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_REPORT_AUDIO_STATUS; + msg->data[2] = (audioMuteStatus << HDMI_CEC_AUDIO_MUTE_STATUS_SHIFT) | + (audioVolumeStatus & HDMI_CEC_AUDIO_VOLUME_STATUS_MARK); +} + +void HdmiCecEncodingRequestShortAudioDescriptorMsg(struct HdmiCecMsg *msg, + uint8_t *id, uint8_t *code, uint32_t len, bool response) +{ + uint32_t num, i; + + if (id == NULL || code == NULL || len == 0) { + HDF_LOGE("encoding request short audio descriptor, input param invalid."); + return; + } + num = (len > HDMI_CEC_MAX_AUDIO_FORMAT_NUM) ? HDMI_CEC_MAX_AUDIO_FORMAT_NUM : len; + msg->len = HDMI_CEC_GET_MSG_LEN(num * HDMI_CEC_AUDIO_FORMAT_LEN); + msg->data[1] = HDMI_CEC_OPCODE_REQUEST_SHORT_AUDIO_DESCRIPTOR; + for (i = 0; i < num; i++) { + msg->data[2 + i] = (id[i] << HDMI_CEC_AUDIO_FORMAT_ID_SHIFT) | (code[i] & HDMI_CEC_AUDIO_FORMAT_CODE_MARK); + } + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_REPORT_SHORT_AUDIO_DESCRIPTOR; + } +} + +void HdmiCecEncodingReportShortAudioDescriptorMsg(struct HdmiCecMsg *msg, uint32_t *descriptor, uint32_t len) +{ + uint32_t num, i; + + if (descriptor == NULL || len == 0) { + HDF_LOGE("encoding report short audio descriptor, input param invalid."); + return; + } + num = (len > HDMI_CEC_MAX_SHORT_AUDIO_DESCRIPTOR_NUM) ? HDMI_CEC_MAX_SHORT_AUDIO_DESCRIPTOR_NUM : len; + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SHORT_AUDIO_DESCRIPTOR_LEN * num); + msg->data[1] = HDMI_CEC_OPCODE_REPORT_SHORT_AUDIO_DESCRIPTOR; + for (i = 0; i < num; i++) { + msg->data[2 + i * HDMI_CEC_SHORT_AUDIO_DESCRIPTOR_LEN] = + (descriptor[i] >> HDMI_TWO_BYTES_SHIFT) & HDMI_ONE_BYTE_MARK; + msg->data[3 + i * HDMI_CEC_SHORT_AUDIO_DESCRIPTOR_LEN] = + (descriptor[i] >> HDMI_ONE_BYTE_SHIFT) & HDMI_ONE_BYTE_MARK; + msg->data[4 + i * HDMI_CEC_SHORT_AUDIO_DESCRIPTOR_LEN] = descriptor[i] & HDMI_ONE_BYTE_MARK; + } +} + +void HdmiCecEncodingSetSystemAudioModeMsg(struct HdmiCecMsg *msg, uint8_t status) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SYSTEM_AUDIO_STATUS_LEN); + msg->data[1] = HDMI_CEC_OPCODE_SET_SYSTEM_AUDIO_MODE; + msg->data[2] = status; +} + +void HdmiCecEncodingSystemAudioModeRequestMsg(struct HdmiCecMsg *msg, uint16_t phyAddr, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SYSTEM_AUDIO_MODE_REQUEST_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST; + msg->data[2] = (phyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (phyAddr & HDMI_ONE_BYTE_MARK); + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_SET_SYSTEM_AUDIO_MODE; + } +} + +void HdmiCecEncodingSystemAudioModeStatusMsg(struct HdmiCecMsg *msg, uint8_t status) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SYSTEM_AUDIO_STATUS_LEN); + msg->data[1] = HDMI_CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS; + msg->data[2] = status; +} + +void HdmiCecEncodingSetAudioRateMsg(struct HdmiCecMsg *msg, uint8_t rate) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_SET_AUDIO_RATE_PARAM_LEN); + msg->data[1] = HDMI_CEC_OPCODE_SET_AUDIO_RATE; + msg->data[2] = rate; +} + +void HdmiCecEncodingInitiateArcMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_INITIATE_ARC; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_REPORT_ARC_INITIATED; + } +} + +void HdmiCecEncodingReportArcInitiatedMsg(struct HdmiCecMsg *msg) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_REPORT_ARC_INITIATED; +} + +void HdmiCecEncodingReportArcTerminationMsg(struct HdmiCecMsg *msg) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_REPORT_ARC_TERMINATION; +} + +void HdmiCecEncodingRequestArcInitiationMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_REQUEST_ARC_INITIATION; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_INITIATE_ARC; + } +} + +void HdmiCecEncodingRequestArcTerminationMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_REQUEST_ARC_TERMINATION; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_TERMINATE_ARC; + } +} + +void HdmiCecEncodingTerminateArcMsg(struct HdmiCecMsg *msg, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(0); + msg->data[1] = HDMI_CEC_OPCODE_TERMINATE_ARC; + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_REPORT_ARC_TERMINATION; + } +} + +void HdmiCecEncodingRequestCurrentLatencyMsg(struct HdmiCecMsg *msg, uint16_t phyAddr, bool response) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_REQUEST_CURRENT_LATENCY_MSG_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_REQUEST_CURRENT_LATENCY; + msg->data[2] = (phyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (phyAddr & HDMI_ONE_BYTE_MARK); + if (response == true) { + msg->rspMsg = HDMI_CEC_OPCODE_REPORT_CURRENT_LATENCY; + } +} + +void HdmiCecEncodingReportCurrentLatencyMsg(struct HdmiCecMsg *msg, + uint16_t phyAddr, struct HdmiCecLatencyInfo *info) +{ + msg->len = HDMI_CEC_GET_MSG_LEN(HDMI_CEC_REPORT_CURRENT_LATENCY_MSG_PARAM_MIN_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_REPORT_CURRENT_LATENCY; + msg->data[2] = (phyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (phyAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = info->videoLatency; + msg->data[5] = (info->lowLatencyMode << HDMI_CEC_LOW_LATENCY_MODE_SHIFT) | (info->audioOutputCompensated); + /* Operand[Audio Output Delay] is only present when [Audio Output Compensated] is 3. */ + if (info->audioOutputCompensated == HDMI_CEC_AUDIO_OUTPUT_COMPENSATED_PARTIAL_DELAY) { + msg->len++; + msg->data[6] = info->audioOutputDelay; + } +} + +/* CDC Message Encoding. */ +void HdmiCdcEncodingHecInquireStateMsg(struct HdmiCecMsg *msg, uint16_t initiatorPhyAddr, + uint16_t phyAddr1, uint16_t phyAddr2, bool response) +{ + msg->len = HDMI_CDC_GET_MSG_LEN(HDMI_CDC_HEC_INQUIRE_STATE_MSG_PARAM_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_CDC_MESSAGE; + msg->data[2] = (initiatorPhyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (initiatorPhyAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = HDMI_CDC_HEC_INQUIRE_STATE; + msg->data[5] = (phyAddr1 >> HDMI_ONE_BYTE_SHIFT); + msg->data[6] = (phyAddr1 & HDMI_ONE_BYTE_MARK); + msg->data[7] = (phyAddr2 >> HDMI_ONE_BYTE_SHIFT); + msg->data[8] = (phyAddr2 & HDMI_ONE_BYTE_MARK); + if (response == true) { + msg->rspMsg = HDMI_CDC_HEC_REPORT_STATE; + } +} + +void HdmiCdcEncodingHecReportStateMsg(struct HdmiCecMsg *msg, uint16_t initiatorPhyAddr, + uint16_t phyAddr, struct HdmiCdcHecState *state) +{ + msg->len = HDMI_CDC_GET_MSG_LEN(HDMI_CDC_HEC_REPORT_STATE_MSG_PARAM_MIN_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_CDC_MESSAGE; + msg->data[2] = (initiatorPhyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (initiatorPhyAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = HDMI_CDC_HEC_REPORT_STATE; + msg->data[5] = (phyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[6] = (phyAddr & HDMI_ONE_BYTE_MARK); + msg->data[7] = (state->hecFuncState << HDMI_CDC_HEC_FUNC_STATE_SHIFT) | + (state->hostFuncState << HDMI_CDC_HOST_FUNC_STATE_SHIFT) | + (state->encFuncState << HDMI_CDC_ENC_FUNC_STATE_SHIFT) | + (state->cdcErrCode); + if (state->haveHecField == true) { + msg->len = HDMI_CDC_GET_MSG_LEN(HDMI_CDC_HEC_REPORT_STATE_MSG_PARAM_MAX_LEN); + msg->data[8] = (state->hecField >> HDMI_ONE_BYTE_SHIFT); + msg->data[9] = (state->hecField & HDMI_ONE_BYTE_MARK); + } +} + +void HdmiCdcEncodingHecSetStateAdjacentMsg(struct HdmiCecMsg *msg, uint16_t initiatorPhyAddr, + uint16_t phyAddr, uint8_t hecSetState, bool response) +{ + msg->len = HDMI_CDC_GET_MSG_LEN(HDMI_CDC_HEC_SET_STATE_ADJACENT_MSG_PARAM_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_CDC_MESSAGE; + msg->data[2] = (initiatorPhyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (initiatorPhyAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = HDMI_CDC_HEC_SET_STATE_ADJACENT; + msg->data[5] = (phyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[6] = (phyAddr & HDMI_ONE_BYTE_MARK); + msg->data[7] = hecSetState; + if (response == true) { + msg->rspMsg = HDMI_CDC_HEC_REPORT_STATE; + } +} + +void HdmiCdcEncodingHecSetStateMsg(struct HdmiCecMsg *msg, uint16_t initiatorPhyAddr, + struct HemiCdcHecStateInfo *info, bool response) +{ + uint32_t i; + + msg->len = HDMI_CDC_GET_MSG_LEN(HDMI_CDC_HEC_SET_STATE_MSG_MIN_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_CDC_MESSAGE; + msg->data[2] = (initiatorPhyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (initiatorPhyAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = HDMI_CDC_HEC_SET_STATE; + msg->data[5] = (info->phyAddr1 >> HDMI_ONE_BYTE_SHIFT); + msg->data[6] = (info->phyAddr1 & HDMI_ONE_BYTE_MARK); + msg->data[7] = (info->phyAddr2 >> HDMI_ONE_BYTE_SHIFT); + msg->data[8] = (info->phyAddr2 & HDMI_ONE_BYTE_MARK); + msg->data[9] = info->hecSetState; + for (i = 0; (i < info->phyAddrLen) && (i < HDMI_CDC_HEC_SET_STATE_MSG_OPTIONAL_PA_MAX_NUM); i++) { + if (info->phyAddr[i] == HDMI_CEC_INVALID_PHY_ADDR) { + break; + } + msg->data[msg->len] = (info->phyAddr[i] >> HDMI_ONE_BYTE_SHIFT); + (msg->len)++; + msg->data[msg->len] = (info->phyAddr[i] & HDMI_ONE_BYTE_MARK); + (msg->len)++; + } + if (response == true) { + msg->rspMsg = HDMI_CDC_HEC_REPORT_STATE; + } +} + +void HdmiCdcEncodingHecRequestDeactivationMsg(struct HdmiCecMsg *msg, uint16_t initiatorPhyAddr, + uint16_t *phyAddr, uint32_t len, bool response) +{ + uint32_t i; + + if (phyAddr == NULL || len != HDMI_CDC_HEC_REQUEST_DEACTIVATION_MSG_PHY_ADDR_NUM) { + return; + } + msg->len = HDMI_CDC_GET_MSG_LEN(0); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_CDC_MESSAGE; + msg->data[2] = (initiatorPhyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (initiatorPhyAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = HDMI_CDC_HEC_REQUEST_DEACTIVATION; + for (i = 0; i < len; i++) { + msg->data[msg->len] = (phyAddr[i] >> HDMI_ONE_BYTE_SHIFT); + (msg->len)++; + msg->data[msg->len] = (phyAddr[i] & HDMI_ONE_BYTE_MARK); + (msg->len)++; + } + if (response == true) { + msg->rspMsg = HDMI_CDC_HEC_REPORT_STATE; + } +} + +void HdmiCdcEncodingHecNotifyAliveMsg(struct HdmiCecMsg *msg, uint16_t initiatorPhyAddr) +{ + msg->len = HDMI_CDC_GET_MSG_LEN(0); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_CDC_MESSAGE; + msg->data[2] = (initiatorPhyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (initiatorPhyAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = HDMI_CDC_HEC_NOTIFY_ALIVE; +} + +void HdmiCdcEncodingHecDiscoverMsg(struct HdmiCecMsg *msg, uint16_t initiatorPhyAddr, bool response) +{ + msg->len = HDMI_CDC_GET_MSG_LEN(0); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_CDC_MESSAGE; + msg->data[2] = (initiatorPhyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (initiatorPhyAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = HDMI_CDC_HEC_DISCOVER; + if (response == true) { + msg->rspMsg = HDMI_CDC_HEC_REPORT_STATE; + } +} + +void HdmiCdcEncodingHpdSetStateMsg(struct HdmiCecMsg *msg, uint16_t initiatorPhyAddr, + uint8_t portNum, uint8_t hpdState, bool response) +{ + msg->len = HDMI_CDC_GET_MSG_LEN(HDMI_CDC_HPD_SET_STATE_MSG_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_CDC_MESSAGE; + msg->data[2] = (initiatorPhyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (initiatorPhyAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = HDMI_CDC_HPD_SET_STATE; + msg->data[5] = (portNum << HDMI_CDC_INPUT_PORT_NUMBER_SHIFT) | hpdState; + if (response == true) { + msg->rspMsg = CEC_MSG_CDC_HPD_REPORT_STATE; + } +} + +void HdmiCdcEncodingHpdReportStateMsg(struct HdmiCecMsg *msg, uint16_t initiatorPhyAddr, + uint8_t hpdState, uint8_t errCode) +{ + msg->len = HDMI_CDC_GET_MSG_LEN(HDMI_CDC_HPD_REPORT_STATE_MSG_LEN); + msg->data[0] |= HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST; + msg->data[1] = HDMI_CEC_OPCODE_CDC_MESSAGE; + msg->data[2] = (initiatorPhyAddr >> HDMI_ONE_BYTE_SHIFT); + msg->data[3] = (initiatorPhyAddr & HDMI_ONE_BYTE_MARK); + msg->data[4] = CEC_MSG_CDC_HPD_REPORT_STATE; + msg->data[5] = (hpdState << HDMI_CDC_INPUT_PORT_NUMBER_SHIFT) | errCode; +} + +static int32_t HdmiCecSendMsg(struct HdmiCntlr *cntlr, struct HdmiCecMsg *msg) +{ + int32_t ret; + + if (cntlr->ops == NULL || cntlr->ops->cecMsgSend == NULL) { + return HDF_ERR_NOT_SUPPORT; + } + + if (msg->response == true) { + msg->timeout = HDMI_CEC_WAIT_RESPONSE_MSG_MAX_TIME; + } + + HdmiCntlrLock(cntlr); + ret = cntlr->ops->cecMsgSend(cntlr, msg); + HdmiCntlrUnlock(cntlr); + return ret; +} + +static bool HdmiCecMsgIgnore(uint8_t opcode, bool unregistered, bool broadcast) +{ + switch (opcode) { + case HDMI_CEC_OPCODE_GET_CEC_VERSION : + case HDMI_CEC_OPCODE_ABORT : + case HDMI_CEC_OPCODE_GIVE_DEVICE_POWER_STATUS : + case HDMI_CEC_OPCODE_GIVE_OSD_NAME : + /* Ignore if initiator is Unregistered, because these messages should reply with a directed message. */ + if (unregistered == true) { + return true; + } + /* fallthrough */ + case HDMI_CEC_OPCODE_GIVE_DEVICE_VENDOR_ID : + case HDMI_CEC_OPCODE_GIVE_FEATURES : + case HDMI_CEC_OPCODE_GIVE_PHYSICAL_ADDRESS : + /* Ignore if addressing is wrong */ + if (broadcast == true) { + return true; + } + break; + case HDMI_CEC_OPCODE_USER_CONTROL_PRESSED : + case HDMI_CEC_OPCODE_USER_CONTROL_RELEASED : + if (unregistered == true || broadcast == true) { + return true; + } + break; + case HDMI_CEC_OPCODE_REPORT_PHYSICAL_ADDRESS : + if (broadcast == false) { + return true; + } + break; + default : + break; + } + return false; +} + +static void HdmiCecHandleReportPhyAddressMsg(struct HdmiCntlr *cntlr, + struct HdmiCecMsg *msg, struct HdmiCecMsg *txMsg) +{ + uint16_t phyAddr = ((msg->data[2] << HDMI_ONE_BYTE_SHIFT) | msg->data[3]); + (void)cntlr; + (void)txMsg; + + HDF_LOGD("reported phy address is %x.%x.%x.%x, logical address is %d", + HDMI_CEC_PHY_ADDR_PHASE(phyAddr), HdmiCecGetMsgInitiator(msg)); +} + +static void HdmiCecHandleUserControlPrtessedMsg(struct HdmiCntlr *cntlr, + struct HdmiCecMsg *msg, struct HdmiCecMsg *txMsg) +{ + /* Not support CEC Remote Control. */ + if (cntlr->cap.baseCap.bits.cecRc == 0) { + return; + } + + /* TODO */ +} + +static void HdmiCecHandleUserControlReleasedMsg(struct HdmiCntlr *cntlr, + struct HdmiCecMsg *msg, struct HdmiCecMsg *txMsg) +{ + /* Not support CEC Remote Control. */ + if (cntlr->cap.baseCap.bits.cecRc == 0) { + return; + } + /* TODO */ +} + +static void HdmiCecHandleGetCecVersionMsg(struct HdmiCntlr *cntlr, + struct HdmiCecMsg *msg, struct HdmiCecMsg *txMsg) +{ + HdmiCecEncodingCecVersionMsg(txMsg, cntlr->cec->info.cecVersion); + HdmiCecSendMsg(cntlr, txMsg); +} + +static void HdmiCecHandleGivePhyAddressMsg(struct HdmiCntlr *cntlr, + struct HdmiCecMsg *msg, struct HdmiCecMsg *txMsg) +{ + /* Ignore for CEC switches using addr 15. */ + if (cntlr->cec->info.primaryDeviceType == HDMI_CEC_DEVICE_TYPE_PURE_CEC_SWITCH && + HdmiCecGetMsgDestination(msg) == HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST) { + return; + } + + HdmiCecEncodingReportPhyAddressMsg(txMsg, cntlr->cec->info.phyAddr, cntlr->cec->info.primaryDeviceType); + HdmiCecSendMsg(cntlr, txMsg); +} + +static void HdmiCecHandleGiveDeviceVendorIdMsg(struct HdmiCntlr *cntlr, + struct HdmiCecMsg *msg, struct HdmiCecMsg *txMsg) +{ + if (cntlr->cec->info.vendorId == HDMI_CEC_VENDOR_ID_UNKNOWN) { + HdmiCecEncodingFeatureAbortMsg(txMsg, msg->data[1], HDMI_CEC_ABORT_UNRECOGNIZED_OPCODE); + HdmiCecSendMsg(cntlr, txMsg); + return; + } + HdmiCecEncodingDeviceVendorIdMsg(txMsg, cntlr->cec->info.vendorId); + HdmiCecSendMsg(cntlr, txMsg); +} + +static void HdmiCecHandleAbortMsg(struct HdmiCntlr *cntlr, + struct HdmiCecMsg *msg, struct HdmiCecMsg *txMsg) +{ + /* Ignore for CEC switches. */ + if (cntlr->cec->info.primaryDeviceType == HDMI_CEC_DEVICE_TYPE_PURE_CEC_SWITCH) { + return; + } + HdmiCecEncodingFeatureAbortMsg(txMsg, msg->data[1], HDMI_CEC_ABORT_REFUSED); + HdmiCecSendMsg(cntlr, txMsg); +} + +static void HdmiCecHandleGiveOsdNameMsg(struct HdmiCntlr *cntlr, + struct HdmiCecMsg *msg, struct HdmiCecMsg *txMsg) +{ + if (cntlr->cec->info.osdName[0] == 0) { + HdmiCecEncodingFeatureAbortMsg(txMsg, msg->data[1], HDMI_CEC_ABORT_UNRECOGNIZED_OPCODE); + HdmiCecSendMsg(cntlr, txMsg); + return; + } + + HdmiCecEncodingSetOsdNameMsg(txMsg, cntlr->cec->info.osdName, cntlr->cec->info.osdNameLen); + HdmiCecSendMsg(cntlr, txMsg); +} + +static void HdmiCecHandleGiveFeaturesMsg(struct HdmiCntlr *cntlr, + struct HdmiCecMsg *msg, struct HdmiCecMsg *txMsg) +{ + if (cntlr->cec->info.cecVersion < HDMI_CEC_VERSION_2_0) { + HdmiCecEncodingFeatureAbortMsg(txMsg, msg->data[1], HDMI_CEC_ABORT_UNRECOGNIZED_OPCODE); + HdmiCecSendMsg(cntlr, txMsg); + return; + } + + HdmiCecEncodingReportFeaturesMsg(txMsg, &(cntlr->cec->info)); + HdmiCecSendMsg(cntlr, txMsg); +} + +static void HdmiCecMsgDefaultHandle(struct HdmiCntlr *cntlr, + struct HdmiCecMsg *msg, struct HdmiCecMsg *txMsg) +{ + bool broadcast = HdmiCecIsBroadcastMsg(msg); + uint8_t opcode = msg->data[1]; + bool isResponse = (cntlr->cec->info.isWaitingResponse == true && cntlr->cec->info.response == opcode); + + if (broadcast == true || isResponse == true) { + return; + } + if (opcode != HDMI_CEC_OPCODE_FEATURE_ABORT) { + return; + } + + HdmiCecEncodingFeatureAbortMsg(txMsg, opcode, HDMI_CEC_ABORT_UNRECOGNIZED_OPCODE); + HdmiCecSendMsg(cntlr, txMsg); +} + +static void HdmiCecMsgHandle(struct HdmiCntlr *cntlr, struct HdmiCecMsg *msg, + struct HdmiCecMsg *txMsg, uint8_t opcode) +{ + uint32_t i, len; + + struct HdmiCecHandleMsgFuncMap funcMap[] = { + { HDMI_CEC_OPCODE_GET_CEC_VERSION, HdmiCecHandleGetCecVersionMsg }, + { HDMI_CEC_OPCODE_REPORT_PHYSICAL_ADDRESS, HdmiCecHandleReportPhyAddressMsg }, + { HDMI_CEC_OPCODE_USER_CONTROL_PRESSED, HdmiCecHandleUserControlPrtessedMsg }, + { HDMI_CEC_OPCODE_USER_CONTROL_RELEASED, HdmiCecHandleUserControlReleasedMsg }, + { HDMI_CEC_OPCODE_GIVE_PHYSICAL_ADDRESS, HdmiCecHandleGivePhyAddressMsg }, + { HDMI_CEC_OPCODE_GIVE_DEVICE_VENDOR_ID, HdmiCecHandleGiveDeviceVendorIdMsg }, + { HDMI_CEC_OPCODE_ABORT, HdmiCecHandleAbortMsg }, + { HDMI_CEC_OPCODE_GIVE_OSD_NAME, HdmiCecHandleGiveOsdNameMsg }, + { HDMI_CEC_OPCODE_GIVE_FEATURES, HdmiCecHandleGiveFeaturesMsg } + }; + + len = sizeof(funcMap) / sizeof(funcMap[0]); + for (i = 0; i < len; i++) { + if (opcode == funcMap[i].opcode) { + funcMap[i].func(cntlr, msg, txMsg); + return; + } + } + HdmiCecMsgDefaultHandle(cntlr, msg, txMsg); +} + +static void HdmiCecUpdateResponseFlag(struct HdmiCec *cec, uint8_t opcode) +{ + /* receive response msg. */ + if (cec->info.isWaitingResponse == true && cec->info.response == opcode) { + cec->info.isWaitingResponse = false; + cec->info.response = 0; + } +} + +static void HdmiCecReceivedMsgHandle(struct HdmiCntlr *cntlr, struct HdmiCecMsg *msg) +{ + uint8_t opcode = msg->data[1]; + bool broadcast = HdmiCecIsBroadcastMsg(msg); + bool unregistered = (HdmiCecGetMsgInitiator(msg) == HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST); + struct HdmiCecMsg txMsg = {0}; + + if (HdmiCecMsgIgnore(opcode, unregistered, broadcast) == true) { + HdmiCecUpdateResponseFlag(cntlr->cec, opcode); + return; + } + + HdmiCecFillMsgHeader(&txMsg, msg); + HdmiCecMsgHandle(cntlr, msg, &txMsg, opcode); + HdmiCecUpdateResponseFlag(cntlr->cec, opcode); +} + +int32_t HdmiCecReceivedMsg(struct HdmiCec *cec, struct HdmiCecMsg *msg) +{ + struct HdmiCntlr *cntlr = NULL; + uint8_t opcode, initiator, destination; + + if (cec == NULL || cec->priv == NULL || msg == NULL) { + HDF_LOGE("cec receive msg, input param invalid."); + return HDF_ERR_INVALID_PARAM; + } + + cntlr = (struct HdmiCntlr *)cec->priv; + if (cntlr->cap.baseCap.bits.cec == 0) { + HDF_LOGD("not support cec."); + return HDF_ERR_NOT_SUPPORT; + } + + if (msg->len < HDMI_CEC_MSG_MIN_LEN) { + HDF_LOGE("cec receive msg, len is error."); + return HDF_ERR_INVALID_PARAM; + } + + initiator = HdmiCecGetMsgInitiator(msg); + destination = HdmiCecGetMsgDestination(msg); + opcode = msg->data[1]; + /* Check if this message is for us. */ + if (initiator != HDMI_CEC_LOG_ADDR_UNREGISTERED_OR_BROADCAST && + HdmiCecLogAddrValid(cntlr->cec, initiator) == true) { + return HDF_ERR_INVALID_PARAM; + } + if (HdmiCecIsBroadcastMsg(msg) == false && + HdmiCecLogAddrValid(cec, destination) == false) { + HDF_LOGD("this cec msg is not for us!"); + return HDF_ERR_INVALID_PARAM; + } + + if (cntlr->cec->info.logAddrMask == 0) { + return HDF_ERR_NOT_SUPPORT; + } + + /* CDC Only devices should ignore non-CDC messages. */ + if (HdmiCecIsCdcOnlyDevice(cec) == true && + opcode != HDMI_CEC_OPCODE_CDC_MESSAGE) { + HDF_LOGD("this cec msg is not cdc msg."); + return HDF_ERR_NOT_SUPPORT; + } + if (HdmiCecCheckMsgLen(cec, msg, opcode) == false) { + return HDF_ERR_INVALID_PARAM; + } + + HdmiCecReceivedMsgHandle(cntlr, msg); + return HDF_SUCCESS; +} diff --git a/support/platform/src/hdmi/hdmi_common.c b/support/platform/src/hdmi/hdmi_common.c new file mode 100644 index 00000000..031d40be --- /dev/null +++ b/support/platform/src/hdmi/hdmi_common.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdf_log.h" +#include "hdmi_common.h" + +#define HDF_LOG_TAG hdmi_common_c + +/* + * vic, pixel clk, vfreq, hactive, vactive, hblank, vblank, hfront, hsync, hback, vfront, vsync, vback, aspect, + * timing, I/P + */ +struct HdmiVideoDefInfo g_ceaVideoDefInfoMap[HDMI_CEA_VIDEO_CODE_MAX] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + HDMI_PICTURE_ASPECT_NO_DATA, HDMI_VIDEO_TIMING_NONE, HDMI_VIDEO_FORMAT_NULL }, + { HDMI_VIC_640X480P60_4_3, 25175, 59940, 640, 480, 160, 45, 16, 96, 48, 10, 2, 33, + HDMI_PICTURE_ASPECT_4_3, HDMI_VIDEO_TIMING_640X480P60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_720X480P60_4_3, 27000, 59940, 720, 480, 138, 45, 16, 62, 60, 9, 6, 30, + HDMI_PICTURE_ASPECT_4_3, HDMI_VIDEO_TIMING_720X480P60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_720X480P60_16_9, 27000, 59940, 720, 480, 138, 45, 16, 62, 60, 9, 6, 30, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_720X480P60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1280X720P60_16_9, 74250, 60000, 1280, 720, 370, 30, 110, 40, 220, 5, 5, 20, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1280X720P60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1920X1080I60_16_9, 74250, 60000, 1920, 1080, 280, 22, 88, 44, 148, 2, 5, 15, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1920X1080I60, HDMI_VIDEO_FORMA_INTERLACE }, + { HDMI_VIC_1440X480I60_4_3, 27000, 59940, 1440, 480, 276, 22, 38, 124, 114, 4, 3, 15, + HDMI_PICTURE_ASPECT_4_3, HDMI_VIDEO_TIMING_1440X480I60, HDMI_VIDEO_FORMA_INTERLACE }, + { HDMI_VIC_1440X480I60_16_9, 27000, 59940, 1440, 480, 276, 22, 38, 124, 114, 4, 3, 15, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1440X480I60, HDMI_VIDEO_FORMA_INTERLACE }, + { HDMI_VIC_1440X240P60_4_3, 27000, 60054, 1440, 240, 276, 22, 38, 124, 114, 4, 3, 15, + HDMI_PICTURE_ASPECT_4_3, HDMI_VIDEO_TIMING_1440X240P60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1440X240P60_16_9, 27000, 60054, 1440, 240, 276, 22, 38, 124, 114, 4, 3, 15, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1440X240P60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_2880X480I60_4_3, 54000, 59940, 2880, 480, 552, 22, 76, 248, 228, 4, 3, 15, + HDMI_PICTURE_ASPECT_4_3, HDMI_VIDEO_TIMING_2880X480I60, HDMI_VIDEO_FORMA_INTERLACE }, + { HDMI_VIC_2880X480I60_16_9, 54000, 59940, 2880, 480, 552, 22, 76, 248, 228, 4, 3, 15, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_2880X480I60, HDMI_VIDEO_FORMA_INTERLACE }, + { HDMI_VIC_2880X240P60_4_3, 54000, 60054, 2880, 240, 552, 22, 76, 248, 228, 4, 3, 15, + HDMI_PICTURE_ASPECT_4_3, HDMI_VIDEO_TIMING_2880X240I60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_2880X240P60_16_9, 54000, 60054, 2880, 240, 552, 23, 76, 248, 228, 4, 3, 15, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_2880X240I60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1440X480P60_4_3, 54000, 59940, 1440, 480, 276, 45, 32, 124, 120, 9, 6, 30, + HDMI_PICTURE_ASPECT_4_3, HDMI_VIDEO_TIMING_1440X480P60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1440X480P60_16_9, 54000, 59940, 1440, 480, 276, 45, 32, 124, 120, 9, 6, 30, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1440X480P60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1920X1080P60_16_9, 148500, 60000, 1920, 1080, 280, 45, 88, 44, 148, 4, 5, 36, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1920X1080P60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_720X576P50_4_3, 27000, 50000, 720, 576, 144, 49, 12, 64, 68, 5, 5, 39, + HDMI_PICTURE_ASPECT_4_3, HDMI_VIDEO_TIMING_720X576P50, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_720X576P50_16_9, 27000, 50000, 720, 576, 144, 49, 12, 64, 68, 5, 5, 39, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_720X576P50, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1280X720P50_16_9, 74250, 50000, 1280, 720, 700, 30, 440, 40, 220, 5, 5, 20, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1280X720P50, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1920X1080I50_16_9, 74250, 50000, 1920, 1080, 720, 24, 528, 44, 148, 2, 5, 15, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1920X1080I50, HDMI_VIDEO_FORMA_INTERLACE }, + { HDMI_VIC_1440X576I50_4_3, 27000, 50000, 1440, 576, 288, 24, 24, 126, 138, 2, 3, 19, + HDMI_PICTURE_ASPECT_4_3, HDMI_VIDEO_TIMING_1440X576I50, HDMI_VIDEO_FORMA_INTERLACE }, + { HDMI_VIC_1440X576I50_16_9, 27000, 50000, 1440, 576, 288, 24, 24, 126, 138, 2, 3, 19, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1440X576I50, HDMI_VIDEO_FORMA_INTERLACE }, + { HDMI_VIC_1440X576P50_4_3, 54000, 50000, 1440, 576, 288, 49, 24, 128, 136, 5, 5, 39, + HDMI_PICTURE_ASPECT_4_3, HDMI_VIDEO_TIMING_1440X576P50, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1440X576P50_16_9, 54000, 50000, 1440, 576, 288, 49, 24, 128, 136, 5, 5, 39, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1440X576P50, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1920X1080P50_16_9, 148500, 50000, 1920, 1080, 720, 45, 528, 44, 148, 4, 5, 36, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1920X1080P50, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1920X1080P24_16_9, 742500, 24000, 1920, 1080, 830, 45, 638, 44, 148, 4, 5, 36, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1920X1080P24, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1920X1080P25_16_9, 742500, 25000, 1920, 1080, 720, 45, 528, 44, 148, 4, 5, 36, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1920X1080P25, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_1920X1080P30_16_9, 742500, 30000, 1920, 1080, 280, 45, 88, 44, 148, 4, 5, 36, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_1920X1080P30, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_3840X2160P24_16_9, 297000, 24000, 3840, 2160, 1660, 90, 1276, 88, 296, 8, 10, 72, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_3840X2160P24, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_3840X2160P25_16_9, 297000, 25000, 3840, 2160, 1440, 90, 1056, 88, 296, 8, 10, 72, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_3840X2160P25, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_3840X2160P30_16_9, 297000, 30000, 3840, 2160, 560, 90, 176, 88, 296, 8, 10, 72, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_3840X2160P30, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_3840X2160P50_16_9, 594000, 50000, 3840, 2160, 1440, 90, 1056, 88, 296, 8, 10, 72, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_3840X2160P50, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_3840X2160P60_16_9, 594000, 60000, 3840, 2160, 560, 90, 176, 88, 296, 8, 10, 72, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_3840X2160P60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_4096X2160P24_256_135, 297000, 24000, 4096, 2160, 1404, 90, 1020, 88, 296, 8, 10, 72, + HDMI_PICTURE_ASPECT_256_135, HDMI_VIDEO_TIMING_4096X2160P24, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_4096X2160P25_256_135, 297000, 25000, 4096, 2160, 1184, 90, 968, 88, 128, 8, 10, 72, + HDMI_PICTURE_ASPECT_256_135, HDMI_VIDEO_TIMING_4096X2160P25, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_4096X2160P30_256_135, 297000, 30000, 4096, 2160, 304, 90, 88, 88, 128, 8, 10, 72, + HDMI_PICTURE_ASPECT_256_135, HDMI_VIDEO_TIMING_4096X2160P30, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_4096X2160P50_256_135, 594000, 50000, 4096, 2160, 1184, 90, 968, 88, 128, 8, 10, 72, + HDMI_PICTURE_ASPECT_256_135, HDMI_VIDEO_TIMING_4096X2160P50, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_4096X2160P60_256_135, 594000, 60000, 4096, 2160, 304, 90, 88, 88, 128, 8, 10, 72, + HDMI_PICTURE_ASPECT_256_135, HDMI_VIDEO_TIMING_4096X2160P60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_3840X2160P120_16_9, 1188000, 120000, 3840, 2160, 560, 90, 176, 88, 296, 8, 10, 72, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_3840X2160P120, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_7680X4320P24_16_9, 1188000, 24000, 7680, 4320, 3320, 180, 2552, 176, 592, 16, 20, 144, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_7680X4320P24, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_7680X4320P25_16_9, 1188000, 25000, 7680, 4320, 3120, 80, 2352, 176, 592, 16, 20, 44, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_7680X4320P25, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_7680X4320P30_16_9, 1188000, 30000, 7680, 4320, 1320, 80, 552, 176, 592, 16, 20, 44, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_7680X4320P30, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_VIC_4096X2160P120_256_135, 1188000, 120000, 4096, 2160, 304, 90, 88, 88, 128, 8, 10, 72, + HDMI_PICTURE_ASPECT_256_135, HDMI_VIDEO_TIMING_4096X2160P120, HDMI_VIDEO_FORMAT_PROGRESSIVE } +}; + +struct HdmiVideoDefInfo g_vesaVideoDefInfoMap[HDMI_VESA_VIDEO_CODE_MAX] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, HDMI_PICTURE_ASPECT_NO_DATA, + HDMI_VIDEO_TIMING_NONE, HDMI_VIDEO_FORMAT_NULL }, + { 0, 40000, 60317, 800, 600, 256, 28, 40, 128, 88, 1, 4, 23, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_800X600_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 33750, 60000, 848, 480, 240, 37, 16, 112, 112, 6, 8, 23, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_848X480_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 65000, 60004, 1024, 768, 320, 38, 24, 136, 160, 3, 6, 29, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1024X768_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 74250, 60000, 1280, 720, 370, 30, 110, 40, 220, 5, 5, 20, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1280X720_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 68250, 59995, 1280, 768, 160, 22, 48, 32, 80, 3, 7, 12, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1280X768_60_RB, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 79500, 59870, 1280, 768, 384, 30, 64, 128, 192, 3, 7, 20, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1280X768_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 71001, 59910, 1280, 800, 160, 23, 48, 32, 80, 3, 6, 14, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1280X800_60_RB, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 83500, 59810, 1280, 800, 400, 31, 72, 128, 200, 3, 6, 22, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1280X800_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 108000, 60000, 1280, 960, 520, 40, 96, 112, 312, 1, 3, 36, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1280X960_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 108000, 60020, 1280, 1024, 408, 42, 48, 112, 248, 1, 3, 38, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1280X1024_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 85500, 60015, 1360, 768, 432, 27, 64, 112, 256, 3, 6, 18, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1360X768_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 85501, 59790, 1366, 768, 426, 30, 70, 143, 213, 3, 3, 24, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1366X768_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 121749, 59978, 1400, 1050, 464, 39, 88, 144, 232, 3, 4, 32, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1400X1050_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 88749, 59901, 1440, 900, 160, 26, 48, 32, 80, 3, 6, 17, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1440X900_60_RB, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 106499, 59887, 1440, 900, 464, 34, 80, 152, 232, 3, 6, 25, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1440X900_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 108000, 60000, 1440, 1050, 144, 49, 12, 64, 68, 3, 6, 25, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1440X1050_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 108000, 60000, 1440, 1050, 144, 49, 12, 64, 68, 3, 6, 25, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1440X1050_60_RB, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 108000, 60000, 1600, 900, 200, 100, 24, 80, 96, 1, 3, 96, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1600X900_60_RB, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 162000, 60000, 1600, 1200, 560, 50, 64, 192, 304, 1, 3, 46, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1600X1200_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 118999, 59883, 1680, 1050, 160, 30, 48, 32, 80, 3, 6, 21, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1680X1050_60_RB, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 146249, 59954, 1680, 1050, 560, 39, 104, 176, 280, 3, 6, 30, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1680X1050_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 204751, 60000, 1792, 1344, 656, 50, 128, 200, 328, 1, 3, 46, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1792X1344_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 218249, 59995, 1856, 1392, 672, 47, 96, 224, 352, 1, 3, 43, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1856X1392_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 148500, 60000, 1920, 1080, 280, 45, 88, 44, 148, 4, 5, 36, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1920X1080_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 154000, 59950, 1920, 1200, 160, 35, 48, 32, 80, 3, 6, 26, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1920X1200_60_RB, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 193251, 59885, 1920, 1200, 672, 45, 136, 200, 336, 3, 6, 36, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1920X1200_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 234000, 60000, 1920, 1440, 680, 60, 128, 208, 344, 1, 3, 56, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_1920X1440_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 162000, 60000, 2048, 1152, 202, 48, 26, 80, 96, 1, 3, 44, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_2048X1152_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 82500, 50000, 2560, 1440, 520, 30, 260, 40, 220, 3, 3, 24, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_2560X1440_60_RB, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { 0, 348502, 59987, 2560, 1600, 944, 58, 192, 280, 472, 3, 6, 49, HDMI_PICTURE_ASPECT_16_9, + HDMI_VIDEO_TIMING_VESA_2560X1600_60, HDMI_VIDEO_FORMAT_PROGRESSIVE }, +}; + +struct HdmiVideo4kInfo g_video4kInfoMap[HDMI_VIDEO_4K_CODES_MAX] = { + { HDMI_4K_VIC_3840X2160_30, HDMI_VIC_3840X2160P30_16_9, 296703, 30, 3840, 2160, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_3840X2160P30, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_4K_VIC_3840X2160_25, HDMI_VIC_3840X2160P25_16_9, 297000, 25, 3840, 2160, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_3840X2160P25, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_4K_VIC_3840X2160_24, HDMI_VIC_3840X2160P24_16_9, 296703, 24, 3840, 2160, + HDMI_PICTURE_ASPECT_16_9, HDMI_VIDEO_TIMING_3840X2160P24, HDMI_VIDEO_FORMAT_PROGRESSIVE }, + { HDMI_4K_VIC_4096X2160_24, HDMI_VIC_4096X2160P24_256_135, 297000, 24, 4096, 2160, + HDMI_PICTURE_ASPECT_256_135, HDMI_VIDEO_TIMING_4096X2160P24, HDMI_VIDEO_FORMAT_PROGRESSIVE } +}; + +enum HdmiVideoBitDepth HdmiCommonDeepClolorConvertToColorDepth(enum HdmiDeepColor deepColor) +{ + enum HdmiVideoBitDepth colorDepth; + + switch (deepColor) { + case HDMI_DEEP_COLOR_24BITS : + colorDepth = HDMI_VIDEO_BIT_DEPTH_8; + break; + case HDMI_DEEP_COLOR_30BITS : + colorDepth = HDMI_VIDEO_BIT_DEPTH_10; + break; + case HDMI_DEEP_COLOR_36BITS : + colorDepth = HDMI_VIDEO_BIT_DEPTH_12; + break; + case HDMI_DEEP_COLOR_48BITS : + colorDepth = HDMI_VIDEO_BIT_DEPTH_16; + break; + default : + HDF_LOGD("deep color %d is not support, use default value.", deepColor); + colorDepth = HDMI_VIDEO_BIT_DEPTH_8; + break; + } + return colorDepth; +} + +enum HdmiDeepColor HdmiCommonColorDepthConvertToDeepClolor(enum HdmiVideoBitDepth colorDepth) +{ + enum HdmiDeepColor deepColor; + + switch (colorDepth) { + case HDMI_VIDEO_BIT_DEPTH_8 : + deepColor = HDMI_DEEP_COLOR_24BITS; + break; + case HDMI_VIDEO_BIT_DEPTH_10 : + deepColor = HDMI_DEEP_COLOR_30BITS; + break; + case HDMI_VIDEO_BIT_DEPTH_12 : + deepColor = HDMI_DEEP_COLOR_36BITS; + break; + case HDMI_VIDEO_BIT_DEPTH_16 : + deepColor = HDMI_DEEP_COLOR_48BITS; + break; + case HDMI_VIDEO_BIT_DEPTH_OFF : + deepColor = HDMI_DEEP_COLOR_OFF; + break; + default : + deepColor = HDMI_DEEP_COLOR_BUTT; + break; + } + return deepColor; +} + +enum HdmiVic HdmiCommonGetVic(enum HdmiVideoTiming timing, + enum HdmiPictureAspectRatio aspect, bool enable3d) +{ + uint32_t i, len; + enum HdmiVic vic = 0; + + len = sizeof(g_ceaVideoDefInfoMap) / sizeof(g_ceaVideoDefInfoMap[0]); + for (i = 0; i < len; i++) { + if (timing == g_ceaVideoDefInfoMap[i].timing && aspect == g_ceaVideoDefInfoMap[i].aspect) { + vic = g_ceaVideoDefInfoMap[i].vic; + break; + } + } + + if (enable3d == true) { + /* see hdmi spec 10.2. */ + if (vic == HDMI_VIC_3840X2160P24_16_9 || vic == HDMI_VIC_3840X2160P25_16_9 || + vic == HDMI_VIC_3840X2160P30_16_9 || vic == HDMI_VIC_4096X2160P24_256_135) { + HDF_LOGI("4k x 2k 2D vic:%d.", vic); + vic = HDMI_VIC_NONE; + } + } + return vic; +} + +static struct HdmiVideoDefInfo *HdmiCommonGetCommFormatInfo(enum HdmiVic vic) +{ + uint32_t i, len; + + len = sizeof(g_ceaVideoDefInfoMap) / sizeof(g_ceaVideoDefInfoMap[0]); + for (i = 0; i < len; i++) { + if (vic == g_ceaVideoDefInfoMap[i].vic) { + return &g_ceaVideoDefInfoMap[i]; + } + } + return NULL; +} + +static struct HdmiVideoDefInfo *HdmiCommonGetVesaFormatInfo(enum HdmiVideoTiming timing) +{ + uint32_t i, len; + + len = sizeof(g_vesaVideoDefInfoMap) / sizeof(g_vesaVideoDefInfoMap[0]); + for (i = 0; i < len; i++) { + if (timing == g_vesaVideoDefInfoMap[i].timing) { + return &g_vesaVideoDefInfoMap[i]; + } + } + return NULL; +} + +struct HdmiVideoDefInfo *HdmiCommonGetVideoDefInfo(enum HdmiVideoTiming timing, + enum HdmiPictureAspectRatio aspect, bool enable3d) +{ + enum HdmiVic vic; + struct HdmiVideoDefInfo *info = NULL; + + if (timing < HDMI_VIDEO_TIMING_VESA_DEFINE) { + vic = HdmiCommonGetVic(timing, aspect, enable3d); + info = HdmiCommonGetCommFormatInfo(vic); + } else if (timing < HDMI_VIDEO_TIMING_USER_DEFINE) { + info = HdmiCommonGetVesaFormatInfo(timing); + } + return info; +} + +enum HdmiVideoTiming HdmiCommonGetVideoTiming(enum HdmiVic vic, enum HdmiPictureAspectRatio aspect) +{ + uint32_t i, len; + enum HdmiVideoTiming timing = HDMI_VIDEO_TIMING_NONE; + + len = sizeof(g_ceaVideoDefInfoMap) / sizeof(g_ceaVideoDefInfoMap[0]); + for (i = 0; i < len; i++) { + if (vic == g_ceaVideoDefInfoMap[i].vic && aspect == g_ceaVideoDefInfoMap[i].aspect) { + timing = g_ceaVideoDefInfoMap[i].timing; + break; + } + } + return timing; +} + +struct HdmiVideo4kInfo *HdmiCommonGetVideo4kInfo(uint32_t _4kVic) +{ + uint32_t i, len; + + len = sizeof(g_video4kInfoMap) / sizeof(g_video4kInfoMap[0]); + for (i = 0; i < len; i++) { + if (_4kVic == g_video4kInfoMap[i]._4kVic) { + return &g_video4kInfoMap[i]; + } + } + HDF_LOGD("4k not support vic = %u", _4kVic); + return NULL; +} + +enum HdmiVideoTiming HdmiCommonGetVideo4kTiming(uint32_t _4kVic) +{ + uint32_t i, len; + enum HdmiVideoTiming timing = HDMI_VIDEO_TIMING_NONE; + + len = sizeof(g_video4kInfoMap) / sizeof(g_video4kInfoMap[0]); + for (i = 0; i < len; i++) { + if (_4kVic == g_video4kInfoMap[i]._4kVic) { + timing = g_video4kInfoMap[i].timing; + break; + } + } + return timing; +} diff --git a/support/platform/src/hdmi/hdmi_core.c b/support/platform/src/hdmi/hdmi_core.c new file mode 100644 index 00000000..7f3396a8 --- /dev/null +++ b/support/platform/src/hdmi/hdmi_core.c @@ -0,0 +1,1415 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "device_resource_if.h" +#include "hdf_log.h" +#include "hdmi_core.h" +#include "hdmi_dispatch.h" +#include "osal_mem.h" +#include "osal_time.h" +#include "securec.h" + +#define HDF_LOG_TAG hdmi_core_c + +int32_t HdmiCntlrAllocDev(struct HdmiCntlr *cntlr) +{ + struct HdmiDevice *dev = (struct HdmiDevice *)OsalMemCalloc(sizeof(struct HdmiDevice)); + + if (dev == NULL) { + HDF_LOGE("Hdmi alloc dev fail"); + return HDF_ERR_MALLOC_FAIL; + } + + dev->cntlr = cntlr; + cntlr->hdmi = dev; + return HDF_SUCCESS; +} + +void HdmiCntlrFreeDev(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL || cntlr->hdmi == NULL) { + return; + } + + OsalMemFree(cntlr->hdmi); + cntlr->hdmi = NULL; +} + +static void HdmiCecInit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + if (cntlr->cap.baseCap.bits.cec == 0) { + HDF_LOGD("not support cec"); + return; + } + + if (cntlr->cec == NULL) { + cntlr->cec = (struct HdmiCec *)OsalMemCalloc(sizeof(struct HdmiCec)); + if (cntlr->scdc == NULL) { + HDF_LOGE("cec malloc fail"); + return; + } + } + HDF_LOGE("HdmiCecInit, success."); + cntlr->cec->priv = (void *)cntlr; +} + +static void HdmiCecDeinit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + if (cntlr->cec != NULL) { + OsalMemFree(cntlr->cec); + cntlr->cec = NULL; + } +} + +static void HdmiDdcInit(struct HdmiCntlr *cntlr) +{ + int32_t ret; + + if (cntlr == NULL) { + HDF_LOGE("ddc init: param is invalid"); + return; + } + cntlr->ddc.priv = (void *)cntlr; + if (cntlr->ddc.init == true) { + return; + } + ret = OsalMutexInit(&(cntlr->ddc.ddcMutex)); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiDdcInit: mutex init fail!"); + return; + } + HDF_LOGE("HdmiDdcInit, success."); + cntlr->ddc.init = true; +} + +static void HdmiDdcDeinit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + HDF_LOGE("ddc init: param is invalid"); + return; + } + + (void)OsalMutexDestroy(&(cntlr->ddc.ddcMutex)); + if (memset_s(&(cntlr->ddc), sizeof(struct HdmiDdc), 0, sizeof(struct HdmiDdc)) != EOK) { + HDF_LOGE("deinit ddc, memset_s fail."); + } + cntlr->ddc.priv = NULL; + cntlr->ddc.init = false; +} + +static void HdmiFrlInit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + if (cntlr->cap.baseCap.bits.frl == 0) { + HDF_LOGD("not support frl"); + return; + } + + if (cntlr->frl == NULL) { + cntlr->frl = (struct HdmiFrl *)OsalMemCalloc(sizeof(struct HdmiFrl)); + if (cntlr->frl == NULL) { + HDF_LOGE("frl malloc fail"); + return; + } + } + HDF_LOGE("HdmiFrlInit, success."); + cntlr->frl->priv = (void *)cntlr; +} + +static void HdmiFrlDeinit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + if (cntlr->frl != NULL) { + OsalMemFree(cntlr->frl); + cntlr->frl = NULL; + } +} + +static void HdmiHdcpInit(struct HdmiCntlr *cntlr) +{ + int32_t ret; + + if (cntlr == NULL) { + return; + } + if (cntlr->cap.baseCap.bits.hdcp == 0) { + HDF_LOGD("not support hdcp"); + return; + } + + if (cntlr->hdcp == NULL) { + cntlr->hdcp = (struct HdmiHdcp *)OsalMemCalloc(sizeof(struct HdmiHdcp)); + if (cntlr->hdcp == NULL) { + HDF_LOGE("hdcp malloc fail"); + return; + } + ret = OsalMutexInit(&(cntlr->hdcp->hdcpMutex)); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiHdcpInit: mutex init fail!"); + return; + } + } + HDF_LOGE("HdmiHdcpInit, success."); + cntlr->hdcp->priv = (void *)cntlr; +} + +static void HdmiHdcpDeinit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + if (cntlr->hdcp != NULL) { + HdmiHdcpClose(cntlr->hdcp); + OsalMemFree(cntlr->hdcp); + cntlr->hdcp = NULL; + } +} + +static void HdmiHdrInit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + if (cntlr->cap.baseCap.bits.hdr == 0) { + HDF_LOGD("not support hdr"); + return; + } + + if (cntlr->hdr == NULL) { + cntlr->hdr = (struct HdmiHdr *)OsalMemCalloc(sizeof(struct HdmiHdr)); + if (cntlr->hdr == NULL) { + HDF_LOGE("hdr malloc fail"); + return; + } + } + HDF_LOGE("HdmiHdrInit, success."); + cntlr->hdr->priv = (void *)cntlr; +} + +static void HdmiHdrDeinit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + if (cntlr->hdr != NULL) { + OsalMemFree(cntlr->hdr); + cntlr->hdr = NULL; + } +} + +static void HdmiInfoframeInit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + HDF_LOGE("HdmiInfoframeInit, success."); + cntlr->infoframe.priv = (void *)cntlr; +} + +static void HdmiInfoframeDeInit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + + if (memset_s(&(cntlr->infoframe), sizeof(struct HdmiInfoframe), 0, sizeof(struct HdmiInfoframe)) != EOK) { + HDF_LOGE("deinit infoframe, memset_s fail."); + } + cntlr->infoframe.priv = NULL; +} + +static void HdmiScdcInit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + if (cntlr->cap.baseCap.bits.scdc == 0) { + HDF_LOGD("not support scdc"); + return; + } + + if (cntlr->scdc == NULL) { + cntlr->scdc = (struct HdmiScdc *)OsalMemCalloc(sizeof(struct HdmiScdc)); + if (cntlr->scdc == NULL) { + HDF_LOGE("scdc malloc fail"); + return; + } + } + HDF_LOGE("HdmiScdcInit, success."); + cntlr->scdc->priv = (void *)cntlr; +} + +static void HdmiScdcDeinit(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL) { + return; + } + if (cntlr->scdc != NULL) { + OsalMemFree(cntlr->scdc); + cntlr->scdc = NULL; + } +} + +static int32_t HdmiCntlrInit(struct HdmiCntlr *cntlr) +{ + int32_t ret; + + if (cntlr == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + + if (cntlr->hdfDevObj == NULL) { + HDF_LOGE("HdmiCntlrInit: no HdfDeviceObject attached!"); + return HDF_ERR_INVALID_OBJECT; + } + + ret = OsalMutexInit(&cntlr->mutex); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrInit: mutex init fail!"); + return ret; + } + + cntlr->msgQueue = PlatformQueueCreate(HdmiEventMsgHandleDefault, "PlatformHdmiWorkerThread", cntlr); + if (cntlr->msgQueue == NULL) { + HDF_LOGE("HdmiCntlrInit: failed to create msg queue!"); + return HDF_PLT_ERR_OS_API; + } + ret = PlatformQueueStart(cntlr->msgQueue); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrInit: failed to start msg queue!"); + PlatformQueueDestroy(cntlr->msgQueue); + return ret; + } + + cntlr->service.Dispatch = HdmiIoDispatch; + cntlr->hdfDevObj->service = &(cntlr->service); + cntlr->device.magic = cntlr->deviceIndex; + cntlr->device.hdfDev = cntlr->hdfDevObj; + HdmiInfoframeInit(cntlr); + HdmiDdcInit(cntlr); + return HDF_SUCCESS; +} + +static void HdmiCntlrUninit(struct HdmiCntlr *cntlr) +{ + if (cntlr != NULL) { + HdmiInfoframeDeInit(cntlr); + HdmiScdcDeinit(cntlr); + HdmiDdcDeinit(cntlr); + HdmiCecDeinit(cntlr); + HdmiFrlDeinit(cntlr); + HdmiHdcpDeinit(cntlr); + HdmiCntlrFreeDev(cntlr); + (void)OsalMutexDestroy(&cntlr->mutex); + } +} + +int32_t HdmiCntlrAdd(struct HdmiCntlr *cntlr) +{ + int32_t ret; + + if (cntlr == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + + ret = HdmiCntlrInit(cntlr); + if (ret != HDF_SUCCESS) { + return ret; + } + + cntlr->device.manager = PlatformManagerGet(PLATFORM_MODULE_HDMI); + ret = PlatformDeviceAdd(&cntlr->device); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrAdd: device add fail!"); + HdmiCntlrUninit(cntlr); + return ret; + } + return HDF_SUCCESS; +} + +void HdmiCntlrRemove(struct HdmiCntlr *cntlr) +{ + if (cntlr != NULL) { + HdmiCntlrUninit(cntlr); + PlatformDeviceDel(&cntlr->device); + } +} + +static int32_t HdmiCntlrParseVideoCaps(struct HdmiCntlr *cntlr, struct DeviceResourceIface *drsOps, + const struct DeviceResourceNode *node) +{ + int32_t ret; + + ret = drsOps->GetUint32(node, "maxTmdsClock", &(cntlr->cap.maxTmdsClock), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseVideoCaps: read maxTmdsClock fail!"); + return ret; + } + + ret = drsOps->GetUint32(node, "defTmdsClock", &(cntlr->cap.defTmdsClock), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseVideoCaps: read defTmdsClock fail!"); + return ret; + } + + ret = drsOps->GetUint32(node, "maxFrlRate", &(cntlr->cap.maxFrlRate), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseVideoCaps: read maxFrlRate fail!"); + return ret; + } + + ret = drsOps->GetUint32(node, "videoTiming", &(cntlr->cap.videoTiming), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseVideoCaps: read videoTiming fail!"); + return ret; + } + + ret = drsOps->GetUint32(node, "quantization", &(cntlr->cap.quantization), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseVideoCaps: read quantization fail!"); + return ret; + } + + ret = drsOps->GetUint32(node, "colorSpace", &(cntlr->cap.colorSpace), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseVideoCaps: read colorSpace fail!"); + return ret; + } + + ret = drsOps->GetUint32(node, "colorimetry", &(cntlr->cap.colorimetry), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseVideoCaps: read colorimetry fail!"); + return ret; + } + return HDF_SUCCESS; +} + +static int32_t HdmiCntlrParseAudioCaps(struct HdmiCntlr *cntlr, struct DeviceResourceIface *drsOps, + const struct DeviceResourceNode *node) +{ + int32_t ret; + + ret = drsOps->GetUint32(node, "audioIfType", &(cntlr->cap.audioIfType), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseAudioCaps: read audioIfType fail!"); + return ret; + } + HDF_LOGD("HdmiCntlrParseAudioCaps: audioIfType = %d", cntlr->cap.audioIfType); + + ret = drsOps->GetUint32(node, "audioBitDepth", &(cntlr->cap.audioBitDepth), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseAudioCaps: read audioBitDepth fail!"); + return ret; + } + HDF_LOGD("HdmiCntlrParseAudioCaps: audioBitDepth = %d", cntlr->cap.audioBitDepth); + + ret = drsOps->GetUint32(node, "audioSampleRate", &(cntlr->cap.audioSampleRate), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseAudioCaps: read audioSampleRate fail!"); + return ret; + } + HDF_LOGD("HdmiCntlrParseAudioCaps: audioSampleRate = %d", cntlr->cap.audioSampleRate); + + ret = drsOps->GetUint32(node, "audioChannels", &(cntlr->cap.audioChannels), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseAudioCaps: read audioChannels fail!"); + return ret; + } + HDF_LOGD("HdmiCntlrParseAudioCaps: audioChannels = %d", cntlr->cap.audioChannels); + return HDF_SUCCESS; +} + +static int32_t HdmiCntlrParseHdrCaps(struct HdmiCntlr *cntlr, struct DeviceResourceIface *drsOps, + const struct DeviceResourceNode *node) +{ + int32_t ret; + + ret = drsOps->GetUint32(node, "hdrColorimetry", &(cntlr->cap.hdrColorimetry), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseAudioCaps: read hdrColorimetry fail!"); + return ret; + } + HDF_LOGD("HdmiCntlrParseAudioCaps: hdrColorimetry = %d", cntlr->cap.hdrColorimetry); + + ret = drsOps->GetUint32(node, "hdrUserMode", &(cntlr->cap.hdrUserMode), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParseAudioCaps: read hdrUserMode fail!"); + return ret; + } + HDF_LOGD("HdmiCntlrParseAudioCaps: hdrUserMode = %d", cntlr->cap.hdrUserMode); + return HDF_SUCCESS; +} + +int32_t HdmiCntlrParse(struct HdmiCntlr *cntlr, struct HdfDeviceObject *obj) +{ + const struct DeviceResourceNode *node = NULL; + struct DeviceResourceIface *drsOps = NULL; + int32_t ret; + + if (obj == NULL || cntlr == NULL) { + HDF_LOGE("HdmiCntlrParse: input param is NULL."); + return HDF_FAILURE; + } + + node = obj->property; + if (node == NULL) { + HDF_LOGE("HdmiCntlrParse: drs node is NULL."); + return HDF_FAILURE; + } + drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); + if (drsOps == NULL || drsOps->GetUint32 == NULL) { + HDF_LOGE("HdmiCntlrParse: invalid drs ops fail!"); + return HDF_FAILURE; + } + + ret = drsOps->GetUint32(node, "index", &(cntlr->deviceIndex), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParse: read hostId fail!"); + return ret; + } + + ret = drsOps->GetUint32(node, "cap", &(cntlr->cap.baseCap.data), 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParse: read baseCap fail!"); + return ret; + } + + ret = HdmiCntlrParseVideoCaps(cntlr, drsOps, node); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParse: read video caps fail!"); + return ret; + } + + ret = HdmiCntlrParseAudioCaps(cntlr, drsOps, node); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParse: read audio caps fail!"); + return ret; + } + + ret = HdmiCntlrParseHdrCaps(cntlr, drsOps, node); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiCntlrParse: read hdr caps fail!"); + return ret; + } + return HDF_SUCCESS; +} + +static struct HdmiSinkDeviceCapability *HdmiGetSinkCapability(struct HdmiDevice *hdmi) +{ + if (hdmi == NULL) { + return NULL; + } + + if (hdmi->edid.edidPhase == false) { + return NULL; + } + return &(hdmi->edid.sinkCap); +} + +int32_t HdmiCntlrGetSinkEdid(struct HdmiCntlr *cntlr, uint8_t *buffer, uint32_t len) +{ + int32_t ret; + + if (cntlr == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + if (HdmiHpdStatusDelayGet(cntlr) == false) { + HDF_LOGE("no hdmi sink device"); + HdmiCntlrFreeDev(cntlr); + return HDF_DEV_ERR_NO_DEVICE; + } + if (cntlr->hdmi != NULL) { + return HdmiEdidGetRaw(&(cntlr->hdmi->edid), buffer, len); + } + + ret = HdmiCntlrAllocDev(cntlr); + if (ret != HDF_SUCCESS) { + return ret; + } + + ret = HdmiEdidRawDataRead(&(cntlr->hdmi->edid), &(cntlr->ddc)); + if (ret != HDF_SUCCESS) { + HdmiCntlrFreeDev(cntlr); + return ret; + } + + if (cntlr->hdmi->edid.edidPhase != true) { + (void)HdmiEdidPhase(&(cntlr->hdmi->edid)); + cntlr->hdmi->edid.edidPhase = true; + } + return HdmiEdidGetRaw(&(cntlr->hdmi->edid), buffer, len); +} + +static void HdmiCntlrModeSelect(struct HdmiCntlr *cntlr) +{ + enum HdmiTmdsModeType tmdsMode; + struct HdmiCommonAttr *commAttr = &(cntlr->attr.commAttr); + struct HdmiScdcScrambleCap scramble = {0}; + struct HdmiScdcScrambleCap curScramble = {0}; + int32_t ret; + + /* support FRL. */ + if (HdmiFrlSupport(cntlr->frl) == true && + cntlr->cap.baseCap.bits.frl > 0) { + return; + } + + if (cntlr->cap.baseCap.bits.scdc > 0) { + ret = HdmiScdcFillScrambleCap(cntlr->scdc, &scramble, &tmdsMode); + if (ret != HDF_SUCCESS) { + return; + } + } else { + tmdsMode = (commAttr->enableHdmi == true) ? HDMI_TMDS_MODE_HDMI_1_4 : HDMI_TMDS_MODE_DVI; + } + + cntlr->tmdsMode = tmdsMode; + HdmiCntlrTmdsModeSet(cntlr, tmdsMode); + HdmiCntlrReset(cntlr); + + if (cntlr->cap.baseCap.bits.scdc > 0 && + HdmiEdidScdcSupport(cntlr->hdmi) == true) { + ret = HdmiScdcScrambleGet(cntlr->scdc, &curScramble); + if (ret != HDF_SUCCESS) { + return; + } + if (scramble.sinkScramble != curScramble.sinkScramble || + scramble.sourceScramble != curScramble.sourceScramble || + scramble.tmdsBitClockRatio40 != curScramble.tmdsBitClockRatio40) { + (void)HdmiScdcScrambleSet(cntlr->scdc, &scramble); + } + } +} + +static void HdmiCommonAttrInit(struct HdmiCntlr *cntlr) +{ + struct HdmiCommonAttr *commAttr = &(cntlr->attr.commAttr); + + commAttr->enableHdmi = true; + commAttr->enableVideo = true; + commAttr->enableAudio = true; + commAttr->audio = true; + commAttr->avi = true; + commAttr->hdcpMode = HDMI_HDCP_MODE_1_4; + commAttr->colorSpace = (enum HdmiColorSpace)cntlr->cap.colorSpace; + commAttr->quantization = (enum HdmiQuantizationRange)cntlr->cap.quantization; +} + +static void HdmiVideoAttrInit(struct HdmiCntlr *cntlr) +{ + struct HdmiVideoAttr *videoAttr = &(cntlr->attr.videoAttr); + bool colorimetry601; + + videoAttr->colorSpace = (enum HdmiColorSpace)cntlr->cap.colorSpace; + videoAttr->colorimetry = (enum HdmiColorimetry)cntlr->cap.colorimetry; + videoAttr->timing = (enum HdmiVideoTiming)cntlr->cap.videoTiming; + colorimetry601 = ((videoAttr->timing == HDMI_VIDEO_TIMING_720X480P60) || + (videoAttr->timing == HDMI_VIDEO_TIMING_720X576P50) || + (videoAttr->timing == HDMI_VIDEO_TIMING_1440X240P60) || + (videoAttr->timing == HDMI_VIDEO_TIMING_1440X480I60) || + (videoAttr->timing == HDMI_VIDEO_TIMING_1440X576I50) || + (videoAttr->timing == HDMI_VIDEO_TIMING_1440X576P50) || + (videoAttr->timing == HDMI_VIDEO_TIMING_1440X576I60)); + + if (videoAttr->timing == HDMI_VIDEO_TIMING_640X480P60) { + videoAttr->colorimetry = HDMI_COLORIMETRY_ITU709; + videoAttr->aspect = HDMI_PICTURE_ASPECT_4_3; + } else if (colorimetry601 == true) { + videoAttr->colorimetry = HDMI_COLORIMETRY_ITU601; + videoAttr->aspect = HDMI_PICTURE_ASPECT_4_3; + } else if (videoAttr->timing <= HDMI_VIDEO_TIMING_4096X2160P120 && + videoAttr->timing >= HDMI_VIDEO_TIMING_4096X2160P24) { + videoAttr->colorimetry = HDMI_COLORIMETRY_ITU709; + videoAttr->aspect = HDMI_PICTURE_ASPECT_256_135; + } else { + videoAttr->colorimetry = HDMI_COLORIMETRY_ITU709; + videoAttr->aspect = HDMI_PICTURE_ASPECT_16_9; + } + + videoAttr->pixelRepeat = 1; + if (videoAttr->timing == HDMI_VIDEO_TIMING_1440X480I60 || + videoAttr->timing == HDMI_VIDEO_TIMING_1440X576I50) { + videoAttr->pixelRepeat = 2; + } + + if (videoAttr->timing <= HDMI_VIDEO_TIMING_640X480P60) { + videoAttr->quantization = HDMI_QUANTIZATION_RANGE_DEFAULT; + } else { + videoAttr->yccQuantization = HDMI_YCC_QUANTIZATION_RANGE_LIMITED; + } + + if (videoAttr->timing != HDMI_VIDEO_TIMING_NONE && + videoAttr->timing != HDMI_VIDEO_TIMING_640X480P60) { + videoAttr->colorSpace = HDMI_COLOR_SPACE_YCBCR444; + } else { + videoAttr->colorSpace = HDMI_COLOR_SPACE_RGB; + } + + videoAttr->_3dStruct = HDMI_VS_VIDEO_3D_BUTT; + videoAttr->activeAspect = HDMI_ACTIVE_FORMAT_ASPECT_PICTURE; +} + +static void HdmiAudioAttrInit(struct HdmiCntlr *cntlr) +{ + struct HdmiAudioAttr *audioAttr = &(cntlr->attr.audioAttr); + + audioAttr->ifType = (enum HdmiAudioInterfaceType)cntlr->cap.audioIfType; + audioAttr->bitDepth = (enum HdmiAudioBitDepth)cntlr->cap.audioBitDepth; + audioAttr->sampleRate = (enum HdmiSampleRate)cntlr->cap.audioSampleRate; + audioAttr->channels = (enum HdmiAudioFormatChannel)cntlr->cap.audioChannels; +} + +static void HdmiHdrAttrInit(struct HdmiCntlr *cntlr) +{ + struct HdmiHdrAttr *hdrAttr = &(cntlr->attr.hdrAttr); + + hdrAttr->userMode = (enum HdmiHdrUserMode)cntlr->cap.hdrUserMode; + hdrAttr->colorimetry = (enum HdmiHdrColormetry)cntlr->cap.hdrColorimetry; +} + +static void HdmiAttrInit(struct HdmiCntlr *cntlr) +{ + HdmiCommonAttrInit(cntlr); + HdmiVideoAttrInit(cntlr); + HdmiAudioAttrInit(cntlr); + HdmiHdrAttrInit(cntlr); +} + +int32_t HdmiCntlrOpen(struct HdmiCntlr *cntlr) +{ + int32_t ret; + + if (cntlr == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + HdmiInfoframeInit(cntlr); + HdmiDdcInit(cntlr); + HdmiScdcInit(cntlr); + HdmiFrlInit(cntlr); + HdmiHdcpInit(cntlr); + HdmiCecInit(cntlr); + HdmiHdrInit(cntlr); + HdmiAttrInit(cntlr); + HdmiCntlrHardWareInit(cntlr); + /* HDCP on. */ + if ((cntlr->cap.baseCap.data & HDMI_CAP_HDCP_MARK) > 0) { + ret = HdmiHdcpOpen(cntlr->hdcp); + if (ret != HDF_SUCCESS) { + HdmiHdcpClose(cntlr->hdcp); + } + } + cntlr->state |= HDMI_CNTLR_STATE_OPEN; + return HDF_SUCCESS; +} + +int32_t HdmiCntlrStart(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL || cntlr->ops == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + + HdmiCntlrLowPowerSet(cntlr, false); + /* select mode */ + HdmiCntlrModeSelect(cntlr); + HdmiCntlrAvmuteSet(cntlr, false); + + if (cntlr->cap.baseCap.bits.hdr > 0 && + cntlr->cap.baseCap.bits.frl > 0) { + HdmiFrlEnable(cntlr->frl, true); + } else { + /* TMDS Transfer. */ + if (cntlr->ops->phyOutputEnable != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->phyOutputEnable(cntlr, true); + HdmiCntlrUnlock(cntlr); + } + } + + HdmiCntlrAudioPathEnable(cntlr, true); + HdmiCntlrBlackDataSet(cntlr, false); + + cntlr->state |= HDMI_CNTLR_STATE_START; + return HDF_SUCCESS; +} + +int32_t HdmiCntlrStop(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL || cntlr->ops == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + + HdmiCntlrLock(cntlr); + if (cntlr->ops->audioPathEnable != NULL) { + cntlr->ops->audioPathEnable(cntlr, false); + } + if (cntlr->ops->avmuteSet != NULL) { + cntlr->ops->avmuteSet(cntlr, true); + } + if (cntlr->ops->blackDataSet != NULL) { + cntlr->ops->blackDataSet(cntlr, true); + } + HdmiFrlEnable(cntlr->frl, false); + if (cntlr->ops->phyOutputEnable != NULL) { + cntlr->ops->phyOutputEnable(cntlr, false); + } + HdmiCntlrUnlock(cntlr); + + HdmiCntlrLowPowerSet(cntlr, true); + cntlr->state = HDMI_CNTLR_STATE_STOP; + return HDF_SUCCESS; +} + +static void HdmiTmdsClockUpdate(struct HdmiVideoAttr *videoAttr, struct HdmiCommonAttr *commAttr) +{ + /* + * Video at the default 24-bit color depth is carried at a TMDS clock rate equal to the pixel clock rate. + * YCBCB 4:2:0 video is carried at a TMDS clock rate equal to the 1/2 pixel clock rate. + */ + if (commAttr->colorSpace == HDMI_COLOR_SPACE_YCBCR420) { + videoAttr->tmdsClock = HDMI_MULTIPLE_0P5(videoAttr->pixelClock); + return; + } + + /* + * The TMDS clock rate is ibcreased by the ratio of the pixel size to 24-bits: + * 24-bit mode: TMDS clock is 1.0 X pixel clock; + * 30-bit mode: TMDS clock is 1.25 X pixel clock; + * 36-bit mode: TMDS clock is 1.5 X pixel clock; + * 48-bit mode: TMDS clock is 2.0 X pixel clock; + */ + videoAttr->tmdsClock = videoAttr->pixelClock; + if (commAttr->colorSpace != HDMI_COLOR_SPACE_YCBCR422) { + if (commAttr->deepColor == HDMI_DEEP_COLOR_30BITS) { + videoAttr->tmdsClock = HDMI_MULTIPLE_1P25(videoAttr->pixelClock); + } else if (commAttr->deepColor == HDMI_DEEP_COLOR_36BITS) { + videoAttr->tmdsClock = HDMI_MULTIPLE_1P5(videoAttr->pixelClock); + } else if (commAttr->deepColor == HDMI_DEEP_COLOR_48BITS) { + videoAttr->tmdsClock = HDMI_MULTIPLE_2P0(videoAttr->pixelClock); + } + } else { + if ((commAttr->deepColor != HDMI_DEEP_COLOR_OFF) && + (commAttr->deepColor != HDMI_DEEP_COLOR_24BITS)) { + HDF_LOGD("Y422 foce deepcolor 8bit"); + commAttr->deepColor = HDMI_DEEP_COLOR_24BITS; + } + if (videoAttr->timing == HDMI_VIDEO_TIMING_1440X480I60 || + videoAttr->timing == HDMI_VIDEO_TIMING_1440X576I50) { + HDF_LOGD("Y422 is not support at pal and ntsc, force adapt to rgb!"); + commAttr->colorSpace = HDMI_COLOR_SPACE_RGB; + } + } +} + +static bool HdmiYcbcr420FormatCheck(struct HdmiSinkDeviceCapability *sinkCap, struct HdmiVideoAttr *videoAttr) +{ + uint32_t i; + enum HdmiVic vic; + + vic = HdmiCommonGetVic(videoAttr->timing, videoAttr->aspect, false); + if (vic == HDMI_VIC_NONE) { + HDF_LOGD("Y420 not have supported vic."); + return false; + } + + for (i = 0; i < sinkCap->y420Cap.SupportY420VicNum; i++) { + if (vic == sinkCap->y420Cap.SupportY420Format[i]) { + HDF_LOGD("Y420 supported vic is %d.", vic); + return true; + } + } + + for (i = 0; i < sinkCap->y420Cap.onlySupportY420VicNum; i++) { + if (vic == sinkCap->y420Cap.onlySupportY420Format[i]) { + HDF_LOGD("Y420 supported vic is %d.", vic); + return true; + } + } + + HDF_LOGD("Y420 have no supported vic."); + return false; +} + +static int32_t HdmiColorSpaceCheck(struct HdmiCntlr *cntlr, struct HdmiSinkDeviceCapability *sinkCap, + uint32_t maxTmdsClk) +{ + struct HdmiVideoAttr *videoAttr = &(cntlr->attr.videoAttr); + struct HdmiCommonAttr *commAttr = &(cntlr->attr.commAttr); + union HdmiCap *cap = &(cntlr->cap.baseCap); + bool supportColorSpace = false; + + if (videoAttr->pixelClock > maxTmdsClk && + commAttr->colorSpace != HDMI_COLOR_SPACE_YCBCR420) { + return HDF_ERR_INVALID_PARAM; + } + + switch (commAttr->colorSpace) { + case HDMI_COLOR_SPACE_RGB : + supportColorSpace = true; + if ((sinkCap->colorSpace.rgb444 && cap->bits.rgb444) == false) { + HDF_LOGD("sink or source not support RGB!"); + } + break; + case HDMI_COLOR_SPACE_YCBCR422: + supportColorSpace = sinkCap->colorSpace.ycbcr422 && cap->bits.ycbcr422; + break; + case HDMI_COLOR_SPACE_YCBCR444: + supportColorSpace = sinkCap->colorSpace.ycbcr444 && cap->bits.ycbcr444; + break; + case HDMI_COLOR_SPACE_YCBCR420: + supportColorSpace = cap->bits.ycbcr420 && HdmiYcbcr420FormatCheck(sinkCap, videoAttr); + break; + default: + HDF_LOGE("unknow color_space = %u!\n", commAttr->colorSpace); + break; + } + + if (supportColorSpace != true) { + return HDF_ERR_INVALID_PARAM; + } + return HDF_SUCCESS; +} + +static void hdmiDeepColor10bitsCheck(struct HdmiSinkDeviceCapability *sinkCap, struct HdmiCommonAttr *commAttr, + union HdmiCap *cap, uint32_t *tmdsClock, bool *supportDeepColor) +{ + uint32_t tmpTmdsClk = *tmdsClock; + + switch (commAttr->colorSpace) { + case HDMI_COLOR_SPACE_RGB: + tmpTmdsClk = HDMI_MULTIPLE_1P25(tmpTmdsClk); + *supportDeepColor = (sinkCap->vsdbInfo.deepColor.dc30bit && cap->bits.deepColor10bits) ? true : false; + break; + case HDMI_COLOR_SPACE_YCBCR444: + tmpTmdsClk = HDMI_MULTIPLE_1P25(tmpTmdsClk); + *supportDeepColor = (sinkCap->vsdbInfo.deepColor.dc30bit && cap->bits.deepColor10bits && + sinkCap->vsdbInfo.deepColor.dcY444) ? true : false; + break; + case HDMI_COLOR_SPACE_YCBCR420: + tmpTmdsClk = HDMI_MULTIPLE_1P25(tmpTmdsClk); + *supportDeepColor = (sinkCap->hfVsdbInfo.dc.dc30bit && cap->bits.deepColor10bits) ? true : false; + break; + default: + /* Y422, ignore deepclr */ + *supportDeepColor = true; + break; + } + *tmdsClock = tmpTmdsClk; +} + +static void hdmiDeepColor12bitsCheck(struct HdmiSinkDeviceCapability *sinkCap, struct HdmiCommonAttr *commAttr, + union HdmiCap *cap, uint32_t *tmdsClock, bool *supportDeepColor) +{ + uint32_t tmpTmdsClk = *tmdsClock; + + switch (commAttr->colorSpace) { + case HDMI_COLOR_SPACE_RGB: + tmpTmdsClk = HDMI_MULTIPLE_1P5(tmpTmdsClk); + *supportDeepColor = (sinkCap->vsdbInfo.deepColor.dc36bit && cap->bits.deepColor12bits) ? true : false; + break; + case HDMI_COLOR_SPACE_YCBCR444: + tmpTmdsClk = HDMI_MULTIPLE_1P5(tmpTmdsClk); + *supportDeepColor = (sinkCap->vsdbInfo.deepColor.dc36bit && cap->bits.deepColor12bits && + sinkCap->vsdbInfo.deepColor.dcY444) ? true : false; + break; + case HDMI_COLOR_SPACE_YCBCR420: + tmpTmdsClk = HDMI_MULTIPLE_1P5(tmpTmdsClk); + *supportDeepColor = (sinkCap->hfVsdbInfo.dc.dc36bit && cap->bits.deepColor12bits) ? true : false; + break; + default: + /* Y422, ignore deepclr */ + *supportDeepColor = true; + break; + } + *tmdsClock = tmpTmdsClk; +} + +static int32_t hdmiDeepColorCheck(struct HdmiCntlr *cntlr, struct HdmiSinkDeviceCapability *sinkCap, + uint32_t maxTmdsClk) +{ + struct HdmiVideoAttr *videoAttr = &(cntlr->attr.videoAttr); + struct HdmiCommonAttr *commAttr = &(cntlr->attr.commAttr); + union HdmiCap *cap = &(cntlr->cap.baseCap); + uint32_t tmdsClock = videoAttr->pixelClock; + bool supportDeepColor = false; + + if (commAttr->colorSpace == HDMI_COLOR_SPACE_YCBCR420) { + tmdsClock = HDMI_MULTIPLE_0P5(tmdsClock); + } + + switch (commAttr->deepColor) { + case HDMI_DEEP_COLOR_30BITS: + hdmiDeepColor10bitsCheck(sinkCap, commAttr, cap, &tmdsClock, &supportDeepColor); + break; + case HDMI_DEEP_COLOR_36BITS: + hdmiDeepColor12bitsCheck(sinkCap, commAttr, cap, &tmdsClock, &supportDeepColor); + break; + default: + commAttr->deepColor = HDMI_DEEP_COLOR_24BITS; + supportDeepColor = true; + break; + } + + if (supportDeepColor == false || tmdsClock > maxTmdsClk) { + return HDF_ERR_INVALID_PARAM; + } + videoAttr->tmdsClock = tmdsClock; + /* Y422 default 12bit output, deep_color force adapt to 8bit(24bit). */ + if (commAttr->colorSpace == HDMI_COLOR_SPACE_YCBCR422) { + if (videoAttr->timing == HDMI_VIDEO_TIMING_1440X480I60 || + videoAttr->timing == HDMI_VIDEO_TIMING_1440X576I50) { + HDF_LOGD("force change colorspace to RGB!"); + commAttr->colorSpace = HDMI_COLOR_SPACE_RGB; + } + if ((videoAttr->deepColor != HDMI_DEEP_COLOR_24BITS) && + (videoAttr->deepColor != HDMI_DEEP_COLOR_OFF)) { + videoAttr->deepColor = HDMI_DEEP_COLOR_OFF; + HDF_LOGD("when Y422, deep_color not support 10/12bit!"); + } + } + return HDF_SUCCESS; +} + +static int32_t HdmiColorBitSelect(struct HdmiCntlr *cntlr) +{ + struct HdmiSinkDeviceCapability *sinkCap = NULL; + uint32_t maxTmdsClk = 0; + + /* DVI mode, must set RGB and DEEP_COLOR_OFF */ + if (cntlr->attr.commAttr.enableHdmi == false) { + if (cntlr->attr.commAttr.colorSpace != HDMI_COLOR_SPACE_RGB) { + HDF_LOGE("DVI mode, the color space is not RGB!"); + return HDF_ERR_INVALID_PARAM; + } + cntlr->attr.commAttr.deepColor = HDMI_DEEP_COLOR_OFF; + cntlr->attr.videoAttr.tmdsClock = cntlr->attr.videoAttr.pixelClock; + return HDF_SUCCESS; + } + + /* FRL mode. */ + if (cntlr->cap.baseCap.bits.hdr > 0) { + HdmiTmdsClockUpdate(&(cntlr->attr.videoAttr), &(cntlr->attr.commAttr)); + if (cntlr->attr.videoAttr.tmdsClock > HDMI_HDMI20_MAX_TMDS_RATE) { + HDF_LOGD("HDMI2.1, tmds clock exceed max."); + return HDF_SUCCESS; + } + } + + sinkCap = HdmiGetSinkCapability(cntlr->hdmi); + if (sinkCap == NULL) { + HdmiTmdsClockUpdate(&(cntlr->attr.videoAttr), &(cntlr->attr.commAttr)); + return HDF_SUCCESS; + } + + if (sinkCap->maxTmdsClk == 0) { + /* use default clock. */ + maxTmdsClk = cntlr->cap.defTmdsClock; + } else { + maxTmdsClk = (sinkCap->maxTmdsClk < cntlr->cap.maxTmdsClock) ? + sinkCap->maxTmdsClk : cntlr->cap.maxTmdsClock; + } + /* MHz is converted to KHz */ + maxTmdsClk *= 1000; + + if (HdmiColorSpaceCheck(cntlr, sinkCap, maxTmdsClk) != HDF_SUCCESS) { + return HDF_ERR_INVALID_PARAM; + } + if (hdmiDeepColorCheck(cntlr, sinkCap, maxTmdsClk) != HDF_SUCCESS) { + return HDF_ERR_INVALID_PARAM; + } + return HDF_SUCCESS; +} + +static int32_t HdmiAudioAttrHandle(struct HdmiCntlr *cntlr) +{ + struct HdmiAudioConfigInfo audioCfg = {0}; + struct HdmiCommonAttr *commAttr = &(cntlr->attr.commAttr); + struct HdmiVideoAttr *videoAttr = &(cntlr->attr.videoAttr); + struct HdmiAudioAttr *audioAttr = &(cntlr->attr.audioAttr); + int32_t ret; + + audioCfg.downSample = audioAttr->downSample; + audioCfg.channels = audioAttr->channels; + audioCfg.bitDepth = audioAttr->bitDepth; + audioCfg.sampleRate = audioAttr->sampleRate; + audioCfg.ifType = audioAttr->ifType; + audioCfg.enable = (commAttr->enableAudio) && (commAttr->enableHdmi); + audioCfg.tmdsClock = videoAttr->tmdsClock; + audioCfg.pixelRepeat = videoAttr->pixelRepeat; + + HdmiCntlrAudioPathEnable(cntlr, false); + HdmiCntlrAudioPathSet(cntlr, &audioCfg); + ret = HdmiAudioInfoframeSend(&(cntlr->infoframe), ((commAttr->enableAudio) && (commAttr->audio))); + HdmiCntlrAudioPathEnable(cntlr, true); + return ret; +} + +static void HdmiHdrModeCheck(struct HdmiCommonAttr *commAttr, + struct HdmiVideoAttr *videoAttr, struct HdmiHdrAttr *hdrAttr) +{ + switch (hdrAttr->userMode) { + case HDMI_HDR_USERMODE_DOLBY: + videoAttr->yccQuantization = HDMI_YCC_QUANTIZATION_RANGE_LIMITED; + commAttr->colorSpace = HDMI_COLOR_SPACE_YCBCR444; + videoAttr->tmdsClock = videoAttr->pixelClock; + commAttr->deepColor = HDMI_DEEP_COLOR_24BITS; + videoAttr->quantization = HDMI_QUANTIZATION_RANGE_DEFAULT; + break; + case HDMI_HDR_USERMODE_HDR10: + if (hdrAttr->mode == HDMI_HDR_MODE_CEA_861_3) { + if (hdrAttr->colorimetry > HDMI_HDR_COLORIMETRY_EXTENDED) { + videoAttr->colorimetry = HDMI_COLORIMETRY_EXTENDED; + videoAttr->extColorimetry = (enum HdmiExtendedColorimetry)(hdrAttr->colorimetry - + HDMI_HDR_EXTENDED_COLORIMETRY_XV_YCC_601); + } else { + videoAttr->colorimetry = (enum HdmiColorimetry)(hdrAttr->colorimetry); + videoAttr->extColorimetry = HDMI_EXTENDED_COLORIMETRY_BUTT; + } + commAttr->xvyccMode = false; + } + break; + default: + break; + } +} + +static void HdmiFillVideoAttrFromHardwareStatus(struct HdmiVideoAttr *videoAttr, + struct HdmiHardwareStatus *hwStatus, struct HdmiCommonAttr *commAttr) +{ + bool rgb; + bool aspectIs256; + uint8_t vic; + enum HdmiVsVideoFormat format; + enum Hdmi4kVic vic4k; + + rgb = ((hwStatus->videoStatus.rgb2Ycbcr) || + ((!hwStatus->videoStatus.ycbcr2Rgb) && (hwStatus->videoStatus.outColorSpace == HDMI_COLOR_SPACE_RGB))); + videoAttr->colorSpace = (rgb == true) ? HDMI_COLOR_SPACE_RGB : HDMI_COLOR_SPACE_YCBCR444; + + if (hwStatus->infoframeStatus.aviEnable) { + vic = hwStatus->infoframeStatus.avi[7]; + /* + * when the timing is 4096*2160, the aspect ratio in AVI infoframe is 0 + * (but the real aspect ratio is 256:135<0x04>, the video_code is 0) + */ + aspectIs256 = (((vic == 0) && (hwStatus->infoframeStatus.vsif[8] == 0x04)) || + ((vic >= HDMI_VIC_4096X2160P25_256_135) && (vic <= HDMI_VIC_4096X2160P60_256_135))); + videoAttr->aspect = (aspectIs256 == true) ? HDMI_PICTURE_ASPECT_256_135 : + ((hwStatus->infoframeStatus.avi[5] >> 4) & 0x3); /* 4'b, BIT[2:1] */ + videoAttr->activeAspect = hwStatus->infoframeStatus.avi[5] & 0xf; + videoAttr->colorimetry = (hwStatus->infoframeStatus.avi[5] >> 6) & 0x3; /* 6'b, BIT[2:1] */ + videoAttr->quantization = (hwStatus->infoframeStatus.avi[6] >> 2) & 0x3; /* 2'b, BIT[2:1] */ + videoAttr->extColorimetry = (hwStatus->infoframeStatus.avi[6] >> 4) & 0x07; /* 4'b, BIT[3:1] */ + videoAttr->yccQuantization = (hwStatus->infoframeStatus.avi[8] >> 6) & 0x3; /* 6'b, BIT[2:1] */ + videoAttr->pixelRepeat = (hwStatus->infoframeStatus.avi[8] & 0xf) + 1; + videoAttr->timing = HdmiCommonGetVideoTiming(vic, videoAttr->aspect); + if ((!hwStatus->infoframeStatus.vsifEnable) && (!vic)) { + videoAttr->timing = HDMI_VIDEO_TIMING_NONE; + } + commAttr->quantization = (commAttr->colorSpace == HDMI_COLOR_SPACE_RGB) ? + videoAttr->quantization : (videoAttr->yccQuantization + 1); + } + + videoAttr->_3dStruct = HDMI_VS_VIDEO_3D_BUTT; + if (hwStatus->infoframeStatus.vsifEnable) { + format = (hwStatus->infoframeStatus.vsif[7] >> 5) & 0x3; /* 5'b, BIT[2:1] */ + if (format == HDMI_VS_VIDEO_FORMAT_4K) { + vic4k = hwStatus->infoframeStatus.vsif[8]; + videoAttr->timing = HdmiCommonGetVideo4kTiming(vic4k); + } else if (format == HDMI_VS_VIDEO_FORMAT_3D) { + videoAttr->_3dStruct = (hwStatus->infoframeStatus.vsif[8] >> 4) & 0xf; /* 4'b, BIT[4:1] */ + } + } +} + +static void HdmiFillCommonAttrFromHardwareStatus(struct HdmiCommonAttr *commAttr, + struct HdmiHardwareStatus *hwStatus, struct HdmiAttr *attr) +{ + bool dolby; + + switch (hwStatus->commonStatus.tmdsMode) { + case HDMI_TMDS_MODE_HDMI_1_4 : + case HDMI_TMDS_MODE_HDMI_2_0 : + commAttr->enableHdmi = true; + commAttr->enableVideo = true; + break; + case HDMI_TMDS_MODE_DVI : + commAttr->enableHdmi = false; + commAttr->enableVideo = true; + break; + default: + commAttr->enableHdmi = false; + commAttr->enableVideo = false; + break; + } + + commAttr->enableAudio = (hwStatus->audioStatus.enable && hwStatus->infoframeStatus.audioEnable); + commAttr->avi = hwStatus->infoframeStatus.aviEnable; + commAttr->audio = hwStatus->infoframeStatus.audioEnable; + commAttr->xvyccMode = hwStatus->infoframeStatus.gdbEnable; + commAttr->deepColor = HdmiCommonColorDepthConvertToDeepClolor(hwStatus->videoStatus.outBitDepth); + + /* color space is ycbcr444 when the hdr mode is dolby. */ + dolby = ((attr->hdrAttr.userMode == HDMI_HDR_USERMODE_DOLBY) && + (!hwStatus->videoStatus.rgb2Ycbcr) && + (!hwStatus->videoStatus.ycbcr2Rgb) && + (!hwStatus->videoStatus.ycbcr444422) && + (!hwStatus->videoStatus.ycbcr422420) && + (!hwStatus->videoStatus.ycbcr422444) && + (!hwStatus->videoStatus.ycbcr420422)); + commAttr->colorSpace = (dolby == true) ? HDMI_COLOR_SPACE_YCBCR444 : hwStatus->videoStatus.outColorSpace; +} + +static bool HdmiCommonAttrChanged(struct HdmiCommonAttr *curCommAttr, struct HdmiCommonAttr *commAttr) +{ + bool change; + + change = (commAttr->enableHdmi != curCommAttr->enableHdmi) || + (commAttr->colorSpace != curCommAttr->colorSpace) || + (commAttr->xvyccMode != curCommAttr->xvyccMode) || + (commAttr->avi != curCommAttr->avi) || + (commAttr->quantization != curCommAttr->quantization); + + if (change == true) { + return true; + } + + if (((commAttr->deepColor == HDMI_DEEP_COLOR_OFF) || + (commAttr->deepColor == HDMI_DEEP_COLOR_24BITS)) && + ((curCommAttr->deepColor == HDMI_DEEP_COLOR_OFF) || + (curCommAttr->deepColor == HDMI_DEEP_COLOR_24BITS))) { + HDF_LOGI("deep color not change: %u", curCommAttr->deepColor); + } else if (commAttr->deepColor != curCommAttr->deepColor) { + return true; + } + return false; +} + +static bool HdmiVideoAttrChanged(struct HdmiVideoAttr *curVideoAttr, struct HdmiVideoAttr *videoAttr) +{ + bool change; + + change = (videoAttr->timing != curVideoAttr->timing) || + (videoAttr->colorSpace != curVideoAttr->colorSpace) || + (videoAttr->_3dStruct != curVideoAttr->_3dStruct) || + (videoAttr->pixelRepeat != curVideoAttr->pixelRepeat) || + (videoAttr->colorimetry != curVideoAttr->colorimetry) || + (videoAttr->extColorimetry != curVideoAttr->extColorimetry) || + (videoAttr->quantization != curVideoAttr->quantization) || + (videoAttr->yccQuantization != curVideoAttr->yccQuantization) || + (videoAttr->aspect != curVideoAttr->aspect); + return change; +} + +static int32_t HdmiVedioAttrHandle(struct HdmiCntlr *cntlr, struct HdmiHardwareStatus *hwStatus) +{ + struct HdmiCommonAttr *commAttr = &(cntlr->attr.commAttr); + struct HdmiVideoAttr *videoAttr = &(cntlr->attr.videoAttr); + struct HdmiCommonAttr curCommAttr = {0}; + struct HdmiVideoAttr curVideoAttr = {0}; + int32_t ret; + + /* support HDR. */ + if (cntlr->cap.baseCap.bits.hdr > 0) { + HdmiHdrModeCheck(commAttr, videoAttr, &(cntlr->attr.hdrAttr)); + } + + /* support FRL. */ + if (cntlr->cap.baseCap.bits.frl > 0) { + ret = HdmiFrlModeSelect(cntlr->frl); + if (ret != HDF_SUCCESS) { + return ret; + } + } + + HdmiFillCommonAttrFromHardwareStatus(&curCommAttr, hwStatus, &(cntlr->attr)); + HdmiFillVideoAttrFromHardwareStatus(&curVideoAttr, hwStatus, &curCommAttr); + if (HdmiCommonAttrChanged(&curCommAttr, commAttr) == false && + HdmiVideoAttrChanged(&curVideoAttr, videoAttr) == false && + HdmiFrlModeChanged(cntlr->frl) == false) { + HDF_LOGI("video and common attr is not changed."); + return HDF_SUCCESS; + } + + if (commAttr->enableVideo == true) { + HdmiCntlrVideoPathSet(cntlr, videoAttr); + } + + (void)HdmiAviInfoframeSend(&(cntlr->infoframe), (commAttr->enableHdmi && commAttr->avi)); + (void)HdmiVsInfoframeSend(&(cntlr->infoframe), commAttr->enableHdmi, commAttr->vsifDolby); + /* the drm infoframe is stop because software was reset in videopath, so re-enable it if the mode is HDR10. */ + if (cntlr->cap.baseCap.bits.hdr > 0) { + if (cntlr->attr.hdrAttr.mode == HDMI_HDR_MODE_CEA_861_3) { + (void)HdmiDrmInfoframeSend(&(cntlr->infoframe), false); + (void)HdmiDrmInfoframeSend(&(cntlr->infoframe), true); + } + } + return HDF_SUCCESS; +} + +static void HdmiAttrUpdate(struct HdmiCntlr *cntlr) +{ + struct HdmiHardwareStatus hwStatus = {0}; + + if (HdmiColorBitSelect(cntlr) != HDF_SUCCESS) { + HDF_LOGD("attr update: color bit select fail."); + return; + } + + if (cntlr->ops->hardWareStatusGet == NULL) { + return; + } + + HdmiCntlrLock(cntlr); + cntlr->ops->hardWareStatusGet(cntlr, &hwStatus); + HdmiCntlrUnlock(cntlr); + + if (HdmiAudioAttrHandle(cntlr) != HDF_SUCCESS) { + HDF_LOGD("audio attr check fail"); + return; + } + if (HdmiVedioAttrHandle(cntlr, &hwStatus) != HDF_SUCCESS) { + HDF_LOGD("vedio attr check fail"); + } +} + +int32_t HdmiCntlrDeepColorSet(struct HdmiCntlr *cntlr, enum HdmiDeepColor color) +{ + if (cntlr == NULL || cntlr->ops == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + + if (cntlr->attr.commAttr.colorSpace == HDMI_COLOR_SPACE_YCBCR422) { + if (color != HDMI_DEEP_COLOR_24BITS && color != HDMI_DEEP_COLOR_OFF) { + HDF_LOGE("not support deepcolor %u when colorspace is ycbcr422.", color); + return HDF_ERR_INVALID_PARAM; + } + } + + /* if the current hdmi mode is dolby, deep color set is invalid. */ + if (cntlr->attr.hdrAttr.mode == HDMI_HDR_MODE_DOLBY_NORMAL || + cntlr->attr.hdrAttr.mode == HDMI_HDR_MODE_DOLBY_TUNNELING) { + HDF_LOGD("don't change deepcolor when dolby mode is %u.", cntlr->attr.hdrAttr.mode); + return HDF_ERR_NOT_SUPPORT; + } + + cntlr->attr.commAttr.deepColor = color; + HdmiCntlrAvmuteSet(cntlr, true); + HdmiAttrUpdate(cntlr); + HdmiCntlrAvmuteSet(cntlr, false); + return HDF_SUCCESS; +} + +int32_t HdmiCntlrDeepColorGet(struct HdmiCntlr *cntlr, enum HdmiDeepColor *color) +{ + if (cntlr == NULL || cntlr->ops == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + if (color == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + *color = cntlr->attr.commAttr.deepColor; + return HDF_SUCCESS; +} + +int32_t HdmiCntlrSetVideoAttribute(struct HdmiCntlr *cntlr, struct HdmiVideoAttr *attr) +{ + struct HdmiHardwareStatus hwStatus = {0}; + + if (cntlr == NULL || cntlr->ops == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + if (attr == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + cntlr->attr.videoAttr = *attr; + + if (cntlr->ops->hardWareStatusGet == NULL) { + return HDF_ERR_NOT_SUPPORT; + } + + HdmiCntlrLock(cntlr); + cntlr->ops->hardWareStatusGet(cntlr, &hwStatus); + HdmiCntlrUnlock(cntlr); + return HdmiVedioAttrHandle(cntlr, &hwStatus); +} + +int32_t HdmiCntlrSetAudioAttribute(struct HdmiCntlr *cntlr, struct HdmiAudioAttr *attr) +{ + if (cntlr == NULL || cntlr->ops == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + if (attr == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + cntlr->attr.audioAttr = *attr; + return HdmiAudioAttrHandle(cntlr); +} + +int32_t HdmiCntlrSetHdrAttribute(struct HdmiCntlr *cntlr, struct HdmiHdrAttr *attr) +{ + if (cntlr == NULL || cntlr->ops == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + if (attr == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + return HdmiHdrAttrHandle(cntlr->hdr, attr); +} + +int32_t HdmiCntlrInfoframeGet(struct HdmiCntlr *cntlr, enum HdmiPacketType type, union HdmiInfoframeInfo *frame) +{ + if (cntlr == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + return HdmiInfoframeGetInfo(&(cntlr->infoframe), type, frame); +} + +int32_t HdmiCntlrInfoframeSet(struct HdmiCntlr *cntlr, enum HdmiPacketType type, union HdmiInfoframeInfo *frame) +{ + if (cntlr == NULL || cntlr->ops == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + if (frame == NULL) { + return HDF_ERR_INVALID_PARAM; + } + return HdmiInfoframeSetInfo(&(cntlr->infoframe), type, frame); +} + +void HdmiCntlrClose(struct HdmiCntlr *cntlr) +{ + if (cntlr == NULL || cntlr->ops == NULL) { + return; + } + + if ((cntlr->state & HDMI_CNTLR_STATE_START) > 0) { + HdmiCntlrStop(cntlr); + } + + HdmiInfoframeDeInit(cntlr); + HdmiDdcDeinit(cntlr); + HdmiScdcDeinit(cntlr); + HdmiFrlDeinit(cntlr); + HdmiHdcpDeinit(cntlr); + HdmiCecDeinit(cntlr); + HdmiHdrDeinit(cntlr); + cntlr->state = HDMI_CNTLR_STATE_CLOSE; +} diff --git a/support/platform/src/hdmi/hdmi_ddc.c b/support/platform/src/hdmi/hdmi_ddc.c new file mode 100644 index 00000000..8fd4b239 --- /dev/null +++ b/support/platform/src/hdmi/hdmi_ddc.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdmi_core.h" + +#define HDF_LOG_TAG hdmi_ddc_c + +int32_t HdmiCntlrDdcTransfer(struct HdmiCntlr *cntlr, struct HdmiDdcCfg *ddcCfg) +{ + int32_t ret; + + if (cntlr == NULL || cntlr->ops == NULL || cntlr->ops->ddcTransfer == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + if (ddcCfg == NULL) { + return HDF_ERR_INVALID_PARAM; + } + HdmiCntlrLock(cntlr); + ret = cntlr->ops->ddcTransfer(cntlr, ddcCfg); + HdmiCntlrUnlock(cntlr); + return ret; +} + +int32_t HdmiDdcTransfer(struct HdmiDdc *ddc, struct HdmiDdcCfg *cfg) +{ + int32_t ret; + + if (ddc == NULL || cfg == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + if (cfg->mode >= HDMI_DDC_MODE_BUTT) { + return HDF_ERR_INVALID_PARAM; + } + + (void)OsalMutexLock(&(ddc->ddcMutex)); + ret = HdmiCntlrDdcTransfer(ddc->priv, cfg); + (void)OsalMutexUnlock(&(ddc->ddcMutex)); + return ret; +} diff --git a/support/platform/src/hdmi/hdmi_dfm.c b/support/platform/src/hdmi/hdmi_dfm.c new file mode 100644 index 00000000..eddff1b7 --- /dev/null +++ b/support/platform/src/hdmi/hdmi_dfm.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdf_log.h" +#include "hdmi_common.h" +#include "hdmi_dfm.h" + +#define HDF_LOG_TAG hdmi_dfm_c + +#define HDMI_DFM_THOUSAND 1000 +#define HDMI_DFM_INVALID_VAL (-1) + +uint32_t HdmiDfmGetPixelFormat(enum HdmiColorSpace colorSpace) +{ + uint32_t pixelFormat; + + switch (colorSpace) { + case HDMI_COLOR_SPACE_RGB : + pixelFormat = HDMI_DFM_PIXEL_FORMAT_MODE_0; + break; + case HDMI_COLOR_SPACE_YCBCR420 : + pixelFormat = HDMI_DFM_PIXEL_FORMAT_MODE_1; + break; + case HDMI_COLOR_SPACE_YCBCR422 : + pixelFormat = HDMI_DFM_PIXEL_FORMAT_MODE_2; + break; + case HDMI_COLOR_SPACE_YCBCR444 : + pixelFormat = HDMI_DFM_PIXEL_FORMAT_MODE_3; + break; + default : + pixelFormat = HDMI_DFM_PIXEL_FORMAT_MODE_0; + break; + } + return pixelFormat; +} + +void HdmiDfmFillParam(struct HdmiDfmParam *param, struct HdmiVideoDefInfo *videoInfo, + struct HdmiAudioAttr *audioAttr, enum HdmiColorSpace colorSpace, enum HdmiDeepColor deepColor) +{ + if (param == NULL || videoInfo == NULL || audioAttr == NULL) { + return; + } + param->hactive = videoInfo->hactive; + param->vactive = videoInfo->vactive; + param->hblank = videoInfo->hblank; + param->vblank = videoInfo->vblank; + param->hsync = videoInfo->hsync; + param->hback = videoInfo->hback; + param->hfront = videoInfo->hfront; + param->vsync = videoInfo->vsync; + param->vback = videoInfo->vback; + param->vfront = videoInfo->vfront; + param->vfreq = videoInfo->rate; + param->colorDepth = HdmiCommonDeepClolorConvertToColorDepth(deepColor); + param->pixelFormat = HdmiDfmGetPixelFormat(colorSpace); + param->audioRate = (uint32_t)audioAttr->sampleRate; + param->layout = (audioAttr->channels > HDMI_AUDIO_FORMAT_CHANNEL_2) ? true : false; + /* ACAT packet_type */ + param->acat = HDMI_AUDIO_CHANNEL_ALLOC_TYPE3; + param->packetType = HDMI_AUDIO_SAMPLE_PACKET; +} + +static void HdmiDfmBaseInfoInit(struct HdmiDfmInfo *info, struct HdmiDfmParam *param) +{ + info->htotal = param->hactive + param->hblank; + info->vtotal = param->vactive + param->vblank; + info->pixelClk = (uint64_t)(info->htotal) * info->vtotal * param->vfreq / HDMI_DFM_THOUSAND; + + /* 1. Determine the maximum legal pixel rate. */ + info->maxPixelClk = info->pixelClk * (HDMI_DFM_THOUSAND + HDMI_DFM_FRL_PIXELCLK_TOLERANCE) / HDMI_DFM_THOUSAND; + info->minPixelClk = info->pixelClk * (HDMI_DFM_THOUSAND - HDMI_DFM_FRL_PIXELCLK_TOLERANCE) / HDMI_DFM_THOUSAND; + if (info->maxPixelClk == 0 || info->minPixelClk == 0) { + HDF_LOGE("max or min pixel clock is 0!"); + return; + } + + /* 2. Determine the minimum Video Line period. */ + info->lineMinTime = (uint64_t)info->htotal * 1000000000000 / info->maxPixelClk; + info->lineMaxTime = (uint64_t)info->htotal * 1000000000000 / info->minPixelClk; + + /* 3. Determine the Worst Case Slow Bit Rate. x10000 */ + info->minBitRate = (uint64_t)param->bitRate * 1000000000 * (10000 - HDMI_DFM_FRL_BITRATE_TOLERANCE) / 10000; + info->maxBitRate = (uint64_t)param->bitRate * 1000000000 * (10000 + HDMI_DFM_FRL_BITRATE_TOLERANCE) / 10000; + + /* 4. Determine the FRL Character Rate */ + info->minFrlCharRate = info->minBitRate / 18; + info->maxFrlCharRate = info->maxBitRate / 18; + + /* 5. Determine the Total FRL Characters per line Period. */ + info->minFrlCharsPerLine = (uint32_t)(info->lineMinTime * info->minFrlCharRate * param->laneNum / 1000000000000); + info->maxFrlCharsPerLine = (uint32_t)(info->lineMaxTime * info->maxFrlCharRate * param->laneNum / 1000000000000); + + info->cFrlSb = HDMI_DFM_FRL_SB_LEN(param->laneNum); + info->overheadSb = param->laneNum * 100000 / info->cFrlSb; + info->overheadRs = HDMI_DFM_RS_NUM_PER_CB * HDMI_DFM_FRL_CB_NUM_PER_SB * 100000 / info->cFrlSb; + info->overheadMap = 25 * 10000 / info->cFrlSb; /* FRL map chars per blk. */ + info->overheadMin = info->overheadSb + info->overheadRs + info->overheadMap; + info->overheadMax = info->overheadMin + HDMI_DFM_OVERHEAD_SIZE; +} + +static uint32_t HdmiDfmGetAudioPackets(struct HdmiDfmParam *param) +{ + uint32_t ap = 0; + + switch (param->packetType) { + case HDMI_AUDIO_SAMPLE_PACKET : + case HDMI_ONE_BIT_AUDIO_SAMPLE_PACKET : + ap = HDMI_AUDIO_AP_SIZE_100; + if (param->layout == false) { + ap = HDMI_AUDIO_AP_SIZE_25; + } + break; + case HDMI_DTS_AUDIO_PACKET : + case HDMI_HBR_AUDIO_PACKET : + case HDMI_MULTI_STREAM_AUDIO_SAMPLE_PACKET : + case HDMI_ONE_BIT_MULTI_STREAM_AUDIO_SAMPLE_PACKET : + ap = HDMI_AUDIO_AP_SIZE_100; + break; + case HDMI_AUDIO_3D_SAMPLE_PACKET : + case HDMI_ONE_BIT_AUDIO_3D_SAMPLE_PACKET : + if (param->acat == HDMI_AUDIO_CHANNEL_ALLOC_TYPE1) { + ap = HDMI_AUDIO_AP_SIZE_200; + } else if (param->acat == HDMI_AUDIO_CHANNEL_ALLOC_TYPE2) { + ap = HDMI_AUDIO_AP_SIZE_300; + } else if (param->acat == HDMI_AUDIO_CHANNEL_ALLOC_TYPE3) { + ap = HDMI_AUDIO_AP_SIZE_400; + } + break; + default : + HDF_LOGE("audio packet type 0x%x, is not support.", param->packetType); + break; + } + + return ap; +} + +static void HdmiDfmCaculateAudioInfo(struct HdmiDfmInfo *info, struct HdmiDfmParam *param) +{ + /* 1. Determine the number of audio packets required to carry each sample. */ + info->audioAp = HdmiDfmGetAudioPackets(param); + + /* 2. Determine Average Audio Related Packet Rate. */ + info->audioRap = (uint32_t)((uint64_t)param->audioRate * (1000 + HDMI_DFM_FRL_AUDIOCLK_TOLERANCE) * + info->audioAp / 100000); + + /* 3. Determine Average Required Packets per line. */ + info->avgAudioPacketsPerLine = (uint32_t)((uint64_t)info->audioRap * info->lineMinTime / 1000000000); + + /* 4. Determine the Packets per Hblank that must be supportable. */ + info->audioPacketsLine = (info->avgAudioPacketsPerLine + HDMI_DFM_THOUSAND - 1) / HDMI_DFM_THOUSAND; + + /* + * 5. Determine The c_frl_blank_min(64(guard bands, two 12-character control periods, c_frl_active_extra) + * and 32 audio_packets). + */ + info->hblankAudioMin = 64 + 32 * info->audioPacketsLine; +} + +static void HdmiDfmCaculateVideoBorrowInfo(struct HdmiDfmInfo *info) +{ + if (info->activeTimeRef >= info->activeTimeMin && info->blankTimeRef >= info->blankTimeMin) { + info->tBorrow = 0; + } else if (info->activeTimeRef < info->activeTimeMin && info->blankTimeRef >= info->blankTimeMin) { + info->tBorrow = info->activeTimeMin - info->activeTimeRef; + } else { + info->tBorrow = HDMI_DFM_INVALID_VAL; + } + if (info->tBorrow == HDMI_DFM_INVALID_VAL) { + info->tbBorrow = HDMI_DFM_INVALID_VAL; + } else { + info->tbBorrow = ((int32_t)(info->tBorrow * info->avgTbRate / 100000000000) + 10 - 1) / 10; + } +} + +static void HdmiDfmCaculateVideoInfo(struct HdmiDfmInfo *info, struct HdmiDfmParam *param) +{ + uint32_t kcd, k420; + + /* + * 1. if 4:2:2 pixels, kcd is 1. Otherwise, kcd is CD / 8. + * if 4:2:0 pixels, k420 is 2. Otherwise, k420 is 1. + */ + kcd = (param->pixelFormat == 2) ? HDMI_DFM_MAGNIFICATION_8 : param->colorDepth; + k420 = (param->pixelFormat == 1) ? 2 : 1; + + /* 2. Determine Bits per Pixel */ + info->bpp = ((24 * kcd) / k420) / HDMI_DFM_MAGNIFICATION_8; + + /* 3. Determine Video Bytes per line. */ + info->activeBytesPerLine = info->bpp * param->hactive / HDMI_DFM_MAGNIFICATION_8; + + /* + * 4. Determine Required Characters to carry Active Video per line. + * 3 is means active_bytes_per_line need 3 characters. + */ + info->activeTbPerLine = (info->activeBytesPerLine + 3 - 1) / 3; + + /* 5. Determine Required Characters to carry H-Blank Video per line. */ + info->hblankTbPerLine = (param->hblank * kcd / k420 + HDMI_DFM_MAGNIFICATION_8 - 1) / HDMI_DFM_MAGNIFICATION_8; + + /* 6. 32 is FRL characters each packet, 7 is guard bands island(4 FRL char) + video(3 FRL char) */ + if (((param->hblank * kcd) / k420) / HDMI_DFM_MAGNIFICATION_8 > 32 * (1 + info->audioPacketsLine) + 7) { + info->cFrlFree = ((param->hblank * kcd) / k420) / HDMI_DFM_MAGNIFICATION_8 - + 32 * (1 + info->audioPacketsLine) - 7; + } + + /* 7. add 1 character each for RC break caused by 4 */ + info->cFrlRcMargin = 4; + /* 8. RC compression transmit control characters reduce 7/8th total characters. */ + if (7 * info->cFrlFree / HDMI_DFM_MAGNIFICATION_8 > info->cFrlRcMargin) { + info->cFrlRcSavings = 7 * info->cFrlFree / HDMI_DFM_MAGNIFICATION_8 - info->cFrlRcMargin; + } + + if (info->htotal == 0) { + HDF_LOGE("htotal is 0!"); + return; + } + info->avgTbRate = info->maxPixelClk * (info->activeTbPerLine + info->hblankTbPerLine) / info->htotal; + info->activeTimeRef = (uint64_t)info->lineMinTime * param->hactive / info->htotal; + info->blankTimeRef = (uint64_t)info->lineMinTime * param->hblank / info->htotal; + + /* 9. (3 / 2) is active_tb coefficient in protocol */ + info->activeTimeMin = (uint64_t)info->activeTbPerLine * 3 * 100000000000000 / + (2 * param->laneNum * info->minFrlCharRate * (HDMI_DFM_RATE_MAGNIFICATION - info->overheadMax) / + HDMI_DFM_THOUSAND); + info->blankTimeMin = (uint64_t)info->hblankTbPerLine * 100000000000000 / + (param->laneNum * info->minFrlCharRate * (HDMI_DFM_RATE_MAGNIFICATION - info->overheadMax) / + HDMI_DFM_THOUSAND); + + /* 10. Determine Borrow Info */ + HdmiDfmCaculateVideoBorrowInfo(info); + + /* 11. (3 / 2) is active_tb coefficient in protocol */ + info->cFrlActualPayload = + (3 * info->activeTbPerLine + 2 - 1) / 2 + info->hblankTbPerLine - info->cFrlRcSavings; + + if (info->minFrlCharsPerLine == 0) { + HDF_LOGE("min FRL Characters per line is 0!"); + return; + } + info->utilization = (uint64_t)info->cFrlActualPayload * 100000 / (uint64_t)info->minFrlCharsPerLine; + info->margin = 100000 - (info->utilization + info->overheadMax); +} + +static void HdmiDfmFillInfo(struct HdmiDfmInfo *info, struct HdmiDfmParam *param) +{ + HdmiDfmBaseInfoInit(info, param); + HdmiDfmCaculateAudioInfo(info, param); + HdmiDfmCaculateVideoInfo(info, param); + + /* Check Audio Cap. */ + info->audioSupport = (info->hblankTbPerLine >= info->hblankAudioMin) ? true : false; + /* Check Video Cap. */ + if (info->tbBorrow == HDMI_DFM_INVALID_VAL) { + info->videoSupport = false; + } else { + info->videoSupport = (info->tbBorrow <= HDMI_DFM_FRL_MAX_TB_BORROW) ? true : false; + } + + info->uncompressSupport = (info->margin >= 0) ? true : false; + info->canbeTrans = (info->audioSupport && info->videoSupport && info->uncompressSupport) ? true : false; + info->isExtraMode = (info->canbeTrans && (info->tbBorrow > 0)) ? true : false; +} + +bool HdmiDfmFormatSupport(struct HdmiDfmParam *param) +{ + struct HdmiDfmInfo info = {0}; + + HdmiDfmFillInfo(&info, param); + if (info.audioSupport == true && info.videoSupport == true && info.uncompressSupport == true) { + return true; + } + return false; +} diff --git a/support/platform/src/hdmi/hdmi_dispatch.c b/support/platform/src/hdmi/hdmi_dispatch.c new file mode 100644 index 00000000..c1a3f130 --- /dev/null +++ b/support/platform/src/hdmi/hdmi_dispatch.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdf_log.h" +#include "hdmi_dispatch.h" +#include "hdmi_core.h" +#include "hdmi_if.h" + +#define HDF_LOG_TAG hdmi_dispatch_c + +enum HdmiIoCmd { + HDMI_CMD_OPEN, + HDMI_CMD_CLOSE, + HDMI_CMD_START, + HDMI_CMD_STOP, + HDMI_CMD_AVMUTE_SET, + HDMI_CMD_DEEP_COLOR_SET, + HDMI_CMD_DEEP_COLOR_GET, + HDMI_CMD_VIDEO_ATTR_SET, + HDMI_CMD_AUDIO_ATTR_SET, + HDMI_CMD_HDR_ATTR_SET, + HDMI_CMD_READ_SINK_EDID, + HDMI_CMD_INFOFRAME_SET, + HDMI_CMD_INFOFRAME_GET, + HDMI_CMD_BUTT, +}; + +struct HdmiDispatchFunc { + int32_t cmd; + int32_t (*func)(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply); +}; + +static int32_t HdmiCmdOpen(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + (void)data; + (void)reply; + + return HdmiCntlrOpen(cntlr); +} + +static int32_t HdmiCmdClose(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + (void)data; + (void)reply; + + HdmiCntlrClose(cntlr); + return HDF_SUCCESS; +} + +static int32_t HdmiCmdStart(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + (void)data; + (void)reply; + + return HdmiCntlrStart(cntlr); +} + +static int32_t HdmiCmdStop(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + (void)data; + (void)reply; + + return HdmiCntlrStop(cntlr); +} + +static int32_t HdmiCmdAvmuteSet(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + bool *enable = NULL; + size_t size; + (void)reply; + + if (!HdfSbufReadBuffer(data, (const void **)&enable, &size)) { + HDF_LOGE("HdmiCmdAvmuteSet: sbuf read buffer failed"); + return HDF_ERR_IO; + } + HdmiCntlrAvmuteSet(cntlr, *enable); + return HDF_SUCCESS; +} + +static int32_t HdmiCmdDeepColorSet(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + enum HdmiDeepColor *color = NULL; + size_t size; + (void)reply; + + if (!HdfSbufReadBuffer(data, (const void **)&color, &size)) { + HDF_LOGE("HdmiCmdDeepColorSet: sbuf read buffer failed"); + return HDF_ERR_IO; + } + return HdmiCntlrDeepColorSet(cntlr, *color); +} + +static int32_t HdmiCmdDeepColorGet(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + int32_t ret; + enum HdmiDeepColor color; + (void)data; + + if (reply == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + ret = HdmiCntlrDeepColorGet(cntlr, &color); + if (ret != HDF_SUCCESS) { + return ret; + } + + if (HdfSbufWriteBuffer(reply, &color, sizeof(color)) == false) { + HDF_LOGE("HdmiCmdDeepColorGet: write back color fail!"); + return HDF_ERR_IO; + } + return HDF_SUCCESS; +} + +static int32_t HdmiCmdVideoAttrSet(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + struct HdmiVideoAttr *attr = NULL; + size_t size; + (void)reply; + + if (!HdfSbufReadBuffer(data, (const void **)&attr, &size)) { + HDF_LOGE("HdmiCmdVideoAttrSet: sbuf read buffer failed"); + return HDF_ERR_IO; + } + return HdmiCntlrSetVideoAttribute(cntlr, attr); +} + +static int32_t HdmiCmdAudioAttrSet(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + struct HdmiAudioAttr *attr = NULL; + size_t size; + (void)reply; + + if (!HdfSbufReadBuffer(data, (const void **)&attr, &size)) { + HDF_LOGE("HdmiCmdAudioAttrSet: sbuf read buffer failed"); + return HDF_ERR_IO; + } + return HdmiCntlrSetAudioAttribute(cntlr, attr); +} + +static int32_t HdmiCmdHdrAttrSet(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + struct HdmiHdrAttr *attr = NULL; + size_t size; + (void)reply; + + if (!HdfSbufReadBuffer(data, (const void **)&attr, &size)) { + HDF_LOGE("HdmiCmdHdrAttrSet: sbuf read buffer failed"); + return HDF_ERR_IO; + } + return HdmiCntlrSetHdrAttribute(cntlr, attr); +} + +static int32_t HdmiCmdReadSinkEdid(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + int32_t ret; + uint8_t edid[HDMI_EDID_TOTAL_SIZE] = {0}; + (void)data; + + if (reply == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + ret = HdmiCntlrGetSinkEdid(cntlr, edid, HDMI_EDID_TOTAL_SIZE); + if (ret != HDF_SUCCESS) { + return ret; + } + + if (HdfSbufWriteBuffer(reply, edid, HDMI_EDID_TOTAL_SIZE) == false) { + HDF_LOGE("HdmiCmdReadSinkEdid: write back edid fail!"); + return HDF_ERR_IO; + } + + return HDF_SUCCESS; +} + +static int32_t HdmiCmdInfoframeSet(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + enum HdmiPacketType type; + union HdmiInfoframeInfo *frame = NULL; + size_t size; + + if (!HdfSbufReadUint16(data, (uint16_t *)&type)) { + HDF_LOGE("HdmiCmdInfoframeSet: sbuf read uint16 failed"); + return HDF_ERR_IO; + } + + if (!HdfSbufReadBuffer(data, (const void **)&frame, &size)) { + HDF_LOGE("HdmiCmdInfoframeSet: sbuf read buffer failed"); + return HDF_ERR_IO; + } + return HdmiCntlrInfoframeSet(cntlr, type, frame); +} + +static int32_t HdmiCmdInfoframeGet(struct HdmiCntlr *cntlr, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + size_t size; + int32_t ret; + enum HdmiPacketType *type = NULL; + union HdmiInfoframeInfo frame = {0}; + + if (!HdfSbufReadBuffer(data, (const void **)&type, &size)) { + HDF_LOGE("HdmiCmdInfoframeGet: sbuf read buffer failed"); + return HDF_ERR_IO; + } + + ret = HdmiCntlrInfoframeGet(cntlr, *type, &frame); + if (ret != HDF_SUCCESS) { + return ret; + } + + if (HdfSbufWriteBuffer(reply, &frame, sizeof(frame)) == false) { + HDF_LOGE("HdmiCmdInfoframeGet: write back frame fail!"); + return HDF_ERR_IO; + } + + return HDF_SUCCESS; +} + +int32_t HdmiIoDispatch(struct HdfDeviceIoClient *client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply) +{ + struct HdmiCntlr *cntlr = NULL; + uint32_t i, len; + struct HdmiDispatchFunc dispatchFunc[] = { + { HDMI_CMD_OPEN, HdmiCmdOpen }, + { HDMI_CMD_CLOSE, HdmiCmdClose }, + { HDMI_CMD_START, HdmiCmdStart }, + { HDMI_CMD_STOP, HdmiCmdStop }, + { HDMI_CMD_AVMUTE_SET, HdmiCmdAvmuteSet }, + { HDMI_CMD_DEEP_COLOR_SET, HdmiCmdDeepColorSet }, + { HDMI_CMD_DEEP_COLOR_GET, HdmiCmdDeepColorGet }, + { HDMI_CMD_VIDEO_ATTR_SET, HdmiCmdVideoAttrSet }, + { HDMI_CMD_AUDIO_ATTR_SET, HdmiCmdAudioAttrSet }, + { HDMI_CMD_HDR_ATTR_SET, HdmiCmdHdrAttrSet }, + { HDMI_CMD_READ_SINK_EDID, HdmiCmdReadSinkEdid }, + { HDMI_CMD_INFOFRAME_SET, HdmiCmdInfoframeSet }, + { HDMI_CMD_INFOFRAME_GET, HdmiCmdInfoframeGet }, + }; + + if (client == NULL || client->device == NULL) { + HDF_LOGE("HdmiIoDispatch: client or hdf dev obj is NULL"); + return HDF_ERR_INVALID_OBJECT; + } + + cntlr = (struct HdmiCntlr *)client->device->service; + if (cntlr == NULL) { + HDF_LOGE("HdmiIoDispatch: service is NULL"); + return HDF_ERR_INVALID_OBJECT; + } + + len = sizeof(dispatchFunc) / sizeof(dispatchFunc[0]); + for (i = 0; i < len; i++) { + if (dispatchFunc[i].cmd == cmd) { + return dispatchFunc[i].func(cntlr, data, reply); + } + } + + HDF_LOGE("HdmiIoDispatch: cmd %d is not support", cmd); + return HDF_ERR_NOT_SUPPORT; +} diff --git a/support/platform/src/hdmi/hdmi_edid.c b/support/platform/src/hdmi/hdmi_edid.c new file mode 100644 index 00000000..e619f425 --- /dev/null +++ b/support/platform/src/hdmi/hdmi_edid.c @@ -0,0 +1,1320 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdf_log.h" +#include "hdmi_core.h" +#include "securec.h" + +#define HDF_LOG_TAG hdmi_edid_c + +/* + * Address locations 0x00 and 0x07 contain data values 0x00 and locations 0x01 through 0x06 contain 0xFF as data + * values. CTA-861 requires this data. This header is used to determine the beginning of an EDID structure in a Sink. + */ +uint8_t g_edidHeader[HDMI_EDID_BLOCK_HEADER_FIELD_LEN] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; + +int32_t HdmiEdidReset(struct HdmiEdid *edid) +{ + if (edid == NULL) { + return HDF_ERR_INVALID_PARAM; + } + if (memset_s(edid, sizeof(struct HdmiEdid), 0, sizeof(struct HdmiEdid)) != EOK) { + HDF_LOGE("memset_s fail."); + return HDF_ERR_IO; + } + return HDF_SUCCESS; +} + +int32_t HdmiEdidGetRaw(struct HdmiEdid *edid, uint8_t *raw, uint32_t len) +{ + uint32_t length; + + if (edid == NULL || raw == NULL || len == 0) { + return HDF_ERR_INVALID_PARAM; + } + + length = ((len < edid->rawLen) ? len : edid->rawLen); + if (memcpy_s(raw, len, edid->raw, length) != EOK) { + HDF_LOGE("memcpy_s fail."); + return HDF_ERR_IO; + } + return (int32_t)length; +} + +static int32_t HdmiEdidHeaderPhase(struct HdmiEdid *edid) +{ + struct HdmiEdidFirstBlockInfo *block = (struct HdmiEdidFirstBlockInfo *)edid->raw; + uint32_t i; + + for (i = 0; i < HDMI_EDID_BLOCK_HEADER_FIELD_LEN; i++) { + if (block->header[i] != g_edidHeader[i]) { + HDF_LOGE("header[%d] = 0x%x, is error.", i, block->header[i]); + return HDF_ERR_INVALID_PARAM; + } + } + return HDF_SUCCESS; +} + +static int32_t HdmiEdidBlockCheckSum(uint8_t *data) +{ + uint32_t i; + uint32_t checkSum = 0; + + HDF_LOGI("check sum is 0x%x", data[HDMI_EDID_CHECKSUM_ADDR]); + for (i = 0; i < HDMI_EDID_SINGLE_BLOCK_SIZE; i++) { + checkSum += data[i]; + } + if ((checkSum & HDMI_EDID_CHECK_SUM_MARK) == 0) { + return HDF_SUCCESS; + } + HDF_LOGE("checksum = 0x%x, is invalid.", checkSum); + return HDF_FAILURE; +} + +static int32_t HdmiEdidVendorInfoPhase(struct HdmiEdid *edid) +{ + uint16_t data, i, tmpData; + struct HdmiSinkDeviceCapability *sinkCap = &(edid->sinkCap); + struct HdmiEdidFirstBlockInfo *block = (struct HdmiEdidFirstBlockInfo *)edid->raw; + + /* Manufacturer Name */ + data = (block->vendorName[0] << HDMI_EDID_MANUFACRURER_NAME_SHIFT) | (block->vendorName[1]); + for (i = 0; i < HDMI_EDID_MANUFACRURER_NAME_MAX_LEN - 1; i++) { + tmpData = (data & (HDMI_EDID_MANUFACRURER_NAME_CHAR_MARK << (HDMI_EDID_MANUFACRURER_NAME_CHAR_SHIFT * i))); + tmpData = (tmpData >> (HDMI_EDID_MANUFACRURER_NAME_CHAR_SHIFT * i)); + if (tmpData > HDMI_EDID_MANUFACRURER_NAME_LOW_INVALID && + tmpData < HDMI_EDID_MANUFACRURER_NAME_HIGH_INVALID) { + sinkCap->vendorInfo.mfrName[2 - i] = (char)('A' + tmpData - 1); + } + } + + /* Product Code */ + data = (block->productCode[1] << HDMI_EDID_PRODUCT_CODE_SHIFT) | (block->productCode[0]); + sinkCap->vendorInfo.productCode = data; + + /* Serial Number */ + for (i = 0; i < HDMI_EDID_SERIAL_NUMBER_FIELD_LEN; i++) { + sinkCap->vendorInfo.serialNumber |= (block->serialNumber[i] << (HDMI_EDID_SERIAL_NUMBER_SHIFT * i)); + } + sinkCap->vendorInfo.week = block->week; + sinkCap->vendorInfo.year = block->year + HDMI_EDID_YEAR_BASE; + return HDF_SUCCESS; +} + +static int32_t HdmiEdidVersionInfoPhase(struct HdmiEdid *edid) +{ + struct HdmiSinkDeviceCapability *sinkCap = &(edid->sinkCap); + struct HdmiEdidFirstBlockInfo *block = (struct HdmiEdidFirstBlockInfo *)edid->raw; + + sinkCap->verInfo.version = block->version; + sinkCap->verInfo.revision = block->revision; + if (sinkCap->verInfo.version != HDMI_EDID_VERSION_NUM) { + HDF_LOGW("edid version is %d", sinkCap->verInfo.version); + } + if (sinkCap->verInfo.revision != HDMI_EDID_REVISION_NUM) { + HDF_LOGW("edid revision is %d", sinkCap->verInfo.revision); + } + return HDF_SUCCESS; +} + +static int32_t HdmiEdidBasicDispPhase(struct HdmiEdid *edid) +{ + struct HdmiSinkDeviceCapability *sinkCap = &(edid->sinkCap); + struct HdmiEdidFirstBlockInfo *block = (struct HdmiEdidFirstBlockInfo *)edid->raw; + + sinkCap->disp.width = block->width; + sinkCap->disp.height = block->height; + HDF_LOGI("width = %d, height = %d", block->width, block->height); + return HDF_SUCCESS; +} + +static int32_t HdmiEdidColorFeaturePhase(struct HdmiEdid *edid) +{ + struct HdmiSinkDeviceCapability *sinkCap = &(edid->sinkCap); + struct HdmiEdidFirstBlockInfo *block = (struct HdmiEdidFirstBlockInfo *)edid->raw; + + /* red color phase */ + sinkCap->colorInfo.redX = (block->redX << HDMI_EDID_COLOR_HIGH_OFFSET) | + ((block->redGreenLow >> HDMI_EDID_COLOR_RED_X_LOW_OFFSET) & HDMI_EDID_COLOR_LOW_BITS_MARK); + sinkCap->colorInfo.redY = (block->redY << HDMI_EDID_COLOR_HIGH_OFFSET) | + ((block->redGreenLow >> HDMI_EDID_COLOR_RED_Y_LOW_OFFSET) & HDMI_EDID_COLOR_LOW_BITS_MARK); + /* green color phase */ + sinkCap->colorInfo.greenX = (block->greenX << HDMI_EDID_COLOR_HIGH_OFFSET) | + ((block->redGreenLow >> HDMI_EDID_COLOR_GREEN_X_LOW_OFFSET) & HDMI_EDID_COLOR_LOW_BITS_MARK); + sinkCap->colorInfo.greenY = (block->greenY << HDMI_EDID_COLOR_HIGH_OFFSET) | + (block->redGreenLow & HDMI_EDID_COLOR_LOW_BITS_MARK); + /* blue color phase */ + sinkCap->colorInfo.blueX = (block->blueX << HDMI_EDID_COLOR_HIGH_OFFSET) | + ((block->blueWhiteLow >> HDMI_EDID_COLOR_BLUE_X_LOW_OFFSET) & HDMI_EDID_COLOR_LOW_BITS_MARK); + sinkCap->colorInfo.blueY = (block->blueY << HDMI_EDID_COLOR_HIGH_OFFSET) | + ((block->blueWhiteLow >> HDMI_EDID_COLOR_BLUE_Y_LOW_OFFSET) & HDMI_EDID_COLOR_LOW_BITS_MARK); + /* white color phase */ + sinkCap->colorInfo.whiteX = (block->whiteX << HDMI_EDID_COLOR_HIGH_OFFSET) | + ((block->blueWhiteLow >> HDMI_EDID_COLOR_WHITE_X_LOW_OFFSET) & HDMI_EDID_COLOR_LOW_BITS_MARK); + sinkCap->colorInfo.whiteY = (block->whiteY << HDMI_EDID_COLOR_HIGH_OFFSET) | + (block->blueWhiteLow & HDMI_EDID_COLOR_LOW_BITS_MARK); + return HDF_SUCCESS; +} + +static int32_t HdmiEdidEstablisedTimingPhase(struct HdmiEdid *edid) +{ + uint32_t i; + uint32_t data = 0; + struct HdmiSinkDeviceCapability *sinkCap = &(edid->sinkCap); + struct HdmiEdidFirstBlockInfo *block = (struct HdmiEdidFirstBlockInfo *)edid->raw; + + for (i = 0; i < HDMI_EDID_ESTABLISHED_TIMINGS_FIELD_LEN; i++) { + data |= (block->estTimings[i] << (i * HDMI_EDID_ONE_BYTE_SHIFT)); + } + + /* + * The established timing block is a field of one-bit flags, which are used to inducate support for established + * VESA and other common timing in a very compact form. A bit set to "1" indicate support for that timing. + */ + for (i = 0; i < HDMI_EDID_ESTABLISHED_TIMING_BUTT; i++) { + if ((data & (1 << i)) > 0) { + sinkCap->establishedTimingsInfo.estTimings[i] = i; + sinkCap->establishedTimingsInfo.estTimingsNum++; + } + } + return HDF_SUCCESS; +} + +static uint32_t HdmiEdidGetStandardTimingVertPixel(uint32_t aspectRatio, uint32_t horizPixel) +{ + uint32_t vertPixel = 0; + + switch (aspectRatio) { + case HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_16_10 : + vertPixel = horizPixel * 10 / 16; + break; + case HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_5_4 : + vertPixel = horizPixel * 4 / 5; + break; + case HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_4_3 : + vertPixel = horizPixel * 3 / 4; + break; + case HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_16_9 : + vertPixel = horizPixel * 9 / 16; + break; + default : + HDF_LOGE("aspectRatio %d is invalid.", aspectRatio); + break; + } + return vertPixel; +} + +static int32_t HdmiEdidStandardTimingPhase(struct HdmiEdid *edid) +{ + uint32_t i, aspectRatio; + struct HdmiSinkDeviceCapability *sinkCap = &(edid->sinkCap); + struct HdmiEdidFirstBlockInfo *block = (struct HdmiEdidFirstBlockInfo *)edid->raw; + uint8_t *data = block->stdTiming; + + /* + * A 2-byte timing identifier identifies each timing mode. + * Unused fields in this section shall be set to 01h, 01h. + */ + for (i = 0; i < HDMI_EDID_STANDARD_TIMING_COUNT; i++) { + if (data[0] != HDMI_EDID_STANDARD_TIMING_UNUSED_FLAG || data[1] != HDMI_EDID_STANDARD_TIMING_UNUSED_FLAG) { + sinkCap->stdTimingsInfo[i].horizPixel = (data[0] + HDMI_EDID_STANDARD_TIMING_HORIZ_PIXEL_BASE) * + HDMI_EDID_STANDARD_TIMING_HORIZ_PIXEL_FACTOR; + sinkCap->stdTimingsInfo[i].refreshRate = (data[1] & HDMI_EDID_STANDARD_TIMING_REFRESH_RATE_MARK) + + HDMI_EDID_STANDARD_TIMING_REFRESH_RATE_BASE; + aspectRatio = (data[1] & HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_MARK) >> + HDMI_EDID_STANDARD_TIMING_ASPECT_RATE_SHIFT; + sinkCap->stdTimingsInfo[i].vertPixel = + HdmiEdidGetStandardTimingVertPixel(aspectRatio, sinkCap->stdTimingsInfo[i].horizPixel); + } + data += HDMI_EDID_PER_STANDARD_TIMING_BYTE_NUM; + } + return HDF_SUCCESS; +} + +static void HdmiEdidMonitorDescriptorPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint32_t len) +{ + struct HdmiEdidMonitorBlockInfo *block = (struct HdmiEdidMonitorBlockInfo *)data; + + if (block->dataTag != HDMI_EDID_MONITOR_DATA_NAME) { + return; + } + if (memcpy_s(sinkCap->sinkDeviceName, HDMI_EDID_MAX_SINK_NAME_COUNT, + block->data, HDMI_EDID_MONITOR_DATA_FIELD_LEN) != EOK) { + HDF_LOGE("memcpy_s sink name fail"); + } +} + +static void HdmiEdidDigitalSyncSignal(struct HdmiEdidPreferredTimingInfo *perTiming, uint8_t flags) +{ + /* bit3/bit2/bit1 */ + switch ((flags & HDMI_EDID_DETAILED_TIMING_SYNC_SIGNAL_TYPE_MARK) >> 1) { + case HDMI_EDID_DETAILED_TIMING_SYNC_DCS_WS_0 : + case HDMI_EDID_DETAILED_TIMING_SYNC_DCS_WS_1 : + case HDMI_EDID_DETAILED_TIMING_SYNC_DCS_DS_2 : + case HDMI_EDID_DETAILED_TIMING_SYNC_DCS_DS_3 : + perTiming->ihs = false; + perTiming->ivs = false; + break; + case HDMI_EDID_DETAILED_TIMING_SYNC_DSS_VN_HN_4 : + perTiming->ihs = false; + perTiming->ivs = false; + break; + case HDMI_EDID_DETAILED_TIMING_SYNC_DSS_VN_HP_5 : + perTiming->ihs = true; + perTiming->ivs = false; + break; + case HDMI_EDID_DETAILED_TIMING_SYNC_DSS_VP_HN_6 : + perTiming->ihs = false; + perTiming->ivs = true; + break; + case HDMI_EDID_DETAILED_TIMING_SYNC_DSS_VP_HP_7 : + perTiming->ihs = true; + perTiming->ivs = true; + break; + default : + break; + } +} + +static void HdmiEdidDetailedTimingDescriptorPhase(struct HdmiSinkDeviceCapability *cap, uint8_t *data, uint32_t len) +{ + struct HdmiEdidDetailedTimingBlockInfo *block = (struct HdmiEdidDetailedTimingBlockInfo *)data; + struct HdmiEdidPreferredTimingInfo *perTiming = NULL; + uint32_t pixelClock; + + if (cap->preTimingCnt >= HDMI_EDID_MAX_DETAILED_TIMING_COUNT) { + HDF_LOGE("preTimingCnt reach the maximum"); + return; + } + + perTiming = &cap->preTimingInfo[cap->preTimingCnt]; + pixelClock = (block->pixelClk[1] << HDMI_EDID_ONE_BYTE_SHIFT) | (block->pixelClk[0]); + if (pixelClock == 0) { + HDF_LOGD(" pixel clock is 0. preTimingCnt = %d", cap->preTimingCnt); + return; + } + + perTiming->pixelClk = pixelClock * HDMI_EDID_DETAILED_TIMING_PIXEL_CLK_KHZ_FACTOR; + perTiming->hActive = (block->hActive) | + ((block->hActiveBlanking & HDMI_EDID_DETAILED_TIMING_UPPER_4BITS_MARK) << HDMI_EDID_NIBBLE_SHIFT); + perTiming->hBackBlank = (block->hBlanking) | + ((block->hActiveBlanking & HDMI_EDID_DETAILED_TIMING_LOWER_4BITS_MARK) << HDMI_EDID_ONE_BYTE_SHIFT); + perTiming->hFrontBlank = (block->hSyncOffset) | + ((block->hsOffsetVsOffset & HDMI_EDID_DETAILED_TIMING_HS_OFFSET_MARK) << HDMI_EDID_2_BITS_SHIFT); + perTiming->hSyncPluseWidth = (block->hSyncPulseWidth) | + ((block->hsOffsetVsOffset & HDMI_EDID_DETAILED_TIMING_HS_PULSE_WIDTH_MARK) << HDMI_EDID_NIBBLE_SHIFT); + + perTiming->vActive = (block->vActive) | + ((block->vActiveBlanking & HDMI_EDID_DETAILED_TIMING_UPPER_4BITS_MARK) << HDMI_EDID_NIBBLE_SHIFT); + perTiming->vBackBlank = (block->vBlanking) | + ((block->vActiveBlanking & HDMI_EDID_DETAILED_TIMING_LOWER_4BITS_MARK) << HDMI_EDID_ONE_BYTE_SHIFT); + perTiming->vFrontBlank = + ((block->hsOffsetVsOffset & HDMI_EDID_DETAILED_TIMING_VS_OFFSET_MARK) << HDMI_EDID_2_BITS_SHIFT) | + ((block->vsOffesetPulseWidth & HDMI_EDID_DETAILED_TIMING_UPPER_4BITS_MARK) >> HDMI_EDID_NIBBLE_SHIFT); + perTiming->vSyncPluseWidth = + ((block->hsOffsetVsOffset & HDMI_EDID_DETAILED_TIMING_VS_PULSE_WIDTH_MARK) << HDMI_EDID_NIBBLE_SHIFT) | + (block->vsOffesetPulseWidth & HDMI_EDID_DETAILED_TIMING_LOWER_4BITS_MARK); + + perTiming->imageWidth = (block->hImageSize) | + ((block->hvImageSize & HDMI_EDID_DETAILED_TIMING_UPPER_4BITS_MARK) << HDMI_EDID_NIBBLE_SHIFT); + perTiming->imageHeight = (block->vImageSize) | + ((block->hvImageSize & HDMI_EDID_DETAILED_TIMING_LOWER_4BITS_MARK) << HDMI_EDID_ONE_BYTE_SHIFT); + perTiming->interlaceFlag = (block->flags & HDMI_EDID_BIT7_MARK) ? true : false; + /* Digital composite/separate */ + if ((block->flags & HDMI_EDID_BIT4_MARK) != 0) { + HdmiEdidDigitalSyncSignal(perTiming, block->flags); + } + cap->preTimingCnt++; +} + +static void HdmiEdidDetailedTiming(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint32_t len) +{ + /* + * Monitor Descriptor flag: data0/data1/data2 is 0x00. + */ + if (data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x00) { + HdmiEdidMonitorDescriptorPhase(sinkCap, data, len); + return; + } + + /* + * Those 18-byte blocks not used for Monitor Descriptors shall be used for detailed timings. + */ + HdmiEdidDetailedTimingDescriptorPhase(sinkCap, data, len); +} + +static int32_t HdmiEdidDetailedTimingPhase(struct HdmiEdid *edid) +{ + struct HdmiSinkDeviceCapability *sinkCap = &(edid->sinkCap); + struct HdmiEdidFirstBlockInfo *block = (struct HdmiEdidFirstBlockInfo *)edid->raw; + + /* + * The detailed timing section is divided into four descriptor blocks, which are 18 bytes each. + * The first descriptor block shall be used to indicate the display's preferred timing mode. + * A Monitor Name Descriptor must be provided. + */ + HdmiEdidDetailedTiming(sinkCap, block->detailedTiming1, HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN); + HdmiEdidDetailedTiming(sinkCap, block->detailedTiming2, HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN); + HdmiEdidDetailedTiming(sinkCap, block->detailedTiming3, HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN); + HdmiEdidDetailedTiming(sinkCap, block->detailedTiming4, HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN); + return HDF_SUCCESS; +} + +static int32_t HdmiEdidExtBlockNumPhase(struct HdmiEdid *edid) +{ + struct HdmiSinkDeviceCapability *sinkCap = &(edid->sinkCap); + + sinkCap->extBlockNum = edid->raw[HDMI_EDID_EXTENSION_BLOCK_ADDR]; + if (sinkCap->extBlockNum > (HDMI_EDID_MAX_BLOCK_NUM - 1)) { + HDF_LOGW("ext block number %d is invallid.", sinkCap->extBlockNum); + sinkCap->extBlockNum = HDMI_EDID_MAX_BLOCK_NUM - 1; + } + return HDF_SUCCESS; +} + +static int32_t HdmiEdidFirstBlockPhase(struct HdmiEdid *edid) +{ + uint32_t i, len; + int32_t ret; + HdmiEdidPhaseFunc func[] = { HdmiEdidHeaderPhase, + HdmiEdidVendorInfoPhase, + HdmiEdidVersionInfoPhase, + HdmiEdidBasicDispPhase, + HdmiEdidColorFeaturePhase, + HdmiEdidEstablisedTimingPhase, + HdmiEdidStandardTimingPhase, + HdmiEdidDetailedTimingPhase, + HdmiEdidExtBlockNumPhase }; + + ret = HdmiEdidBlockCheckSum(edid->raw); + if (ret != HDF_SUCCESS) { + HDF_LOGE("edid block0 check sum fail."); + return ret; + } + + len = sizeof(func) / sizeof(func[0]); + for (i = 0; i < len; i++) { + if (func[i] == NULL) { + continue; + } + ret = (func[i])(edid); + if (ret != HDF_SUCCESS) { + HDF_LOGE("func[%d] exe fail.", i); + return ret; + } + } + return HDF_SUCCESS; +} + +static void HdmiEdidExtAdbSampleRatePhase(struct HdmiEdidAudioInfo *audio, uint8_t data, uint8_t formatCode) +{ + if ((data & HDMI_EDID_BIT0_MARK) > 0 && + audio->sampleRateNum < HDMI_EDID_EXTENSION_AUDIO_MAX_SAMPLE_RATE_NUM) { + audio->sampleRate[audio->sampleRateNum] = HDMI_SAMPLE_RATE_32K; + audio->sampleRateNum++; + } + if ((data & HDMI_EDID_BIT1_MARK) > 0 && + audio->sampleRateNum < HDMI_EDID_EXTENSION_AUDIO_MAX_SAMPLE_RATE_NUM) { + audio->sampleRate[audio->sampleRateNum] = HDMI_SAMPLE_RATE_44K; + audio->sampleRateNum++; + } + if ((data & HDMI_EDID_BIT2_MARK) > 0 && + audio->sampleRateNum < HDMI_EDID_EXTENSION_AUDIO_MAX_SAMPLE_RATE_NUM) { + audio->sampleRate[audio->sampleRateNum] = HDMI_SAMPLE_RATE_48K; + audio->sampleRateNum++; + } + if ((data & HDMI_EDID_BIT3_MARK) > 0 && + audio->sampleRateNum < HDMI_EDID_EXTENSION_AUDIO_MAX_SAMPLE_RATE_NUM) { + audio->sampleRate[audio->sampleRateNum] = HDMI_SAMPLE_RATE_88K; + audio->sampleRateNum++; + } + if ((data & HDMI_EDID_BIT4_MARK) > 0 && + audio->sampleRateNum < HDMI_EDID_EXTENSION_AUDIO_MAX_SAMPLE_RATE_NUM) { + audio->sampleRate[audio->sampleRateNum] = HDMI_SAMPLE_RATE_96K; + audio->sampleRateNum++; + } + + if (formatCode >= HDMI_AUDIO_CODING_TYPE_LPCM && formatCode <= HDMI_AUDIO_CODING_TYPE_WMA_PRO) { + if ((data & HDMI_EDID_BIT5_MARK) > 0 && + audio->sampleRateNum < HDMI_EDID_EXTENSION_AUDIO_MAX_SAMPLE_RATE_NUM) { + audio->sampleRate[audio->sampleRateNum] = HDMI_SAMPLE_RATE_176K; + audio->sampleRateNum++; + } + if ((data & HDMI_EDID_BIT6_MARK) > 0 && + audio->sampleRateNum < HDMI_EDID_EXTENSION_AUDIO_MAX_SAMPLE_RATE_NUM) { + audio->sampleRate[audio->sampleRateNum] = HDMI_SAMPLE_RATE_192K; + audio->sampleRateNum++; + } + } +} + +static void HdmiEdidExtAdbDepthAndMaxRatePhase(struct HdmiEdidAudioInfo *audio, uint8_t data, uint8_t formatCode) +{ + /* + * Audio Format Code is 1, bit[2:0] bit depth; + * Audio Format Codes 2 to 8, Maximum bit rate divided by 8 kHz. + */ + if (formatCode == HDMI_AUDIO_CODING_TYPE_LPCM) { + if ((data & HDMI_EDID_BIT0_MARK) > 0 && + audio->bitDepthNum < HDMI_EDID_EXTENSION_AUDIO_MAX_BIT_DEPTH_NUM) { + audio->bitDepth[audio->bitDepthNum] = HDMI_ADIO_BIT_DEPTH_16; + audio->bitDepthNum++; + } + if ((data & HDMI_EDID_BIT1_MARK) > 0 && + audio->bitDepthNum < HDMI_EDID_EXTENSION_AUDIO_MAX_BIT_DEPTH_NUM) { + audio->bitDepth[audio->bitDepthNum] = HDMI_ADIO_BIT_DEPTH_20; + audio->bitDepthNum++; + } + if ((data & HDMI_EDID_BIT2_MARK) > 0 && + audio->bitDepthNum < HDMI_EDID_EXTENSION_AUDIO_MAX_BIT_DEPTH_NUM) { + audio->bitDepth[audio->bitDepthNum] = HDMI_ADIO_BIT_DEPTH_24; + audio->bitDepthNum++; + } + } else if (formatCode >= HDMI_AUDIO_CODING_TYPE_AC3 && formatCode <= HDMI_AUDIO_CODING_TYPE_ATRAC) { + audio->maxBitRate = data * HDMI_EDID_EXTENSION_AUDIO_BIT_RATE_FACTOR; + } else { + HDF_LOGI("formatCode %d reserved or not care", formatCode); + } +} + +static int32_t HdmiEdidExtAudioDataBlockPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + uint8_t i, formatCode; + + /* + * Each Short Audio Descriptor is 3-bytes long. There can be up to 31 bytes following any tag, + * therefore there may be up to 10 Short Audio Descriptors in the Audio Data Block (ADB). + */ + if (len > (HDMI_EDID_EXTENSION_SHORT_AUDIO_DESCRIPTOR_LEN * HDMI_EDID_EXTENSION_MAX_SHORT_AUDIO_DESCRIPTOR_NUM)) { + HDF_LOGE("ADB: len %d is invalid", len); + return HDF_ERR_INVALID_PARAM; + } + + for (i = 0; i < (len / HDMI_EDID_EXTENSION_SHORT_AUDIO_DESCRIPTOR_LEN); i++) { + if (sinkCap->audioInfoCnt >= HDMI_EDID_EXTENSION_AUDIO_CAP_COUNT) { + HDF_LOGE("ADB: info cnt reach the maximum"); + break; + } + data += (i * HDMI_EDID_EXTENSION_SHORT_AUDIO_DESCRIPTOR_LEN); + /* byte0: bit[6:3] Audio Format Code; bit[2:0] Max Number of channels - 1 */ + formatCode = (data[0] & HDMI_EDID_EXTENSION_AUDIO_FORMAT_CODE_MARK) >> + HDMI_EDID_EXTENSION_AUDIO_FORMAT_CODE_SHIFT; + sinkCap->audioInfo[sinkCap->audioInfoCnt].formatCode = (enum HdmiAudioCodingType)formatCode; + sinkCap->audioInfo[sinkCap->audioInfoCnt].channels = + (data[0] & HDMI_EDID_EXTENSION_AUDIO_MAX_CHANNEL_MARK) + 1; + /* byte1: Sample Rate */ + HdmiEdidExtAdbSampleRatePhase(&(sinkCap->audioInfo[sinkCap->audioInfoCnt]), data[1], formatCode); + /* byte2: bit depth or maximum bit rate */ + HdmiEdidExtAdbDepthAndMaxRatePhase(&(sinkCap->audioInfo[sinkCap->audioInfoCnt]), data[2], formatCode); + sinkCap->audioInfoCnt++; + } + return HDF_SUCCESS; +} + +static int32_t HdmiEdidExtVideoDataBlockPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + uint8_t i; + uint32_t vicAll = 0; + uint32_t vicLower = 0; + uint32_t implicitNative = 0; + + for (i = 0; i < len; i++) { + if (sinkCap->videoInfo.vicNum >= HDMI_EDID_EXTENSION_MAX_VIC_COUNT) { + HDF_LOGD("VDB: vicNum reach the maximum"); + break; + } + vicAll = data[i]; + vicLower = (vicAll & HDMI_EDID_EXTENSION_VIC_LOWER7_MARK); + if (vicAll == 0) { + continue; + } + /* + * For VICs 1 through 64, the lower 7-bits are an index associated with the Video Format supported. + * The most significant bit declares whether the format is a Native Video Format of the + * display (native =1, not native = 0). Typically, there is a single SVD, with its native bit set. + */ + if ((vicAll & HDMI_EDID_BIT7_MARK) > 0 && vicLower < HDMI_EDID_EXTENSION_VIC_NATIVE_MAX) { + if (sinkCap->videoInfo.nativeFormat == 0) { + sinkCap->videoInfo.nativeFormat = vicLower; + } + } + /* set the first valid vic as implicit native */ + if (implicitNative == 0) { + implicitNative = vicAll; + } + if ((vicAll & HDMI_EDID_BIT7_MARK) > 0 && vicLower < HDMI_EDID_EXTENSION_VIC_NATIVE_MAX) { + sinkCap->videoInfo.vic[sinkCap->videoInfo.vicNum] = vicLower; + } else { + sinkCap->videoInfo.vic[sinkCap->videoInfo.vicNum] = vicAll; + } + sinkCap->videoInfo.vicNum++; + } + + if (sinkCap->videoInfo.nativeFormat == 0) { + sinkCap->videoInfo.nativeFormat = implicitNative; + } + return HDF_SUCCESS; +} + +static void HdmiEdidVsdbCecPhyAddrPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + if (len >= 5) { + sinkCap->vsdbInfo.cecAddr.phyAddrA = (data[3] & HDMI_EDID_UPPER_NIBBLE_MARK) >> HDMI_EDID_NIBBLE_SHIFT; + sinkCap->vsdbInfo.cecAddr.phyAddrB = (data[3] & HDMI_EDID_LOWER_NIBBLE_MARK); + sinkCap->vsdbInfo.cecAddr.phyAddrC = (data[4] & HDMI_EDID_UPPER_NIBBLE_MARK) >> HDMI_EDID_NIBBLE_SHIFT; + sinkCap->vsdbInfo.cecAddr.phyAddrD = (data[4] & HDMI_EDID_LOWER_NIBBLE_MARK); + sinkCap->vsdbInfo.cecAddr.addrValid = + (sinkCap->vsdbInfo.cecAddr.phyAddrA != HDMI_EDID_EXTENSION_VSDB_CEC_INVALID_ADDR) && + (sinkCap->vsdbInfo.cecAddr.phyAddrB != HDMI_EDID_EXTENSION_VSDB_CEC_INVALID_ADDR) && + (sinkCap->vsdbInfo.cecAddr.phyAddrC != HDMI_EDID_EXTENSION_VSDB_CEC_INVALID_ADDR) && + (sinkCap->vsdbInfo.cecAddr.phyAddrD != HDMI_EDID_EXTENSION_VSDB_CEC_INVALID_ADDR); + } +} + +static void HdmiEdidVsdbColorDepthPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + if (len >= 6) { + sinkCap->vsdbInfo.supportAi = (data[5] & HDMI_EDID_BIT7_MARK) ? true : false; + sinkCap->vsdbInfo.supportDviDual = (data[5] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->vsdbInfo.deepColor.dcY444 = (data[5] & HDMI_EDID_BIT3_MARK) ? true : false; + sinkCap->vsdbInfo.deepColor.dc30bit = (data[5] & HDMI_EDID_BIT4_MARK) ? true : false; + sinkCap->vsdbInfo.deepColor.dc36bit = (data[5] & HDMI_EDID_BIT5_MARK) ? true : false; + sinkCap->vsdbInfo.deepColor.dc48bit = (data[5] & HDMI_EDID_BIT6_MARK) ? true : false; + } +} + +static void HdmiEdidVsdbMaxTmdsClockPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + /* + * This field shall be set cprrectly and non-zero if the sink support TMDS clock frequencies above 165MHz or + * supports ant Deep Color mode or supports DVI dual-link. A value of zeor means that no clock rate is indicated. + */ + if (len >= 7) { + sinkCap->maxTmdsClk = data[6] * HDMI_EDID_EXTENSION_TMDS_FACTOR; + sinkCap->supportHdmi20 = (sinkCap->maxTmdsClk > HDMI_EDID_EXTENSION_MAX_HDMI14_TMDS_RATE) ? true : false; + } +} + +static void HdmiEdidVsdbSinkPresentPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + if (len >= 8) { + sinkCap->vsdbInfo.latencyFieldsPresent = (data[7] & HDMI_EDID_BIT7_MARK) ? true : false; + sinkCap->vsdbInfo.iLatencyFieldsPresent = (data[7] & HDMI_EDID_BIT6_MARK) ? true : false; + sinkCap->vsdbInfo.hdmiVideoPresent = (data[7] & HDMI_EDID_BIT5_MARK) ? true : false; + } +} + +static void HdmiEdidVsdbSinkLatencyPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + if (sinkCap->vsdbInfo.latencyFieldsPresent == true) { + if (len >= 9) { + sinkCap->vsdbInfo.videoLatency = data[8]; + } + if (len >= 10) { + sinkCap->vsdbInfo.videoLatency = data[9]; + } + } + if (sinkCap->vsdbInfo.iLatencyFieldsPresent == true) { + if (len >= 11) { + sinkCap->vsdbInfo.interlacedVideoLatency = data[10]; + } + if (len >= 12) { + sinkCap->vsdbInfo.interlacedAudioLatency = data[11]; + } + } +} + +static void HdmiEdidVsdbVicInfoPhase(struct HdmiSinkDeviceCapability *sinkCap, + uint8_t *data, uint8_t vicLen, uint8_t *offset) +{ + uint8_t i, index; + /* see hdmi spec 1.4 table 8-13. */ + uint32_t hdmi4kVic[] = { 0, + HDMI_VIC_3840X2160P30_16_9, + HDMI_VIC_3840X2160P25_16_9, + HDMI_VIC_3840X2160P24_16_9, + HDMI_VIC_4096X2160P24_256_135 }; + + for (i = 0; i < vicLen; i++) { + if (sinkCap->videoInfo.vicNum >= HDMI_EDID_EXTENSION_MAX_VIC_COUNT) { + break; + } + index = data[(*offset)]; + if (index != 0 && index < sizeof(hdmi4kVic) / sizeof(hdmi4kVic[0])) { + sinkCap->videoInfo.vic[sinkCap->videoInfo.vicNum] = hdmi4kVic[index]; + sinkCap->videoInfo.vicNum++; + } + (*offset)++; + } +} + +static void HdmiEdidVsdb3dStructureInfoPhase(struct HdmiSinkDeviceCapability *sinkCap, + uint8_t *data, uint8_t len, uint8_t *offset) +{ + /* + * If 3D_Multi_present is 1 or 2, 3D_Struct_ALL_15...0 is present and assigns 3D formats to + * all of the VICs listed in the first 16 entries in the EDID. + */ + if ((sinkCap->vsdbInfo._3dMultiPresent & HDMI_EDID_EXTENSION_VSDB_3D_STR_INVALID_MARK) == 0) { + return; + } + /* see hdmi spec 1.4 table H-8. */ + if ((*offset) <= len) { + /* + * bit[15:9]: reserved. + * bit8: sinks support "Side-by-side(half) with all sub-sampling methods" 3D formats. + */ + sinkCap->vsdbInfo.support3dType[HDMI_VS_VIDEO_3D_SIDE_BY_SIDE_HALF] = + (data[(*offset)] & HDMI_EDID_BIT0_MARK) ? true : false; + (*offset)++; + } + + if ((*offset) <= len) { + sinkCap->vsdbInfo.support3dType[HDMI_VS_VIDEO_3D_FRAME_PACKING] = + (data[(*offset)] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->vsdbInfo.support3dType[HDMI_VS_VIDEO_3D_FIELD_ALTERNATIVE] = + (data[(*offset)] & HDMI_EDID_BIT1_MARK) ? true : false; + sinkCap->vsdbInfo.support3dType[HDMI_VS_VIDEO_3D_LINE_ALTERNATIVE] = + (data[(*offset)] & HDMI_EDID_BIT2_MARK) ? true : false; + sinkCap->vsdbInfo.support3dType[HDMI_VS_VIDEO_3D_SIDE_BY_SIDE_FULL] = + (data[(*offset)] & HDMI_EDID_BIT3_MARK) ? true : false; + sinkCap->vsdbInfo.support3dType[HDMI_VS_VIDEO_3D_L_DEPTH] = + (data[(*offset)] & HDMI_EDID_BIT4_MARK) ? true : false; + sinkCap->vsdbInfo.support3dType[HDMI_VS_VIDEO_3D_L_DEPTH_GFX_GFX_DEPTH] = + (data[(*offset)] & HDMI_EDID_BIT5_MARK) ? true : false; + sinkCap->vsdbInfo.support3dType[HDMI_VS_VIDEO_3D_TOP_AND_BOTTOM] = + (data[(*offset)] & HDMI_EDID_BIT6_MARK) ? true : false; + (*offset)++; + } +} + +static void HdmiEdidVsdbVicAnd3dInfoPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + uint8_t hdmiVicLen = 0; + uint8_t hdmi3dLen = 0; + uint8_t offset; + + if (len < 13) { + HDF_LOGD("vsdb: these is no vic/3d field."); + return; + } + sinkCap->vsdbInfo._3dPresent = (data[12] & HDMI_EDID_BIT7_MARK) ? true : false; + sinkCap->vsdbInfo._3dMultiPresent = + (data[12] & HDMI_EDID_EXTENSION_VSDB_3D_MULTI_PRESENT_MARK) >> HDMI_EDID_EXTENSION_VSDB_3D_MULTI_PRESENT_SHIFT; + + if (len >= 14) { + hdmiVicLen = (data[13] & HDMI_EDID_EXTENSION_VSDB_VIC_LEN_MARK) >> HDMI_EDID_EXTENSION_VSDB_VIC_LEN_SHIFT; + hdmi3dLen = (data[13] & HDMI_EDID_EXTENSION_VSDB_3D_LEN_MARK); + } + + /* byte14~byteN: Vic info/3D info */ + offset = 14; + if (hdmiVicLen > 0 && (hdmiVicLen + offset + 1) <= len) { + HdmiEdidVsdbVicInfoPhase(sinkCap, data, hdmiVicLen, &offset); + } + + if (hdmi3dLen > 0 && + sinkCap->vsdbInfo._3dPresent == true && + (hdmi3dLen + offset + 1) <= len) { + HdmiEdidVsdb3dStructureInfoPhase(sinkCap, data, len, &offset); + } +} + +static int32_t HdmiEdidVsdbPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + /* byte3 byte4: cec addr */ + if (len < 5) { + HDF_LOGD("vsdb: len = %d, too short.", len); + return HDF_SUCCESS; + } + HdmiEdidVsdbCecPhyAddrPhase(sinkCap, data, len); + /* byte 5: color depth flags */ + HdmiEdidVsdbColorDepthPhase(sinkCap, data, len); + /* byte 6: max tmds clock. */ + HdmiEdidVsdbMaxTmdsClockPhase(sinkCap, data, len); + /* byte7: some sink present */ + HdmiEdidVsdbSinkPresentPhase(sinkCap, data, len); + /* + * byte8: Video_Latency + * byte9: Audio_Latency + * byte10: Interlaced_Video_Latency + * byte11: Interlaced_Audio_Latency + */ + HdmiEdidVsdbSinkLatencyPhase(sinkCap, data, len); + /* + * byte12: 3D_Present, 3D_Multi_present + * byte13: HDMI_VIC_LEN/HDMI_3D_LEN + * byte14~byteN: Vic info/3D info + */ + HdmiEdidVsdbVicAnd3dInfoPhase(sinkCap, data, len); + return HDF_SUCCESS; +} + +static void HdmiEdidHfVsdb21Phase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + sinkCap->hfVsdbInfo.maxFrlRate = (data[6] & HDMI_EDID_UPPER_NIBBLE_MARK) >> HDMI_EDID_NIBBLE_SHIFT; + + sinkCap->hfVsdbInfo.fapaStartLocation = (data[7] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->hfVsdbInfo.allm = (data[7] & HDMI_EDID_BIT1_MARK) ? true : false; + sinkCap->hfVsdbInfo.fva = (data[7] & HDMI_EDID_BIT2_MARK) ? true : false; + sinkCap->hfVsdbInfo.cnmVrr = (data[7] & HDMI_EDID_BIT3_MARK) ? true : false; + sinkCap->hfVsdbInfo.cinemaVrr = (data[7] & HDMI_EDID_BIT4_MARK) ? true : false; + sinkCap->hfVsdbInfo.mDelta = (data[7] & HDMI_EDID_BIT5_MARK) ? true : false; + sinkCap->hfVsdbInfo.vrrMin = (data[8] & 0x3F); + sinkCap->hfVsdbInfo.vrrMax = ((data[8] & 0xC0) << 2) | data[9]; + + sinkCap->hfVsdbInfo.dscInfo.dsc1p2 = (data[10] & HDMI_EDID_BIT7_MARK) ? true : false; + sinkCap->hfVsdbInfo.dscInfo.dscNative420 = (data[10] & HDMI_EDID_BIT6_MARK) ? true : false; + sinkCap->hfVsdbInfo.dscInfo.dscAllBpp = (data[10] & HDMI_EDID_BIT3_MARK) ? true : false; + sinkCap->hfVsdbInfo.dscInfo.dsc10bpc = (data[10] & HDMI_EDID_BIT2_MARK) ? true : false; + sinkCap->hfVsdbInfo.dscInfo.dsc20bpc = (data[10] & HDMI_EDID_BIT1_MARK) ? true : false; + sinkCap->hfVsdbInfo.dscInfo.dsc16bpc = (data[10] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->hfVsdbInfo.dscInfo.dscMaxSlices = (data[11] & HDMI_EDID_LOWER_NIBBLE_MARK); + sinkCap->hfVsdbInfo.dscInfo.dscMaxFrlRate = (data[11] & HDMI_EDID_UPPER_NIBBLE_MARK) >> HDMI_EDID_NIBBLE_SHIFT; + sinkCap->hfVsdbInfo.dscInfo.dscTotalChunkKBytes = (data[12] & 0x3F); +} + +static int32_t HdmiEdidHfVsdbPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + if (len < HDMI_EDID_EXTENSION_HFVSDB_MIN_INVALID_LEN) { + HDF_LOGD("vsdb: data len %d is too short.", len); + return HDF_SUCCESS; + } + + /* byte3: Version */ + if (data[3] != HDMI_EDID_EXTENSION_HFVSDB_VERSION) { + HDF_LOGD("vsdb: verdion %d is invalid.", data[3]); + } + /* byte4: Max_TMDS_Character_Rate */ + sinkCap->maxTmdsClk = data[4] * HDMI_EDID_EXTENSION_TMDS_FACTOR; + sinkCap->supportHdmi20 = (sinkCap->maxTmdsClk > HDMI_EDID_EXTENSION_MAX_HDMI14_TMDS_RATE) ? true : false; + /* byte5: several sink present */ + sinkCap->hfVsdbInfo.scdcPresent = (data[5] & HDMI_EDID_BIT7_MARK) ? true : false; + sinkCap->hfVsdbInfo.rrCapable = (data[5] & HDMI_EDID_BIT6_MARK) ? true : false; + sinkCap->hfVsdbInfo.lte340McscScramble = (data[5] & HDMI_EDID_BIT3_MARK) ? true : false; + sinkCap->hfVsdbInfo.independentView = (data[5] & HDMI_EDID_BIT2_MARK) ? true : false; + sinkCap->hfVsdbInfo.dualView = (data[5] & HDMI_EDID_BIT1_MARK) ? true : false; + sinkCap->hfVsdbInfo._3dOsdDisparity = (data[5] & HDMI_EDID_BIT0_MARK) ? true : false; + /* byte6: deep color */ + sinkCap->hfVsdbInfo.dc.dc30bit = (data[6] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->hfVsdbInfo.dc.dc36bit = (data[6] & HDMI_EDID_BIT1_MARK) ? true : false; + sinkCap->hfVsdbInfo.dc.dc48bit = (data[6] & HDMI_EDID_BIT2_MARK) ? true : false; + if (len > HDMI_EDID_EXTENSION_HFVSDB_MIN_INVALID_LEN && + len <= HDMI_EDID_EXTENSION_HFVSDB_MAX_INVALID_LEN) { + HdmiEdidHfVsdb21Phase(sinkCap, data, len); + } + return HDF_SUCCESS; +} + +static int32_t HdmiEdidExtVsDataBlockPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + int32_t ret = HDF_SUCCESS; + bool vsdb = false; + bool hfVsdb = false; + + if (len >= HDMI_EDID_EXTENSION_VSDB_LEN && + data[0] == HDMI_EDID_EXTENSION_VSDB_IEEE_1ST && + data[1] == HDMI_EDID_EXTENSION_VSDB_IEEE_2ND && + data[2] == HDMI_EDID_EXTENSION_VSDB_IEEE_3RD) { + vsdb = true; + } + + if (len >= HDMI_EDID_EXTENSION_VSDB_LEN && + data[0] == HDMI_EDID_EXTENSION_HFVSDB_IEEE_1ST && + data[1] == HDMI_EDID_EXTENSION_HFVSDB_IEEE_2ND && + data[2] == HDMI_EDID_EXTENSION_HFVSDB_IEEE_3RD) { + hfVsdb = true; + } + + if (vsdb == true) { + sinkCap->supportHdmi14 = true; + ret = HdmiEdidVsdbPhase(sinkCap, data, len); + } else if (hfVsdb == true) { + ret = HdmiEdidHfVsdbPhase(sinkCap, data, len); + } + return ret; +} + +static int32_t HdmiEdidExtSpeakerDataBlockPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + if (len < HDMI_EDID_EXTENSION_SADB_MIN_INVALID_LEN) { + HDF_LOGD("SADB: len %d is too short", len); + return HDF_SUCCESS; + } + + sinkCap->supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_FL_FR] = + (data[0] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_LFE] = + (data[0] & HDMI_EDID_BIT1_MARK) ? true : false; + sinkCap->supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_FC] = + (data[0] & HDMI_EDID_BIT2_MARK) ? true : false; + sinkCap->supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_BL_BR] = + (data[0] & HDMI_EDID_BIT3_MARK) ? true : false; + sinkCap->supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_BC] = + (data[0] & HDMI_EDID_BIT4_MARK) ? true : false; + sinkCap->supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_FLC_FRC] = + (data[0] & HDMI_EDID_BIT5_MARK) ? true : false; + sinkCap->supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_RLC_RRC] = + (data[0] & HDMI_EDID_BIT6_MARK) ? true : false; + sinkCap->supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_FLW_FRW] = + (data[0] & HDMI_EDID_BIT7_MARK) ? true : false; + sinkCap->supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_TPFL_TPFH] = + (data[1] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_TPC] = + (data[1] & HDMI_EDID_BIT1_MARK) ? true : false; + sinkCap->supportAudioSpeaker[HDMI_EDID_AUDIO_SPEAKER_TPFC] = + (data[1] & HDMI_EDID_BIT2_MARK) ? true : false; + return HDF_SUCCESS; +} + +static void HdmiEdidExtUseExtDataBlockVcdbPhase(struct HdmiSinkDeviceCapability *sinkCap, + uint8_t *data, uint8_t len) +{ + if (len < HDMI_EDID_VCDB_LEN) { + HDF_LOGD("VCDB: len is too short"); + return; + } + + sinkCap->videoCap.qy = (data[1] & HDMI_EDID_BIT7_MARK) ? true : false; + sinkCap->videoCap.qs = (data[1] & HDMI_EDID_BIT6_MARK) ? true : false; +} + +static void HdmiEdidExtUseExtDataBlockCdbPhase(struct HdmiSinkDeviceCapability *sinkCap, + uint8_t *data, uint8_t len) +{ + if (len < HDMI_EDID_CDB_LEN) { + HDF_LOGD("CDB: len is too short"); + return; + } + + sinkCap->colorimetry.xvYcc601 = (data[1] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->colorimetry.xvYcc709 = (data[1] & HDMI_EDID_BIT1_MARK) ? true : false; + sinkCap->colorimetry.sYcc601 = (data[1] & HDMI_EDID_BIT2_MARK) ? true : false; + sinkCap->colorimetry.opYcc601 = (data[1] & HDMI_EDID_BIT3_MARK) ? true : false; + sinkCap->colorimetry.opRgb = (data[1] & HDMI_EDID_BIT4_MARK) ? true : false; + sinkCap->colorimetry.bt2020cYcc = (data[1] & HDMI_EDID_BIT5_MARK) ? true : false; + sinkCap->colorimetry.bt2020Ycc = (data[1] & HDMI_EDID_BIT6_MARK) ? true : false; + sinkCap->colorimetry.bt2020Rgb = (data[1] & HDMI_EDID_BIT7_MARK) ? true : false; + + sinkCap->colorimetry.dciP3 = (data[2] & HDMI_EDID_BIT7_MARK) ? true : false; + sinkCap->colorimetry.md = (data[2] & HDMI_EDID_LOWER_NIBBLE_MARK); +} + +static void HdmiEdidExtUseExtDataBlockY420VdbPhase(struct HdmiSinkDeviceCapability *sinkCap, + uint8_t *data, uint8_t len) +{ + uint8_t i; + uint32_t vic; + + for (i = 1; i < len; i++) { + if (sinkCap->y420Cap.onlySupportY420VicNum >= HDMI_EDID_EXTENSION_MAX_VIC_COUNT) { + HDF_LOGD("Y420Vdb: vic num reach to max."); + break; + } + vic = data[i]; + if (vic == 0 || + (vic >= HDMI_EDID_EXTENSION_VIC_INVALID_LOW && vic <= HDMI_EDID_EXTENSION_VIC_INVALID_HIGH)) { + continue; + } + sinkCap->y420Cap.onlySupportY420Format[sinkCap->y420Cap.onlySupportY420VicNum] = vic; + sinkCap->y420Cap.onlySupportY420VicNum++; + sinkCap->colorSpace.ycbcr420 = true; + } +} + +static void HdmiEdidExtUseExtDataBlockY420CmdbPhase(struct HdmiSinkDeviceCapability *sinkCap, + uint8_t *data, uint8_t len) +{ + uint32_t i, loop; + + /* + * When the Length field is set to 1, the Y420CMDB does not include a YCBCR 4:2:0 Capability Bit Map and + * all the SVDs in the regular Video Data Block(s) support YCBCR 4:2:0 sampling mode. + */ + if (len == 1) { + for (i = 0; (i < sinkCap->videoInfo.vicNum) && (i < HDMI_EDID_EXTENSION_MAX_VIC_COUNT); i++) { + if (sinkCap->y420Cap.SupportY420VicNum >= HDMI_EDID_EXTENSION_MAX_VIC_COUNT) { + break; + } + sinkCap->y420Cap.SupportY420Format[sinkCap->y420Cap.SupportY420VicNum] = sinkCap->videoInfo.vic[i]; + sinkCap->y420Cap.SupportY420VicNum++; + sinkCap->colorSpace.ycbcr420 = true; + } + return; + } + + /* + * Bit 0 of data byte 3 is associated with the first sequential SVD listed in the regular Video Data Block(s) + * of the EDID, bit 1 the second SVD, bit 2 the third, and so on. + */ + loop = len * HDMI_EDID_BITS_OF_ONE_BYTE; + loop = (loop > HDMI_EDID_EXTENSION_MAX_VIC_COUNT) ? HDMI_EDID_EXTENSION_MAX_VIC_COUNT : loop; + data++; + for (i = 0; (i < loop) && (i < sinkCap->videoInfo.vicNum); i++) { + if (sinkCap->y420Cap.SupportY420VicNum >= HDMI_EDID_EXTENSION_MAX_VIC_COUNT) { + break; + } + if ((data[i / HDMI_EDID_BITS_OF_ONE_BYTE] & (0x01 << (i % HDMI_EDID_BITS_OF_ONE_BYTE))) > 0) { + sinkCap->y420Cap.SupportY420Format[sinkCap->y420Cap.SupportY420VicNum] = sinkCap->videoInfo.vic[i]; + sinkCap->y420Cap.SupportY420VicNum++; + sinkCap->colorSpace.ycbcr420 = true; + } + } +} + +static void HdmiEdidExtUseExtDataBlockHdrSmdbPhase(struct HdmiSinkDeviceCapability *sinkCap, + uint8_t *data, uint8_t len) +{ + if (len < HDMI_EDID_HDR_SMDB_MIN_LEN) { + HDF_LOGD("Hdr SMDB: len is too short"); + return; + } + + sinkCap->hdrCap.eotf.sdr = (data[1] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->hdrCap.eotf.hdr = (data[1] & HDMI_EDID_BIT1_MARK) ? true : false; + sinkCap->hdrCap.eotf.smpteSt2048 = (data[1] & HDMI_EDID_BIT2_MARK) ? true : false; + sinkCap->hdrCap.eotf.hlg = (data[1] & HDMI_EDID_BIT2_MARK) ? true : false; + sinkCap->hdrCap.smType1 = (data[2] & HDMI_EDID_BIT0_MARK) ? true : false; + + /* + * The length of the data block, n, in Byte 1 indicates which of the Bytes 5 to 7 are present. Bytes 5 to 7 are + * optional to declare. When n is 3, Bytes 5 to 7 are not present. When n is 4, Byte 5 is present; when n is 5, + * Bytes 5 and 6 are present; and when n is 6, Bytes 5 to 7 are present. + */ + if (len >= 4) { + sinkCap->hdrCap.maxLuminancedata = data[3]; + } + if (len >= 5) { + sinkCap->hdrCap.maxFrameAverageLuminanceData = data[4]; + } + if (len >= 6) { + sinkCap->hdrCap.maxFrameAverageLuminanceData = data[5]; + } +} + +static void HdmiEdidExtUseExtDataBlockVsvdbPhase(struct HdmiSinkDeviceCapability *sinkCap, + uint8_t *data, uint8_t len) +{ + uint32_t oui; + + if (len != HDMI_EDID_VSVDB_DOLBY_VERSION_0_LEN && + len != HDMI_EDID_VSVDB_DOLBY_VERSION_1_LEN) { + HDF_LOGD("Vsvdb: invalid dolby len"); + return; + } + + oui = (data[1]) | (data[2] << 8) | (data[3] << 16); + if (oui != HDMI_EDID_VSVDB_DOLBY_OUI) { + return; + } + sinkCap->dolbyCap.oui = oui; + sinkCap->dolbyCap.version = (data[4] & HDMI_EDID_VSVDB_DOLBY_VERSION_MARK) >> HDMI_EDID_VSVDB_DOLBY_VERSION_SHIFT; + sinkCap->dolbyCap.yuv422 = (data[4] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->dolbyCap.b2160p60 = (data[4] & HDMI_EDID_BIT1_MARK) ? true : false; + if (sinkCap->dolbyCap.version == HDMI_EDID_VSVDB_DOLBY_VERSION_0) { + sinkCap->dolbyCap.globalDimming = (data[4] & HDMI_EDID_BIT2_MARK) ? true : false; + sinkCap->dolbyCap.redX = ((data[5] & HDMI_EDID_UPPER_NIBBLE_MARK) >> HDMI_EDID_NIBBLE_SHIFT) | + (data[6] << HDMI_EDID_NIBBLE_SHIFT); + sinkCap->dolbyCap.redY = (data[5] & HDMI_EDID_LOWER_NIBBLE_MARK) | (data[7] << HDMI_EDID_NIBBLE_SHIFT); + sinkCap->dolbyCap.greenX = ((data[8] & HDMI_EDID_UPPER_NIBBLE_MARK) >> HDMI_EDID_NIBBLE_SHIFT) | + (data[9] << HDMI_EDID_NIBBLE_SHIFT); + sinkCap->dolbyCap.greenY = (data[8] & HDMI_EDID_LOWER_NIBBLE_MARK) | (data[10] << HDMI_EDID_NIBBLE_SHIFT); + sinkCap->dolbyCap.blueX = ((data[11] & HDMI_EDID_UPPER_NIBBLE_MARK) >> HDMI_EDID_NIBBLE_SHIFT) | + (data[12] << HDMI_EDID_NIBBLE_SHIFT); + sinkCap->dolbyCap.blueY = (data[11] & HDMI_EDID_LOWER_NIBBLE_MARK) | (data[13] << HDMI_EDID_NIBBLE_SHIFT); + sinkCap->dolbyCap.whiteX = ((data[14] & HDMI_EDID_UPPER_NIBBLE_MARK) >> HDMI_EDID_NIBBLE_SHIFT) | + (data[15] << HDMI_EDID_NIBBLE_SHIFT); + sinkCap->dolbyCap.whiteY = (data[14] & HDMI_EDID_LOWER_NIBBLE_MARK) | (data[16] << HDMI_EDID_NIBBLE_SHIFT); + sinkCap->dolbyCap.minLuminance = ((data[17] & HDMI_EDID_UPPER_NIBBLE_MARK) >> HDMI_EDID_NIBBLE_SHIFT) | + (data[18] << HDMI_EDID_NIBBLE_SHIFT); + sinkCap->dolbyCap.maxLuminance = + (data[17] & HDMI_EDID_LOWER_NIBBLE_MARK) | (data[19] << HDMI_EDID_NIBBLE_SHIFT); + sinkCap->dolbyCap.dMajorVer = (data[20] & HDMI_EDID_UPPER_NIBBLE_MARK) >> HDMI_EDID_NIBBLE_SHIFT; + sinkCap->dolbyCap.dMinorVer = (data[20] & HDMI_EDID_LOWER_NIBBLE_MARK); + return; + } + if (sinkCap->dolbyCap.version == HDMI_EDID_VSVDB_DOLBY_VERSION_1) { + sinkCap->dolbyCap.dmVer = (data[4] & HDMI_EDID_VSVDB_DOLBY_DM_VER_MARK) >> HDMI_EDID_VSVDB_DOLBY_DM_VER_SHIFT; + sinkCap->dolbyCap.globalDimming = (data[5] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->dolbyCap.maxLuminance = ((data[5] >> 1) & HDMI_EDID_VSVDB_DOLBY_LOWER_7BIT_MARK); + sinkCap->dolbyCap.colorimetry = (data[6] & HDMI_EDID_BIT0_MARK) ? true : false; + sinkCap->dolbyCap.minLuminance = ((data[6] >> 1) & HDMI_EDID_VSVDB_DOLBY_LOWER_7BIT_MARK); + sinkCap->dolbyCap.redX = data[8]; + sinkCap->dolbyCap.redY = data[9]; + sinkCap->dolbyCap.greenX = data[10]; + sinkCap->dolbyCap.greenY = data[11]; + sinkCap->dolbyCap.blueX = data[12]; + sinkCap->dolbyCap.blueY = data[13]; + } +} + +static int32_t HdmiEdidExtUseExtDataBlockPhase(struct HdmiSinkDeviceCapability *sinkCap, uint8_t *data, uint8_t len) +{ + uint8_t extTagCode = data[0]; + + switch (extTagCode) { + case HDMI_EDID_EXT_VCDB : + HdmiEdidExtUseExtDataBlockVcdbPhase(sinkCap, data, len); + break; + case HDMI_EDID_EXT_VSVDB : + HdmiEdidExtUseExtDataBlockVsvdbPhase(sinkCap, data, len); + break; + case HDMI_EDID_EXT_CDB : + HdmiEdidExtUseExtDataBlockCdbPhase(sinkCap, data, len); + break; + case HDMI_EDID_EXT_HDR_SMDB : + HdmiEdidExtUseExtDataBlockHdrSmdbPhase(sinkCap, data, len); + break; + case HDMI_EDID_EXT_YCBCR420_VDB : + HdmiEdidExtUseExtDataBlockY420VdbPhase(sinkCap, data, len); + break; + case HDMI_EDID_EXT_YCBCR420_CMDB : + HdmiEdidExtUseExtDataBlockY420CmdbPhase(sinkCap, data, len); + break; + default : + HDF_LOGD("ext use ext DB: tag code %d unphase", extTagCode); + break; + } + return HDF_SUCCESS; +} + +static int32_t HdmiEdidExtDataBlockPhase(struct HdmiSinkDeviceCapability *sinkCap, + uint8_t *data, uint8_t len, uint8_t tag) +{ + int32_t ret = HDF_SUCCESS; + + if (len == 0) { + HDF_LOGD("ext DB: len is 0"); + return ret; + } + + switch (tag) { + case HDMI_EDID_AUDIO_DATA_BLOCK : + /* Audio Data Block (includes one or more Short Audio Descriptors) */ + ret = HdmiEdidExtAudioDataBlockPhase(sinkCap, data, len); + break; + case HDMI_EDID_VIDEO_DATA_BLOCK : + /* Video Data Block (includes one or more Short Video Descriptors) */ + ret = HdmiEdidExtVideoDataBlockPhase(sinkCap, data, len); + break; + case HDMI_EDID_VENDOR_SPECIFIC_DATA_BLOCK : + ret = HdmiEdidExtVsDataBlockPhase(sinkCap, data, len); + break; + case HDMI_EDID_SPEAKER_ALLOCATION_DATA_BLOCK : + ret = HdmiEdidExtSpeakerDataBlockPhase(sinkCap, data, len); + break; + case HDMI_EDID_USE_EXT_DATA_BLOCK : + ret = HdmiEdidExtUseExtDataBlockPhase(sinkCap, data, len); + break; + default : + HDF_LOGD("tag = %d is reserved or unphase block", tag); + break; + } + return ret; +} + +static void HdmiEdidExtSeveralDataBlockPhase(struct HdmiEdid *edid, uint8_t blockNum) +{ + uint8_t *data = edid->raw + (blockNum * HDMI_EDID_SINGLE_BLOCK_SIZE); + struct HdmiSinkDeviceCapability *sinkCap = &(edid->sinkCap); + uint8_t blkOffset = HDMI_EDID_EXTENSION_BLOCK_OFFSET; + uint8_t dtdOffset = data[2]; + uint8_t dbTagCode, blkLen; + int32_t ret; + + data += blkOffset; + /* phase data block */ + for (blkLen = 0; (blkOffset < dtdOffset) && (data != NULL); blkOffset += (blkLen + 1)) { + data += blkLen; + blkLen = (data[0] & HDMI_EDID_EXTENSION_DATA_BLOCK_LEN_MARK); + dbTagCode = (data[0] & HDMI_EDID_EXTENSION_DATA_BLOCK_TAG_CODE_MARK) >> + HDMI_EDID_EXTENSION_DATA_BLOCK_TAG_CODE_SHIFT; + data++; + ret = HdmiEdidExtDataBlockPhase(sinkCap, data, blkLen, dbTagCode); + if (ret != HDF_SUCCESS) { + HDF_LOGE("data block %d phase fail", dbTagCode); + return; + } + } + + data += blkLen; + /* phase detialed timing descriptors */ + while ((HDMI_EDID_SINGLE_BLOCK_SIZE - 1 - blkOffset) >= HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN) { + HdmiEdidDetailedTiming(sinkCap, data, HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN); + blkOffset += HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN; + data += HDMI_EDID_DETAILED_TIMING_DESCRIPTOR_FIELD_LEN; + } +} + +static int32_t HdmiEdidExtBlockPhase(struct HdmiEdid *edid, uint8_t blockNum) +{ + uint8_t *data = edid->raw; + struct HdmiSinkDeviceCapability *sinkCap = &(edid->sinkCap); + int32_t ret; + + if (blockNum >= HDMI_EDID_MAX_BLOCK_NUM) { + HDF_LOGE("blockNum %d is invalid", blockNum); + return HDF_ERR_INVALID_PARAM; + } + + data += (blockNum * HDMI_EDID_SINGLE_BLOCK_SIZE); + ret = HdmiEdidBlockCheckSum(data); + if (ret != HDF_SUCCESS) { + HDF_LOGE("edid block%d check sum fail.", blockNum); + return ret; + } + + /* byte0: Extension Tag */ + if (data[0] != HDMI_EDID_CTA_EXTENSION_TAG) { + HDF_LOGD("ext tag is %d", data[0]); + } + /* byte1: Extension Revision Number */ + if (data[1] != HDMI_EDID_CTA_EXTENSION3_REVISION) { + HDF_LOGD("revision number is %d", data[1]); + } + /* + * byte2: Byte number offset d where 18-byte descriptors begin (typically Detailed Timing Descriptors). + * If no data is provided in the reserved data block, then d is 4. If d is 0, then no detailed timing + * descriptors are provided and no data is provided in the reserved data block collection. + */ + if (data[2] < HDMI_EDID_EXTENSION_D_INVALID_MIN_VAL) { + HDF_LOGD("ext block%d no dtd", blockNum); + return HDF_SUCCESS; + } + /* byte3: indication of underscan support, audio support, support of YCBCR and total number of native DTDs. */ + sinkCap->colorSpace.rgb444 = true; + sinkCap->colorSpace.ycbcr422 = (data[3] & HDMI_EDID_BIT4_MARK) ? true : false; + sinkCap->colorSpace.ycbcr444 = (data[3] & HDMI_EDID_BIT5_MARK) ? true : false; + sinkCap->supportAudio = (data[3] & HDMI_EDID_BIT6_MARK) ? true : false; + /* + * Video Data Block, Audio Data Block, Speaker Allocation Data Block, + * Vendor Specific Data Block and Video Capability Data Block phase. + */ + HdmiEdidExtSeveralDataBlockPhase(edid, blockNum); + return HDF_SUCCESS; +} + +int32_t HdmiEdidPhase(struct HdmiEdid *edid) +{ + uint8_t blockNum; + int32_t ret; + struct HdmiSinkDeviceCapability *sinkCap = NULL; + + if (edid == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + ret = HdmiEdidFirstBlockPhase(edid); + if (ret != HDF_SUCCESS) { + HDF_LOGE("edid first block phase fail."); + return ret; + } + + sinkCap = &(edid->sinkCap); + for (blockNum = 1; blockNum < sinkCap->extBlockNum; blockNum++) { + ret = HdmiEdidExtBlockPhase(edid, blockNum); + if (ret != HDF_SUCCESS) { + HDF_LOGE("edid ext block%d phase fail.", blockNum); + return ret; + } + } + return HDF_SUCCESS; +} + +int32_t HdmiEdidRawDataRead(struct HdmiEdid *edid, struct HdmiDdc *ddc) +{ + struct HdmiDdcCfg cfg = {0}; + int32_t ret; + uint8_t extBlkNum; + + if (edid == NULL || ddc == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + /* read block0 */ + cfg.type = HDMI_DDC_DEV_EDID; + cfg.mode = HDMI_DDC_MODE_READ_MUTIL_NO_ACK; + cfg.data = edid->raw; + cfg.dataLen = HDMI_EDID_SINGLE_BLOCK_SIZE; + cfg.readFlag = true; + cfg.devAddr = HDMI_DDC_EDID_DEV_ADDRESS; + ret = HdmiDdcTransfer(ddc, &cfg); + if (ret != HDF_SUCCESS) { + HDF_LOGE("edid block0 read fail"); + return ret; + } + edid->rawLen += HDMI_EDID_SINGLE_BLOCK_SIZE; + + extBlkNum = edid->raw[HDMI_EDID_EXTENSION_BLOCK_ADDR]; + if (extBlkNum > (HDMI_EDID_MAX_BLOCK_NUM - 1)) { + extBlkNum = (HDMI_EDID_MAX_BLOCK_NUM - 1); + HDF_LOGD("extBlkNum > max, use max."); + } + if (extBlkNum == 0) { + HDF_LOGD("edid only has block0"); + return HDF_SUCCESS; + } + + /* read block1 */ + cfg.data += HDMI_EDID_SINGLE_BLOCK_SIZE; + ret = HdmiDdcTransfer(ddc, &cfg); + if (ret != HDF_SUCCESS) { + HDF_LOGE("edid block1 read fail"); + return ret; + } + edid->rawLen += HDMI_EDID_SINGLE_BLOCK_SIZE; + + if (extBlkNum == 1) { + HDF_LOGD("edid only has block0~1"); + return HDF_SUCCESS; + } + /* read block2~3 */ + cfg.data += HDMI_EDID_SINGLE_BLOCK_SIZE; + cfg.dataLen = (extBlkNum - 1) * HDMI_EDID_SINGLE_BLOCK_SIZE; + cfg.mode = HDMI_DDC_MODE_READ_SEGMENT_NO_ACK; + cfg.segment = 1; + ret = HdmiDdcTransfer(ddc, &cfg); + if (ret != HDF_SUCCESS) { + HDF_LOGE("edid block2~3 read fail"); + return ret; + } + edid->rawLen += (extBlkNum - 1) * HDMI_EDID_SINGLE_BLOCK_SIZE; + return HDF_SUCCESS; +} + +bool HdmiEdidSupportFrl(struct HdmiDevice *hdmi) +{ + if (hdmi == NULL) { + HDF_LOGD("no hdmi sink."); + return false; + } + + if (hdmi->edid.sinkCap.hfVsdbInfo.scdcPresent == true && + hdmi->edid.sinkCap.hfVsdbInfo.maxFrlRate > 0) { + return true; + } + return false; +} + +uint8_t HdmiEdidGetMaxFrlRate(struct HdmiDevice *hdmi) +{ + if (hdmi == NULL) { + HDF_LOGD("no hdmi sink."); + return 0; + } + return hdmi->edid.sinkCap.hfVsdbInfo.maxFrlRate; +} + +bool HdmiEdidScdcSupport(struct HdmiDevice *hdmi) +{ + if (hdmi == NULL) { + HDF_LOGD("no hdmi sink."); + return false; + } + return hdmi->edid.sinkCap.hfVsdbInfo.scdcPresent; +} diff --git a/support/platform/src/hdmi/hdmi_event.c b/support/platform/src/hdmi/hdmi_event.c new file mode 100644 index 00000000..19e22265 --- /dev/null +++ b/support/platform/src/hdmi/hdmi_event.c @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdf_log.h" +#include "hdmi_core.h" +#include "osal_mem.h" + +#define HDF_LOG_TAG hdmi_event_c + +static int32_t HdmiEventPostMsg(struct HdmiCntlr *cntlr, struct HdmiEventMsg *event) +{ + int32_t ret; + + if (cntlr == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + if (event == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + PlatformQueueAddMsg(cntlr->msgQueue, &event->msg); + ret = PlatformMsgWait(&event->msg); + if (event->msg.block == true) { + (void)OsalSemDestroy(&event->msg.sem); + OsalMemFree(event); + } + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiEventPostMsg: wait hdmi event msg fail!"); + return ret; + } + return HDF_SUCCESS; +} + +bool HdmiHpdStatusGet(struct HdmiCntlr *cntlr) +{ + bool ret; + + if (cntlr == NULL || cntlr->ops == NULL || cntlr->ops->hotPlugStateGet == NULL) { + return false; + } + + HdmiCntlrLock(cntlr); + ret = cntlr->ops->hotPlugStateGet(cntlr); + HdmiCntlrUnlock(cntlr); + return ret; +} + +bool HdmiHpdStatusDelayGet(struct HdmiCntlr *cntlr) +{ + uint32_t i; + + /* + * An HDMI Sink shall indicate any change to the contents of the EDID by driving a low voltage level pulse + * on the Hot Plug Detect pin. This pluse shall be at least 100 msec. + */ + for (i = 0; i < HDMI_READ_HPD_STATUS_DELAY; i++) { + if (HdmiHpdStatusGet(cntlr) == true) { + return true; + } + OsalMSleep(1); + } + return false; +} + +int32_t HdmiAddEventMsgToQueue(struct HdmiCntlr *cntlr, int32_t code, bool block, void *data) +{ + struct HdmiEventMsg *event = NULL; + + if (cntlr == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + + event = (struct HdmiEventMsg *)OsalMemCalloc(sizeof(struct HdmiEventMsg)); + if (event == NULL) { + HDF_LOGE("HdmiAddEventMsgToQueue: OsalMemCalloc fail!n"); + return HDF_ERR_MALLOC_FAIL; + } + event->msg.code = code; + event->msg.data = (void *)cntlr; + event->msg.block = block; + event->priv = data; + return HdmiEventPostMsg(cntlr, event); +} + +static int32_t HdmiEventHotPlugHandleComm(struct HdmiCntlr *cntlr) +{ + int32_t ret; + + cntlr->event.plugged = true; + if (cntlr->hdmi == NULL) { + ret = HdmiCntlrAllocDev(cntlr); + if (ret != HDF_SUCCESS) { + goto __END; + } + HDF_LOGE("HdmiEventHotPlugHandleComm HdmiCntlrAllocDev success."); + } + + /* Update EDID. */ + if (memset_s(cntlr->hdmi, sizeof(struct HdmiDevice), 0, sizeof(struct HdmiDevice)) != EOK) { + HDF_LOGE("memcpy_s fail."); + ret = HDF_ERR_IO; + goto __END; + } + ret = HdmiEdidRawDataRead(&(cntlr->hdmi->edid), &(cntlr->ddc)); + if (ret != HDF_SUCCESS) { + goto __END; + } + ret = HdmiEdidPhase(&(cntlr->hdmi->edid)); + if (ret != HDF_SUCCESS) { + goto __END; + } + +__END: + if (ret != HDF_SUCCESS) { + cntlr->event.plugged = false; + cntlr->event.hpdDetected = false; + return ret; + } + cntlr->event.hpdDetected = true; + return HDF_SUCCESS; +} + +static int32_t HdmiEventHotPlugHandle(struct HdmiCntlr *cntlr) +{ + if (HdmiHpdStatusDelayGet(cntlr) == false) { + HDF_LOGD("not detect HPD."); + return HDF_ERR_IO; + } + + if (cntlr->event.plugged == true) { + HDF_LOGD("hdp state not change"); + return HDF_SUCCESS; + } + return HdmiEventHotPlugHandleComm(cntlr); +} + +static int32_t HdmiEventHotUnplugHandle(struct HdmiCntlr *cntlr) +{ + if (cntlr->event.plugged == false) { + HDF_LOGD("plug state not change"); + return HDF_SUCCESS; + } + + HdmiCntlrClose(cntlr); + HdmiCntlrFreeDev(cntlr); + cntlr->event.plugged = false; + cntlr->event.hpdDetected = false; + return HDF_SUCCESS; +} + +static int32_t HdmiEventDetectSinkHandle(struct HdmiCntlr *cntlr) +{ + if (HdmiHpdStatusDelayGet(cntlr) == false) { + HDF_LOGD("not detect HPD."); + return HDF_SUCCESS; + } + return HdmiEventHotPlugHandleComm(cntlr); +} + +static int32_t HdmiEventCecMsgHandle(struct HdmiCntlr *cntlr, struct HdmiCecMsg *msg) +{ + if (msg == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + + return HdmiCecReceivedMsg(cntlr->cec, msg); +} + +static int32_t HdmiEventHdrZeroDrmIfTimeout(struct HdmiCntlr *cntlr) +{ + return HdmiHdrDrmInfoframeStop(cntlr->hdr); +} + +static int32_t HdmiEventSwitchToHdrModeTimeout(struct HdmiCntlr *cntlr) +{ + return HdmiHdrModeChangeTimeout(cntlr->hdr); +} + +int32_t HdmiEventMsgHandleDefault(struct PlatformQueue *queue, struct PlatformMsg *msg) +{ + int32_t ret; + struct HdmiCntlr *cntlr = NULL; + struct HdmiEventMsg *event = NULL; + + if (queue == NULL || msg == NULL) { + HDF_LOGE("HdmiEventMsgHandleDefault: msg or queue is null!"); + return HDF_ERR_INVALID_OBJECT; + } + + cntlr = (struct HdmiCntlr *)queue->data; + if (cntlr == NULL) { + HDF_LOGE("HdmiEventMsgHandleDefault: cntlr is null!"); + return HDF_ERR_INVALID_OBJECT; + } + event = (struct HdmiEventMsg *)msg; + switch (msg->code) { + case HDMI_EVENT_HOTPLUG : + ret = HdmiEventHotPlugHandle(cntlr); + break; + case HDMI_EVENT_HOTUNPLUG : + ret = HdmiEventHotUnplugHandle(cntlr); + break; + case HDMI_EVENT_DETECT_SINK : + ret = HdmiEventDetectSinkHandle(cntlr); + break; + case HDMI_EVENT_CEC_MSG: + ret = HdmiEventCecMsgHandle(cntlr, event->priv); + break; + case HDMI_EVENT_ZERO_DRMIF_TIMEOUT : + ret = HdmiEventHdrZeroDrmIfTimeout(cntlr); + break; + case HDMI_EVENT_SWITCH_TO_HDRMODE_TIMEOUT : + ret = HdmiEventSwitchToHdrModeTimeout(cntlr); + break; + default: + ret = HDF_ERR_NOT_SUPPORT; + break; + } + + if (event->msg.block == false) { + OsalMemFree(event); + } + return ret; +} + +int32_t HdmiEventHandle(struct HdmiCntlr *cntlr, enum HdmiEventType event, void *data) +{ + int32_t ret = HDF_SUCCESS; + + if (cntlr == NULL) { + HDF_LOGE("HdmiEventHandleIrq: cntlr is null!"); + return HDF_ERR_INVALID_OBJECT; + } + switch (event) { + case HDMI_EVENT_HOTPLUG : + ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_HOTPLUG, false, data); + break; + case HDMI_EVENT_HOTUNPLUG : + ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_HOTUNPLUG, false, data); + break; + case HDMI_EVENT_DETECT_SINK : + ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_DETECT_SINK, false, data); + break; + case HDMI_EVENT_CEC_MSG : + ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_CEC_MSG, false, data); + break; + case HDMI_EVENT_HDCP_MSG : + ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_HDCP_MSG, false, data); + break; + case HDMI_EVENT_ZERO_DRMIF_TIMEOUT : + ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_ZERO_DRMIF_TIMEOUT, false, data); + break; + case HDMI_EVENT_SWITCH_TO_HDRMODE_TIMEOUT : + ret = HdmiAddEventMsgToQueue(cntlr, HDMI_EVENT_SWITCH_TO_HDRMODE_TIMEOUT, false, data); + break; + default : + HDF_LOGE("event %d is not support", event); + break; + } + return ret; +} diff --git a/support/platform/src/hdmi/hdmi_frl.c b/support/platform/src/hdmi/hdmi_frl.c new file mode 100644 index 00000000..58eb823c --- /dev/null +++ b/support/platform/src/hdmi/hdmi_frl.c @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdf_log.h" +#include "hdmi_core.h" +#include "hdmi_common.h" +#include "hdmi_dfm.h" +#include "hdmi_ncts.h" + +#define HDF_LOG_TAG hdmi_frl_c + +static uint8_t HdmiFrlGetSinkVersion(struct HdmiScdc *scdc) +{ + uint8_t version = 0; + + if (HdmiScdcOptMsgHandle(scdc, HDMI_SCDC_OPT_GET_SINK_VER, &version, sizeof(version)) != HDF_SUCCESS) { + HDF_LOGD("frl get sink version fail"); + return 0; + } + return version; +} + +static bool HdmiFrlGetFltUpdate(struct HdmiScdc *scdc) +{ + bool fltUpdate = false; + uint8_t flag = 0; + + if (HdmiScdcOptMsgHandle(scdc, HDMI_SCDC_OPT_GET_FLT_UPDATE, &flag, sizeof(flag)) != HDF_SUCCESS) { + HDF_LOGD("frl get flt update fail"); + return fltUpdate; + } + + fltUpdate = (flag & HDMI_SCDC_FLT_UPDATE_MARK) ? true : false; + return fltUpdate; +} + +static bool HdmiFrlGetFrlStart(struct HdmiScdc *scdc) +{ + bool frlStart = false; + uint8_t flag = 0; + + if (HdmiScdcOptMsgHandle(scdc, HDMI_SCDC_OPT_GET_FLT_UPDATE, &flag, sizeof(flag)) != HDF_SUCCESS) { + HDF_LOGD("frl get frl start fail"); + return frlStart; + } + + frlStart = (flag & HDMI_SCDC_FRL_START_MARK) ? true : false; + return frlStart; +} + +static bool HdmiFrlGetFltReady(struct HdmiScdc *scdc) +{ + bool fltReady = false; + uint8_t flag = 0; + + if (HdmiScdcOptMsgHandle(scdc, HDMI_SCDC_OPT_GET_FLT_READY, &flag, sizeof(flag)) != HDF_SUCCESS) { + HDF_LOGD("frl get flt ready fail"); + return fltReady; + } + + fltReady = (flag & HDMI_SCDC_FLT_READY_MARK) ? true : false; + return fltReady; +} + +static uint8_t HdmiFrlGetTestConfig1(struct HdmiScdc *scdc) +{ + uint8_t cfg = 0; + + if (HdmiScdcOptMsgHandle(scdc, HDMI_SCDC_OPT_GET_TEST_CONFIG_1, &cfg, sizeof(cfg)) != HDF_SUCCESS) { + HDF_LOGD("frl get test cfg1 fail"); + return 0; + } + return cfg; +} + +static void HdmiFrlSetFltUpdate(struct HdmiScdc *scdc, bool fltUpdate) +{ + uint8_t flag = 0; + + if (HdmiScdcOptMsgHandle(scdc, HDMI_SCDC_OPT_GET_FLT_UPDATE, &flag, sizeof(flag)) != HDF_SUCCESS) { + HDF_LOGD("frl get flt update fail"); + return; + } + + if (fltUpdate == true) { + flag |= HDMI_SCDC_FLT_UPDATE_MARK; + } else { + flag &= (~HDMI_SCDC_FLT_UPDATE_MARK); + } + if (HdmiScdcOptMsgHandle(scdc, HDMI_SCDC_OPT_SET_FLT_UPDATE, &flag, sizeof(flag)) != HDF_SUCCESS) { + HDF_LOGD("frl set flt update fail"); + } +} + +static void HdmiFrlSetFrlStart(struct HdmiScdc *scdc, bool frlStart) +{ + uint8_t flag = 0; + + if (HdmiScdcOptMsgHandle(scdc, HDMI_SCDC_OPT_GET_FLT_UPDATE, &flag, sizeof(flag)) != HDF_SUCCESS) { + HDF_LOGD("frl get frl start fail"); + return; + } + + if (frlStart == true) { + flag |= HDMI_SCDC_FRL_START_MARK; + } else { + flag &= (~HDMI_SCDC_FRL_START_MARK); + } + + if (HdmiScdcOptMsgHandle(scdc, HDMI_SCDC_OPT_GET_FLT_UPDATE, &flag, sizeof(flag)) != HDF_SUCCESS) { + HDF_LOGD("frl set frl start fail"); + } +} + +static void HdmiFrlSetConfig1(struct HdmiScdc *scdc, uint8_t *data) +{ + if (HdmiScdcOptMsgHandle(scdc, HDMI_SCDC_OPT_SET_CONFIG1, data, sizeof(*data)) != HDF_SUCCESS) { + HDF_LOGD("frl set cfg1 fail"); + } +} + +static void HdmiFrlSetTrainRate(struct HdmiFrl *frl) +{ + union HdmiScdcsConfig1 cfg = {0}; + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + + if (cntlr == NULL) { + HDF_LOGE("frl set train rate fail"); + return; + } + + if (frl->info.mode == HDMI_FRL_MODE_FRL) { + cfg.bits.frlRate = frl->info.curFrlRate; + cfg.bits.ffeLevels = HDMI_FRL_TXFFE_MODE_0; + } + HdmiFrlSetConfig1(cntlr->scdc, &(cfg.data)); +} + +static bool HdmiFrlCheckFrlCapability(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + uint8_t sinkScdcVerion; + uint8_t sinkMaxFrlRate; + + sinkScdcVerion = HdmiFrlGetSinkVersion(cntlr->scdc); + if (HdmiEdidSupportFrl(cntlr->hdmi) != true || + cntlr->cap.baseCap.bits.hdmi21 == 0 || + cntlr->cap.baseCap.bits.frl == 0 || + sinkScdcVerion == 0) { + frl->info.maxFrlRate = 0; + return HDF_ERR_NOT_SUPPORT; + } + sinkMaxFrlRate = HdmiEdidGetMaxFrlRate(cntlr->hdmi); + frl->info.maxFrlRate = (sinkMaxFrlRate > cntlr->cap.maxFrlRate) ? cntlr->cap.maxFrlRate : sinkMaxFrlRate; + return HDF_SUCCESS; +} + +static bool HdmiFrlCheckFrlStrategy(enum HdmiFrlStrategyMode strategy, uint32_t pixelClock, + uint32_t tmdsClock, enum HdmiVideoFormatType formatType) +{ + bool support = true; + + switch (strategy) { + case HDMI_FRL_STRATEGY_MODE_1 : + if (pixelClock <= HDMI_HDMI20_MAX_TMDS_RATE && tmdsClock <= HDMI_HDMI20_MAX_TMDS_RATE) { + support = false; + } + break; + case HDMI_FRL_STRATEGY_MODE_2 : + if (tmdsClock <= HDMI_HDMI14_MAX_TMDS_RATE) { + support = false; + } + break; + case HDMI_FRL_STRATEGY_MODE_3 : + if (formatType == HDMI_VIDEO_FORMA_INTERLACE) { + support = false; + } + break; + default : + HDF_LOGE("strategy %d is not support", strategy); + break; + } + return support; +} + +static void HdmiFrlFillRateInfo(uint32_t *frlBitRate, uint32_t *frlLaneNum, uint32_t frlRate) +{ + *frlLaneNum = HDMI_FRL_4_LANES; + if (frlRate <= HDMI_FRL_WORK_MODE_3L6G) { + *frlLaneNum = HDMI_FRL_3_LANES; + } + + switch (frlRate) { + case HDMI_FRL_WORK_MODE_3L3G : + *frlBitRate = HDMI_FRL_BIT_RATE_3; + break; + case HDMI_FRL_WORK_MODE_3L6G : + case HDMI_FRL_WORK_MODE_4L6G : + *frlBitRate = HDMI_FRL_BIT_RATE_6; + break; + case HDMI_FRL_WORK_MODE_4L8G : + *frlBitRate = HDMI_FRL_BIT_RATE_8; + break; + case HDMI_FRL_WORK_MODE_4L10G : + *frlBitRate = HDMI_FRL_BIT_RATE_10; + break; + case HDMI_FRL_WORK_MODE_4L12G : + *frlBitRate = HDMI_FRL_BIT_RATE_12; + break; + default : + break; + } +} + +static bool HdnmiFrlCheckFrlMode(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + struct HdmiVideoDefInfo *videoInfo = NULL; + struct HdmiDfmParam param = {0}; + bool enable3d; + uint32_t i; + + enable3d = (cntlr->attr.videoAttr._3dStruct >= HDMI_VS_VIDEO_3D_BUTT) ? false : true; + videoInfo = HdmiCommonGetVideoDefInfo(cntlr->attr.videoAttr.timing, cntlr->attr.videoAttr.aspect, enable3d); + if (videoInfo == NULL) { + HDF_LOGD("have no this video param, use tmds to transmit."); + return false; + } + HDF_LOGD("use frl to transmit, vic is %d.", videoInfo->vic); + + frl->info.tmdsClock = cntlr->attr.videoAttr.tmdsClock; + if (HdmiFrlCheckFrlStrategy(frl->info.strategy, cntlr->attr.videoAttr.pixelClock, + frl->info.tmdsClock, videoInfo->formatType) == false) { + return false; + } + + if (frl->info.maxFrlRate > HDMI_FRL_WORK_MODE_4L12G) { + HDF_LOGD("max frl rate is wrong(%u)", frl->info.maxFrlRate); + frl->info.maxFrlRate = HDMI_FRL_WORK_MODE_4L12G; + return true; + } + + /* Check whether a particular video format can be transmitted in a particular FRL configuration. */ + HdmiDfmFillParam(¶m, videoInfo, &(cntlr->attr.audioAttr), cntlr->attr.commAttr.colorSpace, + cntlr->attr.commAttr.deepColor); + for (i = frl->info.maxFrlRate; i > 0; i--) { + HdmiFrlFillRateInfo(&(param.bitRate), &(param.laneNum), i); + if (HdmiDfmFormatSupport(¶m) == true) { + frl->info.minFrlRate = i; + HDF_LOGD("min_rate: %d", i); + } else { + break; + } + } + if (i == frl->info.maxFrlRate) { + return false; + } + return true; +} + +static bool HdmiFrlIsCtsMode(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + union HdmiScdcsTestConfig1 cfg = {0}; + + cfg.data = HdmiFrlGetTestConfig1(cntlr->scdc); + if ((cfg.bits.frlMax > 0 && cfg.bits.dscFrlMax == 0) || + (cfg.bits.frlMax == 0 && cfg.bits.dscFrlMax > 0)) { + return true; + } + return false; +} + +static int32_t HdmiFrlGetCurRate(struct HdmiFrl *frl) +{ + uint8_t curFrlrate = frl->info.curFrlRate; + + if (frl->info.ctsMode == true) { + frl->info.preFrlRate = curFrlrate; + curFrlrate = frl->info.maxFrlRate; + } else { + if (frl->info.preFrlRate != 0) { + curFrlrate = frl->info.preFrlRate; + frl->info.preFrlRate = 0; + } else { + if (frl->info.rateSelect == HDMI_FRL_RATE_BIG) { + curFrlrate--; + } else { + curFrlrate++; + } + } + } + + if ((curFrlrate > frl->info.maxFrlRate) || + (curFrlrate < frl->info.minFrlRate)) { + return HDF_FAILURE; + } + frl->info.curFrlRate = curFrlrate; + return HDF_SUCCESS; +} + +static void HdmiFrlAudioNctsSet(struct HdmiFrl *frl) +{ + struct HdmiFrlAudioNctsConfig cfg = {0}; + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + + if (cntlr == NULL || cntlr->ops == NULL || cntlr->ops->audioNctsSet == NULL) { + HDF_LOGD("not support set frl audio ncts."); + return; + } + + cfg.mode = frl->info.mode; + cfg.sampleRate = cntlr->attr.audioAttr.sampleRate; + if (cfg.mode == HDMI_FRL_MODE_FRL) { + cfg.frlRate = frl->info.curFrlRate; + } else { + cfg.pixelClk = cntlr->attr.videoAttr.pixelClock; + cfg.n = HdmiGetN(cfg.sampleRate, cfg.pixelClk); + cfg.cts = HdmiGetCts(cfg.sampleRate, cfg.pixelClk); + } + HdmiCntlrLock(cntlr); + cntlr->ops->audioNctsSet(cntlr, &cfg); + HdmiCntlrUnlock(cntlr); +} + +static void HdmiFrlTxffeSet(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + struct HdmiPhyCfg cfg = {0}; + + if (cntlr == NULL || cntlr->ops == NULL || cntlr->ops->phyOutputSet == NULL) { + HDF_LOGD("not support phy output set."); + return; + } + + cfg.modeCfg = HDMI_PHY_MODE_TXFFE; + cfg.rate = (enum HdmiFrlWorkMode)frl->info.curFrlRate; + HdmiCntlrLock(cntlr); + cntlr->ops->phyOutputSet(cntlr, &cfg); + HdmiCntlrUnlock(cntlr); +} + +static void HdmiFrlphyConfigSet(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + struct HdmiPhyCfg cfg = {0}; + + if (cntlr == NULL || cntlr->ops == NULL) { + return; + } + + cfg.tmdsClk = cntlr->attr.videoAttr.tmdsClock; + cfg.pixelClk = cntlr->attr.videoAttr.pixelClock; + cfg.deepColor = cntlr->attr.videoAttr.deepColor; + cfg.colorSpace = cntlr->attr.commAttr.colorSpace; + if (frl->info.mode == HDMI_FRL_MODE_FRL) { + cfg.modeCfg = HDMI_PHY_MODE_FRL; + cfg.rate = (enum HdmiFrlWorkMode)frl->info.curFrlRate; + } + + if (cntlr->ops->phyOutputEnable != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->phyOutputEnable(cntlr, false); + HdmiCntlrUnlock(cntlr); + } + if (cntlr->ops->phyOutputSet != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->phyOutputSet(cntlr, &cfg); + HdmiCntlrUnlock(cntlr); + } + if (cntlr->ops->phyOutputEnable != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->phyOutputEnable(cntlr, true); + HdmiCntlrUnlock(cntlr); + } +} + +static void HdmiFrlStateMachineChangeState(struct HdmiFrl *frl, enum HdmiFrlTrainStep state) +{ + /* change state machine's state */ + frl->info.machineInfo.trainingState = state; + /* restart timer */ + frl->info.machineInfo.startTime = OsalGetSysTimeMs(); +} + +static void HdmiFrlTrainingReadyCheck(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + + if (HdmiFrlGetFltReady(cntlr->scdc) == true) { + HDF_LOGD("step, ready chack pass, start training."); + HdmiFrlphyConfigSet(frl); + HdmiFrlSetTrainRate(frl); + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_TRAIN_START); + } +} + +static void HdmiFrlConfigAndStartTraining(struct HdmiFrl *frl) +{ + struct HdmiFrlTrainConfig cfg = {0}; + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + union HdmiScdcsTestConfig1 testCfg = {0}; + + if (cntlr == NULL || cntlr->ops == NULL) { + return; + } + + cfg.frlRate = frl->info.curFrlRate; + cfg.txffe = HDMI_FRL_TXFFE_MODE_0; + testCfg.data = HdmiFrlGetTestConfig1(cntlr->scdc); + if (testCfg.bits.fltNoTimeout > 0) { + cfg.frlNoTimeout = true; + } + cfg.trainTimeout = frl->info.machineInfo.trainTimeout; + + if (cntlr->ops->frlTrainingConfigSet != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->frlTrainingConfigSet(cntlr, &cfg); + HdmiCntlrUnlock(cntlr); + } + if (cntlr->ops->frlEnable != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->frlEnable(cntlr, false); + HdmiCntlrUnlock(cntlr); + } + if (cntlr->ops->frlTrainingStart != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->frlTrainingStart(cntlr); + HdmiCntlrUnlock(cntlr); + } + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_RESULT_CHECK); + return; +} + +static void HdmiFrlTrainingResultCheck(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + struct HdmiFrlTrainRslt rslt = {0}; + + if (cntlr != NULL && cntlr->ops != NULL && cntlr->ops->frlGetTriningRslt != NULL) { + cntlr->ops->frlGetTriningRslt(cntlr, &rslt); + } + + if (rslt.status == HDMI_FRL_TRAIN_STATUS_SUCC) { + frl->info.trainingFailCnt = 0; + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_RESULT_HANDLE); + } else if (rslt.failReason == HDMI_FRL_TRAIN_FAIL_FFE_CHANGE) { + frl->info.trainingFailCnt = 0; + HdmiFrlTxffeSet(frl); + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_TRAIN_START); + } else if (rslt.failReason == HDMI_FRL_TRAIN_FAIL_RATE_CHANGE) { + frl->info.trainingFailCnt = 0; + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_RATE_CHANGE); + } else { + (frl->info.trainingFailCnt)++; + } +} + +static void HdmiFrlTrainingException(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + struct HdmiPhyCfg cfg = {0}; + + if (cntlr != NULL || cntlr->ops != NULL) { + return; + } + + if (cntlr->ops->phyOutputEnable != NULL) { + cntlr->ops->phyOutputEnable(cntlr, false); + } + + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_TRAIN_STOP); + frl->info.start = false; + /* TMDS config. */ + cfg.pixelClk = cntlr->attr.videoAttr.pixelClock; + cfg.tmdsClk = cntlr->attr.videoAttr.tmdsClock; + cfg.deepColor = cntlr->attr.videoAttr.deepColor; + cfg.modeCfg = HDMI_PHY_MODE_TMDS; + cfg.colorSpace = cntlr->attr.commAttr.colorSpace; + HDF_LOGD("FRL change to TMDS."); + if (cfg.tmdsClk > HDMI_HDMI20_MAX_TMDS_RATE) { + HDF_LOGE("TMDS clk > 600M. can't work TMDS mode."); + return; + } + frl->info.mode = HDMI_FRL_MODE_TMDS; + HdmiFrlSetTrainRate(frl); + HdmiFrlAudioNctsSet(frl); + + if (cntlr->ops->phyOutputSet != NULL) { + cntlr->ops->phyOutputSet(cntlr, &cfg); + } + if (cntlr->ops->phyOutputEnable != NULL) { + cntlr->ops->phyOutputEnable(cntlr, true); + } +} + +static void HdmiFrlTrainingRateChange(struct HdmiFrl *frl) +{ + frl->info.ctsMode = HdmiFrlIsCtsMode(frl); + if (HdmiFrlGetCurRate(frl) != HDF_SUCCESS) { + HDF_LOGE("FRL rate %u get failed!\n", frl->info.curFrlRate); + HdmiFrlTrainingException(frl); + return; + } + /* FRL rate change */ + HdmiFrlphyConfigSet(frl); + HdmiFrlSetTrainRate(frl); + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_TRAIN_START); +} + +static void HdmiFrlTrainingPassedCheck(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + + if (cntlr != NULL || cntlr->ops != NULL) { + return; + } + + if (frl->info.start == false || + HdmiFrlGetFrlStart(cntlr->scdc) == false) { + return; + } + + HDF_LOGD("FRL training passed."); + frl->info.work = true; + /* n/cts config */ + HdmiFrlAudioNctsSet(frl); + OsalMSleep(1); + if (cntlr->ops->phyOutputEnable != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->phyOutputEnable(cntlr, frl->info.work); + HdmiCntlrUnlock(cntlr); + } + OsalMSleep(1); + HdmiFrlSetFrlStart(cntlr->scdc, true); + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_RETRAIN_CHECK); +} + +static void HdmiFrlRetrainingCheck(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + + if (cntlr != NULL || cntlr->ops != NULL) { + return; + } + if (HdmiFrlGetFltUpdate(cntlr->scdc) == false) { + return; + } + + HDF_LOGD("FRL retraining flt_update get OK"); + HdmiFrlSetFltUpdate(cntlr->scdc, true); + frl->info.work = false; + if (cntlr->ops->phyOutputEnable != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->phyOutputEnable(cntlr, frl->info.work); + HdmiCntlrUnlock(cntlr); + } + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_TRAIN_START); +} + +static void HdmiFrlTrainingStop(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + + if (cntlr != NULL || cntlr->ops != NULL) { + return; + } + + frl->info.work = false; + if (cntlr->ops->phyOutputEnable != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->phyOutputEnable(cntlr, frl->info.work); + HdmiCntlrUnlock(cntlr); + } + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_BUTT); +} + +void HdmiFrlTrainingStateMachineHandle(struct HdmiFrl *frl) +{ + if (frl == NULL) { + HDF_LOGE("FRL trining, not support FRL."); + return; + } + + switch (frl->info.machineInfo.trainingState) { + case HDMI_FRL_TRAIN_STEP_READR_CHECK : + HdmiFrlTrainingReadyCheck(frl); + break; + case HDMI_FRL_TRAIN_STEP_TRAIN_START : + HdmiFrlConfigAndStartTraining(frl); + break; + case HDMI_FRL_TRAIN_STEP_RESULT_CHECK : + HdmiFrlTrainingResultCheck(frl); + break; + case HDMI_FRL_TRAIN_STEP_RATE_CHANGE : + HdmiFrlTrainingRateChange(frl); + break; + case HDMI_FRL_TRAIN_STEP_RESULT_HANDLE : + HdmiFrlTrainingPassedCheck(frl); + break; + case HDMI_FRL_TRAIN_STEP_RETRAIN_CHECK : + HdmiFrlRetrainingCheck(frl); + break; + case HDMI_FRL_TRAIN_STEP_TRAIN_STOP : + HdmiFrlTrainingStop(frl); + break; + default : + break; + } +} + +static void HdmiFrlTrainingReadyCheckTimeout(struct HdmiFrl *frl) +{ + uint64_t curTime = OsalGetSysTimeMs(); + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + + if ((curTime - frl->info.machineInfo.startTime) > frl->info.machineInfo.waitReadyTime) { + if (HdmiFrlGetFltReady(cntlr->scdc) == true) { + HDF_LOGD("step, ready chack pass, start training."); + frl->info.machineInfo.timeoutCnt = 0; + HdmiFrlphyConfigSet(frl); + HdmiFrlSetTrainRate(frl); + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_TRAIN_START); + } else { + (frl->info.machineInfo.timeoutCnt)++; + /* */ + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_READR_CHECK); + } + } else { + /* wait for a maximum of 10 times, (wait_ready_ms * 10) ms */ + if (frl->info.machineInfo.timeoutCnt < 10) { + return; + } + HDF_LOGD("FRL training READY_CHECK exception."); + frl->info.machineInfo.timeoutCnt = 0; + HdmiFrlTrainingException(frl); + } +} + +static void HdmiFrlTrainingResultCheckTimeout(struct HdmiFrl *frl) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + struct HdmiFrlTrainRslt rslt = {0}; + + if (cntlr != NULL && cntlr->ops != NULL && cntlr->ops->frlGetTriningRslt != NULL) { + cntlr->ops->frlGetTriningRslt(cntlr, &rslt); + } + + if (rslt.status == HDMI_FRL_TRAIN_STATUS_SUCC) { + frl->info.trainingFailCnt = 0; + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_RESULT_HANDLE); + } else if (rslt.failReason == HDMI_FRL_TRAIN_FAIL_FFE_CHANGE) { + frl->info.trainingFailCnt = 0; + HdmiFrlTxffeSet(frl); + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_TRAIN_START); + } else if (rslt.failReason == HDMI_FRL_TRAIN_FAIL_RATE_CHANGE) { + frl->info.trainingFailCnt = 0; + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_RATE_CHANGE); + } else { + (frl->info.trainingFailCnt)++; + if (frl->info.trainingFailCnt > frl->info.trainingMaxFailTimes) { + frl->info.trainingFailCnt = 0; + HdmiFrlTrainingException(frl); + } else { + /* not reach max fail times, re-training. */ + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_TRAIN_START); + } + } +} + +static void HdmiFrlTrainingResultHandleTimeout(struct HdmiFrl *frl) +{ + uint64_t curTime; + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + + if (cntlr != NULL || cntlr->ops != NULL) { + return; + } + + do { + if (HdmiFrlGetFrlStart(cntlr->scdc) == true) { + if (frl->info.start == true) { + frl->info.work = true; + /* n/cts config */ + HdmiFrlAudioNctsSet(frl); + if (cntlr->ops->phyOutputEnable != NULL) { + cntlr->ops->phyOutputEnable(cntlr, frl->info.work); + } + HdmiFrlSetFrlStart(cntlr->scdc, true); + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_RETRAIN_CHECK); + break; + } + } else if (HdmiFrlGetFltUpdate(cntlr->scdc) == true) { + HdmiFrlSetFltUpdate(cntlr->scdc, true); + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_TRAIN_START); + break; + } + + curTime = OsalGetSysTimeMs(); + if ((curTime - frl->info.machineInfo.startTime) > frl->info.machineInfo.waitHandleTime) { + (frl->info.machineInfo.timeoutCnt)++; + break; + } + /* check the sink's status every 2ms required by protocol */ + OsalUDelay(2000); + } while (true); + + if (frl->info.machineInfo.timeoutCnt >= 3) { + HDF_LOGE("FRL training timeout."); + frl->info.machineInfo.timeoutCnt = 0; + HdmiFrlTrainingException(frl); + } +} + +static void HdmiFrlRetrainingCheckTimeout(struct HdmiFrl *frl) +{ + uint64_t curTime = OsalGetSysTimeMs(); + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)frl->priv; + + if (cntlr != NULL || cntlr->ops != NULL) { + return; + } + if ((curTime - frl->info.machineInfo.startTime) <= frl->info.machineInfo.waitRetrainTime) { + return; + } + if (HdmiFrlGetFltUpdate(cntlr->scdc) != true) { + return; + } + + HdmiFrlSetFltUpdate(cntlr->scdc, true); + frl->info.work = true; + if (cntlr->ops->phyOutputEnable != NULL) { + cntlr->ops->phyOutputEnable(cntlr, frl->info.work); + } + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_TRAIN_START); +} + +void HdmiFrlTrainingStateMachineTimeoutHandle(struct HdmiFrl *frl) +{ + if (frl == NULL || frl->priv == NULL) { + HDF_LOGE("FRL trining, not support FRL."); + return; + } + + switch (frl->info.machineInfo.trainingState) { + case HDMI_FRL_TRAIN_STEP_READR_CHECK : + HdmiFrlTrainingReadyCheckTimeout(frl); + break; + case HDMI_FRL_TRAIN_STEP_TRAIN_START : + HdmiFrlConfigAndStartTraining(frl); + break; + case HDMI_FRL_TRAIN_STEP_RESULT_CHECK : + HdmiFrlTrainingResultCheckTimeout(frl); + break; + case HDMI_FRL_TRAIN_STEP_RATE_CHANGE : + HdmiFrlTrainingRateChange(frl); + break; + case HDMI_FRL_TRAIN_STEP_RESULT_HANDLE : + HdmiFrlTrainingResultHandleTimeout(frl); + break; + case HDMI_FRL_TRAIN_STEP_RETRAIN_CHECK : + HdmiFrlRetrainingCheckTimeout(frl); + break; + case HDMI_FRL_TRAIN_STEP_TRAIN_STOP : + HdmiFrlTrainingStop(frl); + break; + default : + break; + } +} + +void HdmiFrlEnable(struct HdmiFrl *frl, bool enable) +{ + if (frl == NULL || frl->priv == NULL) { + return; + } + + frl->info.start = enable; + frl->info.machineInfo.start = enable; + frl->info.machineInfo.machineState = (enable == true) ? HDMI_FRL_STATE_MACHINE_START : HDMI_FRL_STATE_MACHINE_STOP; + frl->info.ctsMode = HdmiFrlIsCtsMode(frl); + if (frl->info.ctsMode == true) { + HdmiFrlGetCurRate(frl); + HDF_LOGD("frl cur rate %d", frl->info.curFrlRate); + } + HdmiFrlStateMachineChangeState(frl, HDMI_FRL_TRAIN_STEP_READR_CHECK); +} + +int32_t HdmiFrlModeSelect(struct HdmiFrl *frl) +{ + int32_t ret; + struct HdmiCntlr *cntlr = NULL; + struct HdmiVideoAttr *videoAttr = NULL; + + if (frl == NULL || frl->priv == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + ret = HdmiFrlCheckFrlCapability(frl); + if (ret == HDF_FAILURE) { + return ret; + } else if (ret != HDF_SUCCESS) { + HDF_LOGD("frl check capability fail, change to TMDS."); + frl->info.mode = HDMI_FRL_MODE_TMDS; + } else { + if (HdnmiFrlCheckFrlMode(frl) == true) { + HDF_LOGD("frl check frl mode succ."); + frl->info.mode = HDMI_FRL_MODE_FRL; + } else { + HDF_LOGD("frl check frl mode fail, change to TMDS."); + frl->info.mode = HDMI_FRL_MODE_TMDS; + } + } + + cntlr = (struct HdmiCntlr *)frl->priv; + videoAttr = &(cntlr->attr.videoAttr); + if (frl->info.mode == HDMI_FRL_MODE_TMDS) { + if (videoAttr->tmdsClock > HDMI_HDMI20_MAX_TMDS_RATE) { + HDF_LOGE("FRL mode select, tmds Clock exceed max."); + return HDF_FAILURE; + } + if (HdmiEdidScdcSupport(cntlr->hdmi) == true) { + HdmiFrlSetTrainRate(frl); + } + return HDF_SUCCESS; + } + + /* FRL mode. */ + frl->info.curFrlRate = (frl->info.rateSelect == HDMI_FRL_RATE_BIG) ? + frl->info.maxFrlRate : frl->info.minFrlRate; + cntlr->tmdsMode = HDMI_TMDS_MODE_HDMI_2_0; + if (cntlr->ops != NULL && cntlr->ops->tmdsModeSet != NULL) { + HdmiCntlrLock(cntlr); + cntlr->ops->tmdsModeSet(cntlr, cntlr->tmdsMode); + HdmiCntlrUnlock(cntlr); + } + frl->info.ctsMode = false; + return HDF_SUCCESS; +} + +bool HdmiFrlModeChanged(struct HdmiFrl *frl) +{ + if (frl == NULL) { + return false; + } + + if (frl->info.perMode != frl->info.mode) { + frl->info.perMode = frl->info.mode; + return true; + } + return false; +} + +bool HdmiFrlSupport(struct HdmiFrl *frl) +{ + if (frl == NULL) { + return false; + } + + if (frl->info.mode == HDMI_FRL_MODE_FRL) { + return true; + } + return false; +} diff --git a/support/platform/src/hdmi/hdmi_hdcp.c b/support/platform/src/hdmi/hdmi_hdcp.c new file mode 100644 index 00000000..b642d47d --- /dev/null +++ b/support/platform/src/hdmi/hdmi_hdcp.c @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdf_log.h" +#include "hdmi_core.h" + +#define HDF_LOG_TAG hdmi_hdcp_c + +static int32_t HdmiHdcpRead(struct HdmiHdcp *hdcp, enum HdmiHdcpPortOffset offset, uint8_t *buffer, uint32_t len) +{ + struct HdmiDdcCfg cfg = {0}; + struct HdmiCntlr *cntlr = NULL; + + if (hdcp == NULL || hdcp->priv == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + cntlr = (struct HdmiCntlr *)hdcp->priv; + cfg.type = HDMI_DDC_DEV_HDCP; + cfg.readFlag = true; + cfg.devAddr = HDMI_DDC_HDCP_DEV_ADDRESS; + cfg.data = buffer; + cfg.dataLen = len; + cfg.offset = offset; + cfg.mode = HDMI_DDC_MODE_READ_MUTIL_NO_ACK; + return HdmiDdcTransfer(&(cntlr->ddc), &cfg); +} + +static int32_t HdmiHdcpWrite(struct HdmiHdcp *hdcp, enum HdmiHdcpPortOffset offset, uint8_t *buffer, uint32_t len) +{ + struct HdmiDdcCfg cfg = {0}; + struct HdmiCntlr *cntlr = NULL; + + if (hdcp == NULL || hdcp->priv == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + cntlr = (struct HdmiCntlr *)hdcp->priv; + cfg.type = HDMI_DDC_DEV_HDCP; + cfg.readFlag = false; + cfg.devAddr = HDMI_DDC_HDCP_DEV_ADDRESS; + cfg.data = buffer; + cfg.dataLen = len; + cfg.offset = offset; + cfg.mode = HDMI_DDC_MODE_WRITE_MUTIL_ACK; + return HdmiDdcTransfer(&(cntlr->ddc), &cfg); +} + +static bool HdmiHdcpCheckKvs(uint8_t *ksv, uint32_t len) +{ + uint32_t i, j; + uint32_t cnt = 0; + + for (i = 0; i < len; i++) { + for (j = 0; j < HDMI_ONE_BYTE_SHIFT; j++) { + if (((ksv[i] >> j) & 0x01) > 0) { + cnt++; + } + } + } + /* KSV contains 20 ones and 20 zeros. */ + if (cnt != HDMI_HDCP_AKSV_ONE_NUM) { + HDF_LOGE("HdmiHdcpCheckKvs: cnt = %d.", cnt); + return false; + } + return true; +} + +static int32_t HdmiHdcpWriteMsgToReg(struct HdmiHdcp *hdcp, enum HdmiHdcpRegOptType type, uint8_t *data, uint32_t len) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)hdcp->priv; + + if (cntlr->ops == NULL || cntlr->ops->hdcpOptReg == NULL) { + HDF_LOGD("not support hdcp write reg."); + return HDF_ERR_INVALID_PARAM; + } + return cntlr->ops->hdcpOptReg(cntlr, type, data, len); +} + +static int32_t HdmiHdcpReadMsgBksv(struct HdmiHdcp *hdcp) +{ + int32_t ret; + + ret = HdmiHdcpRead(hdcp, HDMI_HDCP_BKSV, hdcp->bksv, sizeof(hdcp->bksv)); + if (ret != HDF_SUCCESS) { + return ret; + } + if (HdmiHdcpCheckKvs(hdcp->bksv, sizeof(hdcp->bksv)) == false) { + HDF_LOGE("auth part I: bksv check fail."); + return HDF_ERR_INVALID_PARAM; + } + return HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_WRITE_BKSV, hdcp->bksv, sizeof(hdcp->bksv)); +} + +static int32_t HdmiHdcpReadMsgRi(struct HdmiHdcp *hdcp) +{ + int32_t ret; + ret = HdmiHdcpRead(hdcp, HDMI_HDCP_RI, hdcp->ri, sizeof(hdcp->ri)); + if (ret != HDF_SUCCESS) { + return ret; + } + return HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_WRITE_RI, hdcp->ri, sizeof(hdcp->ri)); +} + +static int32_t HdmiHdcpWriteMsgAksv(struct HdmiHdcp *hdcp) +{ + if (HdmiHdcpCheckKvs(hdcp->aksv, sizeof(hdcp->aksv)) == false) { + HDF_LOGE("auth part I: aksv check fail."); + return HDF_ERR_INVALID_PARAM; + } + return HdmiHdcpWrite(hdcp, HDMI_HDCP_AN, hdcp->aksv, sizeof(hdcp->aksv)); +} + +static int32_t HdmiHdcpWriteMsgAn(struct HdmiHdcp *hdcp) +{ + return HdmiHdcpWrite(hdcp, HDMI_HDCP_AN, hdcp->an, sizeof(hdcp->an)); +} + +static int32_t HdmiHdcpReadMsgHv(struct HdmiHdcp *hdcp) +{ + uint8_t offset, i; + uint8_t vhNum = HDMI_HDCP_MSG_ALL_VH_LEN / HDMI_HDCP_MSG_PER_VH_LEN; + int32_t ret; + + if (hdcp == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + for (i = 0; i < vhNum; i++) { + offset = HDMI_HDCP_V_H0 + i * HDMI_HDCP_MSG_PER_VH_LEN; + ret = HdmiHdcpRead(hdcp, offset, &(hdcp->vh[i]), HDMI_HDCP_MSG_PER_VH_LEN); + if (ret != HDF_SUCCESS) { + return ret; + } + } + return HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_WRITE_V_H_ALL, hdcp->vh, sizeof(hdcp->vh)); +} + +static int32_t HdmiHdcpReadMsgBcaps(struct HdmiHdcp *hdcp) +{ + int32_t ret; + ret = HdmiHdcpRead(hdcp, HDMI_HDCP_BCAPS, &(hdcp->bcaps), sizeof(hdcp->bcaps)); + if (ret != HDF_SUCCESS) { + return ret; + } + return HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_WRITE_BCAPS, &(hdcp->bcaps), sizeof(hdcp->bcaps)); +} + +static int32_t HdmiHdcpAuthenticationGenerateAksvAn(struct HdmiHdcp *hdcp) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)hdcp->priv; + + if (cntlr->ops == NULL || cntlr->ops->hdcpGenerateAksvAndAn == NULL) { + return HDF_ERR_NOT_SUPPORT; + } + return cntlr->ops->hdcpGenerateAksvAndAn(cntlr); +} + +static void HdmiHdcpRegPrepare(struct HdmiHdcp *hdcp) +{ + struct HdmiCntlr *cntlr = (struct HdmiCntlr *)hdcp->priv; + + if (cntlr->ops == NULL || cntlr->ops->hdcpRegInit == NULL) { + return; + } + cntlr->ops->hdcpRegInit(cntlr); +} + +static int32_t HdmiHdcpAuthenticationPrepare(struct HdmiHdcp *hdcp) +{ + int32_t ret; + + HdmiHdcpRegPrepare(hdcp); + if (hdcp->aksvValid == false) { + ret = HdmiHdcpAuthenticationGenerateAksvAn(hdcp); + if (ret != HDF_SUCCESS) { + hdcp->state = HDMI_HDCP_AUTH_AKSV_INVALID; + return ret; + } + } + hdcp->aksvValid = true; + return HDF_SUCCESS; +} + +static int32_t HdmiHdcpAuthenticationFirstPart(struct HdmiHdcp *hdcp) +{ + int32_t ret; + + hdcp->state = HDMI_HDCP_AUTH_DOING; + /* + * Authentication is initiated by the HDCP Transmitter by sendind an initiation massage containing its KSV(aksv) + * and a 64-bit pseudo-random value(An) generated by the HDCP Cipher function hdcpRngCipher to the HDCP Reciever. + */ + ret = HdmiHdcpWriteMsgAksv(hdcp); + if (ret != HDF_SUCCESS) { + return ret; + } + ret = HdmiHdcpWriteMsgAn(hdcp); + if (ret != HDF_SUCCESS) { + return ret; + } + + /* + * The HDCP Reciever responds by sending a response message containing the receiver's KSV(bksv) and + * the REPEATER bit, which indicates if the reciever is an HDCP Repeater. + */ + ret = HdmiHdcpReadMsgBksv(hdcp); + if (ret != HDF_SUCCESS) { + return ret; + } + ret = HdmiHdcpReadMsgBcaps(hdcp); + if (ret != HDF_SUCCESS) { + return ret; + } + + /* + * The HDCP Transmitter must not read the R0' value sooner than 100ms after writing Aksv. + */ + OsalMSleep(120); + /* Read R0' */ + ret = HdmiHdcpReadMsgRi(hdcp); + if (ret != HDF_SUCCESS) { + return ret; + } + + /* Verify R0/R0' matched or not */ + ret = HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_CHECK_R, NULL, 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("hdcp auth, check V fail."); + return ret; + } + return HDF_SUCCESS; +} + +static int32_t HdmiHdcpAuthenticationCheckBstatus(struct HdmiHdcp *hdcp) +{ + int32_t ret; + uint16_t bstatus; + bool maxDevExceeded, maxCascadeExceeded; + + ret = HdmiHdcpRead(hdcp, HDMI_HDCP_BSTATUS, hdcp->bstatus, sizeof(hdcp->bstatus)); + if (ret != HDF_SUCCESS) { + return ret; + } + + /* phase bstatus. */ + bstatus = (hdcp->bstatus[1] << 8) | hdcp->bstatus[0]; + hdcp->deviceCount = bstatus & HDMI_HDCP_BSTATUS_DEVICE_COUNT_MARK; + maxDevExceeded = (bstatus & HDMI_HDCP_BSTATUS_MAX_DEVS_EXCEEDED_MARK) ? true : false; + maxCascadeExceeded = (bstatus & HDMI_HDCP_BSTATUS_MAX_CASCADE_EXCEEDED_MARK) ? true : false; + if (hdcp->deviceCount == 0) { + HDF_LOGE("hdcp auth, check bstatus, no device attached to the repeater."); + return HDF_DEV_ERR_NO_DEVICE; + } + if (maxDevExceeded == true) { + HDF_LOGE("hdcp auth, check bstatus, exceeds max allowed connected devices."); + return HDF_ERR_IO; + } + if (maxCascadeExceeded == true) { + HDF_LOGE("hdcp auth, check bstatus, exceeds max allowed cascade."); + return HDF_ERR_IO; + } + return HDF_SUCCESS; +} + +static int32_t HdmiHdcpAuthenticationWaitKsvListReady(struct HdmiHdcp *hdcp) +{ + uint32_t i; + int32_t ret; + bool ready = false; + + /* Set up 5s timer, poll for KSV list ready. Fail if timer expires prior to ready. */ + for (i = 0; i < HDMI_HDCP_WAIT_KSV_LIST_READ_REG_CNT; i++) { + ret = HdmiHdcpRead(hdcp, HDMI_HDCP_BCAPS, &(hdcp->bcaps), sizeof(hdcp->bcaps)); + if (ret != HDF_SUCCESS) { + return ret; + } + if ((hdcp->bcaps & HDMI_HDCP_BCAPS_KSV_FIFO_READY_MARK) > 0) { + ready = true; + break; + } + OsalMSleep(HDMI_HDCP_WAIT_KSV_LIST_READ_REG_INTERVAL); + } + if (ready == false) { + return HDF_ERR_TIMEOUT; + } + /* */ + ret = HdmiHdcpAuthenticationCheckBstatus(hdcp); + if (ret != HDF_SUCCESS) { + return ret; + } + (void)HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_WRITE_BCAPS, &(hdcp->bcaps), sizeof(hdcp->bcaps)); + (void)HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_WRITE_BSTATUS, hdcp->bstatus, sizeof(hdcp->bstatus)); + return HDF_SUCCESS; +} + +static int32_t HdmiHdcpAuthenticationReadKsvList(struct HdmiHdcp *hdcp) +{ + int32_t ret; + uint32_t try = HDMI_HDCP_DEFAULT_READ_REG_TRY; + + hdcp->ksvLen = HDMI_HDCP_GET_KSV_LEN(hdcp->deviceCount); + do { + ret = HdmiHdcpRead(hdcp, HDMI_HDCP_KSV_FIFO, hdcp->ksvList, hdcp->ksvLen); + if (ret == HDF_SUCCESS) { + break; + } + OsalMSleep(HDMI_HDCP_WAIT_KSV_LIST_READ_REG_INTERVAL); + try--; + } while (try > 0); + + ret = HdmiHdcpReadMsgHv(hdcp); + if (ret != HDF_SUCCESS) { + return ret; + } + /* We may need to reset SHA before write ksv list. */ + (void)HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_RESET_SHA, NULL, 0); + (void)HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_WRITE_KSV_FIFO, hdcp->ksvList, hdcp->ksvLen); + return HDF_SUCCESS; +} + +static int32_t HdmiHdcpAuthenticationSecondPart(struct HdmiHdcp *hdcp) +{ + int32_t ret; + + /* Poll: KSV list ready. */ + ret = HdmiHdcpAuthenticationWaitKsvListReady(hdcp); + if (ret != HDF_SUCCESS) { + HDF_LOGE("hdcp auth, wait ksv list ready fail."); + return ret; + } + + /* Read KSV list */ + ret = HdmiHdcpAuthenticationReadKsvList(hdcp); + if (ret != HDF_SUCCESS) { + HDF_LOGE("hdcp auth, read ksv list fail."); + return ret; + } + + /* Verify V/V' matched or not */ + ret = HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_CHECK_V, NULL, 0); + if (ret != HDF_SUCCESS) { + HDF_LOGE("hdcp auth, check V fail."); + return ret; + } + return HDF_SUCCESS; +} + +static void HdmiHdcpAuthenticationSucc(struct HdmiHdcp *hdcp) +{ + (void)HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_AUTH_DONE, NULL, 0); + hdcp->state = HDMI_HDCP_AUTH_DONE; + hdcp->authRetryCnt = 0; +} + +static void HdmiHdcpAuthenticationFail(struct HdmiHdcp *hdcp) +{ + (void)HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_AUTH_FAIL, NULL, 0); + hdcp->state = HDMI_HDCP_AUTH_FAIL; +} + +static int32_t HdmiHdcpAuthentication(struct HdmiHdcp *hdcp) +{ + int32_t ret; + + if (hdcp == NULL || hdcp->priv == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + /* auth prepare, get aksv and driver clear registers. */ + ret = HdmiHdcpAuthenticationPrepare(hdcp); + if (ret != HDF_SUCCESS) { + goto _END; + } + + /* + * First part of the authentication exchange. + */ + ret = HdmiHdcpAuthenticationFirstPart(hdcp); + if (ret != HDF_SUCCESS) { + goto _END; + } + HDF_LOGD("hdcp auth Part I success."); + /* receiver (0), repeater (1) */ + if ((hdcp->bcaps & HDMI_HDCP_BCAPS_REPEATER_MARK) == 0) { + goto _END; + } + + /* + * The second part of the authentication protocol is required if the HDCP Reciever is an HDCP Repeater. + */ + ret = HdmiHdcpAuthenticationSecondPart(hdcp); + if (ret != HDF_SUCCESS) { + goto _END; + } + +_END: + if (ret == HDF_SUCCESS) { + HdmiHdcpAuthenticationSucc(hdcp); + } else { + HdmiHdcpAuthenticationFail(hdcp); + } + return ret; +} + +static int32_t HdmiHdcpAuthenticationRetry(struct HdmiHdcp *hdcp) +{ + if (hdcp == NULL || hdcp->priv == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + if (hdcp->authRetryCnt > HDMI_HDCP_AUTH_MAX_RETRY_CNT) { + HDF_LOGE("hdcp auth reach to max cnt, auth fail"); + return HDF_FAILURE; + } + return HdmiHdcpAuthentication(hdcp); +} + +int32_t HdmiHdcpOpen(struct HdmiHdcp *hdcp) +{ + int32_t ret; + + (void)OsalMutexLock(&(hdcp->hdcpMutex)); + hdcp->state = HDMI_HDCP_AUTH_INACTIVE; + hdcp->authRetryCnt = 0; + ret = HdmiHdcpAuthentication(hdcp); + if (ret == HDF_SUCCESS) { + HDF_LOGD("hdcp Authentication success!"); + goto __END; + } + + while (hdcp->authRetryCnt <= HDMI_HDCP_AUTH_MAX_RETRY_CNT) { + ret = HdmiHdcpAuthenticationRetry(hdcp); + if (ret == HDF_SUCCESS) { + goto __END; + } + hdcp->authRetryCnt++; + } + __END : + (void)OsalMutexUnlock(&(hdcp->hdcpMutex)); + return ret; +} + +void HdmiHdcpClose(struct HdmiHdcp *hdcp) +{ + if (hdcp == NULL) { + return; + } + + if (hdcp->state == HDMI_HDCP_AUTH_INACTIVE || + hdcp->state == HDMI_HDCP_AUTH_AKSV_INVALID) { + return; + } + + (void)HdmiHdcpWriteMsgToReg(hdcp, HDMI_HDCP_OPT_AUTH_CLOSE, NULL, 0); + hdcp->state = HDMI_HDCP_AUTH_INACTIVE; + hdcp->authRetryCnt = 0; +} diff --git a/support/platform/src/hdmi/hdmi_hdr.c b/support/platform/src/hdmi/hdmi_hdr.c new file mode 100644 index 00000000..fdfa29de --- /dev/null +++ b/support/platform/src/hdmi/hdmi_hdr.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdf_log.h" +#include "hdmi_core.h" + +#define HDF_LOG_TAG hdmi_hdr_c + +static bool HdmiHdrAttrChange(struct HdmiHdrAttr *curAttr, struct HdmiHdrAttr *oldAttr) +{ + if (memcmp(curAttr, oldAttr, sizeof(struct HdmiHdrAttr)) == 0) { + return false; + } + return true; +} + +static void HdmiHdrColorimetryUpdate(struct HdmiVideoAttr *videoAttr, enum HdmiHdrColormetry colorimetry) +{ + if (colorimetry >= HDMI_HDR_COLORIMETRY_EXTENDED) { + videoAttr->colorimetry = HDMI_COLORIMETRY_EXTENDED; + videoAttr->extColorimetry = (enum HdmiExtendedColorimetry)(colorimetry - + HDMI_HDR_EXTENDED_COLORIMETRY_XV_YCC_601); + } else { + videoAttr->colorimetry = (enum HdmiColorimetry)colorimetry; + videoAttr->extColorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + } +} + +static void HdmiHdrZeroDrmInfoframeTimerSet(struct HdmiCntlr *cntlr, bool start) +{ + struct HdmiHdrInfo *hdrInfo = &(cntlr->hdr->info); + struct HdmiHdrAttr *hdrAttr = &(cntlr->attr.hdrAttr); + + hdrInfo->zeroDrmIfTimer.start = false; + hdrInfo->zeroDrmIfTimer.timerType = HDMI_HDR_TIMER_ZERO_DRMIF; + hdrInfo->zeroDrmIfTimer.time = HDMI_ZERO_DRMIF_SEND_TIME; + HdmiCntlrHdrTimerSet(cntlr, &(hdrInfo->zeroDrmIfTimer)); + if (start == false) { + return; + } + + hdrAttr->eotfType = HDMI_DRM_EOTF_SDR_LUMIN; + hdrAttr->metadataType = HDMI_DRM_STATIC_METADATA_TYPE_1; + if (memset_s(&(hdrAttr->descriptor), sizeof(hdrAttr->descriptor), 0, sizeof(hdrAttr->descriptor)) != EOK) { + HDF_LOGE("memset_s fail"); + return; + } + (void)HdmiDrmInfoframeSend(&(cntlr->infoframe), true); + + hdrInfo->zeroDrmIfTimer.start = true; + HdmiCntlrHdrTimerSet(cntlr, &(hdrInfo->zeroDrmIfTimer)); +} + +static void HdmiHdrModeChangeTimerSet(struct HdmiCntlr *cntlr, bool start) +{ + struct HdmiHdrInfo *hdrInfo = &(cntlr->hdr->info); + + hdrInfo->stateChangeTimer.start = false; + hdrInfo->stateChangeTimer.timerType = HDMI_HDR_TIMER_SDR_TO_HDR10; + hdrInfo->stateChangeTimer.time = HDMI_HDR_STATE_CHANGE_TIME; + HdmiCntlrHdrTimerSet(cntlr, &(hdrInfo->stateChangeTimer)); + if (start == false) { + return; + } + + hdrInfo->stateChangeTimer.start = true; + HdmiCntlrHdrTimerSet(cntlr, &(hdrInfo->stateChangeTimer)); +} + +static int32_t HdmiDisableHdr(struct HdmiCntlr *cntlr, struct HdmiHdrAttr *curAttr) +{ + int32_t ret = HDF_SUCCESS; + struct HdmiHdrAttr *oldAttr = &(cntlr->attr.hdrAttr); + struct HdmiVideoAttr *videoAttr = &(cntlr->attr.videoAttr); + struct HdmiCommonAttr *commAttr = &(cntlr->attr.commAttr); + struct HdmiHdrInfo *hdrInfo = &(cntlr->hdr->info); + + switch (oldAttr->mode) { + case HDMI_HDR_MODE_DISABLE: + break; + case HDMI_HDR_MODE_CEA_861_3: + *oldAttr = *curAttr; + if (hdrInfo->state != HDMI_HDR_STATE_NONE) { + /* to solve the problem of some TV can not switch smoothly from HDR10 to non-HDR10. */ + if (hdrInfo->state == HDMI_HDR_STATE_OE) { + HdmiCntlrAudioMuteEnable(cntlr, false); + HdmiCntlrBlackDataSet(cntlr, true); + } + HdmiCntlrAvmuteSet(cntlr, true); + if (hdrInfo->state == HDMI_HDR_STATE_OE) { + HdmiCntlrPhyOutputEnablet(cntlr, false); + } + HdmiHdrModeChangeTimerSet(cntlr, true); + HdmiCntlrHdrTimerSet(cntlr, &(hdrInfo->stateChangeTimer)); + (void)HdmiDrmInfoframeSend(&(cntlr->infoframe), false); + } else { + /* start timer, send zero DRMIF and stop after 2 seconds. */ + HdmiHdrZeroDrmInfoframeTimerSet(cntlr, true); + } + break; + case HDMI_HDR_MODE_CEA_861_3_AUTHEN: + case HDMI_HDR_MODE_DOLBY_NORMAL: + case HDMI_HDR_MODE_DOLBY_TUNNELING: + if (oldAttr->mode != HDMI_HDR_MODE_DOLBY_NORMAL) { + commAttr->colorSpace = HDMI_COLOR_SPACE_YCBCR444; + } + videoAttr->quantization = HDMI_QUANTIZATION_RANGE_DEFAULT; + videoAttr->yccQuantization = HDMI_YCC_QUANTIZATION_RANGE_LIMITED; + break; + default: + ret = HDF_FAILURE; + break; + } + return ret; +} + +static void HdmiChangeToHdr(struct HdmiCntlr *cntlr, struct HdmiCommonAttr *commAttr) +{ + struct HdmiHdrAttr *hdrAttr = &(cntlr->attr.hdrAttr); + struct HdmiHdrInfo *hdrInfo = &(cntlr->hdr->info); + + HdmiHdrZeroDrmInfoframeTimerSet(cntlr,false); + if (hdrAttr->userMode != HDMI_HDR_USERMODE_HDR10) { + HDF_LOGE("usermode is not HDR10/HLG."); + return; + } + commAttr->drm = true; + + if (hdrInfo->state != HDMI_HDR_STATE_NONE) { + /* to solve the problem of some TV can not switch smoothly from non-HDR10 to HDR10. */ + if (hdrInfo->state == HDMI_HDR_STATE_OE) { + HdmiCntlrAudioMuteEnable(cntlr, false); + HdmiCntlrBlackDataSet(cntlr, true); + } + HdmiCntlrAvmuteSet(cntlr, true); + if (hdrInfo->state == HDMI_HDR_STATE_OE) { + HdmiCntlrPhyOutputEnablet(cntlr, false); + } + hdrInfo->stateChangeTimer.start = true; + hdrInfo->stateChangeTimer.timerType = HDMI_HDR_TIMER_SDR_TO_HDR10; + hdrInfo->stateChangeTimer.time = HDMI_HDR_STATE_CHANGE_TIME; + HdmiCntlrHdrTimerSet(cntlr, &(hdrInfo->stateChangeTimer)); + } +} + +static int32_t HdmiHdrModeSelect(struct HdmiCntlr *cntlr) +{ + struct HdmiHdrAttr *hdrAttr = &(cntlr->attr.hdrAttr); + struct HdmiCommonAttr *commAttr = &(cntlr->attr.commAttr); + + switch (hdrAttr->mode) { + case HDMI_HDR_MODE_CEA_861_3: + HdmiChangeToHdr(cntlr, commAttr); + commAttr->vsifDolby = false; + break; + case HDMI_HDR_MODE_CEA_861_3_AUTHEN: + /* HDR10 authen mode, HDMI must bypass. */ + if (hdrAttr->userMode != HDMI_HDR_USERMODE_DOLBY) { + HDF_LOGE("user mode is not dolby"); + return HDF_FAILURE; + } + commAttr->drm = true; + commAttr->vsifDolby = false; + break; + case HDMI_HDR_MODE_DOLBY_NORMAL: + case HDMI_HDR_MODE_DOLBY_TUNNELING: + if (hdrAttr->userMode != HDMI_HDR_USERMODE_DOLBY) { + HDF_LOGE("user mode is not dolby"); + return HDF_FAILURE; + } + commAttr->drm = false; + commAttr->vsifDolby = true; + break; + default: + return HDF_FAILURE; + } + + return HDF_SUCCESS; +} + +int32_t HdmiHdrAttrHandle(struct HdmiHdr *hdr, struct HdmiHdrAttr *curAttr) +{ + struct HdmiHdrAttr *oldAttr = NULL; + struct HdmiCommonAttr *commAttr = NULL; + struct HdmiCntlr *cntlr = NULL; + int32_t ret = HDF_FAILURE; + + if (hdr == NULL || hdr->priv == NULL) { + HDF_LOGE("hdr attr handle, input param invalid."); + return HDF_ERR_INVALID_PARAM; + } + + cntlr = (struct HdmiCntlr *)hdr->priv; + oldAttr = &(cntlr->attr.hdrAttr); + commAttr = &(cntlr->attr.commAttr); + if (HdmiHdrAttrChange(curAttr, oldAttr) == false) { + HDF_LOGD("hdr attr not change"); + return HDF_SUCCESS; + } + + if (oldAttr->colorimetry != curAttr->colorimetry) { + HdmiHdrColorimetryUpdate(&(cntlr->attr.videoAttr), curAttr->colorimetry); + } + + /* change to SDR */ + if (curAttr->mode == HDMI_HDR_MODE_DISABLE) { + if (HdmiDisableHdr(cntlr, curAttr) == HDF_SUCCESS) { + commAttr->vsifDolby = false; + cntlr->attr.hdrAttr = *curAttr; + goto _SEND_INFOFRAME; + } else { + return HDF_FAILURE; + } + } + + /* change to HDR */ + cntlr->attr.hdrAttr = *curAttr; + ret = HdmiHdrModeSelect(cntlr); + if (ret != HDF_SUCCESS) { + return ret; + } + (void)HdmiDrmInfoframeSend(&(cntlr->infoframe), (commAttr->enableHdmi & commAttr->drm)); + +_SEND_INFOFRAME: + (void)HdmiAviInfoframeSend(&(cntlr->infoframe), (commAttr->enableHdmi && commAttr->avi)); + (void)HdmiVsInfoframeSend(&(cntlr->infoframe), commAttr->enableHdmi, commAttr->vsifDolby); + HdmiCntlrVideoPathSet(cntlr, &(cntlr->attr.videoAttr)); + return ret; +} + +int32_t HdmiHdrDrmInfoframeStop(struct HdmiHdr *hdr) +{ + struct HdmiCntlr *cntlr = NULL; + + HDF_LOGD("zero DRM infoframe send timeout."); + if (hdr == NULL || hdr->priv == NULL) { + HDF_LOGE("hdr stop drm, input param invalid."); + return HDF_ERR_INVALID_PARAM; + } + cntlr = (struct HdmiCntlr *)hdr->priv; + + if (cntlr->attr.hdrAttr.mode != HDMI_HDR_MODE_CEA_861_3) { + return HdmiDrmInfoframeSend(&(cntlr->infoframe), false); + } + return HDF_SUCCESS; +} + +int32_t HdmiHdrModeChangeTimeout(struct HdmiHdr *hdr) +{ + struct HdmiCntlr *cntlr = NULL; + + HDF_LOGD("hdr mode change timeout."); + if (hdr == NULL || hdr->priv == NULL) { + HDF_LOGE("hdr mode change timeout, input param invalid."); + return HDF_ERR_INVALID_PARAM; + } + cntlr = (struct HdmiCntlr *)hdr->priv; + + if (hdr->info.state == HDMI_HDR_STATE_OE) { + HdmiCntlrPhyOutputEnablet(cntlr, true); + } + HdmiCntlrAvmuteSet(cntlr, false); + if (hdr->info.state == HDMI_HDR_STATE_OE) { + HdmiCntlrBlackDataSet(cntlr, false); + HdmiCntlrAudioMuteEnable(cntlr, true); + } + return HDF_SUCCESS; +} diff --git a/support/platform/src/hdmi/hdmi_if.c b/support/platform/src/hdmi/hdmi_if.c new file mode 100644 index 00000000..c6b960a8 --- /dev/null +++ b/support/platform/src/hdmi/hdmi_if.c @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdmi_if.h" +#ifndef __USER__ +#include "hdmi_core.h" +#endif +#include "hdf_base.h" +#include "hdf_log.h" +#include "osal_mem.h" +#ifdef __USER__ +#include "hdf_io_service_if.h" +#include "securec.h" +#endif + +#define HDF_LOG_TAG hdmi_if_c + +#define HDMI_SERVICE_NAME_LEN 32 + +#ifdef __USER__ + +enum HdmiIoCmd { + HDMI_CMD_OPEN, + HDMI_CMD_CLOSE, + HDMI_CMD_START, + HDMI_CMD_STOP, + HDMI_CMD_AVMUTE_SET, + HDMI_CMD_DEEP_COLOR_SET, + HDMI_CMD_DEEP_COLOR_GET, + HDMI_CMD_VIDEO_ATTR_SET, + HDMI_CMD_AUDIO_ATTR_SET, + HDMI_CMD_HDR_ATTR_SET, + HDMI_CMD_READ_SINK_EDID, + HDMI_CMD_INFOFRAME_SET, + HDMI_CMD_INFOFRAME_GET, + HDMI_CMD_BUTT, +}; + +static int32_t HdmiGetDataFromReply(struct HdfSBuf *reply, uint8_t *data, uint32_t size) +{ + uint32_t rLen; + const void *rBuf = NULL; + + if (HdfSbufReadBuffer(reply, &rBuf, &rLen) == false) { + HDF_LOGE("HdmiGetDataFromReply: read rBuf fail!"); + return HDF_ERR_IO; + } + if (size != rLen) { + HDF_LOGE("HdmiGetDataFromReply: err len:%u, rLen:%u", size, rLen); + if (rLen > size) { + rLen = size; + } + } + + if (memcpy_s(data, size, rBuf, rLen) != EOK) { + HDF_LOGE("HdmiGetDataFromReply: memcpy rBuf fail!"); + return HDF_ERR_IO; + } + return HDF_SUCCESS; +} + +static void HdmiUserClose(DevHandle handle) +{ + struct HdfIoService *service = (struct HdfIoService *)handle; + int32_t ret; + + if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("HdmiUserClose: service is invalid"); + return; + } + + ret = service->dispatcher->Dispatch(&service->object, HDMI_CMD_CLOSE, NULL, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiUserClose: failed to send service call:%d", ret); + } +} + +static int32_t HdmiUserStart(DevHandle handle) +{ + struct HdfIoService *service = (struct HdfIoService *)handle; + int32_t ret; + + if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("HdmiUserStart: service is invalid"); + return HDF_ERR_INVALID_PARAM; + } + + ret = service->dispatcher->Dispatch(&service->object, HDMI_CMD_START, NULL, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiUserStart: failed to send service call:%d", ret); + return ret; + } + return HDF_SUCCESS; +} + +static int32_t HdmiUserStop(DevHandle handle) +{ + struct HdfIoService *service = (struct HdfIoService *)handle; + int32_t ret; + + if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("HdmiUserStop: service is invalid"); + return HDF_ERR_INVALID_PARAM; + } + + ret = service->dispatcher->Dispatch(&service->object, HDMI_CMD_STOP, NULL, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiUserStop: failed to send service call:%d", ret); + return ret; + } + return HDF_SUCCESS; +} + +static int32_t HdmiUserAvmuteSet(DevHandle handle, bool enable) +{ + int32_t ret; + struct HdfSBuf *buf = NULL; + struct HdfIoService *service = (struct HdfIoService *)handle; + + if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("HdmiUserAvmuteSet: service is invalid"); + return HDF_ERR_INVALID_PARAM; + } + + buf = HdfSBufObtain(sizeof(enable)); + if (buf == NULL) { + HDF_LOGE("HdmiUserAvmuteSet: failed to obtain buf"); + return HDF_ERR_MALLOC_FAIL; + } + if (!HdfSbufWriteBuffer(buf, &enable, sizeof(enable))) { + HDF_LOGE("HdmiUserAvmuteSet: sbuf write buffer failed"); + HdfSBufRecycle(buf); + return HDF_ERR_IO; + } + + ret = service->dispatcher->Dispatch(&service->object, HDMI_CMD_AVMUTE_SET, buf, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiUserAvmuteSet: failed to write, ret %d", ret); + } + HdfSBufRecycle(buf); + return ret; +} + +static int32_t HdmiUserDeepColorSet(DevHandle handle, enum HdmiDeepColor color) +{ + int32_t ret; + struct HdfSBuf *buf = NULL; + struct HdfIoService *service = (struct HdfIoService *)handle; + + if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("HdmiUserDeepColorSet: service is invalid"); + return HDF_ERR_INVALID_PARAM; + } + + buf = HdfSBufObtain(sizeof(color)); + if (buf == NULL) { + HDF_LOGE("HdmiUserDeepColorSet: failed to obtain buf"); + return HDF_ERR_MALLOC_FAIL; + } + if (!HdfSbufWriteBuffer(buf, &color, sizeof(color))) { + HDF_LOGE("HdmiUserDeepColorSet: sbuf write color failed"); + HdfSBufRecycle(buf); + return HDF_ERR_IO; + } + + ret = service->dispatcher->Dispatch(&service->object, HDMI_CMD_DEEP_COLOR_SET, buf, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiUserDeepColorSet: failed to write, ret %d", ret); + } + HdfSBufRecycle(buf); + return ret; +} + +static int32_t HdmiUserSetVideoAttribute(DevHandle handle, struct HdmiVideoAttr *attr) +{ + int32_t ret; + struct HdfSBuf *buf = NULL; + struct HdfIoService *service = (struct HdfIoService *)handle; + + if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("HdmiUserSetVideoAttribute: service is invalid"); + return HDF_ERR_INVALID_PARAM; + } + if (attr == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + buf = HdfSBufObtain(sizeof(struct HdmiVideoAttr)); + if (buf == NULL) { + HDF_LOGE("HdmiUserSetVideoAttribute: failed to obtain buf"); + return HDF_ERR_MALLOC_FAIL; + } + if (!HdfSbufWriteBuffer(buf, attr, sizeof(struct HdmiVideoAttr))) { + HDF_LOGE("HdmiUserSetVideoAttribute: sbuf write attr failed"); + HdfSBufRecycle(buf); + return HDF_ERR_IO; + } + + ret = service->dispatcher->Dispatch(&service->object, HDMI_CMD_VIDEO_ATTR_SET, buf, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiUserSetVideoAttribute: failed to write, ret %d", ret); + } + HdfSBufRecycle(buf); + return ret; +} + +static int32_t HdmiUserSetAudioAttribute(DevHandle handle, struct HdmiAudioAttr *attr) +{ + int32_t ret; + struct HdfSBuf *buf = NULL; + struct HdfIoService *service = (struct HdfIoService *)handle; + + if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("HdmiUserSetAudioAttribute: service is invalid"); + return HDF_ERR_INVALID_PARAM; + } + if (attr == NULL) { + HDF_LOGE("HdmiUserSetAudioAttribute: attr is NULL"); + return HDF_ERR_INVALID_PARAM; + } + + buf = HdfSBufObtain(sizeof(struct HdmiAudioAttr)); + if (buf == NULL) { + HDF_LOGE("HdmiUserSetAudioAttribute: failed to obtain buf"); + return HDF_ERR_MALLOC_FAIL; + } + if (!HdfSbufWriteBuffer(buf, attr, sizeof(struct HdmiAudioAttr))) { + HDF_LOGE("HdmiUserSetAudioAttribute: sbuf write attr failed"); + HdfSBufRecycle(buf); + return HDF_ERR_IO; + } + + ret = service->dispatcher->Dispatch(&service->object, HDMI_CMD_AUDIO_ATTR_SET, buf, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiUserSetAudioAttribute: failed to write, ret %d", ret); + } + HdfSBufRecycle(buf); + return ret; +} + +static int32_t HdmiUserSetHdrAttribute(DevHandle handle, struct HdmiHdrAttr *attr) +{ + int32_t ret; + struct HdfSBuf *buf = NULL; + struct HdfIoService *service = (struct HdfIoService *)handle; + + if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("HdmiUserSetHdrAttribute: service is invalid"); + return HDF_ERR_INVALID_PARAM; + } + if (attr == NULL) { + HDF_LOGE("HdmiUserSetHdrAttribute: attr is NULL"); + return HDF_ERR_INVALID_PARAM; + } + + buf = HdfSBufObtain(sizeof(struct HdmiHdrAttr)); + if (buf == NULL) { + HDF_LOGE("HdmiUserSetHdrAttribute: failed to obtain buf"); + return HDF_ERR_MALLOC_FAIL; + } + if (!HdfSbufWriteBuffer(buf, attr, sizeof(struct HdmiHdrAttr))) { + HDF_LOGE("HdmiUserSetHdrAttribute: sbuf write attr failed"); + HdfSBufRecycle(buf); + return HDF_ERR_IO; + } + + ret = service->dispatcher->Dispatch(&service->object, HDMI_CMD_HDR_ATTR_SET, buf, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiUserSetAudioAttribute: failed to write, ret %d", ret); + } + HdfSBufRecycle(buf); + return ret; +} + +static int32_t HdmiUserDeepColorGet(DevHandle handle, enum HdmiDeepColor *color) +{ + int32_t ret; + struct HdfSBuf *reply = NULL; + struct HdfIoService *service = (struct HdfIoService *)handle; + + if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("HdmiUserDeepColorGet: service is invalid"); + return HDF_ERR_INVALID_PARAM; + } + if (color == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + /* Four bytes are used to store the buffer length, and four bytes are used to align the memory. */ + reply = HdfSBufObtain(sizeof(*color) + sizeof(uint64_t)); + if (reply == NULL) { + HDF_LOGE("HdmiUserDeepColorGet: failed to obtain reply"); + ret = HDF_ERR_MALLOC_FAIL; + goto __EXIT; + } + + ret = service->dispatcher->Dispatch(&service->object, HDMI_CMD_DEEP_COLOR_GET, NULL, reply); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiUserDeepColorGet: failed to write, ret %d", ret); + } else { + ret = HdmiGetDataFromReply(reply, (uint8_t *)color, sizeof(*color)); + } + +__EXIT : + if (reply != NULL) { + HdfSBufRecycle(reply); + } + return ret; +} + +static int32_t HdmiUserGetSinkEdid(DevHandle handle, uint8_t *buffer, uint32_t len) +{ + int32_t ret; + struct HdfSBuf *reply = NULL; + struct HdfIoService *service = (struct HdfIoService *)handle; + + if (service == NULL || service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("HdmiUserGetSinkEdid: service is invalid"); + return HDF_ERR_INVALID_PARAM; + } + if (buffer == NULL || len == 0) { + return HDF_ERR_INVALID_PARAM; + } + + reply = HdfSBufObtain(len); + if (reply == NULL) { + HDF_LOGE("HdmiUserGetSinkEdid: failed to obtain reply"); + ret = HDF_ERR_MALLOC_FAIL; + goto __EXIT; + } + + ret = service->dispatcher->Dispatch(&service->object, HDMI_CMD_READ_SINK_EDID, NULL, reply); + if (ret <= 0) { + HDF_LOGE("HdmiUserGetSinkEdid: failed to write, ret %d", ret); + } else { + ret = HdmiGetDataFromReply(reply, buffer, len); + } + +__EXIT : + if (reply != NULL) { + HdfSBufRecycle(reply); + } + return ret; +} +#endif + +static void *HdmiCntlrObjGet(uint16_t busNum) +{ + char *serviceName = NULL; + void *obj = NULL; + + serviceName = (char *)OsalMemCalloc(HDMI_SERVICE_NAME_LEN + 1); + if (serviceName == NULL) { + HDF_LOGE("HDMI service name malloc fail."); + return NULL; + } + if (snprintf_s(serviceName, (HDMI_SERVICE_NAME_LEN + 1), + HDMI_SERVICE_NAME_LEN, "HDF_PLATFORM_HDMI_%d", busNum) < 0) { + HDF_LOGE("get HDMI service name fail."); + goto __ERR; + } +#ifdef __USER__ + obj = (void *)HdfIoServiceBind(serviceName); +#else + obj = (void *)HdmiCntlrGetByBusNum(busNum); +#endif +__ERR: + OsalMemFree(serviceName); + return obj; +} + +DevHandle HdmiOpen(uint16_t busNum) +{ + DevHandle *obj = (DevHandle *)HdmiCntlrObjGet(busNum); + int32_t ret; + + if (obj == NULL) { + return NULL; + } +#ifdef __USER__ + struct HdfIoService *service = (struct HdfIoService *)obj; + if (service->dispatcher == NULL || service->dispatcher->Dispatch == NULL) { + HDF_LOGE("HdmiOpen: dispatcher or Dispatch is NULL!"); + return NULL; + } + ret = service->dispatcher->Dispatch(&service->object, HDMI_CMD_OPEN, NULL, NULL); + if (ret != HDF_SUCCESS) { + HDF_LOGE("HdmiOpen: failed to send service call:%d", ret); + return NULL; + } +#else + ret = HdmiCntlrOpen((struct HdmiCntlr *)obj); + if (ret != HDF_SUCCESS) { + return NULL; + } +#endif + return obj; +} + +int32_t HdmiStart(DevHandle handle) +{ +#ifdef __USER__ + return HdmiUserStart(handle); +#else + return HdmiCntlrStart((struct HdmiCntlr *)handle); +#endif +} + +int32_t HdmiStop(DevHandle handle) +{ +#ifdef __USER__ + return HdmiUserStop(handle); +#else + return HdmiCntlrStop((struct HdmiCntlr *)handle); +#endif +} + +int32_t HdmiAvmuteSet(DevHandle handle, bool enable) +{ +#ifdef __USER__ + return HdmiUserAvmuteSet(handle, enable); +#else + HdmiCntlrAvmuteSet((struct HdmiCntlr *)handle, enable); + return HDF_SUCCESS; +#endif +} + +int32_t HdmiDeepColorSet(DevHandle handle, enum HdmiDeepColor color) +{ +#ifdef __USER__ + return HdmiUserDeepColorSet(handle, color); +#else + return HdmiCntlrDeepColorSet((struct HdmiCntlr *)handle, color); +#endif +} + +int32_t HdmiDeepColorGet(DevHandle handle, enum HdmiDeepColor *color) +{ +#ifdef __USER__ + return HdmiUserDeepColorGet(handle, color); +#else + return HdmiCntlrDeepColorGet((struct HdmiCntlr *)handle, color); +#endif +} + +int32_t HdmiSetVideoAttribute(DevHandle handle, struct HdmiVideoAttr *attr) +{ +#ifdef __USER__ + return HdmiUserSetVideoAttribute(handle, attr); +#else + return HdmiCntlrSetVideoAttribute((struct HdmiCntlr *)handle, attr); +#endif +} + +int32_t HdmiSetAudioAttribute(DevHandle handle, struct HdmiAudioAttr *attr) +{ +#ifdef __USER__ + return HdmiUserSetAudioAttribute(handle, attr); +#else + return HdmiCntlrSetAudioAttribute((struct HdmiCntlr *)handle, attr); +#endif +} + +int32_t HdmiSetHdrAttribute(DevHandle handle, struct HdmiHdrAttr *attr) +{ +#ifdef __USER__ + return HdmiUserSetHdrAttribute(handle, attr); +#else + return HdmiCntlrSetHdrAttribute((struct HdmiCntlr *)handle, attr); +#endif +} + +int32_t HdmiReadSinkEdid(DevHandle handle, uint8_t *buffer, uint32_t len) +{ +#ifdef __USER__ + return HdmiUserGetSinkEdid(handle, buffer, len); +#else + return HdmiCntlrGetSinkEdid((struct HdmiCntlr *)handle, buffer, len); +#endif +} + +void HdmiClose(DevHandle handle) +{ +#ifdef __USER__ + HdmiUserClose(handle); +#else + HdmiCntlrClose((struct HdmiCntlr *)handle); +#endif +} diff --git a/support/platform/src/hdmi/hdmi_infoframe.c b/support/platform/src/hdmi/hdmi_infoframe.c new file mode 100644 index 00000000..34e67ac4 --- /dev/null +++ b/support/platform/src/hdmi/hdmi_infoframe.c @@ -0,0 +1,806 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdf_log.h" +#include "hdmi_core.h" +#include "securec.h" + +#define HDF_LOG_TAG hdmi_infoframe_c + +#define HDMI_IEEE_OUI_1_4_1ST 0x03 +#define HDMI_IEEE_OUI_1_4_2ND 0x0C +#define HDMI_IEEE_OUI_1_4_3RD 0x00 + +static void HdmiInfoframeFillCheckSum(uint8_t *data, uint32_t len) +{ + uint32_t i; + uint8_t checkSum = 0; + + for (i = 0; i < len; i++) { + checkSum += data[i]; + } + if (checkSum > 0) { + /* + * The checksum shall be calculated such that a byte-wide sum of all three bytes of the Packet Header and + * all valid bytes of the InfoFrame Packet contents(determined by InfoFrame_length), plus the checksum itself, + * equals zero. + */ + data[3] = HDMI_INFOFRAME_CHECKSUM - checkSum; + } +} + +static void HdmiInfoframeFillHeader(struct HdmiInfoframeHeader *header, uint8_t *data, uint32_t len) +{ + if (len < HDMI_INFOFRAME_PACKET_HEADER_LEN) { + HDF_LOGE("len = %d, val is too small.", len); + return; + } + data[0] = header->type; + data[1] = header->verNum; + data[2] = header->len; +} + +static int32_t HdmiInfoframePacketVsEncoding(union HdmiInfoframeInfo *infoframe, uint8_t *data, uint32_t len) +{ + uint32_t lenght; + struct HdmiVs14VsifContent *vsifContent = NULL; + struct HdmiVsUserVsifContent *userContent = NULL; + struct HdmiVsInfoframe *vs = &(infoframe->vs); + + lenght = HDMI_INFOFRAME_PACKET_HEADER_LEN + vs->len; + if (len < lenght) { + HDF_LOGE("len = %d, val is too small.", len); + return HDF_ERR_INVALID_PARAM; + } + if (memset_s(data, len, 0, len) != EOK) { + HDF_LOGE("memset_s fail."); + return HDF_ERR_IO; + } + + HdmiInfoframeFillHeader(&(infoframe->header), data, len); + if (vs->vsifContent._14Vsif.oui == HDMI_IEEE_OUI_1_4) { + data[4] = HDMI_IEEE_OUI_1_4_1ST; + data[5] = HDMI_IEEE_OUI_1_4_2ND; + data[6] = HDMI_IEEE_OUI_1_4_3RD; + vsifContent = &(vs->vsifContent._14Vsif); + userContent = &(vs->vsifContent.userVsif); + data[7] = (vsifContent->format & HDMI_VENDOR_1_4_FORMAT_MARK) << HDMI_VENDOR_1_4_FORMAT_SHIFT; + if (vsifContent->format == HDMI_VS_VIDEO_FORMAT_4K) { + data[8] = vsifContent->vic; + return HDF_SUCCESS; + } else if (vsifContent->format == HDMI_VS_VIDEO_FORMAT_3D) { + data[8] = (vsifContent->_3dStruct & HDMI_VENDOR_3D_STRUCTURE_MARK) << HDMI_VENDOR_3D_STRUCTURE_SHIFT; + } + data[9] = (vsifContent->_3dExtData & HDMI_VENDOR_3D_EXT_DATA_MARK) << HDMI_VENDOR_3D_EXT_DATA_SHIFT; + if (vsifContent->_3dMetaPresent == false) { + if (userContent->len == 0 || (userContent->len + lenght) > len) { + return HDF_SUCCESS; + } + if (memcpy_s(&data[lenght], (len - lenght), userContent->data, userContent->len) != EOK) { + HDF_LOGE("memcpy_s fail."); + return HDF_ERR_IO; + } + lenght += userContent->len; + } + } + HdmiInfoframeFillCheckSum(data, lenght); + return HDF_SUCCESS; +} + +static int32_t HdmiInfoframePacketAviEncoding(union HdmiInfoframeInfo *infoframe, uint8_t *data, uint32_t len) +{ + uint32_t lenght; + uint8_t *buff = data; + struct HdmiAviInfoframe *avi = &(infoframe->avi); + + lenght = HDMI_INFOFRAME_PACKET_HEADER_LEN + avi->len; + if (len < lenght) { + HDF_LOGE("len = %d, val is too small.", len); + return HDF_ERR_INVALID_PARAM; + } + if (memset_s(buff, len, 0, len) != EOK) { + HDF_LOGE("memset_s fail."); + return HDF_ERR_IO; + } + + HdmiInfoframeFillHeader(&(infoframe->header), data, len); + buff += HDMI_INFOFRAME_PACKET_HEADER_LEN; + /* PB1 */ + buff[0] |= (avi->colorSpace & HDMI_AVI_COLOR_SPACE_MARK) << HDMI_AVI_COLOR_SPACE_SHIFT; + buff[0] |= (avi->scanMode & HDMI_AVI_SCAN_MODE_MARK); + if (avi->activeFormatInformationPresent == true) { + buff[0] |= (1 << HDMI_AVI_ACTIVE_INFORMATION_SHIFT); + } + if (avi->horizBarInfoPresent == true) { + buff[0] |= (1 << HDMI_AVI_HORIZONTAL_BAR_SHIFT); + } + if (avi->vertBarInfoPresent == true) { + buff[0] |= (1 << HDMI_AVI_VERTICAL_BAR_SHIFT); + } + /* PB2 */ + buff[1] |= (avi->colorimetry & HDMI_AVI_COLORIMETRY_MARK) << HDMI_AVI_COLORIMETRY_SHIFT; + buff[1] |= (avi->pictureAspect & HDMI_AVI_PICTURE_ASPECT_RATE_MARK) << HDMI_AVI_PICTURE_ASPECT_RATE_SHIFT; + buff[1] |= (avi->activeAspect & HDMI_AVI_ACTIVE_FORMAT_ASPECT_RATE_MARK); + /* PB3 */ + buff[2] |= (avi->extColorimetry & HDMI_AVI_EXT_COLORIMETRY_MARK) << HDMI_AVI_EXT_COLORIMETRY_SHIFT; + buff[2] |= (avi->range & HDMI_AVI_EXT_QUANTIZATION_RANGE_MARK) << HDMI_AVI_EXT_QUANTIZATION_RANGE_SHIFT; + buff[2] |= (avi->nups & HDMI_AVI_NUPS_RANGE_MARK); + if (avi->itc == true) { + buff[2] |= (1 << HDMI_AVI_IT_CONTENT_SHIFT); + } + /* PB4 */ + buff[3] = avi->vic; + /* PB5 */ + buff[4] |= (avi->yccRange & HDMI_AVI_YCC_QUANTIZATION_RANGE_MARK) << HDMI_AVI_YCC_QUANTIZATION_RANGE_SHIFT; + buff[4] |= (avi->itcType & HDMI_AVI_IT_CONTENT_TYPE_MARK) << HDMI_AVI_IT_CONTENT_TYPE_SHIFT; + buff[4] |= (avi->pixelRepetitionFactor & HDMI_AVI_PIXEL_REPETION_FACTOR_MARK); + /* PB6 */ + buff[5] = (uint8_t)(avi->topBar & HDMI_AVI_BAR_MODE_MARK); + /* PB7 */ + buff[6] = (uint8_t)((avi->topBar >> HDMI_AVI_BAR_MODE_SHIFT) & HDMI_AVI_BAR_MODE_MARK); + /* PB8 */ + buff[7] = (uint8_t)(avi->bottomBar & HDMI_AVI_BAR_MODE_MARK); + /* PB9 */ + buff[8] = (uint8_t)((avi->bottomBar >> HDMI_AVI_BAR_MODE_SHIFT) & HDMI_AVI_BAR_MODE_MARK); + /* PB10 */ + buff[9] = (uint8_t)(avi->leftBar & HDMI_AVI_BAR_MODE_MARK); + /* PB11 */ + buff[10] = (uint8_t)((avi->leftBar >> HDMI_AVI_BAR_MODE_SHIFT) & HDMI_AVI_BAR_MODE_MARK); + /* PB12 */ + buff[11] = (uint8_t)(avi->rightBar & HDMI_AVI_BAR_MODE_MARK); + /* PB13 */ + buff[12] = (uint8_t)((avi->rightBar >> HDMI_AVI_BAR_MODE_SHIFT) & HDMI_AVI_BAR_MODE_MARK); + HdmiInfoframeFillCheckSum(data, lenght); + return HDF_SUCCESS; +} + +static int32_t HdmiInfoframePacketSpdEncoding(union HdmiInfoframeInfo *infoframe, uint8_t *data, uint32_t len) +{ + uint32_t lenght; + uint8_t *buff = data; + struct HdmiSpdInfoframe *spd = &(infoframe->spd); + + lenght = HDMI_INFOFRAME_PACKET_HEADER_LEN + spd->len; + if (len < lenght) { + HDF_LOGE("len = %d, val is too small.", len); + return HDF_ERR_INVALID_PARAM; + } + if (memset_s(buff, len, 0, len) != EOK) { + HDF_LOGE("memset_s fail."); + return HDF_ERR_IO; + } + + buff += HDMI_INFOFRAME_PACKET_HEADER_LEN; + /* PB1~PB8 */ + if (memcpy_s(buff, (len - HDMI_INFOFRAME_PACKET_HEADER_LEN), spd->vendorName, sizeof(spd->vendorName)) != EOK) { + HDF_LOGE("memcpy_s fail."); + return HDF_ERR_IO; + } + buff += HDMI_SPD_VENDOR_NAME_LEN; + /* PB9~PB24 */ + if (memcpy_s(buff, (len - HDMI_INFOFRAME_PACKET_HEADER_LEN - HDMI_SPD_VENDOR_NAME_LEN), + spd->productDescription, sizeof(spd->productDescription)) != EOK) { + HDF_LOGE("memcpy_s fail."); + return HDF_ERR_IO; + } + buff += HDMI_SPD_PRODUCT_DESCRIPTION_LEN; + /* PB25 */ + buff[0] = spd->sdi; + HdmiInfoframeFillCheckSum(data, lenght); + return HDF_SUCCESS; +} + +static int32_t HdmiInfoframePacketAudioEncoding(union HdmiInfoframeInfo *infoframe, uint8_t *data, uint32_t len) +{ + uint32_t lenght; + uint8_t *buff = data; + struct HdmiAudioInfoframe *audio = &(infoframe->audio); + + lenght = HDMI_INFOFRAME_PACKET_HEADER_LEN + audio->len; + if (len < lenght) { + HDF_LOGE("len = %d, val is too small.", len); + return HDF_ERR_INVALID_PARAM; + } + if (memset_s(buff, len, 0, len) != EOK) { + HDF_LOGE("memset_s fail."); + return HDF_ERR_IO; + } + + HdmiInfoframeFillHeader(&(infoframe->header), data, len); + buff += HDMI_INFOFRAME_PACKET_HEADER_LEN; + /* PB1 */ + buff[0] |= (audio->codingType & HDMI_AUDIO_CODING_TYPE_MARK) << HDMI_AUDIO_CODING_TYPE_SHIFT; + buff[0] |= (audio->channelCount & HDMI_AUDIO_CHANNEL_COUNT_MARK); + /* PB2 */ + buff[1] |= (audio->sampleFreq & HDMI_AUDIO_SAMPLE_FREQUENCY_MARK) << HDMI_AUDIO_SAMPLE_FREQUENCY_SHIFT; + buff[1] |= (audio->sampleSize & HDMI_AUDIO_SAMPLE_SIZE_MARK); + /* PB3 */ + buff[2] |= (audio->codingExtType & HDMI_AUDIO_CXT_MARK); + /* PB4 */ + buff[3] |= audio->channelAllocation; + /* PB5 */ + buff[4] |= (audio->levelShiftValue & HDMI_AUDIO_LEVEL_SHIFT_VALUE_MARK) << HDMI_AUDIO_LEVEL_SHIFT_VALUE_SHIFT; + buff[4] |= (audio->playBackLevel & HDMI_AUDIO_LEF_PLAYBACK_LEVEL_MARK); + if (audio->dmInh == true) { + buff[4] |= (1 << HDMI_AUDIO_DM_INH_SHIFT); + } + HdmiInfoframeFillCheckSum(data, lenght); + return HDF_SUCCESS; +} + +static int32_t HdmiInfoframePacketDrmEncoding(union HdmiInfoframeInfo *infoframe, uint8_t *data, uint32_t len) +{ + uint32_t lenght; + uint8_t *buff = data; + struct HdmiDrmInfoframe *drm = &(infoframe->drm); + struct HdmiStaticMetadataDescriptor1st *des = &(drm->des.type1); + + lenght = HDMI_INFOFRAME_PACKET_HEADER_LEN + drm->len; + if (len < lenght) { + HDF_LOGE("len = %d, val is too small.", len); + return HDF_ERR_INVALID_PARAM; + } + if (memset_s(buff, len, 0, len) != EOK) { + HDF_LOGE("memset_s fail."); + return HDF_ERR_IO; + } + + HdmiInfoframeFillHeader(&(infoframe->header), data, len); + buff += HDMI_INFOFRAME_PACKET_HEADER_LEN; + /* PB1 */ + buff[0] = drm->eotfType; + /* PB2 */ + buff[1] = drm->metadataType; + /* PB3 */ + buff[2] = (uint8_t)(des->displayPrimaries0X & HDMI_DRM_METADATA_MARK); + /* PB4 */ + buff[3] = (uint8_t)((des->displayPrimaries0X >> HDMI_DRM_METADATA_SHIFT) & HDMI_DRM_METADATA_MARK); + /* PB5 */ + buff[4] = (uint8_t)(des->displayPrimaries0Y & HDMI_DRM_METADATA_MARK); + /* PB6 */ + buff[5] = (uint8_t)((des->displayPrimaries0Y & HDMI_DRM_METADATA_MARK) & HDMI_DRM_METADATA_MARK); + /* PB7 */ + buff[6] = (uint8_t)(des->displayPrimaries1X & HDMI_DRM_METADATA_MARK); + /* PB8 */ + buff[7] = (uint8_t)((des->displayPrimaries1X & HDMI_DRM_METADATA_MARK) & HDMI_DRM_METADATA_MARK); + /* PB9 */ + buff[8] = (uint8_t)(des->displayPrimaries1Y & HDMI_DRM_METADATA_MARK); + /* PB10 */ + buff[9] = (uint8_t)((des->displayPrimaries1Y & HDMI_DRM_METADATA_MARK) & HDMI_DRM_METADATA_MARK); + /* PB11 */ + buff[10] = (uint8_t)(des->displayPrimaries2X & HDMI_DRM_METADATA_MARK); + /* PB12 */ + buff[11] = (uint8_t)((des->displayPrimaries2X & HDMI_DRM_METADATA_MARK) & HDMI_DRM_METADATA_MARK); + /* PB13 */ + buff[12] = (uint8_t)(des->displayPrimaries2Y & HDMI_DRM_METADATA_MARK); + /* PB14 */ + buff[13] = (uint8_t)((des->displayPrimaries2Y & HDMI_DRM_METADATA_MARK) & HDMI_DRM_METADATA_MARK); + /* PB15 */ + buff[14] = (uint8_t)(des->whitePointX & HDMI_DRM_METADATA_MARK); + /* PB16 */ + buff[15] = (uint8_t)((des->whitePointX & HDMI_DRM_METADATA_MARK) & HDMI_DRM_METADATA_MARK); + /* PB17 */ + buff[16] = (uint8_t)(des->whitePointY & HDMI_DRM_METADATA_MARK); + /* PB18 */ + buff[17] = (uint8_t)((des->whitePointY & HDMI_DRM_METADATA_MARK) & HDMI_DRM_METADATA_MARK); + /* PB19 */ + buff[18] = (uint8_t)(des->maxDisplayMasteringLuminance & HDMI_DRM_METADATA_MARK); + /* PB20 */ + buff[19] = (uint8_t)((des->maxDisplayMasteringLuminance & HDMI_DRM_METADATA_MARK) & HDMI_DRM_METADATA_MARK); + /* PB21 */ + buff[20] = (uint8_t)(des->minDisplayMasteringLuminance & HDMI_DRM_METADATA_MARK); + /* PB22 */ + buff[21] = (uint8_t)((des->minDisplayMasteringLuminance & HDMI_DRM_METADATA_MARK) & HDMI_DRM_METADATA_MARK); + /* PB23 */ + buff[22] = (uint8_t)(des->maxContentLightLevel & HDMI_DRM_METADATA_MARK); + /* PB24 */ + buff[23] = (uint8_t)((des->maxContentLightLevel & HDMI_DRM_METADATA_MARK) & HDMI_DRM_METADATA_MARK); + /* PB25 */ + buff[24] = (uint8_t)(des->maxFrameAverageLightLevel & HDMI_DRM_METADATA_MARK); + /* PB26 */ + buff[25] = (uint8_t)((des->maxFrameAverageLightLevel & HDMI_DRM_METADATA_MARK) & HDMI_DRM_METADATA_MARK); + HdmiInfoframeFillCheckSum(data, lenght); + return HDF_SUCCESS; +} + +static int32_t HdmiInfoframePacketEncoding(union HdmiInfoframeInfo *infoframe, + enum HdmiPacketType type, uint8_t *data, uint32_t len) +{ + int32_t ret; + + if (infoframe == NULL || data == NULL) { + HDF_LOGE("input param is invalid."); + return HDF_ERR_INVALID_PARAM; + } + + switch (type) { + case HDMI_INFOFRAME_PACKET_TYPE_VS: + ret = HdmiInfoframePacketVsEncoding(infoframe, data, len); + break; + case HDMI_INFOFRAME_PACKET_TYPE_AVI: + ret = HdmiInfoframePacketAviEncoding(infoframe, data, len); + break; + case HDMI_INFOFRAME_PACKET_TYPE_SPD: + ret = HdmiInfoframePacketSpdEncoding(infoframe, data, len); + break; + case HDMI_INFOFRAME_PACKET_TYPE_AUDIO: + ret = HdmiInfoframePacketAudioEncoding(infoframe, data, len); + break; + case HDMI_INFOFRAME_PACKET_TYPE_DRM: + ret = HdmiInfoframePacketDrmEncoding(infoframe, data, len); + break; + default: + HDF_LOGD("type %d not support.", type); + ret = HDF_ERR_NOT_SUPPORT; + } + return ret; +} + +static int32_t HdmiInfoframeSend(struct HdmiInfoframe *frame, union HdmiInfoframeInfo *infoframe) +{ + uint8_t buffer[HDMI_INFOFRAME_LEN] = {0}; + struct HdmiCntlr *cntlr = NULL; + int32_t ret; + + if (frame == NULL || frame->priv == NULL || infoframe == NULL) { + HDF_LOGE("HdmiInfoframeSend: input param is invalid."); + return HDF_ERR_INVALID_PARAM; + } + cntlr = (struct HdmiCntlr *)frame->priv; + if (cntlr->ops == NULL || cntlr->ops->infoframeSend == NULL || cntlr->ops->infoframeEnable == NULL) { + HDF_LOGD("HdmiInfoframeSend not support."); + return HDF_ERR_NOT_SUPPORT; + } + + ret = HdmiInfoframePacketEncoding(infoframe, infoframe->header.type, buffer, HDMI_INFOFRAME_LEN); + if (ret != HDF_SUCCESS) { + HDF_LOGE("encding infoframe %d fail", infoframe->header.type); + return ret; + } + + HdmiCntlrLock(cntlr); + cntlr->ops->infoframeEnable(cntlr, infoframe->header.type, false); + ret = cntlr->ops->infoframeSend(cntlr, infoframe->header.type, buffer, HDMI_INFOFRAME_LEN); + if (ret != HDF_SUCCESS) { + HDF_LOGE("send infoframe %d fail", infoframe->header.type); + HdmiCntlrUnlock(cntlr); + return ret; + } + cntlr->ops->infoframeEnable(cntlr, infoframe->header.type, true); + HdmiCntlrUnlock(cntlr); + return HDF_SUCCESS; +} + +static void HdmiFillAviHdrInfoframe(struct HdmiAviInfoframe *avi, + struct HdmiVideoAttr *videoAttr, struct HdmiHdrAttr *HdrAttr, struct HdmiCommonAttr *commAttr) +{ + switch (HdrAttr->mode) { + case HDMI_HDR_MODE_CEA_861_3: + case HDMI_HDR_MODE_CEA_861_3_AUTHEN: + avi->colorimetry = videoAttr->colorimetry; + avi->extColorimetry = videoAttr->extColorimetry; + avi->colorSpace = commAttr->colorSpace; + if (HdrAttr->mode == HDMI_HDR_MODE_CEA_861_3_AUTHEN) { + avi->colorSpace = HDMI_COLOR_SPACE_YCBCR422; + } + avi->range = videoAttr->quantization; + avi->yccRange = videoAttr->yccQuantization; + break; + case HDMI_HDR_MODE_DOLBY_NORMAL: + avi->colorSpace = HDMI_COLOR_SPACE_YCBCR422; + avi->colorimetry = (videoAttr->xvycc == true) ? HDMI_COLORIMETRY_EXTENDED : videoAttr->colorimetry; + avi->extColorimetry = videoAttr->extColorimetry; + avi->range = videoAttr->quantization; + avi->yccRange = HDMI_YCC_QUANTIZATION_RANGE_FULL; + break; + case HDMI_HDR_MODE_DOLBY_TUNNELING: + avi->colorSpace = HDMI_COLOR_SPACE_RGB; + avi->colorimetry = (videoAttr->xvycc == true) ? HDMI_COLORIMETRY_EXTENDED : videoAttr->colorimetry; + avi->extColorimetry = videoAttr->extColorimetry; + avi->range = HDMI_QUANTIZATION_RANGE_FULL; + avi->yccRange = videoAttr->yccQuantization; + break; + default: + avi->colorSpace = commAttr->colorSpace; + avi->colorimetry = (videoAttr->xvycc == true) ? HDMI_COLORIMETRY_EXTENDED : videoAttr->colorimetry; + avi->extColorimetry = videoAttr->extColorimetry; + avi->range = videoAttr->quantization; + avi->yccRange = videoAttr->yccQuantization; + break; + } +} + +static void HdmiFillAviInfoframeVersion(struct HdmiAviInfoframe *avi) +{ + /* + * see hdmi spec2.0 10.1. + * The Y2 and VIC7 bits are simply set to zero in a Version 2 AVI InfoFrame and might not be decoded by + * some Sinks. A Version 3 AVI InfoFrame shall be used and the Version field set to 0x03 (indicating that + * the Sink shall decode the additional most-significant bits) whenever either of the most-significant bits + * Y2 or VIC7 are set to '1'. If both Y2 and VIC7 are set to '0', then a Version 2 AVI InfoFrame shall be used + * and the Version field shall be set to 0x02 (indicating that the Sink does not have to decode the additional + * most-significant bits). + */ + avi->verNum = HDMI_AVI_VERSION2; + if (((uint32_t)avi->colorSpace & HDMI_AVI_Y2_MASK) > 0 || + (avi->vic > HDMI_VIC_5120X2160P100_64_27)) { + avi->verNum = HDMI_AVI_VERSION3; + } else if (avi->colorimetry == HDMI_COLORIMETRY_EXTENDED && + avi->extColorimetry == HDMI_EXTENDED_COLORIMETRY_ADDITIONAL) { + /* + * (C1,C0) is (1,1) and (EC2,EC1,EC0) is (1,1,1), version shall be 4. + * All fields of the Version 4 AVI InfoFrame are the same as Version 3 AVI InfoFrame, + * except for the InfoFrame Version Number, Length of AVI InfoFrame, and additional Data Byte 14. + */ + avi->verNum = HDMI_AVI_VERSION4; + (avi->len)++; + } +} + +static void HdmiFillAviInfoframe(struct HdmiAviInfoframe *avi, + struct HdmiVideoAttr *videoAttr, struct HdmiHdrAttr *HdrAttr, struct HdmiCommonAttr *commAttr) +{ + bool enable3d; + + if (memset_s(avi, sizeof(struct HdmiAviInfoframe), 0, sizeof(struct HdmiAviInfoframe)) != EOK) { + HDF_LOGE("fill vsif, memset_s fail."); + return; + } + avi->type = HDMI_INFOFRAME_PACKET_TYPE_AVI; + avi->len = HDMI_AVI_INFOFRAME_LEN; + + avi->activeFormatInformationPresent = true; + avi->colorSpace = commAttr->colorSpace; + avi->activeAspect = videoAttr->activeAspect; + avi->pictureAspect = videoAttr->aspect; + avi->colorimetry = (videoAttr->xvycc == true) ? HDMI_COLORIMETRY_EXTENDED : videoAttr->colorimetry; + avi->nups = videoAttr->nups; + + avi->range = videoAttr->quantization; + avi->extColorimetry = videoAttr->extColorimetry; + enable3d = (videoAttr->_3dStruct >= HDMI_VS_VIDEO_3D_BUTT) ? false : true; + avi->vic = HdmiCommonGetVic(videoAttr->timing, videoAttr->aspect, enable3d); + avi->pixelRepetitionFactor = (uint8_t)videoAttr->pixelRepeat; + avi->yccRange = videoAttr->yccQuantization; + HdmiFillAviHdrInfoframe(avi, videoAttr, HdrAttr, commAttr); + HdmiFillAviInfoframeVersion(avi); +} + +int32_t HdmiAviInfoframeSend(struct HdmiInfoframe *frame, bool enable) +{ + struct HdmiCntlr *cntlr = NULL; + union HdmiInfoframeInfo infoframe = {0}; + + if (frame == NULL || frame->priv == NULL) { + HDF_LOGE("HdmiAviInfoframeSend: input param is invalid."); + return HDF_ERR_INVALID_PARAM; + } + cntlr = (struct HdmiCntlr *)frame->priv; + if (cntlr->ops == NULL || cntlr->ops->infoframeEnable == NULL || cntlr->ops->infoframeSend == NULL) { + HDF_LOGD("HdmiAviInfoframeSend not support."); + return HDF_ERR_NOT_SUPPORT; + } + + if (enable == false) { + cntlr->ops->infoframeEnable(cntlr, HDMI_INFOFRAME_PACKET_TYPE_AVI, false); + return HDF_SUCCESS; + } + HdmiFillAviInfoframe(&(frame->avi), &(cntlr->attr.videoAttr), &(cntlr->attr.hdrAttr), &(cntlr->attr.commAttr)); + infoframe.avi = frame->avi; + return HdmiInfoframeSend(frame, &infoframe); +} + +void HdmiFillAudioInfoframe(struct HdmiAudioInfoframe *audio, struct HdmiAudioAttr *audioAttr) +{ + if (memset_s(audio, sizeof(struct HdmiAudioInfoframe), 0, sizeof(struct HdmiAudioInfoframe)) != EOK) { + HDF_LOGE("fill vsif, memset_s fail."); + return; + } + audio->type = HDMI_INFOFRAME_PACKET_TYPE_AUDIO; + audio->len = HDMI_AUDIO_INFOFRAME_LEN; + audio->verNum = HDMI_AUDIO_INFOFRAME_VERSION; + + /* fill channels. */ + if (audioAttr->ifType != HDMI_AUDIO_IF_TYPE_I2S) { + HDF_LOGI("audio channel refer to stream."); + } else { + HDF_LOGI("audio channel %u \n", audioAttr->channels); + audio->channelCount = (audioAttr->channels >= 2) ? (audioAttr->channels - 1) : 0; + } + + /* fill coding type. */ + if (audioAttr->codingType == HDMI_AUDIO_CODING_TYPE_AC3 || audioAttr->codingType == HDMI_AUDIO_CODING_TYPE_DTS || + audioAttr->codingType == HDMI_AUDIO_CODING_TYPE_EAC3 || audioAttr->codingType == HDMI_AUDIO_CODING_TYPE_DTS_HD) { + audio->codingType = audioAttr->codingType; + } else { + audio->codingType = HDMI_AUDIO_CODING_TYPE_STREAM; + } + + /* fill CA field. see CEA-861-D table 20. */ + switch (audioAttr->channels) { + case HDMI_AUDIO_FORMAT_CHANNEL_3: + audio->channelAllocation = 0x01; /* 1 channel */ + break; + case HDMI_AUDIO_FORMAT_CHANNEL_6: + audio->channelAllocation = 0x0b; /* 3, 4 channel */ + break; + case HDMI_AUDIO_FORMAT_CHANNEL_8: + audio->channelAllocation = 0x13; /* 1, 2, 5 channel */ + break; + default: + audio->channelAllocation = 0x00; /* 0 channel */ + break; + } +} + +int32_t HdmiAudioInfoframeSend(struct HdmiInfoframe *frame, bool enable) +{ + struct HdmiCntlr *cntlr = NULL; + union HdmiInfoframeInfo infoframe = {0}; + + if (frame == NULL || frame->priv == NULL) { + HDF_LOGE("HdmiAudioInfoframeSend: input param is invalid."); + return HDF_ERR_INVALID_PARAM; + } + cntlr = (struct HdmiCntlr *)frame->priv; + if (cntlr->ops == NULL || cntlr->ops->infoframeEnable == NULL) { + HDF_LOGD("HdmiAudioInfoframeSend not support."); + return HDF_ERR_NOT_SUPPORT; + } + + if (enable == false) { + HdmiCntlrLock(cntlr); + cntlr->ops->infoframeEnable(cntlr, HDMI_INFOFRAME_PACKET_TYPE_AUDIO, false); + HdmiCntlrUnlock(cntlr); + return HDF_SUCCESS; + } + HdmiFillAudioInfoframe(&(frame->audio), &(cntlr->attr.audioAttr)); + infoframe.audio = frame->audio; + return HdmiInfoframeSend(frame, &infoframe); +} + +static void HdmiFillDrmInfoframe(struct HdmiDrmInfoframe *drm, struct HdmiHdrAttr *HdrAttr) +{ + if (memset_s(drm, sizeof(struct HdmiDrmInfoframe), 0, sizeof(struct HdmiDrmInfoframe)) != EOK) { + HDF_LOGE("fill vsif, memset_s fail."); + return; + } + drm->type = HDMI_INFOFRAME_PACKET_TYPE_DRM; + drm->len = HDMI_DRM_INFOFRAME_LEN; + drm->verNum = HDMI_DRM_INFOFRAME_VERSION; + drm->eotfType = HdrAttr->eotfType; + drm->metadataType = HdrAttr->metadataType; + drm->des = HdrAttr->descriptor; +} + +int32_t HdmiDrmInfoframeSend(struct HdmiInfoframe *frame, bool enable) +{ + struct HdmiCntlr *cntlr = NULL; + union HdmiInfoframeInfo infoframe = {0}; + + if (frame == NULL || frame->priv == NULL) { + HDF_LOGE("HdmiDrmInfoframeSend: input param is invalid."); + return HDF_ERR_INVALID_PARAM; + } + cntlr = (struct HdmiCntlr *)frame->priv; + if (cntlr->ops == NULL || cntlr->ops->infoframeEnable == NULL) { + HDF_LOGD("HdmiDrmInfoframeSend not support."); + return HDF_ERR_NOT_SUPPORT; + } + + if (enable == false) { + cntlr->ops->infoframeEnable(cntlr, HDMI_INFOFRAME_PACKET_TYPE_DRM, false); + return HDF_SUCCESS; + } + HdmiFillDrmInfoframe(&(frame->drm), &(cntlr->attr.hdrAttr)); + infoframe.drm = frame->drm; + return HdmiInfoframeSend(frame, &infoframe); +} + +static uint8_t HdmiGetVsifLength(struct HdmiVs14VsifContent *_14Vsif, bool dolbyEnable, bool hdrSupport) +{ + uint8_t length = 0x07; + + if (hdrSupport == true) { + if (dolbyEnable == true) { + length = 0x18; + } else if (_14Vsif->format == HDMI_VS_VIDEO_FORMAT_4K) { + length = 0x05; + } else if (_14Vsif->format == HDMI_VS_VIDEO_FORMAT_3D) { + length = 0x07; + } else { + length = 0x04; + } + } + return length; +} + +static void HdmiFill14Vsif(struct HdmiVsInfoframe *vs, struct HdmiVideoAttr *videoAttr) +{ + struct HdmiVideo4kInfo *_4kInfo = NULL; + struct HdmiVs14VsifContent *_14Vsif = &(vs->vsifContent._14Vsif); + enum HdmiVic vic; + uint32_t cnt; + + _14Vsif->oui = HDMI_IEEE_OUI_1_4; + vic = HdmiCommonGetVic(videoAttr->timing, videoAttr->aspect, false); + if ((vic == HDMI_VIC_3840X2160P24_16_9 || vic == HDMI_VIC_3840X2160P25_16_9 || + vic == HDMI_VIC_3840X2160P30_16_9 || vic == HDMI_VIC_4096X2160P24_256_135) && + videoAttr->_3dStruct == HDMI_VS_VIDEO_3D_BUTT) { + _14Vsif->format = HDMI_VS_VIDEO_FORMAT_4K; + for (cnt = 0; cnt <= HDMI_VIDEO_4K_CODES_MAX; cnt++) { + _4kInfo = HdmiCommonGetVideo4kInfo(cnt); + if (_4kInfo != NULL && _4kInfo->timing == videoAttr->timing) { + _14Vsif->vic = _4kInfo->_4kVic; + break; + } + } + } else if (videoAttr->_3dStruct < HDMI_VS_VIDEO_3D_BUTT) { // common 3D + _14Vsif->format = HDMI_VS_VIDEO_FORMAT_3D; + _14Vsif->_3dStruct = videoAttr->_3dStruct; + } else { + _14Vsif->format = HDMI_VS_VIDEO_FORMAT_NULL; + _14Vsif->_3dStruct = videoAttr->_3dStruct; + } +} + +static void HdmiFillVsInfoframe(struct HdmiInfoframe *frame, struct HdmiVideoAttr *videoAttr, + bool dolbyEnable, bool hdrSupport) +{ + struct HdmiVsInfoframe *vs = &(frame->vs); + int32_t ret; + + ret = memset_s(vs, sizeof(struct HdmiVsInfoframe), 0, sizeof(struct HdmiVsInfoframe)); + if (ret != EOK) { + HDF_LOGE("fill vsif, memset_s fail."); + return; + } + vs->type = HDMI_INFOFRAME_PACKET_TYPE_VS; + vs->verNum = HDMI_VSIF_VERSION; + HdmiFill14Vsif(vs, videoAttr); + vs->len = HdmiGetVsifLength(&(vs->vsifContent._14Vsif), dolbyEnable, hdrSupport); + /* fill user vendor data */ + vs->vsifContent.userVsif.len = frame->userVsif.len; + ret = memcpy_s(vs->vsifContent.userVsif.data, HDMI_VENDOR_USER_DATA_MAX_LEN, + frame->userVsif.data, frame->userVsif.len); + if (ret != EOK) { + HDF_LOGE("fill vsif, memcpy_s fail."); + } +} + +int32_t HdmiVsInfoframeSend(struct HdmiInfoframe *frame, bool enable, bool dolbyEnable) +{ + struct HdmiCntlr *cntlr = NULL; + union HdmiInfoframeInfo infoframe = {0}; + + if (frame == NULL || frame->priv == NULL) { + HDF_LOGE("HdmiVsInfoframeSend: input param is invalid."); + return HDF_ERR_INVALID_PARAM; + } + cntlr = (struct HdmiCntlr *)frame->priv; + if (cntlr->ops == NULL || cntlr->ops->infoframeEnable == NULL) { + HDF_LOGD("HdmiVsInfoframeSend not support."); + return HDF_ERR_NOT_SUPPORT; + } + + if (enable == false) { + cntlr->ops->infoframeEnable(cntlr, HDMI_INFOFRAME_PACKET_TYPE_VS, false); + return HDF_SUCCESS; + } + HdmiFillVsInfoframe(frame, &(cntlr->attr.videoAttr), dolbyEnable, frame->hdrSupport); + infoframe.vs = frame->vs; + return HdmiInfoframeSend(frame, &infoframe); +} + +static void HdmiFillSpdInfoframe(struct HdmiSpdInfoframe *spd, char *vendorName, + char *productName, enum HdmiSpdSdi sdi) +{ + uint32_t len, length; + + if (memset_s(spd, sizeof(struct HdmiSpdInfoframe), 0, sizeof(struct HdmiSpdInfoframe)) != EOK) { + HDF_LOGE("fill spd infoframe, memset_s fail."); + return; + } + spd->type = HDMI_INFOFRAME_PACKET_TYPE_SPD; + spd->len = HDMI_SPD_INFOFRAME_LEN; + spd->verNum = HDMI_SPD_VERSION; + spd->sdi = sdi; + + len = (uint32_t)strlen(vendorName); + length = (uint32_t)sizeof(spd->vendorName); + length = (length > len) ? len : length; + if (memcpy_s(spd->vendorName, length, vendorName, length) != EOK) { + HDF_LOGE("fill spd infoframe vendor name, memcpy_s fail."); + } + + len = (uint32_t)strlen(productName); + length = (uint32_t)sizeof(spd->productDescription); + length = (length > len) ? len : length; + if (memcpy_s(spd->productDescription, length, productName, length) != EOK) { + HDF_LOGE("fill spd infoframe product name, memcpy_s fail."); + } +} + +int32_t HdmiSpdInfoframeSend(struct HdmiInfoframe *frame, bool enable, + char *vendorName, char *productName, enum HdmiSpdSdi sdi) +{ + struct HdmiCntlr *cntlr = NULL; + union HdmiInfoframeInfo infoframe = {0}; + + if (frame == NULL || frame->priv == NULL) { + HDF_LOGE("HdmiSpdInfoframeSend: input param is invalid."); + return HDF_ERR_INVALID_PARAM; + } + cntlr = (struct HdmiCntlr *)frame->priv; + if (cntlr->ops == NULL || cntlr->ops->infoframeEnable == NULL) { + HDF_LOGD("HdmiSpdInfoframeSend not support."); + return HDF_ERR_NOT_SUPPORT; + } + + if (enable == false) { + cntlr->ops->infoframeEnable(cntlr, HDMI_INFOFRAME_PACKET_TYPE_SPD, false); + return HDF_SUCCESS; + } + HdmiFillSpdInfoframe(&(frame->spd), vendorName, productName, sdi); + infoframe.spd = frame->spd; + return HdmiInfoframeSend(frame, &infoframe); +} + +int32_t HdmiInfoframeGetInfo(struct HdmiInfoframe *frame, enum HdmiPacketType type, + union HdmiInfoframeInfo *infoframe) +{ + if (frame == NULL || infoframe == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + switch (type) { + case HDMI_INFOFRAME_PACKET_TYPE_VS : + infoframe->vs = frame->vs; + break; + case HDMI_INFOFRAME_PACKET_TYPE_AVI : + infoframe->avi = frame->avi; + break; + case HDMI_INFOFRAME_PACKET_TYPE_AUDIO : + infoframe->audio = frame->audio; + break; + case HDMI_INFOFRAME_PACKET_TYPE_DRM : + infoframe->drm = frame->drm; + break; + default : + HDF_LOGD("infoframe %d not support get", type); + return HDF_ERR_INVALID_PARAM; + } + return HDF_SUCCESS; +} + +int32_t HdmiInfoframeSetInfo(struct HdmiInfoframe *frame, enum HdmiPacketType type, + union HdmiInfoframeInfo *infoframe) +{ + if (frame == NULL || infoframe == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + switch (type) { + case HDMI_INFOFRAME_PACKET_TYPE_VS : + frame->vs = infoframe->vs; + break; + case HDMI_INFOFRAME_PACKET_TYPE_AVI : + frame->avi = infoframe->avi; + break; + case HDMI_INFOFRAME_PACKET_TYPE_AUDIO : + frame->audio = infoframe->audio; + break; + case HDMI_INFOFRAME_PACKET_TYPE_DRM : + frame->drm = infoframe->drm; + break; + default : + HDF_LOGD("infoframe %d not support set", type); + return HDF_ERR_INVALID_PARAM; + } + return HDF_SUCCESS; +} \ No newline at end of file diff --git a/support/platform/src/hdmi/hdmi_ncts.c b/support/platform/src/hdmi/hdmi_ncts.c new file mode 100644 index 00000000..78a05078 --- /dev/null +++ b/support/platform/src/hdmi/hdmi_ncts.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdmi_ncts.h" + +#define HDF_LOG_TAG hdmi_ncts_c + +#define HDMI_NCTS_INVALID_VALUE 0xffffffff + +/* + * see hdmi1.4 table 7-1กข7-2กข7-3. + * The exact relationship: 128 * fs = tmdsClock * N / CTS. + */ +static struct HdmiAudioNCts g_audioNctsMap[] = { + { 32000, 25174, 4576, 28125 }, + { 32000, 25200, 4096, 25200 }, + { 32000, 27000, 4096, 27000 }, + { 32000, 27027, 4096, 27027 }, + { 32000, 54000, 4096, 54000 }, + { 32000, 54054, 4096, 54054 }, + { 32000, 74175, 11648, 210937}, + { 32000, 74250, 4096, 74250 }, + { 32000, 148351, 11648, 421875 }, + { 32000, 148500, 4096, 148500 }, + { 32000, 296703, 5824, 421875 }, + { 32000, 297000, 3072, 222750 }, + { 32000, 593406, 5824, 843750 }, + { 32000, 594000, 3072, 445500 }, + { 32000, 0, 4096, 0 }, + { 44100, 25174, 7007, 31250 }, + { 44100, 25200, 6272, 28000 }, + { 44100, 27000, 6272, 30000 }, + { 44100, 27027, 6272, 30030 }, + { 44100, 54000, 6272, 60000 }, + { 44100, 54054, 6272, 60060 }, + { 44100, 74175, 17836, 234375 }, + { 44100, 74250, 6272, 82500 }, + { 44100, 148351, 8918, 234375 }, + { 44100, 148500, 6272, 165000 }, + { 44100, 296703, 4459, 234375 }, + { 44100, 297000, 4704, 247500 }, + { 44100, 593406, 8918, 937500 }, + { 44100, 594000, 9408, 990000 }, + { 44100, 0, 6272, 0 }, + { 48000, 25174, 6864, 28125 }, + { 48000, 25200, 6144, 25200 }, + { 48000, 27000, 6144, 27000 }, + { 48000, 27027, 6144, 27027 }, + { 48000, 54000, 6144, 54000 }, + { 48000, 54054, 6144, 54054 }, + { 48000, 74175, 11648, 140625 }, + { 48000, 74250, 6144, 74250 }, + { 48000, 148351, 5824, 140625 }, + { 48000, 148500, 6144, 148500 }, + { 48000, 296703, 5824, 281250 }, + { 48000, 297000, 5120, 247500 }, + { 48000, 593406, 5824, 562500 }, + { 48000, 594000, 6144, 594000 }, + { 48000, 0, 6144, 0 } + }; + +uint32_t HdmiGetN(uint32_t sampleRate, uint32_t tmdsClock) +{ + uint32_t i; + + for (i = 0;i < sizeof(g_audioNctsMap) / sizeof(g_audioNctsMap[0]); i++) { + if (g_audioNctsMap[i].sampleRate == sampleRate && + g_audioNctsMap[i].tmdsClock == tmdsClock) { + return g_audioNctsMap[i].n; + } + if (g_audioNctsMap[i].sampleRate == sampleRate && + g_audioNctsMap[i].tmdsClock >= (tmdsClock - HDMI_NCTS_TMDS_DEVIATION) && + g_audioNctsMap[i].tmdsClock <= (tmdsClock + HDMI_NCTS_TMDS_DEVIATION)) { + return g_audioNctsMap[i].n; + } + if (g_audioNctsMap[i].sampleRate == sampleRate && + g_audioNctsMap[i].tmdsClock == 0) { + return g_audioNctsMap[i].n; + } + } + return HDMI_NCTS_N_DEFAULT; +} + +uint32_t HdmiGetCts(uint32_t sampleRate, uint32_t tmdsClock) +{ + uint32_t i; + uint32_t tmpN = HDMI_NCTS_INVALID_VALUE; + uint32_t tmpCts = HDMI_NCTS_INVALID_VALUE; + + for (i = 0;i < sizeof(g_audioNctsMap) / sizeof(g_audioNctsMap[0]); i++) { + if (g_audioNctsMap[i].sampleRate == sampleRate && + g_audioNctsMap[i].tmdsClock == tmdsClock) { + tmpN = g_audioNctsMap[i].n; + tmpCts = g_audioNctsMap[i].cts; + break; + } + if (g_audioNctsMap[i].sampleRate == sampleRate && + g_audioNctsMap[i].tmdsClock >= (tmdsClock - HDMI_NCTS_TMDS_DEVIATION) && + g_audioNctsMap[i].tmdsClock <= (tmdsClock + HDMI_NCTS_TMDS_DEVIATION)) { + tmpN = g_audioNctsMap[i].n; + tmpCts = g_audioNctsMap[i].cts; + break; + } + if (g_audioNctsMap[i].sampleRate == sampleRate && + g_audioNctsMap[i].tmdsClock == 0) { + tmpN = g_audioNctsMap[i].n; + tmpCts = g_audioNctsMap[i].cts; + break; + } + } + + if (tmpCts == 0 && sampleRate >= 1000) { + tmpCts = (tmpN / HDMI_NCTS_FACTOR) * tmdsClock * 10 / (sampleRate / 1000); + } else if (tmpCts == HDMI_NCTS_INVALID_VALUE && sampleRate >= 1000) { + tmpCts = (HDMI_NCTS_N_DEFAULT / HDMI_NCTS_FACTOR) * tmdsClock * 10 / (sampleRate / 1000); + } + return tmpCts; +} diff --git a/support/platform/src/hdmi/hdmi_scdc.c b/support/platform/src/hdmi/hdmi_scdc.c new file mode 100644 index 00000000..2b74f920 --- /dev/null +++ b/support/platform/src/hdmi/hdmi_scdc.c @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. + * + * HDF is dual licensed: you can use it either under the terms of + * the GPL, or the BSD license, at your option. + * See the LICENSE file in the root of this repository for complete details. + */ + +#include "hdf_log.h" +#include "hdmi_core.h" + +#define HDF_LOG_TAG hdmi_scdc_c + +#define HDMI_SCDC_READ_SOURCE_VERSION_TIMES 2 + +int32_t HdmiScdcRead(struct HdmiScdc *scdc, enum HdmiScdcsOffset offset, uint8_t *buffer, uint32_t len) +{ + struct HdmiDdcCfg cfg = {0}; + struct HdmiCntlr *cntlr = NULL; + + if (scdc == NULL || scdc->priv == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + cntlr = (struct HdmiCntlr *)scdc->priv; + cfg.type = HDMI_DDC_DEV_SCDC; + cfg.readFlag = true; + cfg.devAddr = HDMI_DDC_SCDC_DEV_ADDRESS; + cfg.data = buffer; + cfg.dataLen = len; + cfg.offset = offset; + cfg.mode = HDMI_DDC_MODE_READ_MUTIL_NO_ACK; + return HdmiDdcTransfer(&(cntlr->ddc), &cfg); +} + +int32_t HdmiScdcWrite(struct HdmiScdc *scdc, enum HdmiScdcsOffset offset, uint8_t *buffer, uint32_t len) +{ + struct HdmiDdcCfg cfg = {0}; + struct HdmiCntlr *cntlr = NULL; + + if (scdc == NULL || scdc->priv == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + cntlr = (struct HdmiCntlr *)scdc->priv; + cfg.type = HDMI_DDC_DEV_SCDC; + cfg.readFlag = false; + cfg.devAddr = HDMI_DDC_SCDC_DEV_ADDRESS; + cfg.data = buffer; + cfg.dataLen = len; + cfg.offset = offset; + cfg.mode = HDMI_DDC_MODE_WRITE_MUTIL_ACK; + return HdmiDdcTransfer(&(cntlr->ddc), &cfg); +} + +int32_t HdmiScdcReadByte(struct HdmiScdc *scdc, enum HdmiScdcsOffset offset, uint8_t *byte) +{ + return HdmiScdcRead(scdc, offset, byte, sizeof(*byte)); +} + +int32_t HdmiScdcWriteByte(struct HdmiScdc *scdc, enum HdmiScdcsOffset offset, uint8_t *byte) +{ + return HdmiScdcWrite(scdc, offset, byte, sizeof(*byte)); +} + +/* read opt */ +int32_t HdmiScdcReadSinkVersion(struct HdmiScdc *scdc, uint8_t *sinkVer) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_SINK_VERSION, sinkVer); +} + +int32_t HdmiScdcReadSourceVersion(struct HdmiScdc *scdc, uint8_t *srcVer) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_SOURCE_VERSION, srcVer); +} + +int32_t HdmiScdcReadUpdate0(struct HdmiScdc *scdc, uint8_t *flag) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_UPDATE_0, flag); +} + +int32_t HdmiScdcReadScramblerStatus(struct HdmiScdc *scdc, uint8_t *status) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_SCRAMBLER_STATUS, status); +} + +int32_t HdmiScdcReadTmdsConfig(struct HdmiScdc *scdc, uint8_t *tmdsCfg) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_TMDS_CONFIG, tmdsCfg); +} + +int32_t HdmiScdcReadConfig0(struct HdmiScdc *scdc, uint8_t *cfg) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_CONFIG_0, cfg); +} + +int32_t HdmiScdcReadConfig1(struct HdmiScdc *scdc, uint8_t *cfg) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_CONFIG_1, cfg); +} + +int32_t HdmiScdcReadTestConfig0(struct HdmiScdc *scdc, uint8_t *testCfg) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_TEST_CONFIG_0, testCfg); +} + +int32_t HdmiScdcReadTestConfig1(struct HdmiScdc *scdc, uint8_t *testCfg) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_TEST_CONFIG_1, testCfg); +} + +int32_t HdmiScdcReadStatusFlag0(struct HdmiScdc *scdc, uint8_t *flag) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_STASTUS_FLAG_0, flag); +} + +int32_t HdmiScdcReadStatusFlag1(struct HdmiScdc *scdc, uint8_t *flag) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_STASTUS_FLAG_1, flag); +} + +int32_t HdmiScdcReadStatusFlag2(struct HdmiScdc *scdc, uint8_t *flag) +{ + return HdmiScdcReadByte(scdc, HDMI_SCDCS_OFFSET_STASTUS_FLAG_2, flag); +} + +/* write opt */ +int32_t HdmiScdcWriteSourceVersion(struct HdmiScdc *scdc, uint8_t *srcVer) +{ + return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_SOURCE_VERSION, srcVer); +} + +int32_t HdmiScdcWriteUpdate0(struct HdmiScdc *scdc, uint8_t *flag) +{ + return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_UPDATE_0, flag); +} + +int32_t HdmiScdcWriteTmdsConfig(struct HdmiScdc *scdc, uint8_t *tmdsCfg) +{ + return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_TMDS_CONFIG, tmdsCfg); +} + +int32_t HdmiScdcWriteConfig0(struct HdmiScdc *scdc, uint8_t *cfg) +{ + return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_CONFIG_0, cfg); +} + +int32_t HdmiScdcWriteConfig1(struct HdmiScdc *scdc, uint8_t *cfg) +{ + return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_CONFIG_1, cfg); +} + +int32_t HdmiScdcWriteTestConfig0(struct HdmiScdc *scdc, uint8_t *testCfg) +{ + return HdmiScdcWriteByte(scdc, HDMI_SCDCS_OFFSET_TEST_CONFIG_0, testCfg); +} + +/* cntlr ops */ +bool HdmiCntlrScdcSourceScrambleGet(struct HdmiCntlr *cntlr) +{ + bool ret; + + if (cntlr == NULL || cntlr->ops == NULL || cntlr->ops->scdcSourceScrambleGet == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + HdmiCntlrLock(cntlr); + ret = cntlr->ops->scdcSourceScrambleGet(cntlr); + HdmiCntlrUnlock(cntlr); + return ret; +} + +int32_t HdmiCntlrScdcSourceScrambleSet(struct HdmiCntlr *cntlr, bool enable) +{ + int32_t ret; + + if (cntlr == NULL || cntlr->ops == NULL || cntlr->ops->scdcSourceScrambleSet == NULL) { + return HDF_ERR_INVALID_OBJECT; + } + HdmiCntlrLock(cntlr); + ret = cntlr->ops->scdcSourceScrambleSet(cntlr, enable); + HdmiCntlrUnlock(cntlr); + return ret; +} + +/* scdc opt */ +int32_t HdmiScdcRrDisable(struct HdmiScdc *scdc) +{ + union HdmiScdcsConfig0 cfg = {0}; + union HdmiScdcsTestConfig0 testCfg = {0}; + int32_t ret; + + if (scdc == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + ret = HdmiScdcWriteConfig0(scdc, &(cfg.data)); + if (ret != HDF_SUCCESS) { + HDF_LOGE("scdc write config0 fail"); + return ret; + } + scdc->status.cfg0 = cfg; + + ret = HdmiScdcWriteTestConfig0(scdc, &(testCfg.data)); + if (ret != HDF_SUCCESS) { + HDF_LOGE("scdc write test config0 fail"); + return ret; + } + scdc->status.testCfg0 = testCfg; + return HDF_SUCCESS; +} + +int32_t HdmiScdcScrambleSet(struct HdmiScdc *scdc, struct HdmiScdcScrambleCap *scramble) +{ + union HdmiScdcsTmdsConfig cfg = {0}; + int32_t ret; + + if (scdc == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + ret = HdmiCntlrScdcSourceScrambleSet((struct HdmiCntlr *)scdc->priv, scramble->sourceScramble); + if (ret != HDF_SUCCESS) { + HDF_LOGE("scdc source scrambler set fail"); + return ret; + } + + if (scramble->sinkScramble == true) { + cfg.bits.scramblingEnable = 1; + } + if (scramble->tmdsBitClockRatio40 == true) { + cfg.bits.tmdsBitClockRatio = 1; + } + ret = HdmiScdcWriteTmdsConfig(scdc, &(cfg.data)); + if (ret != HDF_SUCCESS) { + HDF_LOGE("scdc write tmds config fail"); + return ret; + } + return HDF_SUCCESS; +} + +int32_t HdmiScdcScrambleGet(struct HdmiScdc *scdc, struct HdmiScdcScrambleCap *scramble) +{ + union HdmiScdcsScramblerStatus status = {0}; + union HdmiScdcsTmdsConfig cfg = {0}; + int32_t ret; + + if (scdc == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + ret = HdmiScdcReadScramblerStatus(scdc, &(status.data)); + if (ret != HDF_SUCCESS) { + HDF_LOGE("scdc read scrambler status fail"); + return ret; + } + scramble->sinkScramble = (status.bits.scramblingStatus ? true : false); + + ret = HdmiScdcReadTmdsConfig(scdc, &(cfg.data)); + if (ret != HDF_SUCCESS) { + HDF_LOGE("scdc read tmds config fail"); + return ret; + } + scramble->tmdsBitClockRatio40 = (cfg.bits.tmdsBitClockRatio ? true : false); + scramble->sourceScramble = HdmiCntlrScdcSourceScrambleGet(scdc->priv); + + scdc->status.tmdsCfg = cfg; + scdc->status.scramblerStatus = status; + return HDF_SUCCESS; +} + +bool HdmiScdcSinkSupport(struct HdmiScdc *scdc) +{ + uint8_t srcVer, i; + int32_t ret; + + if (scdc == NULL) { + return HDF_ERR_INVALID_PARAM; + } + + for (i = 0; i < HDMI_SCDC_READ_SOURCE_VERSION_TIMES; i++) { + srcVer = HDMI_SCDC_HDMI20_VERSION; + ret = HdmiScdcWriteSourceVersion(scdc, &srcVer); + if (ret != HDF_SUCCESS) { + HDF_LOGE("scdc write source version fail"); + return false; + } + ret = HdmiScdcReadSourceVersion(scdc, &srcVer); + if (ret != HDF_SUCCESS) { + HDF_LOGE("scdc read source version fail"); + return false; + } + } + scdc->status.sourceVersion = HDMI_SCDC_HDMI20_VERSION; + return true; +} + +int32_t HdmiScdcOptMsgHandle(struct HdmiScdc *scdc, enum HdmiScdcOptMsg msg, uint8_t *buffer, uint32_t len) +{ + int32_t ret; + + if (scdc == NULL || buffer == NULL || len == 0) { + return HDF_ERR_INVALID_PARAM; + } + + switch (msg) { + case HDMI_SCDC_OPT_SET_SOURCE_VER : + ret = HdmiScdcWriteSourceVersion(scdc, buffer); + break; + case HDMI_SCDC_OPT_GET_SOURCE_VER : + ret = HdmiScdcReadSourceVersion(scdc, buffer); + break; + case HDMI_SCDC_OPT_GET_SINK_VER : + ret = HdmiScdcReadSinkVersion(scdc, buffer); + break; + case HDMI_SCDC_OPT_SET_FLT_UPDATE : + case HDMI_SCDC_OPT_SET_FRL_START : + ret = HdmiScdcWriteUpdate0(scdc, buffer); + break; + case HDMI_SCDC_OPT_GET_FLT_UPDATE : + case HDMI_SCDC_OPT_GET_FRL_START : + ret = HdmiScdcReadUpdate0(scdc, buffer); + break; + case HDMI_SCDC_OPT_SET_CONFIG1 : + ret = HdmiScdcWriteConfig1(scdc, buffer); + break; + case HDMI_SCDC_OPT_GET_CONFIG1 : + ret = HdmiScdcReadConfig1(scdc, buffer); + break; + case HDMI_SCDC_OPT_GET_TEST_CONFIG_1 : + ret = HdmiScdcReadTestConfig1(scdc, buffer); + break; + case HDMI_SCDC_OPT_GET_FLT_READY : + ret = HdmiScdcReadStatusFlag0(scdc, buffer); + break; + case HDMI_SCDC_OPT_GET_LTP_REQ : + ret = HdmiScdcRead(scdc, HDMI_SCDCS_OFFSET_STASTUS_FLAG_1, buffer, len); + break; + default : + HDF_LOGE("scdc msg handle, msg %d not support.", msg); + ret = HDF_ERR_NOT_SUPPORT; + break; + } + + return ret; +} + +int32_t HdmiScdcFillScrambleCap(struct HdmiScdc *scdc, struct HdmiScdcScrambleCap *scramble, + enum HdmiTmdsModeType *tmdsMode) +{ + struct HdmiCntlr *cntlr = NULL; + struct HdmiCommonAttr *commAttr = NULL; + struct HdmiVideoAttr *videoAttr = NULL; + + if (scdc == NULL || scdc->priv == NULL || scramble == NULL || tmdsMode == NULL) { + HDF_LOGD("scdc fill scramble cap: param is null"); + return HDF_ERR_INVALID_PARAM; + } + + cntlr = (struct HdmiCntlr *)scdc->priv; + commAttr = &(cntlr->attr.commAttr); + videoAttr = &(cntlr->attr.videoAttr); + if (commAttr->enableHdmi == false) { + /* DVI mode */ + *tmdsMode = HDMI_TMDS_MODE_DVI; + scramble->sinkScramble = false; + scramble->sourceScramble = false; + scramble->tmdsBitClockRatio40 = false; + if (videoAttr->tmdsClock > HDMI_HDMI14_MAX_TMDS_RATE) { + HDF_LOGE("tmds clock %u can't support in DVI mode.", videoAttr->tmdsClock); + return HDF_ERR_INVALID_PARAM; + } + } else if (videoAttr->tmdsClock > HDMI_HDMI14_MAX_TMDS_RATE) { + *tmdsMode = HDMI_TMDS_MODE_HDMI_2_0; + scramble->sinkScramble = true; + scramble->sourceScramble = true; + scramble->tmdsBitClockRatio40 = true; + } else { + *tmdsMode = HDMI_TMDS_MODE_HDMI_1_4; + scramble->sinkScramble = false; + scramble->sourceScramble = false; + scramble->tmdsBitClockRatio40 = false; + } + return HDF_SUCCESS; +}